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