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