e6ead109d3f1dcc299e94a3bcf19f9735de3982d
[people/lynusvaz/gpxe.git] / src / hci / parse.c
1 #include <gpxe/parse.h>
2
3 #include <string.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <gpxe/settings.h>
7
8 char * string3cat ( struct string *s1, const char *s2, const char *s3 ) { /* The len is the size of s1 */
9         char *tmp = s1->value;
10         asprintf ( &s1->value, "%s%s%s", s1->value, s2, s3 );
11         free ( tmp );
12         return s1->value;
13 }
14
15 char * stringcpy ( struct string *s1, const char *s2 ) {
16         char *tmp = s1->value;
17         s1->value = strdup ( s2 );
18         free ( tmp );
19         return s1->value;
20 }
21
22 char * stringcat ( struct string *s1, const char *s2 ) {
23         char *tmp;
24         if ( !s1->value )
25                 return stringcpy ( s1, s2 );
26         if ( !s2 )
27                 return s1->value;
28         tmp = s1->value;
29         asprintf ( &s1->value, "%s%s", s1->value, s2 );
30         free ( tmp );
31         return s1->value;
32 }
33
34 void free_string ( struct string *s ) {
35         free ( s->value );
36         s->value = NULL;
37 }
38
39 /* struct string *s:
40 Before: [start]$<exp>[end]
41 End: [start]<expanded>[end]
42 and *end points to [end]
43 */
44 char * dollar_expand ( struct string *s, char *inp, char ** end ) {
45         char *name;
46         int setting_len;
47         int len;
48         
49         len = inp - s->value;
50         
51         if ( inp[1] == '{' ) {
52                 *inp = 0;
53                 name = ( inp + 2 );
54
55                 /* Locate closer */
56                 *end = strstr ( name, "}" );
57                 if ( ! *end ) {
58                         printf ( "can't find ending }\n" );
59                         free_string ( s );
60                         return NULL;
61                 }
62                 **end = 0;
63                 *end += 1;
64                 
65                 /* Determine setting length */
66                 setting_len = fetchf_named_setting ( name, NULL, 0 );
67                 if ( setting_len < 0 )
68                         setting_len = 0; /* Treat error as empty setting */
69
70                 /* Read setting into buffer */
71                 {
72                         char expdollar[setting_len + 1];
73                         expdollar[0] = '\0';
74                         fetchf_named_setting ( name, expdollar,
75                                                         setting_len + 1 );
76                         if ( string3cat ( s, expdollar, *end ) )
77                                 *end = s->value + len + strlen ( expdollar );
78                 }
79                 return s->value;
80         } else if ( inp[1] == '(' ) {
81                 name = inp;
82                 {
83                         int ret;
84                         ret = parse_arith ( s, name, end );
85                         return s->value;                /* if ret < 0, s->value = NULL */
86                 }
87         }
88         /* Can't find { or (, so preserve the $ */
89         *end = inp + 1;
90         return s->value;
91 }
92
93 char * parse_escape ( struct string *s, char *input, char **end ) {
94         char *exp;
95         *input = 0;
96         *end = input + 2;
97         if ( input[1] == '\n' ) {
98                 int len = input - s->value;
99                 exp = stringcat ( s, *end );
100                 *end = exp + len;
101         } else {
102                 int len = input - s->value;
103                 *end = input + 1;
104                 exp = stringcat ( s, *end );
105                 *end = exp + len + 1;
106         }
107         return exp;
108 }
109
110 /* Both *head and *end point somewhere within s */
111 char * expand_string ( struct string *s, char **head, char **end, const struct char_table *table, int tlen, int in_quotes, int *success ) {
112         int i;
113         char *cur_pos;
114         int start;
115         
116         *success = 0;
117         start = *head - s->value;
118         cur_pos = *head;
119         
120         while ( *cur_pos ) {
121                 const struct char_table * tline = NULL;
122                 
123                 for ( i = 0; i < tlen; i++ ) {
124                         if ( table[i].token == *cur_pos ) {
125                                 tline = table + i;
126                                 break;
127                         }
128                 }
129                 
130                 if ( ! tline ) {
131                         *success = 1;
132                         cur_pos++;
133                 } else {
134                         switch ( tline->type ) {
135                                 case ENDQUOTES: /* 0 for end of input, where next char is to be discarded. Used for ending ' or " */
136                                 {
137                                         int pos = cur_pos - s->value;
138                                         char *t;
139                                         *success = 1;
140                                         *cur_pos = 0;
141                                         if ( ( t = stringcat ( s, cur_pos + 1 ) ) ) {
142                                                 *end = t + pos;
143                                                 *head = s->value + start;
144                                         }
145                                         return s->value;
146                                 }
147                                         break;
148                                 case TABLE: /* 1 for recursive call. Probably found quotes */
149                                         {
150                                                 int s2;
151                                                 char *end;
152                                                 char *tmp;
153                                                 
154                                                 *success = 1;
155                                                 *cur_pos = 0;
156                                                 tmp = s->value;
157                                                 stringcat ( s, cur_pos + 1 );
158                                                 cur_pos = s->value + ( cur_pos - tmp );
159                                                 if ( !expand_string ( s, &cur_pos, &end, tline->next.next_table.ntable, tline->next.next_table.len, 1, &s2 ) ) {
160                                                         return NULL;
161                                                 }
162                                                 cur_pos = end;
163                                         }
164                                         break;
165                                 case FUNC: /* Call another function */
166                                         {
167                                                 char *nstr;
168                                                 
169                                                 *success = 1;
170                                                 nstr = tline->next.parse_func ( s, cur_pos, &cur_pos );
171                                                 if ( !nstr ) {
172                                                         return NULL;
173                                                 }
174                                         }
175                                         break;
176                                         
177                                 case ENDTOK: /* End of input, and we also want next character */
178                                         *end = cur_pos;
179                                         *head = s->value + start;
180                                         return s->value;
181                                         break;
182                         }
183                 }
184                 
185         }
186         if ( in_quotes ) {
187                 printf ( "can't find closing '%c'\n", table[0].token );
188                 free_string ( s );
189                 return NULL;
190         }
191         *end = cur_pos;
192         *head = s->value + start;
193         return s->value;
194 }