1 /* $Id$
2 * --------------------------------------------------------------------------
3 *
4 * //===== //===== ===//=== //===// // // //===//
5 * // // // // // // // // //
6 * //====// // // //===// // // //===<<
7 * // // // // // // // //
8 * ======// //===== // // //===== // //===//
9 *
10 * -------------- An SCTP implementation according to RFC 4960 --------------
11 *
12 * Copyright (C) 2001 by Andreas Lang
13 *
14 * This library is free software: you can redistribute it and/or modify it
15 * under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation, either version 2.1 of the License, or
17 * (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * Contact: anla@gmx.net
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include "sctptest.h"
35
36
37 /**
38 * This function reads one command from the script file.
39 * @param scriptFile
40 * the file pointer that belongs to the script file. The parser starts to read at
41 * the current file position. After the function returns, the new file position is at the
42 * character that follows the last character that has been read. This means, if the file
43 * position is not changed outside of this function, subsequent calls of this function
44 * will get the script commands one after another.
45 * @param scriptCommand
46 * pointer to an sctptest_scriptCommand structure that will be filled with the data
47 * extracted from the script command.
48 * Please see the description of "struct sctptest_scriptCommand" in "sctptest.h" for more details
49 * @param line
50 * pointer to an integer variable that is used to count lines in the script file. If this
51 * pointer is non-NULL, the variable is increased by one when a new-line character occurs
52 * in the script file.
53 * If this integer variable is set to zero before the first call of getScriptCommand(), it
54 * always contains the line number that corresponds to the current file position, unless
55 * the file position or the variable are changed outside of this function.
56 * @param column
57 * pointer to an integer variable that (if the pointer is not NULL) is used to hold the number
58 * of the column that corresponds with the current file position.
59 * If this integer variable is set to zero before the first call of getScriptCommand(), it
60 * always contains the correct column number, unless the file position or the variable
61 * are changed outside of this function.
62 * NOTE: this variable actually does not count columns but characters. For example, a tab
63 * character increases the variable by one, although it usually covers more than one column
64 * in an editor.
65 * @param mode
66 * If "mode" is RUN_SCRIPT, comments in the script file are echoed on "stdout".
67 * See function sctptest_start() for more details.
68 *
69 * @return The parse result, which can have the following values (defined in sctptest.h)
70 * PARSE_OK - if the command has been successfully parsed
71 * END_OF_FILE - if the end of the script file has been reached
72 * PARSE_ERROR - if an error occured during parsing the script command
73 */
getScriptCommand(FILE * scriptFile,struct sctptest_scriptCommand * scriptCommand,unsigned int * line,unsigned int * column,int mode)74 int getScriptCommand(FILE *scriptFile, struct sctptest_scriptCommand *scriptCommand,
75 unsigned int *line, unsigned int *column, int mode)
76 {
77 int i, termExp;
78 int ch;
79 char termCh, wordBuffer[MAX_WORD_LENGTH];
80 enum { COMMAND, PARAM_KEY, PARAM_VALUE, PARAM_VALUE_STRING } state;
81
82
83 /* Initialization */
84 if ((line != NULL) && (*line == 0))
85 *line = 1;
86 for (i = 0; i < MAX_NUM_OF_PARAMS; i++) {
87 *scriptCommand->param[i].key = '\0';
88 *scriptCommand->param[i].value = '\0';
89 }
90 scriptCommand->numOfParams = 0;
91 *wordBuffer = '\0';
92 state = COMMAND;
93 termCh = ':';
94 termExp = 0;
95
96
97 /* enter scan/parse loop */
98 while (1)
99 {
100 ch = fgetc(scriptFile);
101
102 if (state == PARAM_VALUE_STRING) {
103 (*column)++;
104 if (ch == '"') {
105 termExp = 1;
106 state = PARAM_VALUE;
107 continue;
108 }
109 else if (!isprint(ch) || strlen(wordBuffer) >= MAX_WORD_LENGTH-1) {
110 return PARSE_ERROR;
111 }
112 else {
113 int length = strlen(wordBuffer);
114 wordBuffer[length] = ch;
115 wordBuffer[length+1] = '\0';
116 continue;
117 }
118 }
119
120 if (ch == '#') {
121 int printComment;
122 ch = fgetc(scriptFile);
123 printComment = ((ch != '#') && (mode == RUN_SCRIPT));
124 if (printComment)
125 printf("\n#");
126 while ((ch != '\n') && (ch != EOF)) {
127 if (printComment && isprint(ch))
128 printf("%c", ch);
129 ch = fgetc(scriptFile);
130 }
131 if (printComment)
132 printf("\n");
133 }
134
135 ch = toupper(ch);
136
137 if (ch == '\n') {
138 if (line != NULL)
139 (*line)++;
140 if (column != NULL)
141 *column = 0;
142 } else
143 if (column != NULL)
144 (*column)++;
145
146 if (ch == EOF) {
147 if ((*wordBuffer == '\0') && (state == COMMAND))
148 return END_OF_FILE;
149 else
150 return PARSE_ERROR;
151 }
152
153 else if (termExp) {
154
155 if (isspace(ch))
156 continue;
157
158 else if ((ch == termCh) || ( (ch == ';') && (state == COMMAND || state == PARAM_VALUE) )) {
159
160 if (state == PARAM_KEY)
161 if (++scriptCommand->numOfParams > MAX_NUM_OF_PARAMS)
162 return PARSE_ERROR;
163
164 switch (state) {
165 case COMMAND:
166 strcpy(scriptCommand->command, wordBuffer);
167 state = PARAM_KEY;
168 termCh = '=';
169 break;
170 case PARAM_KEY:
171 strcpy(scriptCommand->param[scriptCommand->numOfParams - 1].key, wordBuffer);
172 state = PARAM_VALUE;
173 termCh = ',';
174 break;
175 case PARAM_VALUE:
176 strcpy(scriptCommand->param[scriptCommand->numOfParams - 1].value, wordBuffer);
177 state = PARAM_KEY;
178 termCh = '=';
179 break;
180 case PARAM_VALUE_STRING:
181 /* just to avoid compiler warnings */
182 break;
183 default:
184 break;
185 }
186
187 *wordBuffer = '\0';
188 termExp = 0;
189
190 if (ch == ';')
191 return PARSE_OK;
192 else
193 continue;
194 }
195
196 else
197 return PARSE_ERROR;
198 }
199
200 else { /* (if !termExp) */
201
202 if (isspace(ch)) {
203 if (*wordBuffer != '\0')
204 termExp = 1;
205 continue;
206 }
207
208 else if (ch == '"') {
209 if ((state == PARAM_VALUE) && (*wordBuffer == '\0')) {
210 state = PARAM_VALUE_STRING;
211 continue;
212 } else {
213 return PARSE_ERROR;
214 }
215 }
216
217
218 else if ((ch == termCh) || ( (ch == ';') && (state == COMMAND || state == PARAM_VALUE) )) {
219
220 if (*wordBuffer == '\0')
221 return PARSE_ERROR;
222
223 if (state == PARAM_KEY)
224 if (++scriptCommand->numOfParams > MAX_NUM_OF_PARAMS)
225 return PARSE_ERROR;
226
227 switch (state) {
228 case COMMAND:
229 strcpy(scriptCommand->command, wordBuffer);
230 state = PARAM_KEY;
231 termCh = '=';
232 break;
233 case PARAM_KEY:
234 strcpy(scriptCommand->param[scriptCommand->numOfParams - 1].key, wordBuffer);
235 state = PARAM_VALUE;
236 termCh = ',';
237 break;
238 case PARAM_VALUE:
239 strcpy(scriptCommand->param[scriptCommand->numOfParams - 1].value, wordBuffer);
240 state = PARAM_KEY;
241 termCh = '=';
242 break;
243 case PARAM_VALUE_STRING:
244 /* just to avoid compiler warnings */
245 break;
246 default:
247 break;
248 }
249
250 *wordBuffer = '\0';
251 termExp = 0;
252
253 if (ch == ';')
254 return PARSE_OK;
255 else
256 continue;
257 }
258
259 else if ((!isalnum(ch) && (ch != '_') && (ch != '.')) || strlen(wordBuffer) >= MAX_WORD_LENGTH-1)
260 return PARSE_ERROR;
261
262 else {
263 int length = strlen(wordBuffer);
264 wordBuffer[length] = ch;
265 wordBuffer[length+1] = '\0';
266 }
267
268 }
269 }
270 }
271
272
273
274 /* ONLY FOR TESTING */
printCommand(struct sctptest_scriptCommand * sc,unsigned int lineNum)275 void printCommand(struct sctptest_scriptCommand *sc, unsigned int lineNum)
276 {
277 int i;
278
279 printf("\n\nLine %u:\n", lineNum);
280 printf("COMMAND: %s with %d params\n", sc->command, sc->numOfParams);
281
282 for (i = 0; i < (int)sc->numOfParams; i++)
283 printf("KEY: %s VALUE: %s\n", sc->param[i].key, sc->param[i].value);
284 }
285
286
287