620742ba6f2572be0e6d64e176c72d137529a310
[mes.git] / libc / mlibc.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 char **g_environment = 0;
22 int g_stdin = 0;
23
24 #include <stdio.h>
25 #include <mlibc.h>
26
27 #if __GNUC__ && !POSIX
28
29 #include <stdlib.h>
30
31 void
32 exit (int code)
33 {
34   asm (
35        "movl %0,%%ebx\n\t"
36        "movl $1,%%eax\n\t"
37        "int  $0x80"
38        : // no outputs "=" (r)
39        : "" (code)
40        );
41   // not reached
42   exit (0);
43 }
44
45 int
46 read (int fd, void* buf, size_t n)
47 {
48   int r;
49   //syscall (SYS_write, fd, s, n));
50   asm (
51        "movl %1,%%ebx\n\t"
52        "movl %2,%%ecx\n\t"
53        "movl %3,%%edx\n\t"
54
55        "movl $0x3,%%eax\n\t"
56        "int  $0x80\n\t"
57
58        "mov %%eax,%0\n\t"
59        : "=r" (r)
60        : "" (fd), "" (buf), "" (n)
61        : "eax", "ebx", "ecx", "edx"
62        );
63   return r;
64 }
65
66 int
67 write (int fd, char const* s, int n)
68 {
69   int r;
70   //syscall (SYS_write, fd, s, n));
71   asm (
72        "mov %1,%%ebx\n\t"
73        "mov %2,%%ecx\n\t"
74        "mov %3,%%edx\n\t"
75
76        "mov $0x4, %%eax\n\t"
77        "int $0x80\n\t"
78        "mov %%eax,%0\n\t"
79        : "=r" (r)
80        : "" (fd), "" (s), "" (n)
81        : "eax", "ebx", "ecx", "edx"
82        );
83   return r;
84 }
85
86 int
87 open (char const *s, int flags, ...)
88 {
89   int mode;
90   asm (
91        "mov %%ebp,%%eax\n\t"
92        "add $0x10,%%eax\n\t"
93        "mov (%%eax),%%eax\n\t"
94        "mov %%eax,%0\n\t"
95        : "=mode" (mode)
96        : //no inputs ""
97        );
98   int r;
99   //syscall (SYS_open, mode));
100   asm (
101        "mov %1,%%ebx\n\t"
102        "mov %2,%%ecx\n\t"
103        "mov %3,%%edx\n\t"
104        "mov $0x5,%%eax\n\t"
105        "int $0x80\n\t"
106        "mov %%eax,%0\n\t"
107        : "=r" (r)
108        : "" (s), "" (flags), "" (mode)
109        : "eax", "ebx", "ecx", "edx"
110        );
111   return r;
112 }
113
114 int
115 access (char const *s, int mode)
116 {
117   int r;
118   //syscall (SYS_access, mode));
119   asm (
120        "mov %1,%%ebx\n\t"
121        "mov %2,%%ecx\n\t"
122        "mov $0x21,%%eax\n\t"
123        "int $0x80\n\t"
124        "mov %%eax,%0\n\t"
125        : "=r" (r)
126        : "" (s), "" (mode)
127        : "eax", "ebx", "ecx"
128        );
129   return r;
130 }
131
132 void *
133 brk (void *p)
134 {
135   void *r;
136   asm (
137        "mov %1,%%ebx\n\t"
138
139        "mov $0x2d,%%eax\n\t"
140        "int $0x80\n\t"
141
142        "mov %%eax,%0\n\t"
143        : "=r" (r)
144        : "" (p)
145        : "eax", "ebx"
146        );
147   return r;
148 }
149
150 int
151 fsync (int fd)
152 {
153   int r;
154   //syscall (SYS_fsync, fd));
155   asm (
156        "mov %1,%%ebx\n\t"
157
158        "mov $0x76, %%eax\n\t"
159        "int $0x80\n\t"
160        "mov %%eax,%0\n\t"
161        : "=r" (r)
162        : "" (fd)
163        : "eax", "ebx"
164        );
165   return r;
166 }
167
168 int
169 fputc (int c, int fd)
170 {
171   write (fd, (char*)&c, 1);
172   return 0;
173 }
174
175 int
176 putchar (int c)
177 {
178   write (STDOUT, (char*)&c, 1);
179   return 0;
180 }
181
182 void *g_malloc_base = 0;
183
184 void *
185 malloc (size_t size)
186 {
187   void *p = brk (0);
188   if (!g_malloc_base) g_malloc_base = p;
189   brk (p+size);
190   return p;
191 }
192
193 void *
194 realloc (void *p, size_t size)
195 {
196   (void)p;
197   brk (g_malloc_base + size);
198   return g_malloc_base;
199 }
200
201 void
202 free (void *p)
203 {
204   int *n = (int*)p-1;
205   //munmap ((void*)p, *n);
206 }
207
208 size_t
209 strlen (char const* s)
210 {
211   int i = 0;
212   while (s[i]) i++;
213   return i;
214 }
215
216 int
217 strcmp (char const* a, char const* b)
218 {
219   while (*a && *b && *a == *b) {a++;b++;}
220   return *a - *b;
221 }
222
223 char *
224 strcpy (char *dest, char const *src)
225 {
226   char *p = dest;
227   while (*src) *p++ = *src++;
228   *p = 0;
229   return dest;
230 }
231
232 int
233 eputs (char const* s)
234 {
235   int i = strlen (s);
236   write (STDERR, s, i);
237   return 0;
238 }
239
240 int
241 fputs (char const* s, int fd)
242 {
243   int i = strlen (s);
244   write (fd, s, i);
245   return 0;
246 }
247
248 int
249 puts (char const* s)
250 {
251   int i = strlen (s);
252   write (STDOUT, s, i);
253   return 0;
254 }
255
256 void
257 assert_fail (char* s)
258 {
259   eputs ("assert fail: ");
260   eputs (s);
261   eputs ("\n");
262   *((int*)0) = 0;
263 }
264
265 #define assert(x) ((x) ? (void)0 : assert_fail (#x))
266
267 int ungetc_char = -1;
268 char ungetc_buf[2];
269
270 int
271 getchar ()
272 {
273   char c;
274   int i;
275   if (ungetc_char == -1)
276     {
277       int r = read (g_stdin, &c, 1);
278       if (r < 1) return -1;
279       i = c;
280     }
281   else
282     i = ungetc_buf[ungetc_char--];
283
284   if (i < 0) i += 256;
285
286   return i;
287 }
288
289 int
290 ungetc (int c, int fd)
291 {
292   assert (ungetc_char < 2);
293   ungetc_buf[++ungetc_char] = c;
294   return c;
295 }
296
297 char const* itoa (int);
298
299 int
300 strncmp (char const* a, char const* b, size_t length)
301 {
302   while (*a && *b && *a == *b && --length) {a++;b++;}
303   return *a - *b;
304 }
305
306 char const*
307 getenv (char const* s)
308 {
309   char **p = g_environment;
310   int length = strlen (s);
311   while (*p)
312     {
313       if (!strncmp (s, *p, length) && *(*p + length) == '=') return (*p + length + 1);
314       p++;
315     }
316   return 0;
317 }
318
319 int
320 isdigit (int c)
321 {
322   return (c>='0') && (c<='9');
323 }
324
325 int
326 atoi (char const *s)
327 {
328   int i = 0;
329   int sign = 1;
330   if (*s && *s == '-')
331     {
332       sign = -1;
333       s++;
334     }
335   while (isdigit (*s))
336     {
337       i *= 10;
338       i += (*s - '0');
339       s++;
340     }
341   return i * sign;
342 }
343
344 int
345 printf (char const* format, ...)
346 {
347   int va_arg = 0;
348   int va;
349   char const *p = format;
350   while (*p)
351     if (*p != '%')
352       putchar (*p++);
353     else
354       {
355         p++;
356         char c = *p;
357         switch (c)
358           {
359           case '%': {putchar (*p); break;}
360           case 'c':
361             {
362             asm (
363                  "mov    -0xc(%%ebp),%%eax\n\t"
364                  "shl     $0x2,%%eax\n\t"
365                  "add     %%ebp,%%eax\n\t"
366                  "add     $0xc,%%eax\n\t"
367                  "mov     (%%eax),%%eax\n\t"
368                  //"mov     %%eax,%0\n\t"
369                  : "=va" (va)
370                  : //no inputs ""
371                  );
372             putchar ((char)va);
373             va_arg++;
374             break;
375             }
376           case 'd': {
377             asm (
378                  "mov    -0xc(%%ebp),%%eax\n\t"
379                  "shl     $0x2,%%eax\n\t"
380                  "add     %%ebp,%%eax\n\t"
381                  "add     $0xc,%%eax\n\t"
382                  "mov     (%%eax),%%eax\n\t"
383                  //"mov     %%eax,%0\n\t"
384                  : "=va" (va)
385                  : //no inputs ""
386                  );
387             puts (itoa ((int)va));
388             va_arg++;
389             break;
390           }
391           case 's': {
392             asm (
393                  "mov    -0xc(%%ebp),%%eax\n\t"
394                  "shl     $0x2,%%eax\n\t"
395                  "add     %%ebp,%%eax\n\t"
396                  "add     $0xc,%%eax\n\t"
397                  "mov     (%%eax),%%eax\n\t"
398                  //"mov     %%eax,%0\n\t"
399                  : "=va" (va)
400                  : //no inputs ""
401                  );
402             puts ((char*)va);
403             va_arg++;
404             break;
405           }
406           default: putchar (*p);
407           }
408         p++;
409       }
410   return 0;
411 }
412 #endif
413
414 char itoa_buf[10];
415
416 char const*
417 itoa (int x)
418 {
419   //static char itoa_buf[10];
420   //char *p = buf+9;
421   char *p = itoa_buf;
422   p += 9;
423   *p-- = 0;
424
425   //int sign = x < 0;
426   int sign;
427   sign = x < 0;
428   if (sign)
429     x = -x;
430
431   do
432     {
433       *p-- = '0' + (x % 10);
434       x = x / 10;
435     } while (x);
436
437   if (sign)
438     *p-- = '-';
439
440   return p+1;
441 }
442
443 #if POSIX
444 #define _GNU_SOURCE
445 #include <assert.h>
446 #include <fcntl.h>
447 #include <string.h>
448 #include <unistd.h>
449 #endif // POSIX
450
451 int
452 fdputs (char const* s, int fd)
453 {
454   int i = strlen (s);
455   write (fd, s, i);
456   return 0;
457 }
458
459 #if POSIX
460
461 int
462 fdputc (int c, int fd)
463 {
464   write (fd, (char*)&c, 1);
465   return 0;
466 }
467
468 int
469 putchar (int c)
470 {
471   write (STDOUT, (char*)&c, 1);
472   return 0;
473 }
474
475 int ungetc_char = -1;
476 char ungetc_buf[2];
477
478 int
479 getchar ()
480 {
481   char c;
482   int i;
483   if (ungetc_char == -1)
484     {
485       int r = read (g_stdin, &c, 1);
486       if (r < 1) return -1;
487       i = c;
488     }
489   else
490     i = ungetc_buf[ungetc_char--];
491
492   if (i < 0) i += 256;
493
494   return i;
495 }
496
497 int
498 fdungetc (int c, int fd)
499 {
500   assert (ungetc_char < 2);
501   ungetc_buf[++ungetc_char] = c;
502   return c;
503 }
504
505 #endif // POSIX