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