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