]> mj.ucw.cz Git - moe.git/blob - judge/token.c
Default token buffer is 1 byte long, which makes even small limits on
[moe.git] / judge / token.c
1 /*
2  *      Tokenizer for judges
3  *
4  *      (c) 2007 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <limits.h>
12 #include <errno.h>
13
14 #include "judge.h"
15
16 #define DEFAULT_MAX_TOKEN (32 << 20)
17
18 void tok_init(struct tokenizer *t, struct stream *s)
19 {
20   memset(t, 0, sizeof(*t));
21   t->stream = s;
22   t->bufsize = 1;
23   t->token = xmalloc(t->bufsize);
24   t->maxsize = DEFAULT_MAX_TOKEN;
25   t->line = 1;
26 }
27
28 void tok_cleanup(struct tokenizer *t)
29 {
30   free(t->token);
31 }
32
33 void tok_err(struct tokenizer *t, char *msg, ...)
34 {
35   va_list args;
36   va_start(args, msg);
37   printf("%s:%d: ", t->stream->name, t->line);
38   vprintf(msg, args);
39   putchar('\n');
40   va_end(args);
41   exit(1);
42 }
43
44 static inline int is_white(int c)
45 {
46   return (c == ' ' || c == '\t' || c == '\r' || c == '\n');
47 }
48
49 char *get_token(struct tokenizer *t)
50 {
51   unsigned int len = 0;
52   int c;
53
54   // Skip whitespace
55   do
56     {
57       c = sgetc(t->stream);
58       if (c < 0)
59         return NULL;
60       if (c == '\n')
61         {
62           t->line++;
63           if (t->flags & TF_REPORT_LINES)
64             {
65               t->toksize = 0;
66               t->token[0] = 0;
67               return t->token;
68             }
69         }
70     }
71   while (is_white(c));
72
73   // This is the token itself
74   do
75     {
76       t->token[len++] = c;
77       if (len >= t->bufsize)
78         {
79           if (len > t->maxsize)
80             tok_err(t, "Token too long");
81           t->bufsize *= 2;
82           if (t->bufsize > t->maxsize)
83             t->bufsize = t->maxsize+1;
84           t->token = xrealloc(t->token, t->bufsize);
85         }
86       c = sgetc(t->stream);
87     }
88   while (c >= 0 && !is_white(c));
89   if (c >= 0)
90     sungetc(t->stream);
91
92   t->token[len] = 0;
93   t->toksize = len;
94   return t->token;
95 }
96
97 /*
98  *  Parsing functions. They return 1 if successfully parsed, 0 otherwise.
99  */
100
101 #define PARSE(f, ...)                                           \
102         char *end;                                              \
103         errno = 0;                                              \
104         *x = f(t->token, &end, ##__VA_ARGS__);                  \
105         return !(errno || (unsigned char *) end != t->token + t->toksize)
106
107 int to_long(struct tokenizer *t, long int *x)
108 {
109   PARSE(strtol, 10);
110 }
111
112 int to_ulong(struct tokenizer *t, unsigned long int *x)
113 {
114   if (t->token[0] == '-')               // strtoul accepts negative numbers, but we don't
115     return 0;
116   PARSE(strtoul, 10);
117 }
118
119 int to_double(struct tokenizer *t, double *x)
120 {
121   PARSE(strtod);
122 }
123
124 int to_long_double(struct tokenizer *t, long double *x)
125 {
126   PARSE(strtold);
127 }
128
129 int to_int(struct tokenizer *t, int *x)
130 {
131   long int y;
132   if (!to_long(t, &y) || y > LONG_MAX || y < LONG_MIN)
133     return 0;
134   *x = y;
135   return 1;
136 }
137
138 int to_uint(struct tokenizer *t, unsigned int *x)
139 {
140   unsigned long int y;
141   if (!to_ulong(t, &y) || y > ULONG_MAX)
142     return 0;
143   *x = y;
144   return 1;
145 }
146
147 #define GET(fn, type)                                                                   \
148         type get_##fn(struct tokenizer *t)                                              \
149         {                                                                               \
150           type x;                                                                       \
151           if (!get_token(t))                                                            \
152             tok_err(t, "Unexpected end of file");                                       \
153           if (!to_##fn(t, &x))                                                          \
154             tok_err(t, "Expected " #fn);                                                \
155           return x;                                                                     \
156         }
157
158 GET(int, int)
159 GET(uint, unsigned int)
160 GET(long, long int)
161 GET(ulong, unsigned long int)
162 GET(double, double)
163 GET(long_double, long double)