work on type inference some more
[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 int fromHex(char c)
10 {
11 if (c >= '0' && c <= '9')
12 return c-'0';
13 if (c >= 'a' && c <= 'f')
14 return c-'a'+10;
15 if (c >= 'A' && c <= 'F')
16 return c-'A'+10;
17 return -1;
18 }
19
20 char *escape_char(char c, char *buf, bool str)
21 {
22 buf = buf == NULL ? safe_malloc(10) : buf;
23 switch (c) {
24 case '\0': strcpy(buf, "\\0"); break;
25 case '\a': strcpy(buf, "\\a"); break;
26 case '\b': strcpy(buf, "\\b"); break;
27 case '\t': strcpy(buf, "\\t"); break;
28 case '\n': strcpy(buf, "\\n"); break;
29 case '\v': strcpy(buf, "\\v"); break;
30 case '\f': strcpy(buf, "\\f"); break;
31 case '\r': strcpy(buf, "\\r"); break;
32 case '\\': strcpy(buf, "\\\\"); break;
33 case '\'': strcpy(buf, str ? "'" : "\\'"); break;
34 case '"': strcpy(buf, str ? "\\\"" : "\""); break;
35 default:
36 if (c >= ' ' && c < 127)
37 sprintf(buf, "%c", c);
38 else
39 sprintf(buf, "\\x%02x", (unsigned char)c);
40 break;
41 }
42 return buf;
43 }
44
45 bool isodigit(char c)
46 {
47 return c >= '0' && c <= '7';
48 }
49
50 int fromOctal(char c)
51 {
52 if (isodigit(c))
53 return c-'0';
54 return -1;
55 }
56
57 char *unescape_char(char *c)
58 {
59 if (c[0] == '\\') {
60 if (c[1] == 'x' && isxdigit(c[2])) {
61 //two hex
62 if (isxdigit(c[3])) {
63 c[3] = (fromHex(c[2])*16)+fromHex(c[3]);
64 c+=2;
65 //one hex
66 } else {
67 c[2] = fromHex(c[2]);
68 c++;
69 }
70 } else if (c[1] == '0' && isodigit(c[2])) {
71 if (isodigit(c[3])) {
72 //three octal
73 if (isodigit(c[4])) {
74 c[4] = fromOctal(c[2])*64
75 +fromOctal(c[3])*8
76 +fromOctal(c[4]);
77 c+=2;
78 //two octal
79 } else {
80 c[3] = fromOctal(c[2])*8
81 +fromOctal(c[3]);
82 c+=2;
83 }
84 // one octal
85 } else {
86 c[2] = fromOctal(c[2]);
87 c++;
88 }
89 } else {
90 switch (c[1]) {
91 case '0': c[1] = '\0'; break;
92 case '\'': c[1] = '\''; break;
93 case '\\': c[1] = '\\'; break;
94 case '"': c[1] = '"'; break;
95 case 'a': c[1] = '\a'; break;
96 case 'b': c[1] = '\b'; break;
97 case 't': c[1] = '\t'; break;
98 case 'v': c[1] = '\v'; break;
99 case 'f': c[1] = '\f'; break;
100 case 'r': c[1] = '\r'; break;
101 }
102 }
103 c++;
104 }
105 return c;
106 }
107
108 char *trimquotes(char *c)
109 {
110 char *r = c+1;
111 r[strlen(r)-1] = '\0';
112 return r;
113 }
114
115 void pdie(const char *msg)
116 {
117 perror(msg);
118 exit(1);
119 }
120
121 void die(const char *msg, ...)
122 {
123 va_list ap;
124 va_start(ap, msg);
125 vfprintf(stderr, msg, ap);
126 va_end(ap);
127 exit(1);
128 }
129
130 void pindent(int indent, FILE *out)
131 {
132 for (int i = 0; i<indent; i++)
133 if (fputc('\t', out) == EOF)
134 pdie("fputc");
135 }
136
137 void safe_fprintf(FILE *out, const char *msg, ...)
138 {
139 va_list ap;
140 va_start(ap, msg);
141 int r = vfprintf(out, msg, ap);
142 va_end(ap);
143 if (r < 0)
144 pdie("fprintf");
145 }
146
147 void *safe_malloc(size_t size)
148 {
149 void *res = malloc(size);
150 if (res == NULL)
151 pdie("malloc");
152 return res;
153 }
154
155 void *safe_strdup(const char *c)
156 {
157 size_t nchar = strlen(c);
158 char *res = malloc((nchar+1)*sizeof(char));
159 if (res == NULL)
160 pdie("strdup");
161 memcpy(res, c, nchar+1);
162 return res;
163 }
164
165 FILE *safe_fopen(const char *path, const char *mode)
166 {
167 FILE *res = fopen(path, mode);
168 if (res == NULL)
169 pdie("fopen");
170 return res;
171 }
172
173 void safe_fclose(FILE *file)
174 {
175 if (fclose(file) == -1)
176 pdie("fclose");
177 }