Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #94861 > unrolled thread

Request comments - printx

Started byTim Rentsch <txr@alumni.caltech.edu>
First post2016-10-14 12:03 -0700
Last post2016-11-15 10:37 -0800
Articles 20 on this page of 31 — 10 participants

Back to article view | Back to comp.lang.c


Contents

  Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-14 12:03 -0700
    Re: Request comments - printx supercat@casperkitty.com - 2016-10-14 13:06 -0700
      Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-15 15:28 -0700
        Re: Request comments - printx supercat@casperkitty.com - 2016-10-17 10:26 -0700
          Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-18 08:42 -0700
            Re: Request comments - printx supercat@casperkitty.com - 2016-10-20 09:12 -0700
              Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-22 19:23 -0700
    Re: Request comments - printx Ian Collins <ian-news@hotmail.com> - 2016-10-16 17:30 +1300
      Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-16 00:22 -0700
        Re: Request comments - printx Ian Collins <ian-news@hotmail.com> - 2016-10-16 20:37 +1300
          Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-17 11:22 -0700
    Re: Request comments - printx BartC <bc@freeuk.com> - 2016-10-16 23:44 +0100
      Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-17 10:29 -0700
        Re: Request comments - printx BartC <bc@freeuk.com> - 2016-10-17 18:57 +0100
          Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-18 08:20 -0700
            Re: Request comments - printx Nick Bowler <nbowler@draconx.ca> - 2016-10-19 17:10 +0000
              Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-20 08:58 -0700
                Re: Request comments - printx raltbos@xs4all.nl (Richard Bos) - 2016-10-23 13:37 +0000
                  Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-23 14:16 -0700
    Re: Request comments - printx Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-18 02:41 -0700
      Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-18 08:37 -0700
        Re: Request comments - printx Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-18 08:45 -0700
        Re: Request comments - printx Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-18 09:46 -0700
          Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-18 23:33 -0700
    Request comments - printx asetofsymbols@gmail.com - 2016-10-23 00:39 -0700
      Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-23 14:08 -0700
    Re: Request comments - printx Richard Heathfield <rjh@cpax.org.uk> - 2016-11-09 16:32 +0000
      Re: Request comments - printx "Mr. Man-wai Chang" <toylet.toylet@gmail.com> - 2016-11-10 01:03 +0800
      Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-11-12 17:53 -0800
        Re: Request comments - printx Richard Heathfield <rjh@cpax.org.uk> - 2016-11-13 16:43 +0000
          Re: Request comments - printx Tim Rentsch <txr@alumni.caltech.edu> - 2016-11-15 10:37 -0800

Page 1 of 2  [1] 2  Next page →


#94861 — Request comments - printx

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-14 12:03 -0700
SubjectRequest comments - printx
Message-ID<kfnh98e7nxs.fsf@x-alumni2.alumni.caltech.edu>
I am soliciting comments and suggestions for a small family of
functions (and a few supporting macro and type definitions) which
I have taken to calling "printx", with printx() being the
representative function of the family.

The printx() function behaves like printf(), except it has an
extension that allows customized printing of data types outside
the usual set of printf() conversions.  Here is a small example,
providing a way of printing complex numbers as part of a format
specification.  The code

  #include "printx.h"

  /* ... define some convenience types ... */

  static int
  format_complex( Formatter it, Format format, va_list *list, Channel out ){
      union { _Complex double z; double d[2]; } u;
      u.z = va_arg( *list, _Complex double );
      return  printx_send( out, "(%f + %f*I)", u.d[0], u.d[1] );
  }

  static PRINTX_FORMATTER( Fcomplex, format_complex );

defines a custom format conversion, to be referenced by the name
'Fcomplex'.  This formatter can then be used in a printx() call
as shown in the example code fragment next.  The lines

      _Complex double z = 1.23 + 4.56*I;

      printx( "The value of z is %!\n", Fcomplex, z );

print "The value of z is (1.230000 + 4.560000*I)" (and followed
by a newline, naturally).  (The identifier 'I' in the initializer
for 'z' is defined outside the code sample given, with a value
of the imaginary unit i.)

Just a few remarks before giving more examples.  One, the type
names in the prototype for format_complex() do not come out of
the "printx.h" header, but are defined locally in terms of type
names like 'struct printx_formatter_s', and which do come out of
"printx.h".  Two, although some decisions were made in order to
present the examples, nothing is cast in stone;  please feel
free to suggest interfaces changes if and where that may be
appropriate.

Next example:  allowing _Complex float and _Complex long double.
The definition of format_complex() can be changed to accept
the two other flavors of _Complex data types:

  static int
  format_complex( Formatter it, Format format, va_list *a, Channel out ){
      union { _Complex long double z; long double d[2]; } u;
      if(       format->mod_none  )  u.z = va_arg( *a, _Complex double );
      else if(  format->mod_h     )  u.z = va_arg( *a, _Complex float );
      else if(  format->mod_L     )  u.z = va_arg( *a, _Complex long double );
      else return -1;

      return  printx_send( out, "(%Lf + %Lf*I)", u.d[0], u.d[1] );
  }

With this change, other _Complex types can be printed by using a
length modifier:

      _Complex float zf = z;
      _Complex long double zld = z;

      printx( "zf is %h!,  zld is %L!\n", _Fcomplex, zf, _Fcomplex, zld );

Next example:  we would like to be able to choose a precision,
rather than the default of six digits, when printing complex
numbers.  Here is a way to do that:

  static int
  format_complex( Formatter it, Format format, va_list *a, Channel out ){
      union { _Complex long double z; long double d[2]; } u;
      if(  format->mod_none    )  u.z = va_arg( *a, _Complex double );
      else if(  format->mod_h  )  u.z = va_arg( *a, _Complex float );
      else if(  format->mod_L  )  u.z = va_arg( *a, _Complex long double );
      else return -1;

      long double x = u.d[0], y = u.d[1];
      int p = format->precision;

      if(  format->dot_present  ){
          return  printx_send( out, "(%.*Lf + %.*Lf*I)", p, x, p, y );
      } else {
          return  printx_send( out, "(%Lf + %Lf*I)", x, y );
      }
  }

Now calls through Fcomplex can use a precision specifier:

      printx( "z with 3 decimal places: %.3!\n", Fcomplex, z );

which gives

  z with 3 decimal places: (1.230 + 4.560*I)

or an argument value precision specifier:

      printx( "z with 2 decimal places: %.*!\n", 2, Fcomplex, z );

which gives

  z with 2 decimal places: (1.23 + 4.56*I)

The rule for '*' in the width or precision fields follows the
rule used for other conversion specifiers:  they are picked up,
with an 'int' type, before the primary argument value (which is
Fcomplex in this case).  The values are available in members of
the 'format' struct:  format->width, format->precision.

The return value for a custom formatting function is negative to
indicate failure of some sort, zero or positive to indicate
success.  Any failure along the way stops formatting and returns
the failure value to the caller of printx().  If there are no
failures, printx() returns the value that printf() would, ie,
the number of characters transmitted.

Formatting functions are not limited to a single argument value.
Here is an example function for formatting int-valued matrices:

  static int
  format_matrix( Formatter it, Format format, va_list *list, Channel out ){
      int i, j, rows = va_arg( *list, int ), columns = va_arg( *list, int );
      const char *prefix = va_arg( *list, char * );
      typedef int (*Matrix)[columns];
      Matrix m = va_arg( *list, Matrix );
      const char *final_prefix = va_arg( *list, char * );
      int r = printx_send( out, "{\n" );
      for(  i = 0;  r >= 0  &&  i < rows;  i++  ){
          r = printx_send( out, "%s{", prefix );
          for(  j = 0;  r >= 0  &&  j < columns;  j++  ){
              r = printx_send( out, " %d,", m[i][j] );
          }
          r = r < 0 ? r : printx_send( out, " },\n" );
      }
      r = r < 0 ? r : printx_send( out, "%s}", final_prefix );
      return  r;
  }

And a sample call:

      int m[4][3] = {
          { 1, 2, 3 },
          { 2, 3, 4 },
          { 3, 4, 5 },
          { 4, 5, 6 },
      };
      printx( "   m = %!;\n", Fmatrix, 4, 3, "      ", m, "   " );

which produces:

     m = {
        { 1, 2, 3, },
        { 2, 3, 4, },
        { 3, 4, 5, },
        { 4, 5, 6, },
     };

That is the last example.

Let's see, what else do I need to say?  In addition to printx(),
there are functions corresponding to other members of the
printf() family:

    printx()    vprintx()
    sprintx()   vsprintx()
    snprintx()  vsnprintx()

There are also functions fprintx() and vfprintx(), but
declarations for those are contained in a separate header file,
in case a calling .c file doesn't want to include <stdio.h> for
those cases that don't need it (only fprintx() and vfprintx()
do).  All custom formatters work with any of the *printx()
functions.

In every case the prototype of functions in the -printx() family
matches the prototype of the corresponding -printf() function.
The behavior also matches, so *printx() functions are plug
compatible with their *printf() counterparts.

A call to a *printx() function may contain multiple custom
conversions in a single format.  Also, calls to printx_send()
may use custom conversions in their formats and arguments,
recursively.  Other conversion specification information, in
particular flags, is available through the 'format' argument,
but how to make it available conveniently is an open question.
Maybe someone will have some suggestions for what would be a
good way to do that (the same applies to width, precision, and
length modifiers, which are illustrated above as they are
currently).

I think this is probably a good stopping point.  All questions,
comments and suggestions are welcome.

[toc] | [next] | [standalone]


#94862

Fromsupercat@casperkitty.com
Date2016-10-14 13:06 -0700
Message-ID<e6a47f0d-cf94-4a69-a82b-5d386380f74e@googlegroups.com>
In reply to#94861
On Friday, October 14, 2016 at 2:03:56 PM UTC-5, Tim Rentsch wrote:
> I am soliciting comments and suggestions for a small family of
> functions (and a few supporting macro and type definitions) which
> I have taken to calling "printx", with printx() being the
> representative function of the family.

I would suggest that one start by defining a single unified vprintf variant
which can be used to implement vsprintf, vfprintf, vprintf, etc. by accepting
a double-indirect pointer to an output function, and which passes that pointer
to the output function itself.  This would allow e.g. vfprintf to be
implemented as:

    struct vfprintf_info { int (*proc)(void *caller_info, 
      unsigned char *out_dat, int out_length_or_command); FILE *f; };
    int do_fprintf_output(void *caller_info, 
      void *out_dat, long out_length_or_command)
    {
      if (out_length_or_command >= 0)
      {
        struct vfprintf_info *p = caller_info;
        return fwrite(out_dat, 1, out_length_or_command, p->f);
      }
      else
        return -1;
    }
    int vfprintf(FILE *f, char *fmt, va_list vp)
    {
      struct vfprintf_info inf;
      inf->proc = do_fprintf_output;
      inf->f = f;
      return vgen_printf(&inf, fmt, vp);
    }

Such a function could then support additional formatting options by
having it invoke the passed-in function with various negative lengths
when unknown formatting characters were encountered [most likely, a
negative length would indicate that "out_dat" will hold a pointer to
a structure describing what needs to be done].

Having one function combine the roles of the equivalents to fprintf,
printf, sprintf, etc. seems better than having different functions for
the different purposes.

[toc] | [prev] | [next] | [standalone]


#94888

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-15 15:28 -0700
Message-ID<kfnmvi55jsf.fsf@x-alumni2.alumni.caltech.edu>
In reply to#94862
supercat@casperkitty.com writes:

> On Friday, October 14, 2016 at 2:03:56 PM UTC-5, Tim Rentsch wrote:
>> I am soliciting comments and suggestions for a small family of
>> functions (and a few supporting macro and type definitions) which
>> I have taken to calling "printx", with printx() being the
>> representative function of the family.
>
> I would suggest that one start by defining a single unified vprintf
> variant which can be used to implement vsprintf, vfprintf, vprintf,
> etc.  by accepting a double-indirect pointer to an output function,
> and which passes that pointer to the output function itself.  This
> would allow e.g. vfprintf to be implemented as:  [code omitted]
>
> Such a function could then support additional formatting options by
> having it invoke the passed-in function with various negative
> lengths when unknown formatting characters were encountered [most
> likely, a negative length would indicate that "out_dat" will hold a
> pointer to a structure describing what needs to be done].
>
> Having one function combine the roles of the equivalents to fprintf,
> printf, sprintf, etc.  seems better than having different functions
> for the different purposes.

Unless I am misunderstanding you, these comments are either
orthogonal to what I'm asking about or purely about implementation.
Providing functions that are plug compatible with printf(), etc, is
a given in the problem statement and cannot be changed.  My question
is about what interface and/or functionality might be provided
beyond this minimal specification.  Taking the general outline of
printx() functions as fixed and not subject to change, do you have
any comments or suggestions about additional interface and/or
functionality?

[toc] | [prev] | [next] | [standalone]


#95003

Fromsupercat@casperkitty.com
Date2016-10-17 10:26 -0700
Message-ID<294eb770-91af-4688-add0-f62051db62f7@googlegroups.com>
In reply to#94888
On Saturday, October 15, 2016 at 5:28:39 PM UTC-5, Tim Rentsch wrote:
> Unless I am misunderstanding you, these comments are either
> orthogonal to what I'm asking about or purely about implementation.
> Providing functions that are plug compatible with printf(), etc, is
> a given in the problem statement and cannot be changed.  My question
> is about what interface and/or functionality might be provided
> beyond this minimal specification.  Taking the general outline of
> printx() functions as fixed and not subject to change, do you have
> any comments or suggestions about additional interface and/or
> functionality?

If one is designing a function whose functionality is a proper superset
of printf/fprintf/sprintf/vprintf/vfprintf/vsprintf [and unless I was
misunderstanding your intention, you were expecting that the function
would support existing printf codes in addition to your new ones], then
it would seem wasteful to include both the new function and a full-fledged
implementation of all the others within the same application, rather than
using one routine as a replacement for all of them.  While that wouldn't
be helpful (or perhaps even possible) in all implementations, there are
enough implementations where that would be helpful that it would seem useful
to allow for it.  Were you not intending your functionality to be a superset
of normal functionality?

Further, rather than having to implement vprintx, vsprintx, and vfprintx
as independent functions each with its own format processor, it would seem
more efficient to have one general routine which can serves all such
purposes and many more (e.g. outputting to a graphical display).  Since
it may be helpful to have some devices respond to formatting codes whose
meaning may not be readily expressed by data within an ASCII character
stream [e.g. outputting a number as right-aligned on a screen where
characters have different widths], allowing the output device to involve
itself in the formatting process would seem useful.

[toc] | [prev] | [next] | [standalone]


#95065

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-18 08:42 -0700
Message-ID<kfny41l3bp9.fsf@x-alumni2.alumni.caltech.edu>
In reply to#95003
supercat@casperkitty.com writes:

> On Saturday, October 15, 2016 at 5:28:39 PM UTC-5, Tim Rentsch wrote:
>> Unless I am misunderstanding you, these comments are either
>> orthogonal to what I'm asking about or purely about implementation.
>> Providing functions that are plug compatible with printf(), etc, is
>> a given in the problem statement and cannot be changed.  My question
>> is about what interface and/or functionality might be provided
>> beyond this minimal specification.  Taking the general outline of
>> printx() functions as fixed and not subject to change, do you have
>> any comments or suggestions about additional interface and/or
>> functionality?
>
> If one is designing a function whose functionality is a proper superset
> of printf/fprintf/sprintf/vprintf/vfprintf/vsprintf [and unless I was
> misunderstanding your intention, you were expecting that the function
> would support existing printf codes in addition to your new ones], then
> it would seem wasteful to include both the new function and a full-fledged
> implementation of all the others within the same application, rather than
> using one routine as a replacement for all of them.  While that wouldn't
> be helpful (or perhaps even possible) in all implementations, there are
> enough implementations where that would be helpful that it would seem useful
> to allow for it.  Were you not intending your functionality to be a superset
> of normal functionality?
>
> Further, rather than having to implement vprintx, vsprintx, and vfprintx
> as independent functions each with its own format processor, it would seem
> more efficient to have one general routine which can serves all such
> purposes and many more (e.g. outputting to a graphical display).  Since
> it may be helpful to have some devices respond to formatting codes whose
> meaning may not be readily expressed by data within an ASCII character
> stream [e.g.  outputting a number as right-aligned on a screen where
> characters have different widths], allowing the output device to involve
> itself in the formatting process would seem useful.

Let me say this again.

    My
    question
    is
    only
    about
    interface,
    not
    about
    implementation.

Did I say that slowly enough so that you understood it this time?

[toc] | [prev] | [next] | [standalone]


#95094

Fromsupercat@casperkitty.com
Date2016-10-20 09:12 -0700
Message-ID<78080066-05d1-42c4-9992-1604c471d43a@googlegroups.com>
In reply to#95065
On Tuesday, October 18, 2016 at 10:43:06 AM UTC-5, Tim Rentsch wrote:
> Let me say this again.
> 
>     My
>     question
>     is
>     only
>     about
>     interface,
>     not
>     about
>     implementation.
> 
> Did I say that slowly enough so that you understood it this time?

If a function accepts other functions as arguments, the contract for those
other functions is part of the interface for the original function, is it
not?

If the supplied function accepts a char* and length, that will require
that the printx code somehow know what size buffer it should allocate, or
will require that the called function perform all its work twice.  If
instead one designs the interface to pass around a means of "outputting"
characters rather than a location where they can be stored, the need for
a buffer will evaporate.

[toc] | [prev] | [next] | [standalone]


#95155

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-22 19:23 -0700
Message-ID<kfny41fztur.fsf@x-alumni2.alumni.caltech.edu>
In reply to#95094
supercat@casperkitty.com writes:

> On Tuesday, October 18, 2016 at 10:43:06 AM UTC-5, Tim Rentsch wrote:
>> Let me say this again.
>>
>>     My
>>     question
>>     is
>>     only
>>     about
>>     interface,
>>     not
>>     about
>>     implementation.
>>
>> Did I say that slowly enough so that you understood it this time?
>
> If a function accepts other functions as arguments, the contract for those
> other functions is part of the interface for the original function, is it
> not?

The type of a formatting function is fixed, which it must be so
that printx() code can call the function.  Beyond that, the only
responsibility a formatting function has is to consume all of its
arguments (or return a negative value if there was a failure of
some sort).  As far as printx() code is concerned, nothing else
about the internals of a formatting function matters.

> If the supplied function accepts a char* and length, that will require
> that the printx code somehow know what size buffer it should allocate, or
> will require that the called function perform all its work
> twice.

No, it doesn't.

> If
> instead one designs the interface to pass around a means of "outputting"
> characters rather than a location where they can be stored, the need for
> a buffer will evaporate.

Go back and look at the example formatting functions again.  What
do you know about a 'Channel', beyond the fact that one is used
as the first argument to printx_send()?

[toc] | [prev] | [next] | [standalone]


#94904

FromIan Collins <ian-news@hotmail.com>
Date2016-10-16 17:30 +1300
Message-ID<e6ge41Fu8usU2@mid.individual.net>
In reply to#94861
On 10/15/16 08:03 AM, Tim Rentsch wrote:
> I am soliciting comments and suggestions for a small family of
> functions (and a few supporting macro and type definitions) which
> I have taken to calling "printx", with printx() being the
> representative function of the family.

This looks really interesting and I like the way you have kept things 
well within the spirit of printf.  Do you have a reference 
implementation written?

I assume you would also consider an equivalent "scanx"?

-- 
Ian

[toc] | [prev] | [next] | [standalone]


#94905

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-16 00:22 -0700
Message-ID<kfn60os69nb.fsf@x-alumni2.alumni.caltech.edu>
In reply to#94904
Ian Collins <ian-news@hotmail.com> writes:

> On 10/15/16 08:03 AM, Tim Rentsch wrote:
>> I am soliciting comments and suggestions for a small family of
>> functions (and a few supporting macro and type definitions) which
>> I have taken to calling "printx", with printx() being the
>> representative function of the family.
>
> This looks really interesting and I like the way you have kept
> things well within the spirit of printf.

Thank you, that is nice to hear.

> Do you have a reference implementation written?

Yes, modulo some finishing touches near the edges.  The examples
I showed were all run through that implementation.  Also it
passes all the cases in my little test suite, which is currently
somewhere between 40 and 50 cases.  (I'm not going to say whether
the tests were written first. :)

> I assume you would also consider an equivalent "scanx"?

I would consider it, sure.  Having said that, *scanf() is a very
different kind of beast, and I'm not sure how the printx() ideas
would map onto scanx().  The first order of business is to get
printx() finalized and wrapped up;  after that's done we can
come back to what might work for scanx().

Do you have any other comments or suggestions for what additional
functionality to make available, or how?  One thing I know it
would be nice to be able to do but I'm not sure how is passing
flags along in a printx_send() call.  For example, in the complex
number formatters, it would be nice to be able to pick up the
flag characters in the original %! conversion, and use those
flags on the two components of the complex number.  There is an
obvious way to do that, by constructing a format string for the
call to printx_send(), but that's a bit heavy-handed - I am
hoping for some better idea(s) about how to arrange such things.

[toc] | [prev] | [next] | [standalone]


#94906

FromIan Collins <ian-news@hotmail.com>
Date2016-10-16 20:37 +1300
Message-ID<e6gp2hF15saU1@mid.individual.net>
In reply to#94905
On 10/16/16 08:22 PM, Tim Rentsch wrote:
> Ian Collins <ian-news@hotmail.com> writes:
>
>> On 10/15/16 08:03 AM, Tim Rentsch wrote:
>>> I am soliciting comments and suggestions for a small family of
>>> functions (and a few supporting macro and type definitions) which
>>> I have taken to calling "printx", with printx() being the
>>> representative function of the family.
>>
>> This looks really interesting and I like the way you have kept
>> things well within the spirit of printf.
>
> Thank you, that is nice to hear.
>
>> Do you have a reference implementation written?
>
> Yes, modulo some finishing touches near the edges.  The examples
> I showed were all run through that implementation.  Also it
> passes all the cases in my little test suite, which is currently
> somewhere between 40 and 50 cases.  (I'm not going to say whether
> the tests were written first. :)

It might be more fun to publish the tests rather than the code to see 
what other can come up with :)

>> I assume you would also consider an equivalent "scanx"?
>
> I would consider it, sure.  Having said that, *scanf() is a very
> different kind of beast, and I'm not sure how the printx() ideas
> would map onto scanx().  The first order of business is to get
> printx() finalized and wrapped up;  after that's done we can
> come back to what might work for scanx().

I guess the obvious use case is to read back in what printx() writes 
out: data serialisation.

> Do you have any other comments or suggestions for what additional
> functionality to make available, or how?  One thing I know it
> would be nice to be able to do but I'm not sure how is passing
> flags along in a printx_send() call.  For example, in the complex
> number formatters, it would be nice to be able to pick up the
> flag characters in the original %! conversion, and use those
> flags on the two components of the complex number.  There is an
> obvious way to do that, by constructing a format string for the
> call to printx_send(), but that's a bit heavy-handed - I am
> hoping for some better idea(s) about how to arrange such things.

Well you could do something along the lines of setting the state of your 
Channel object if you had something analogous to fprintf() or you allow 
the state of stdout to be manipulated.  That's the (admittedly clunky) 
way C++ stream manipulators are used to set output formatting such as 
precision and representation.  Although in this case you would have to 
use multiple printx() calls if you wanted to use differing 
representations for each parameter.

-- 
Ian

[toc] | [prev] | [next] | [standalone]


#95008

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-17 11:22 -0700
Message-ID<kfnoa2i4yyk.fsf@x-alumni2.alumni.caltech.edu>
In reply to#94906
Ian Collins <ian-news@hotmail.com> writes:

> On 10/16/16 08:22 PM, Tim Rentsch wrote:
>> Ian Collins <ian-news@hotmail.com> writes:
>>
>>> On 10/15/16 08:03 AM, Tim Rentsch wrote:
>>>> I am soliciting comments and suggestions for a small family of
>>>> functions (and a few supporting macro and type definitions) which
>>>> I have taken to calling "printx", with printx() being the
>>>> representative function of the family.
>>>
>>> This looks really interesting and I like the way you have kept
>>> things well within the spirit of printf.
>>
>> Thank you, that is nice to hear.
>>
>>> Do you have a reference implementation written?
>>
>> Yes, modulo some finishing touches near the edges.  The examples
>> I showed were all run through that implementation.  Also it
>> passes all the cases in my little test suite, which is currently
>> somewhere between 40 and 50 cases.  (I'm not going to say whether
>> the tests were written first. :)
>
> It might be more fun to publish the tests rather than the code to
> see what other can come up with :)

Interesting suggestion.  There are two kinds of tests: without
using extensions, and with using extensions.  The ones with using
extensions require writing one or more corresponding formatting
functions, and then checking to see that they do the right thing.
For example, with Fcomplex, there could be code like

    sprintx( buffer, "%!", Fcomplex, (_Complex double){ 1 + 2*I } );
    if(  strcmp( buffer, "(1.000000 + 2.000000*I)" ) != 0  ) ...

The examples in my first posting should have most of what's
needed to write any number of test cases (leaving the '...'
just as written, I can take care of that).  I guess I should add
what is the current definition of the format information struct,
along with a disclaimer that it's a work in progress (and part of
what prompted me to post in the first place), so please excuse
any rough edges:

    struct printx_format_s {
      const char    *raw_start;
      const char    *raw_limit;

	unsigned     flags_present  :1;
	unsigned     width_present  :1;
	unsigned     dot_present    :1;
	unsigned     mod_present    :1;

	unsigned     flag_space     :1;
	unsigned     flag_plus      :1;
	unsigned     flag_minus     :1;
	unsigned     flag_sharp     :1;
	unsigned     flag_zero      :1;
	unsigned     flag_quote     :1;
	unsigned     flag_I         :1;

	unsigned     width_star     :1;
	unsigned     dot_star       :1;

	unsigned     mod_none       :1;
	unsigned     mod_hh         :1;
	unsigned     mod_h          :1;
	unsigned     mod_l          :1;
	unsigned     mod_ll         :1;
	unsigned     mod_j          :1;
	unsigned     mod_t          :1;
	unsigned     mod_z          :1;
	unsigned     mod_L          :1;

	  signed     width;
	  signed     precision;
    };

Some of these fields are used in the examples.  Hopefully
everything else is self-explanatory.

For tests that don't make use of extensions, these are really
easy.  Any set of arguments that would make up a legal call
to printf() can be a test.  For example

    ( "foo %-8d bas", 12 )

is a test.  For %n conversions, there are variables n_, nhh, nh,
nl, nll, nj, nz, and nt, of appropriate types, that may be
used, as for example:

    ( "foo %s bas %lln", "blah blah blah", &nll )

is a test both of the formatting output and that the %lln
conversion stores the right value.

It would be great to get any test cases - if anyone is interested
please send via email (address in the From: field is valid).

>>> I assume you would also consider an equivalent "scanx"?
>>
>> I would consider it, sure.  Having said that, *scanf() is a very
>> different kind of beast, and I'm not sure how the printx() ideas
>> would map onto scanx().  The first order of business is to get
>> printx() finalized and wrapped up;  after that's done we can
>> come back to what might work for scanx().
>
> I guess the obvious use case is to read back in what printx()
> writes out:  data serialisation.

Oh, I get that.  What I meant is I'm not sure what sort of
mechanism would facilitate such use cases.

>> Do you have any other comments or suggestions for what additional
>> functionality to make available, or how?  One thing I know it
>> would be nice to be able to do but I'm not sure how is passing
>> flags along in a printx_send() call.  For example, in the complex
>> number formatters, it would be nice to be able to pick up the
>> flag characters in the original %! conversion, and use those
>> flags on the two components of the complex number.  There is an
>> obvious way to do that, by constructing a format string for the
>> call to printx_send(), but that's a bit heavy-handed - I am
>> hoping for some better idea(s) about how to arrange such things.
>
> Well you could do something along the lines of setting the state
> of your Channel object if you had something analogous to fprintf()
> or you allow the state of stdout to be manipulated.  That's the
> (admittedly clunky) way C++ stream manipulators are used to set
> output formatting such as precision and representation.  Although
> in this case you would have to use multiple printx() calls if you
> wanted to use differing representations for each parameter.

Okay, I would not have thought of that.  I don't know how it
might fit in with everything else but maybe it will help stir
my thinking.  Thank you for the suggestions.

[toc] | [prev] | [next] | [standalone]


#94944

FromBartC <bc@freeuk.com>
Date2016-10-16 23:44 +0100
Message-ID<nu0vsd$vjo$1@dont-email.me>
In reply to#94861
On 14/10/2016 20:03, Tim Rentsch wrote:
> I am soliciting comments and suggestions for a small family of
> functions (and a few supporting macro and type definitions) which
> I have taken to calling "printx", with printx() being the
> representative function of the family.

>       printx( "The value of z is %!\n", Fcomplex, z );

>       _Complex float zf = z;
>       _Complex long double zld = z;
>
>       printx( "zf is %h!,  zld is %L!\n", _Fcomplex, zf, _Fcomplex, zld );

>       printx( "z with 3 decimal places: %.3!\n", Fcomplex, z );
>
> which gives
>
>   z with 3 decimal places: (1.230 + 4.560*I)
>
> or an argument value precision specifier:
>
>       printx( "z with 2 decimal places: %.*!\n", 2, Fcomplex, z );
>
> which gives
>
>   z with 2 decimal places: (1.23 + 4.56*I)

>       int m[4][3] = {
>           { 1, 2, 3 },
>           { 2, 3, 4 },
>           { 3, 4, 5 },
>           { 4, 5, 6 },
>       };
>       printx( "   m = %!;\n", Fmatrix, 4, 3, "      ", m, "   " );
>
> which produces:
>
>      m = {
>         { 1, 2, 3, },
>         { 2, 3, 4, },
>         { 3, 4, 5, },
>         { 4, 5, 6, },
>      };

No real comments but just a summary of how I believe your extension works:

* printx-family functions can be plug-in replacements for printf-family

* printx recognises a new "%...!" format code

* When "%..!" is seen, that takes a special operand off the list of
  arguments that is being scanned, that needs to be a custom formatter
  (function?) like _Fcomplex (after any * arguments if necessary).

* The custom formatter then takes over popping and using as many more
   arguments as it needs, before finishing. The format is now positioned
   just after the "!" and the process continues.

* Any standard format codes are presumably passed on to regular printf
   functions or otherwise processed as normal.

* printx functions can be recursive (the handler for one format may make
   use of further printf calls)

* Multiple "%..!" codes can occur in a single format string
   interspersed with normal format codes.

A couple of issues that I can see: with regular printf, the compiler can 
warn against mismatches between format code and argument type, which I 
don't think would be possible here.

Also, especially with examples such as Fmatrix, it is easy to miss out 
an argument or add an extraneous one. What happens if the next "!" 
expects something like an _Fcomplex but it gets an integer instead?

(This happens with normal printf too but that doesn't usually end up 
calling an argument, if that is what happens with printx. And some 
compilers can check the number and type of printf arguments as I said.)

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#95004

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-17 10:29 -0700
Message-ID<kfnshru51fq.fsf@x-alumni2.alumni.caltech.edu>
In reply to#94944
BartC <bc@freeuk.com> writes:

> On 14/10/2016 20:03, Tim Rentsch wrote:
>> I am soliciting comments and suggestions for a small family of
>> functions (and a few supporting macro and type definitions) which
>> I have taken to calling "printx", with printx() being the
>> representative function of the family.
>>
>>       printx( "The value of z is %!\n", Fcomplex, z );
>>
>>       _Complex float zf = z;
>>       _Complex long double zld = z;
>>
>>       printx( "zf is %h!,  zld is %L!\n", _Fcomplex, zf, _Fcomplex, zld );
>>
>>       printx( "z with 3 decimal places: %.3!\n", Fcomplex, z );
>>
>> which gives
>>
>>   z with 3 decimal places:  (1.230 + 4.560*I)
>>
>> or an argument value precision specifier:
>>
>>       printx( "z with 2 decimal places: %.*!\n", 2, Fcomplex, z );
>>
>> which gives
>>
>>   z with 2 decimal places:  (1.23 + 4.56*I)
>>
>>       int m[4][3] = {
>>           { 1, 2, 3 },
>>           { 2, 3, 4 },
>>           { 3, 4, 5 },
>>           { 4, 5, 6 },
>>       };
>>       printx( "   m = %!;\n", Fmatrix, 4, 3, "      ", m, "   " );
>>
>> which produces:
>>
>>      m = {
>>         { 1, 2, 3, },
>>         { 2, 3, 4, },
>>         { 3, 4, 5, },
>>         { 4, 5, 6, },
>>      };
>
> No real comments but just a summary of how I believe your extension works:
>
> * printx-family functions can be plug-in replacements for printf-family
>
> * printx recognises a new "%...!" format code
>
> * When "%..!" is seen, that takes a special operand off the list of
>  arguments that is being scanned, that needs to be a custom formatter
>  (function?) like _Fcomplex (after any * arguments if necessary).
>
> * The custom formatter then takes over popping and using as many more
>   arguments as it needs, before finishing.  The format is now positioned
>   just after the "!" and the process continues.
>
> * Any standard format codes are presumably passed on to regular printf
>   functions or otherwise processed as normal.
>
> * printx functions can be recursive (the handler for one format may make
>   use of further printf calls)
>
> * Multiple "%..!" codes can occur in a single format string
>   interspersed with normal format codes.
>
> A couple of issues that I can see:  with regular printf, the compiler
> can warn against mismatches between format code and argument type,
> which I don't think would be possible here.
>
> Also, especially with examples such as Fmatrix, it is easy to miss out
> an argument or add an extraneous one.  What happens if the next "!"
> expects something like an _Fcomplex but it gets an integer instead?
>
> (This happens with normal printf too but that doesn't usually end up
> calling an argument, if that is what happens with printx.  And some
> compilers can check the number and type of printf arguments as I
> said.)

Thank you for your response.  Do you have any constructive
comments to make?

[toc] | [prev] | [next] | [standalone]


#95006

FromBartC <bc@freeuk.com>
Date2016-10-17 18:57 +0100
Message-ID<nu33di$7fm$1@dont-email.me>
In reply to#95004
On 17/10/2016 18:29, Tim Rentsch wrote:
> BartC <bc@freeuk.com> writes:

>> No real comments but just a summary of how I believe your extension works:

> Thank you for your response.  Do you have any constructive
> comments to make?

As I said, I was just checking if I'd understood how it works (from the 
point of view of someone using after custom formatters have been 
created). That can be an important part of such an extension.

Otherwise it sounds fine.

-- 
bartc

[toc] | [prev] | [next] | [standalone]


#95059

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-18 08:20 -0700
Message-ID<kfnbmyh4rb0.fsf@x-alumni2.alumni.caltech.edu>
In reply to#95006
BartC <bc@freeuk.com> writes:

> On 17/10/2016 18:29, Tim Rentsch wrote:
>> BartC <bc@freeuk.com> writes:
>>
>>> No real comments but just a summary of how I believe your extension works:
>>
>> Thank you for your response.  Do you have any constructive
>> comments to make?
>
> As I said, I was just checking if I'd understood how it works (from
> the point of view of someone using after custom formatters have been
> created).  That can be an important part of such an extension.

Ah.  I would summarize as follows.

The *printx() functions behave just like their *printf()
counterparts, except that they recognize %! as a conversion
specifier.  A %! conversion invokes a custom format, the
next argument in the parameter list (after zero, one or two
int arguments for *'s).  Invoking a custom format calls the
corresponding formatting function, which picks up any further
argument values from the parameter list, and produces output
by means of printx_send().  Custom formatting functions may
make use of any flags, width, precision, or length modifiers
that were given in the %! specification (or not make use of
them, as they choose).  Calls to printx_send() behave like
printx(), except their output is sent to whatever sink is
associated with the top-level call to printx(), fprintf(),
sprintx(), etc.  Ordinary conversion specifiers and custom
conversion specifiers may be freely intermixed in calls to
the *printx() functions and printx_send().

Something I did not mention before, but may be relevant:  the
*printx() functions (and also printx_send()) recognize only those
conversion specifications (besides %!, of course) that are
defined in the Standard.  They do not recognize, and will fail
on, any extended conversion specifications that may be defined by
the implementation.  The reason for this is that it's impossible
to know where an unknown extended conversion specification ends,
and also impossible to know what sorts of arguments it expects.
That makes it impossible to recover in general when one is
encountered.  It may be possible to accommodate the specific
case of Posix positional arguments, which is a common extension,
but I haven't yet looked into that closely or decided what to
do about it.

[toc] | [prev] | [next] | [standalone]


#95084

FromNick Bowler <nbowler@draconx.ca>
Date2016-10-19 17:10 +0000
Message-ID<nu89dp$75c$2@dont-email.me>
In reply to#95059
On Tue, 18 Oct 2016 08:20:35 -0700, Tim Rentsch wrote:
> Something I did not mention before, but may be relevant:  the
> *printx() functions (and also printx_send()) recognize only those
> conversion specifications (besides %!, of course) that are
> defined in the Standard.
[...]
> It may be possible to accommodate the specific case of Posix
> positional arguments, which is a common extension, but I haven't
> yet looked into that closely or decided what to do about it.

Just as a general comment, the positional argument extension (or
something that serves a similar function) is absolutely essential
for translatable format strings, as some languages may require the
substituted to be output in a different order from the original
language.

If these functions do not support it, then it may be difficult
or impossible to translate the output of programs using these
functions into some languages, which will limit their utility.

[toc] | [prev] | [next] | [standalone]


#95092

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-20 08:58 -0700
Message-ID<kfnbmyf1082.fsf@x-alumni2.alumni.caltech.edu>
In reply to#95084
Nick Bowler <nbowler@draconx.ca> writes:

> On Tue, 18 Oct 2016 08:20:35 -0700, Tim Rentsch wrote:
>> Something I did not mention before, but may be relevant:  the
>> *printx() functions (and also printx_send()) recognize only those
>> conversion specifications (besides %!, of course) that are
>> defined in the Standard.
>
> [...]
>
>> It may be possible to accommodate the specific case of Posix
>> positional arguments, which is a common extension, but I haven't
>> yet looked into that closely or decided what to do about it.
>
> Just as a general comment, the positional argument extension (or
> something that serves a similar function) is absolutely essential
> for translatable format strings, as some languages may require the
> substituted to be output in a different order from the original
> language.
>
> If these functions do not support it, then it may be difficult
> or impossible to translate the output of programs using these
> functions into some languages, which will limit their utility.

Okay, thank you for the comment.  I have now looked into the
Posix positional arguments a bit more.  I believe these can
be accommodated by *printx(), including custom formatters,
perhaps with some limitations on how custom formatters are
used.

[toc] | [prev] | [next] | [standalone]


#95164

Fromraltbos@xs4all.nl (Richard Bos)
Date2016-10-23 13:37 +0000
Message-ID<580cbac9.18055312@news.xs4all.nl>
In reply to#95092
Tim Rentsch <txr@alumni.caltech.edu> wrote:

> Nick Bowler <nbowler@draconx.ca> writes:
> 
> > Just as a general comment, the positional argument extension (or
> > something that serves a similar function) is absolutely essential
> > for translatable format strings, as some languages may require the
> > substituted to be output in a different order from the original
> > language.
> >
> > If these functions do not support it, then it may be difficult
> > or impossible to translate the output of programs using these
> > functions into some languages, which will limit their utility.
> 
> Okay, thank you for the comment.  I have now looked into the
> Posix positional arguments a bit more.  I believe these can
> be accommodated by *printx(), including custom formatters,
> perhaps with some limitations on how custom formatters are
> used.

Be careful, though. Limit them enough and you may still eliminate some
natural languages. French and Italian have combined preposition-
pronouns. Scots Gaelic still has a dual. In German, adjectives can be
formatted differently depending on syntactic context. And that's just in
Europe. There are some _very_ weird natural languages out there - some
even weirder than C++.

Richard

[toc] | [prev] | [next] | [standalone]


#95207

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-10-23 14:16 -0700
Message-ID<kfn8ttezry8.fsf@x-alumni2.alumni.caltech.edu>
In reply to#95164
raltbos@xs4all.nl (Richard Bos) writes:

> Tim Rentsch <txr@alumni.caltech.edu> wrote:
>
>> Nick Bowler <nbowler@draconx.ca> writes:
>>
>>> Just as a general comment, the positional argument extension (or
>>> something that serves a similar function) is absolutely essential
>>> for translatable format strings, as some languages may require the
>>> substituted to be output in a different order from the original
>>> language.
>>>
>>> If these functions do not support it, then it may be difficult
>>> or impossible to translate the output of programs using these
>>> functions into some languages, which will limit their utility.
>>
>> Okay, thank you for the comment.  I have now looked into the
>> Posix positional arguments a bit more.  I believe these can
>> be accommodated by *printx(), including custom formatters,
>> perhaps with some limitations on how custom formatters are
>> used.
>
> Be careful, though.  Limit them enough and you may still eliminate some
> natural languages.  French and Italian have combined preposition-
> pronouns.  Scots Gaelic still has a dual.  In German, adjectives can be
> formatted differently depending on syntactic context.  And that's just in
> Europe.  There are some _very_ weird natural languages out there - some
> even weirder than C++.

This comment prompts me to ask a question.  I confess to having
no experience with the Posix positional printf() arguments (not
counting experimenting to see how they work).  My impression is
that one writes a printf() call with a fixed set of arguments,
but with a format string chosen based on what language is being
targeted for output.  Is that a typical use case?  Based on your
comment it seems like there isn't enough flexibility in the Posix
positional arguments to accommodate all the variations mentioned
above.  To what extent does the Posix argument capability address
the multi-language problem?

[toc] | [prev] | [next] | [standalone]


#95047

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2016-10-18 02:41 -0700
Message-ID<4580bde5-8e51-4cae-85c5-3377d96f26a7@googlegroups.com>
In reply to#94861
On Friday, October 14, 2016 at 8:03:56 PM UTC+1, Tim Rentsch wrote:
>
> I think this is probably a good stopping point.  All questions,
> comments and suggestions are welcome.
>
Firstly, I wouldn't think in terms of complex numbers. It's a good simple 
example, but it's a bit of a trap. Fundamental mathematical types have
characteristics that most user-defined structures lack. You don't want
to produce something that allows people to define their own custom
printx formatters for complex types and huge integers, but doesn't scale
to what most people will actually use it for.

Which is what? I'd suggest printing enumerated values as human-readable
strings. Maybe also dumping database record type structures, but would
people really go to all the hassle of setting up a format conversion specifer
for that? You'll only have one argument, so won't it be more convenient
just to use printf? But the thing that people might want is reciprocal 
write / reads. printf and scanf look superficially as though they provide that,
and that might well have been the original idea, but in fact they don't. But
if someone does set up a format converter, it would nice to be able to use
the same converter for scanx, and keep the text format in synch.



 

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web