1 /** **************************************************************
2 \page script_parsing Script Parsing Class
3
4 \par script_parsing.cxx (FLAMP)
5
6 \par Author(s):
7 Robert Stiles, KK5VD, Copyright © 2014
8 <br>
9 <br>
10 This is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version. This software is distributed in
14 the hope that it will be useful, but WITHOUT ANY WARRANTY; without
15 even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 PURPOSE. See the GNU General Public License for more details. You
17 should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 <br>
20 <br>
21
22 \par USE:
23 Create a structure of data contained within the SCRIPT_COMMANDS
24 structure \(see \ref script_cmds\). Each element are as follows.<br>
25
26 \verbatim
27 { SCRIPT_COMMAND, 0, "AUTO LOAD QUEUE", 1, {0}, { p_string }, 0, 0, 0, 0 }
28 \endverbatim
29
30 \par "int flags <SCRIPT_COMMAND and/or QUEUE_COMMAND>"
31 Indicates if the script command is a global assignment (SCRIPT_COMMAND)
32 or local for each of the queued files (QUEUE_COMMAND).
33
34 \par "size_t command_length"
35 Programmer assignment not required. Internally Assigned. This is the
36 length of the script command in bytes.
37
38 \par "char command[MAX_COMMAND_LENGTH]"
39 The script command used to match within the content of the script
40 file. MAX_COMMAND_LENGTH is the maximum length of the supplied buffer.
41
42 \par "int argc"
43 The number of argument as required for the script command. The
44 parsing engine will limit the number of scanned parameters even of more
45 has been supplied.
46
47 \par "char *args[MAX_CMD_PARAMETERS]"
48 An array of char string pointers to each parameter scanned for
49 the specific command. MAX_CMD_PARAMETERS is the maximum number
50 of positions available in the parameter buffer table.
51
52 \par "enum paramter_types param_check[MAX_CMD_PARAMETERS]"
53 A list of validation flags for each parameters required.
54 MAX_CMD_PARAMETERS is the maximum number of positions available
55 in the param_check buffer table. See \ref paramter_types for a list
56 of valid values.<br>
57
58 \par "calling_func func"
59 When a command string is matched in the script file, this StringParsing
60 Class member is executed for further processing of the command
61 paramaters. This can include any validation checks if required. The member
62 functions are assigned during the creation of the class instance. See the
63 constructor member ScriptParsing::ScriptParsing() for details.
64
65 \par "const char **valid_values"
66 List of valid paramters. Use function
67 int assign_valid_parameters(const char *command, const char **array, const int array_count);
68 to asssign the values to a specific script command.
69
70 \par "int valid_value_count"
71 Number of valid paramters.
72
73 \par "int (*cb)(ScriptParsing *sp, struct script_cmds *sd)"
74 This is assigned using the StringParsing Member:<br>
75 <br>
76 int assign_callback(const char *scriptCommand, int (*cb)(ScriptParsing *sp, SCRIPT_COMMANDS *sc));<br>
77 <br>
78 The function which is supplied by the programmer after the creation of the
79 Class instance is called when the command is matched. This allows the
80 programmer access to a multitude of information for further processing
81 outside of the ScriptParsing Class instance.<br>
82 <br>
83 Example:<br>
84 \verbatim
85 #include "script_parsing.h"
86
87 static const char *modems[] = {
88 "BPSK31",
89 "MFSK32",
90 "MT63-500",
91 "MFSK64"
92 };
93
94 int callback(ScriptParsing *sp, struct script_cmds *sc)
95 {
96 // do something
97 return 0;
98 }
99
100 int main(int argc, const char * argv[])
101 {
102 ScriptParsing *sp = new ScriptParsing;
103
104 if(sp) {
105 sp->assign_valid_parameters("MODEM", modems, sizeof(modems)/sizeof(char *));
106 sp->assign_callback("FILE", callback);
107 sp->parse_commands((char *)"/fldigi-dev/test_parse_commands/running_test.txt");
108 }
109
110 return 0;
111 }
112 \endverbatim
113 <br>
114 See \ref script_parsing_class and \ref script_cmds for details about
115 what data is provided by the ScriptParsing *sp and SCRIPT_COMMANDS *sc
116 pointers. The passed SCRIPT_COMMANDS *sc pointer is a copy of the
117 original data. Modification of this information does not alter the
118 internal data.<br><br>
119 <b>Note:</b> The member and function pointers within the SCRIPT_COMMANDS
120 *sc pointer are set to dummy functions which return back to the caller
121 if executed.
122 *******************************************************************/
123
124 #include "config.h"
125 #include "util.h"
126
127 #include <stdio.h>
128 #include <stdlib.h>
129 #include <string.h>
130 #include <ctype.h>
131 #include <pthread.h>
132 #include <unistd.h>
133 #include <sys/stat.h>
134
135 //#define EXTERNAL_TESTING
136 #undef EXTERNAL_TESTING
137 #ifdef EXTERNAL_TESTING
138 #define TESTING 1
139 #define LOG_INFO printf
140 #else
141 #include "debug.h"
142 #endif
143
144 #ifdef __WIN32__
145 #define PATH_SEPERATOR "\\"
146 #define PATH_CHAR_SEPERATOR '\\'
147 #include <direct.h>
148 #define get_current_dir _getcwd
149 #else
150 #define PATH_SEPERATOR "/"
151 #define PATH_CHAR_SEPERATOR '/'
152 #include <unistd.h>
153 #define get_current_dir getcwd
154 #endif
155
156 #include "script_parsing.h"
157
158 // This table (by reference) is not used. Copy to another memory location.
159 // Do not change the order of this without changing the order of
160 // void ScriptParsing::initialize_function_members(void) to match.
161
162 static const SCRIPT_COMMANDS default_script_command_table[] = {
163 { CMD_AUTO_LOAD_QUEUE, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
164 { CMD_BASE, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 1, {0}, { p_unsigned_int }, 0, 0, 0, 0 },
165 { CMD_BLOCKS, SCRIPT_COMMAND, 0, 1, {0}, { p_unsigned_int }, 0, 0, 0, 0 },
166 { CMD_CALLFROM, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
167 { CMD_CALLTO, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
168 { CMD_CLEAR_MISSING, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
169 { CMD_CLEAR_RXQ, SCRIPT_COMMAND, 0, 0, {0}, { p_null }, 0, 0, 0, 0 },
170 { CMD_CLEAR_TXQ, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 0, {0}, { p_null }, 0, 0, 0, 0 },
171 { CMD_COMP, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
172 { CMD_EVENT_FOREVER, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
173 { CMD_EVENT_TIMED, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
174 { CMD_EVENT_TIMES, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
175 { CMD_EVENT_TYPE, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
176 { CMD_EVENT, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
177 { CMD_FILE, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 2, {0}, { p_filename, p_string }, 0, 0, 0, 0 },
178 { CMD_HAMCAST_MODEM, SCRIPT_COMMAND, 0, 2, {0}, { p_unsigned_int, p_string }, 0, 0, 0, 0 },
179 { CMD_HAMCAST, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
180 { CMD_HDR_REPEAT, SCRIPT_COMMAND, 0, 1, {0}, { p_unsigned_int }, 0, 0, 0, 0 },
181 { CMD_HEADER_MODEM, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
182 { CMD_HEADER, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
183 { CMD_INFO, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
184 { CMD_INHIBIT_HEADER, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
185 { CMD_INTERVAL, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
186 { CMD_LOAD_QUEUE, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 2, {0}, { p_string, p_string }, 0, 0, 0, 0 },
187 { CMD_LOAD_TXDIR, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 1, {0}, { p_string, p_string }, 0, 0, 0, 0 },
188 { CMD_MODEM, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
189 { CMD_PATH, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 1, {0}, { p_path }, 0, 0, 0, 0 },
190 { CMD_PROTO, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
191 { CMD_QUEUE_FILEPATH, SCRIPT_COMMAND | QUEUE_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
192 { CMD_RESET, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
193 { CMD_RX_INTERVAL, SCRIPT_COMMAND, 0, 1, {0}, { p_unsigned_int }, 0, 0, 0, 0 },
194 { CMD_SYNC_WITH, SCRIPT_COMMAND, 0, 2, {0}, { p_string, p_string }, 0, 0, 0, 0 },
195 { CMD_TX_INTERVAL, SCRIPT_COMMAND, 0, 1, {0}, { p_float }, 0, 0, 0, 0 },
196 { CMD_TX_REPORT, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
197 { CMD_UNPROTO_MARKERS, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
198 { CMD_WARN_USER, SCRIPT_COMMAND, 0, 1, {0}, { p_string }, 0, 0, 0, 0 },
199 { CMD_XMIT_REPEAT, SCRIPT_COMMAND, 0, 1, {0}, { p_unsigned_int }, 0, 0, 0, 0 }
200 };
201
202 /** **************************************************************
203 * \brief Assign a list of valid parameters for verification checks.
204 * \param array An Array of pointers to each element.
205 * \param array_count Number of entries in the array.
206 * \return the array count or '0' if error.
207 * \par Note:
208 * This array is limited to the first parameter of the command
209 * used in it's comparison.
210 *****************************************************************/
assign_valid_parameters(const char * command,const char ** array,const int array_count)211 int ScriptParsing::assign_valid_parameters(const char *command, const char **array, const int array_count)
212 {
213 if(!array || array_count < 1 || !command) return 0;
214
215 int index = 0;
216 int count = 0;
217
218 SCRIPT_COMMANDS * cmd_sc = search_command(command);
219
220 if(!cmd_sc) {
221 return 0;
222 }
223
224 for(index = 0; index < array_count; index++) {
225 if(*array[index]) count++;
226 }
227
228 if(count != array_count) return 0;
229
230 cmd_sc->valid_values = array;
231 cmd_sc->valid_value_count = array_count;
232
233 return array_count;
234 }
235
236 /** **************************************************************
237 * \brief Return true state if string is matched.
238 * \param state Referenced value to assign results to.
239 * \param string Pointer to the data string.
240 * \param true_state Pointer to the data to match with.
241 * \return SCRIPT_CODES error code.
242 *****************************************************************/
test_on_off_state(bool & state,char * string,char * true_state=(char *)"ON")243 inline SCRIPT_CODES ScriptParsing::test_on_off_state(bool &state, char *string, char *true_state=(char *)"ON")
244 {
245 if(!string || !true_state) {
246 return script_function_parameter_error;
247 }
248
249 bool flag = false;
250
251 if(strncmp(string, true_state, MAX_PARAMETER_LENGTH) == 0)
252 flag = true;
253
254 state = flag;
255
256 return script_no_errors;
257 }
258
259 /** **************************************************************
260 * \brief Validate if file is located in the specified location.
261 * \param filename Pointer to a series of charcters
262 * \return SCRIPT_CODES error code.
263 *****************************************************************/
check_filename(char * filename,char * full_name_path=0,size_t limit=0,int path_flag=SCRIPT_COMMAND)264 SCRIPT_CODES ScriptParsing::check_filename(char *filename, char *full_name_path=0, size_t limit=0, int path_flag=SCRIPT_COMMAND)
265 {
266 char *filename_path = (char *)0;
267 char *path = (char *)0;
268 SCRIPT_CODES error = script_no_errors;
269 std::string user_path = "";
270
271 if(!filename) {
272 return script_function_parameter_error;
273 }
274
275 filename_path = new char[FILENAME_MAX + 1];
276
277 if(!filename_path) {
278 return script_memory_allocation_error;
279 }
280
281 memset(filename_path, 0, (FILENAME_MAX + 1));
282
283 path = new char[FILENAME_MAX + 1];
284
285 if(!path) {
286 delete [] filename_path;
287 return script_memory_allocation_error;
288 }
289
290 memset(path, 0, (FILENAME_MAX + 1));
291
292 if(path_flag == QUEUE_COMMAND) {
293 user_path.assign(this->queue_path());
294 } else {
295 user_path.assign(this->path());
296 }
297
298 if(user_path.empty()) {
299 if (!get_current_dir(path, FILENAME_MAX))
300 strncpy(path, user_path.c_str(), FILENAME_MAX);
301 } else {
302 strncpy(path, user_path.c_str(), FILENAME_MAX);
303 }
304
305 size_t size = strnlen(path, FILENAME_MAX);
306
307 if(size > 1) {
308 if(path[size - 1] != PATH_CHAR_SEPERATOR) {
309 strncat(path, PATH_SEPERATOR, FILENAME_MAX);
310 }
311 }
312
313 strncpy(filename_path, path, FILENAME_MAX);
314 strncat(filename_path, filename, FILENAME_MAX);
315
316 #ifdef TESTING
317 printf(" filename = %s\n", filename);
318 printf(" path = %s\n", path);
319 printf("filename_path = %s\n", filename_path);
320 #endif
321
322 FILE *fd = (FILE *)0;
323
324 fd = fopen(filename_path, "r");
325
326 if(!fd) {
327 error = script_file_not_found;
328 } else {
329 fclose(fd);
330
331 if(full_name_path && limit > 0)
332 strncpy(full_name_path, filename_path, limit);
333 }
334
335 delete [] filename_path;
336 delete [] path;
337
338 return error;
339 }
340
341 /** **************************************************************
342 * \brief Validate if path is present.
343 * \param path The path to verify.
344 * \return SCRIPT_CODES error code.
345 *****************************************************************/
check_path(const char * path)346 SCRIPT_CODES ScriptParsing::check_path(const char *path)
347 {
348 if(!path) {
349 return script_function_parameter_error;
350 }
351
352 struct stat st;
353 memset(&st, 0, sizeof(struct stat));
354
355 if(stat(path, &st) == 0) {
356 if(st.st_mode & S_IFDIR)
357 return script_no_errors;
358 }
359
360 return script_path_not_found;
361 }
362
363 /** **************************************************************
364 * \brief Validate if the parameter is a value.
365 * \param value The string in question.
366 * \param p format verification.
367 * \return SCRIPT_CODES error code.
368 *****************************************************************/
check_numbers(char * value,paramter_types p)369 SCRIPT_CODES ScriptParsing::check_numbers(char *value, paramter_types p)
370 {
371 SCRIPT_CODES error = script_no_errors;
372 size_t length = 0;
373 size_t index = 0;
374 int data_count = 0;
375 int signed_value = 0;
376 int decimal_point = 0;
377
378 if(!value)
379 return script_function_parameter_error;
380
381 length = strnlen(value, MAX_PARAMETER_LENGTH);
382
383 if(length < 1)
384 return script_parameter_error;
385
386 // Skip any leading white spaces.
387 for(index = 0; index < length; index++) {
388 if(value[index] > ' ')
389 break;
390 }
391
392 if((index >= length))
393 return script_parameter_error;
394
395 switch(p) {
396 case p_int:
397 case p_long:
398
399 if(value[0] == '-' || value[0] == '+') {
400 index++;
401 signed_value++;
402 }
403
404 case p_unsigned_int:
405 case p_unsigned_long:
406
407 for(; index< length; index++) {
408 if(isdigit(value[index]))
409 data_count++;
410 else
411 break;
412 }
413 break;
414
415 if(data_count)
416 return script_no_errors;
417
418 case p_float:
419 case p_double:
420 if(value[0] == '-' || value[0] == '+') {
421 index++;
422 signed_value++;
423 }
424
425 for(; index< length; index++) {
426 if(isdigit(value[index]))
427 data_count++;
428
429 if(value[index] == '.')
430 decimal_point++;
431
432 if(decimal_point > 1)
433 return script_parameter_error;
434 }
435
436 if(data_count)
437 return script_no_errors;
438
439 break;
440
441 default:;
442
443 }
444
445 return error;
446 }
447
448 /** **************************************************************
449 * \brief Validate the script parameter(s) are of the expected format.
450 * \param cmd Matching command data structure.
451 * \param p A table of expected parameters types (null terminated).
452 * \param p_count the number of 'p[]' items in the table (includes null termination).
453 * \return SCRIPT_CODES error code.
454 *****************************************************************/
check_parameters(struct script_cmds * cmd)455 SCRIPT_CODES ScriptParsing::check_parameters(struct script_cmds *cmd)
456 {
457 SCRIPT_CODES error = script_no_errors;
458 int count = 0;
459 int index = 0;
460 size_t size = 0;
461
462 if(!cmd)
463 return script_function_parameter_error;
464
465 count = cmd->argc;
466
467 if(count < 1)
468 return script_no_errors;
469
470 for(index = 0; index < count; index++) {
471
472 if(!cmd->args[index]) {
473 return script_args_eol;
474 }
475
476 if(cmd->param_check[index] == p_null) {
477 size = 0;
478 } else {
479 size = strnlen(cmd->args[index], MAX_COMMAND_LENGTH);
480 }
481
482 switch(cmd->param_check[index]) {
483 case p_null:
484 error = script_param_check_eol;
485 break;
486
487 case p_char:
488 if(size > 1)
489 error = script_paramter_exceeds_length;
490 break;
491
492 case p_int:
493 case p_long:
494 case p_unsigned_int:
495 case p_unsigned_long:
496 case p_float:
497 case p_double:
498 error = check_numbers(cmd->args[index], cmd->param_check[index]);
499 break;
500
501 case p_string:
502 if(size < 1)
503 error = script_parameter_error;
504 break;
505
506 case p_path:
507 error = check_path(cmd->args[index]);
508 break;
509
510 case p_filename:
511 error = check_filename(cmd->args[index]);
512 break;
513 }
514
515 if(error != script_no_errors)
516 break;
517 }
518
519 return error;
520 }
521
522 /** **************************************************************
523 * \brief Search the content of SCRIPT_COMMANDS structure table
524 * for the specified command.
525 * \param command The command to search for.
526 * \return Pointer to the matching SCRIPT_COMMANDS entry. Null if
527 * not found.
528 *****************************************************************/
search_command(const char * command)529 SCRIPT_COMMANDS * ScriptParsing::search_command(const char *command)
530 {
531 char *cmd_buffer = (char *)0;
532 int diff = 0;
533 SCRIPT_COMMANDS * found = (SCRIPT_COMMANDS *) 0;
534 size_t count = _script_command_table_count;
535 size_t index = 0;
536
537 if(!command) return found;
538
539 cmd_buffer = new char [MAX_COMMAND_LENGTH];
540
541 if(!cmd_buffer) {
542 LOG_INFO("cmd_buffer allocation error near line %d", __LINE__);
543 return found;
544 }
545
546 memset(cmd_buffer, 0, MAX_COMMAND_LENGTH);
547 strncpy(cmd_buffer, command, MAX_COMMAND_LENGTH-1);
548
549 to_uppercase(cmd_buffer, (int) MAX_COMMAND_LENGTH);
550 trim(cmd_buffer, (int) MAX_COMMAND_LENGTH);
551
552 for(index = 0; index < count; index++) {
553 diff = strncmp(cmd_buffer, _script_command_table[index].command, MAX_COMMAND_LENGTH);
554 if(diff == 0) {
555 found = &_script_command_table[index];
556 break;
557 }
558 }
559
560 cmd_buffer[0] = 0;
561 delete [] cmd_buffer;
562
563 return found;
564 }
565
566 /** **************************************************************
567 * \brief Convert string to uppercase characters.<br>
568 * \par str Pointer to data.
569 * \par limit data buffer size
570 * \return void
571 *****************************************************************/
to_uppercase(char * str,int limit)572 void ScriptParsing::to_uppercase(char *str, int limit)
573 {
574 if(!str || limit < 1) return;
575
576 int character = 0;
577 int count = 0;
578 int index = 0;
579
580 count = (int) strnlen(str, limit);
581
582 for(index = 0; index < count; index++) {
583 character = str[index];
584 if(character == 0) break;
585 character = (char) toupper(character);
586 str[index] = character;
587 }
588 }
589
590 /** **************************************************************
591 * \brief Convert string to uppercase characters.<br>
592 * \par str String storage passed by reference.
593 * \return void
594 *****************************************************************/
to_uppercase(std::string & str)595 void ScriptParsing::to_uppercase(std::string &str)
596 {
597 int character = 0;
598 int count = 0;
599 int index = 0;
600
601 count = (int) str.length();
602
603 for(index = 0; index < count; index++) {
604 character = str[index];
605 if(character == 0) break;
606 character = (char) toupper(character);
607 str[index] = character;
608 }
609 }
610
611 /** **************************************************************
612 * \brief Assign Call back function to a given script command.<br>
613 * \param scriptCommand Script command string<br>
614 * \param cb Pointer to call back function. int (*cb)(ScriptParsing *sp, SCRIPT_COMMANDS *sc)
615 *****************************************************************/
assign_callback(const char * scriptCommand,int (* cb)(ScriptParsing * sp,SCRIPT_COMMANDS * sc))616 int ScriptParsing::assign_callback(const char *scriptCommand, int (*cb)(ScriptParsing *sp, SCRIPT_COMMANDS *sc))
617 {
618 char *cmd_buffer = (char *)0;
619 int diff = 0;
620 size_t count = _script_command_table_count;
621 size_t index = 0;
622
623 if(!scriptCommand || !cb) return 0;
624
625 cmd_buffer = new char[MAX_COMMAND_LENGTH];
626
627 if(!cmd_buffer) {
628 LOG_INFO("cmd_buffer allocation error near line %d", __LINE__);
629 return 0;
630 }
631
632 memset(cmd_buffer, 0, MAX_COMMAND_LENGTH);
633 strncpy(cmd_buffer, scriptCommand, MAX_COMMAND_LENGTH-1);
634
635 to_uppercase(cmd_buffer, (int) MAX_COMMAND_LENGTH);
636 trim(cmd_buffer, (int) MAX_COMMAND_LENGTH);
637
638 for(index = 0; index < count; index++) {
639 diff = strncmp(cmd_buffer, _script_command_table[index].command, MAX_COMMAND_LENGTH);
640 if(diff == 0) {
641 if(_script_command_table[index].cb)
642 LOG_INFO("Over writing call back funcion for \"%s\"", cmd_buffer);
643 _script_command_table[index].cb = cb;
644 break;
645 }
646 }
647
648 cmd_buffer[0] = 0;
649 delete [] cmd_buffer;
650
651 return 0;
652 }
653
654 /** **************************************************************
655 * \brief Assign func to func array checking array bounds.
656 * \param pos Position in the indexed array
657 * \param func The function (member) to assign
658 * \param limit Array count limit
659 * \return void (nothing)
660 *****************************************************************/
assign_func(size_t pos,calling_func func,size_t limit)661 void ScriptParsing::assign_func(size_t pos, calling_func func, size_t limit)
662 {
663 if(pos < limit) {
664 _script_command_table[pos].func = func;
665 _script_command_table[pos].command_length = strnlen(_script_command_table[pos].command, MAX_COMMAND_LENGTH);
666 }
667 }
668
669 /** **************************************************************
670 * \brief Initialize callable members.
671 * \return void (nothing)
672 *****************************************************************/
defaults(bool all)673 void ScriptParsing::defaults(bool all)
674 {
675 if(all) {
676 _call_from = "";
677 _call_to = "";
678 }
679
680 _clear_missing = false;
681 _event = false;
682 _event_forever = false;
683 _hamcast = false;
684 _hamcast_modem_1_enable = false;
685 _hamcast_modem_2_enable = false;
686 _hamcast_modem_3_enable = false;
687 _hamcast_modem_4_enable = false;
688 _inhibit_header = false;
689 _interval = false;
690 _proto = true;
691 _sync_with_flamp = false;
692 _sync_with_fldigi = false;
693 _sync_with_prior = false;
694 _tx_report = false;
695 _warn_user = false;
696 }
697
698 /** **************************************************************
699 * \brief Initialize callable members.
700 * \return void (nothing)
701 *****************************************************************/
initialize_function_members(void)702 void ScriptParsing::initialize_function_members(void)
703 {
704 // Ensure this is in the same sequence as the structure it's assigned to.
705 int index = 0;
706 assign_func(index++, &ScriptParsing::sc_auto_load_queue, _script_command_table_total_count);
707 assign_func(index++, &ScriptParsing::sc_base_encode, _script_command_table_total_count);
708 assign_func(index++, &ScriptParsing::sc_block_count, _script_command_table_total_count);
709 assign_func(index++, &ScriptParsing::sc_call_from, _script_command_table_total_count);
710 assign_func(index++, &ScriptParsing::sc_call_to, _script_command_table_total_count);
711 assign_func(index++, &ScriptParsing::sc_clear_missing, _script_command_table_total_count);
712 assign_func(index++, &ScriptParsing::sc_clear_rxq, _script_command_table_total_count);
713 assign_func(index++, &ScriptParsing::sc_clear_txq, _script_command_table_total_count);
714 assign_func(index++, &ScriptParsing::sc_compression, _script_command_table_total_count);
715 assign_func(index++, &ScriptParsing::sc_event_forever, _script_command_table_total_count);
716 assign_func(index++, &ScriptParsing::sc_event_timed, _script_command_table_total_count);
717 assign_func(index++, &ScriptParsing::sc_event_times, _script_command_table_total_count);
718 assign_func(index++, &ScriptParsing::sc_event_type, _script_command_table_total_count);
719 assign_func(index++, &ScriptParsing::sc_event, _script_command_table_total_count);
720 assign_func(index++, &ScriptParsing::sc_file, _script_command_table_total_count);
721 assign_func(index++, &ScriptParsing::sc_hamcast_modem, _script_command_table_total_count);
722 assign_func(index++, &ScriptParsing::sc_hamcast, _script_command_table_total_count);
723 assign_func(index++, &ScriptParsing::sc_hdr_repeat, _script_command_table_total_count);
724 assign_func(index++, &ScriptParsing::sc_header_modem, _script_command_table_total_count);
725 assign_func(index++, &ScriptParsing::sc_header, _script_command_table_total_count);
726 assign_func(index++, &ScriptParsing::sc_info, _script_command_table_total_count);
727 assign_func(index++, &ScriptParsing::sc_inhibit_header, _script_command_table_total_count);
728 assign_func(index++, &ScriptParsing::sc_interval, _script_command_table_total_count);
729 assign_func(index++, &ScriptParsing::sc_load_queue, _script_command_table_total_count);
730 assign_func(index++, &ScriptParsing::sc_load_txdir, _script_command_table_total_count);
731 assign_func(index++, &ScriptParsing::sc_modem, _script_command_table_total_count);
732 assign_func(index++, &ScriptParsing::sc_path, _script_command_table_total_count);
733 assign_func(index++, &ScriptParsing::sc_proto, _script_command_table_total_count);
734 assign_func(index++, &ScriptParsing::sc_queue_filepath, _script_command_table_total_count);
735 assign_func(index++, &ScriptParsing::sc_reset, _script_command_table_total_count);
736 assign_func(index++, &ScriptParsing::sc_rx_interval, _script_command_table_total_count);
737 assign_func(index++, &ScriptParsing::sc_sync_with, _script_command_table_total_count);
738 assign_func(index++, &ScriptParsing::sc_tx_interval, _script_command_table_total_count);
739 assign_func(index++, &ScriptParsing::sc_tx_report, _script_command_table_total_count);
740 assign_func(index++, &ScriptParsing::sc_unproto_makers, _script_command_table_total_count);
741 assign_func(index++, &ScriptParsing::sc_warn_user, _script_command_table_total_count);
742 assign_func(index++, &ScriptParsing::sc_xmit_repeat, _script_command_table_total_count);
743 }
744
745 /** **************************************************************
746 * \brief Constructor: Copy and initialize function arrays.<br>
747 *****************************************************************/
ScriptParsing()748 ScriptParsing::ScriptParsing()
749 {
750 size_t count = 0;
751
752 // Initialize class variables.
753
754 _auto_load_queue = false;
755 _base = 0;
756 _blocks = 0;
757 _call_from = "";
758 _call_to = "";
759 _clear_missing = false;
760 _clear_rxq = false;
761 _clear_txq = false;
762 _comp = false;
763 _desc = "";
764 _envent_times = "";
765 _event = false;
766 _event_forever = false;
767 _event_type = 0;
768 _file = "";
769 _file_type = SCRIPT_COMMAND;
770 _hamcast = false;
771 _hamcast_modem_1 = "";
772 _hamcast_modem_1_enable = false;
773 _hamcast_modem_2 = "";
774 _hamcast_modem_2_enable = false;
775 _hamcast_modem_3 = "";
776 _hamcast_modem_3_enable = false;
777 _hamcast_modem_4 = "";
778 _hamcast_modem_4_enable = false;
779 _hdr_repeat = 0;
780 _info = "";
781 _inhibit_header = false;
782 _interval = false;
783 _modem = "";
784 _path = "";
785 _proto = true;
786 _queue_filename = "";
787 _queue_path = "";
788 _reset = 0;
789 _rx_interval = 0;
790 _sync_with_flamp = false;
791 _sync_with_fldigi = false;
792 _sync_with_prior = false;
793 _tx_interval = 0;
794 _tx_report = false;
795 _warn_user = false;
796 _xmit_repeat = false;
797
798 _sub_script_count = 0;
799 _parent = (ScriptParsing *)0;
800
801 _script_command_table = (SCRIPT_COMMANDS *)0;
802 _script_command_table_count = 0;
803 _script_command_table_total_count = 0;
804
805 count = sizeof(default_script_command_table)/sizeof(SCRIPT_COMMANDS);
806
807 _script_command_table = new SCRIPT_COMMANDS[count + 1];
808
809 if(!_script_command_table) {
810 return;
811 }
812
813 _script_command_table_count = count;
814 _script_command_table_total_count = count + 1;
815
816 memset(_script_command_table, 0, sizeof(SCRIPT_COMMANDS) * _script_command_table_total_count);
817 memcpy(_script_command_table, default_script_command_table, sizeof(default_script_command_table));
818
819 memset(line_buffer, 0, sizeof(line_buffer));
820
821 initialize_function_members();
822
823 }
824
825 /** **************************************************************
826 * \brief Copy environment to the sub ScriptParsing class
827 * \param src Source Class pointer to copy from.
828 *****************************************************************/
CopyScriptParsingEnv(ScriptParsing * src)829 int ScriptParsing::CopyScriptParsingEnv(ScriptParsing *src)
830 {
831 if(!src || (src == this)) return -1;
832
833 #if 0 // Do not copy these variables.
834 desc(src->desc());
835 file(src->file());
836 load_queue(src->load_queue());
837 #endif // 0
838
839 auto_load_queue(src->auto_load_queue());
840 base(src->base());
841 blocks(src->blocks());
842 call_from(src->call_from());
843 call_to(src->call_to());
844 clear_missing(src->clear_missing());
845 clear_rxq(src->clear_rxq());
846 clear_txq(src->clear_txq());
847 comp(src->comp());
848 event_forever(src->event_forever());
849 event_times(src->event_times());
850 event_type(src->event_type());
851 event(src->event());
852 hamcast_modem_1_enable(src->hamcast_modem_1_enable());
853 hamcast_modem_1(src->hamcast_modem_1());
854 hamcast_modem_2_enable(src->hamcast_modem_2_enable());
855 hamcast_modem_2(src->hamcast_modem_2());
856 hamcast_modem_3_enable(src->hamcast_modem_3_enable());
857 hamcast_modem_3(src->hamcast_modem_3());
858 hamcast_modem_4_enable(src->hamcast_modem_4_enable());
859 hamcast_modem_4(src->hamcast_modem_4());
860 hamcast(src->hamcast());
861 hdr_repeat(src->hdr_repeat());
862 info(src->info());
863 inhibit_header(src->inhibit_header());
864 interval(src->interval());
865 modem(src->modem());
866 path(src->path());
867 proto(src->proto());
868 reset(src->reset());
869 rx_interval(src->rx_interval());
870 sync_with_flamp(src->sync_with_flamp());
871 sync_with_fldigi(src->sync_with_fldigi());
872 sync_with_prior(src->sync_with_prior());
873 tx_interval(src->tx_interval());
874 tx_report(src->tx_report());
875 warn_user(src->warn_user());
876 xmit_repeat(src->xmit_repeat());
877
878 parent(src);
879 script_command_table_count(src->script_command_table_count());
880 script_command_table_total_count(src->script_command_table_total_count());
881 sub_script_count(src->sub_script_count() + 1);
882
883 SCRIPT_COMMANDS * dst_table = script_command_table();
884 SCRIPT_COMMANDS * src_table = src->script_command_table();
885
886 size_t index = 0;
887 size_t count = script_command_table_count();
888
889 for(index = 0; index < count; index++) {
890 dst_table[index].cb = src_table[index].cb;
891 dst_table[index].valid_value_count = src_table[index].valid_value_count;
892 dst_table[index].valid_values = src_table[index].valid_values;
893 }
894
895 initialize_function_members();
896
897 return 0;
898 }
899
900 /** **************************************************************
901 * \brief Enable/Disable Auto load of TX queue during timed event.<br>
902 * \param cmd Pointer to matching struct script_cmds script
903 * command.
904 * \return SCRIPT_CODES error see \ref script_codes
905 * \par Script Command:<br>
906 * <tt>\"AUTO LOAD QUEUE:\<ON|OFF\>\"</tt><br>
907 * \par Script Parameters:<br>
908 * <tt>ON = Enable</tt><br>
909 * <tt>OFF = Disable</tt><br>
910 *****************************************************************/
sc_auto_load_queue(struct script_cmds * cmd)911 SCRIPT_CODES ScriptParsing::sc_auto_load_queue(struct script_cmds *cmd)
912 {
913 SCRIPT_CODES error = script_invalid_parameter;
914 bool state = false;
915
916 if(!cmd)
917 return script_function_parameter_error;
918
919 if(cmd->argc && cmd->args[0]) {
920 error = test_on_off_state(state, cmd->args[0]);
921
922 if(error == script_no_errors)
923 this->auto_load_queue(state);
924 }
925
926 return error;
927 }
928
929 /** **************************************************************
930 * \brief Set the base encoding type.<br>
931 * \param cmd Pointer to matching struct script_cmds script
932 * command.
933 * \return SCRIPT_CODES error see \ref script_codes
934 * \par Script Command:<br>
935 * <tt>\"BASE:\<64|128|256\>\"</tt><br>
936 * \par Script Parameters:<br>
937 * <tt>64 = Base64</tt><br>
938 * <tt>128 = Base128</tt><br>
939 * <tt>256 = Base256</tt><br>
940 *****************************************************************/
sc_base_encode(struct script_cmds * cmd)941 SCRIPT_CODES ScriptParsing::sc_base_encode(struct script_cmds *cmd)
942 {
943 if(!cmd)
944 return script_function_parameter_error;
945
946 int value = 0;
947
948 if(cmd->argc && cmd->args[0]) {
949
950 value = atoi(cmd->args[0]);
951
952 switch(value) {
953 case 64:
954 case 128:
955 case 256:
956 break;
957
958 default:
959 LOG_INFO("%s Valid Parameters: 64, 128, or 256.", cmd->command);
960 return script_invalid_parameter;
961 }
962
963 this->base(value);
964 }
965
966 return script_no_errors;
967 }
968
969 /** **************************************************************
970 * \brief Set the block count.
971 * \param cmd Pointer to matching struct script_cmds script
972 * command.
973 * \return SCRIPT_CODES error see \ref script_codes
974 * \par Script Command:<br>
975 * <tt>\"Blocks:\<value\>\"</tt><br>
976 * \par Script Parameters:<br>
977 * <tt>value = 16, 32, 48, ..., 2048</tt><br>
978 *****************************************************************/
sc_block_count(struct script_cmds * cmd)979 SCRIPT_CODES ScriptParsing::sc_block_count(struct script_cmds *cmd)
980 {
981 if(!cmd)
982 return script_function_parameter_error;
983
984 int value = 0;
985 int modulus = 0;
986
987 if(cmd->argc && cmd->args[0]) {
988 value = atoi(cmd->args[0]);
989
990 modulus = value % 16;
991
992 if(modulus == 0) {
993 this->blocks(value);
994 }
995 else {
996 LOG_INFO("%s Parameters are modulus 16 values (16, 32,..., 2048).", cmd->command);
997 return script_invalid_parameter;
998 }
999 }
1000
1001 return script_no_errors;
1002 }
1003
1004 /** **************************************************************
1005 * \brief Set the transmitting stations callsign.
1006 * \param cmd Pointer to matching struct script_cmds script
1007 * command.
1008 * \return SCRIPT_CODES error see \ref script_codes
1009 * \par Script Command:<br>
1010 * <tt>\"CALLFROM:\<string\>\"</tt><br>
1011 * \par Script Parameters:<br>
1012 * <tt>string = ham radio operator call sign</tt><br>
1013 *****************************************************************/
sc_call_from(struct script_cmds * cmd)1014 SCRIPT_CODES ScriptParsing::sc_call_from(struct script_cmds *cmd)
1015 {
1016 if(!cmd)
1017 return script_function_parameter_error;
1018
1019 if(cmd->argc && cmd->args[0]) {
1020 std::string value = "";
1021
1022 value.assign(cmd->args[0]);
1023
1024 if(!value.empty())
1025 this->call_from(value);
1026 else
1027 return script_invalid_parameter;
1028 }
1029
1030 return script_no_errors;
1031 }
1032
1033 /** **************************************************************
1034 * \brief Set the receiving station(s) callsign.
1035 * \param cmd Pointer to matching struct script_cmds script
1036 * command.
1037 * \return SCRIPT_CODES error see \ref script_codes
1038 * \par Script Command:<br>
1039 * <tt>\"CALLTO:\<string\>\"</tt><br>
1040 * \par Script Parameters:<br>
1041 * <tt>string = ham radio operator call sign</tt>
1042 *****************************************************************/
sc_call_to(struct script_cmds * cmd)1043 SCRIPT_CODES ScriptParsing::sc_call_to(struct script_cmds *cmd)
1044 {
1045 if(!cmd)
1046 return script_function_parameter_error;
1047
1048 if(cmd->argc && cmd->args[0]) {
1049 std::string value = "";
1050
1051 value.assign(cmd->args[0]);
1052
1053 if(!value.empty())
1054 this->call_to(value);
1055 else
1056 return script_invalid_parameter;
1057 }
1058
1059 return script_no_errors;
1060 }
1061
1062 /** **************************************************************
1063 * \brief Set flag to clear received missing block on a fill
1064 * retransmission.
1065 * \param cmd Pointer to matching struct script_cmds script
1066 * command.
1067 * \return SCRIPT_CODES error see \ref script_codes
1068 * \par Script Command:<br>
1069 * <tt>\"CLEAR MISSING:\<ON|OFF\>\"</tt><br>
1070 * \par Script Parameters:<br>
1071 * <tt>ON = Enable</tt><br>
1072 * <tt>OFF = Disable</tt><br>
1073 *****************************************************************/
sc_clear_missing(struct script_cmds * cmd)1074 SCRIPT_CODES ScriptParsing::sc_clear_missing(struct script_cmds *cmd)
1075 {
1076 SCRIPT_CODES error = script_invalid_parameter;
1077 bool state = false;
1078
1079 if(!cmd)
1080 return script_function_parameter_error;
1081
1082 if(cmd->argc && cmd->args[0]) {
1083 error = test_on_off_state(state, cmd->args[0]);
1084
1085 if(error == script_no_errors)
1086 this->clear_missing(state);
1087 }
1088
1089 return error;
1090 }
1091
1092 /** **************************************************************
1093 * \brief Remove all files in the receive queue.
1094 * \param cmd Pointer to matching struct script_cmds script
1095 * command.
1096 \return SCRIPT_CODES error see \ref script_codes
1097 * \par Script Command:<br>
1098 * <tt>\"CLEAR RXQ:\"</tt><br>
1099 * \par Script Parameters:<br>
1100 * <tt>None</tt><br>
1101 *****************************************************************/
sc_clear_rxq(struct script_cmds * cmd)1102 SCRIPT_CODES ScriptParsing::sc_clear_rxq(struct script_cmds *cmd)
1103 {
1104 return script_no_errors;
1105 }
1106
1107 /** **************************************************************
1108 * \brief Remove all files in the transmit queue.
1109 * \param cmd Pointer to matching struct script_cmds script
1110 * command.
1111 \return SCRIPT_CODES error see \ref script_codes
1112 * \par Script Command:<br>
1113 * <tt>\"CLEAR TXQ:\"</tt><br>
1114 * \par Script Parameters:<br>
1115 * <tt>None</tt><br>
1116 *****************************************************************/
sc_clear_txq(struct script_cmds * cmd)1117 SCRIPT_CODES ScriptParsing::sc_clear_txq(struct script_cmds *cmd)
1118 {
1119 return script_no_errors;
1120 }
1121
1122 /** **************************************************************
1123 * \brief Enable/Disable file compression on transmitted file.
1124 * \param cmd Pointer to matching struct script_cmds script
1125 * command.
1126 \return SCRIPT_CODES error see \ref script_codes
1127 * \par Script Command:<br>
1128 * <tt>\"COMP:\<ON|OFF\>\"</tt><br>
1129 * \par Script Parameters:<br>
1130 * <tt>ON = Enable</tt><br>
1131 * <tt>OFF = Disable</tt><br>
1132 *****************************************************************/
sc_compression(struct script_cmds * cmd)1133 SCRIPT_CODES ScriptParsing::sc_compression(struct script_cmds *cmd)
1134 {
1135 SCRIPT_CODES error = script_invalid_parameter;
1136 bool state = false;
1137
1138 if(!cmd)
1139 return script_function_parameter_error;
1140
1141 if(cmd->argc && cmd->args[0]) {
1142 error = test_on_off_state(state, cmd->args[0]);
1143
1144 if(error == script_no_errors)
1145 this->comp(state);
1146 }
1147
1148 return error;
1149 }
1150
1151 /** **************************************************************
1152 * \brief Set the event type used when events are enabled.
1153 * \param cmd Pointer to matching struct script_cmds script
1154 * command.
1155 * \return SCRIPT_CODES error see \ref script_codes
1156 * \par Script Command:<br>
1157 * <tt>\"EVENT TYPE:\<string\>\"</tt><br>
1158 * \par Script Parameters:<br>
1159 * <tt>\"5 min\" = Transmit every 5 minutes</tt><br>
1160 * <tt>\"15 min\" = Transmit every 15 minutes</tt><br>
1161 * <tt>\"30 min\" = Transmit every 30 minutes</tt><br>
1162 * <tt>\"Hourly\" = Transmit every hour</tt><br>
1163 * <tt>\"Even hours\" = Transmit every even hour</tt><br>
1164 * <tt>\"Odd hours\" = Transmit every odd hour</tt><br>
1165 * <tt>\"Repeated at\" = Transmit at specific time intervals repeatedly</tt><br>
1166 * <tt>\"One time at\" = Transmit at specific time intervals once</tt><br>
1167 * <tt>\"Continuous at\" = Transmit between specific time intervals repeatedly</tt><br>
1168 *****************************************************************/
sc_event_type(struct script_cmds * cmd)1169 SCRIPT_CODES ScriptParsing::sc_event_type(struct script_cmds *cmd)
1170 {
1171 if(!cmd)
1172 return script_function_parameter_error;
1173
1174 static const char *valid_values[] = {
1175 (char *) "5 MIN",
1176 (char *) "15 MIN",
1177 (char *) "30 MIN",
1178 (char *) "HOURLY",
1179 (char *) "EVEN HOURS",
1180 (char *) "ODD HOURS",
1181 (char *) "REPEATED AT",
1182 (char *) "ONE TIME AT",
1183 (char *) "CONTINUOUS AT"
1184 };
1185
1186 static const int event_ref[] = {
1187 et_5_min,
1188 et_15_min,
1189 et_30_min,
1190 et_hourly,
1191 et_even_hours,
1192 et_odd_hours,
1193 et_repeat_at,
1194 et_one_time_at,
1195 et_continious_at
1196 };
1197
1198 int match = -1;
1199 SCRIPT_CODES error = script_invalid_parameter;
1200 size_t count = (sizeof(valid_values)/sizeof(char *));
1201 size_t index = 0;
1202 std::string value = "";
1203
1204 if(cmd->argc && cmd->args[0]) {
1205 value.assign(cmd->args[0]);
1206 if(value.empty())
1207 return script_invalid_parameter;
1208
1209 to_uppercase(value);
1210
1211 for(index = 0; index < count; index++) {
1212 match = strncmp(value.c_str(), valid_values[index], MAX_PARAMETER_LENGTH);
1213 if(match == 0) {
1214 this->event_type(event_ref[index]);
1215 return script_no_errors;
1216 }
1217 }
1218 }
1219
1220 return error;
1221 }
1222
1223 /** **************************************************************
1224 * \brief Assign event times
1225 * \param cmd Pointer to matching struct script_cmds script
1226 * command.
1227 * \return SCRIPT_CODES error see \ref script_codes
1228 * \par Script Command
1229 * <tt>XMIT TIMES:<start_time-end_time> (Continuous at)</tt> or
1230 * <tt>XMIT TIMES:<single_event>,<next_single_event>,... (all other event types)</tt>
1231 * All times are in 0000 through 2359 Hr (zulu/utc) format
1232 *****************************************************************/
sc_event_times(struct script_cmds * cmd)1233 SCRIPT_CODES ScriptParsing::sc_event_times(struct script_cmds *cmd)
1234 {
1235 if(!cmd) return script_function_parameter_error;
1236
1237 char *cPtr = (char *)0;
1238 size_t count = cmd->argc;
1239 size_t hits = 0;
1240 size_t index = 0;
1241 size_t j = 0;
1242 size_t size = 0;
1243 size_t valid_data = 0;
1244 std::string valid_string = "";
1245
1246 if(!count) return script_parameter_error;
1247
1248 valid_string.clear();
1249
1250 for(index = 0; index < count; index++) {
1251 cPtr = cmd->args[index];
1252 if(!cPtr) break;
1253
1254 size = strnlen(cPtr, MAX_PARAMETER_LENGTH);
1255 hits = 0;
1256
1257 for(j = 0; j < size; j++) {
1258 if(!*cPtr) break;
1259 if(isdigit(*cPtr) || *cPtr == '-' || *cPtr == ' ') hits++;
1260 cPtr++;
1261 }
1262
1263 if(hits == size) {
1264 valid_data++;
1265 valid_string.append(cmd->args[index]).append(" ");
1266 }
1267 }
1268
1269 if(valid_data != count)
1270 return script_incorrectly_assigned_value;
1271
1272 event_times(valid_string);
1273
1274 return script_no_errors;
1275 }
1276
1277 /** **************************************************************
1278 * \brief Enable timed event to occur.
1279 * \param cmd Pointer to matching struct script_cmds script
1280 * command.
1281 * \return SCRIPT_CODES error see @ref script_codes
1282 * \par Script Command:<br>
1283 * <tt>\"EVENT TIMED:\<ON|OFF\>\"</tt><br>
1284 * \par Script Parameters:<br>
1285 * <tt>ON = Enable</tt><br>
1286 * <tt>OFF = Disable</tt><br>
1287 *****************************************************************/
sc_event_timed(struct script_cmds * cmd)1288 SCRIPT_CODES ScriptParsing::sc_event_timed(struct script_cmds *cmd)
1289 {
1290 SCRIPT_CODES error = script_invalid_parameter;
1291 bool state = false;
1292
1293 if(!cmd)
1294 return script_function_parameter_error;
1295
1296 if(cmd->argc && cmd->args[0]) {
1297 error = test_on_off_state(state, cmd->args[0]);
1298
1299 if(error == script_no_errors)
1300 this->event_timed(state);
1301 }
1302
1303 return error;
1304 }
1305
1306 /** **************************************************************
1307 * \brief Enable event transmission.
1308 * \param cmd Pointer to matching struct script_cmds script
1309 * command.
1310 * \return SCRIPT_CODES error see @ref script_codes
1311 * \par Script Command:<br>
1312 * <tt>\"EVENT:\<ON|OFF\>\"</tt><br>
1313 * \par Script Parameters:<br>
1314 * <tt>ON = Enable</tt><br>
1315 * <tt>OFF = Disable</tt><br>
1316 *****************************************************************/
sc_event(struct script_cmds * cmd)1317 SCRIPT_CODES ScriptParsing::sc_event(struct script_cmds *cmd)
1318 {
1319 SCRIPT_CODES error = script_invalid_parameter;
1320 bool state = false;
1321
1322 if(!cmd)
1323 return script_function_parameter_error;
1324
1325 if(cmd->argc && cmd->args[0]) {
1326 error = test_on_off_state(state, cmd->args[0]);
1327
1328 if(error == script_no_errors)
1329 this->event(state);
1330 }
1331
1332 return error;
1333 }
1334
1335 /** **************************************************************
1336 * \brief Enable forever timed event to occur.
1337 * \param cmd Pointer to matching struct script_cmds script
1338 * command.
1339 * \return SCRIPT_CODES error see @ref script_codes
1340 * \par Script Command:<br>
1341 * <tt>\"EVENT FOREVER:\<ON|OFF\>\"</tt><br>
1342 * \par Script Parameters:<br>
1343 * <tt>ON = Enable</tt><br>
1344 * <tt>OFF = Disable</tt><br>
1345 * \par Note:
1346 * Requires event flag to be enabled. See ScriptParsing::sc_event()
1347 *****************************************************************/
sc_event_forever(struct script_cmds * cmd)1348 SCRIPT_CODES ScriptParsing::sc_event_forever(struct script_cmds *cmd)
1349 {
1350 SCRIPT_CODES error = script_invalid_parameter;
1351 bool state = false;
1352
1353 if(!cmd)
1354 return script_function_parameter_error;
1355
1356 if(cmd->argc && cmd->args[0]) {
1357 error = test_on_off_state(state, cmd->args[0]);
1358
1359 if(error == script_no_errors)
1360 this->event_forever(state);
1361 }
1362
1363 return error;
1364 }
1365
1366 /** **************************************************************
1367 * \brief Varify and set file name / description parameters.
1368 * \param cmd Pointer to matching struct script_cmds script
1369 * command.
1370 * \return SCRIPT_CODES error see \ref script_codes
1371 * \par Script Command:<br>
1372 * <tt>\"FILE:<file_name.ext>\"</tt><br>
1373 *****************************************************************/
sc_file(struct script_cmds * cmd)1374 SCRIPT_CODES ScriptParsing::sc_file(struct script_cmds *cmd)
1375 {
1376 if(!cmd)
1377 return script_function_parameter_error;
1378
1379 char *buffer = (char *)0;
1380 SCRIPT_CODES error = script_no_errors;
1381 std::string value = "";
1382
1383 if(cmd->argc > 1) {
1384 buffer = new char[FILENAME_MAX];
1385
1386 if(!buffer)
1387 return script_memory_allocation_error;
1388
1389 memset(buffer, 0, FILENAME_MAX);
1390
1391 error = check_filename(cmd->args[0], buffer, FILENAME_MAX-1);
1392
1393 if(error != script_no_errors)
1394 return error;
1395
1396 value.assign(buffer);
1397
1398 delete [] buffer;
1399
1400 if(value.empty())
1401 return script_parameter_error;
1402
1403 this->file(value);
1404
1405 value.assign(cmd->args[1]);
1406
1407 if(value.size())
1408 this->desc(value);
1409 else
1410 this->desc("");
1411
1412 }
1413
1414 return script_no_errors;
1415 }
1416
1417 /** **************************************************************
1418 * \brief Assign modem type to hamcast position x
1419 * \param cmd Pointer to matching struct script_cmds script
1420 * command.
1421 * \return SCRIPT_CODES error see \ref script_codes
1422 * \par Script Command:<br>
1423 * <tt>\"HAMCAST MODEM:<pos>,<modem_id_string>\"</tt><br>
1424 * \par Script Parameters:<br>
1425 * <tt> pos = A value of 1, 2, 3, or 4</tt>
1426 * <tt> modem_id_string = MFSK32 (for example)</tt>
1427 *****************************************************************/
sc_hamcast_modem(struct script_cmds * cmd)1428 SCRIPT_CODES ScriptParsing::sc_hamcast_modem(struct script_cmds *cmd)
1429 {
1430 SCRIPT_CODES error = script_no_errors;
1431
1432 if(!cmd)
1433 return script_function_parameter_error;
1434
1435 bool flag = false;
1436 int diff = 0;
1437 int index = 0;
1438 int off_diff = 0;
1439 int on_diff = 0;
1440 int pos = 0;
1441
1442 size_t size = 0;
1443 std::string value = "";
1444
1445 if(cmd->argc > 1) {
1446 if(cmd->args[0])
1447 pos = atoi(cmd->args[0]);
1448
1449 if(pos < 1 || pos > 4) {
1450 LOG_INFO("Parameter 1 out of range. (1, 2, 3, or 4)");
1451 return script_invalid_parameter;
1452 }
1453
1454 if(cmd->args[1]) {
1455
1456 value.assign(cmd->args[1]);
1457
1458 if(value.empty())
1459 return script_invalid_parameter;
1460
1461 to_uppercase(value);
1462
1463 on_diff = strncmp(value.c_str(), "ON", MAX_PARAMETER_LENGTH);
1464 off_diff = strncmp(value.c_str(), "OFF", MAX_PARAMETER_LENGTH);
1465
1466 if(on_diff == 0 || off_diff == 0) {
1467 if(on_diff == 0) flag = true;
1468 else flag = false;
1469
1470 switch(pos) {
1471 case 1:
1472 this->hamcast_modem_1_enable(flag);
1473 break;
1474 case 2:
1475 this->hamcast_modem_2_enable(flag);
1476 break;
1477 case 3:
1478 this->hamcast_modem_3_enable(flag);
1479 break;
1480 case 4:
1481 this->hamcast_modem_4_enable(flag);
1482 break;
1483 }
1484
1485 return script_no_errors;
1486 }
1487
1488 if(cmd->valid_values && cmd->valid_value_count) {
1489 for(index = 0; index < cmd->valid_value_count; index++) {
1490 diff = strncmp(cmd->args[1], cmd->valid_values[index], MAX_PARAMETER_LENGTH);
1491 if(diff == 0) {
1492 switch(pos) {
1493 case 1:
1494 this->hamcast_modem_1(value);
1495 break;
1496 case 2:
1497 this->hamcast_modem_2(value);
1498 break;
1499 case 3:
1500 this->hamcast_modem_3(value);
1501 break;
1502 case 4:
1503 this->hamcast_modem_4(value);
1504 break;
1505 }
1506
1507 return script_no_errors;
1508 }
1509 }
1510 LOG_INFO("Non-matching/unavailable modem ID string (%s).", value.c_str());
1511 return script_invalid_parameter;
1512 }
1513
1514 size = (int) strnlen(cmd->args[1], MAX_PARAMETER_LENGTH);
1515
1516 if(size < 4) {
1517 error = script_invalid_parameter;
1518 } else {
1519 switch(pos) {
1520 case 1:
1521 this->hamcast_modem_1(value);
1522 break;
1523 case 2:
1524 this->hamcast_modem_2(value);
1525 break;
1526 case 3:
1527 this->hamcast_modem_3(value);
1528 break;
1529 case 4:
1530 this->hamcast_modem_4(value);
1531 break;
1532 }
1533 }
1534 }
1535 }
1536
1537 return error;
1538 }
1539
1540 /** **************************************************************
1541 * \brief Enable hamcast events
1542 * \param cmd Pointer to matching struct script_cmds script
1543 * command.
1544 * \return SCRIPT_CODES error see \ref script_codes
1545 * \par Script Command:<br>
1546 * <tt>\"HAMCAST:\<ON|OFF\>\"</tt><br>
1547 * \par Script Parameters:<br>
1548 * <tt>ON = Enable</tt><br>
1549 * <tt>OFF = Disable</tt><br>
1550 *****************************************************************/
sc_hamcast(struct script_cmds * cmd)1551 SCRIPT_CODES ScriptParsing::sc_hamcast(struct script_cmds *cmd)
1552 {
1553 SCRIPT_CODES error = script_invalid_parameter;
1554 bool state = false;
1555
1556 if(!cmd)
1557 return script_function_parameter_error;
1558
1559 if(cmd->argc && cmd->args[0]) {
1560 error = test_on_off_state(state, cmd->args[0]);
1561
1562 if(error == script_no_errors)
1563 this->hamcast(state);
1564 }
1565
1566 return error;
1567 }
1568
1569 /** **************************************************************
1570 * \brief Enable/Disable Header modem use.<br>
1571 * \param cmd Pointer to matching struct script_cmds script
1572 * command.
1573 * \return SCRIPT_CODES error see \ref script_codes
1574 * \par Script Command:<br>
1575 * <tt>\"HEADER:\<ON|OFF\>\"</tt><br>
1576 * \par Script Parameters:<br>
1577 * <tt>ON = Enable</tt><br>
1578 * <tt>OFF = Disable</tt><br>
1579 *****************************************************************/
sc_header(struct script_cmds * cmd)1580 SCRIPT_CODES ScriptParsing::sc_header(struct script_cmds *cmd)
1581 {
1582 SCRIPT_CODES error = script_invalid_parameter;
1583 bool state = false;
1584
1585 if(!cmd)
1586 return script_function_parameter_error;
1587
1588 if(cmd->argc && cmd->args[0]) {
1589 error = test_on_off_state(state, cmd->args[0]);
1590
1591 if(error == script_no_errors)
1592 this->auto_load_queue(state);
1593 }
1594
1595 return error;
1596 }
1597
1598 /** **************************************************************
1599 * \brief Process and test modem parameters for validity.
1600 * \param cmd Pointer to matching struct script_cmds script
1601 * command.
1602 * \return SCRIPT_CODES error see \ref script_codes
1603 * \par "Script Command:"<br>
1604 * <tt>\"HEADER MODEM:\<modem_id_string\>\"<br>
1605 * Example:\"HEADER MODEM:BPSK250\"</tt><br>
1606 *****************************************************************/
sc_header_modem(struct script_cmds * cmd)1607 SCRIPT_CODES ScriptParsing::sc_header_modem(struct script_cmds *cmd)
1608 {
1609 SCRIPT_CODES error = script_no_errors;
1610
1611 if(!cmd)
1612 return script_function_parameter_error;
1613
1614 int diff = 0;
1615 int index = 0;
1616 std::string value = "";
1617
1618 if(cmd->argc > 0 && cmd->args[0]) {
1619
1620 value.assign(cmd->args[0]);
1621
1622 if(value.empty())
1623 return script_invalid_parameter;
1624
1625 to_uppercase(value);
1626
1627 if(strncmp(value.c_str(), "ON", MAX_PARAMETER_LENGTH) == 0) {
1628 header_modem_enable(true);
1629 return script_no_errors;
1630 }
1631
1632 if(strncmp(value.c_str(), "OFF", MAX_PARAMETER_LENGTH) == 0) {
1633 header_modem_enable(false);
1634 return script_no_errors;
1635 }
1636
1637 if(cmd->valid_values && cmd->valid_value_count) {
1638 for(index = 0; index < cmd->valid_value_count; index++) {
1639 diff = strncmp(cmd->args[0], cmd->valid_values[index], MAX_PARAMETER_LENGTH);
1640 if(diff == 0) {
1641 header_modem(cmd->args[0]);
1642 return script_no_errors;
1643 }
1644 }
1645 LOG_INFO("Non-matching/unavailable modem ID string (%s).", value.c_str());
1646 return script_invalid_parameter;
1647 }
1648 }
1649
1650 return error;
1651 }
1652
1653 /** **************************************************************
1654 * \brief Set the header repeat count
1655 * \param cmd Pointer to matching struct script_cmds script
1656 * command.
1657 * \return SCRIPT_CODES error see \ref script_codes
1658 * \par Script Command:<br>
1659 * <tt>\"HDR REPEAT:<number>\"</tt><br>
1660 * \par Script Parameters:<br>
1661 * <tt>number = 1,2,3,...,10</tt><br>
1662 *****************************************************************/
sc_hdr_repeat(struct script_cmds * cmd)1663 SCRIPT_CODES ScriptParsing::sc_hdr_repeat(struct script_cmds *cmd)
1664 {
1665 if(!cmd)
1666 return script_function_parameter_error;
1667
1668 int value = 0;
1669
1670 if(cmd->argc && cmd->args[0]) {
1671 value = atoi(cmd->args[0]);
1672
1673 if(value < 1) value = 1;
1674 if(value > 10) value = 10;
1675
1676 this->hdr_repeat(value);
1677 }
1678
1679 return script_no_errors;
1680 }
1681
1682 /** **************************************************************
1683 * \brief Assign INFO field
1684 * \param cmd Pointer to matching struct script_cmds script
1685 * command.
1686 * \return SCRIPT_CODES error see \ref script_codes
1687 * \par Script Command:<br>
1688 * <tt>\"INFO:<string>\"</tt><br>
1689 * \par Script Parameters:<br>
1690 * <tt>string = Byte value 32 to byte value 255</tt><br>
1691 *****************************************************************/
sc_info(struct script_cmds * cmd)1692 SCRIPT_CODES ScriptParsing::sc_info(struct script_cmds *cmd)
1693 {
1694 if(!cmd)
1695 return script_function_parameter_error;
1696
1697 if(cmd->argc && cmd->args[0]) {
1698 std::string value = "";
1699 value.assign(cmd->args[0]);
1700
1701 if(value.empty())
1702 return script_incorrectly_assigned_value;
1703
1704 this->info(value);
1705 }
1706
1707 return script_no_errors;
1708 }
1709
1710 /** **************************************************************
1711 * \brief Enable/Disable Header modem use.
1712 * \param cmd Pointer to matching struct script_cmds script
1713 * command.
1714 * \return SCRIPT_CODES error see \ref script_codes
1715 * \par Script Command:<br>
1716 * <tt>\"INHIBIT HEADER:\<ON|OFF\>\"</tt><br>
1717 * \par Script Parameters:<br>
1718 * <tt>ON = Enable</tt><br>
1719 * <tt>OFF = Disable</tt><br>
1720 *****************************************************************/
sc_inhibit_header(struct script_cmds * cmd)1721 SCRIPT_CODES ScriptParsing::sc_inhibit_header(struct script_cmds *cmd)
1722 {
1723 SCRIPT_CODES error = script_invalid_parameter;
1724 bool state = false;
1725
1726 if(!cmd)
1727 return script_function_parameter_error;
1728
1729 if(cmd->argc && cmd->args[0]) {
1730 error = test_on_off_state(state, cmd->args[0]);
1731
1732 if(error == script_no_errors)
1733 this->inhibit_header(state);
1734 }
1735
1736 return error;
1737 }
1738
1739 /** **************************************************************
1740 * \brief Enable/Disable interval timer.
1741 * \param cmd Pointer to matching struct script_cmds script
1742 * command.
1743 * \return SCRIPT_CODES error see \ref script_codes
1744 * \par Script Command:<br>
1745 * <tt>\"INTERVAL:\<ON|OFF\>\"</tt><br>
1746 * \par Script Parameters:<br>
1747 * <tt>ON = Enable</tt><br>
1748 * <tt>OFF = Disable</tt><br>
1749 *****************************************************************/
sc_interval(struct script_cmds * cmd)1750 SCRIPT_CODES ScriptParsing::sc_interval(struct script_cmds *cmd)
1751 {
1752 SCRIPT_CODES error = script_invalid_parameter;
1753 bool state = false;
1754
1755 if(!cmd)
1756 return script_function_parameter_error;
1757
1758 if(cmd->argc && cmd->args[0]) {
1759 error = test_on_off_state(state, cmd->args[0]);
1760
1761 if(error == script_no_errors)
1762 this->interval(state);
1763 }
1764
1765 return error;
1766 }
1767
1768 /** **************************************************************
1769 * \brief Load Queue script execution.
1770 * \param cmd Pointer to matching struct script_cmds script
1771 * command.
1772 * \return SCRIPT_CODES error see \ref script_codes
1773 * \par Script Commands:
1774 * LOAD QUEUE:FILE,<file_name><br>
1775 * LOAD QUEUE:PATH,<directory_path><br>
1776 * \par Parameters
1777 * FILE = Indicates next prarmeter is a file name of the queue load script.<br>
1778 * PATH = Indicates next prarmeter is a path to the file name.<br>
1779 * \par Note(s):
1780 * This command is recursive for a maximum of MAX_SUB_SCRIPTS times.
1781 * Queue scripts use a subset of availble commands see default_script_command_table[]
1782 * int flags field for details. The parent ScriptParsing enviroment is
1783 * duplicated to the newly created subscript. Any modification to the subscript
1784 * environment will not effect the parent.
1785 *****************************************************************/
sc_load_queue(struct script_cmds * cmd)1786 SCRIPT_CODES ScriptParsing::sc_load_queue(struct script_cmds *cmd)
1787 {
1788 char *buffer = (char *)0;
1789 SCRIPT_CODES error = script_no_errors;
1790 std::string value = "";
1791
1792 if(sub_script_count() >= MAX_SUB_SCRIPTS)
1793 return script_max_sub_script_reached;
1794
1795 if(!cmd)
1796 return script_function_parameter_error;
1797
1798 if(cmd->argc > 1 && cmd->args[0] && cmd->args[1]) {
1799 value.assign(cmd->args[0]);
1800
1801 if(value.empty())
1802 return script_invalid_parameter;
1803
1804 to_uppercase(value);
1805
1806 if(strncmp(value.c_str(), "PATH", 4) == 0) {
1807
1808 value.assign(cmd->args[1]);
1809 if(value.empty())
1810 return script_invalid_parameter;
1811
1812 error = check_path(cmd->args[1]);
1813
1814 if(error != script_no_errors)
1815 return error;
1816
1817 this->queue_path(value);
1818
1819 return script_no_errors;
1820 }
1821
1822 if(strncmp(value.c_str(), "FILE", 4) == 0) {
1823 value.assign(cmd->args[1]);
1824 if(value.empty())
1825 return script_invalid_parameter;
1826
1827 buffer = new char[FILENAME_MAX];
1828 if(!buffer)
1829 return script_memory_allocation_error;
1830
1831 memset(buffer, 0, FILENAME_MAX);
1832
1833 error = check_filename(cmd->args[1], buffer, FILENAME_MAX-1, QUEUE_COMMAND);
1834
1835 if(error != script_no_errors)
1836 return error;
1837
1838 this->queue_filename(value);
1839
1840 ScriptParsing *sp = new ScriptParsing;
1841
1842 if(!sp) {
1843 delete [] buffer;
1844 return script_subscript_exec_fail;
1845 }
1846
1847 if(sp->CopyScriptParsingEnv(this)) {
1848 delete [] buffer;
1849 return script_subscript_exec_fail;
1850 }
1851
1852 sp->file_type(QUEUE_COMMAND);
1853
1854 error = sp->parse_commands(buffer);
1855
1856 delete [] buffer;
1857
1858 #ifdef TESTING
1859 printf("Modem:%s\n", this->modem().c_str());
1860 #endif // TESTING
1861
1862 return error;
1863 }
1864 }
1865
1866 return script_invalid_parameter;
1867 }
1868
1869 /** **************************************************************
1870 * \brief Flag the queue loader to load from the tx directory
1871 * \param cmd Pointer to matching struct script_cmds script
1872 * command.
1873 * \return SCRIPT_CODES error see \ref script_codes
1874 * \par Script Command:<br>
1875 * <tt>\"LOAD TXDIR:\<ON|OFF\>\"</tt><br>
1876 * \par Script Parameters:<br>
1877 * <tt>ON = Enable</tt><br>
1878 * <tt>OFF = Disable</tt><br>
1879 *****************************************************************/
sc_load_txdir(struct script_cmds * cmd)1880 SCRIPT_CODES ScriptParsing::sc_load_txdir(struct script_cmds *cmd)
1881 {
1882 SCRIPT_CODES error = script_invalid_parameter;
1883 bool state = false;
1884
1885 if(!cmd)
1886 return script_function_parameter_error;
1887
1888 if(cmd->argc && cmd->args[0]) {
1889 error = test_on_off_state(state, cmd->args[0]);
1890
1891 if(error == script_no_errors)
1892 this->load_txdir(state);
1893 }
1894
1895 return error;
1896
1897 }
1898
1899 /** **************************************************************
1900 * \brief Process and test modem parameters for validity.
1901 * \param cmd Pointer to matching struct script_cmds script
1902 * command.
1903 * \return SCRIPT_CODES error see \ref script_codes
1904 * \par "Script Command:"<br>
1905 * <tt>\"MODEM:\<modem_id_string\>\" Example:\"MODEM:BPSK250\"</tt><br>
1906 *****************************************************************/
sc_modem(struct script_cmds * cmd)1907 SCRIPT_CODES ScriptParsing::sc_modem(struct script_cmds *cmd)
1908 {
1909 if(!cmd)
1910 return script_function_parameter_error;
1911
1912 std::string value = "";
1913
1914 if(cmd->argc) {
1915 value.assign(cmd->args[0]);
1916
1917 if(value.empty())
1918 return script_parameter_error;
1919
1920 if(cmd->valid_values && cmd->valid_value_count) {
1921 int index = 0;
1922 int diff = 0;
1923 for(index = 0; index < cmd->valid_value_count; index++) {
1924 diff = strncmp(cmd->args[0], cmd->valid_values[index], MAX_PARAMETER_LENGTH);
1925 if(diff == 0) {
1926 this->modem(value);
1927 return script_no_errors;
1928 }
1929 }
1930 LOG_INFO("Non-matching/available modem ID string used (%s).", value.c_str());
1931 return script_invalid_parameter;
1932 }
1933
1934 this->modem(value);
1935 }
1936
1937 return script_no_errors;
1938 }
1939
1940 /** **************************************************************
1941 * \brief Base path for file access that follows.
1942 * \param cmd Pointer to matching struct script_cmds script
1943 * command.
1944 * \return SCRIPT_CODES error see \ref script_codes
1945 * \par "Script Command:"<br>
1946 * <tt>\"PATH:\<directory_path\>\" Example:\"PATH:/usr/local\"</tt><br>
1947 *****************************************************************/
sc_path(struct script_cmds * cmd)1948 SCRIPT_CODES ScriptParsing::sc_path(struct script_cmds *cmd)
1949 {
1950 if(!cmd)
1951 return script_function_parameter_error;
1952
1953 SCRIPT_CODES error = script_invalid_parameter;
1954 std::string value = "";
1955
1956 if(cmd->argc) {
1957 value.assign(cmd->args[0]);
1958
1959 if(value.empty())
1960 return script_parameter_error;
1961
1962 error = check_path(value.c_str());
1963
1964 if(error == script_no_errors) {
1965 this->path(value);
1966 }
1967 }
1968
1969 return error;
1970 }
1971
1972 /** **************************************************************
1973 * \brief Enable/Disable AMP2 protocol in the transmitted data.
1974 * \param cmd Pointer to matching struct script_cmds script
1975 * command.
1976 * \return SCRIPT_CODES error see \ref script_codes
1977 * \par Script Command:<br>
1978 * <tt>\"PROTO:\<ON|OFF\>\"</tt><br>
1979 * \par Script Parameters:<br>
1980 * <tt>ON = Enable</tt><br>
1981 * <tt>OFF = Disable</tt><br>
1982 *****************************************************************/
sc_proto(struct script_cmds * cmd)1983 SCRIPT_CODES ScriptParsing::sc_proto(struct script_cmds *cmd)
1984 {
1985 SCRIPT_CODES error = script_invalid_parameter;
1986 bool state = false;
1987
1988 if(!cmd)
1989 return script_function_parameter_error;
1990
1991 if(cmd->argc && cmd->args[0]) {
1992 error = test_on_off_state(state, cmd->args[0]);
1993
1994 if(error == script_no_errors)
1995 this->proto(state);
1996 }
1997
1998 return error;
1999 }
2000 /** **************************************************************
2001 * \brief Enable/Disable unproto makers.
2002 * \param cmd Pointer to matching struct script_cmds script
2003 * command.
2004 * \return SCRIPT_CODES error see \ref script_codes
2005 * \par Script Command:<br>
2006 * <tt>\"UNPROTO MARKERS:\<ON|OFF\>\"</tt><br>
2007 * \par Script Parameters:<br>
2008 * <tt>ON = Enable</tt><br>
2009 * <tt>OFF = Disable</tt><br>
2010 *****************************************************************/
sc_unproto_makers(struct script_cmds * cmd)2011 SCRIPT_CODES ScriptParsing::sc_unproto_makers(struct script_cmds *cmd)
2012 {
2013 SCRIPT_CODES error = script_invalid_parameter;
2014 bool state = false;
2015
2016 if(!cmd)
2017 return script_function_parameter_error;
2018
2019 if(cmd->argc && cmd->args[0]) {
2020 error = test_on_off_state(state, cmd->args[0]);
2021
2022 if(error == script_no_errors)
2023 this->unproto_markers(state);
2024 }
2025
2026 return error;
2027 }
2028
2029
2030 /** **************************************************************
2031 * \brief Event queue loading path (full path and file name)
2032 * \param cmd Pointer to matching struct script_cmds script
2033 * command.
2034 * \return SCRIPT_CODES error see \ref script_codes
2035 * \par Script Command:<br>
2036 * <tt>\"QUEUE FILEPATH:\</path/filename.txt>\"</tt><br>
2037 *****************************************************************/
sc_queue_filepath(struct script_cmds * cmd)2038 SCRIPT_CODES ScriptParsing::sc_queue_filepath(struct script_cmds *cmd)
2039 {
2040 if((cmd->argc > 0) && !cmd->args[0])
2041 return script_invalid_parameter;
2042
2043 FILE *fd = fopen(cmd->args[0], "r");
2044
2045 if(fd) {
2046 fclose(fd);
2047 queue_filepath(cmd->args[0]);
2048 return script_no_errors;
2049 }
2050
2051 return script_file_not_found;
2052 }
2053
2054 /** **************************************************************
2055 * \brief Reset program parameters
2056 * \param cmd Pointer to matching struct script_cmds script
2057 * command.
2058 * \return SCRIPT_CODES error see \ref script_codes
2059 * \par Script Command:<br>
2060 * <tt>\"RESET:\<ALL|PARTIAL\>\"</tt><br>
2061 * \par Script Parameters:<br>
2062 * <tt>ALL = Complete reset of all variables</tt><br>
2063 * <tt>PARTIAL = Parital reset of variables.</tt><br>
2064 * \par NOTE:
2065 * The resting of the data is handled by the callback function.
2066 *****************************************************************/
sc_reset(struct script_cmds * cmd)2067 SCRIPT_CODES ScriptParsing::sc_reset(struct script_cmds *cmd)
2068 {
2069 SCRIPT_CODES error = script_invalid_parameter;
2070
2071 if(!cmd)
2072 return script_function_parameter_error;
2073
2074 if(cmd->argc && cmd->args[0]) {
2075 int diff = 0;
2076 std::string value;
2077
2078 value.assign(cmd->args[0]);
2079 if(value.empty())
2080 return script_invalid_parameter;
2081
2082 to_uppercase(value);
2083
2084 diff = strncmp(value.c_str(), "PARTIAL", MAX_PARAMETER_LENGTH);
2085
2086 if(diff == 0) {
2087 this->reset(RESET_PARTIAL);
2088 return script_no_errors;
2089 }
2090
2091 diff = strncmp(value.c_str(), "ALL", MAX_PARAMETER_LENGTH);
2092
2093 if(diff == 0) {
2094 this->reset(RESET_ALL);
2095 return script_no_errors;
2096 }
2097 }
2098
2099 return error;
2100 }
2101
2102 /** **************************************************************
2103 * \brief Set the receive interval time (seconds)
2104 * \param cmd Pointer to matching struct script_cmds script
2105 * command.
2106 * \return SCRIPT_CODES error see \ref script_codes
2107 * \par Script Command:<br>
2108 * <tt>\"RX INTERVAL:\<time_in_seconds\>\"</tt><br>
2109 * <tt>Value range 1-120</tt>
2110 *****************************************************************/
sc_rx_interval(struct script_cmds * cmd)2111 SCRIPT_CODES ScriptParsing::sc_rx_interval(struct script_cmds *cmd)
2112 {
2113 if(!cmd)
2114 return script_function_parameter_error;
2115
2116 int value = 0;
2117
2118 if(cmd->argc && cmd->args[0]) {
2119 value = atoi(cmd->args[0]);
2120
2121 if(value < 1) value = 1;
2122 if(value > 120) value = 120;
2123
2124 this->rx_interval(value);
2125 }
2126
2127 return script_no_errors;
2128 }
2129
2130 /** **************************************************************
2131 * \brief Modem sync method between FLAMP and FLDIGI
2132 * \param cmd Pointer to matching struct script_cmds script
2133 * command.
2134 * \return SCRIPT_CODES error see \ref script_codes
2135 * \par Script Command:<br>
2136 * <tt>\"SYNC WITH:\<mode\>,\<ON|OFF\>\"</tt><br>
2137 * \par Script Parameters:<br>
2138 * <tt>FLAMP = FLDIGI Sync's with FLAMP</tt><br>
2139 * <tt>FLDIGI = FLAMP Sync's with FLDIGI</tt><br>
2140 * <tt>PRIOR = Set FLDIGI to FLAMP's modem prior to transmitting data</tt>
2141 * <tt>ON = Enable</tt>
2142 * <tt>OFF = Disable</tt>
2143 *****************************************************************/
sc_sync_with(struct script_cmds * cmd)2144 SCRIPT_CODES ScriptParsing::sc_sync_with(struct script_cmds *cmd)
2145 {
2146 SCRIPT_CODES error = script_invalid_parameter;
2147 bool state = false;
2148
2149 char *valid_values[] = {
2150 (char *) "FLAMP",
2151 (char *) "FLDIGI",
2152 (char *) "PRIOR"
2153 };
2154
2155 if(!cmd)
2156 return script_function_parameter_error;
2157
2158 if(cmd->argc && cmd->args[0]) {
2159 int diff = 0;
2160 std::string value;
2161
2162 value.assign(cmd->args[0]);
2163 if(value.empty())
2164 return script_invalid_parameter;
2165
2166 to_uppercase(value);
2167
2168 for(size_t index = 0; index < sizeof(valid_values)/sizeof(char *); index++) {
2169 diff = strncmp(value.c_str(), valid_values[index], MAX_PARAMETER_LENGTH);
2170
2171 if(diff == 0) {
2172 error = test_on_off_state(state, cmd->args[1]);
2173
2174 if(error == script_no_errors) {
2175 switch(index) {
2176 case 0:
2177 this->sync_with_flamp(state);
2178 break;
2179
2180 case 1:
2181 this->sync_with_fldigi(state);
2182 break;
2183
2184 case 2:
2185 this->sync_with_prior(state);
2186 break;
2187 }
2188 }
2189
2190 break;
2191 }
2192 }
2193 }
2194
2195 return error;
2196 }
2197
2198 /** **************************************************************
2199 * \brief Set the transmit interval in minutes
2200 * \param cmd Pointer to matching struct script_cmds script
2201 * command.
2202 * \return SCRIPT_CODES error see \ref script_codes
2203 * \par Script Command:<br>
2204 * <tt>\"TX INTERVAL:\<time_in_minutes\>\"</tt><br>
2205 * \par Script Parameters:<br>
2206 * <tt>Value range 1 to 8</tt><br>
2207 *****************************************************************/
sc_tx_interval(struct script_cmds * cmd)2208 SCRIPT_CODES ScriptParsing::sc_tx_interval(struct script_cmds *cmd)
2209 {
2210 if(!cmd)
2211 return script_function_parameter_error;
2212
2213 float value = 0;
2214
2215 if(cmd->argc && cmd->args[0]) {
2216 value = atof(cmd->args[0]);
2217
2218 if(value < 1) value = 1;
2219 if(value > 8) value = 8;
2220
2221 this->tx_interval(value);
2222 }
2223
2224 return script_no_errors;
2225 }
2226
2227 /** **************************************************************
2228 * \brief Enable/Diable transmit on report.
2229 * \param cmd Pointer to matching struct script_cmds script
2230 * command.
2231 * \return SCRIPT_CODES error see \ref script_codes
2232 * \par Script Command:<br>
2233 * <tt>\"TX REPORT:\<ON|OFF\>\"</tt><br>
2234 * \par Script Parameters:<br>
2235 * <tt>ON = Enable</tt><br>
2236 * <tt>OFF = Disable</tt><br>
2237 *****************************************************************/
sc_tx_report(struct script_cmds * cmd)2238 SCRIPT_CODES ScriptParsing::sc_tx_report(struct script_cmds *cmd)
2239 {
2240 SCRIPT_CODES error = script_invalid_parameter;
2241 bool state = false;
2242
2243 if(!cmd)
2244 return script_function_parameter_error;
2245
2246 if(cmd->argc && cmd->args[0]) {
2247 error = test_on_off_state(state, cmd->args[0]);
2248
2249 if(error == script_no_errors)
2250 this->tx_report(state);
2251 }
2252
2253 return error;
2254 }
2255
2256 /** **************************************************************
2257 * \brief
2258 * \param cmd Pointer to matching struct script_cmds script
2259 * command.
2260 * \return SCRIPT_CODES error see \ref script_codes
2261 * \par Script Command:<br>
2262 * <tt>\"WARN USER:\<ON|OFF\>\"</tt><br>
2263 * \par Script Parameters:<br>
2264 * <tt>ON = Enable</tt><br>
2265 * <tt>OFF = Disable</tt><br>
2266 *****************************************************************/
sc_warn_user(struct script_cmds * cmd)2267 SCRIPT_CODES ScriptParsing::sc_warn_user(struct script_cmds *cmd)
2268 {
2269 SCRIPT_CODES error = script_invalid_parameter;
2270 bool state = false;
2271
2272 if(!cmd)
2273 return script_function_parameter_error;
2274
2275 if(cmd->argc && cmd->args[0]) {
2276 error = test_on_off_state(state, cmd->args[0]);
2277
2278 if(error == script_no_errors)
2279 this->warn_user(state);
2280 }
2281
2282 return error;
2283 }
2284
2285 /** **************************************************************
2286 * \brief Set the number of times transmited data is repeated.
2287 * \param cmd Pointer to matching struct script_cmds script
2288 * command.
2289 * \return SCRIPT_CODES error see \ref script_codes
2290 * \par Script Command:<br>
2291 * <tt>\"XMIT REPEAT:\<count\>\"</tt><br>
2292 * \par Script Parameters:<br>
2293 * <tt>count = number of transmit repeats</tt><br>
2294 * <tt>Value range 1 - 100</tt>
2295 *****************************************************************/
sc_xmit_repeat(struct script_cmds * cmd)2296 SCRIPT_CODES ScriptParsing::sc_xmit_repeat(struct script_cmds *cmd)
2297 {
2298 if(!cmd)
2299 return script_function_parameter_error;
2300
2301 int value = 0;
2302
2303 if(cmd->argc && cmd->args[0]) {
2304 value = atoi(cmd->args[0]);
2305
2306 if(value < 1) value = 1;
2307 if(value > 100) value = 100;
2308
2309 this->xmit_repeat(value);
2310 }
2311
2312 return script_no_errors;
2313 }
2314
2315 /** **************************************************************
2316 * \brief Used for initialization of the function vector table.
2317 * \param cmd Pointer to matching struct script_cmds script
2318 * command.
2319 * \return SCRIPT_CODES error see \ref script_codes
2320 *****************************************************************/
sc_dummy(struct script_cmds * cmd)2321 SCRIPT_CODES ScriptParsing::sc_dummy(struct script_cmds *cmd)
2322 {
2323 return script_no_errors;
2324 }
2325
2326 /** **************************************************************
2327 * \brief Convert error numbers into human readable form.
2328 * \param error_no Error number to convert.
2329 * \param line_number The offending line number in the script file.
2330 * \param cmd The script command is question.
2331 * \return SCRIPT_CODES error see \ref script_codes
2332 *****************************************************************/
script_error_string(SCRIPT_CODES error_no,int line_number,char * cmd)2333 char * ScriptParsing::script_error_string(SCRIPT_CODES error_no, int line_number, char *cmd)
2334 {
2335 char *es = (char *) "";
2336
2337 memset(error_buffer, 0, sizeof(error_buffer));
2338 memset(error_cmd_buffer, 0, sizeof(error_cmd_buffer));
2339 memset(error_string, 0, sizeof(error_string));
2340
2341 if(cmd) {
2342 strncpy(error_cmd_buffer, cmd, sizeof(error_cmd_buffer)-1);
2343 }
2344
2345 switch(error_no) {
2346 case script_command_not_found:
2347 es = (char *) "Command Not Found";
2348 break;
2349
2350 case script_non_script_file:
2351 es = (char *) "Not a script file/tag not found";
2352 break;
2353
2354 case script_parameter_error:
2355 es = (char *) "Invalid parameter";
2356 break;
2357
2358 case script_function_parameter_error:
2359 es = (char *) "Invalid function parameter (internal non-script error)";
2360 break;
2361
2362 case script_mismatched_quotes:
2363 es = (char *) "Missing paired quotes (\")";
2364 break;
2365
2366 case script_general_error:
2367 es = (char *) "General Error";
2368 break;
2369
2370 case script_no_errors:
2371 es = (char *) "No Errors";
2372 break;
2373
2374 case script_char_match_not_found:
2375 es = (char *) "Character searched not found";
2376 break;
2377
2378 case script_end_of_line_reached:
2379 es = (char *) "End of line reached";
2380 break;
2381
2382 case script_file_not_found:
2383 es = (char *) "File not found";
2384 break;
2385
2386 case script_path_not_found:
2387 es = (char *) "Directory path not found";
2388 break;
2389
2390 case script_args_eol:
2391 es = (char *) "Unexpected end of parameter (args[]) list found";
2392 break;
2393
2394 case script_param_check_eol:
2395 es = (char *) "Unexpected end of parameter check list found";
2396 break;
2397
2398 case script_paramter_exceeds_length:
2399 es = (char *) "Character count in args[] parameter exceeds expectations";
2400 break;
2401
2402 case script_memory_allocation_error:
2403 es = (char *) "Memory Allocation Error (internal non-script error)";
2404 break;
2405
2406 case script_incorrectly_assigned_value:
2407 es = (char *) "Passed parameter is not of the expected type.";
2408 break;
2409
2410 case script_invalid_parameter:
2411 es = (char *) "Parameter is not valid.";
2412 break;
2413
2414 case script_command_seperator_missing:
2415 es = (char *) "Command missing ':'.";
2416 break;
2417
2418 case script_max_sub_script_reached:
2419 es = (char *) "Maximum open subscripts reached.";
2420 break;
2421
2422 case script_subscript_exec_fail:
2423 es = (char *) "Subscript execution fail (internal).";
2424 break;
2425
2426 default:
2427 es = (char *) "Undefined error";
2428 }
2429
2430 snprintf(error_buffer, sizeof(error_buffer)-1, "Line: %d Error:%d %s (%s)",
2431 line_number, error_no, es, error_cmd_buffer);
2432
2433 return error_buffer;
2434 }
2435
2436 /** **************************************************************
2437 * \brief Search for first occurrence of a non white space
2438 * \param data Data pointer to search.
2439 * \param limit Number of bytes in the data buffer.
2440 * \param error returned error code.
2441 * \return Pointer to character if found. Otherwise, return null
2442 * \par Note:<br>
2443 * The searched condition is ignored if the expected content is
2444 * encapsulated in quotes \(\"\"\).
2445 *****************************************************************/
skip_white_spaces(char * data,char * limit,SCRIPT_CODES & error)2446 char * ScriptParsing::skip_white_spaces(char * data, char * limit, SCRIPT_CODES &error)
2447 {
2448 char *cPtr = (char *) 0;
2449
2450 if(!data || !limit) {
2451 error = script_function_parameter_error;
2452 return (char *)0;
2453 }
2454
2455 for(cPtr = data; cPtr < limit; cPtr++) {
2456 if(*cPtr > ' ') {
2457 error = script_no_errors;
2458 return cPtr;
2459 }
2460 }
2461
2462 error = script_end_of_line_reached;
2463
2464
2465 return (char *)0; // End of line reached.
2466 }
2467
2468 /** **************************************************************
2469 * \brief Search for the first occurrence on a non number.
2470 * \param data Data pointer to search.
2471 * \param limit Number of bytes in the data buffer.
2472 * \param error returned error code.
2473 * \return Pointer to character if found. Otherwise, return null
2474 * \par Note:<br>
2475 * The searched condition is ignored if the expected content is
2476 * encapsulated in quotes \(\"\"\).
2477 *****************************************************************/
skip_numbers(char * data,char * limit,SCRIPT_CODES & error)2478 char * ScriptParsing::skip_numbers(char * data, char * limit, SCRIPT_CODES &error)
2479 {
2480 char *cPtr = (char *) 0;
2481 int q_flag = 0;
2482
2483 if(!data || !limit) {
2484 error = script_function_parameter_error;
2485 return (char *)0;
2486 }
2487
2488 for(cPtr = data; cPtr < limit; cPtr++) {
2489 if(*cPtr == '"') // Check for encapsulated strings ("")
2490 q_flag++;
2491
2492 if((q_flag & 0x1)) // Continue if string is encapsulated
2493 continue;
2494
2495 if(!isdigit(*cPtr)) {
2496 error = script_no_errors;
2497 return cPtr;
2498 }
2499 }
2500
2501 if(q_flag & 0x1) {
2502 error = script_mismatched_quotes;
2503 } else {
2504 error = script_end_of_line_reached;
2505 }
2506
2507 return (char *)0; // End of line reached.
2508 }
2509
2510 /** **************************************************************
2511 * \brief Skip characters until either a number or white space is
2512 * found.
2513 * \param data Data pointer to search.
2514 * \param limit Number of bytes in the data buffer.
2515 * \param error returned error code.
2516 * \return Pointer to character if found. Otherwise, return null
2517 * \par Note:<br>
2518 * The searched condition is ignored if the expected content is
2519 * encapsulated in quotes \(\"\"\).
2520 *****************************************************************/
skip_characters(char * data,char * limit,SCRIPT_CODES & error)2521 char * ScriptParsing::skip_characters(char * data, char * limit, SCRIPT_CODES &error)
2522 {
2523 char *cPtr = (char *) 0;
2524 int q_flag = 0;
2525
2526 if(!data || !limit) {
2527 error = script_function_parameter_error;
2528 return (char *)0;
2529 }
2530
2531 for(cPtr = data; cPtr < limit; cPtr++) {
2532 if(*cPtr == '"') // Check for encapsulated strings ("")
2533 q_flag++;
2534
2535 if((q_flag & 0x1)) // Continue if string is encapsulated
2536 continue;
2537
2538 if(isdigit(*cPtr) || *cPtr <= ' ') {
2539 error = script_no_errors;
2540 return cPtr;
2541 }
2542 }
2543
2544 if(q_flag & 0x1) {
2545 error = script_mismatched_quotes;
2546 } else {
2547 error = script_end_of_line_reached;
2548 }
2549
2550 return (char *)0; // End of line reached.
2551 }
2552
2553 /** **************************************************************
2554 * \brief Search for the first occurrence of a white space.
2555 * \param data Data pointer to search.
2556 * \param limit Number of bytes in the data buffer.
2557 * \param error returned error code.
2558 * \return Pointer to character if found. Otherwise, return null
2559 * \par Note:<br>
2560 * The searched condition is ignored if the expected content is
2561 * encapsulated in quotes \(\"\"\).
2562 *****************************************************************/
skip_alpha_numbers(char * data,char * limit,SCRIPT_CODES & error)2563 char * ScriptParsing::skip_alpha_numbers(char * data, char * limit, SCRIPT_CODES &error)
2564 {
2565 char *cPtr = (char *) 0;
2566 int q_flag = 0;
2567
2568 if(!data || !limit) {
2569 error = script_function_parameter_error;
2570 return (char *)0;
2571 }
2572
2573 for(cPtr = data; cPtr < limit; cPtr++) {
2574
2575 if(*cPtr == '"') // Check for encapsulated strings ("")
2576 q_flag++;
2577
2578 if((q_flag & 0x1)) // Continue if string is encapsulated
2579 continue;
2580
2581 if(*cPtr <= ' ') {
2582 error = script_no_errors;
2583 return cPtr;
2584 }
2585 }
2586
2587 if(q_flag & 0x1) {
2588 error = script_mismatched_quotes;
2589 } else {
2590 error = script_end_of_line_reached;
2591 }
2592
2593 return (char *)0; // End of line reached.
2594 }
2595
2596 /** **************************************************************
2597 * \brief Search for first occurrence of 'character'
2598 * \param c Character to search for
2599 * \param data Pointer to Data to search for character in.
2600 * \param limit Number of bytes in the data buffer.
2601 * \param error returned error code.
2602 * \return Pointer to character if found. Otherwise, return null
2603 * \par Note:<br>
2604 * The searched condition is ignored if the expected content is
2605 * encapsulated in quotes \(\"\"\).
2606 *****************************************************************/
skip_to_character(char c,char * data,char * limit,SCRIPT_CODES & error)2607 char * ScriptParsing::skip_to_character(char c, char * data, char * limit, SCRIPT_CODES &error)
2608 {
2609 char *cPtr = (char *) 0;
2610 int q_flag = 0;
2611
2612 if(!data || !limit) {
2613 error = script_function_parameter_error;
2614 return (char *)0;
2615 }
2616
2617 for(cPtr = data; cPtr < limit; cPtr++) {
2618 if(*cPtr == '"') // Check for encapsulated strings ("")
2619 q_flag++;
2620
2621 if((q_flag & 0x1)) // Continue if string is encapsulated
2622 continue;
2623
2624 if(*cPtr == c) { // Match found. Return pointer to it's location
2625 error = script_no_errors;
2626 return cPtr;
2627 }
2628 }
2629
2630 if(q_flag & 0x1) {
2631 error = script_mismatched_quotes;
2632 } else {
2633 error = script_end_of_line_reached;
2634 }
2635
2636 return (char *)0; // End of line reached.
2637 }
2638
2639 /** **************************************************************
2640 * \brief Replace CR, LF, and '#' with '0' (by value)
2641 * \param data Search data pointer
2642 * \param limit data buffer size
2643 * \return void (none)
2644 * \par Note:<br>
2645 * The searched condition is ignored if the remark character \(#\)
2646 * is encapsulated in quotes \(\"\"\).
2647 *****************************************************************/
remove_crlf_comments(char * data,char * limit,size_t & count)2648 SCRIPT_CODES ScriptParsing::remove_crlf_comments(char *data, char *limit, size_t &count)
2649 {
2650 char *cPtr = (char *) 0;
2651 int q_flag = 0;
2652
2653 SCRIPT_CODES error = script_no_errors;
2654
2655 if(!data || !limit)
2656 return script_function_parameter_error;
2657
2658 count = 0;
2659
2660 for(cPtr = data; cPtr < limit; cPtr++) {
2661 if(*cPtr == '\r' || *cPtr == '\n') {
2662 *cPtr = 0;
2663 return script_no_errors;
2664 }
2665
2666 if(*cPtr == '"')
2667 q_flag++;
2668
2669 if((q_flag & 0x1))
2670 continue;
2671
2672 if(*cPtr == '#') {
2673 *cPtr = 0;
2674 break;
2675 }
2676
2677 if(*cPtr > ' ')
2678 count++;
2679
2680 }
2681
2682 // Remove trailing white spaces.
2683 while(cPtr >= data) {
2684 if(*cPtr <= ' ') *cPtr = 0;
2685 else break;
2686 cPtr--;
2687 }
2688
2689 if(q_flag & 0x1) {
2690 error = script_mismatched_quotes;
2691 } else {
2692 error = script_end_of_line_reached;
2693 }
2694
2695 return error;
2696 }
2697
2698 /** **************************************************************
2699 * \brief Copy memory from address to address to the source buffer.
2700 * \param buffer Destination buffer
2701 * \param sPtr Start of the copy Address
2702 * \param ePtr End of the copy Address
2703 * \param limit Destination buffer size
2704 * command.
2705 * \return SCRIPT_CODES error see \ref script_codes
2706 *****************************************************************/
copy_command(char * buffer,char * sPtr,char * ePtr,size_t limit)2707 SCRIPT_CODES ScriptParsing::copy_command(char *buffer, char *sPtr, char *ePtr, size_t limit)
2708 {
2709 if(!buffer || !sPtr || !ePtr || limit < 1) {
2710 return script_function_parameter_error;
2711 }
2712
2713 char *dPtr = buffer;
2714 size_t index = 0;
2715
2716 for(index = 0; index < limit; index++) {
2717 *dPtr++ = toupper(*sPtr++);
2718 if(sPtr >= ePtr) break;
2719 }
2720
2721 return script_no_errors;
2722 }
2723
2724 /** **************************************************************
2725 * \brief Remove leading/trailing white spaces and quotes.
2726 * \param buffer Destination buffer
2727 * \param limit passed buffer size
2728 * \return void
2729 *****************************************************************/
trim(char * buffer,size_t limit)2730 void ScriptParsing::trim(char *buffer, size_t limit)
2731 {
2732 char *s = (char *)0;
2733 char *e = (char *)0;
2734 char *dst = (char *)0;
2735 size_t count = 0;
2736
2737 if(!buffer || limit < 1) {
2738 return;
2739 }
2740
2741 for(count = 0; count < limit; count++)
2742 if(buffer[count] == 0) break;
2743
2744 if(count < 1) return;
2745
2746 s = buffer;
2747 e = &buffer[count-1];
2748
2749 for(size_t i = 0; i < count; i++) {
2750 if((*s <= ' ') || (*s == '"')) s++;
2751 else break;
2752 }
2753
2754 while(e > s) {
2755 if((*e <= ' ') || (*e == '"'))
2756 *e = 0;
2757 else
2758 break;
2759 e--;
2760 }
2761
2762 dst = buffer;
2763 for(; s <= e; s++) {
2764 *dst++ = *s;
2765 }
2766 *dst = 0;
2767 }
2768
2769 /** **************************************************************
2770 * \brief Parse the parameters and seperate into individual components.
2771 * \param s char pointer to the start of the string.
2772 * \param e char pointer to the end of the string.
2773 * \param matching_command pointer to the data strucure of the matching
2774 * command. See \ref SCRIPT_COMMANDS
2775 * \return SCRIPT_CODES error see \ref script_codes
2776 *****************************************************************/
parse_parameters(char * s,char * e,SCRIPT_COMMANDS * matching_command)2777 SCRIPT_CODES ScriptParsing::parse_parameters(char *s, char *e, SCRIPT_COMMANDS *matching_command)
2778 {
2779 char *c = s;
2780 char *d = (char *)0;
2781 int index = 0;
2782 int parameter_count = matching_command->argc;
2783 int count = 0;
2784 long tmp = 0;
2785
2786 SCRIPT_CODES error = script_no_errors;
2787
2788 // Clear the old pointers.
2789 for(index = 0; index < MAX_CMD_PARAMETERS; index++) {
2790 matching_command->args[index] = (char *)0;
2791 }
2792
2793 if(parameter_count > 0) {
2794 count = parameter_count - 1;
2795 for(index = 0; index < count; index++) {
2796 c = skip_white_spaces(c, e, error);
2797
2798 if(error != script_no_errors)
2799 return script_parameter_error;
2800
2801 d = skip_to_character(',', c, e, error);
2802
2803 if(error != script_no_errors)
2804 return script_parameter_error;
2805
2806 *d = 0;
2807 tmp = (long) (d - c);
2808 if(tmp > 0)
2809 trim(c, (size_t)(tmp));
2810 matching_command->args[index] = c;
2811 c = d + 1;
2812 }
2813
2814 c = skip_white_spaces(c, e, error);
2815 if(error) return error;
2816
2817 d = skip_alpha_numbers(c, e, error);
2818 if(error) return error;
2819
2820 *d = 0;
2821 tmp = (long) (d - c);
2822 if(tmp > 0)
2823 trim(c, (size_t)(tmp));
2824
2825 matching_command->args[index] = c;
2826 }
2827
2828 #ifdef TESTING
2829 for(int i = 0; i < parameter_count; i++)
2830 if(matching_command->args[i])
2831 printf("parameters %d (%s)\n", i, matching_command->args[i]);
2832 #endif
2833
2834 error = check_parameters(matching_command);
2835
2836 if(error != script_no_errors)
2837 return error;
2838
2839 if(matching_command->func)
2840 error = (this->*matching_command->func)(matching_command);
2841 if(error) return error;
2842
2843
2844 return script_no_errors;
2845 }
2846
2847 /** **************************************************************
2848 * \brief Execute callback function.
2849 * \param cb_data Pointer for making a copy of the data to prevent
2850 * exterior alteration of source information.
2851 * \return 0 = No error<br> \< 0 = Error<br>
2852 *****************************************************************/
call_callback(SCRIPT_COMMANDS * cb_data)2853 int ScriptParsing::call_callback(SCRIPT_COMMANDS *cb_data)
2854 {
2855 int argc = 0;
2856 int error = 0;
2857 int index = 0;
2858 SCRIPT_COMMANDS *tmp = (SCRIPT_COMMANDS *)0;
2859 size_t count = 0;
2860
2861 if(!cb_data || !cb_data->cb) return -1;
2862
2863 argc = cb_data->argc;
2864
2865 tmp = new SCRIPT_COMMANDS;
2866
2867 if(!tmp) return -1;
2868
2869 memset(tmp, 0, sizeof(SCRIPT_COMMANDS));
2870
2871 for(index = 0; index < argc; index++) {
2872 if(cb_data->args[index]) {
2873 count = strnlen(cb_data->args[index], MAX_PARAMETER_LENGTH-1);
2874 tmp->args[index] = new char[count+1];
2875 if(tmp->args[index]) {
2876 memset(tmp->args[index], 0, count+1);
2877 strncpy(tmp->args[index], cb_data->args[index], count);
2878 } else {
2879 error = -1;
2880 break;
2881 }
2882 } else break;
2883 }
2884
2885 if(error > -1) {
2886 // Fill SCRIPT_COMMANDS (tmp) struct with useful data.
2887 tmp->flags = cb_data->flags;
2888 tmp->command_length = cb_data->command_length;
2889 tmp->argc = cb_data->argc;
2890 strncpy(tmp->command, cb_data->command, MAX_COMMAND_LENGTH);
2891
2892 // Initialize with do nothing functions
2893 tmp->func = &ScriptParsing::sc_dummy;
2894 tmp->cb = callback_dummy;
2895
2896 error = (*cb_data->cb)(this, tmp);
2897 }
2898
2899 if(tmp) {
2900 for(index = 0; index < argc; index++) {
2901 if(tmp->args[index]) {
2902 delete [] tmp->args[index];
2903 }
2904 }
2905
2906 delete tmp;
2907 }
2908
2909 return error;
2910 }
2911
2912 /** **************************************************************
2913 * \brief Parse a single line of data from the script file being read.
2914 * \param data Pointer the the script scring in question
2915 * \param buffer_size buffer size of the data pointer.
2916 * command.
2917 * \return SCRIPT_CODES error see \ref script_codes
2918 *****************************************************************/
parse_single_command(char * data,size_t buffer_size)2919 SCRIPT_CODES ScriptParsing::parse_single_command(char *data, size_t buffer_size)
2920 {
2921 char *buffer = (char *)0;
2922 char *cPtr = (char *)0;
2923 char *endPtr = (char *)0;
2924 char *ePtr = (char *)0;
2925 int allocated_buffer_size = 128;
2926 int callback_error = 0;
2927 size_t cmd_size = 0;
2928 size_t cmp_results = 0;
2929 size_t index = 0;
2930 size_t size = 0;
2931
2932 SCRIPT_CODES error = script_no_errors;
2933
2934 cPtr = data;
2935 endPtr = &data[buffer_size];
2936
2937 cPtr = skip_white_spaces(cPtr, endPtr, error);
2938 if(error != script_no_errors) return error;
2939
2940 ePtr = skip_to_character(':', cPtr, endPtr, error);
2941 if(error != script_no_errors) return script_command_seperator_missing;
2942
2943 buffer = new char [allocated_buffer_size];
2944 if(!buffer) {
2945 LOG_INFO("Buffer allocation Error near File: %s Line %d", __FILE__, __LINE__);
2946 return script_memory_allocation_error;
2947 }
2948
2949 memset(buffer, 0, allocated_buffer_size);
2950 error = copy_command(buffer, cPtr, ePtr, allocated_buffer_size-1);
2951 if(error != script_no_errors) {
2952 buffer[0] = 0;
2953 delete [] buffer;
2954 return error;
2955 }
2956
2957 int str_count = str_cnt(buffer, allocated_buffer_size);
2958 trim(buffer, str_count);
2959
2960 for(index = 0; index < _script_command_table_count; index++) {
2961 size = strnlen(_script_command_table[index].command, MAX_COMMAND_LENGTH);
2962 cmd_size = strnlen(buffer, MAX_COMMAND_LENGTH);
2963 cmp_results = memcmp(buffer, _script_command_table[index].command, size);
2964
2965 if(cmp_results == 0 && (cmd_size == size)) {
2966 if(file_type() & _script_command_table[index].flags) {
2967 error = parse_parameters(++ePtr, endPtr, &_script_command_table[index]);
2968 if(error) {
2969 buffer[0] = 0;
2970 delete [] buffer;
2971 return error;
2972 }
2973
2974 if(_script_command_table[index].cb) {
2975 callback_error = call_callback(&_script_command_table[index]);
2976 if(callback_error < 0)
2977 LOG_INFO("Call back for script command %s reported an Error", _script_command_table[index].command);
2978 }
2979 } else {
2980 LOG_INFO("Command %s ignored, not supported in current file type:", buffer);
2981 }
2982 break;
2983 }
2984 }
2985
2986 buffer[0] = 0;
2987 delete [] buffer;
2988
2989 return script_no_errors;
2990 }
2991
2992 /** **************************************************************
2993 * \brief Script entry point for parsing the script file.
2994 * \param file_name_path path and file name for the script to parse.
2995 * \return SCRIPT_CODES error see \ref script_codes
2996 *****************************************************************/
parse_commands(char * file_name_path)2997 SCRIPT_CODES ScriptParsing::parse_commands(char *file_name_path)
2998 {
2999 bool log_error = false;
3000 char *cPtr = (char *)0;
3001 FILE *fd = (FILE *)0;
3002 int line_number = 0;
3003 SCRIPT_CODES error_code = script_no_errors;
3004 size_t count = 0;
3005 size_t tmp = 0;
3006
3007 if(!file_name_path) {
3008 LOG_INFO("Invalid function parameter 'char *file_name_path' (null)");
3009 return script_general_error;
3010 }
3011
3012 fd = fopen(file_name_path, "r");
3013
3014 if(!fd) {
3015 LOG_INFO("Unable to open file %s", file_name_path);
3016 return script_general_error;
3017 }
3018
3019 memset(line_buffer, 0, sizeof(line_buffer));
3020
3021 line_number++;
3022 char *retval = fgets(line_buffer, sizeof(line_buffer) - 1, fd);
3023
3024 tmp = strlen(SCRIPT_FILE_TAG);
3025 line_buffer[tmp] = 0;
3026 tmp = strncmp(SCRIPT_FILE_TAG, line_buffer, tmp);
3027
3028 if(!retval || tmp) {
3029 cPtr = script_error_string(script_non_script_file, line_number, line_buffer);
3030 LOG_INFO("%s", cPtr);
3031 fclose(fd);
3032 return script_non_script_file;
3033 }
3034
3035 while(1) {
3036 if(ferror(fd) || feof(fd)) break;
3037
3038 memset(line_buffer, 0, sizeof(line_buffer));
3039 if(fgets(line_buffer, sizeof(line_buffer) - 1, fd))
3040 line_number++;
3041
3042 #ifdef TESTING
3043 printf("Reading: %s", line_buffer);
3044 #endif
3045
3046 error_code = remove_crlf_comments(line_buffer, &line_buffer[sizeof(line_buffer)], count);
3047
3048 if(count < 1) {
3049 continue;
3050 }
3051
3052 #ifdef TESTING
3053 printf("remove_crlf_comments(%s)\n", line_buffer);
3054 #endif
3055
3056 if(error_code >= script_no_errors)
3057 error_code = parse_single_command(line_buffer, sizeof(line_buffer) - 1);
3058
3059 if(error_code != script_no_errors) {
3060 LOG_INFO("%s", script_error_string(error_code, line_number, line_buffer));
3061 log_error = true;
3062 }
3063 }
3064
3065 fclose(fd);
3066
3067 if(log_error) {
3068 return script_general_error;
3069 }
3070
3071 return script_no_errors;
3072 }
3073
3074 /** **************************************************************
3075 * \brief Destructors
3076 *****************************************************************/
~ScriptParsing()3077 ScriptParsing::~ScriptParsing()
3078 {
3079 if(_script_command_table)
3080 delete [] _script_command_table;
3081 }
3082
3083 /** **************************************************************
3084 * \brief Dummy callback function for initialization of
3085 * function pointers.
3086 * \param sp The calling ScriptParsing Class
3087 * \param sc Command data structure pointer to the matching script
3088 * command.
3089 * \return 0 = No error<br> \< 0 = Error<br>
3090 *****************************************************************/
callback_dummy(ScriptParsing * sp,struct script_cmds * sc)3091 int callback_dummy(ScriptParsing *sp, struct script_cmds *sc)
3092 {
3093 return 0;
3094 }
3095
3096 /** ********************************************************
3097 * \brief Determine the length of the string with a count
3098 * limitation.
3099 * \return signed integer. The number of characters in the
3100 * array not to excede count limit.
3101 ***********************************************************/
str_cnt(char * str,int count_limit)3102 int ScriptParsing::str_cnt(char * str, int count_limit)
3103 {
3104 if(!str || (count_limit < 1))
3105 return 0;
3106
3107 int value = 0;
3108
3109 for(int index = 0; index < count_limit; index++) {
3110 if(str[index] == 0) break;
3111 value++;
3112 }
3113
3114 return value;
3115 }
3116
3117
3118
3119
3120