Re: [dev] [sbase] printf(1)

2014-01-24 Thread sin
On Thu, Dec 19, 2013 at 10:49:03PM +, sin wrote:
> On Thu, Dec 19, 2013 at 10:18:34PM +, Rob wrote:
> > printf '%f\n' 2
> > 
> > If you "throw it into the standard library's printf", even forgetting
> > about how we do that, you'd still interpret 2 as an int, when printf
> > expects a float. And that's only the beginning, what about %n, or not
> > passing enough arguments?
> 
> Exactly.
> 
> BTW, I just noticed this thread as the messages had been bouncing for some 
> time
> (was migrating my mail setup).

is there any update on this?  Sorry I do not have the original message
so I can't respond there.

bye,
sin



Re: [dev] [sbase] printf(1)

2013-12-19 Thread sin
On Thu, Dec 19, 2013 at 10:18:34PM +, Rob wrote:
> printf '%f\n' 2
> 
> If you "throw it into the standard library's printf", even forgetting
> about how we do that, you'd still interpret 2 as an int, when printf
> expects a float. And that's only the beginning, what about %n, or not
> passing enough arguments?

Exactly.

BTW, I just noticed this thread as the messages had been bouncing for some time
(was migrating my mail setup).

bye,
sin




Re: [dev] [sbase] printf(1)

2013-12-19 Thread Rob

Roberto E. Vargas Caballero, Thu, 19 Dec 2013:

I'm confused about what you're trying to accomplish here.
How about you just copy the format part from the for loop up there and
throw it into the standard library's printf?



I agree!
This strongly smells like NiH-syndrome. Considering we have suckless
standard libraries like uClibc, which we could link statically to by
default some day in the future, we can safely assume letting the stdlib


I think you are lossing something important here. When you execute
printf in a program you have the variables which you want to pass
to printf, or in the case of vprintf you have the va_list, but
in this case you don't have any of them. You cannot call to printf
(or vprintf, or sprintf, or vsprintf) with an array of pointers
to chars (argv), so you have to forgot the library routines.


Exactly. Not to mention, what if the user did this:

printf '%f\n' 2

If you "throw it into the standard library's printf", even forgetting
about how we do that, you'd still interpret 2 as an int, when printf
expects a float. And that's only the beginning, what about %n, or not
passing enough arguments?


Rob



Re: [dev] [sbase] printf(1)

2013-12-19 Thread Roberto E. Vargas Caballero
> That's what I did at first, but I forgot the exact reason why I changed
> it :P  I probably found kind of wasteful to call putchar() for every
> character, but then again, it probably doesn't matter since arguments
> for printf usually aren't that long.

Remember that putchar is a macro, and it only stores a char in an
array and does a comparation (from k&r):

#define putc(x,p) (--(p)->cnt >= 0 \
? (unsigned char) * (p)->ptr++ = (x) : _fillbuf(p))

It is cheap and I think the code is far clear with that aproach.

Regards,

-- 
Roberto E. Vargas Caballero



Re: [dev] [sbase] printf(1)

2013-12-19 Thread Maurice Quennet
On Thu, Dec 19, 2013 at 02:39:21PM +0100, Roberto E. Vargas Caballero wrote:
> You only have to use putchar for every character (except in the case
> of the format specifiers), and then you don't need the enp pointer, or
> am I missing something else?

That's what I did at first, but I forgot the exact reason why I changed
it :P  I probably found kind of wasteful to call putchar() for every
character, but then again, it probably doesn't matter since arguments
for printf usually aren't that long.




Re: [dev] [sbase] printf(1)

2013-12-19 Thread Roberto E. Vargas Caballero
> I admit, printfmt() needs some cleanup.  fmt is supposed to point at the
> begining of the conversion string ('%' for a conversion specifier and
> '\' for a escape sequence) and end, well, points at the end of the
> conversion string (one character after conversion characters like 'd' or
> 's').  end is necessary, so you can set "*end = '\0'", otherwise fmt
> will include everything up unitl to the end of the complete format
> string.

You only have to use putchar for every character (except in the case
of the format specifiers), and then you don't need the enp pointer, or
am I missing something else?


Regards,

-- 
Roberto E. Vargas Caballero



Re: [dev] [sbase] printf(1)

2013-12-19 Thread Maurice Quennet
On Thu, Dec 19, 2013 at 02:22:53PM +0100, Roberto E. Vargas Caballero wrote:
> I also think all the operations with fmt and end are a bit confusing
> and maybe it is a bit more clear something like this (taken from a
> personal project):

I admit, printfmt() needs some cleanup.  fmt is supposed to point at the
begining of the conversion string ('%' for a conversion specifier and
'\' for a escape sequence) and end, well, points at the end of the
conversion string (one character after conversion characters like 'd' or
's').  end is necessary, so you can set "*end = '\0'", otherwise fmt
will include everything up unitl to the end of the complete format
string.
I hope I made it clear now (which I'm not so sure of).

Best regards
Maurice Quennet




Re: [dev] [sbase] printf(1)

2013-12-19 Thread Roberto E. Vargas Caballero
> > I'm confused about what you're trying to accomplish here.
> > How about you just copy the format part from the for loop up there and
> > throw it into the standard library's printf?
> > 
> 
> I agree!
> This strongly smells like NiH-syndrome. Considering we have suckless
> standard libraries like uClibc, which we could link statically to by
> default some day in the future, we can safely assume letting the stdlib

I think you are lossing something important here. When you execute
printf in a program you have the variables which you want to pass
to printf, or in the case of vprintf you have the va_list, but
in this case you don't have any of them. You cannot call to printf
(or vprintf, or sprintf, or vsprintf) with an array of pointers
to chars (argv), so you have to forgot the library routines.

I also think all the operations with fmt and end are a bit confusing
and maybe it is a bit more clear something like this (taken from a
personal project):

void
printf(const char *fmt, ...)
{
unsigned char c;
va_list va;
int base, sign;

va_start(va, fmt);
while (( c = *fmt++) != '\0') {
if (c == '%') {
sign = 0;
switch (*fmt++) {
case '%':
c = '%';
goto printchar;
case 'c':
c = va_arg(va, char);
goto printchar;
case 'o':
base = 8;
break;
case 'd':
sign = 1;
base = 10;
break;
case 'p':
case 'x':
base = 16;
break;
case 's':
puts(va_arg(va, char *));
/* passthrou */
default:
continue;
}
printn(va_arg(va, int), base, sign);
continue;
}
printchar:
putchar(c);
}
}

Of course, it is a simplified version, and it handles operands from
the stack, but it can be easily adapated to argv.

Regards,

-- 
Roberto E. Vargas Caballero



Re: [dev] [sbase] printf(1)

2013-12-19 Thread Maurice Quennet
On Thu, Dec 19, 2013 at 08:50:46AM +0100, Martti Kühne wrote:
> I'm confused about what you're trying to accomplish here.
> How about you just copy the format part from the for loop up there and
> throw it into the standard library's printf?

That's what I'm doing.  You still have to figure out, where the format
string starts and where it ends and you have to convert the argument to
the correct type.

Best regards
Maurice Quennet




Re: [dev] [sbase] printf(1)

2013-12-19 Thread Truls Becken
On 2013-12-19, at 10:47, FRIGN wrote:

>> Considering we have suckless standard libraries like uClibc,
> 
> Whoops, I meant dietlibc. I kinda mixed up the names.

musl FTW!

-Truls



Re: [dev] [sbase] printf(1)

2013-12-19 Thread FRIGN
On Thu, 19 Dec 2013 10:44:52 +0100
FRIGN  wrote:

> Considering we have suckless standard libraries like uClibc,

Whoops, I meant dietlibc. I kinda mixed up the names.

-- 
FRIGN 



Re: [dev] [sbase] printf(1)

2013-12-19 Thread FRIGN
On Thu, 19 Dec 2013 08:50:46 +0100
Martti Kühne  wrote:
>
> I'm confused about what you're trying to accomplish here.
> How about you just copy the format part from the for loop up there and
> throw it into the standard library's printf?
> 
> cheers!
> mar77i
> 

I agree!
This strongly smells like NiH-syndrome. Considering we have suckless
standard libraries like uClibc, which we could link statically to by
default some day in the future, we can safely assume letting the stdlib
do it is a better choice.

Cheers

FRIGN

-- 
FRIGN 



Re: [dev] [sbase] printf(1)

2013-12-18 Thread Martti Kühne
On Wed, Dec 18, 2013 at 11:36 PM, Maurice Quennet  wrote:
> Hello dev@,
>

Hello mjq@,

> diff --git a/Makefile b/Makefile
> index 2a72a1c..e93f570 100644
[...]
> +void
> +printfmt(void)
> +{
> +   int e;
> +   long l;
> +   double d;
> +   char c, f, *tmp;
> +
> +   if (*end == '%') {
> +   putchar('%');
> +   fmt = ++end;
> +   return;
> +   }
> +
> +   if (*arg == NULL)
> +   eprintf("missing argument\n");
> +
> +   if (*end == 'b') {
> +   fmt = *arg;
> +   tmp = end;
> +
> +   while (*fmt) {
> +   if (*fmt == '\\') {
> +   ++fmt;
> +   printesc();
> +   continue;
> +   }
> +   putchar(*fmt);
> +   ++fmt;
> +   }
> +
> +   fmt = end = tmp + 1;
> +   return;
> +   }
> +
> +   for (; *end; ++end) {
> +   if (!isdigit(*end) && *end != '#' && *end != '.' &&
> +   *end != '+' && *end != '-' && *end != ' ')
> +   break;
> +   }
> +
> +   if (*end == '\0')
> +   eprintf("%s: invalid directive\n", fmt);
> +
> +   f = *end;
> +   c = *++end;
> +   *end = '\0';
> +
> +   switch (f) {
> +   case 'c':
> +   printf(fmt, **arg++);
> +   break;
> +   case 's':
> +   printf(fmt, *arg++);
> +   break;
> +   case 'd': case 'i': case 'o':
> +   case 'u': case 'X': case 'x':
> +   e = errno;
> +   errno = 0;
> +   l = strtol(*arg, NULL, 0);
> +   if (errno)
> +   eprintf("%s: invalid value\n", *arg);
> +   printf(fmt, l);
> +   ++arg;
> +   errno = e;
> +   break;
> +   case 'a': case 'A': case 'e': case 'E':
> +   case 'f': case 'F': case 'g': case 'G':
> +   e = errno;
> +   errno = 0;
> +   d = strtod(*arg, NULL);
> +   if (errno)
> +   eprintf("%s: invalid value\n", *arg);
> +   printf(fmt, d);
> +   ++arg;
> +   errno = e;
> +   break;
> +   default:
> +   eprintf("%s: invalid directive\n", fmt);
> +   }
> +
> +   *end = c;
> +   fmt = end;
> +}
> +

I'm confused about what you're trying to accomplish here.
How about you just copy the format part from the for loop up there and
throw it into the standard library's printf?

cheers!
mar77i



Re: [dev] [sbase] printf(1)

2013-12-18 Thread Chris Down
On 2013-12-18 21:06:08 -0600, William Giokas wrote:
> People on this list need to learn about 'git format-patch' and 'git
> send-email'...

...and about not quoting the entirety of the last message as context
when it doesn't provide any. :-)


pgpIqSRxp_FhA.pgp
Description: PGP signature


Re: [dev] [sbase] printf(1)

2013-12-18 Thread William Giokas
On Wed, Dec 18, 2013 at 11:36:12PM +0100, Maurice Quennet wrote:
> Hello dev@,
> 
> I was searching for a programming project so I looked into TODO and
> picked printf.  I hacked something up a few weeks ago, but I didn't
> publish it until now, since I didn't have a man page yet and I was a
> little busy (a patch follows at the end of the mail).
> In the following I will tell a little bit about my implementation and
> point out differences to OpenBSD's printf implementation (since I am a
> OpenBSD user):
> First for my `algorithm': There is nothing much to say.  My
> implementation simply skips through the format string until it finds a
> '\' or a '%' and prints everything before that character.  If a '\' was
> found, the appropriate escape sequence is printed.  If a '%' was found,
> it skips forward until it finds a supported conversion specifier, and
> passes everything starting from the '%' up until that point to printf(3)
> (plus the approprietly converted command line argument).
> And now for the differences: For a large part my implementation is
> similar to OpenBSD's version.  Both support the same escape sequences,
> flags and conversion specifiers (which, as far as tested,  behave the
> same).  The major difference is error handling.  While OpenBSD's version
> prints a warning to stderr and continues parsing its input, my version
> exits immediately.  Also, my implementation does not check the syntax of
> the conversion specifier flags, but simply skips over them.
> This is for the following two reasons:
> 1.) printf(1) is mostly used for shell scripting, so I think it is ok to
> expect the user to pass a well formed format string and to check his
> arguments.  Even if using a POSIX compliant printf(1), if you put in
> garbage you will in return get garbage (or at least not what you
> expected to get).
> 2.) This way of error handling makes the code simpler/shorter.
> For the man page: well, I really suck at writing man pages, especially
> since my english is quite shaky.  Also, while writing the man page, I
> was wondering if it wasn't possible to simply use OpenBSD's man page
> (with a few modifications) since both implementations seem to be largely
> equivalent.
> I have the feeling that I forgot to mention something, but, well, it
> probably will come up again.  Anyways I hope you like it.
> 
> Best regards,
> Maurice Quennet

People on this list need to learn about 'git format-patch' and 'git
send-email'...

-- 
William Giokas | KaiSforza | http://kaictl.net/
GnuPG Key: 0x73CD09CF
Fingerprint: F73F 50EF BBE2 9846 8306  E6B8 6902 06D8 73CD 09CF


pgp7WKAm13S8G.pgp
Description: PGP signature


[dev] [sbase] printf(1)

2013-12-18 Thread Maurice Quennet
Hello dev@,

I was searching for a programming project so I looked into TODO and
picked printf.  I hacked something up a few weeks ago, but I didn't
publish it until now, since I didn't have a man page yet and I was a
little busy (a patch follows at the end of the mail).
In the following I will tell a little bit about my implementation and
point out differences to OpenBSD's printf implementation (since I am a
OpenBSD user):
First for my `algorithm': There is nothing much to say.  My
implementation simply skips through the format string until it finds a
'\' or a '%' and prints everything before that character.  If a '\' was
found, the appropriate escape sequence is printed.  If a '%' was found,
it skips forward until it finds a supported conversion specifier, and
passes everything starting from the '%' up until that point to printf(3)
(plus the approprietly converted command line argument).
And now for the differences: For a large part my implementation is
similar to OpenBSD's version.  Both support the same escape sequences,
flags and conversion specifiers (which, as far as tested,  behave the
same).  The major difference is error handling.  While OpenBSD's version
prints a warning to stderr and continues parsing its input, my version
exits immediately.  Also, my implementation does not check the syntax of
the conversion specifier flags, but simply skips over them.
This is for the following two reasons:
1.) printf(1) is mostly used for shell scripting, so I think it is ok to
expect the user to pass a well formed format string and to check his
arguments.  Even if using a POSIX compliant printf(1), if you put in
garbage you will in return get garbage (or at least not what you
expected to get).
2.) This way of error handling makes the code simpler/shorter.
For the man page: well, I really suck at writing man pages, especially
since my english is quite shaky.  Also, while writing the man page, I
was wondering if it wasn't possible to simply use OpenBSD's man page
(with a few modifications) since both implementations seem to be largely
equivalent.
I have the feeling that I forgot to mention something, but, well, it
probably will come up again.  Anyways I hope you like it.

Best regards,
Maurice Quennet

diff --git a/Makefile b/Makefile
index 2a72a1c..e93f570 100644
--- a/Makefile
+++ b/Makefile
@@ -64,6 +64,7 @@ SRC = \
nohup.c\
paste.c\
printenv.c \
+   printf.c \
pwd.c  \
readlink.c \
renice.c   \
diff --git a/printf.1 b/printf.1
new file mode 100644
index 000..e1b8f88
--- /dev/null
+++ b/printf.1
@@ -0,0 +1,79 @@
+.TH PRINTF 1 sbase-VERSION
+.SH NAME
+printf \- formatted output
+.SH "SYNOPSIS"
+.PP
+.B printf
+.I format
+[
+.I arguments ...
+]
+.SH DESCRIPTION
+.B printf
+formats and prints its
+.I arguments
+as instructed by the
+.I format
+string.
+.P
+If an encoding error occurs, such as an unsupported conversion specifier or
+escape sequence, or if an argument is missing,
+.B printf
+will exit immediately without printing any further output.
+.SH ESCAPE SEQUENCES
+.B printf
+supports the following escape sequences:
+.TP
+.B \ea
+bell character
+.TP
+.B \eb
+backspace character
+.TP
+.B \ee
+escape character
+.TP
+.B \ef
+form feed character
+.TP
+.B \en
+new line character
+.TP
+.B \er
+carriage return character
+.TP
+.B \et
+tab character
+.TP
+.B \ev
+vertical tab character
+.TP
+.B \e'
+single quote character
+.TP
+.B \e\e
+backslash character
+.TP
+.BI \ex hh
+ascii character which is represented by the 1- or 2-digit hexadecimal number
+.I hh
+.TP
+.BI \e num
+ascii character which is represented by the 1-, 2- or 3-digit octal number
+.I num
+.SH CONVERSION SPECIFIERS
+.B printf
+supports the following conversion specifiers: a, A, c, d, e, E, f, F, g, G, i, 
o, u, x, X.
+Since
+.B printf
+relies on its implementation, see
+.IR printf (3)
+for a detailed description of those conversion specifiers and their flags.
+.P
+Additionally the `b' conversion specifier is supported, which takes no flags 
and
+prints its argument, expanding escape sequences.
+.SH EXIT VALUES
+.B printf
+exits 0 on successful completion, and >0 if an error occurs.
+.SH SEE ALSO
+.IR printf (3)
\ No newline at end of file
diff --git a/printf.c b/printf.c
new file mode 100644
index 000..3516a73
--- /dev/null
+++ b/printf.c
@@ -0,0 +1,203 @@
+#include 
+#include 
+#include 
+#include 
+
+#include "util.h"
+
+/* macros from OpenBSD's printf(1) implementation */
+#define isodigit(c) ('0' <= (c) && (c) <= '7')
+#define hextobin(c) ('A' <= (c) && (c) <= 'F' ? (c) - 'A' + 10 : \
+'a' <= (c) && (c) <= 'f' ? (c) - 'a' + 10 : (c) - '0')
+#define octtobin(c) ((c) - '0')
+
+static char**arg;
+static char *end;
+static char *fmt;
+
+static void  printesc(void);
+static void  printfmt(void);
+static void  printhex(void);
+static void  printoct(void);
+static void  usage(void);
+
+void
+printesc(void)
+{
+