From 6eebdb8e3ac0c5db648f9cec19b9d828ed14a337 Mon Sep 17 00:00:00 2001 From: gdr-ftp Date: Sat, 31 Oct 1998 17:22:05 +0000 Subject: [PATCH] Makefile, vsprintmt.c: - Added the sprintmt and vsprintmt routines. These are thread safe variants of the sprintf and vsprintf routines. Note that they don't support as many formatting options as stdio does. gnomisc.c: - Define the global variable "__progname". This is initially set to "(unknown)", but is properly initialized to the return value of __prognameGS() the first time that function is called. --- lib/libc/gno/Makefile | 4 +- lib/libc/gno/gnomisc.c | 13 +- lib/libc/gno/vsprintmt.c | 315 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+), 7 deletions(-) create mode 100644 lib/libc/gno/vsprintmt.c diff --git a/lib/libc/gno/Makefile b/lib/libc/gno/Makefile index a0c4cc9..44128c5 100644 --- a/lib/libc/gno/Makefile +++ b/lib/libc/gno/Makefile @@ -1,14 +1,14 @@ # # gno/libc/gno/Makefile # -# $Id: Makefile,v 1.7 1998/02/19 01:05:16 gdr-ftp Exp $ +# $Id: Makefile,v 1.8 1998/10/31 17:22:05 gdr-ftp Exp $ # LIB = c LIBPFX = $(OBJ_DIR)../ NO_REZ = true SRC_ASM = gnocmd.asm parsearg.asm stack.asm -SRC_C = gnomisc.c gsstring.c map.c stack2.c +SRC_C = gnomisc.c gsstring.c map.c stack2.c vsprintmt.c SRCS = $(SRC_ASM) $(SRC_C) .INCLUDE: /src/gno/lib/lib.mk diff --git a/lib/libc/gno/gnomisc.c b/lib/libc/gno/gnomisc.c index 71c34c1..92a0097 100644 --- a/lib/libc/gno/gnomisc.c +++ b/lib/libc/gno/gnomisc.c @@ -1,5 +1,5 @@ /* - * $Id: gnomisc.c,v 1.2 1997/09/21 06:07:24 gdr Exp $ + * $Id: gnomisc.c,v 1.3 1998/10/31 17:22:05 gdr-ftp Exp $ * * This file is formatted with tabs every 8 characters. */ @@ -25,7 +25,7 @@ needsgno(void) { } } -static char *unknown = "(unknown)"; +char * __progname = "(unknown)"; static GetNameRecGS namerec = { 1, NULL }; char * @@ -35,19 +35,22 @@ __prognameGS (void) { namerec.dataBuffer = (ResultBuf255Ptr) GOchange (NULL, NAME_MAX, NULL); if (namerec.dataBuffer == NULL) { - return unknown; + /* we can't get it now, we likely can't get it later */ + namerec.dataBuffer = NULL; + return __progname; } GetNameGS(&namerec); if (_toolErr) { GOfree(namerec.dataBuffer); namerec.dataBuffer = NULL; - return unknown; + return __progname; } /* NULL-terminate it */ namerec.dataBuffer->bufString.text [namerec.dataBuffer->bufString.length] = '\0'; + __progname = namerec.dataBuffer->bufString.text; } - return namerec.dataBuffer->bufString.text; + return __progname; } void diff --git a/lib/libc/gno/vsprintmt.c b/lib/libc/gno/vsprintmt.c new file mode 100644 index 0000000..4afc093 --- /dev/null +++ b/lib/libc/gno/vsprintmt.c @@ -0,0 +1,315 @@ +/* + * Thread-safe and buffer-overrun-safe versions of sprintf and vsprintf + * Written to support thread-safe versions of the syslog routines. + * + * Devin Reade, October 1998 + * + * $Id: vsprintmt.c,v 1.1 1998/10/31 17:22:05 gdr-ftp Exp $ + */ + +#ifdef __ORCAC__ +#pragma memorymodel 1 +segment "libc_gno__"; +#endif + +#include +#include +#include +#ifdef __GNO__ +#include /* prototype consistency check */ +#endif + +/* + * sprintmt, vsprintmt + * + * These are sprintf- and vsprintf-variants that are thread-safe. + * + * is the place where the formatted string will be put. + * is the length of . No more than -1 characters + * will be placed into . + * gives the printf-like format string. + * is the usual vararg thing. + * + * RETURNS: A pointer the the NULL-terminator at the end of + * + * Only a subset of printf format specifiers are permitted. They are: + * %d signed int (decimal output) + * %u unsigned int (decimal output) + * %x unsigned int (decimal output) + * %s string + * %% the literal, "%" + * There is also an extra format specifier: + * %m the string currently returned by strerror(); + * + * In addition, the %d, %u, and %x format specifiers may use the 'l' + * modifier (%ld, %lu, %lx) for long signed and unsigned ints. + * + * Floating point format specifiers are not supported. + * + * Any other character following the '%' is treated as a literal. For + * example, '%A' would be printed as "A". + * + * LIMITATION: + * This routines assumes that shorts are the same length as ints. + */ + +#define PRINTCHAR(c) \ +{ \ + if (blen > 0) { \ + *bptr++ = (c); \ + --blen; \ + } \ +} +#define MAX_ULONG_CHARS 11 /* > number of digits in an unsigned long */ + +char * +vsprintmt (char *buffer, size_t blen, const char *format, va_list ap) +{ + unsigned long uival; + long int ival; + const char *fptr; + char *bptr, *sval; + int i, j; + short base, islong, capX; + char intbuffer[MAX_ULONG_CHARS]; + + fptr = format-1; /* we'll increment this right away */ + bptr = buffer; + --blen; /* leave space for the null-terminator */ + +nextchar: + fptr++; + islong = 0; + capX = 0; + + if (*fptr == '\0') { + goto done; + } + + if (*fptr != '%') { + /* regular character */ + PRINTCHAR(*fptr); + goto nextchar; + } + + fptr++; /* skip the '%' */ + + if (*fptr == '\0') { + goto done; + } + + if (*fptr == '%') { + /* + * '%%' is a literal percent. Check it here so that we don't + * treat "%l%..." the same as "%%...". + */ + PRINTCHAR(*fptr); + goto nextchar; + } + + if (*fptr == 'l') { + /* + * long qualifier, unless at end of string, in which case it's + * ignored. "%ls" and "%lm" are treated like "%s" and "%lm", for + * simplicity's sake + */ + islong = 1; + fptr++; + if (*fptr == '\0') { + goto done; + } + } + + /* At this point, we're at the main type specifier */ + switch (*fptr) { + case '\0': + /* '%' at end of format string? Ignore it. */ + goto done; + + case 'd': + if (islong) { + ival = va_arg(ap, long int); + } else { + ival = va_arg(ap, int); + } + goto printint; + + case 'X': + capX = 1; + /*FALLTHROUGH*/ + case 'x': + case 'u': + if (islong) { + uival = va_arg(ap, unsigned long int); + } else { + uival = va_arg(ap, unsigned int); + } + if (*fptr == 'u') { + goto printuint; + } else { + goto printhex; + } + /*NOTREACHED*/ + + case 's': + case 'm': + + if (*fptr == 's') { + sval = va_arg(ap, char *); + } else { + sval = strerror(errno); + } + while ((blen > 0) && *sval) { + *bptr++ = *sval++; + --blen; + } + goto nextchar; + + default: + /* treat everything else following '%' as a literal */ + PRINTCHAR(*fptr); + goto nextchar; + } + + /* + * Nothing falls through this point. In order to get here, you have + * to jump your way in. However, to be on the safe side, we put the + * 'done' label here. + */ +done: + *bptr = '\0'; + return bptr; + +printhex: + /* + * Prereq: uival contains an unsigned integer + */ + base = 16; + goto printunsigned; + +printuint: + /* + * Prereq: uival contains an unsigned integer + */ + base = 10; + goto printunsigned; + +printint: + /* + * Prereq: ival contains a signed integer + */ + if (ival < 0) { + uival = -ival; + PRINTCHAR('-'); + } else { + uival = ival; + } + base = 10; + goto printunsigned; + +printunsigned: + /* + * Prereq: - base is set to the number base (10 or 8) + * - uival is set to the value to print + * Uses: i, intbuffer + */ + i = 0; + if (uival == 0) { + intbuffer[i++] = '0'; + } else { + while (uival > 0 && i < MAX_ULONG_CHARS) { + j = uival % base; + if ( j>9 ) { + intbuffer[i++] = (capX ? 'A' : 'a') + (j-10); + } else { + intbuffer[i++] = '0' + j; + } + uival /= base; + } + } + --i; + while (i>=0) { + PRINTCHAR(intbuffer[i]); + --i; + } + intbuffer[i]='\0'; + goto nextchar; + +} +#undef PRINTCHAR + +#pragma optimize 78 +#pragma debug 0 + +char * +sprintmt (char *buffer, size_t blen, const char *format, ...) { + va_list ap; + char *result; + + va_start(ap, format); + result = vsprintmt(buffer, blen, format, ap); + va_end(ap); + return result; +} + +#if 0 /* testing, only */ + +#pragma debug 25 +#pragma optimize 0 + +#include + +#define BUFFERSIZE 32 +#define I -1234 +#define IL -12345678L +#define U 5678 +#define UL 12345678L +#define X 5432 +#define XL 98765432L +#define SHORTSTRING "a short test string" +#define LONGSTRING "123456789 123456789 123456789 123456789 123456789 123456789" + +int main (int argc, char **argv) { + + static char buffer[BUFFERSIZE]; + int i; + + sprintmt(buffer, BUFFERSIZE, "-->%d<--", I); + printf("1\t%d:\t%s\n", I, buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%u<--", U); + printf("2\t%u:\t%s\n", U, buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%x<--", X); + printf("3\t%x:\t%s\n", X, buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%X<--", X); + printf("4\t%x:\t%s\n", X, buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%ld<--", IL); + printf("5\t%ld:\t%s\n", IL, buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%lu<--", UL); + printf("6\t%lu:\t%s\n", UL, buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%lx<--", XL); + printf("7\t%lx:\t%s\n", XL, buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%lX<--", XL); + printf("8\t%lX:\t%s\n", XL, buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%s<--", SHORTSTRING); + printf("9\tshort:\t\"%s\"\n", buffer); + + sprintmt(buffer, BUFFERSIZE, "-->%s<--", LONGSTRING); + printf("10\tlong:\t\"%s\"\n", buffer); + + for (i=0; i%m<--"); + printf("%d\terrno %d:\t\"%s\"\n", 11+i, i, buffer); + } + return 0; +} + +#endif /* 0 */