8a8af86b0279e4bdb84340b507cb15115430c679
[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 int
179 fputc (int c, FILE* stream)
180 {
181   return fdputc (c, (int)stream);
182 }
183
184 int
185 fputs (char const* s, FILE* stream)
186 {
187   return fdputs (s, (int)stream);
188 }
189
190 int
191 putc (int c, FILE* stream)
192 {
193   return fdputc (c, (int)stream);
194 }
195
196 FILE*
197 fopen (char const* file_name, char const* mode)
198 {
199   FILE* f;
200   if ('w' == mode[0])
201     /* 577 is O_WRONLY|O_CREAT|O_TRUNC, 384 is 600 in octal */
202     f = open (file_name, 577 , 384);
203   else
204     /* Everything else is a read */
205     f = open (file_name, 0, 0);
206
207   /* Negative numbers are error codes */
208   if (0 > f)
209     return 0;
210
211   return f;
212 }
213
214 int
215 putchar (int c)
216 {
217   write (STDOUT, (char*)&c, 1);
218   return 0;
219 }
220
221 void
222 assert_fail (char* s)
223 {
224   eputs ("assert fail: ");
225   eputs (s);
226   eputs ("\n");
227   //*((int*)0) = 0;
228   char *fail = s;
229   fail = 0;
230   *fail = 0;
231 }
232
233 int ungetc_char = -1;
234 char ungetc_buf[2];
235
236 int
237 getchar ()
238 {
239   char c;
240   int i;
241   if (ungetc_char == -1)
242     {
243       int r = read (g_stdin, &c, 1);
244       if (r < 1) return -1;
245       i = c;
246    }
247   else
248     {
249        //FIXME
250        //i = ungetc_buf[ungetc_char--];
251        i = ungetc_buf[ungetc_char];
252        //ungetc_char--;
253        ungetc_char = ungetc_char - 1;
254      }
255   if (i < 0) i += 256;
256
257   return i;
258 }
259
260 int
261 fgetc (int fd)
262 {
263   char c;
264   int i;
265   int r = read (fd, &c, 1);
266   if (r < 1) return -1;
267   i = c;
268   return i;
269 }
270
271 void
272 free (void *ptr)
273 {
274 }
275
276 //#define assert(x) ((x) ? (void)0 : assert_fail (#x))
277 int
278 ungetc (int c, int fd)
279 {
280   //FIXME
281   //assert (ungetc_char < 2);
282   //assert (ungetc_char == -1 || ungetc_char < 2);
283   //FIXME
284   //ungetc_buf[++ungetc_char] = c;
285   ungetc_char++;
286   ungetc_buf[ungetc_char] = c;
287   return c;
288 }
289
290 int
291 strcmp (char const* a, char const* b)
292 {
293   while (*a && *b && *a == *b)
294     {
295       a++;b++;
296     }
297   return *a - *b;
298 }
299
300
301 char *
302 strcpy (char *dest, char const *src)
303 {
304   char *p = dest;
305   while (*src) *p++ = *src++;
306   *p = 0;
307   return dest;
308 }
309
310 char *g_brk = 0;
311
312 void *
313 malloc (size_t size)
314 {
315   if (!g_brk)
316     g_brk = brk (0);
317   if (brk (g_brk + size) == (void*)-1)
318     return 0;
319   char *p = g_brk;
320   g_brk += size;
321   return p;
322 }
323
324 void *
325 memcpy (void *dest, void const *src, size_t n)
326 {
327   char* p = dest;
328   char const* q = src;
329   while (n--) *p++ = *q++;
330   return dest;
331 }
332
333 void *
334 realloc (void *ptr, size_t size)
335 {
336   void *new = malloc (size);
337   if (ptr && new)
338     {
339       memcpy (new, ptr, size);
340       free (ptr);
341     }
342   return new;
343 }
344
345 int
346 strncmp (char const* a, char const* b, size_t length)
347 {
348   while (*a && *b && *a == *b && --length) {a++;b++;}
349   return *a - *b;
350 }
351
352 size_t
353 fwrite (void const *data, size_t size, size_t count, FILE *stream)
354 {
355   if (! size || !count)
356     return 0;
357   int bytes = write ((int)stream, data, size * count);
358   if (bytes > 0)
359     //return bytes/size;
360     return count;
361   return bytes;
362 }
363
364 char *
365 getenv (char const* s)
366 {
367   char **p = g_environment;
368   int length = strlen (s);
369   while (*p)
370     {
371       if (!strncmp (s, *p, length) && *(*p + length) == '=') return (*p + length + 1);
372       p++;
373     }
374   return 0;
375 }
376
377 int
378 setenv (char const* s, char const* v, int overwrite_p)
379 {
380   char **p = g_environment;
381   int length = strlen (s);
382   while (*p)
383     {
384       if (!strncmp (s, *p, length) && *(*p + length) == '=')
385         break;
386       p++;
387     }
388   char *entry = malloc (length + strlen (v) + 2);
389   int end_p = *p == 0;
390   *p = entry;
391   strcpy (entry, s);
392   strcpy (entry + length, "=");
393   strcpy (entry + length + 1, v);
394   *(entry + length + strlen (v) + 2) = 0;
395   if (end_p)
396     *++p = 0;
397   return 0;
398 }
399
400 int
401 vprintf (char const* format, va_list ap)
402 {
403   char const *p = format;
404   while (*p)
405     if (*p != '%')
406       putchar (*p++);
407     else
408       {
409         p++;
410         char c = *p;
411         switch (c)
412           {
413           case '%': {putchar (*p); break;}
414           case 'c': {char c; c = va_arg (ap, char); putchar (c); break;}
415           case 'd': {int d; d = va_arg (ap, int); puts (itoa (d)); break;}
416           case 's': {char *s; s = va_arg (ap, char *); puts (s); break;}
417           default: {putchar (*p); break;}
418           }
419         p++;
420       }
421   va_end (ap);
422   return 0;
423 }
424
425 int
426 printf (char const* format, ...)
427 {
428   va_list ap;
429   va_start (ap, format);
430   int r = vprintf (format, ap);
431   va_end (ap);
432   return r;
433 }
434
435 int
436 vsprintf (char *str, char const* format, va_list ap)
437 {
438   char const *p = format;
439   while (*p)
440     if (*p != '%')
441       *str++ = *p++;
442     else
443       {
444         p++;
445         char c = *p;
446         switch (c)
447           {
448           case '%': {*str++ = *p; break;}
449           case 'c': {char c; c = va_arg (ap, char); *str++ = c; break;}
450           case 'd': {int d; d = va_arg (ap, int); char const *s; s = itoa (d); while (*s) *str++ = *s++; break;}
451           case 's': {char *s; s = va_arg (ap, char *); while (*s) *str++ = *s++; break;}
452           default: {*str++ = *p; break;}
453           }
454         p++;
455       }
456   va_end (ap);
457   *str = 0;
458   return strlen (str);
459 }
460
461 int
462 sprintf (char *str, char const* format, ...)
463 {
464   va_list ap;
465   va_start (ap, format);
466   int r = vsprintf (str, format, ap);
467   va_end (ap);
468   return r;
469 }
470
471 int
472 isatty (int fd)
473 {
474   return ioctl (fd, TCGETS, 0) & 0xf0;
475 }
476
477 int
478 wait (int *status_ptr)
479 {
480   return waitpid  (-1, status_ptr, 0);
481 }
482
483 #endif //!POSIX