mlibc: Tinycc support: itoab, for debugging.
[mes.git] / lib / libc-gcc.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * Mes --- Maxwell Equations of Software
3  * Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
4  *
5  * This file is part of Mes.
6  *
7  * Mes is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or (at
10  * your option) any later version.
11  *
12  * Mes is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Mes.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <stdio.h>
22 #include <mlibc.h>
23
24 #if __GNUC__
25 #include <stdlib.h>
26 #endif
27
28 #if (__GNUC__ || __TINYC__) && !POSIX
29
30 void
31 exit (int code)
32 {
33 #if !__TINYC__
34   asm (
35        "mov    %0,%%ebx\n\t"
36        "mov    $1,%%eax\n\t"
37        "int    $0x80\n\t"
38        : // no outputs "=" (r)
39        : "" (code)
40        );
41 #else // __TINYC__
42   asm (
43        "mov    %0,%%ebx\n\t"
44        "mov    $1,%%eax\n\t"
45        "int    $128\n\t"
46        : // no outputs "=" (r)
47        : "Ir" (code)
48        );
49 #endif // __TINYC__
50   // not reached
51   exit (0);
52 }
53
54 int
55 read (int fd, void* buf, size_t n)
56 {
57 #if !__TINYC__
58   int r;
59   //syscall (SYS_write, fd, s, n));
60   asm (
61        "mov    %1,%%ebx\n\t"
62        "mov    %2,%%ecx\n\t"
63        "mov    %3,%%edx\n\t"
64
65        "movl $0x3,%%eax\n\t"
66        "int  $0x80\n\t"
67
68        "mov    %%eax,%0\n\t"
69        : "=r" (r)
70        : "" (fd), "" (buf), "" (n)
71        : "eax", "ebx", "ecx", "edx"
72        );
73   return r;
74 #endif
75 }
76
77 int
78 write (int fd, char const* s, int n)
79 {
80   int r;
81 #if __GNUC__
82   asm (
83        "mov    %1,%%ebx\n\t"
84        "mov    %2,%%ecx\n\t"
85        "mov    %3,%%edx\n\t"
86
87        "mov    $0x04,%%eax\n\t"
88        "int    $0x80\n\t"
89        "mov    %%eax,%0\n\t"
90        : "=r" (r)
91        : "" (fd), "" (s), "" (n)
92        : "eax", "ebx", "ecx", "edx"
93        );
94
95   //syscall (SYS_write, fd, s, n));
96 #elif __TINYC__
97   asm (
98        "mov    %1,%%ebx\n\t"
99        "mov    %2,%%ecx\n\t"
100        "mov    %3,%%edx\n\t"
101
102        "mov    $4, %%eax\n\t"
103        "int    $128\n\t"
104        "mov    %%eax,%0\n\t"
105        : "=r" (r)
106        : "Ir" (fd), "Ir" (s), "Ir" (n)
107        : "eax", "ebx", "ecx"//, "edx"
108        );
109 #endif
110   return r;
111 }
112
113 int
114 open (char const *s, int flags, ...)
115 {
116 #if !__TINYC__
117   int mode;
118   asm (
119        "mov    %%ebp,%%eax\n\t"
120        "add    $0x10,%%eax\n\t"
121        "mov    (%%eax),%%eax\n\t"
122        "mov    %%eax,%0\n\t"
123        : "=mode" (mode)
124        : //no inputs ""
125        );
126   int r;
127   //syscall (SYS_open, mode));
128   asm (
129        "mov    %1,%%ebx\n\t"
130        "mov    %2,%%ecx\n\t"
131        "mov    %3,%%edx\n\t"
132        "mov    $0x5,%%eax\n\t"
133        "int    $0x80\n\t"
134        "mov    %%eax,%0\n\t"
135        : "=r" (r)
136        : "" (s), "" (flags), "" (mode)
137        : "eax", "ebx", "ecx", "edx"
138        );
139   return r;
140 #endif
141 }
142
143 int
144 chmod (char const *s, int mode)
145 {
146 #if !__TINYC__
147   int r;
148   //syscall (SYS_chmod, mode));
149   asm (
150        "mov    %1,%%ebx\n\t"
151        "mov    %2,%%ecx\n\t"
152        "mov    $0x0f,%%eax\n\t"
153        "int    $0x80\n\t"
154        "mov    %%eax,%0\n\t"
155        : "=r" (r)
156        : "" (s), "" (mode)
157        : "eax", "ebx", "ecx"
158        );
159   return r;
160 #endif
161 }
162
163 int
164 access (char const *s, int mode)
165 {
166 #if !__TINYC__
167   int r;
168   //syscall (SYS_access, mode));
169   asm (
170        "mov    %1,%%ebx\n\t"
171        "mov    %2,%%ecx\n\t"
172        "mov    $0x21,%%eax\n\t"
173        "int    $0x80\n\t"
174        "mov    %%eax,%0\n\t"
175        : "=r" (r)
176        : "" (s), "" (mode)
177        : "eax", "ebx", "ecx"
178        );
179   return r;
180 #endif
181 }
182
183 void *
184 brk (void *p)
185 {
186 #if !__TINYC__
187   void *r;
188   asm (
189        "mov    %1,%%ebx\n\t"
190
191        "mov    $0x2d,%%eax\n\t"
192        "int    $0x80\n\t"
193
194        "mov    %%eax,%0\n\t"
195        : "=r" (r)
196        : "" (p)
197        : "eax", "ebx"
198        );
199   return r;
200 #endif
201 }
202
203 int
204 fsync (int fd)
205 {
206 #if !__TINYC__
207   int r;
208   //syscall (SYS_fsync, fd));
209   asm (
210        "mov    %1,%%ebx\n\t"
211
212        "mov    $0x76, %%eax\n\t"
213        "int    $0x80\n\t"
214        "mov    %%eax,%0\n\t"
215        : "=r" (r)
216        : "" (fd)
217        : "eax", "ebx"
218        );
219   return r;
220 #endif
221 }
222
223 int
224 fputc (int c, int fd)
225 {
226   write (fd, (char*)&c, 1);
227   return 0;
228 }
229
230 void
231 free (void *ptr)
232 {
233 }
234
235 char *g_brk = 0;
236
237 void *
238 malloc (size_t size)
239 {
240   if (!g_brk)
241     g_brk = brk (0);
242   if ((int)brk (g_brk + size) == -1)
243     return 0;
244   char *p = g_brk;
245   g_brk += size;
246   return p;
247 }
248
249 void *
250 memcpy (void *dest, void const *src, size_t n)
251 {
252   char* p = dest;
253   char const* q = src;
254   while (n--) *p++ = *q++;
255   return dest;
256 }
257
258 int
259 putchar (int c)
260 {
261   write (STDOUT, (char*)&c, 1);
262   return 0;
263 }
264
265 void *
266 realloc (void *ptr, size_t size)
267 {
268   void *new = malloc (size);
269   if (ptr && new)
270     {
271       memcpy (new, ptr, size);
272       free (ptr);
273     }
274   return new;
275 }
276
277 size_t
278 strlen (char const* s)
279 {
280   int i = 0;
281   while (s[i]) i++;
282   return i;
283 }
284
285 int
286 strcmp (char const* a, char const* b)
287 {
288   while (*a && *b && *a == *b) {a++;b++;}
289   return *a - *b;
290 }
291
292 char *
293 strcpy (char *dest, char const *src)
294 {
295   char *p = dest;
296   while (*src) *p++ = *src++;
297   *p = 0;
298   return dest;
299 }
300
301 int
302 fputs (char const* s, int fd)
303 {
304   int i = strlen (s);
305   write (fd, s, i);
306   return 0;
307 }
308
309 int
310 puts (char const* s)
311 {
312   int i = strlen (s);
313   write (STDOUT, s, i);
314   return 0;
315 }
316
317 void
318 assert_fail (char* s)
319 {
320   eputs ("assert fail: ");
321   eputs (s);
322   eputs ("\n");
323   *((int*)0) = 0;
324 }
325
326 #define assert(x) ((x) ? (void)0 : assert_fail (#x))
327
328 int ungetc_char = -1;
329 char ungetc_buf[2];
330
331 int
332 getchar ()
333 {
334   char c;
335   int i;
336   if (ungetc_char == -1)
337     {
338       int r = read (g_stdin, &c, 1);
339       if (r < 1) return -1;
340       i = c;
341     }
342   else
343     i = ungetc_buf[ungetc_char--];
344
345   if (i < 0) i += 256;
346
347   return i;
348 }
349
350 int
351 ungetc (int c, int fd)
352 {
353   assert (ungetc_char < 2);
354   ungetc_buf[++ungetc_char] = c;
355   return c;
356 }
357
358 char const* itoa (int);
359
360 int
361 strncmp (char const* a, char const* b, size_t length)
362 {
363   while (*a && *b && *a == *b && --length) {a++;b++;}
364   return *a - *b;
365 }
366
367 char *
368 getenv (char const* s)
369 {
370   char **p = g_environment;
371   int length = strlen (s);
372   while (*p)
373     {
374       if (!strncmp (s, *p, length) && *(*p + length) == '=') return (*p + length + 1);
375       p++;
376     }
377   return 0;
378 }
379
380 int
381 isdigit (int c)
382 {
383   return (c>='0') && (c<='9');
384 }
385
386 int
387 isxdigit (int c)
388 {
389   return isdigit (c) || (c>='a') && (c<='f');
390 }
391
392 int
393 isnumber (int c, int base)
394 {
395   if (base == 2)
396     return (c>='0') && (c<='1');
397   if (base == 8)
398     return (c>='0') && (c<='7');
399   if (base == 10)
400     return isdigit (c);
401   if (base == 16)
402     return isxdigit (c);
403 }
404
405 int
406 _atoi (char const **p, int base)
407 {
408   char const *s = *p;
409   int i = 0;
410   int sign = 1;
411   if (!base) base = 10;
412   if (*s && *s == '-')
413     {
414       sign = -1;
415       s++;
416     }
417   while (isnumber (*s, base))
418     {
419       i *= base;
420       int m = *s > '9' ? 'a' - 10 : '0';
421       i += *s - m;
422       s++;
423     }
424   *p = s;
425   return i * sign;
426 }
427
428 int
429 atoi (char const *s)
430 {
431   char const *p = s;
432   return _atoi (&p, 0);
433 }
434
435 // FIXME: copied from libc-mes.c now
436 #include <stdarg.h>
437
438 int
439 vprintf (char const* format, va_list ap)
440 {
441   char const *p = format;
442   while (*p)
443     if (*p != '%')
444       putchar (*p++);
445     else
446       {
447         p++;
448         char c = *p;
449         switch (c)
450           {
451           case '%': {putchar (*p); break;}
452           case 'c': {char c; c = va_arg (ap, char); putchar (c); break;}
453           case 'd': {int d; d = va_arg (ap, int); puts (itoa (d)); break;}
454           case 's': {char *s; s = va_arg (ap, char *); puts (s); break;}
455           default: putchar (*p);
456           }
457         p++;
458       }
459   va_end (ap);
460   return 0;
461 }
462
463 int
464 printf (char const* format, ...)
465 {
466   va_list ap;
467   va_start (ap, format);
468   int r = vprintf (format, ap);
469   va_end (ap);
470   return r;
471 }
472
473 int
474 vsprintf (char *str, char const* format, va_list ap)
475 {
476   char const *p = format;
477   while (*p)
478     if (*p != '%')
479       *str++ = *p++;
480     else
481       {
482         p++;
483         char c = *p;
484         switch (c)
485           {
486           case '%': {*str++ = *p; break;}
487           case 'c': {char c; c = va_arg (ap, char); *str++ = c; break;}
488           case 'd': {int d; d = va_arg (ap, int); char const *s = itoa (d); while (*s) *str++ = *s++; break;}
489           case 's': {char *s; s = va_arg (ap, char *); while (*s) *str++ = *s++; break;}
490           default: *str++ = *p;
491           }
492         p++;
493       }
494
495   *str = 0;
496   return strlen (str);
497 }
498
499 int
500 sprintf (char *str, char const* format, ...)
501 {
502   va_list ap;
503   va_start (ap, format);
504   int r = vsprintf (str, format, ap);
505   va_end (ap);
506   return r;
507 }
508 #endif
509
510 char itoa_buf[10];
511
512 char const*
513 itoa (int x)
514 {
515   //static char itoa_buf[10];
516   //char *p = buf+9;
517   char *p = itoa_buf;
518   p += 9;
519   *p-- = 0;
520
521   //int sign = x < 0;
522   int sign;
523   sign = x < 0;
524   if (sign)
525     x = -x;
526
527   do
528     {
529       *p-- = '0' + (x % 10);
530       x = x / 10;
531     } while (x);
532
533   if (sign)
534     *p-- = '-';
535
536   return p+1;
537 }
538
539 char const*
540 itoab (int x, int base)
541 {
542   //static char itoa_buf[10];
543   //char *p = buf+9;
544   char *p = itoa_buf;
545   p += 9;
546   *p-- = 0;
547
548   //int sign = x < 0; // FIXME
549   int sign = 0;
550   if (x < 0) sign = 1;
551   if (sign)
552     x = -x;
553
554   do
555      {
556        int i = x % base;
557        *p-- = i > 9 ? 'a' + i - 10 : '0' + i;
558        x = x / base;
559      } while (x);
560
561   if (sign && *(p + 1) != '0')
562     *p-- = '-';
563
564   return p+1;
565 }
566
567 #if POSIX
568 #define _GNU_SOURCE
569 #include <assert.h>
570 #include <fcntl.h>
571 #include <string.h>
572 #include <unistd.h>
573 #endif // POSIX
574
575 int
576 fdputs (char const* s, int fd)
577 {
578   int i = strlen (s);
579   write (fd, s, i);
580   return 0;
581 }
582
583 int
584 eputc (int c)
585 {
586   return fdputc (c, STDERR);
587 }
588
589 int
590 eputs (char const* s)
591 {
592   return fdputs (s, STDERR);
593 }
594
595 int
596 fdputc (int c, int fd)
597 {
598   write (fd, (char*)&c, 1);
599   return 0;
600 }
601
602 #if POSIX
603
604 int
605 putchar (int c)
606 {
607   write (STDOUT, (char*)&c, 1);
608   return 0;
609 }
610
611 int ungetc_char = -1;
612 char ungetc_buf[2];
613
614 int
615 getchar ()
616 {
617   char c;
618   int i;
619   if (ungetc_char == -1)
620     {
621       int r = read (g_stdin, &c, 1);
622       if (r < 1) return -1;
623       i = c;
624     }
625   else
626     i = ungetc_buf[ungetc_char--];
627
628   if (i < 0) i += 256;
629
630   return i;
631 }
632
633 int
634 fdungetc (int c, int fd)
635 {
636   assert (ungetc_char < 2);
637   ungetc_buf[++ungetc_char] = c;
638   return c;
639 }
640
641 #endif // POSIX