1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2015
3 //              Robert Stiles
4 //
5 // This file is part of fldigi
6 //
7 // fldigi is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // fldigi is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You 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 // ----------------------------------------------------------------------------
20 
21 #include <string.h>
22 #include "config.h"
23 #include "util.h"
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <pthread.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 
33 #include <FL/fl_utf8.h>
34 #include "debug.h"
35 #include "gettext.h"
36 #include "script_parsing.h"
37 #include "run_script.h"
38 
39 // Do not use directly. It's copied for each instance
40 
41 static const SCRIPT_COMMANDS default_operator_command_table[] = {
42 	{ CMD_CALLSIGN,                SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_callsign_info, 0, 0},
43 	{ CMD_NAME,                    SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_name_info,     0, 0},
44 	{ CMD_QTH,                     SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_qth_info,      0, 0},
45 	{ CMD_LOCATOR,                 SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_locator_info,  0, 0},
46 	{ CMD_ANTENNA,                 SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_antenna_info,  0, 0},
47 	{ CMD_END_CMD,                 SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
48 	{ {0} }
49 };
50 
51 static const SCRIPT_COMMANDS default_audio_device_command_table[] = {
52 	{ CMD_OSS_AUDIO,               SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_use_oss_audio_device,    0, 0},
53 	{ CMD_OSS_AUDIO_DEV_PATH,      SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_oss_audio_device_path,   0, 0},
54 	{ CMD_PORT_AUDIO,              SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_use_port_audio_device,   0, 0},
55 	{ CMD_PORTA_CAP,               SCRIPT_COMMAND, 0,  2, {0}, { p_int, p_dev_name }, 0, 0, 0, process_capture_path,            0, 0},
56 	{ CMD_PORTA_PLAY,              SCRIPT_COMMAND, 0,  2, {0}, { p_int, p_dev_name }, 0, 0, 0, process_playback_path,           0, 0},
57 	{ CMD_PULSEA,                  SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_use_pulse_audio_device,  0, 0},
58 	{ CMD_PULSEA_SERVER,           SCRIPT_COMMAND, 0,  1, {0}, { p_dev_path }, 0, 0, 0, process_pulse_audio_device_path, 0, 0},
59 	{ CMD_END_CMD,                 SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
60 	{ {0} }
61 };
62 
63 static const SCRIPT_COMMANDS default_audio_settings_command_table[] = {
64 	{ CMD_CAPTURE_SAMPLE_RATE,     SCRIPT_COMMAND, 0,  1, {0}, { p_string   },     0, 0, 0, process_audio_device_sample_rate_capture, 0, 0},
65 	{ CMD_PLAYBACK_SAMPLE_RATE,    SCRIPT_COMMAND, 0,  1, {0}, { p_string   },     0, 0, 0, process_audio_device_sample_rate_playback, 0, 0},
66 	{ CMD_AUDIO_CONVERTER,         SCRIPT_COMMAND, 0,  1, {0}, { p_string   },     0, 0, 0, process_audio_device_converter, 0, 0},
67 	{ CMD_RX_PPM,                  SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_rx_ppm, 0, 0},
68 	{ CMD_TX_PPM,                  SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_tx_ppm, 0, 0},
69 	{ CMD_TX_OFFSET,               SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_tx_offset, 0, 0},
70 	{ CMD_END_CMD,                 SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
71 	{ {0} }
72 };
73 
74 static const SCRIPT_COMMANDS default_audio_rt_channel_command_table[] = {
75 	{ CMD_AUDIO_L_R,               SCRIPT_COMMAND, 0,  1, {0}, { p_bool }, 0, 0, 0, process_modem_signal_left_right,  0, 0},
76 	{ CMD_AUDIO_REV_L_R,           SCRIPT_COMMAND, 0,  1, {0}, { p_bool }, 0, 0, 0, process_reverse_left_right,       0, 0},
77 	{ CMD_PTT_RIGHT_CHAN,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool }, 0, 0, 0, process_ptt_tone_right_channel,   0, 0},
78 	{ CMD_CW_QSK_RT_CHAN,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool }, 0, 0, 0, process_cw_qsk_right_channel,     0, 0},
79 	{ CMD_PSEUDO_FSK_RT_CHAN,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool }, 0, 0, 0, process_pseudo_fsk_right_channel, 0, 0},
80 	{ CMD_END_CMD,                 SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
81 	{ {0} }
82 };
83 
84 static const SCRIPT_COMMANDS default_audio_wave_command_table[] = {
85 	{ CMD_WAVE_SR, SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_wave_file_sample_rate, 0, 0},
86 	{ CMD_END_CMD, SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
87 	{ {0} }
88 };
89 
90 static const SCRIPT_COMMANDS default_rig_hrdwr_ptt_command_table[] = {
91 	{ CMD_HPPT_PTT_RT,             SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_hrdw_ptt_right_audio_channel, 0, 0},
92 	{ CMD_HPTT_SP2,                SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_hrdw_ptt_sep_serial_port, 0, 0},
93 	{ CMD_HPTT_SP2_PATH,           SCRIPT_COMMAND, 0,  1, {0}, { p_dev_path },     0, 0, 0, process_hrdw_ptt_sep_serial_port_path, 0, 0},
94 	{ CMD_HPTT_SP2_RTS,            SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_hrdw_ptt_sep_serial_port_rts, 0, 0},
95 	{ CMD_HPTT_SP2_DTR,            SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_hrdw_ptt_sep_serial_port_dtr, 0, 0},
96 	{ CMD_HPTT_SP2_RTS_V,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_hrdw_ptt_sep_serial_port_rts_v, 0, 0},
97 	{ CMD_HPTT_SP2_DTR_V,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_hrdw_ptt_sep_serial_port_dtr_v, 0, 0},
98 	{ CMD_HPTT_SP2_START_DELAY,    SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_hrdw_ptt_start_delay, 0, 0},
99 	{ CMD_HPTT_SP2_END_DELAY,      SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_hrdw_ptt_end_delay, 0, 0},
100 	{ CMD_HPTT_UHROUTER,           SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_hrdw_ptt_uhrouter, 0, 0},
101 	{ CMD_HPTT_SP2_INITIALIZE,     SCRIPT_COMMAND, 0,  0, {0}, { p_void },         0, 0, 0, process_hrdw_ptt_initialize, 0, 0},
102 	{ CMD_END_CMD,                 SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
103 	{ {0} }
104 };
105 
106 static const SCRIPT_COMMANDS default_rigcat_command_table[] = {
107 	{ CMD_RIGCAT_STATE,            SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_use_rigcat, 0, 0},
108 	{ CMD_RIGCAT_DESC_FILE,        SCRIPT_COMMAND, 0,  1, {0}, { p_filename },     0, 0, 0, process_rigcat_desc_file, 0, 0},
109 	{ CMD_RIGCAT_DEV_PATH,         SCRIPT_COMMAND, 0,  1, {0}, { p_dev_path },     0, 0, 0, process_rigcat_device_path, 0, 0},
110 	{ CMD_RIGCAT_RETRIES,          SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_rigcat_retries, 0, 0},
111 	{ CMD_RIGCAT_RETRY_INTERVAL,   SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_rigcat_retry_interval, 0, 0},
112 	{ CMD_RIGCAT_WRITE_DELAY,      SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_rigcat_write_delay, 0, 0},
113 	{ CMD_RIGCAT_INTIAL_DELAY,     SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_rigcat_init_delay, 0, 0},
114 	{ CMD_RIGCAT_BAUD_RATE,        SCRIPT_COMMAND, 0,  1, {0}, { p_string },       0, 0, 0, process_rigcat_baud_rate, 0, 0},
115 	{ CMD_RIGCAT_STOP_BITS,        SCRIPT_COMMAND, 0,  1, {0}, { p_float  },       0, 0, 0, process_rigcat_stop_bits, 0, 0},
116 	{ CMD_RIGCAT_ECHO,             SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_rigcat_commands_echoed, 0, 0},
117 	{ CMD_RIGCAT_TOGGLE_RTS_PTT,   SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_rigcat_toggle_rts_ptt, 0, 0},
118 	{ CMD_RIGCAT_RESTORE,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_rigcat_restore_on_close, 0, 0},
119 	{ CMD_RIGCAT_PTT_COMMAND,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_rigcat_cat_command_ptt, 0, 0},
120 	{ CMD_RIGCAT_RTS_12V,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_rigcat_rts_12v, 0, 0},
121 	{ CMD_RIGCAT_DTR_12V,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_rigcat_dtr_12v, 0, 0},
122 	{ CMD_RIGCAT_HRDWR_FLOW,       SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_rigcat_hrdwr_flow, 0, 0},
123 	{ CMD_RIGCAT_VSP,              SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_rigcat_vsp_enable, 0, 0},
124 	{ CMD_RIGCAT_INITIALIZE,       SCRIPT_COMMAND, 0,  0, {0}, { p_void },         0, 0, 0, process_rigcat_initialize, 0, 0},
125 	{ CMD_END_CMD,                 SCRIPT_COMMAND, 0,  0, {0}, { p_list_end },     0, 0, 0, 0, 0, 0},
126 	{ {0} }
127 };
128 
129 static const SCRIPT_COMMANDS default_hamlib_command_table[] = {
130 	{ CMD_HAMLIB_STATE,            SCRIPT_COMMAND, 0,  1, {0}, { p_bool },         0, 0, 0, process_use_hamlib,              0, 0},
131 	{ CMD_HAMLIB_RIG,              SCRIPT_COMMAND, 0,  1, {0}, { p_dev_name },     0, 0, 0, process_hamlib_rig,              0, 0},
132 	{ CMD_HAMLIB_DEV_PATH,         SCRIPT_COMMAND, 0,  1, {0}, { p_dev_path },     0, 0, 0, process_hamlib_device_path,      0, 0},
133 	{ CMD_HAMLIB_RETRIES,          SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_hamlib_retries,          0, 0},
134 	{ CMD_HAMLIB_RETRY_INTERVAL,   SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_hamlib_retry_interval,   0, 0},
135 	{ CMD_HAMLIB_WRITE_DELAY,      SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_hamlib_write_delay,      0, 0},
136 	{ CMD_HAMLIB_POST_WRITE_DELAY, SCRIPT_COMMAND, 0,  1, {0}, { p_unsigned_int }, 0, 0, 0, process_hamlib_post_write_delay, 0, 0},
137 	{ CMD_HAMLIB_BAUD_RATE,        SCRIPT_COMMAND, 0,  1, {0}, { p_string },       0, 0, 0, process_hamlib_baud_rate,        0, 0},
138 	{ CMD_HAMLIB_STOP_BITS,        SCRIPT_COMMAND, 0,  1, {0}, { p_string },       0, 0, 0, process_hamlib_stop_bits,        0, 0},
139 	{ CMD_HAMLIB_SIDE_BAND,        SCRIPT_COMMAND, 0,  1, {0}, { p_string },       0, 0, 0, process_hamlib_sideband,         0, 0},
140 	{ CMD_HAMLIB_PTT_COMMAND,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool   },       0, 0, 0, process_hamlib_ptt_hl_command,   0, 0},
141 	{ CMD_HAMLIB_DTR_12V,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool   },       0, 0, 0, process_hamlib_dtr_12,           0, 0},
142 	{ CMD_HAMLIB_RTS_12V,          SCRIPT_COMMAND, 0,  1, {0}, { p_bool   },       0, 0, 0, process_hamlib_rts_12,           0, 0},
143 	{ CMD_HAMLIB_HRDWR_FLOW,       SCRIPT_COMMAND, 0,  1, {0}, { p_bool   },       0, 0, 0, process_hamlib_rts_cts_flow,     0, 0},
144 	{ CMD_HAMLIB_SFTWR_FLOW,       SCRIPT_COMMAND, 0,  1, {0}, { p_bool   },       0, 0, 0, process_hamlib_xon_xoff_flow,    0, 0},
145 	{ CMD_HAMLIB_ADV_CONFIG,       SCRIPT_COMMAND, 0,  1, {0}, { p_string },       0, 0, 0, process_hamlib_advanced_config,  0, 0},
146 	{ CMD_HAMLIB_INITIALIZE,       SCRIPT_COMMAND, 0,  0, {0}, { p_void   },       0, 0, 0, process_hamlib_initialize,       0, 0},
147 	{ CMD_END_CMD,                 SCRIPT_COMMAND, 0,  0, {0}, { p_list_end },     0, 0, 0, 0, 0, 0},
148 	{ {0} }
149 };
150 
151 static const SCRIPT_COMMANDS default_kiss_command_table[] = {
152 	{ CMD_IO_KISS_IPA,             SCRIPT_COMMAND, 0,  1, {0}, { p_string  },  0, 0, 0, process_io_kiss_ip_address,     0, 0},
153 	{ CMD_IO_KISS_IOPN,            SCRIPT_COMMAND, 0,  1, {0}, { p_int  },     0, 0, 0, process_io_kiss_io_port_no,     0, 0},
154 	{ CMD_IO_KISS_OPN,             SCRIPT_COMMAND, 0,  1, {0}, { p_int  },     0, 0, 0, process_io_kiss_o_port_no,      0, 0},
155 	{ CMD_IO_KISS_DP,              SCRIPT_COMMAND, 0,  1, {0}, { p_bool  },    0, 0, 0, process_io_kiss_dual_port,      0, 0},
156 	{ CMD_IO_KISS_BUSY,            SCRIPT_COMMAND, 0,  1, {0}, { p_bool  },    0, 0, 0, process_io_kiss_busy_channel,   0, 0},
157 	{ CMD_IO_KISS_CONT,            SCRIPT_COMMAND, 0,  1, {0}, { p_int  },     0, 0, 0, process_io_kiss_continue_after, 0, 0},
158 	{ CMD_IO_KISS_ATTEN,           SCRIPT_COMMAND, 0,  1, {0}, { p_int  },     0, 0, 0, process_io_kiss_kpsql_atten,    0, 0},
159 	{ CMD_END_CMD,                 SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
160 	{ {0} }
161 };
162 
163 static const SCRIPT_COMMANDS default_arq_command_table[] = {
164 	{ CMD_IO_ARQ_IPA,             SCRIPT_COMMAND, 0,  1, {0}, { p_string  },  0, 0, 0, process_io_arq_ip_address, 0, 0},
165 	{ CMD_IO_ARQ_IOPN,            SCRIPT_COMMAND, 0,  1, {0}, { p_int  },     0, 0, 0, process_io_arq_io_port_no, 0, 0},
166 	{ CMD_END_CMD,                SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
167 	{ {0} }
168 };
169 
170 static const SCRIPT_COMMANDS default_xmlrpc_command_table[] = {
171 	{ CMD_IO_XMLRPC_IPA,          SCRIPT_COMMAND, 0,  1, {0}, { p_string  },  0, 0, 0, process_io_xmlrpc_ip_address, 0, 0},
172 	{ CMD_IO_XMLRPC_IOPN,         SCRIPT_COMMAND, 0,  1, {0}, { p_int  },     0, 0, 0, process_io_xmlrpc_io_port_no, 0, 0},
173 	{ CMD_END_CMD,                SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
174 	{ {0} }
175 };
176 
177 static const SCRIPT_COMMANDS default_io_command_table[] = {
178 	{ CMD_IO_LOCK,         SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_io_lock,        0, 0},
179 	{ CMD_IO_ACT_PORT,     SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_io_active_port, 0, 0},
180 	{ CMD_IO_AX25_DECODE,  SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_io_ax25_decode, 0, 0},
181 	{ CMD_IO_CSMA,         SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_io_csma,        0, 0},
182 	{ CMD_IO_KISS,         SCRIPT_COMMAND, 0,  0, {0}, { p_list     }, 0, 0, 0, 0, (struct script_cmds *) &default_kiss_command_table,   sizeof(default_kiss_command_table)/sizeof(SCRIPT_COMMANDS)},
183 	{ CMD_IO_ARQ,          SCRIPT_COMMAND, 0,  0, {0}, { p_list     }, 0, 0, 0, 0, (struct script_cmds *) &default_arq_command_table,    sizeof(default_arq_command_table)/sizeof(SCRIPT_COMMANDS)},
184 	{ CMD_IO_XMLRPC,       SCRIPT_COMMAND, 0,  0, {0}, { p_list     }, 0, 0, 0, 0, (struct script_cmds *) &default_xmlrpc_command_table, sizeof(default_xmlrpc_command_table)/sizeof(SCRIPT_COMMANDS)},
185 	{ CMD_END_CMD,         SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
186 	{ {0} }
187 };
188 
189 static const SCRIPT_COMMANDS default_fldigi_command_table[] = {
190 	{ CMD_FLDIGI_FREQ,      SCRIPT_COMMAND, 0,  1, {0}, { p_double   }, 0, 0, 0, process_rig_freq,     0, 0},
191 	{ CMD_FLDIGI_MODE,      SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_rig_mode,     0, 0},
192 	{ CMD_FLDIGI_WFHZ,      SCRIPT_COMMAND, 0,  1, {0}, { p_int      }, 0, 0, 0, process_wf_hz_offset, 0, 0},
193 	{ CMD_FLDIGI_RXID,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rx_rsid,      0, 0},
194 	{ CMD_FLDIGI_TXID,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_tx_rsid,      0, 0},
195 	{ CMD_FLDIGI_SPOT,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_spot,         0, 0},
196 	{ CMD_FLDIGI_REV,       SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rev,          0, 0},
197 	{ CMD_FLDIGI_AFC,       SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_afc,          0, 0},
198 	{ CMD_FLDIGI_LOCK,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_lock,         0, 0},
199 	{ CMD_FLDIGI_SQL,       SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_sql,          0, 0},
200 	{ CMD_FLDIGI_KPSQL,     SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_kpsql,        0, 0},
201 	{ CMD_FLDIGI_KPSM,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_kpsql,        0, 0},
202 	{ CMD_FLDIGI_MODEM,     SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_modem,        0, 0},
203 	{ CMD_END_CMD,          SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
204 	{ {0} }
205 };
206 
207 
208 static const SCRIPT_COMMANDS default_nbems_command_table[] = {
209 	{ CMD_NBEMS_FLMSG_PATH, SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_misc_nbems_flmsg_path, 0, 0},
210 	{ CMD_NBEMS_TIMEOUT,    SCRIPT_COMMAND, 0,  1, {0}, { p_double   }, 0, 0, 0, process_misc_nbems_timeout,    0, 0},
211 	{ CMD_NBEMS_STATE,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_misc_nbems_state,      0, 0},
212 	{ CMD_NBEMS_MSG,        SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_misc_nbems_open_msg,   0, 0},
213 	{ CMD_NBEMS_FLMSG,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_misc_nbems_open_flmsg, 0, 0},
214 	{ CMD_NBEMS_BRWSR,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_misc_nbems_open_brwsr, 0, 0},
215 	{ CMD_END_CMD,          SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
216 	{ {0} }
217 };
218 
219 static const SCRIPT_COMMANDS default_id_rsid_command_table[] = {
220 	{ CMD_ID_RSID_NOTIFY,       SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rsid_notify,       0, 0},
221 	{ CMD_ID_RSID_SRCH_BP,      SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rsid_search_bp,    0, 0},
222 	{ CMD_ID_RSID_MARK_PREV,    SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rsid_mark_prev,    0, 0},
223 	{ CMD_ID_RSID_DETECTOR,     SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rsid_detector,     0, 0},
224 	{ CMD_ID_RSID_ALRT_DIALOG,  SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rsid_alert_dialog, 0, 0},
225 	{ CMD_ID_RSID_TX_FREQ_LOCK, SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rsid_tx_freq_lock, 0, 0},
226 	{ CMD_ID_RSID_FREQ_CHANGE,  SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rsid_freq_change,  0, 0},
227 	{ CMD_ID_RSID_ALLOW_ERRORS, SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_rsid_allow_errors, 0, 0},
228 	{ CMD_ID_RSID_SQL_OPEN,     SCRIPT_COMMAND, 0,  1, {0}, { p_int      }, 0, 0, 0, process_rsid_sql_open,     0, 0},
229 	{ CMD_ID_RSID_PRETONE,      SCRIPT_COMMAND, 0,  1, {0}, { p_double   }, 0, 0, 0, process_rsid_pretone,      0, 0},
230 	{ CMD_ID_RSID_END_XMT_ID,   SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_rsid_end_xmt_id,   0, 0},
231 	{ CMD_END_CMD,              SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
232 	{ {0} }
233 };
234 
235 static const SCRIPT_COMMANDS default_id_video_command_table[] = {
236 	{ CMD_ID_VIDEO_TX_ID_MODE,   SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_video_tx_id_mode,  0, 0},
237 	{ CMD_ID_VIDEO_TX_VIDEO_TXT, SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_video_tx_vid_txt,  0, 0},
238 	{ CMD_ID_VIDEO_TX_TXT_INP,   SCRIPT_COMMAND, 0,  1, {0}, { p_string   }, 0, 0, 0, process_video_txt_input,   0, 0},
239 	{ CMD_ID_VIDEO_SMALL_FONT,   SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_video_small_font,  0, 0},
240 	{ CMD_ID_VIDEO_500_HZ,       SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_video_500hz,       0, 0},
241 	{ CMD_ID_VIDEO_WIDTH_LIMIT,  SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_video_width_limit, 0, 0},
242 	{ CMD_ID_VIDEO_CHAR_ROW,     SCRIPT_COMMAND, 0,  1, {0}, { p_int      }, 0, 0, 0, process_rsid_char_per_row, 0, 0},
243 	{ CMD_END_CMD,               SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
244 	{ {0} }
245 };
246 
247 static const SCRIPT_COMMANDS default_id_cw_command_table[] = {
248 	{ CMD_ID_CW_TX_CALLSIGN, SCRIPT_COMMAND, 0,  1, {0}, { p_bool     }, 0, 0, 0, process_cw_callsign,      0, 0},
249 	{ CMD_ID_CW_SPEED,       SCRIPT_COMMAND, 0,  1, {0}, { p_int      }, 0, 0, 0, process_cw_speed,         0, 0},
250 	{ CMD_END_CMD,           SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
251 	{ {0} }
252 };
253 
254 static const SCRIPT_COMMANDS default_id_command_table[] = {
255 	{ CMD_ID_RSID,          SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_id_rsid_command_table,          sizeof(default_id_rsid_command_table)/sizeof(SCRIPT_COMMANDS)},
256 	{ CMD_ID_VIDEO,         SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_id_video_command_table,         sizeof(default_id_video_command_table)/sizeof(SCRIPT_COMMANDS)},
257 	{ CMD_ID_CW,            SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_id_cw_command_table,            sizeof(default_id_cw_command_table)/sizeof(SCRIPT_COMMANDS)},
258 	{ CMD_END_CMD,          SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
259 	{ {0} }
260 };
261 
262 static const SCRIPT_COMMANDS default_top_level_command_table[] = {
263 	{ CMD_FLDIGI,           SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_fldigi_command_table,           sizeof(default_fldigi_command_table)/sizeof(SCRIPT_COMMANDS)},
264 	{ CMD_OPERATOR,         SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_operator_command_table,         sizeof(default_operator_command_table)/sizeof(SCRIPT_COMMANDS)},
265 	{ CMD_AUDIO_DEVICE,     SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_audio_device_command_table,     sizeof(default_audio_device_command_table)/sizeof(SCRIPT_COMMANDS)},
266 	{ CMD_AUDIO_SETTINGS,   SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_audio_settings_command_table,   sizeof(default_audio_settings_command_table)/sizeof(SCRIPT_COMMANDS)},
267 	{ CMD_AUDIO_RT_CHANNEL, SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_audio_rt_channel_command_table, sizeof(default_audio_rt_channel_command_table)/sizeof(SCRIPT_COMMANDS)},
268 	{ CMD_AUDIO_WAVE,       SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_audio_wave_command_table,       sizeof(default_audio_wave_command_table)/sizeof(SCRIPT_COMMANDS)},
269 	{ CMD_HRDWR_PTT,        SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_rig_hrdwr_ptt_command_table,    sizeof(default_rig_hrdwr_ptt_command_table)/sizeof(SCRIPT_COMMANDS)},
270 	{ CMD_RIGCAT,           SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_rigcat_command_table,           sizeof(default_rigcat_command_table)/sizeof(SCRIPT_COMMANDS)},
271 	{ CMD_HAMLIB,           SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_hamlib_command_table,           sizeof(default_hamlib_command_table)/sizeof(SCRIPT_COMMANDS)},
272 	{ CMD_IO,               SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_io_command_table,               sizeof(default_io_command_table)/sizeof(SCRIPT_COMMANDS)},
273 	{ CMD_NBEMS,            SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_nbems_command_table,            sizeof(default_nbems_command_table)/sizeof(SCRIPT_COMMANDS)},
274 	{ CMD_ID,               SCRIPT_COMMAND, 0,  0, {0}, { p_list   }, 0, 0, 0, 0, (struct script_cmds *) &default_id_command_table,               sizeof(default_id_command_table)/sizeof(SCRIPT_COMMANDS)},
275 	{ CMD_LOAD_MACRO,       SCRIPT_COMMAND | SCRIPT_STRUCTURED_ONLY, 0,  3, {0}, { p_int, p_int, p_string   }, 0, 0, 0, process_load_macro, 0, 0},
276 	{ CMD_END_CMD,          SCRIPT_COMMAND, 0,  0, {0}, { p_list_end }, 0, 0, 0, 0, 0, 0},
277 	{ {0} }
278 };
279 
280 
281 /** **************************************************************
282  * \brief Macro command requires special procesing.
283  * \param cmd Pointer to matching struct script_cmds script
284  * command.
285  * \return SCRIPT_CODES error see \ref script_codes
286  *****************************************************************/
sc_macros(struct script_cmds * cmd)287 SCRIPT_CODES ScriptParsing::sc_macros(struct script_cmds *cmd)
288 {
289 	bool not_done = false;
290 	std::string temp;
291 	SCRIPT_CODES error = script_no_errors;
292 	int line_number_start = line_number;
293 	char *local_buffer = (char *)0;
294 
295 	_macro_command.clear();
296 	temp.clear();
297 
298 	std::string search_cmd;
299 	search_cmd.assign(CMD_END_CMD).append(":");
300 
301 	local_buffer = new char[MAX_READLINE_LENGTH];
302 
303 	if(!local_buffer)
304 		return script_memory_allocation_error;
305 
306 	while(!not_done) {
307 
308 		if(ferror(fd)) {
309 			error = script_file_read_error;
310 			break;
311 		}
312 
313 		if(feof(fd)) {
314 			error = script_unexpected_eof;
315 			break;
316 		}
317 
318 		memset(local_buffer, 0, MAX_READLINE_LENGTH);
319 		if (fgets(local_buffer, MAX_READLINE_LENGTH, fd))
320 			line_number++;
321 
322 		temp.assign(local_buffer);
323 		trim(temp);
324 
325 
326 		if(temp.find(search_cmd) == std::string::npos)
327 			_macro_command.append(local_buffer);
328 		else
329 			break;
330 	}
331 
332 	int pos = _macro_command.length() - 1;
333 	bool lf_removed = false;
334 
335 	// Remove the last new line in the macro command (script syntax requirement)
336 
337 	if(pos > 1) { // Windows way
338 		if(_macro_command[pos-1] == '\r' && _macro_command[pos] == '\n') {
339 			_macro_command.erase(pos - 1, 2);
340 			lf_removed = true;
341 		}
342 	}
343 
344 	if((lf_removed == false) && (pos > 0)) { // Unix/Linux/MacOSX way
345 		if(_macro_command[pos] == '\n')
346 			_macro_command.erase(pos, 1);
347 	}
348 
349 	if(error == script_unexpected_eof) {
350 		LOG_INFO(_("Missing command %s after line %d"), search_cmd.c_str(), line_number_start);
351 	}
352 
353 	delete [] local_buffer;
354 
355 	return error;
356 }
357 
358 /** **************************************************************
359  * \brief Used for initialization of the function vector table.
360  * \param cmd Pointer to matching struct script_cmds script
361  * command.
362  * \return SCRIPT_CODES error see \ref script_codes
363  *****************************************************************/
sc_dummy(struct script_cmds * cmd)364 SCRIPT_CODES ScriptParsing::sc_dummy(struct script_cmds *cmd)
365 {
366 	return script_no_errors;
367 }
368 
369 /** **************************************************************
370  * \brief Convert error numbers into human readable form.
371  * \param error_no Error number to convert.
372  * \param ln The offending line number in the script file.
373  * \param cmd The script command is question.
374  * \return SCRIPT_CODES error see \ref script_codes
375  *****************************************************************/
script_error_string(SCRIPT_CODES error_no,int ln,char * cmd)376 char * ScriptParsing::script_error_string(SCRIPT_CODES error_no, int ln, char *cmd)
377 {
378 	char *es = (char *) "";
379 
380 	memset(error_buffer,     0, sizeof(error_buffer));
381 	memset(error_cmd_buffer, 0, sizeof(error_cmd_buffer));
382 	memset(error_string,     0, sizeof(error_string));
383 
384 	if(cmd) {
385 		strncpy(error_cmd_buffer, cmd, sizeof(error_cmd_buffer)-1);
386 	}
387 
388 	if(error_no < 0) {
389 		_script_error_detected = true;
390 	}
391 
392 	switch(error_no) {
393 		case script_command_not_found:
394 			es =  (char *) _("Command Not Found");
395 			break;
396 
397 		case script_non_script_file:
398 			es = (char *) _("Not a script file/tag not found");
399 			break;
400 
401 		case script_parameter_error:
402 			es = (char *) _("Invalid parameter");
403 			break;
404 
405 		case script_function_parameter_error:
406 			es = (char *) _("Invalid function parameter (internal non-script error)");
407 			break;
408 
409 		case script_mismatched_quotes:
410 			es = (char *) _("Missing paired quotes (\")");
411 			break;
412 
413 		case script_general_error:
414 			es = (char *) _("General Error");
415 			break;
416 
417 		case script_no_errors:
418 			es = (char *) _("No Errors");
419 			break;
420 
421 		case script_char_match_not_found:
422 			es = (char *) _("Character searched not found");
423 			break;
424 
425 		case script_end_of_line_reached:
426 			es = (char *) _("End of line reached");
427 			break;
428 
429 		case script_file_not_found:
430 			es = (char *) _("File not found");
431 			break;
432 
433 		case script_path_not_found:
434 			es = (char *) _("Directory path not found");
435 			break;
436 
437 		case script_args_eol:
438 			es = (char *) _("Unexpected end of parameter (args[]) list found");
439 			break;
440 
441 		case script_param_check_eol:
442 			es = (char *) _("Unexpected end of parameter check list found");
443 			break;
444 
445 		case script_paramter_exceeds_length:
446 			es = (char *) _("Character count in args[] parameter exceeds expectations");
447 			break;
448 
449 		case script_memory_allocation_error:
450 			es = (char *) _("Memory Allocation Error (internal non-script error)");
451 			break;
452 
453 		case script_incorrectly_assigned_value:
454 			es = (char *) _("Passed parameter is not of the expected type.");
455 			break;
456 
457 		case script_invalid_parameter:
458 			es = (char *) _("Parameter is not valid.");
459 			break;
460 
461 		case script_command_seperator_missing:
462 			es = (char *) _("Command missing ':'.");
463 			break;
464 
465 		case script_max_sub_script_reached:
466 			es = (char *) _("Maximum open subscripts reached.");
467 			break;
468 
469 		case script_subscript_exec_fail:
470 			es = (char *) _("Subscript execution fail (internal).");
471 			break;
472 
473 		case script_device_path_not_found:
474 			es = (char *) _("Script device path not found.");
475 			break;
476 
477 		case script_unexpected_eof:
478 			es = (char *) _("Unexpected end of file reached.");
479 			break;
480 
481 		case script_file_read_error:
482 			es = (char *) _("File read error");
483 			break;
484 
485 		default:
486 			es = (char *) _("Undefined error");
487 	}
488 
489 	snprintf(error_buffer, sizeof(error_buffer)-1, _("Line: %d Error:%d %s (%s)"),
490 			 ln, error_no, es, error_cmd_buffer);
491 
492 	return error_buffer;
493 }
494 
495 /** **************************************************************
496  * \brief Search for first occurrence of a non white space
497  * \param data Data pointer to search.
498  * \param limit Number of bytes in the data buffer.
499  * \param error returned error code.
500  * \return Pointer to character if found. Otherwise, return null
501  * \par Note:<br>
502  * The searched condition is ignored if the expected content is
503  * encapsulated in quotes \(\"\"\).
504  *****************************************************************/
skip_white_spaces(char * data,char * limit,SCRIPT_CODES & error)505 char * ScriptParsing::skip_white_spaces(char * data, char * limit, SCRIPT_CODES &error)
506 {
507 	char *cPtr      = (char *) 0;
508 
509 	if(!data || !limit) {
510 		error = script_function_parameter_error;
511 		return (char *)0;
512 	}
513 
514 	for(cPtr = data; cPtr < limit; cPtr++) {
515 		if(*cPtr > ' ') {
516 			error = script_no_errors;
517 			return cPtr;
518 		}
519 	}
520 
521 	error = script_end_of_line_reached;
522 
523 
524 	return (char *)0;        // End of line reached.
525 }
526 
527 /** **************************************************************
528  * \brief Search for the first occurrence on a non number.
529  * \param data Data pointer to search.
530  * \param limit Number of bytes in the data buffer.
531  * \param error returned error code.
532  * \return Pointer to character if found. Otherwise, return null
533  * \par Note:<br>
534  * The searched condition is ignored if the expected content is
535  * encapsulated in quotes \(\"\"\).
536  *****************************************************************/
skip_numbers(char * data,char * limit,SCRIPT_CODES & error)537 char * ScriptParsing::skip_numbers(char * data, char * limit, SCRIPT_CODES &error)
538 {
539 	char *cPtr  = (char *) 0;
540 	int  q_flag = 0;
541 
542 	if(!data || !limit) {
543 		error = script_function_parameter_error;
544 		return (char *)0;
545 	}
546 
547 	for(cPtr = data; cPtr < limit; cPtr++) {
548 		if(*cPtr == '"')     // Check for encapsulated strings ("")
549 			q_flag++;
550 
551 		if((q_flag & 0x1))   // Continue if string is encapsulated
552 			continue;
553 
554 		if(!isdigit(*cPtr)) {
555 			error = script_no_errors;
556 			return cPtr;
557 		}
558 	}
559 
560 	if(q_flag & 0x1) {
561 		error = script_mismatched_quotes;
562 	} else {
563 		error = script_end_of_line_reached;
564 	}
565 
566 	return (char *)0;        // End of line reached.
567 }
568 
569 /** **************************************************************
570  * \brief Skip characters until either a number or white space is
571  * found.
572  * \param data Data pointer to search.
573  * \param limit Number of bytes in the data buffer.
574  * \param error returned error code.
575  * \return Pointer to character if found. Otherwise, return null
576  * \par Note:<br>
577  * The searched condition is ignored if the expected content is
578  * encapsulated in quotes \(\"\"\).
579  *****************************************************************/
skip_characters(char * data,char * limit,SCRIPT_CODES & error)580 char * ScriptParsing::skip_characters(char * data, char * limit, SCRIPT_CODES &error)
581 {
582 	char *cPtr  = (char *) 0;
583 	int  q_flag = 0;
584 
585 	if(!data || !limit) {
586 		error = script_function_parameter_error;
587 		return (char *)0;
588 	}
589 
590 	for(cPtr = data; cPtr < limit; cPtr++) {
591 		if(*cPtr == '"')     // Check for encapsulated strings ("")
592 			q_flag++;
593 
594 		if((q_flag & 0x1))   // Continue if string is encapsulated
595 			continue;
596 
597 		if(isdigit(*cPtr) || *cPtr <= ' ') {
598 			error = script_no_errors;
599 			return cPtr;
600 		}
601 	}
602 
603 	if(q_flag & 0x1) {
604 		error = script_mismatched_quotes;
605 	} else {
606 		error = script_end_of_line_reached;
607 	}
608 
609 	return (char *)0;        // End of line reached.
610 }
611 
612 /** **************************************************************
613  * \brief Search for the first occurrence of a white space.
614  * \param data Data pointer to search.
615  * \param limit Number of bytes in the data buffer.
616  * \param error returned error code.
617  * \return Pointer to character if found. Otherwise, return null
618  * \par Note:<br>
619  * The searched condition is ignored if the expected content is
620  * encapsulated in quotes \(\"\"\).
621  *****************************************************************/
skip_alpha_numbers(char * data,char * limit,SCRIPT_CODES & error)622 char * ScriptParsing::skip_alpha_numbers(char * data, char * limit, SCRIPT_CODES &error)
623 {
624 	char *cPtr  = (char *) 0;
625 	int  q_flag = 0;
626 
627 	if(!data || !limit) {
628 		error = script_function_parameter_error;
629 		return (char *)0;
630 	}
631 
632 	for(cPtr = data; cPtr < limit; cPtr++) {
633 
634 		if(*cPtr == '"')     // Check for encapsulated strings ("")
635 			q_flag++;
636 
637 		if((q_flag & 0x1))   // Continue if string is encapsulated
638 			continue;
639 
640 		if(*cPtr <= ' ') {
641 			error = script_no_errors;
642 			return cPtr;
643 		}
644 	}
645 
646 	if(q_flag & 0x1) {
647 		error = script_mismatched_quotes;
648 	} else {
649 		error = script_end_of_line_reached;
650 	}
651 
652 	return (char *)0;        // End of line reached.
653 }
654 
655 /** **************************************************************
656  * \brief Search for first occurrence of 'character'
657  * \param c Character to search for
658  * \param data Pointer to Data to search for character in.
659  * \param limit Number of bytes in the data buffer.
660  * \param error returned error code.
661  * \return Pointer to character if found. Otherwise, return null
662  * \par Note:<br>
663  * The searched condition is ignored if the expected content is
664  * encapsulated in quotes \(\"\"\).
665  *****************************************************************/
skip_to_character(char c,char * data,char * limit,SCRIPT_CODES & error)666 char * ScriptParsing::skip_to_character(char c, char * data, char * limit, SCRIPT_CODES &error)
667 {
668 	char *cPtr  = (char *) 0;
669 	int  q_flag = 0;
670 
671 	if(!data || !limit) {
672 		error = script_function_parameter_error;
673 		return (char *)0;
674 	}
675 
676 	for(cPtr = data; cPtr < limit; cPtr++) {
677 		if(*cPtr == '"')     // Check for encapsulated strings ("")
678 			q_flag++;
679 
680 		if((q_flag & 0x1))   // Continue if string is encapsulated
681 			continue;
682 
683 		if(*cPtr == c)   {    // Match found. Return pointer to it's location
684 			error = script_no_errors;
685 			return cPtr;
686 		}
687 	}
688 
689 	if(q_flag & 0x1) {
690 		error = script_mismatched_quotes;
691 	} else {
692 		error = script_end_of_line_reached;
693 	}
694 
695 	return (char *)0;        // End of line reached.
696 }
697 
698 /** **************************************************************
699  * \brief Replace CR, LF, and '#' with '0' (by value)
700  * \param data Search data pointer
701  * \param limit data buffer size
702  * \return void (none)
703  * \par Note:<br>
704  * The searched condition is ignored if the remark character \(#\)
705  * is encapsulated in quotes \(\"\"\).
706  *****************************************************************/
remove_crlf_comments(char * data,char * limit,size_t & count)707 SCRIPT_CODES ScriptParsing::remove_crlf_comments(char *data, char *limit, size_t &count)
708 {
709 	char *cPtr  = (char *) 0;
710 	int  q_flag = 0;
711 
712 	SCRIPT_CODES error = script_no_errors;
713 
714 	if(!data || !limit)
715 		return script_function_parameter_error;
716 
717 	count = 0;
718 
719 	for(cPtr = data; cPtr < limit; cPtr++) {
720 		if(*cPtr == '\r' || *cPtr == '\n') {
721 			*cPtr = 0;
722 			return script_no_errors;
723 		}
724 
725 		if(*cPtr == '"')
726 			q_flag++;
727 
728 		if((q_flag & 0x1))
729 			continue;
730 
731 		if(*cPtr == '#') {
732 			*cPtr = 0;
733 			break;
734 		}
735 
736 		if(*cPtr > ' ')
737 			count++;
738 
739 	}
740 
741 	// Remove trailing white spaces.
742 	while(cPtr >= data) {
743 		if(*cPtr <= ' ') *cPtr = 0;
744 		else break;
745 		cPtr--;
746 	}
747 
748 	if(q_flag & 0x1) {
749 		error = script_mismatched_quotes;
750 	} else {
751 		error = script_end_of_line_reached;
752 	}
753 
754 	return error;
755 }
756 
757 /** **************************************************************
758  * \brief Copy memory from address to address.
759  * \param buffer Destination buffer
760  * \param sPtr Start of the copy Address
761  * \param ePtr End of the copy Address
762  * \param limit Destination buffer size
763  * command.
764  * \return SCRIPT_CODES error see \ref script_codes
765  *****************************************************************/
copy_string_uppercase(char * buffer,char * sPtr,char * ePtr,size_t limit)766 SCRIPT_CODES ScriptParsing::copy_string_uppercase(char *buffer, char *sPtr, char *ePtr, size_t limit)
767 {
768 	if(!buffer || !sPtr || !ePtr || limit < 1) {
769 		return script_function_parameter_error;
770 	}
771 
772 	char *dPtr   = buffer;
773 	size_t index = 0;
774 
775 	for(index = 0; index < limit; index++) {
776 		*dPtr++ = toupper(*sPtr++);
777 		if(sPtr >= ePtr) break;
778 	}
779 
780 	return script_no_errors;
781 }
782 
783 /** **************************************************************
784  * \brief Parse the parameters and seperate into individual components.
785  * \param s char pointer to the start of the string.
786  * \param e char pointer to the end of the string.
787  * \param matching_command pointer to the data strucure of the matching
788  * command. See \ref SCRIPT_COMMANDS
789  * \return SCRIPT_CODES error see \ref script_codes
790  *****************************************************************/
parse_parameters(char * s,char * e,SCRIPT_COMMANDS * matching_command)791 SCRIPT_CODES ScriptParsing::parse_parameters(char *s, char *e, SCRIPT_COMMANDS *matching_command)
792 {
793 	char *c   = s;
794 	char *d   = (char *)0;
795 	int index = 0;
796 	int parameter_count = matching_command->argc;
797 	int count = 0;
798 	long tmp  = 0;
799 
800 	SCRIPT_CODES error = script_no_errors;
801 
802 	// Clear the old pointers.
803 	for(index = 0; index < MAX_CMD_PARAMETERS; index++) {
804 		matching_command->args[index] = (char *)0;
805 	}
806 
807 	if(parameter_count > 0) {
808 		count = parameter_count - 1;
809 		for(index = 0; index < count; index++) {
810 			c = skip_white_spaces(c, e, error);
811 
812 			if(error != script_no_errors)
813 				return script_parameter_error;
814 
815 			d = skip_to_character(',', c, e, error);
816 
817 			if(error != script_no_errors)
818 				return script_parameter_error;
819 
820 			*d = 0;
821 			tmp = (long) (d - c);
822 			if(tmp > 0)
823 				trim(c, (size_t)(tmp));
824 			matching_command->args[index] = c;
825 			c = d + 1;
826 		}
827 
828 		c = skip_white_spaces(c, e, error);
829 		if(error) return error;
830 
831 		d = skip_alpha_numbers(c, e, error);
832 		if(error) return error;
833 
834 		*d = 0;
835 		tmp = (long) (d - c);
836 		if(tmp > 0)
837 			trim(c, (size_t)(tmp));
838 
839 		matching_command->args[index] = c;
840 	}
841 
842 #ifdef TESTING
843 	for(int i = 0; i < parameter_count;  i++)
844 		if(matching_command->args[i])
845 			printf("parameters %d (%s)\n", i, matching_command->args[i]);
846 #endif
847 
848 	error = check_parameters(matching_command);
849 
850 	if(error != script_no_errors)
851 		return error;
852 
853 	// If assigned then special processing is required.
854 	if(matching_command->func)
855 		error = (this->*matching_command->func)(matching_command);
856 	if(error) return error;
857 
858 
859 	return script_no_errors;
860 }
861 
862 /** **************************************************************
863  * \brief Execute callback function.
864  * \param cb_data Pointer for making a copy of the data to prevent
865  * exterior alteration of source information.
866  * \return 0 = No error<br> \< 0 = Error<br>
867  *****************************************************************/
call_callback(SCRIPT_COMMANDS * cb_data)868 int ScriptParsing::call_callback(SCRIPT_COMMANDS *cb_data)
869 {
870 	int argc     = 0;
871 	int error    = 0;
872 	int index    = 0;
873 	SCRIPT_COMMANDS *tmp = (SCRIPT_COMMANDS *)0;
874 	size_t count = 0;
875 
876 	if(!cb_data || !cb_data->cb) return -1;
877 
878 	argc = cb_data->argc;
879 
880 	tmp = new SCRIPT_COMMANDS;
881 
882 	if(!tmp) return -1;
883 
884 	memset(tmp, 0, sizeof(SCRIPT_COMMANDS));
885 
886 	for(index = 0; index < argc; index++) {
887 		if(cb_data->args[index]) {
888 			count = strnlen(cb_data->args[index], MAX_PARAMETER_LENGTH-1);
889 			tmp->args[index] = new char[count+1];
890 			if(tmp->args[index]) {
891 				memset(tmp->args[index], 0, count+1);
892 				strncpy(tmp->args[index], cb_data->args[index], count);
893 			} else {
894 				error = -1;
895 				break;
896 			}
897 		} else break;
898 	}
899 
900 	if(error > -1) {
901 		// Fill SCRIPT_COMMANDS (tmp) struct with useful data.
902 		tmp->flags          = cb_data->flags;
903 		tmp->command_length = cb_data->command_length;
904 		tmp->argc           = cb_data->argc;
905 		strncpy(tmp->command, cb_data->command, MAX_COMMAND_LENGTH);
906 
907 		// Initialize with do nothing functions
908 		tmp->func = &ScriptParsing::sc_dummy;
909 		tmp->cb   = callback_dummy;
910 
911 		error = (*cb_data->cb)(this, tmp);
912 	}
913 
914 	if(tmp) {
915 		for(index = 0; index < argc; index++) {
916 			if(tmp->args[index]) {
917 				delete [] tmp->args[index];
918 			}
919 		}
920 
921 		delete tmp;
922 	}
923 
924 	return error;
925 }
926 
927 /** **************************************************************
928  * \brief Parse a single line of data from the script file being read.
929  * \param data Pointer the the script scring in question
930  * \param buffer_size buffer size of the data pointer.
931  * command.
932  * \return SCRIPT_CODES error see \ref script_codes
933  *****************************************************************/
parse_hierarchy_command(char * data,size_t buffer_size)934 SCRIPT_CODES ScriptParsing::parse_hierarchy_command(char *data, size_t buffer_size)
935 {
936 	char *buffer = (char *)0;
937 	char *cPtr   = (char *)0;
938 	char *endPtr = (char *)0;
939 	char *ePtr   = (char *)0;
940 	int allocated_buffer_size = MAX_COMMAND_LENGTH;
941 
942 	SCRIPT_CODES error = script_no_errors;
943 	SCRIPT_COMMANDS *local_list = _script_commands;
944 	size_t local_limit = _script_command_count;
945 
946 	cPtr = data;
947 	endPtr = &data[buffer_size];
948 
949 	cPtr = skip_white_spaces(cPtr, endPtr, error);
950 	if(error != script_no_errors) return error;
951 
952 	ePtr = skip_to_character(':', cPtr, endPtr, error);
953 	if(error != script_no_errors) return script_command_seperator_missing;
954 
955 	buffer = new char [allocated_buffer_size];
956 	if(!buffer) {
957 		LOG_INFO(_("Buffer allocation Error near File: %s Line %d"), __FILE__, __LINE__);
958 		return script_memory_allocation_error;
959 	}
960 
961 	memset(buffer, 0, allocated_buffer_size);
962 	error = copy_string_uppercase(buffer, cPtr, ePtr, allocated_buffer_size-1);
963 
964 	if(error != script_no_errors) {
965 		buffer[0] = 0;
966 		delete [] buffer;
967 		return error;
968 	}
969 
970 	int str_count = str_cnt(buffer, allocated_buffer_size);
971 	trim(buffer, (size_t) str_count);
972 
973 	char sub_command[MAX_COMMAND_LENGTH];
974 
975 	bool not_found = true;
976 	char *endCmd = ePtr;
977 	char *endCmdPtr = endPtr;
978 
979 	cPtr = buffer;
980 	endPtr = &buffer[str_count];
981 
982 	while(not_found) {
983 		memset(sub_command, 0, sizeof(sub_command));
984 
985 		ePtr = skip_to_character('.', cPtr, endPtr, error);
986 
987 		if(error == script_end_of_line_reached) {
988 			ePtr = endPtr;
989 			error = script_no_errors;
990 		}
991 
992 		if(error == script_no_errors) {
993 			copy_string_uppercase(sub_command, cPtr, ePtr, MAX_COMMAND_LENGTH-1);
994 			cPtr = ePtr + 1;
995 		}
996 		else
997 			break;
998 
999 		for(size_t i = 0; i < local_limit; i++) {
1000 
1001 			if(local_list[i].command[0] == 0) {
1002 				not_found = false;
1003 				error = script_command_not_found;
1004 				break;
1005 			}
1006 
1007 			if(strncmp(sub_command, local_list[i].command, MAX_COMMAND_LENGTH) == 0) {
1008 
1009 				if((local_list[i].param_check[0] == p_list) && local_list[i].sub_commands) {
1010 					local_limit = local_list[i].sub_command_count;
1011 					local_list  = local_list[i].sub_commands;
1012 					break;
1013 				}
1014 
1015 				if((file_type() & local_list[i].flags) && !(SCRIPT_STRUCTURED_ONLY & local_list[i].flags)) {
1016 					error = parse_parameters(++endCmd, endCmdPtr, &local_list[i]);
1017 
1018 					if(error)  {
1019 						buffer[0] = 0;
1020 						delete [] buffer;
1021 						return error;
1022 					}
1023 
1024 					if(local_list[i].cb) {
1025 						error = (SCRIPT_CODES) call_callback(&local_list[i]);
1026 						if(error < script_no_errors)
1027 							LOG_INFO(_("Call back for script command %s reported an Error"), local_list[local_limit].command);
1028 						not_found = false;
1029 						error = script_command_handled;
1030 						break;
1031 					}
1032 				} else {
1033 					LOG_INFO(_("Command %s ignored, dot notation not supported"), buffer);
1034 					not_found = false;
1035 					error = script_general_error;
1036 					break;
1037 				}
1038 			}
1039 		}
1040 	}
1041 
1042 	buffer[0] = 0;
1043 	delete [] buffer;
1044 
1045 	return error;
1046 }
1047 
1048 /** **************************************************************
1049  * \brief Parse a single line of data from the script file being read.
1050  * \param data Pointer the the script scring in question
1051  * \param buffer_size buffer size of the data pointer.
1052  * command.
1053  * \return SCRIPT_CODES error see \ref script_codes
1054  *****************************************************************/
parse_single_command(FILE * fd,SCRIPT_COMMANDS * cur_list,size_t limit,char * data,size_t buffer_size)1055 SCRIPT_CODES ScriptParsing::parse_single_command(FILE *fd, SCRIPT_COMMANDS *cur_list, size_t limit, char *data, size_t buffer_size)
1056 {
1057 	char *buffer = (char *)0;
1058 	char *cPtr   = (char *)0;
1059 	char *endPtr = (char *)0;
1060 	char *ePtr   = (char *)0;
1061 	int allocated_buffer_size = MAX_COMMAND_LENGTH;
1062 
1063 	size_t cmd_size    = 0;
1064 	size_t cmp_results = 0;
1065 	size_t index       = 0;
1066 	size_t size        = 0;
1067 	bool dot_notation  = false;
1068 
1069 	SCRIPT_CODES error = script_no_errors;
1070 	SCRIPT_COMMANDS *local_list = cur_list;
1071 	size_t local_limit = limit;
1072 
1073 	cPtr = data;
1074 	endPtr = &data[buffer_size];
1075 
1076 	cPtr = skip_white_spaces(cPtr, endPtr, error);
1077 	if(error != script_no_errors) return error;
1078 
1079 	ePtr = skip_to_character(':', cPtr, endPtr, error);
1080 	if(error != script_no_errors) return script_command_seperator_missing;
1081 
1082 	buffer = new char [allocated_buffer_size];
1083 	if(!buffer) {
1084 		LOG_INFO(_("Buffer allocation Error near File: %s Line %d"), __FILE__, __LINE__);
1085 		return script_memory_allocation_error;
1086 	}
1087 
1088 	memset(buffer, 0, allocated_buffer_size);
1089 	error = copy_string_uppercase(buffer, cPtr, ePtr, allocated_buffer_size-1);
1090 	if(error != script_no_errors) {
1091 		buffer[0] = 0;
1092 		delete [] buffer;
1093 		return error;
1094 	}
1095 
1096 	int str_count = (int) strnlen(buffer, allocated_buffer_size);
1097 	trim(buffer, (size_t) str_count);
1098 
1099 
1100 	for(int i = 0; i < str_count; i++) {
1101 		if(buffer[i] == '.') {
1102 			error = parse_hierarchy_command(data, buffer_size);
1103 			if(error == script_no_errors)
1104 				dot_notation = true;
1105 			break;
1106 		}
1107 	}
1108 
1109 	if(dot_notation == false && error == script_no_errors) {
1110 		for(index = 0; index < local_limit; index++) {
1111 			size = strnlen(local_list[index].command, MAX_COMMAND_LENGTH);
1112 			cmd_size = strnlen(buffer, MAX_COMMAND_LENGTH);
1113 			cmp_results = memcmp(buffer, local_list[index].command, size);
1114 
1115 			if(cmp_results == 0 && (cmd_size == size)) {
1116 
1117 				if(local_list[index].param_check[0] == p_list_end) {
1118 					return script_end_of_list_reached;
1119 				}
1120 
1121 				if(local_list[index].sub_commands && local_list[index].param_check[0] == p_list) {
1122 					if(recursive_count <= RECURSIVE_LIMIT) {
1123 						read_file(fd, local_list[index].sub_commands, local_list[index].sub_command_count);
1124 					} else {
1125 						error = script_recursive_limit_reached;
1126 					}
1127 					break;
1128 				}
1129 
1130 				if((file_type() & local_list[index].flags) && !(SCRIPT_DOT_NOTATION_ONLY & local_list[index].flags)) {
1131 					if(local_list[index].argc > 0) {
1132 						error = parse_parameters(++ePtr, endPtr, &local_list[index]);
1133 						if(error)  {
1134 							buffer[0] = 0;
1135 							delete [] buffer;
1136 							return error;
1137 						}
1138 					}
1139 
1140 					if(local_list[index].cb) {
1141 						error = (SCRIPT_CODES) call_callback(&local_list[index]);
1142 						if(error < script_no_errors)
1143 							LOG_INFO(_("Call back for script command %s reported an Error"), local_list[index].command);
1144 					}
1145 
1146 				} else {
1147 					LOG_INFO(_("Command %s ignored, structured command not supported"), buffer);
1148 					error = script_general_error;
1149 				}
1150 				break;
1151 			}
1152 		}
1153 	}
1154 	buffer[0] = 0;
1155 	delete [] buffer;
1156 
1157 	return error;
1158 }
1159 
1160 /** **************************************************************
1161  * \brief Script entry point for parsing the script file.
1162  * \param file_name_path path and file name for the script to parse.
1163  * \return SCRIPT_CODES error see \ref script_codes
1164  *****************************************************************/
read_file(FILE * fd,SCRIPT_COMMANDS * cur_list,size_t limit)1165 SCRIPT_CODES ScriptParsing::read_file(FILE *fd, SCRIPT_COMMANDS *cur_list, size_t limit)
1166 {
1167 	SCRIPT_CODES return_code = script_no_errors;
1168 	SCRIPT_COMMANDS *local_list = cur_list;
1169 
1170 	size_t count    = 0;
1171 	bool errors_reported = false;
1172 
1173 	recursive_count++;
1174 
1175 	if(recursive_count > RECURSIVE_LIMIT)
1176 		return script_recursive_limit_reached;
1177 
1178 	while(1) {
1179 		if(ferror(fd) || feof(fd)) break;
1180 
1181 		memset(line_buffer, 0, sizeof(line_buffer));
1182 		if (fgets(line_buffer, sizeof(line_buffer) - 1, fd))
1183 			line_number++;
1184 
1185 #ifdef TESTING
1186 		printf("Reading: %s", line_buffer);
1187 #endif
1188 
1189 		return_code = remove_crlf_comments(line_buffer, &line_buffer[sizeof(line_buffer)], count);
1190 
1191 		if(count < 1) {
1192 			continue;
1193 		}
1194 
1195 		if(return_code >= script_no_errors) {
1196 			return_code = parse_single_command(fd, local_list, limit, line_buffer, sizeof(line_buffer) - 1);
1197 		}
1198 
1199 		if(return_code == script_end_of_list_reached)
1200 			break;
1201 
1202 		if(return_code < script_no_errors) {
1203 			LOG_INFO("%s", script_error_string(return_code, line_number, line_buffer));
1204 			errors_reported = true;
1205 		}
1206 	}
1207 
1208 	recursive_count--;
1209 
1210 	if(errors_reported)
1211 		return script_errors_reported;
1212 
1213 	return script_no_errors;
1214 }
1215 
1216 /** **************************************************************
1217  * \brief Script entry point for parsing the script file.
1218  * \param file_name_path path and file name for the script to parse.
1219  * \return SCRIPT_CODES error see \ref script_codes
1220  *****************************************************************/
parse_commands(char * file_name_path)1221 SCRIPT_CODES ScriptParsing::parse_commands(char *file_name_path)
1222 {
1223 	char *cPtr      = (char *)0;
1224 	SCRIPT_CODES error_code = script_no_errors;
1225 	size_t tmp      = 0;
1226 	SCRIPT_COMMANDS *local_script_commands = _script_commands;
1227 	size_t local_script_command_count      = _script_command_count;
1228 
1229 	if(!file_name_path) {
1230 		LOG_INFO(_("Invalid function parameter 'char *file_name_path' (null)"));
1231 		return script_function_parameter_error;
1232 	}
1233 
1234 	fd = fl_fopen(file_name_path, "r");
1235 	line_number = 0;
1236 
1237 	if(!fd) {
1238 		LOG_INFO(_("Unable to open file %s"), file_name_path);
1239 		return script_file_not_found;
1240 	}
1241 
1242 	memset(line_buffer, 0, sizeof(line_buffer));
1243 
1244 	char *retval = fgets(line_buffer, sizeof(line_buffer) - 1, fd);
1245 	line_number++;
1246 
1247 	tmp = strlen(SCRIPT_FILE_TAG);
1248 	line_buffer[tmp] = 0;
1249 	tmp = strncmp(SCRIPT_FILE_TAG, line_buffer, tmp);
1250 
1251 	if(!retval || tmp) {
1252 		cPtr = script_error_string(script_non_script_file, line_number, line_buffer);
1253 		LOG_INFO("%s", cPtr);
1254 		fclose(fd);
1255 		return script_non_script_file;
1256 	}
1257 
1258 	error_code = read_file(fd, local_script_commands, local_script_command_count);
1259 
1260 	fclose(fd);
1261 
1262 	return error_code;
1263 }
1264 /** **************************************************************
1265  * \brief Assign a list of valid parameters for verification checks.
1266  * \param array An Array of pointers to each element.
1267  * \param array_count Number of entries in the array.
1268  * \return the array count or '0' if error.
1269  * \par Note:
1270  * This array is limited to the first parameter of the command
1271  * used in it's comparison.
1272  *****************************************************************/
assign_valid_parameters(const char * command,const char ** array,const int array_count)1273 int ScriptParsing::assign_valid_parameters(const char *command, const char **array, const int array_count)
1274 {
1275 	if(!array || array_count < 1 || !command) return 0;
1276 
1277 	int index = 0;
1278 	int count = 0;
1279 
1280 	SCRIPT_COMMANDS * cmd_sc = search_command(_script_commands, 0, command);
1281 
1282 	if(!cmd_sc) {
1283 		return 0;
1284 	}
1285 
1286 	for(index = 0; index < array_count; index++) {
1287 		if(*array[index]) count++;
1288 	}
1289 
1290 	if(count != array_count) return 0;
1291 
1292 	cmd_sc->valid_values = array;
1293 	cmd_sc->valid_value_count = array_count;
1294 
1295 	return array_count;
1296 }
1297 
1298 /** **************************************************************
1299  * \brief Return true state if string is matched.
1300  * \param state Referenced value to assign results to.
1301  * \param string Pointer to the data string.
1302  * \param true_state Pointer to the data to match with.
1303  * \return SCRIPT_CODES error code.
1304  *****************************************************************/
test_on_off_state(bool & state,char * string,char * true_state=(char *)"ON")1305 inline SCRIPT_CODES ScriptParsing::test_on_off_state(bool &state, char *string, char *true_state=(char *)"ON")
1306 {
1307 	if(!string || !true_state) {
1308 		return script_function_parameter_error;
1309 	}
1310 
1311 	bool flag = false;
1312 
1313 	if(strncmp(string, true_state, MAX_PARAMETER_LENGTH) == 0)
1314 		flag = true;
1315 
1316 	state = flag;
1317 
1318 	return script_no_errors;
1319 }
1320 
1321 /** **************************************************************
1322  * \brief Validate if file is located in the specified location.
1323  * \param filename Pointer to a series of charcters
1324  * \return SCRIPT_CODES error code.
1325  *****************************************************************/
check_filename(char * filename)1326 SCRIPT_CODES ScriptParsing::check_filename(char *filename)
1327 {
1328 	SCRIPT_CODES error = script_no_errors;
1329 
1330 	if(!filename) {
1331 		return script_function_parameter_error;
1332 	}
1333 
1334 	FILE *fd = (FILE *)0;
1335 
1336 	fd = fl_fopen(filename, "r");
1337 
1338 	if(!fd) {
1339 		error = script_file_not_found;
1340 	} else {
1341 		fclose(fd);
1342 	}
1343 
1344 	return error;
1345 }
1346 
1347 /** **************************************************************
1348  * \brief Validate if path is present.
1349  * \param path The path to verify.
1350  * \return SCRIPT_CODES error code.
1351  *****************************************************************/
check_path(const char * path)1352 SCRIPT_CODES ScriptParsing::check_path(const char *path)
1353 {
1354 	if(!path) {
1355 		return script_function_parameter_error;
1356 	}
1357 
1358 	struct stat st;
1359 	memset(&st, 0, sizeof(struct stat));
1360 
1361 	if(stat(path, &st) == 0) {
1362 		if(st.st_mode & S_IFDIR)
1363 			return script_no_errors;
1364 	}
1365 
1366 	return script_path_not_found;
1367 }
1368 
1369 /** **************************************************************
1370  * \brief Validate if device path is present.
1371  * \param path The path to verify.
1372  * \return SCRIPT_CODES error code.
1373  *****************************************************************/
check_dev_path(const char * path)1374 SCRIPT_CODES ScriptParsing::check_dev_path(const char *path)
1375 {
1376 	if(!path) {
1377 		return script_function_parameter_error;
1378 	}
1379 
1380 	struct stat st;
1381 	memset(&st, 0, sizeof(struct stat));
1382 
1383 #ifdef __WIN32__
1384 	std::string alt_path;
1385 	int value = 0;
1386 	int cnt   = 0;
1387 
1388 	alt_path.assign(path);
1389 
1390 	if(!alt_path.empty()) {
1391 		if(alt_path.find("COM") != std::string::npos) {
1392 			cnt = sscanf(alt_path.c_str(), "COM%d", &value);
1393 			if(cnt && (value > 0))
1394 				return script_no_errors;
1395 		}
1396 	}
1397 #endif
1398 
1399 	if(stat(path, &st) == 0) {
1400 		if(st.st_mode & S_IFCHR)
1401 			return script_no_errors;
1402 	}
1403 
1404 	return script_device_path_not_found;
1405 }
1406 
1407 /** **************************************************************
1408  * \brief Validate bool representation.
1409  * \param value String data <ENABLE|YES|1> or <DISABLE|NO|0>
1410  * \param flag  Depending on string content a value of true or false assigned
1411  * \return SCRIPT_CODES error code.
1412  *****************************************************************/
check_bool(const char * value,bool & flag)1413 SCRIPT_CODES ScriptParsing::check_bool(const char *value, bool &flag)
1414 {
1415 	if(!value) {
1416 		return script_function_parameter_error;
1417 	}
1418 
1419 	flag = false;
1420 	std::string uc_value;
1421 
1422 	uc_value.assign(value);
1423 	to_uppercase(uc_value);
1424 
1425 	static char *bool_true_flags[] = {
1426 		(char *)PARM_ENABLE, (char *)PARM_YES, (char *)_("1"), (char *)0
1427 	};
1428 
1429 	static char *bool_false_flags[] = {
1430 		(char *) PARM_DISABLE, (char *)PARM_NO, (char *)_("0"), (char *)0
1431 	};
1432 
1433 	for(size_t i = 0; i < sizeof(bool_true_flags)/sizeof(char *); i++) {
1434 		if(bool_true_flags[i] == (char *)0) break;
1435 		if(strncmp(uc_value.c_str(), bool_true_flags[i], 7) == 0) {
1436 			flag = true;
1437 			return script_no_errors;
1438 		}
1439 	}
1440 
1441 	for(size_t i = 0; i < sizeof(bool_false_flags)/sizeof(char *); i++) {
1442 		if(bool_false_flags[i] == (char *)0) break;
1443 		if(strncmp(uc_value.c_str(), bool_false_flags[i], 7) == 0) {
1444 			flag = false;
1445 			return script_no_errors;
1446 		}
1447 	}
1448 
1449 	flag = false;
1450 	return script_invalid_parameter;
1451 }
1452 
1453 /** **************************************************************
1454  * \brief Validate if the parameter is a value.
1455  * \param value The string in question.
1456  * \param p format verification.
1457  * \return SCRIPT_CODES error code.
1458  *****************************************************************/
check_numbers(char * value,paramter_types p)1459 SCRIPT_CODES ScriptParsing::check_numbers(char *value, paramter_types p)
1460 {
1461 	SCRIPT_CODES error = script_no_errors;
1462 	size_t length = 0;
1463 	size_t index = 0;
1464 	int data_count = 0;
1465 	int signed_value = 0;
1466 	int decimal_point = 0;
1467 
1468 	if(!value)
1469 		return script_function_parameter_error;
1470 
1471 	length = strnlen(value, MAX_PARAMETER_LENGTH);
1472 
1473 	if(length < 1)
1474 		return script_parameter_error;
1475 
1476 	// Skip any leading white spaces.
1477 	for(index = 0; index < length; index++) {
1478 		if(value[index] > ' ')
1479 			break;
1480 	}
1481 
1482 	if((index >= length))
1483 		return script_parameter_error;
1484 
1485 	switch(p) {
1486 		case p_int:
1487 		case p_long:
1488 
1489 			if(value[0] == '-' || value[0] == '+') {
1490 				index++;
1491 				signed_value++;
1492 			}
1493 
1494 		case p_unsigned_int:
1495 		case p_unsigned_long:
1496 
1497 			for(; index< length; index++) {
1498 				if(isdigit(value[index]))
1499 					data_count++;
1500 				else
1501 					break;
1502 			}
1503 			break;
1504 
1505 			if(data_count)
1506 				return script_no_errors;
1507 
1508 		case p_float:
1509 		case p_double:
1510 			if(value[0] == '-' || value[0] == '+') {
1511 				index++;
1512 				signed_value++;
1513 			}
1514 
1515 			for(; index< length; index++) {
1516 				if(isdigit(value[index]))
1517 					data_count++;
1518 
1519 				if(value[index] == '.')
1520 					decimal_point++;
1521 
1522 				if(decimal_point > 1)
1523 					return script_parameter_error;
1524 			}
1525 
1526 			if(data_count)
1527 				return script_no_errors;
1528 
1529 			break;
1530 
1531 		default:;
1532 
1533 	}
1534 
1535 	return error;
1536 }
1537 
1538 /** **************************************************************
1539  * \brief Validate the script parameter(s) are of the expected format.
1540  * \param cmd Matching command data structure.
1541  * \param p A table of expected parameters types (null terminated).
1542  * \param p_count the number of 'p[]' items in the table (includes null termination).
1543  * \return SCRIPT_CODES error code.
1544  *****************************************************************/
check_parameters(struct script_cmds * cmd)1545 SCRIPT_CODES ScriptParsing::check_parameters(struct script_cmds *cmd)
1546 {
1547 	SCRIPT_CODES error = script_no_errors;
1548 	int count   = 0;
1549 	int index   = 0;
1550 	size_t size = 0;
1551 	bool flag = false;
1552 
1553 	if(!cmd)
1554 		return script_function_parameter_error;
1555 
1556 	count = cmd->argc;
1557 
1558 	if(count < 1)
1559 		return script_no_errors;
1560 
1561 	for(index = 0; index < count; index++) {
1562 
1563 		if(!cmd->args[index]) {
1564 			return script_args_eol;
1565 		}
1566 
1567 		if(cmd->param_check[index] == p_null) {
1568 			size = 0;
1569 		} else {
1570 			size = strnlen(cmd->args[index], MAX_COMMAND_LENGTH);
1571 		}
1572 
1573 		switch(cmd->param_check[index]) {
1574 			case p_null:
1575 				error = script_param_check_eol;
1576 				break;
1577 
1578 			case p_char:
1579 				if(size > 1)
1580 					error = script_paramter_exceeds_length;
1581 				break;
1582 
1583 			case p_bool:
1584 				error = check_bool(cmd->args[index], flag);
1585 				break;
1586 
1587 			case p_int:
1588 			case p_long:
1589 			case p_unsigned_int:
1590 			case p_unsigned_long:
1591 			case p_float:
1592 			case p_double:
1593 				error = check_numbers(cmd->args[index], cmd->param_check[index]);
1594 				break;
1595 
1596 			case p_dev_path:
1597 				error = check_dev_path(cmd->args[index]);
1598 				break;
1599 
1600 			case p_dev_name:
1601 			case p_string:
1602 				if(size < 1)
1603 					error = script_parameter_error;
1604 				break;
1605 
1606 			case p_path:
1607 				error = check_path(cmd->args[index]);
1608 				break;
1609 
1610 			case p_filename:
1611 				error = check_filename(cmd->args[index]);
1612 				break;
1613 
1614 			case p_list:
1615 			case p_list_end:
1616 			case p_void:
1617 				break;
1618 		}
1619 
1620 		if(error != script_no_errors)
1621 			break;
1622 	}
1623 
1624 	return error;
1625 }
1626 
1627 /** **************************************************************
1628  * \brief Search the content of SCRIPT_COMMANDS structure table
1629  * for the specified command.
1630  * \param command The command to search for.
1631  * \return Pointer to the matching SCRIPT_COMMANDS entry. Null if
1632  * not found.
1633  *****************************************************************/
search_command(SCRIPT_COMMANDS * table,size_t limit,const char * command)1634 SCRIPT_COMMANDS * ScriptParsing::search_command(SCRIPT_COMMANDS * table, size_t limit, const char *command)
1635 {
1636 	char *cmd_buffer = (char *)0;
1637 	int diff = 0;
1638 	SCRIPT_COMMANDS * found = (SCRIPT_COMMANDS *) 0;
1639 	size_t count = limit;
1640 	size_t index = 0;
1641 
1642 	if(!command) return found;
1643 
1644 	cmd_buffer = new char [MAX_COMMAND_LENGTH];
1645 
1646 	if(!cmd_buffer) {
1647 		LOG_INFO(_("cmd_buffer allocation error near line %d"), __LINE__);
1648 		return found;
1649 	}
1650 
1651 	memset(cmd_buffer, 0, MAX_COMMAND_LENGTH);
1652 	strncpy(cmd_buffer, command, MAX_COMMAND_LENGTH-1);
1653 
1654 	to_uppercase(cmd_buffer, (int) MAX_COMMAND_LENGTH);
1655 	trim(cmd_buffer, (size_t) MAX_COMMAND_LENGTH);
1656 
1657 	for(index = 0; index < count; index++) {
1658 		diff = strncmp(cmd_buffer, table[index].command, MAX_COMMAND_LENGTH);
1659 		if(diff == 0) {
1660 			found = &table[index];
1661 			break;
1662 		}
1663 	}
1664 
1665 	cmd_buffer[0] = 0;
1666 	delete [] cmd_buffer;
1667 
1668 	return found;
1669 }
1670 
1671 /** **************************************************************
1672  * \brief Convert string to uppercase characters.<br>
1673  * \par str Pointer to data.
1674  * \par limit data buffer size
1675  * \return void
1676  *****************************************************************/
to_uppercase(char * str,int limit)1677 void ScriptParsing::to_uppercase(char *str, int limit)
1678 {
1679 	if(!str || limit < 1) return;
1680 
1681 	int character = 0;
1682 	int count     = 0;
1683 	int index     = 0;
1684 
1685 	count = (int) strnlen(str, limit);
1686 
1687 	for(index = 0; index < count; index++) {
1688 		character = str[index];
1689 		if(character == 0) break;
1690 		character = (char) toupper(character);
1691 		str[index] = character;
1692 	}
1693 }
1694 
1695 /** **************************************************************
1696  * \brief Convert string to uppercase characters.<br>
1697  * \par str String storage passed by reference.
1698  * \return void
1699  *****************************************************************/
to_uppercase(std::string & str)1700 void ScriptParsing::to_uppercase(std::string &str)
1701 {
1702 	int character = 0;
1703 	int count     = 0;
1704 	int index     = 0;
1705 
1706 	count = (int) str.length();
1707 
1708 	for(index = 0; index < count; index++) {
1709 		character = str[index];
1710 		if(character == 0) break;
1711 		character = (char) toupper(character);
1712 		str[index] = character;
1713 	}
1714 }
1715 
1716 #if 0
1717 /** **************************************************************
1718  * \brief Assign Call back function to a given script command.<br>
1719  * \param scriptCommand Script command string<br>
1720  * \param cb Pointer to call back function. int (*cb)(ScriptParsing *sp, SCRIPT_COMMANDS *sc)
1721  *****************************************************************/
1722 int ScriptParsing::assign_callback(const char *scriptCommand, int (*cb)(ScriptParsing *sp, SCRIPT_COMMANDS *sc))
1723 {
1724 	char *cmd_buffer = (char *)0;
1725 	int diff = 0;
1726 	size_t count = _script_command_count;
1727 	size_t index = 0;
1728 
1729 	if(!scriptCommand || !cb) return 0;
1730 
1731 	cmd_buffer = new char[MAX_COMMAND_LENGTH];
1732 
1733 	if(!cmd_buffer) {
1734 		LOG_INFO(_("cmd_buffer allocation error near line %d"), __LINE__);
1735 		return 0;
1736 	}
1737 
1738 	memset(cmd_buffer, 0, MAX_COMMAND_LENGTH);
1739 	strncpy(cmd_buffer, scriptCommand, MAX_COMMAND_LENGTH-1);
1740 
1741 	to_uppercase(cmd_buffer, (int) MAX_COMMAND_LENGTH);
1742 	trim(cmd_buffer, (size_t) MAX_COMMAND_LENGTH);
1743 
1744 	for(index = 0; index < count; index++) {
1745 		diff = strncmp(cmd_buffer, _script_commands[index].command, MAX_COMMAND_LENGTH);
1746 		if(diff == 0) {
1747 			if(_script_commands[index].cb)
1748 				LOG_INFO(_("Over writing call back funcion for \"%s\""), cmd_buffer);
1749 			_script_commands[index].cb = cb;
1750 			break;
1751 		}
1752 	}
1753 
1754 	cmd_buffer[0] = 0;
1755 	delete [] cmd_buffer;
1756 
1757 	return 0;
1758 }
1759 #endif // #if 0
1760 
1761 /** **************************************************************
1762  * \brief Assign member calling function to a command
1763  * \param top_command Top Command
1764  * \param sub_command Sub command
1765  * \param func Assigned calling function member
1766  * \return void (nothing)
1767  *****************************************************************/
assign_member_func(char * cmd,SCRIPT_CODES (ScriptParsing::* func)(struct script_cmds *))1768 SCRIPT_CODES ScriptParsing::assign_member_func(char *cmd, SCRIPT_CODES (ScriptParsing::*func)(struct script_cmds *))
1769 {
1770 	char *buffer = (char *)0;
1771 	char *cPtr   = (char *)0;
1772 	char *endPtr = (char *)0;
1773 	char *ePtr   = (char *)0;
1774 	int allocated_buffer_size = MAX_COMMAND_LENGTH;
1775 	size_t size        = 0;
1776 
1777 	SCRIPT_CODES error = script_no_errors;
1778 	SCRIPT_COMMANDS *local_list = _script_commands;
1779 	size_t local_limit = _script_command_count;
1780 
1781 	if(!cmd || !func)
1782 		return script_invalid_parameter;
1783 
1784 	size = strnlen(cmd, MAX_COMMAND_LENGTH);
1785 	cPtr = cmd;
1786 	endPtr = &cmd[size];
1787 	size = 0;
1788 
1789 	cPtr = skip_white_spaces(cPtr, endPtr, error);
1790 	if(error != script_no_errors) return error;
1791 
1792 	ePtr = skip_to_character(':', cPtr, endPtr, error);
1793 	if(error != script_no_errors) return script_command_seperator_missing;
1794 
1795 	buffer = new char [allocated_buffer_size];
1796 	if(!buffer) {
1797 		LOG_INFO(_("Buffer allocation Error near File: %s Line %d"), __FILE__, __LINE__);
1798 		return script_memory_allocation_error;
1799 	}
1800 
1801 	memset(buffer, 0, allocated_buffer_size);
1802 	error = copy_string_uppercase(buffer, cPtr, ePtr, allocated_buffer_size-1);
1803 
1804 	if(error != script_no_errors) {
1805 		buffer[0] = 0;
1806 		delete [] buffer;
1807 		return error;
1808 	}
1809 
1810 	int str_count = str_cnt(buffer, allocated_buffer_size);
1811 	trim(buffer, (size_t) str_count);
1812 
1813 	char sub_command[MAX_COMMAND_LENGTH];
1814 
1815 	bool not_found = true;
1816 
1817 	cPtr = buffer;
1818 	endPtr = &buffer[str_count];
1819 
1820 	while(not_found) {
1821 		memset(sub_command, 0, sizeof(sub_command));
1822 
1823 		ePtr = skip_to_character('.', cPtr, endPtr, error);
1824 
1825 		if(error == script_end_of_line_reached) {
1826 			ePtr = endPtr;
1827 			error = script_no_errors;
1828 		}
1829 
1830 		if(error == script_no_errors) {
1831 			copy_string_uppercase(sub_command, cPtr, ePtr, MAX_COMMAND_LENGTH-1);
1832 			cPtr = ePtr + 1;
1833 		}
1834 		else
1835 			break;
1836 
1837 		for(size_t i = 0; i < local_limit; i++) {
1838 
1839 			if(local_list[i].command[0] == 0) {
1840 				not_found = false;
1841 				error = script_command_not_found;
1842 				break;
1843 			}
1844 
1845 			if(strncmp(sub_command, local_list[i].command, MAX_COMMAND_LENGTH) == 0) {
1846 
1847 				if((local_list[i].param_check[0] == p_list) && local_list[i].sub_commands) {
1848 					local_limit = local_list[i].sub_command_count;
1849 					local_list  = local_list[i].sub_commands;
1850 					break;
1851 				}
1852 
1853 				local_list[i].func = func;
1854 				local_list[i].command_length = strnlen(local_list[i].command, MAX_COMMAND_LENGTH);
1855 				not_found = false;
1856 				error = script_no_errors;
1857 				break;
1858 			}
1859 		}
1860 	}
1861 
1862 	buffer[0] = 0;
1863 	delete [] buffer;
1864 
1865 	return error;
1866 
1867 }
1868 
1869 #if 0
1870 /** **************************************************************
1871  * \brief Assign member calling function to a command
1872  * \param top_command Top Command
1873  * \param sub_command Sub command
1874  * \param func Assigned calling function member
1875  * \return void (nothing)
1876  *****************************************************************/
1877 void ScriptParsing::assign_member_func(char *cmd, SCRIPT_CODES (ScriptParsing::*func)(struct script_cmds *))
1878 {
1879 	if(!top_command || !func) return;
1880 
1881 	SCRIPT_COMMANDS *top_table = (SCRIPT_COMMANDS *)0;
1882 	SCRIPT_COMMANDS *modify_table = (SCRIPT_COMMANDS *)0;
1883 
1884 	if(top_cache) {
1885 		if(strncmp(top_cache->command, top_command, MAX_COMMAND_LENGTH) == 0) {
1886 			top_table = top_cache;
1887 		}
1888 	}
1889 
1890 	if(!top_table) {
1891 		for(int i = 0; i < _script_command_count; i++) {
1892 			if(strncmp(_script_commands[i].command, top_command, MAX_COMMAND_LENGTH) == 0) {
1893 				top_cache = &_script_commands[i];
1894 				top_table = top_cache;
1895 				break;
1896 			}
1897 		}
1898 	}
1899 
1900 	if(!top_table)
1901 		return;
1902 
1903 	if(!sub_command)
1904 		modify_table = top_table;
1905 
1906 	if(modify_table == (SCRIPT_COMMANDS *)0) {
1907 		if(top_table->sub_commands) {
1908 			for(int i = 0; i < top_table->sub_command_count; i++) {
1909 				if(strncmp(sub_command, top_table->sub_commands[i].command, MAX_COMMAND_LENGTH) == 0) {
1910 					modify_table = &top_table->sub_commands[i];
1911 					break;
1912 				}
1913 			}
1914 		}
1915 	}
1916 
1917 	if(modify_table != (SCRIPT_COMMANDS *)0) {
1918 		modify_table->func = func;
1919 		modify_table->command_length = strnlen(modify_table->command, MAX_COMMAND_LENGTH);
1920 	}
1921 }
1922 #endif // #if 0
1923 
1924 /** **************************************************************
1925  * \brief Initialize variables
1926  * \return void (nothing)
1927  *****************************************************************/
clear_script_parameters(bool all)1928 void ScriptParsing::clear_script_parameters(bool all)
1929 {
1930 	_path.clear();
1931 	_file_type = SCRIPT_COMMAND;
1932 	_macro_command.clear();
1933 }
1934 
1935 
1936 /** **************************************************************
1937  * \brief Initialize callable members.
1938  * \return void (nothing)
1939  *****************************************************************/
initialize_function_members(void)1940 void ScriptParsing::initialize_function_members(void)
1941 {
1942 	std::string cmd;
1943 
1944 	cmd.assign(CMD_LOAD_MACRO).append(":"); // For localization
1945 	assign_member_func((char *) cmd.c_str(), &ScriptParsing::sc_macros);
1946 }
1947 
1948 /** **************************************************************
1949  * \brief Copy environment to the sub ScriptParsing class
1950  * \param src Source Class pointer to copy from.
1951  *****************************************************************/
CopyScriptParsingEnv(ScriptParsing * src)1952 int ScriptParsing::CopyScriptParsingEnv(ScriptParsing *src)
1953 {
1954 	if(!src || (src == this)) return -1;
1955 
1956 
1957 	parent(src);
1958 	script_commands(src->script_commands());
1959 	script_command_count(src->script_command_count());
1960 	initialize_function_members();
1961 
1962 	return 0;
1963 }
1964 /** **************************************************************
1965  * \brief Constructor: Copy and initialize.<br>
1966  *****************************************************************/
copy_tables(struct script_cmds * subcmds,size_t count)1967 int ScriptParsing::copy_tables(struct script_cmds * subcmds, size_t count)
1968 {
1969 	size_t index = 0;
1970 	size_t table_count = 0;
1971 
1972 	SCRIPT_COMMANDS * dst_table = 0;
1973 	SCRIPT_COMMANDS * src_table = 0;
1974 
1975 	recursive_count++;
1976 	if(recursive_count > RECURSIVE_LIMIT) return 0;
1977 
1978 	for(index = 0; index < count; index++) {
1979 		src_table   = subcmds[index].sub_commands;
1980 		table_count = subcmds[index].sub_command_count;
1981 
1982 		if(src_table && table_count) {
1983 			dst_table = new SCRIPT_COMMANDS[table_count];
1984 			if(dst_table) {
1985 				add_to_delete_list(dst_table);
1986 				memcpy(dst_table, src_table, sizeof(SCRIPT_COMMANDS) * table_count);
1987 				subcmds[index].sub_commands      = dst_table;
1988 				subcmds[index].sub_command_count = table_count;
1989 				copy_tables(dst_table, table_count);
1990 			}
1991 		}
1992 	}
1993 
1994 	recursive_count--;
1995 	return 0;
1996 }
1997 
1998 /** **************************************************************
1999  * \brief Constructor: Copy and initialize function arrays.<br>
2000  *****************************************************************/
ScriptParsing()2001 ScriptParsing::ScriptParsing()
2002 {
2003 	size_t count = 0;
2004 
2005 	clear_script_parameters(true);
2006 
2007 	memset(line_buffer,      0, sizeof(line_buffer));
2008 	memset(error_cmd_buffer, 0, sizeof(error_cmd_buffer));
2009 	memset(error_string,     0, sizeof(error_string));
2010 	memset(error_buffer,     0, sizeof(error_buffer));
2011 
2012 	memset(memory_delete_list, 0, sizeof(memory_delete_list));
2013 	delete_list_count = 0;
2014 
2015 	top_cache = 0;
2016 	recursive_count = 0;
2017 	_script_error_detected = false;
2018 	_restart_flag = false;
2019 
2020 	fd = 0;
2021 
2022 	count = sizeof(default_top_level_command_table)/sizeof(SCRIPT_COMMANDS);
2023 
2024 	_script_commands  = new SCRIPT_COMMANDS[count];
2025 
2026 	if(_script_commands) {
2027 		add_to_delete_list(_script_commands);
2028 		_script_command_count = count;
2029 		memcpy(_script_commands, default_top_level_command_table, sizeof(SCRIPT_COMMANDS) * _script_command_count);
2030 		copy_tables(_script_commands, _script_command_count);
2031 	}
2032 
2033 	recursive_count = 0;
2034 	initialize_function_members();
2035 
2036 }
2037 
2038 /** **************************************************************
2039  * \brief Destructor
2040  *****************************************************************/
~ScriptParsing()2041 ScriptParsing::~ScriptParsing()
2042 {
2043 	int index = 0;
2044 	for(index = 0; index < MAX_DELETE_LIST_COUNT; index++) {
2045 		if(memory_delete_list[index]) {
2046 			delete [] memory_delete_list[index];
2047 		}
2048 	}
2049 }
2050 
2051 /** **************************************************************
2052  * \brief Keep track of memory allocation for easy deallocation.
2053  *****************************************************************/
add_to_delete_list(SCRIPT_COMMANDS * ptr)2054 void ScriptParsing::add_to_delete_list(SCRIPT_COMMANDS *ptr)
2055 {
2056 	if(!ptr) return;
2057 
2058 	if(delete_list_count < MAX_DELETE_LIST_COUNT) {
2059 		memory_delete_list[delete_list_count] = ptr;
2060 		delete_list_count++;
2061 	}
2062 }
2063 
2064 /** **************************************************************
2065  * \brief Dummy callback function for initialization of
2066  * function pointers.
2067  * \param sp The calling ScriptParsing Class
2068  * \param sc Command data structure pointer to the matching script
2069  * command.
2070  * \return 0 = No error<br> \< 0 = Error<br>
2071  *****************************************************************/
callback_dummy(ScriptParsing * sp,struct script_cmds * sc)2072 int callback_dummy(ScriptParsing *sp, struct script_cmds *sc)
2073 {
2074 	return 0;
2075 }
2076 
2077 /** ********************************************************
2078  * \brief Determine the length of the string with a count
2079  * limitation.
2080  * \return signed integer. The number of characters in the
2081  * array not to excede count limit.
2082  ***********************************************************/
str_cnt(char * str,int count_limit)2083 int ScriptParsing::str_cnt(char * str, int count_limit)
2084 {
2085 	if(!str || (count_limit < 1))
2086 		return 0;
2087 
2088 	int value = 0;
2089 
2090 	for(int index = 0; index < count_limit; index++) {
2091 		if(str[index] == 0) break;
2092 		value++;
2093 	}
2094 
2095 	return value;
2096 }
2097 
2098 /** ********************************************************
2099  * \brief Trim leading and trailing spaces from string.
2100  * \param s String to modify
2101  * \return s modified string.
2102  ***********************************************************/
trim(std::string & s)2103 std::string &ScriptParsing::trim(std::string &s) {
2104 	char *buffer = (char *)0;
2105 	char *dst    = (char *)0;
2106 	char *end    = (char *)0;
2107 	char *src    = (char *)0;
2108 	long count   = s.size();
2109 
2110 	buffer = new char[count + 1];
2111 	if(!buffer) return s;
2112 
2113 	memcpy(buffer, s.c_str(), count);
2114 	buffer[count] = 0;
2115 
2116 	dst = src = buffer;
2117 	end = &buffer[count];
2118 
2119 	while(src < end) {
2120 		if(*src > ' ') break;
2121 		src++;
2122 	}
2123 
2124 	if(src > dst) {
2125 		while((dst < end) && (src < end))
2126 			*dst++ = *src++;
2127 		*dst = 0;
2128 	}
2129 
2130 	while(end >= buffer) {
2131 		if(*end > ' ') break;
2132 		*end-- = 0;
2133 	}
2134 
2135 	s.assign(buffer);
2136 
2137 	delete [] buffer;
2138 
2139 	return s;
2140 }
2141 
2142 /** **************************************************************
2143  * \brief Remove leading/trailing white spaces and quotes.
2144  * \param buffer Destination buffer
2145  * \param limit passed buffer size
2146  * \return void
2147  *****************************************************************/
trim(char * buffer,size_t limit)2148 void ScriptParsing::trim(char *buffer, size_t limit)
2149 {
2150 	char *s      = (char *)0;
2151 	char *e      = (char *)0;
2152 	char *dst    = (char *)0;
2153 	size_t count = 0;
2154 
2155 	if(!buffer || limit < 1) {
2156 		return;
2157 	}
2158 
2159 	for(count = 0; count < limit; count++)
2160 		if(buffer[count] == 0) break;
2161 
2162 	if(count < 1) return;
2163 
2164 	s = buffer;
2165 	e = &buffer[count-1];
2166 
2167 	for(size_t i = 0; i < count; i++) {
2168 		if((*s <= ' ') || (*s == '"')) s++;
2169 		else break;
2170 	}
2171 
2172 	while(e > s) {
2173 		if(*e == '"') {	*e-- = 0; break; }
2174 		if(*e > ' ') break;
2175 		if(*e <= ' ') *e = 0;
2176 		e--;
2177 	}
2178 
2179 	dst = buffer;
2180 	while(s <= e) {
2181 		*dst++ = *s++;
2182 	}
2183 	*dst = 0;
2184 }
2185