Verifica limites de token antes de alocar memória.
[cascardo/declara.git] / lib / token.c
1 /*
2  *  Copyright (C) 2015  Thadeu Lima de Souza Cascardo <cascardo@cascardo.eti.br>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include "token.h"
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 static char * token_unescape(char *start, char *end)
25 {
26         int escape = 0;
27         char *s, *r, *n;
28         s = n = malloc(end - start);
29         if (!s)
30                 return NULL;
31         for (r = start + 1; r < end; r++) {
32                 if (escape) {
33                         *s = *r;
34                         s++;
35                         escape = 0;
36                 } else if (*r == '\\') {
37                         escape = 1;
38                 } else {
39                         *s = *r;
40                         s++;
41                 }
42         }
43         *s = 0;
44         return n;
45 }
46
47 static char * token_next(char *line, char **end)
48 {
49         char *start;
50         char *lend;
51         char cend;
52         int escape = 0;
53         start = line;
54         while (isspace(*start))
55                 start++;
56         if (*start == '"') {
57                 lend = start + 1;
58                 while (*lend) {
59                         cend = *lend;
60                         lend++;
61                         if (escape)
62                                 escape = 0;
63                         else if (cend == '\\')
64                                 escape = 1;
65                         else if (cend == '"')
66                                 break;
67                 }
68         } else {
69                 lend = start;
70                 while (*lend && !isspace(*lend))
71                         lend++;
72         }
73         *end = lend;
74         return start;
75 }
76
77 char ** tokens_new(char *line)
78 {
79         char **args = NULL;
80         size_t alloc = 0;
81         size_t next = 0;
82         const int inc = 8;
83         int more = 0;
84         char *start;
85         char *end;
86         int i;
87         end = line;
88         do {
89                 start = token_next(end, &end);
90                 if (start == end)
91                         break;
92                 if (next <= alloc) {
93                         char **nargs;
94                         alloc += inc;
95                         nargs = realloc(args, alloc * sizeof(char *));
96                         if (!nargs) {
97                                 for (i = 0; i < alloc - inc; i++)
98                                         if (args[i])
99                                                 free(args[i]);
100                                 free(args);
101                                 return NULL;
102                         }
103                         for (i = alloc - inc; i < alloc; i++)
104                                 nargs[i] = NULL;
105                         args = nargs;
106                 }
107                 if (*start == '"') {
108                         args[next] = token_unescape(start, end - 1);
109                 } else {
110                         args[next] = strndup(start, end - start);
111                 }
112                 if (!args[next]) {
113                         for (i = 0; i < alloc; i++)
114                                 if (args[i])
115                                         free(args[i]);
116                         free(args);
117                         return NULL;
118                 }
119                 next++;
120         } while (1);
121         return args;
122 }
123
124 void tokens_free(char **args)
125 {
126         char **arg;
127         for (arg = args; *arg; arg++)
128                 free(*arg);
129         free(args);
130 }