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