mescc: fwrite: Increase debug tracing threshold.
[mes.git] / lib / libc+tcc.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * Mes --- Maxwell Equations of Software
3  * Copyright © 2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
4  * Copyright © 2018 Jeremiah Orians <jeremiah@pdp10.guru>
5  * Copyright (C) 2018 Han-Wen Nienhuys <hanwen@xs4all.nl>
6  *
7  * This file is part of Mes.
8  *
9  * Mes is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or (at
12  * your option) any later version.
13  *
14  * Mes is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Mes.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <setjmp.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <signal.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35 #include <sys/time.h>
36 #include <unistd.h>
37
38 #include <libc.c>
39 #include <linux+tcc.c>
40
41 #if __MESC__
42
43 #include <libc+tcc-mes.c>
44
45 #else // !__MESC__
46
47 #include <libc+tcc-gcc.c>
48
49 #endif // !__MESC__
50
51 char *
52 search_path (char const *file_name)
53 {
54   static char buf[256];
55   char *path = getenv ("PATH");
56   if (__mes_debug ())
57     {
58       eputs ("\n search-path: "); eputs (file_name); eputs ("\n");
59     }
60   while (*path)
61     {
62       char *end = strchr (path, ':');
63       if (!end)
64         end = strchr (path, '\0');
65       strncpy (buf, path, end - path);
66       buf[end - path] = 0;
67       if (__mes_debug ())
68         {
69           eputs (" dir: "); eputs (buf); eputs ("\n");
70         }
71       if (buf[end - path] != '/')
72         strcat (buf, "/");
73       strcat (buf, file_name);
74       if (!access (buf, X_OK))
75         {
76           if (__mes_debug ())
77             {
78               eputs (" found: "); eputs (buf); eputs ("\n");
79             }
80           return buf;
81         }
82       path = end + 1;
83     }
84   return 0;
85 }
86
87 int
88 execvp (char const *file_name, char *const argv[])
89 {
90   if (file_name[0] != '/')
91     file_name = search_path (file_name);
92   if (!file_name)
93     {
94       errno = ENOENT;
95       return -1;
96     }
97   if (__mes_debug ())
98     {
99       eputs (" EXEC: "); eputs (file_name); eputs ("\n");
100       int i = 0;
101       while (argv[i])
102         {
103           eputs (" arg["); eputs (itoa (i)); eputs ("]: "); eputs (argv[i]); eputs ("\n");
104           i++;
105         }
106     }
107   return execve (file_name, argv, environ);
108 }
109
110 int
111 fclose (FILE *stream)
112 {
113   int fd = (int)stream;
114   return close (fd);
115 }
116
117 FILE *
118 fdopen (int fd, char const *mode)
119 {
120   return (FILE*)fd;
121 }
122
123 int
124 ferror (FILE *stream)
125 {
126   int fd = (int)stream;
127   if (fd == -1) return -1;
128   return 0;
129 }
130
131 int
132 fflush (FILE *stream)
133 {
134   fsync ((int)stream);
135 }
136
137 int
138 fprintf (FILE *stream, char const *format, ...)
139 {
140   va_list ap;
141   va_start (ap, format);
142   int r = vfprintf (stream, format, ap);
143   va_end (ap);
144   return r;
145 }
146
147 int
148 _fungetc_p (FILE *stream)
149 {
150   return _fdungetc_p ((int)stream);
151 }
152
153 size_t
154 fread (void *data, size_t size, size_t count, FILE *stream)
155 {
156   if (! size || !count)
157     return 0;
158
159   size_t todo = size * count;
160   char *buf = (char*)data;
161
162   int bytes = 0;
163   while (_fungetc_p (stream) && todo-- && ++bytes)
164     *buf++ = fgetc (stream);
165   if (todo)
166     {
167       int r = read ((int)stream, buf, todo);
168       if (r < 0 && !bytes)
169         bytes = r;
170       else
171         bytes += r;
172     }
173
174   if (__mes_debug ())
175     {
176       eputs ("fread fd="); eputs (itoa ((int)stream));
177       eputs (" bytes="); eputs (itoa (bytes)); eputs ("\n");
178       static char buf[4096];
179       if (bytes > 0 && bytes < sizeof (buf))
180         {
181           strncpy (buf, data, bytes);
182           buf[bytes] = 0;
183           eputs ("fread buf="); eputs (buf); eputs ("\n");
184         }
185     }
186
187   if (bytes > 0)
188     return bytes/size;
189
190   return 0;
191 }
192
193 size_t
194 fwrite (void const *data, size_t size, size_t count, FILE *stream)
195 {
196   if (__mes_debug () > 1)
197     {
198       eputs ("fwrite "); eputs (itoa ((int)stream));
199       eputs ("  "); eputs (itoa (size)); eputs ("\n");
200     }
201
202   if (! size || !count)
203     return 0;
204   int bytes = write ((int)stream, data, size * count);
205
206   if (__mes_debug () > 2)
207     {
208       eputs (" => "); eputs (itoa (bytes)); eputs ("\n");
209     }
210
211   if (bytes > 0)
212     return bytes/size;
213   return 0;
214 }
215
216 long
217 ftell (FILE *stream)
218 {
219   return lseek ((int)stream, 0, SEEK_CUR);
220 }
221
222 FILE*
223 fopen (char const *file_name, char const *opentype)
224 {
225   if (__mes_debug ())
226     {
227       eputs ("fopen "); eputs (file_name);
228       eputs (" "); eputs (opentype); eputs ("\n");
229     }
230
231   int fd;
232   int mode = 0600;
233   if ((opentype[0] == 'a' || !strcmp (opentype, "r+"))
234       && !access (file_name, O_RDONLY))
235     {
236       int flags = O_RDWR;
237       if (opentype[0] == 'a')
238         flags |= O_APPEND;
239       fd = open (file_name, flags, mode);
240     }
241   else if (opentype[0] == 'w' || opentype[0] == 'a' || !strcmp (opentype, "r+"))
242     {
243       char *plus_p = strchr (opentype, '+');
244       int flags = plus_p ? O_RDWR | O_CREAT : O_WRONLY | O_CREAT | O_TRUNC;
245       fd = open (file_name, flags, mode);
246     }
247   else
248     fd = open (file_name, 0, 0);
249
250   if (__mes_debug ())
251     {
252       eputs (" => fd="); eputs (itoa (fd)); eputs ("\n");
253     }
254
255   if (!fd)
256     {
257       eputs (" ***MES LIB C*** fopen of stdin: signal me in band\n");
258       exit (1);
259     }
260   if (fd < 0)
261     fd = 0;
262   return (FILE*)fd;
263 }
264
265 int
266 fseek (FILE *stream, long offset, int whence)
267 {
268   int pos = lseek ((int)stream, offset, whence);
269   if (__mes_debug ())
270     {
271       eputs ("fread fd="); eputs (itoa ((int)stream));
272       eputs ("  =>"); eputs (itoa (pos)); eputs ("\n");
273     }
274   if (pos >= 0)
275     return 0;
276   return -1;
277 }
278
279 int
280 gettimeofday (struct timeval *tv, struct timezone *tz)
281 {
282   static int stub = 0;
283   if (__mes_debug () && !stub)
284     eputs ("gettimeofday stub\n");
285   stub = 1;
286   errno = 0;
287   return 0;
288 }
289
290 double
291 ldexp (double x, int exp)
292 {
293   static int stub = 0;
294   if (__mes_debug () && !stub)
295     eputs ("ldexp stub\n");
296   stub = 1;
297   return 0;
298 }
299
300 struct tm *
301 localtime (time_t const *timep)
302 {
303   static int stub = 0;
304   if (__mes_debug () && !stub)
305     eputs ("localtime stub\n");
306   stub = 1;
307   errno = 0;
308   return 0;
309 }
310
311 void *
312 memmove (void *dest, void const *src, size_t n)
313 {
314   if (dest < src)
315     return memcpy (dest, src, n);
316   char *p = dest + n;
317   char const *q = src +n;
318   while (n--)
319     *--p = *--q;
320   return dest;
321 }
322
323 void *
324 memset (void *s, int c, size_t n)
325 {
326   char *p = s;
327   while (n--) *p++ = c;
328   return s;
329 }
330
331 int
332 memcmp (void const *s1, void const *s2, size_t size)
333 {
334   if (!size)
335     return 0;
336   char *a = s1;
337   char *b = s2;
338   while (*a == *b && --size)
339     {
340       a++;
341       b++;
342     }
343   return *a - *b;
344 }
345
346 int
347 mprotect (void *addr, size_t len, int prot)
348 {
349   return 0;
350 }
351
352 void
353 qswap (void *a, void *b, size_t size)
354 {
355   char *buf[8];
356   memcpy (buf, a, size);
357   memcpy (a, b, size);
358   memcpy (b, buf, size);
359 }
360
361 size_t
362 qpart (void *base, size_t count, size_t size, int (*compare)(void const *, void const *))
363 {
364   void* p = base + count*size;
365   size_t i = 0;
366   for (size_t j = 0; j < count; j++)
367     {
368       if (compare (base+j*size, p) < 0)
369         {
370           qswap (base+i*size, base+j*size, size);
371           i++;
372         }
373     }
374   if (compare (base+count*size, base+i*size) < 0)
375     qswap (base+i*size, base+count*size, size);
376   return i;
377 }
378
379 void
380 qsort (void *base, size_t count, size_t size, int (*compare)(void const *, void const *))
381 {
382   if (count > 1)
383     {
384       int p = qpart (base, count-1, size, compare);
385       qsort (base, p, size, compare);
386       qsort (base+p*size, count-p, size, compare);
387     }
388 }
389
390 int
391 remove (char const *file_name)
392 {
393   struct stat buf;
394   if (stat (file_name, &buf) < 0)
395     return -1;
396   if (S_ISDIR (buf.st_mode))
397     return rmdir (file_name);
398   return unlink (file_name);
399 }
400
401 int
402 sigaction (int signum, struct sigaction const *act, struct sigaction *oldact)
403 {
404   return 0;
405 }
406
407 int
408 sigemptyset (sigset_t *set)
409 {
410   return 0;
411 }
412
413 int
414 snprintf(char *str,  size_t size,  char const *format, ...)
415 {
416   va_list ap;
417   va_start (ap, format);
418   int r = vsprintf (str, format, ap);
419   va_end (ap);
420   return r;
421 }
422
423 int
424 sscanf (char const *str, const char *template, ...)
425 {
426   va_list ap;
427   va_start (ap, template);
428   int r = vsscanf (str, template, ap);
429   va_end (ap);
430   return r;
431 }
432
433 char *
434 strcat (char *to, char const *from)
435 {
436   char *p = strchr (to, '\0');
437   while (*from)
438     *p++ = *from++;
439   *p = 0;
440   return to;
441 }
442
443 char *
444 strchr (char const *s, int c)
445 {
446   char const *p = s;
447   while (*p || !c)
448     {
449       if (c == *p)
450         return p;
451       p++;
452     }
453   return 0;
454 }
455
456 char *
457 strncpy (char *to, char const *from, size_t size)
458 {
459   if (size == 0)
460     return to;
461   char *p = to;
462   while (*from && size--)
463     *p++ = *from++;
464   if (*from)
465     size++;
466   while (size--)
467     *p++ = 0;
468   return to;
469 }
470
471 char *
472 strrchr (char const *s, int c)
473 {
474   int n = strlen (s);
475   if (!n)
476     return 0;
477   char const *p = s + n;
478   if (!*p && !c)
479     return p;
480   p--;
481   while (n-- && (*p || !c))
482     {
483       if (c == *p)
484         return p;
485       p--;
486     }
487   return 0;
488 }
489
490 /** locate a substring. #memmem# finds the first occurrence of
491     #needle# in #haystack#.  This is not ANSI-C.
492
493     The prototype is not in accordance with the Linux Programmer's
494     Manual v1.15, but it is with /usr/include/string.h   */
495
496 unsigned char *
497 _memmem (unsigned char const *haystack, int haystack_len,
498          unsigned char const *needle, int needle_len)
499 {
500   unsigned char const *end_haystack = haystack + haystack_len - needle_len + 1;
501   unsigned char const *end_needle = needle + needle_len;
502
503   /* Ahhh ... Some minimal lowlevel stuff. This *is* nice; Varation
504      is the spice of life */
505   while (haystack < end_haystack)
506     {
507       unsigned char const *subneedle = needle;
508       unsigned char const *subhaystack = haystack;
509       while (subneedle < end_needle)
510         if (*subneedle++ != *subhaystack++)
511           goto next;
512
513       /* Completed the needle.  Gotcha.  */
514       return (unsigned char *) haystack;
515     next:
516       haystack++;
517     }
518   return 0;
519 }
520
521 void *
522 memmem (void const *haystack, int haystack_len,
523         void const *needle, int needle_len)
524 {
525   unsigned char const *haystack_byte_c = (unsigned char const *)haystack;
526   unsigned char const *needle_byte_c = (unsigned char const *)needle;
527   return _memmem (haystack_byte_c, haystack_len, needle_byte_c, needle_len);
528 }
529
530 char *
531 strstr (char const *haystack, char const *needle)
532 {
533   return memmem (haystack, strlen (haystack), needle, strlen (needle));
534 }
535
536 double
537 strtod (char const *string, char **tailptr)
538 {
539   static int stub = 0;
540   if (__mes_debug () && !stub)
541     eputs ("strtod stub\n");
542   stub = 1;
543   return 0;
544 }
545
546 float
547 strtof (char const *string, char **tailptr)
548 {
549   return strtod (string, tailptr);
550 }
551
552 long double
553 strtold (char const *string, char **tailptr)
554 {
555   return strtod (string, tailptr);
556 }
557
558 long
559 strtol (char const *string, char **tailptr, int base)
560 {
561   if (!strncmp (string, "0x", 2))
562     {
563       string += 2;
564       base = 16;
565     }
566   if (tailptr)
567     {
568       *tailptr = string;
569       return abtoi (tailptr, base);
570     }
571   char **p = &string;
572   return abtoi (p, base);
573 }
574
575 long long int
576 strtoll (char const *string, char **tailptr, int base)
577 {
578   return strtol (string, tailptr, base);
579 }
580
581 unsigned long
582 strtoul (char const *string, char **tailptr, int base)
583 {
584   return strtol (string, tailptr, base);
585 }
586
587 unsigned long long
588 strtoull (char const *string, char **tailptr, int base)
589 {
590   return strtol (string, tailptr, base);
591 }
592
593 time_t
594 time (time_t *tloc)
595 {
596   static int stub = 0;
597   if (__mes_debug () && !stub)
598     eputs ("time stub\n");
599   stub = 1;
600   errno = 0;
601   return 0;
602 }
603
604 int
605 vsnprintf (char *str, size_t size, char const *format, va_list ap)
606 {
607   return vsprintf (str, format, ap);
608 }
609
610 void *
611 calloc (size_t nmemb, size_t size)
612 {
613   size_t count = nmemb * size;
614   void *p = malloc (count);
615   memset (p, 0, count);
616   return p;
617 }
618
619 int
620 islower (int c)
621 {
622   return c >= 'a' && c <= 'z';
623 }
624
625 int
626 isupper (int c)
627 {
628   return c >= 'A' && c <= 'Z';
629 }
630
631 int
632 tolower (int c)
633 {
634   if (isupper (c))
635     return c + ('a' - 'A');
636   return c;
637 }
638
639 int
640 toupper (int c)
641 {
642   if (islower (c))
643     return c - ('a' - 'A');
644   return c;
645 }
646
647 char *
648 strlwr (char *string)
649 {
650   char *p = string;
651   while (*p)
652     {
653       *p = tolower (*p);
654       p++;
655     }
656   return string;
657 }
658
659 char *
660 strupr (char *string)
661 {
662   char *p = string;
663   while (*p)
664     {
665       *p = toupper (*p);
666       p++;
667     }
668   return string;
669 }
670
671 int
672 vfprintf (FILE* f, char const* format, va_list ap)
673 {
674   int fd = (int)f;
675   char const *p = format;
676   int count = 0;
677   while (*p)
678     if (*p != '%')
679       {
680         count++;
681         fputc (*p++, fd);
682       }
683     else
684       {
685         p++;
686         char c = *p;
687         int left_p = 0;
688         int precision = -1;
689         int width = -1;
690         if (c == '-')
691           {
692             left_p = 1;
693             c = *++p;
694           }
695         char pad = ' ';
696         if (c == '0')
697           {
698             pad = c;
699             c = *p++;
700           }
701         if (c >= '0' && c <= '9')
702           {
703             width = abtoi (&p, 10);
704             c = *p;
705           }
706         else if (c == '*')
707           {
708             width = va_arg (ap, int);
709             c = *++p;
710           }
711         if (c == '.')
712           {
713             c = *++p;
714             if (c >= '0' && c <= '9')
715               {
716                 precision = abtoi (&p, 10);
717                 c = *p;
718               }
719             else if (c == '*')
720               {
721                 precision = va_arg (ap, int);
722                 c = *++p;
723               }
724           }
725         if (c == 'l')
726           c = *++p;
727         if (c == 'l')
728           {
729             eputs ("vfprintf: skipping second: l\n");
730             c = *++p;
731           }
732         switch (c)
733           {
734           case '%': {fputc (*p, fd); count++; break;}
735           case 'c': {char c; c = va_arg (ap, int); fputc (c, fd); break;}
736           case 'd':
737           case 'i':
738           case 'o':
739           case 'u':
740           case 'x':
741           case 'X':
742             {
743               int d = va_arg (ap, int);
744               int base = c == 'o' ? 8
745                 : c == 'x' || c == 'X' ? 16
746                 : 10;
747               char const *s = number_to_ascii (d, base, c != 'u' && c != 'x' && c != 'X');
748               if (c == 'X')
749                 strupr (s);
750               int length = strlen (s);
751               if (precision == -1)
752                 precision = length;
753               if (!left_p)
754                 {
755                   while (width-- > precision)
756                     {
757                       fputc (pad, f);
758                       count++;
759                     }
760                   while (precision > length)
761                     {
762                       fputc ('0', f);
763                       precision--;
764                       width--;
765                       count++;
766                     }
767                 }
768               while (*s)
769                 {
770                   if (precision-- <= 0)
771                     break;
772                   width--;
773                   fputc (*s++, f);
774                   count++;
775                 }
776               while (width > 0)
777                 {
778                   width--;
779                   fputc (pad, f);
780                   count++;
781                 }
782               break;
783             }
784           case 's':
785             {
786               char *s = va_arg (ap, char *);
787               int length = strlen (s);
788               if (precision == -1)
789                 precision = length;
790               if (!left_p)
791                 {
792                   while (width-- > precision)
793                     {
794                       fputc (pad, f);
795                       count++;
796                     }
797                   while (precision > length)
798                     {
799                       fputc (' ', f);
800                       precision--;
801                       width--;
802                       count++;
803                     }
804                 }
805               while (*s)
806                 {
807                   if (precision-- <= 0)
808                     break;
809                   width--;
810                   fputc (*s++, f);
811                   count++;
812                 }
813               while (width > 0)
814                 {
815                   width--;
816                   fputc (pad, f);
817                   count++;
818                 }
819               break;
820             }
821           case 'n':
822             {
823               int *n = va_arg (ap, int *);
824               *n = count;
825               break;
826             }
827           default:
828             {
829               eputs ("vfprintf: not supported: %:");
830               eputc (c);
831               eputs ("\n");
832               p++;
833             }
834           }
835         p++;
836       }
837   va_end (ap);
838   return 0;
839 }
840
841 int
842 vprintf (char const* format, va_list ap)
843 {
844   return vfprintf (STDOUT, format, ap);
845 }
846
847 int
848 vsscanf (char const *s, char const *template, va_list ap)
849 {
850   char const *p = s;
851   char const *t = template;
852   int count = 0;
853   while (*t && *p)
854     if (*t != '%')
855       {
856         t++;
857         p++;
858       }
859     else
860       {
861         t++;
862         char c = *t;
863         if (c == 'l')
864           c = *++t;
865         switch (c)
866           {
867           case '%': {p++; break;}
868           case 'c':
869             {
870               char *c = va_arg (ap, char*);
871               *c = *p++;
872               count++;
873               break;
874             }
875           case 'd':
876           case 'i':
877           case 'u':
878             {
879               int *d = va_arg (ap, int*);
880               *d = abtoi (&p, 10);
881               count++;
882               break;
883             }
884           default:
885             {
886               eputs ("vsscanf: not supported: %:");
887               eputc (c);
888               eputs ("\n");
889               t++;
890               p++;
891             }
892           }
893         t++;
894       }
895   va_end (ap);
896   return count;
897 }
898
899 int
900 vsprintf (char *str, char const* format, va_list ap)
901 {
902   char const *p = format;
903   int count = 0;
904   while (*p)
905     if (*p != '%')
906       {
907         *str++ = *p++;
908         count++;
909       }
910     else
911       {
912         p++;
913         char c = *p;
914         int left_p = 0;
915         int precision = -1;
916         int width = -1;
917         if (c == '-')
918           {
919             left_p = 1;
920             c = *++p;
921           }
922         char pad = ' ';
923         if (c == '0')
924           {
925             pad = c;
926             c = *p++;
927           }
928         if (c >= '0' && c <= '9')
929           {
930             width = abtoi (&p, 10);
931             c = *p;
932           }
933         else if (c == '*')
934           {
935             width = va_arg (ap, int);
936             c = *++p;
937           }
938         if (c == '.')
939           {
940             c = *++p;
941             if (c >= '0' && c <= '9')
942               {
943                 precision = abtoi (&p, 10);
944                 c = *p;
945               }
946             else if (c == '*')
947               {
948                 precision = va_arg (ap, int);
949                 c = *++p;
950               }
951           }
952         if (c == 'l')
953           c = *++p;
954         if (c == 'l')
955           c = *++p;
956         if (c == 'l')
957           {
958             eputs ("vfprintf: skipping second: l\n");
959             c = *++p;
960           }
961         switch (c)
962           {
963           case '%': {*str++ = *p; count++; break;}
964           case 'c': {c = va_arg (ap, int); *str++ = c; count++; break;}
965           case 'd':
966           case 'i':
967           case 'o':
968           case 'u':
969           case 'x':
970           case 'X':
971             {
972               int d = va_arg (ap, int);
973               int base = c == 'o' ? 8
974                 : c == 'x' || c == 'X' ? 16
975                 : 10;
976               char const *s = number_to_ascii (d, base, c != 'u' && c != 'x' && c != 'X');
977               if (c == 'X')
978                 strupr (s);
979               int length = strlen (s);
980               if (precision == -1)
981                 precision = length;
982               if (!left_p)
983                 {
984                   while (width-- > precision)
985                     {
986                       *str++ = pad;
987                       count++;
988                     }
989                   while (precision > length)
990                     {
991                       *str++ = '0';
992                       precision--;
993                       width--;
994                       count++;
995                     }
996                 }
997               while (*s)
998                 {
999                   if (precision-- <= 0)
1000                     break;
1001                   width--;
1002                   *str++ = *s++;
1003                   count++;
1004                 }
1005               while (width > 0)
1006                 {
1007                   width--;
1008                   *str++ = pad;
1009                   count++;
1010                 }
1011               break;
1012             }
1013           case 's':
1014             {
1015               char *s = va_arg (ap, char *);
1016               int length = strlen (s);
1017               if (precision == -1)
1018                 precision = length;
1019               if (!left_p)
1020                 {
1021                   while (width-- > precision)
1022                     {
1023                       *str++ = pad;
1024                       count++;
1025                     }
1026                   while (width > length)
1027                     {
1028                       *str++ = ' ';
1029                       precision--;
1030                       width--;
1031                       count++;
1032                     }
1033                 }
1034               while (*s)
1035                 {
1036                   if (precision-- <= 0)
1037                     break;
1038                   width--;
1039                   *str++ = *s++;
1040                   count++;
1041                 }
1042               while (width > 0)
1043                 {
1044                   width--;
1045                   *str++ = pad;
1046                   count++;
1047                 }
1048               break;
1049             }
1050           case 'n':
1051             {
1052               int *n = va_arg (ap, int *);
1053               *n = count;
1054               break;
1055             }
1056           default:
1057             {
1058               eputs ("vsprintf: not supported: %:");
1059               eputc (c);
1060               eputs ("\n");
1061               p++;
1062             }
1063           }
1064         p++;
1065       }
1066   va_end (ap);
1067   *str = 0;
1068   return strlen (str);
1069 }
1070
1071 int
1072 sprintf (char *str, char const* format, ...)
1073 {
1074   va_list ap;
1075   va_start (ap, format);
1076   int r = vsprintf (str, format, ap);
1077   va_end (ap);
1078   return r;
1079 }
1080
1081 int
1082 printf (char const* format, ...)
1083 {
1084   va_list ap;
1085   va_start (ap, format);
1086   int r = vprintf (format, ap);
1087   va_end (ap);
1088   return r;
1089 }