framework for typechecking and code generation
[ccc.git] / util.c
1 #include <stdarg.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6
7 #include "util.h"
8
9 struct list *list_cons(void *el, struct list *tail)
10 {
11 struct list *res = safe_malloc(sizeof(struct list));
12 res->el = el;
13 res->tail = tail;
14 return res;
15 }
16
17 void list_free(struct list *head, void (*freefun)(void *))
18 {
19 while (head != NULL) {
20 freefun(head->el);
21 head = head->tail;
22 }
23 }
24
25 void **list_to_array(struct list *list, int *num, bool reverse)
26 {
27 int i = list_length(list);
28 *num = i;
29 void **ptr = safe_malloc(i*sizeof(void *));
30
31 struct list *r = list;
32 while(i > 0) {
33 if (reverse)
34 ptr[--i] = r->el;
35 else
36 ptr[*num-(--i)] = r->el;
37 struct list *t = r;
38 r = r->tail;
39 free(t);
40 }
41 return ptr;
42 }
43
44 int list_length(struct list *r)
45 {
46 int i = 0;
47 while(r != NULL) {
48 i++;
49 r = r->tail;
50 }
51 return i;
52 }
53
54 int fromHex(char c)
55 {
56 if (c >= '0' && c <= '9')
57 return c-'0';
58 if (c >= 'a' && c <= 'f')
59 return c-'a'+10;
60 if (c >= 'A' && c <= 'F')
61 return c-'A'+10;
62 return -1;
63 }
64
65 char *escape_char(char c, char *buf, bool str)
66 {
67 buf = buf == NULL ? safe_malloc(10) : buf;
68 switch (c) {
69 case '\0': strcpy(buf, "\\0"); break;
70 case '\a': strcpy(buf, "\\a"); break;
71 case '\b': strcpy(buf, "\\b"); break;
72 case '\t': strcpy(buf, "\\t"); break;
73 case '\n': strcpy(buf, "\\n"); break;
74 case '\v': strcpy(buf, "\\v"); break;
75 case '\f': strcpy(buf, "\\f"); break;
76 case '\r': strcpy(buf, "\\r"); break;
77 case '\\': strcpy(buf, "\\\\"); break;
78 case '\'': strcpy(buf, str ? "'" : "\\'"); break;
79 case '"': strcpy(buf, str ? "\\\"" : "\""); break;
80 default:
81 if (c >= ' ' && c < 127)
82 sprintf(buf, "%c", c);
83 else
84 sprintf(buf, "\\x%02x", (unsigned char)c);
85 break;
86 }
87 return buf;
88 }
89
90 bool isodigit(char c)
91 {
92 return c >= '0' && c <= '7';
93 }
94
95 int fromOctal(char c)
96 {
97 if (isodigit(c))
98 return c-'0';
99 return -1;
100 }
101
102 char *unescape_char(char *c)
103 {
104 if (c[0] == '\\') {
105 if (c[1] == 'x' && isxdigit(c[2])) {
106 //two hex
107 if (isxdigit(c[3])) {
108 c[3] = (fromHex(c[2])*16)+fromHex(c[3]);
109 c+=2;
110 //one hex
111 } else {
112 c[2] = fromHex(c[2]);
113 c++;
114 }
115 } else if (c[1] == '0' && isodigit(c[2])) {
116 if (isodigit(c[3])) {
117 //three octal
118 if (isodigit(c[4])) {
119 c[4] = fromOctal(c[2])*64
120 +fromOctal(c[3])*8
121 +fromOctal(c[4]);
122 c+=2;
123 //two octal
124 } else {
125 c[3] = fromOctal(c[2])*8
126 +fromOctal(c[3]);
127 c+=2;
128 }
129 // one octal
130 } else {
131 c[2] = fromOctal(c[2]);
132 c++;
133 }
134 } else {
135 switch (c[1]) {
136 case '0': c[1] = '\0'; break;
137 case '\'': c[1] = '\''; break;
138 case '\\': c[1] = '\\'; break;
139 case '"': c[1] = '"'; break;
140 case 'a': c[1] = '\a'; break;
141 case 'b': c[1] = '\b'; break;
142 case 't': c[1] = '\t'; break;
143 case 'v': c[1] = '\v'; break;
144 case 'f': c[1] = '\f'; break;
145 case 'r': c[1] = '\r'; break;
146 }
147 }
148 c++;
149 }
150 return c;
151 }
152
153 char *trimquotes(char *c)
154 {
155 char *r = c+1;
156 r[strlen(r)-1] = '\0';
157 return r;
158 }
159
160 void pdie(const char *msg)
161 {
162 perror(msg);
163 exit(1);
164 }
165
166 void die(const char *msg, ...)
167 {
168 va_list ap;
169 va_start(ap, msg);
170 vfprintf(stderr, msg, ap);
171 va_end(ap);
172 exit(1);
173 }
174
175 void pindent(int indent, FILE *out)
176 {
177 for (int i = 0; i<indent; i++)
178 if (fputc('\t', out) == EOF)
179 pdie("fputc");
180 }
181
182 void safe_fprintf(FILE *out, const char *msg, ...)
183 {
184 va_list ap;
185 va_start(ap, msg);
186 int r = vfprintf(out, msg, ap);
187 va_end(ap);
188 if (r < 0)
189 pdie("fprintf");
190 }
191
192 void *safe_malloc(size_t size)
193 {
194 void *res = malloc(size);
195 if (res == NULL)
196 pdie("malloc");
197 return res;
198 }
199
200 void *safe_strdup(const char *c)
201 {
202 char *res = strdup(c);
203 if (res == NULL)
204 pdie("strdup");
205 return res;
206 }