mescc: Support binutils 2.15a: fread: read ungetc'd chars too.
[mes.git] / lib / libmes.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * Mes --- Maxwell Equations of Software
3  * Copyright © 2016,2017,2018 Jan (janneke) 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 <libmes.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 int
26 isdigit (int c)
27 {
28   return c >= '0' && c <= '9';
29 }
30
31 int
32 isxdigit (int c)
33 {
34   return isdigit (c) || c >= 'a' && c <= 'f';
35 }
36
37 int
38 isspace (int c)
39 {
40   return (c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r' || c == ' ');
41 }
42
43 int
44 isnumber (int c, int base)
45 {
46   if (base == 2)
47     return (c >= '0') && (c <= '1');
48   if (base == 8)
49     return (c >= '0') && (c <= '7');
50   if (base == 10)
51     return isdigit (c);
52   if (base == 16)
53     return isxdigit (c);
54 }
55
56 int
57 abtoi (char const **p, int base)
58 {
59   char const *s = *p;
60   int i = 0;
61   int sign = 1;
62   if (!base) base = 10;
63   if (*s && *s == '-')
64     {
65       sign = -1;
66       s++;
67     }
68   while (isnumber (*s, base))
69     {
70       i *= base;
71       int m = *s > '9' ? 'a' - 10 : '0';
72       i += *s - m;
73       s++;
74     }
75   *p = s;
76   return i * sign;
77 }
78
79 int
80 atoi (char const *s)
81 {
82   char const *p = s;
83   return abtoi (&p, 0);
84 }
85
86 char const*
87 number_to_ascii (int x, int base, int signed_p)
88 {
89   static char itoa_buf[12];
90   char *p = itoa_buf + 11;
91   *p-- = 0;
92
93   int sign = 0;
94   unsigned u = x;
95   if (signed_p && x < 0)
96     {
97       sign = 1;
98       u = -x;
99     }
100
101   do
102      {
103        int i = u % base;
104        *p-- = i > 9 ? 'a' + i - 10 : '0' + i;
105        u = u / base;
106      } while (u);
107
108   if (sign && *(p + 1) != '0')
109     *p-- = '-';
110
111   return p+1;
112 }
113
114 char const*
115 itoab (int x, int base)
116 {
117   return number_to_ascii (x, base, 1);
118 }
119
120 char const*
121 itoa (int x)
122 {
123   return number_to_ascii (x, 10, 1);
124 }
125
126 char const*
127 utoa (unsigned x)
128 {
129   return number_to_ascii (x, 10, 0);
130 }
131
132 int _ungetc_pos = -1;
133 int _ungetc_fd = -1;
134 char _ungetc_buf[10];
135
136 int
137 fdgetc (int fd)
138 {
139   char c;
140   int i;
141   if (_ungetc_pos == -1)
142     {
143       int r = read (fd, &c, 1);
144       if (r < 1)
145         return -1;
146       i = c;
147    }
148   else
149     {
150       if (_ungetc_fd != fd)
151         {
152           eputs (" ***MES LIB C*** fdgetc ungetc conflict unget-fd=");
153           eputs (itoa (_ungetc_fd));
154           eputs (", fdgetc-fd=");
155           eputs (itoa (fd));
156           eputs ("\n");
157           exit (1);
158         }
159       i = _ungetc_buf[_ungetc_pos];
160       _ungetc_pos -= 1;
161       if (_ungetc_pos == -1)
162         _ungetc_fd = -1;
163      }
164   if (i < 0)
165     i += 256;
166
167   return i;
168 }
169
170 int
171 fdputc (int c, int fd)
172 {
173   write (fd, (char*)&c, 1);
174   return 0;
175 }
176
177 int
178 fdputs (char const* s, int fd)
179 {
180   int i = strlen (s);
181   write (fd, s, i);
182   return 0;
183 }
184
185 int
186 fdungetc (int c, int fd)
187 {
188   if (_ungetc_pos == -1)
189     _ungetc_fd = fd;
190   else if (_ungetc_fd != fd)
191     {
192       eputs (" ***MES LIB C*** fdungetc ungetc conflict unget-fd=");
193       eputs (itoa (_ungetc_fd));
194       eputs (", fdungetc-fd=");
195       eputs (itoa (fd));
196       eputs ("\n");
197       exit (1);
198     }
199   _ungetc_pos++;
200   _ungetc_buf[_ungetc_pos] = c;
201   return c;
202 }
203
204 int
205 _fdungetc_p (int fd)
206 {
207   return _ungetc_pos > -1;
208 }
209
210 #if POSIX || __x86_64__
211 #define STDERR 2
212 int
213 eputs (char const* s)
214 {
215   int i = strlen (s);
216   write (STDERR, s, i);
217   return 0;
218 }
219 #endif
220
221 int
222 eputc (int c)
223 {
224   return fdputc (c, STDERR);
225 }