]> mj.ucw.cz Git - umpf.git/blob - lex.c
fix many little bugs, release 0.1
[umpf.git] / lex.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdarg.h>
6
7 #include "cond.tab.h"
8 #include "umpf.h"
9 #define KLEN 10 
10
11 struct keys {
12         char* keywords;
13         enum yytokentype keytoks;
14 };
15
16 static struct keys kwds[] = 
17         {       {"copy", KW_COPY},
18                 {"else", KW_ELSE},
19                 {"if", KW_IF}, 
20                 {"mail", KW_MAIL}, 
21                 {"pipe", KW_PIPE},
22                 {"discard", KW_DISCARD},
23                 {"filter", KW_FILTER}
24         };
25
26 void
27 read_conf(char* filename)
28 {
29         conf = fopen(filename, "r");
30
31         if (! conf) {
32                 fprintf(stderr, "Error reading config file: %m\nSaving to default mailbox %s\n", default_mailbox);
33                 longjmp(env, 1); 
34         }
35 }
36
37 void __attribute__ ((noreturn)) 
38 die(char* msg, ...)
39 {
40         va_list args;
41
42         va_start(args, msg);
43         vfprintf(stderr, msg, args);
44         fputc('\n', stderr);
45         va_end(args);
46         exit(1);
47 }
48
49 void*
50 xmalloc(size_t size)
51 {
52         void* ret;
53
54         if (!(ret = malloc(size)))
55                 die("Low memory");
56
57         return ret;
58 }
59
60 void*
61 xrealloc(void* buf, size_t size)
62 {
63         buf = realloc(buf, size);
64         
65         if (!buf)
66                 die("Low memory");
67
68         return buf;
69 }
70
71 static void __attribute__ ((noreturn)) 
72 parse_err(char* msg, ...)
73 {
74         va_list args;
75
76         va_start(args, msg);
77         fprintf(stderr, "Line %d: ", line);
78         vfprintf(stderr, msg, args);
79         fputc('\n', stderr);
80         fprintf(stderr, "Saving the email to default mailbox %s\n",
81                 default_mailbox);
82         va_end(args);
83         longjmp(env, 1); 
84 }
85
86 char*
87 xstrdup(const char* s)
88 {
89         void* ret;
90
91         if (!(ret = strdup(s)))
92                 die("Low memory");
93
94         return ret;
95 }
96
97 static char*
98 get_string_out(int delim)
99 {
100         int i = 0;
101         int c;
102         char buf[BUFSIZE];
103
104         while ((c = getc(conf)) != delim){
105                 if (c == '\\') {        
106                         c = getc(conf);
107                         if (c == EOF)
108                                 parse_err("Unbounded string, %c missing", delim);
109                         buf[i++] = c;
110                 } else if (c == '\n' || c == EOF)
111                         parse_err("Unbounded string, %c missing", delim);
112                 else            
113                         buf[i++] = c;
114
115                 if (i >= BUFSIZE-1)
116                         parse_err("Too long string, max allowed length is %d",BUFSIZE-1);       
117         }       
118         buf[i] = '\0';
119
120         return xstrdup(buf);
121 }
122
123 static int
124 is_var_id(int c)
125 {
126         return  (c >= '0' && c <= '9' ) ||
127                 (c >= 'a' && c <= 'z') ||
128                 (c >= 'A' && c <= 'Z') ||
129                 c == '_' ||
130                 c == '-'; 
131 }
132
133 static int
134 is_alpha(int c)
135 {
136         return (c >= 'a' && c <= 'z') ||
137                 (c >= 'A' && c <= 'Z');
138 }
139
140 static int
141 get_token_start(void)
142 {
143         int c;
144         int want_newline = 0;
145
146         for(;;) {
147                 c = getc(conf);
148                 if (c == EOF)
149                         return c;
150                 if (c == '#') {
151                         want_newline = 1;
152                         continue;
153                 }
154                 if (c == '\n') {
155                         line++;
156                         want_newline = 0;
157                         continue;
158                 }
159                 if (c != '\n' && want_newline)
160                         continue;
161                 if (c != ' ' && c != '\t')
162                         return c;
163         }
164 }
165
166 int
167 yylex(void)
168 {
169         int c;
170         
171         c = get_token_start();
172         if (c == EOF)
173                 return 0;
174         
175         int d = getc(conf);
176         if (d >= 0) {
177                 switch (CC(c,d)) {
178                 case CC('!','='): yylval.n = CC('!','='); return NEQ;
179                 case CC('!','~'): yylval.n = CC('!','='); return NRE;
180                 case CC('<','='): yylval.n = CC('<','='); return LE;
181                 case CC('>','='): yylval.n = CC('>','='); return GE;
182                 case CC('=','='): yylval.n = CC('=','='); return EQ;
183                 case CC('~','~'): yylval.n = CC('~','~'); return RE;
184                 case CC('-','>'): yylval.n = CC('-','>'); return ARROW;
185                 }
186                 ungetc(d,conf);
187         }
188
189         switch (c) {
190                 case '!':
191                 case '(':
192                 case ')':
193                 case '-':
194                 case '+':
195                 case '*':
196                 case '/':
197                 case '{':
198                 case '}':
199                 case '<':
200                 case '>':
201                 case '=':
202                 case ';':
203                 case '.':
204                 case '|':
205                 case '&':
206                 case '^':
207                         yylval.n = c;
208                         return c;
209                 
210                 case '"':
211                 case '\'':
212                         yylval.str = get_string_out(c);
213                         return CONST;   
214         }
215
216         if (c >= '0' && c <= '9'){
217                 ungetc(c,conf);
218                 int i = 0;
219                 char buf[BUFSIZE];
220         
221                 while ((c = getc(conf))>= '0' && c<= '9'){
222                         buf[i] = c;
223                         i++;
224                         if (i >= BUFSIZE-1)
225                                 parse_err("Too long number");   
226                 }
227                 if (c != EOF)
228                         ungetc(c,conf);
229                 buf[i] = 0;
230                 yylval.str = xstrdup(buf);
231
232                 return CONST;
233         }
234
235         if (c == '$'){
236                 int i = 0;
237                 char buf[BUFSIZE];
238         
239                 while (is_var_id(c = getc(conf))){
240                         buf[i]=c;
241                         i++;
242                         if (i >= BUFSIZE-1)
243                                 parse_err("Too long identifier, max allowed length is %d",BUFSIZE-1);   
244                 }
245                 if (!i)
246                         parse_err("Variable identifier must not be empty");
247                 if (c > 0)
248                         ungetc(c,conf);
249                 buf[i] = 0;
250                 yylval.str = xstrdup(buf);
251
252                 return VAR;
253         }
254
255         if (is_alpha(c)){
256                 char buf[KLEN]; 
257                 int n, i = 0;
258
259                 ungetc(c,conf);
260                 while (is_alpha(c = getc(conf))){
261                         buf[i++] = c;
262                         if (i >= KLEN)
263                                 parse_err("Keyword too long");
264                 }
265                 buf[i] = 0;
266                 if (c > 0)
267                         ungetc(c,conf);
268
269                 n = (sizeof(kwds)/sizeof(struct keys));
270                 for (i = 0; i < n; i++){
271                         if (!strcmp(buf,kwds[i].keywords))
272                                 return kwds[i].keytoks;
273                 }
274
275                 parse_err("Unknown keyword %s", buf);
276         }
277
278         parse_err("Unknown character %c", c);
279 }