core: Support fork, waitpid, execve.
[mes.git] / lib / libc.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * Mes --- Maxwell Equations of Software
3  * Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
4  * Copyright © 2018 Jeremiah Orians <jeremiah@pdp10.guru>
5  *
6  * This file is part of Mes.
7  *
8  * Mes is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or (at
11  * your option) any later version.
12  *
13  * Mes is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Mes.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <sys/ioctl.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25
26 #if POSIX
27 #define _GNU_SOURCE
28 #include <assert.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <unistd.h>
32 #endif // POSIX
33
34 int
35 isdigit (int c)
36 {
37   return (c>='0') && (c<='9');
38 }
39
40 int
41 isxdigit (int c)
42 {
43   return isdigit (c) || (c>='a') && (c<='f');
44 }
45
46 int
47 isspace (int c)
48 {
49   return (c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r' || c == ' ');
50 }
51
52 int
53 isnumber (int c, int base)
54 {
55   if (base == 2)
56     return (c>='0') && (c<='1');
57   if (base == 8)
58     return (c>='0') && (c<='7');
59   if (base == 10)
60     return isdigit (c);
61   if (base == 16)
62     return isxdigit (c);
63 }
64
65 int
66 abtoi (char const **p, int base)
67 {
68   char const *s = *p;
69   int i = 0;
70   int sign = 1;
71   if (!base) base = 10;
72   if (*s && *s == '-')
73     {
74       sign = -1;
75       s++;
76     }
77   while (isnumber (*s, base))
78     {
79       i *= base;
80       int m = *s > '9' ? 'a' - 10 : '0';
81       i += *s - m;
82       s++;
83     }
84   *p = s;
85   return i * sign;
86 }
87
88 int
89 atoi (char const *s)
90 {
91   char const *p = s;
92   return abtoi (&p, 0);
93 }
94
95 char const*
96 itoa (int x)
97 {
98   static char itoa_buf[12];
99   char *p = itoa_buf + 11;
100   *p-- = 0;
101
102   int sign = 0;
103   unsigned u = x;
104   if (x < 0)
105     {
106       sign = 1;
107       u = -x;
108     }
109
110   do
111      {
112        *p-- = '0' + (u % 10);
113        u = u / 10;
114      } while (u);
115
116   if (sign && *(p + 1) != '0')
117     *p-- = '-';
118
119   return p+1;
120 }
121
122 char const*
123 itoab (int x, int base)
124 {
125   static char itoa_buf[12];
126   char *p = itoa_buf + 11;
127   *p-- = 0;
128
129   int sign = 0;
130   unsigned u = x;
131   if (x < 0)
132     {
133       sign = 1;
134       u = -x;
135     }
136
137   do
138      {
139        int i = u % base;
140        *p-- = i > 9 ? 'a' + i - 10 : '0' + i;
141        x = u / base;
142      } while (u);
143
144   if (sign && *(p + 1) != '0')
145     *p-- = '-';
146
147   return p+1;
148 }
149
150 int
151 fdputc (int c, int fd)
152 {
153   write (fd, (char*)&c, 1);
154   return 0;
155 }
156
157 int
158 fdputs (char const* s, int fd)
159 {
160   int i = strlen (s);
161   write (fd, s, i);
162   return 0;
163 }
164
165 #if !POSIX
166
167 ///char **g_environment = 0; // FIXME: todo extern
168 int g_stdin = 0;
169
170 void _env ();
171
172 int
173 eputc (int c)
174 {
175   return fdputc (c, STDERR);
176 }
177
178 FILE*
179 fopen (char const* file_name, char const* mode)
180 {
181   FILE* f;
182   if ('w' == mode[0])
183     /* 577 is O_WRONLY|O_CREAT|O_TRUNC, 384 is 600 in octal */
184     f = open (file_name, 577 , 384);
185   else
186     /* Everything else is a read */
187     f = open (file_name, 0, 0);
188
189   /* Negative numbers are error codes */
190   if (0 > f)
191     return 0;
192
193   return f;
194 }
195
196 int
197 putchar (int c)
198 {
199   write (STDOUT, (char*)&c, 1);
200   return 0;
201 }
202
203 void
204 assert_fail (char* s)
205 {
206   eputs ("assert fail: ");
207   eputs (s);
208   eputs ("\n");
209   //*((int*)0) = 0;
210   char *fail = s;
211   fail = 0;
212   *fail = 0;
213 }
214
215 int ungetc_char = -1;
216 char ungetc_buf[2];
217
218 int
219 getchar ()
220 {
221   char c;
222   int i;
223   if (ungetc_char == -1)
224     {
225       int r = read (g_stdin, &c, 1);
226       if (r < 1) return -1;
227       i = c;
228    }
229   else
230     {
231        //FIXME
232        //i = ungetc_buf[ungetc_char--];
233        i = ungetc_buf[ungetc_char];
234        //ungetc_char--;
235        ungetc_char = ungetc_char - 1;
236      }
237   if (i < 0) i += 256;
238
239   return i;
240 }
241
242 int
243 fgetc (int fd)
244 {
245   char c;
246   int i;
247   int r = read (fd, &c, 1);
248   if (r < 1) return -1;
249   i = c;
250   return i;
251 }
252
253 void
254 free (void *ptr)
255 {
256 }
257
258 //#define assert(x) ((x) ? (void)0 : assert_fail (#x))
259 int
260 ungetc (int c, int fd)
261 {
262   //FIXME
263   //assert (ungetc_char < 2);
264   //assert (ungetc_char == -1 || ungetc_char < 2);
265   //FIXME
266   //ungetc_buf[++ungetc_char] = c;
267   ungetc_char++;
268   ungetc_buf[ungetc_char] = c;
269   return c;
270 }
271
272 int
273 strcmp (char const* a, char const* b)
274 {
275   while (*a && *b && *a == *b)
276     {
277       a++;b++;
278     }
279   return *a - *b;
280 }
281
282
283 char *
284 strcpy (char *dest, char const *src)
285 {
286   char *p = dest;
287   while (*src) *p++ = *src++;
288   *p = 0;
289   return dest;
290 }
291
292 char *g_brk = 0;
293
294 void *
295 malloc (size_t size)
296 {
297   if (!g_brk)
298     g_brk = brk (0);
299   if (brk (g_brk + size) == (void*)-1)
300     return 0;
301   char *p = g_brk;
302   g_brk += size;
303   return p;
304 }
305
306 void *
307 memcpy (void *dest, void const *src, size_t n)
308 {
309   char* p = dest;
310   char const* q = src;
311   while (n--) *p++ = *q++;
312   return dest;
313 }
314
315 void *
316 realloc (void *ptr, size_t size)
317 {
318   void *new = malloc (size);
319   if (ptr && new)
320     {
321       memcpy (new, ptr, size);
322       free (ptr);
323     }
324   return new;
325 }
326
327 int
328 strncmp (char const* a, char const* b, size_t length)
329 {
330   while (*a && *b && *a == *b && --length) {a++;b++;}
331   return *a - *b;
332 }
333
334 char *
335 getenv (char const* s)
336 {
337   char **p = g_environment;
338   int length = strlen (s);
339   while (*p)
340     {
341       if (!strncmp (s, *p, length) && *(*p + length) == '=') return (*p + length + 1);
342       p++;
343     }
344   return 0;
345 }
346
347 int
348 setenv (char const* s, char const* v, int overwrite_p)
349 {
350   char **p = g_environment;
351   int length = strlen (s);
352   while (*p)
353     {
354       if (!strncmp (s, *p, length) && *(*p + length) == '=')
355         break;
356       p++;
357     }
358   char *entry = malloc (length + strlen (v) + 2);
359   int end_p = *p == 0;
360   *p = entry;
361   strcpy (entry, s);
362   strcpy (entry + length, "=");
363   strcpy (entry + length + 1, v);
364   *(entry + length + strlen (v) + 2) = 0;
365   if (end_p)
366     *++p = 0;
367   return 0;
368 }
369
370 int
371 vprintf (char const* format, va_list ap)
372 {
373   char const *p = format;
374   while (*p)
375     if (*p != '%')
376       putchar (*p++);
377     else
378       {
379         p++;
380         char c = *p;
381         switch (c)
382           {
383           case '%': {putchar (*p); break;}
384           case 'c': {char c; c = va_arg (ap, char); putchar (c); break;}
385           case 'd': {int d; d = va_arg (ap, int); puts (itoa (d)); break;}
386           case 's': {char *s; s = va_arg (ap, char *); puts (s); break;}
387           default: {putchar (*p); break;}
388           }
389         p++;
390       }
391   va_end (ap);
392   return 0;
393 }
394
395 int
396 printf (char const* format, ...)
397 {
398   va_list ap;
399   va_start (ap, format);
400   int r = vprintf (format, ap);
401   va_end (ap);
402   return r;
403 }
404
405 int
406 vsprintf (char *str, char const* format, va_list ap)
407 {
408   char const *p = format;
409   while (*p)
410     if (*p != '%')
411       *str++ = *p++;
412     else
413       {
414         p++;
415         char c = *p;
416         switch (c)
417           {
418           case '%': {*str++ = *p; break;}
419           case 'c': {char c; c = va_arg (ap, char); *str++ = c; break;}
420           case 'd': {int d; d = va_arg (ap, int); char const *s; s = itoa (d); while (*s) *str++ = *s++; break;}
421           case 's': {char *s; s = va_arg (ap, char *); while (*s) *str++ = *s++; break;}
422           default: {*str++ = *p; break;}
423           }
424         p++;
425       }
426   va_end (ap);
427   *str = 0;
428   return strlen (str);
429 }
430
431 int
432 sprintf (char *str, char const* format, ...)
433 {
434   va_list ap;
435   va_start (ap, format);
436   int r = vsprintf (str, format, ap);
437   va_end (ap);
438   return r;
439 }
440
441 int
442 isatty (int fd)
443 {
444   return ioctl (fd, TCGETS, 0) & 0xf0;
445 }
446
447 int
448 wait (int *status_ptr)
449 {
450   return waitpid  (-1, status_ptr, 0);
451 }
452
453 #endif //!POSIX