This source file includes following definitions.
- setenv
- unsetenv
- trealloc
- processIsTranslated
- strremove
- strtrimspace
- allowCores
- CleanDUMA
- main
- process_stdin_commands
- set_prompt
- find_cmd
- exit_cmd
- _cmd_name_compare
- fprint_help
- fprint_header
- fprint_reg_help_ex
- fprint_reg_help
- fprint_attach_help_ex
- fprint_set_help_ex
- fprint_set_help
- fprint_show_help_ex
- fprint_show_help
- fprint_brk_help_ex
- help_dev_help
- help_cmd_output
- help_cmd
- spawn_cmd
- echo_cmd
- do_cmd
- do_position
- do_cmd_label
- sim_sub_args
- sim_cmp_string
- assert_cmd
- send_cmd
- sim_show_send
- expect_cmd
- sim_show_expect
- goto_cmd
- return_cmd
- shift_cmd
- call_cmd
- on_cmd
- noop_cmd
- set_on
- set_verify
- set_message
- set_localopc
- set_quiet
- sim_set_environment
- set_cmd
- find_ctab
- find_c1tab
- set_dev_radix
- set_dev_enbdis
- set_unit_enbdis
- set_dev_debug
- show_cmd
- show_cmd_fi
- find_shtab
- show_device
- fprint_sep
- show_unit
- sprint_capac
- fprint_capac
- show_default_base_system_script
- printp
- show_prom
- show_buildinfo
- show_version
- show_config
- show_log_names
- show_dev_logicals
- show_queue
- show_time
- show_break
- show_dev_radix
- show_dev_debug
- show_on
- show_mod_names
- show_dev_modifiers
- show_all_mods
- show_one_mod
- show_show_commands
- show_dev_show_commands
- brk_cmd
- ssh_break
- ssh_break_one
- reset_cmd
- reset_all
- reset_all_p
- attach_cmd
- scp_attach_unit
- attach_unit
- attach_err
- detach_cmd
- detach_all
- scp_detach_unit
- detach_unit
- sim_dname
- sim_uname
- run_cmd
- run_cmd_message
- sim_run_boot_prep
- fprint_stopped_gen
- fprint_stopped
- step_svc
- expect_svc
- int_handler
- exdep_cmd
- exdep_reg_loop
- exdep_addr_loop
- ex_reg
- get_rval
- dep_reg
- put_rval
- ex_addr
- get_aval
- dep_addr
- eval_cmd
- read_line
- read_line_p
- get_glyph_gen
- get_glyph
- get_glyph_nc
- get_glyph_quoted
- get_glyph_cmd
- sim_trim_endspc
- sim_isspace
- sim_islower
- sim_isalpha
- sim_isprint
- sim_isdigit
- sim_isgraph
- sim_isalnum
- get_uint
- get_range
- sim_decode_quoted_string
- sim_encode_quoted_string
- fprint_buffer_string
- find_dev
- find_unit
- sim_register_internal_device
- find_dev_from_unit
- qdisable
- find_reg_glob
- find_reg
- get_switches
- get_sim_sw
- get_sim_opt
- put_switches
- get_rsearch
- get_asearch
- test_search
- strtotv
- sprint_val
- fprint_val
- sim_fmt_secs
- sim_process_event
- sim_activate
- _sim_activate
- sim_activate_abs
- sim_activate_after
- _sim_activate_after
- sim_cancel
- sim_is_active
- sim_activate_time
- sim_gtime
- sim_qcount
- sim_brk_init
- sim_brk_fnd
- sim_brk_fnd_ex
- sim_brk_new
- sim_brk_set
- sim_brk_clr
- sim_brk_clrall
- sim_brk_show
- sim_brk_showall
- sim_brk_test
- sim_brk_getact
- sim_brk_clract
- sim_brk_setact
- sim_brk_npc
- sim_brk_clrspc
- sim_brk_message
- sim_set_expect
- sim_set_noexpect
- sim_exp_fnd
- sim_exp_clr_tab
- sim_exp_clr
- sim_exp_clrall
- sim_exp_set
- sim_exp_show_tab
- sim_exp_show
- sim_exp_showall
- sim_exp_check
- sim_send_input
- sim_send_clear
- sim_show_send_input
- sim_send_poll_data
- sim_error_text
- sim_string_to_stat
- get_dbg_verb
- sim_debug_prefix
- fprint_fields
- sim_debug_bits_hdr
- sim_debug_bits
- sim_printf
- sim_messagef
- _sim_debug
- sim_data_trace
- Fprintf
- appendText
- cleanHelp
- buildHelp
- helpPrompt
- displayMagicTopic
- displayFlatHelp
- matchHelpTopicName
- scp_vhelp
- scp_help
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 #include "sim_defs.h"
45 #include "sim_disk.h"
46 #include "sim_tape.h"
47 #include "sim_sock.h"
48 #include <signal.h>
49 #include <ctype.h>
50 #include <time.h>
51 #include <math.h>
52 #if defined(_WIN32)
53 # ifndef WIN32_LEAN_AND_MEAN
54 # define WIN32_LEAN_AND_MEAN
55 # endif
56 # if defined(_MSC_VER)
57 # pragma warning(push, 3)
58 # endif
59 # include <direct.h>
60 # include <io.h>
61 # include <fcntl.h>
62 #else
63 # include <unistd.h>
64 # define HAVE_UNISTD 1
65 #endif
66 #include <sys/stat.h>
67 #include <sys/types.h>
68 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
69 # include <sys/resource.h>
70 #endif
71 #include <setjmp.h>
72 #include <limits.h>
73 #include <locale.h>
74
75 #include "linehistory.h"
76
77 #if defined(__APPLE__)
78 # include <sys/sysctl.h>
79 #endif
80
81 #if ( defined(__linux__) || defined(__linux) \
82 || defined(_linux) || defined(linux) )
83 # include <sys/sysinfo.h>
84 # define LINUX_OS
85 #endif
86
87 #include <uv.h>
88
89 #ifndef HAVE_UNISTD
90 # undef USE_BACKTRACE
91 #endif
92
93 #ifdef USE_BACKTRACE
94 # include <string.h>
95 # include <signal.h>
96 #endif
97
98 #ifdef __HAIKU__
99 # include <OS.h>
100 #endif
101
102 #define DBG_CTR 0
103
104 #include "../dps8/dps8.h"
105 #include "../dps8/dps8_cpu.h"
106 #include "../dps8/ver.h"
107 #include "../dps8/sysdefs.h"
108
109 #include "../dps8/dps8_iom.h"
110 #include "../dps8/dps8_fnp2.h"
111
112 #include "../decNumber/decContext.h"
113 #include "../decNumber/decNumberLocal.h"
114
115 #include "../dps8/dps8_math128.h"
116
117 #include "dispatch.h"
118
119 #ifndef MAX
120 # define MAX(a,b) (((a) >= (b)) ? (a) : (b))
121 #endif
122
123 #ifdef TESTING
124 # undef FREE
125 # define FREE(p) free(p)
126 #endif
127
128
129
130 #define SCH_OR 0
131 #define SCH_AND 1
132 #define SCH_XOR 2
133 #define SCH_E 0
134 #define SCH_N 1
135 #define SCH_G 2
136 #define SCH_L 3
137 #define SCH_EE 4
138 #define SCH_NE 5
139 #define SCH_GE 6
140 #define SCH_LE 7
141
142 #define MAX_DO_NEST_LVL 20
143 #define SRBSIZ 1024
144 #define SIM_BRK_INILNT 4096
145 #define SIM_BRK_ALLTYP 0xFFFFFFFB
146
147 #define UPDATE_SIM_TIME \
148 if (1) { \
149 int32 _x; \
150 if (sim_clock_queue == QUEUE_LIST_END) \
151 _x = noqueue_time; \
152 else \
153 _x = sim_clock_queue->time; \
154 sim_time = sim_time + (_x - sim_interval); \
155 sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
156 if (sim_clock_queue == QUEUE_LIST_END) \
157 noqueue_time = sim_interval; \
158 else \
159 sim_clock_queue->time = sim_interval; \
160 } \
161 else \
162 (void)0
163
164 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
165
166 #define SZ_R(rp) \
167 (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
168
169 #define SZ_LOAD(sz,v,mb,j) \
170 if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \
171 else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
172 else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
173 else v = *(((t_uint64 *) mb) + ((uint32) j));
174
175 #define SZ_STORE(sz,v,mb,j) \
176 if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \
177 else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
178 else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
179 else *(((t_uint64 *) mb) + ((uint32) j)) = v;
180
181 #define GET_SWITCHES(cp) \
182 if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
183
184 #define GET_RADIX(val,dft) \
185 if (sim_switches & SWMASK ('O')) val = 8; \
186 else if (sim_switches & SWMASK ('D')) val = 10; \
187 else if (sim_switches & SWMASK ('H')) val = 16; \
188 else val = dft;
189
190
191
192
193
194
195 t_bool sim_asynch_enabled = FALSE;
196 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
197 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
198 extern void (*sim_vm_init) (void);
199 extern void (*sim_vm_exit) (void);
200 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
201 void (*sim_vm_post) (t_bool from_scp) = NULL;
202 CTAB *sim_vm_cmd = NULL;
203 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
204 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
205 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
206 t_value (*sim_vm_pc_value) (void) = NULL;
207 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
208 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
209
210
211
212
213
214 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
215 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
216 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
217 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
218 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
219 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
220 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
221 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
222 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
223 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
224 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
225 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
226 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
227 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
228 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
229 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
230 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
231 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
232 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
233 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
234 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
235 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
236 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
237 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
238 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
239 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
240 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
241 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
242 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
243 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
244 t_stat sim_save (FILE *sfile);
245 t_stat sim_rest (FILE *rfile);
246
247
248
249 t_stat sim_brk_init (void);
250 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
251 t_stat sim_brk_clr (t_addr loc, int32 sw);
252 t_stat sim_brk_clrall (int32 sw);
253 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
254 t_stat sim_brk_showall (FILE *st, int32 sw);
255 CONST char *sim_brk_getact (char *buf, int32 size);
256 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
257 char *sim_brk_clract (void);
258
259 FILE *stdnul;
260
261
262
263 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
264 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
265 int32 test_search (t_value *val, SCHTAB *schptr);
266 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
267 int32 get_switches (const char *cptr);
268 CONST char *get_sim_sw (CONST char *cptr);
269 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
270 t_value get_rval (REG *rptr, uint32 idx);
271 void put_rval (REG *rptr, uint32 idx, t_value val);
272 void fprint_help (FILE *st);
273 void fprint_stopped (FILE *st, t_stat r);
274 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
275 void fprint_sep (FILE *st, int32 *tokens);
276 char *read_line (char *ptr, int32 size, FILE *stream);
277 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
278 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
279 char *sim_trim_endspc (char *cptr);
280
281
282
283 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
284 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
285 t_bool qdisable (DEVICE *dptr);
286 t_stat attach_err (UNIT *uptr, t_stat stat);
287 t_stat detach_all (int32 start_device, t_bool shutdown);
288 t_stat assign_device (DEVICE *dptr, const char *cptr);
289 t_stat deassign_device (DEVICE *dptr);
290 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
291 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
292 REG *lowr, REG *highr, uint32 lows, uint32 highs);
293 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
294 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
295 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
296 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
297 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
298 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
299 UNIT *uptr, int32 dfltinc);
300 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
301 t_stat step_svc (UNIT *ptr);
302 t_stat expect_svc (UNIT *ptr);
303 t_stat set_on (int32 flag, CONST char *cptr);
304 t_stat set_verify (int32 flag, CONST char *cptr);
305 t_stat set_message (int32 flag, CONST char *cptr);
306 t_stat set_quiet (int32 flag, CONST char *cptr);
307 t_stat set_localopc (int32 flag, CONST char *cptr);
308 t_stat set_asynch (int32 flag, CONST char *cptr);
309 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
310 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
311 void int_handler (int signal);
312 t_stat set_prompt (int32 flag, CONST char *cptr);
313 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
314 t_stat sim_set_environment (int32 flag, CONST char *cptr);
315 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
316
317
318
319 DEVICE *sim_dflt_dev = NULL;
320 UNIT *sim_clock_queue = QUEUE_LIST_END;
321 int32 sim_interval = 0;
322 int32 sim_switches = 0;
323 FILE *sim_ofile = NULL;
324 SCHTAB *sim_schrptr = FALSE;
325 SCHTAB *sim_schaptr = FALSE;
326 DEVICE *sim_dfdev = NULL;
327 UNIT *sim_dfunit = NULL;
328 DEVICE **sim_internal_devices = NULL;
329 uint32 sim_internal_device_count = 0;
330 int32 sim_opt_out = 0;
331 int32 sim_is_running = 0;
332 t_bool sim_processing_event = FALSE;
333 uint32 sim_brk_summ = 0;
334 uint32 sim_brk_types = 0;
335 BRKTYPTAB *sim_brk_type_desc = NULL;
336 uint32 sim_brk_dflt = 0;
337 uint32 sim_brk_match_type;
338 t_addr sim_brk_match_addr;
339 char *sim_brk_act[MAX_DO_NEST_LVL];
340 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
341 BRKTAB **sim_brk_tab = NULL;
342 int32 sim_brk_ent = 0;
343 int32 sim_brk_lnt = 0;
344 int32 sim_brk_ins = 0;
345 int32 sim_iglock = 0;
346 int32 sim_nolock = 0;
347 int32 sim_quiet = 0;
348 int32 sim_localopc = 1;
349 int32 sim_randompst = 0;
350 int32 sim_randstate = 0;
351 int32 sim_step = 0;
352 int nodist = 0;
353 #ifdef PERF_STRIP
354 int32 sim_nostate = 1;
355 #else
356 int32 sim_nostate = 0;
357 #endif
358 static double sim_time;
359 static uint32 sim_rtime;
360 static int32 noqueue_time;
361 volatile int32 stop_cpu = 0;
362 t_value *sim_eval = NULL;
363 static t_value sim_last_val;
364 static t_addr sim_last_addr;
365 FILE *sim_log = NULL;
366 FILEREF *sim_log_ref = NULL;
367 FILE *sim_deb = NULL;
368 FILEREF *sim_deb_ref = NULL;
369 int32 sim_deb_switches = 0;
370 struct timespec sim_deb_basetime;
371 char *sim_prompt = NULL;
372 static FILE *sim_gotofile;
373 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];
374 static int32 sim_do_echo = 0;
375 static int32 sim_show_message = 1;
376 static int32 sim_on_inherit = 0;
377 static int32 sim_do_depth = 0;
378
379 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
380 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
381 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
382 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
383 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
384
385 t_stat sim_last_cmd_stat;
386
387 static SCHTAB sim_stabr;
388 static SCHTAB sim_staba;
389
390 static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) };
391 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0) };
392
393
394
395 const char save_vercur[] = "V4.1";
396 const char save_ver40[] = "V4.0";
397 const char save_ver35[] = "V3.5";
398 const char save_ver32[] = "V3.2";
399 const char save_ver30[] = "V3.0";
400 const struct scp_error {
401 const char *code;
402 const char *message;
403 } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
404 {{"NXM", "Address space exceeded"},
405 {"UNATT", "Unit not attached"},
406 {"IOERR", "I/O error"},
407 {"CSUM", "Checksum error"},
408 {"FMT", "Format error"},
409 {"NOATT", "Unit not attachable"},
410 {"OPENERR", "File open error"},
411 {"MEM", "Memory exhausted"},
412 {"ARG", "Invalid argument"},
413 {"STEP", "Step expired"},
414 {"UNK", "Unknown command"},
415 {"RO", "Read only argument"},
416 {"INCOMP", "Command not completed"},
417 {"STOP", "Simulation stopped"},
418 {"EXIT", "Goodbye"},
419 {"TTIERR", "Console input I/O error"},
420 {"TTOERR", "Console output I/O error"},
421 {"EOF", "End of file"},
422 {"REL", "Relocation error"},
423 {"NOPARAM", "No settable parameters"},
424 {"ALATT", "Unit already attached"},
425 {"TIMER", "Hardware timer error"},
426 {"SIGERR", "Signal handler setup error"},
427 {"TTYERR", "Console terminal setup error"},
428 {"SUB", "Subscript out of range"},
429 {"NOFNC", "Command not allowed"},
430 {"UDIS", "Unit disabled"},
431 {"NORO", "Read only operation not allowed"},
432 {"INVSW", "Invalid switch"},
433 {"MISVAL", "Missing value"},
434 {"2FARG", "Too few arguments"},
435 {"2MARG", "Too many arguments"},
436 {"NXDEV", "Non-existent device"},
437 {"NXUN", "Non-existent unit"},
438 {"NXREG", "Non-existent register"},
439 {"NXPAR", "Non-existent parameter"},
440 {"NEST", "Nested DO command limit exceeded"},
441 {"IERR", "Internal error"},
442 {"MTRLNT", "Invalid magtape record length"},
443 {"LOST", "Console Telnet connection lost"},
444 {"TTMO", "Console Telnet connection timed out"},
445 {"STALL", "Console Telnet output stall"},
446 {"AFAIL", "Assertion failed"},
447 {"INVREM", "Invalid remote console command"},
448 {"NOTATT", "Not attached"},
449 {"EXPECT", "Expect matched"},
450 {"REMOTE", "Remote console command"},
451 };
452
453 const size_t size_map[] = { sizeof (int8),
454 sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
455 , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
456 };
457
458 const t_value width_mask[] = { 0,
459 0x1, 0x3, 0x7, 0xF,
460 0x1F, 0x3F, 0x7F, 0xFF,
461 0x1FF, 0x3FF, 0x7FF, 0xFFF,
462 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
463 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
464 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
465 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
466 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
467 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
468 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
469 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
470 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
471 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
472 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
473 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
474 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
475 };
476
477 static const char simh_help[] =
478
479 "1Commands\n"
480 #define HLP_RESET "*Commands Resetting Devices"
481
482 "2Resetting Devices\n"
483 " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\n"
484 " simulator to a predefined condition. If the switch \"`-p`\" is specified,\n"
485 " the device is reset to its initial power-on state:\n\n"
486 "++RESET resets all devices\n"
487 "++RESET -p power-cycle all devices\n"
488 "++RESET ALL resets all devices\n"
489 "++RESET <device> resets the specified <device>\n\n"
490 " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\n"
491 " interrupt requests, and returns the device to a quiescent state.\n\n"
492 " * It does **NOT** clear the main memory or affect associated I/O\n"
493 " connections.\n"
494 #define HLP_EXAMINE "*Commands Examining_and_Changing_State"
495 #define HLP_IEXAMINE "*Commands Examining_and_Changing_State"
496 #define HLP_DEPOSIT "*Commands Examining_and_Changing_State"
497 #define HLP_IDEPOSIT "*Commands Examining_and_Changing_State"
498
499 "2Examining and Changing State\n"
500 " There are four commands to examine and change state:\n\n"
501 " * `EXAMINE` (*abbreviated* `E`) examines state\n"
502 " * `DEPOSIT` (*abbreviated* `D`) changes state\n"
503 " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\n"
504 " and allows the user to interactively change it\n"
505 " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\n"
506 " interactively change state\n\n"
507 " All four commands take the form:\n\n"
508 "++command {modifiers} <object list>\n\n"
509 " The `DEPOSIT` command requires the deposit value at the end of the command.\n\n"
510 " There are four kinds of modifiers: **switches**, **device/unit name**,\n"
511 " **search specifier**, and for `EXAMINE`, **output file**.\n\n"
512 " * **Switches** have been described previously.\n"
513 " * A **device/unit name** identifies the device and unit whose address\n"
514 " space is to be examined or modified. If no device is specified, the CPU\n"
515 " main memory is selected. If a device but no unit is specified, unit `0`\n"
516 " of the specified device is selected automatically.\n"
517 " * The **search specifier** provides criteria for testing addresses or\n"
518 " registers to see if they should be processed. The search specifier\n"
519 " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\n"
520 " both, optionally separated by spaces:\n\n"
521 "++{ < logical op > < value > } < relational op > < value >\n\n"
522
523 " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\n"
524 " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\n"
525 " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\n"
526 " equal*), \">=\" (*greater than or equal*), \">\" (*greater\n"
527 " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\n"
528 " * * If any \"<`logical operator`>\" is specified without\n"
529 " a \"<`relational operator`>\", it is ignored.\n"
530 " * * If any \"<`relational operator`>\" is specified without\n"
531 " a \"<`logical operator`>\", no logical operation is performed.\n"
532 " * * All comparisons are unsigned.\n\n"
533 " * The **output file** modifier redirects the command output to a file\n"
534 " instead of the console. The **output file** modifier is specified with\n"
535 " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\n\n"
536 " **NOTE**: Modifiers may be specified in any order. If multiple\n"
537 " modifiers of the same type are specified, later modifiers override earlier\n"
538 " modifiers. If the **device/unit name** comes *after* the search specifier,\n"
539 " the search values will interpreted in the *radix of the CPU*, rather than\n"
540 " of the device/unit.\n\n"
541 " The \"<`object list`>\" argument consists of one or more of the following,\n"
542 " separated by commas:\n\n"
543
544 "++register the specified register\n"
545 "++register[sub1-sub2] the specified register array locations,\n"
546 "++++++++ starting at location sub1 up to and\n"
547 "++++++++ including location sub2\n"
548 "++register[sub1/length] the specified register array locations,\n"
549 "++++++++ starting at location sub1 up to but\n"
550 "++++++++ not including sub1+length\n"
551 "++register[ALL] all locations in the specified register\n"
552 "++++++++ array\n"
553 "++register1-register2 all the registers starting at register1\n"
554 "++++++++ up to and including register2\n"
555 "++address the specified location\n"
556 "++address1-address2 all locations starting at address1 up to\n"
557 "++++++++ and including address2\n"
558 "++address/length all location starting at address up to\n"
559 "++++++++ but not including address+length\n"
560 "++STATE all registers in the device\n"
561 "++ALL all locations in the unit\n"
562 "++$ the last value displayed by an EXAMINE\n"
563 "++++++++ command interpreted as an address\n"
564 "3Switches\n"
565 "4Formatting Control\n"
566 " Switches can be used to control the format of the displayed information:\n\n"
567
568 "5-a\n"
569 " display as ASCII\n"
570 "5-c\n"
571 " display as character string\n"
572 "5-m\n"
573 " display as instruction mnemonics\n"
574 "5-o\n"
575 " display as octal\n"
576 "5-d\n"
577 " display as decimal\n"
578 "5-h\n"
579 " display as hexadecimal\n\n"
580 "3Examples\n"
581 "++ex 1000-1100 examine 1000 to 1100\n"
582 "++de PC 1040 set PC to 1040\n"
583 "++ie 40-50 interactively examine 40:50\n"
584 "++ie >1000 40-50 interactively examine the subset\n"
585 "+++++++++ of locations 40:50 that are >1000\n"
586 "++ex rx0 50060 examine 50060, RX unit 0\n"
587 "++ex rx sbuf[3-6] examine SBUF[3] to SBUF[6] in RX\n"
588 "++de all 0 set main memory to 0\n"
589 "++de &77>0 0 set all addresses whose low order\n"
590 "+++++++++ bits are non-zero to 0\n"
591 "++ex -m @memdump.txt 0-7777 dump memory to file\n\n"
592 " * **NOTE**: To terminate an interactive command, simply type any bad value\n"
593 " (*e.g.* `XYZ`) when input is requested.\n"
594 #define HLP_EVALUATE "*Commands Evaluating_Instructions"
595
596 "2Evaluating Instructions\n"
597 " The `EVAL` command evaluates a symbolic expression and returns the\n"
598 " equivalent numeric value.\n\n"
599
600 "2Running A Simulated Program\n"
601 #define HLP_RUN "*Commands Running_A_Simulated_Program RUN"
602 "3RUN\n"
603 " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\n"
604 " argument, if given, in the PC (program counter), and starts execution.\n"
605 " If no argument is given execution starts at the current PC.\n"
606 #define HLP_GO "*Commands Running_A_Simulated_Program GO"
607 "3GO\n"
608 " The `GO` command does *not* reset devices, deposits its argument (if\n"
609 " given) in the PC, and starts execution. If no argument is given,\n"
610 " execution starts at the current PC (program counter).\n"
611 #define HLP_CONTINUE "*Commands Running_A_Simulated_Program Continuing_Execution"
612 "3Continuing Execution\n"
613 " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\n"
614 " (if execution was stopped, possibly due to hitting a breakpoint) at the\n"
615 " current program counter without resetting any devices.\n"
616 #define HLP_STEP "*Commands Running_A_Simulated_Program Step_Execution"
617 "3Step Execution\n"
618 " The `STEP` command (*abbreviated* `S`) resumes execution at the current\n"
619 " PC for the number of instructions given by its argument. If no argument\n"
620 " is supplied, one instruction is executed.\n"
621 "4Switches\n"
622 "5`-T`\n"
623 " If the `STEP` command is invoked with the \"`-T`\" switch, the step\n"
624 " command will cause execution to run for *microseconds* rather than\n"
625 " instructions.\n"
626 #define HLP_NEXT "*Commands Running_A_Simulated_Program NEXT"
627 "3NEXT\n"
628 " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\n"
629 " for one instruction, attempting to execute *through* subroutine calls.\n"
630 " If the next instruction to be executed is *not* a subroutine call, then\n"
631 " one instruction is executed.\n"
632 #define HLP_BOOT "*Commands Running_A_Simulated_Program Booting_the_system"
633 "3Booting the system\n"
634 " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\n"
635 " the device and unit given by its argument. If no unit is supplied,\n"
636 " unit `0` is bootstrapped. The specified unit must be `ATTACH`'ed.\n\n"
637 " When booting Multics, the boot device should always be `iom0`.\n"
638 " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\n"
639 " into memory and the system will transfer control to the boot record.\n\n"
640 " **Example**\n\n"
641 "++; Boot Multics using iom0\n"
642 "++boot iom0\n\n"
643
644 "2Stopping The Simulator\n"
645 " The simulator runs until the simulated hardware encounters an error, or\n"
646 " until the user forces a stop condition.\n"
647 "3Simulator Detected Stop Conditions\n"
648 " These simulator-detected conditions stop simulation:\n\n"
649 "++- HALT instruction. If a HALT instruction is decoded, simulation stops.\n\n"
650 "++- I/O error. If an I/O error occurs during simulation of an I/O\n"
651 "+++operation, and the device stop-on-I/O-error flag is set, simulation\n"
652 "+++usually stops.\n\n"
653 "++- Processor condition. Certain processor conditions can stop\n"
654 "+++the simulation.\n"
655 "3User Specified Stop Conditions\n"
656 " Typing the interrupt character stops simulation. The interrupt character\n"
657 " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\n"
658 " set to `005` (`^E`).\n\n"
659
660 #define HLP_BREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
661 #define HLP_NOBREAK "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
662 "4Breakpoints\n"
663 " The simulator offers breakpoint capability for debugging. Users may define\n"
664 " breakpoints of different types, identified by letter (for example, `E`\n"
665 " for *execution*, `R` for *read*, `W` for *write*, etc).\n\n"
666 " Associated with each breakpoint is a count and, optionally, one or more\n"
667 " actions. Each time a breakpoint occurs, the associated count\n"
668 " is *decremented*. If the count is less than or equal to `0`, the breakpoint\n"
669 " occurs; otherwise, it is deferred. When the breakpoint occurs, any\n"
670 " optional actions are automatically executed.\n\n"
671 " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\n\n"
672 "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\n\n"
673 " If no type is specified, the default breakpoint type (`E`, *execution*) is\n"
674 " used. If no address range is specified, the current PC is used. As\n"
675 " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\n"
676 " range of addresses low-high, or a relative range of address/length.\n"
677
678 "5Displaying Breakpoints\n"
679 " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\n\n"
680 "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\n\n"
681 " Locations with breakpoints of the specified type are displayed.\n\n"
682 " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\n"
683 " commands which may be subsequently used to establish the same\n"
684 " breakpoint(s).\n\n"
685 "5Removing Breakpoints\n"
686 " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\n"
687 "5Examples\n"
688 " The following examples illustrate breakpoint usage:\n\n"
689 "++BREAK set E break at current PC\n"
690 "++BREAK -e 200 set E break at 200\n"
691 "++BREAK 2000/2[2] set E breaks at 2000,2001 with count = 2\n"
692 "++BREAK 100;EX AC;D MQ 0 set E break at 100 with actions EX AC and\n"
693 "+++++++++D MQ 0\n"
694 "++BREAK 100; delete action on break at 100\n\n"
695
696 "2Connecting and Disconnecting Devices\n"
697 " Units are simulated as files on the host file system. Before using any\n"
698 " simulated unit, the user must specify the file to be accessed by that unit.\n"
699 #define HLP_ATTACH "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
700 "3Attaching devices\n"
701 " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\n\n"
702 "++ATTACH <unit> <filename>\n\n"
703 " Some devices have more detailed or specific help available with:\n\n"
704 "++HELP <device> ATTACH\n\n"
705 "4Switches\n"
706 "5-n\n"
707 " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\n"
708 " file will be created when the filename specified does not exist, or an\n"
709 " existing file will have it's size truncated to zero, and an appropriate\n"
710 " message is printed.\n"
711 "5-e\n"
712 " If the file does not exist, and the \"`-e`\" switch *was not* specified,\n"
713 " a new file is created, and an appropriate message is printed. If\n"
714 " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\n"
715 " error message is printed.\n"
716 "5-r\n"
717 " If the \"`-r`\" switch is specified, or the file is write protected by\n"
718 " host operating system, `ATTACH` tries to open the file in read only mode.\n"
719 " If the file does not exist, or the unit does not support read only\n"
720 " operation, an error occurs. Input-only devices, such as card readers, or\n"
721 " storage devices with write locking switches, such as disks or tapes,\n"
722 " support read only operation - other devices do not. If a file is\n"
723 " attached read only, its contents can be examined but not modified.\n"
724 "5-q\n"
725 " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\n"
726 " or opening one read only (\"`-r`\"), the message announcing this fact\n"
727 " is suppressed.\n"
728 "5-f\n"
729 " For simulated magnetic tapes, the `ATTACH` command can specify the format\n"
730 " of the attached tape image file:\n\n"
731 "++ATTACH -f <tape_unit> <format> <filename>\n\n"
732 " * The currently supported magnetic tape image file formats are:\n\n"
733 " | | |\n"
734 " | ----------------:|:---------------------------------------------------- |\n"
735 " | \"**`SIMH`**\" | The **SIMH** / **DPS8M** native portable tape format |\n"
736 " | \"**`E11`**\" | The *D Bit* **Ersatz-11** simulator format |\n"
737 " | \"**`TPC`**\" | The **TPC** format (*used by _SIMH_ prior to V2.3*) |\n"
738 " | \"**`P7B`**\" | The **Paul Pierce** `7`-track tape archive format |\n\n"
739
740 " * The default tape format can also be specified with the `SET` command\n"
741 " prior to using the `ATTACH` command:\n\n"
742 "++SET <tape_unit> FORMAT=<format>\n"
743 "++ATTACH <tape_unit> <filename>\n\n"
744 " * The format of a currently attached tape image can be displayed with\n"
745 " the `SHOW FORMAT` command:\n\n"
746 "++SHOW <unit> FORMAT\n\n"
747 " **Examples**\n\n"
748 " The following example illustrates common `ATTACH` usage:\n"
749 "++; Associate the tape image file \"12.7MULTICS.tap\" with the tape0 unit\n"
750 "++; in read-only mode, where tape0 corresponds to the first tape device.\n"
751 "++ATTACH -r tape0 12.7MULTICS.tap\n\n"
752 "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\n"
753 "++; The disk0 unit corresponds to the first disk device.\n"
754 "++ATTACH disk0 root.dsk\n\n"
755
756 #define HLP_DETACH "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
757 "3Detaching devices\n"
758 " The `DETACH` (*abbreviation* `DET`) command breaks the association between\n"
759 " a unit and its backing file or device:\n\n"
760 "++DETACH ALL Detach all units\n"
761 "++DETACH <unit> Detach specified unit\n\n"
762 " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\n"
763 #define HLP_SET "*Commands SET"
764 "2SET\n"
765
766 #define HLP_SET_LOG "*Commands SET Logging"
767 "3Logging\n"
768 " Interactions with the simulator session can be recorded to a log file.\n\n"
769 "+SET LOG log_file Specify the log destination\n"
770 "++++++++ (STDOUT, DEBUG, or filename)\n"
771 "+SET NOLOG Disables any currently active logging\n"
772 "4Switches\n"
773 "5`-N`\n"
774 " By default, log output is written at the *end* of the specified log file.\n"
775 " A new log file can created if the \"`-N`\" switch is used on the command\n"
776 " line.\n\n"
777 "5`-B`\n"
778 " By default, log output is written in *text* mode. The log file can be\n"
779 " opened for *binary* mode writing if the \"`-B`\" switch is used on the\n"
780 " command line.\n"
781 #define HLP_SET_DEBUG "*Commands SET Debug_Messages"
782
783 "3Debug Messages\n"
784 "+SET DEBUG debug_file Specify the debug destination\n"
785 "++++++++ (STDOUT, STDERR, LOG, or filename)\n"
786 "+SET NODEBUG Disables any currently active debug output\n"
787 "4Switches\n"
788 " Debug message output contains a timestamp which indicates the number of\n"
789 " simulated instructions which have been executed prior to the debug event.\n\n"
790 " Debug message output can be enhanced to contain additional, potentially\n"
791 " useful information.\n\n\n"
792 " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\n"
793 "5-T\n"
794 " The \"`-T`\" switch causes debug output to contain a time of day displayed\n"
795 " as `hh:mm:ss.msec`.\n"
796 "5-A\n"
797 " The \"`-A`\" switch causes debug output to contain a time of day displayed\n"
798 " as `seconds.msec`.\n"
799 "5-R\n"
800 " The \"`-R`\" switch causes timing to be relative to the start of debugging.\n"
801 "5-P\n"
802 " The \"`-P`\" switch adds the output of the PC (program counter) to each\n"
803 " debug message.\n"
804 "5-N\n"
805 " The \"`-N`\" switch causes a new (empty) file to be written to.\n"
806 " (The default is to append to an existing debug log file).\n"
807 "5-D\n"
808 " The \"`-D`\" switch causes data blob output to also display the data\n"
809 " as **`RADIX-50`** characters.\n"
810 "5-E\n"
811 " The \"`-E`\" switch causes data blob output to also display the data\n"
812 " as \"**EBCDIC**\" characters.\n"
813
814 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
815 "3Environment Variables\n"
816 "+SET ENVIRONMENT NAME=val Set environment variable\n"
817 "+SET ENVIRONMENT NAME Clear environment variable\n"
818 #define HLP_SET_ON "*Commands SET Command_Status_Trap_Dispatching"
819 "3Command Status Trap Dispatching\n"
820 "+SET ON Enables error checking command execution\n"
821 "+SET NOON Disables error checking command execution\n"
822 "+SET ON INHERIT Enables inheritance of ON state and actions\n"
823 "+SET ON NOINHERIT Disables inheritance of ON state and actions\n"
824 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
825 "3Command Execution Display\n"
826 "+SET VERIFY Enables display of processed script commands\n"
827 "+SET VERBOSE Enables display of processed script commands\n"
828 "+SET NOVERIFY Disables display of processed script commands\n"
829 "+SET NOVERBOSE Disables display of processed script commands\n"
830 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
831 "3Command Error Status Display\n"
832 "+SET MESSAGE Re-enables display of script error messages\n"
833 "+SET NOMESSAGE Disables display of script error messages\n"
834 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
835 "3Local Operator Console\n"
836 "+SET LOCALOPC Enables local operator console\n"
837 "+SET NOLOCALOPC Disables local operator console\n"
838 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
839 "3Command Output Display\n"
840 "+SET QUIET Disables suppression of some messages\n"
841 "+SET NOQUIET Re-enables suppression of some messages\n"
842 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
843 "3Command Prompt\n"
844 "+SET PROMPT \"string\" Sets an alternate simulator prompt string\n"
845 "3Device and Unit Settings\n"
846 "+SET <dev> OCT|DEC|HEX Set device display radix\n"
847 "+SET <dev> ENABLED Enable device\n"
848 "+SET <dev> DISABLED Disable device\n"
849 "+SET <dev> DEBUG{=arg} Set device debug flags\n"
850 "+SET <dev> NODEBUG={arg} Clear device debug flags\n"
851 "+SET <dev> arg{,arg...} Set device parameters\n"
852 "+SET <unit> ENABLED Enable unit\n"
853 "+SET <unit> DISABLED Disable unit\n"
854 "+SET <unit> arg{,arg...} Set unit parameters\n"
855 "+HELP <dev> SET Displays any device specific SET commands\n"
856 " \n\n"
857 " See the Omnibus documentation for a complete SET command reference.\n"
858
859 #define HLP_SHOW "*Commands SHOW"
860 "2SHOW\n"
861 "+SH{OW} B{UILDINFO} Show build-time compilation information\n"
862 "+SH{OW} CL{OCKS} Show wall clock and timer information\n"
863 "+SH{OW} C{ONFIGURATION} Show simulator configuration\n"
864 "+SH{OW} D{EFAULT_BASE_SYSTEM} Show default base system script\n"
865 "+SH{OW} DEV{ICES} Show devices\n"
866 "+SH{OW} M{ODIFIERS} Show SET commands for all devices\n"
867 "+SH{OW} O{N} Show ON condition actions\n"
868 "+SH{OW} P{ROM} Show CPU ID PROM initialization data\n"
869 "+SH{OW} Q{UEUE} Show event queue\n"
870 "+SH{OW} S{HOW} Show SHOW commands for all devices\n"
871 "+SH{OW} T{IME} Show simulated timer\n"
872 "+SH{OW} VE{RSION} Show simulator version\n"
873 "+H{ELP} <dev> SHOW Show device-specific SHOW commands\n"
874 "+SH{OW} <dev> {arg,...} Show device parameters\n"
875 "+SH{OW} <dev> DEBUG Show device debug flags\n"
876 "+SH{OW} <dev> MODIFIERS Show device modifiers\n"
877 "+SH{OW} <dev> RADIX Show device display radix\n"
878 "+SH{OW} <dev> SHOW Show device SHOW commands\n"
879 "+SH{OW} <unit> {arg,...} Show unit parameters\n\n"
880 " See the Omnibus documentation for a complete SHOW command reference.\n\n"
881 #define HLP_SHOW_CONFIG "*Commands SHOW"
882 #define HLP_SHOW_DEVICES "*Commands SHOW"
883 #define HLP_SHOW_FEATURES "*Commands SHOW"
884 #define HLP_SHOW_QUEUE "*Commands SHOW"
885 #define HLP_SHOW_TIME "*Commands SHOW"
886 #define HLP_SHOW_MODIFIERS "*Commands SHOW"
887 #define HLP_SHOW_NAMES "*Commands SHOW"
888 #define HLP_SHOW_SHOW "*Commands SHOW"
889 #define HLP_SHOW_VERSION "*Commands SHOW"
890 #define HLP_SHOW_BUILDINFO "*Commands SHOW"
891 #define HLP_SHOW_PROM "*Commands SHOW"
892 #define HLP_SHOW_DBS "*Commands SHOW"
893 #define HLP_SHOW_DEFAULT "*Commands SHOW"
894 #define HLP_SHOW_CONSOLE "*Commands SHOW"
895 #define HLP_SHOW_REMOTE "*Commands SHOW"
896 #define HLP_SHOW_BREAK "*Commands SHOW"
897 #define HLP_SHOW_LOG "*Commands SHOW"
898 #define HLP_SHOW_DEBUG "*Commands SHOW"
899 #define HLP_SHOW_CLOCKS "*Commands SHOW"
900 #define HLP_SHOW_ON "*Commands SHOW"
901 #define HLP_SHOW_SEND "*Commands SHOW"
902 #define HLP_SHOW_EXPECT "*Commands SHOW"
903 #define HLP_HELP "*Commands HELP"
904
905 "2HELP\n"
906 "+H{ELP} Show this message\n"
907 "+H{ELP} <command> Show help for command\n"
908 "+H{ELP} <dev> Show help for device\n"
909 "+H{ELP} <dev> REGISTERS Show help for device register variables\n"
910 "+H{ELP} <dev> ATTACH Show help for device specific ATTACH command\n"
911 "+H{ELP} <dev> SET Show help for device specific SET commands\n"
912 "+H{ELP} <dev> SHOW Show help for device specific SHOW commands\n"
913 "+H{ELP} <dev> <command> Show help for device specific <command> command\n"
914
915 "2Altering The Simulated Configuration\n"
916 " The \"SET <device> DISABLED\" command removes a device from the configuration.\n"
917 " A `DISABLED` device is invisible to running programs. The device can still\n"
918 " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\n\n"
919 " The \"SET <device> ENABLED\" command restores a disabled device to a\n"
920 " configuration.\n\n"
921 " Most multi-unit devices allow units to be enabled or disabled:\n\n"
922 "++SET <unit> ENABLED\n"
923 "++SET <unit> DISABLED\n\n"
924 " When a unit is disabled, it will not be displayed by SHOW DEVICE.\n\n"
925
926 #define HLP_DO "*Commands Executing_Command_Files Processing_Command_Files"
927 "2Executing Command Files\n"
928 "3Processing Command Files\n"
929 " The simulator can invoke another script file with the \"`DO`\" command:\n\n"
930 "++DO <filename> {arguments...} execute commands in specified file\n\n"
931 " The \"`DO`\" command allows command files to contain substitutable\n"
932 " arguments. The string \"`%%n`\", where \"`n`\" is a number\n"
933 " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\n"
934 " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\n"
935 " The string \"`%%0`\" is replaced with \"<`filename`>\".\n The\n"
936 " sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\n"
937 " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\n"
938 " be enclosed in matching single or double quotation marks.\n\n"
939 " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\n"
940 " deep.\n\n"
941 "4Switches\n"
942 "5`-v`\n\n"
943 " If the switch \"`-v`\" is specified, commands in the command file are\n"
944 " echoed *before* they are executed.\n\n"
945 "5`-e`\n\n"
946 " If the switch \"`-e`\" is specified, command processing (including nested\n"
947 " command invocations) will be aborted if any command error is encountered.\n"
948 " (A simulation stop **never** aborts processing; use `ASSERT` to catch\n"
949 " unexpected stops.) Without this switch, all errors except `ASSERT` failures\n"
950 " will be ignored, and command processing will continue.\n\n"
951 "5`-o`\n\n"
952 " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\n"
953 " the calling command file will be inherited by the command file being\n"
954 " invoked.\n"
955 "5`-q`\n\n"
956 " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\n"
957 " enabled for the called command file, otherwise the *quiet mode* setting\n"
958 " is inherited from the calling context.\n"
959
960 #define HLP_GOTO "*Commands Executing_Command_Files GOTO"
961 "3GOTO\n"
962 " Commands in a command file execute in sequence until either an error\n"
963 " trap occurs (when a command completes with an error status), or when an\n"
964 " explict request is made to start command execution elsewhere with\n"
965 " the `GOTO` command:\n\n"
966 "++GOTO <label>\n\n"
967 " * Labels are lines in a command file which the first non-whitespace\n"
968 " character is a \"`:`\".\n"
969 " * The target of a `GOTO` is the first matching label in the current `DO`\n"
970 " command file which is encountered.\n\n"
971 " **Example**\n\n"
972 " The following example illustrates usage of the `GOTO` command (by\n"
973 " creating an infinite loop):\n\n"
974 "++:Label\n"
975 "++:: This is a loop.\n"
976 "++GOTO Label\n\n"
977 #define HLP_RETURN "*Commands Executing_Command_Files RETURN"
978
979 "3RETURN\n"
980 " The `RETURN` command causes the current procedure call to be restored to\n"
981 " the calling context, possibly returning a specific return status.\n"
982 " If no return status is specified, the return status from the last command\n"
983 " executed will be returned. The calling context may have `ON` traps defined\n"
984 " which may redirect command flow in that context.\n\n"
985 "++RETURN return from command file with last command status\n"
986 "++RETURN {-Q} <status> return from command file with specific status\n\n"
987 " * The status return can be any numeric value or one of the standard SCPE_\n"
988 " condition names.\n\n"
989 " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\n"
990 " status to be returned, but normal error status message printing to be\n"
991 " suppressed.\n\n"
992 " **Condition Names**\n\n"
993 " The available standard SCPE_ condition names and their meanings are:\n\n"
994 " | Name | Meaning | Name | Meaning |\n"
995 " | ------- | --------------------------------| ------- | ----------------------------------- |\n"
996 " | NXM | Address space exceeded | UNATT | Unit not attached |\n"
997 " | IOERR | I/O error | CSUM | Checksum error |\n"
998 " | FMT | Format error | NOATT | Unit not attachable |\n"
999 " | OPENERR | File open error | MEM | Memory exhausted |\n"
1000 " | ARG | Invalid argument | STEP | Step expired |\n"
1001 " | UNK | Unknown command | RO | Read only argument |\n"
1002 " | INCOMP | Command not completed | STOP | Simulation stopped |\n"
1003 " | EXIT | Goodbye | TTIERR | Console input I/O error |\n"
1004 " | TTOERR | Console output I/O error | EOF | End of file |\n"
1005 " | REL | Relocation error | NOPARAM | No settable parameters |\n"
1006 " | ALATT | Unit already attached | TIMER | Hardware timer error |\n"
1007 " | SIGERR | Signal handler setup error | TTYERR | Console terminal setup error |\n"
1008 " | NOFNC | Command not allowed | UDIS | Unit disabled |\n"
1009 " | NORO | Read only operation not allowed | INVSW | Invalid switch |\n"
1010 " | MISVAL | Missing value | 2FARG | Too few arguments |\n"
1011 " | 2MARG | Too many arguments | NXDEV | Non-existent device |\n"
1012 " | NXUN | Non-existent unit | NXREG | Non-existent register |\n"
1013 " | NXPAR | Non-existent parameter | NEST | Nested DO command limit exceeded |\n"
1014 " | IERR | Internal error | MTRLNT | Invalid magtape record length |\n"
1015 " | LOST | Console Telnet connection lost | TTMO | Console Telnet connection timed out |\n"
1016 " | STALL | Console Telnet output stall | AFAIL | Assertion failed |\n"
1017 " | INVREM | Invalid remote console command | | |\n"
1018 "\n\n"
1019 #define HLP_SHIFT "*Commands Executing_Command_Files Shift_Parameters"
1020 "3Shift Parameters\n"
1021 " Shift the command files positional parameters\n"
1022 #define HLP_CALL "*Commands Executing_Command_Files Call_a_subroutine"
1023 "3Call a subroutine\n"
1024 " Control can be transferred to a labeled subroutine using `CALL`.\n\n"
1025 " **Example**\n\n"
1026 "++CALL routine\n"
1027 "++BYE\n"
1028 "++\n"
1029 "++:routine\n"
1030 "++ECHO routine called\n"
1031 "++RETURN\n\n"
1032 #define HLP_ON "*Commands Executing_Command_Files ON"
1033 "3ON\n"
1034 " The `ON` command performs actions after a condition, or clears a condition.\n"
1035 "++ON <condition> <action> Perform action after condition\n"
1036 "++ON <condition> Clears action of specified condition\n"
1037 #define HLP_PROCEED "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1038 #define HLP_IGNORE "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1039
1040 "3PROCEED or IGNORE\n"
1041 " The `PROCEED` (or `IGNORE`) command does nothing. It is potentially\n"
1042 " useful as a placeholder for any `ON` action condition that should be\n"
1043 " explicitly ignored, allowing command file execution to continue without\n"
1044 " taking any specific action.\n"
1045 #define HLP_ECHO "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1046
1047 "3Displaying Arbitrary Text\n"
1048 " The `ECHO` command is a useful way of annotating command files. `ECHO`\n"
1049 " prints out its arguments to the console (and to any applicable log file):\n\n"
1050 "++ECHO <string> Output string to console\n\n"
1051 " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\n"
1052 " This may be used to provide spacing for console messages or log file\n"
1053 " output.\n"
1054
1055 #define HLP_ASSERT "*Commands Executing_Command_Files Testing_Assertions"
1056 "3Testing Assertions\n"
1057 " The `ASSERT` command tests a simulator state condition and halts command\n"
1058 " file execution if the condition is false:\n\n"
1059 "++ASSERT <Simulator State Expressions>\n\n"
1060 " * If the indicated expression evaluates to false, the command completes\n"
1061 " with an `AFAIL` condition. By default, when a command file encounters a\n"
1062 " command which returns the `AFAIL` condition, it will exit the running\n"
1063 " command file with the `AFAIL` status to the calling command file. This\n"
1064 " behavior can be changed with the `ON` command as well as switches to the\n"
1065 " invoking `DO` command.\n\n"
1066 " **Examples**\n\n"
1067 " The command file below might be used to bootstrap a hypothetical system\n"
1068 " that halts after the initial load from disk. The `ASSERT` command can then\n"
1069 " be used to confirm that the load completed successfully by examining the\n"
1070 " CPU's \"`A`\" register for the expected value:\n\n"
1071 "++; Example INI file\n"
1072 "++BOOT\n"
1073 "++; A register contains error code; 0 = good boot\n"
1074 "++ASSERT A=0\n"
1075 "++RUN\n\n"
1076
1077 " * In the above example, if the \"`A`\" register is *not* `0`,\n"
1078 " the \"`ASSERT A=0`\" command will be displayed to the user, and the\n"
1079 " command file will be aborted with an \"`Assertion failed`\" message.\n"
1080 " Otherwise, the command file will continue to bring up the system.\n\n"
1081 " * See the **`IF`** command documentation for more information and details\n"
1082 " regarding simulator state expressions.\n\n"
1083 #define HLP_IF "*Commands Executing_Command_Files Testing_Conditions"
1084 "3Testing Conditions\n"
1085 " The `IF` command tests a simulator state condition and executes additional\n"
1086 " commands if the condition is true:\n\n"
1087 "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\n\n"
1088 " **Examples**\n\n"
1089 " The command file below might be used to bootstrap a hypothetical system\n"
1090 " that halts after the initial load from disk. The `IF` command can then\n"
1091 " be used to confirm that the load completed successfully by examining the\n"
1092 " CPU's \"`A`\" register for an expected value:\n\n"
1093 "++; Example INI file\n"
1094 "++BOOT\n"
1095 "++; A register contains error code; 0 = good boot\n"
1096 "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\n"
1097 "++RUN\n\n"
1098
1099 " * In the above example, if the \"`A`\" register is *not* `0`, the\n"
1100 " message \"`Boot failed - Failure Code `\" will be displayed, the contents\n"
1101 " of the \"`A`\" register will be displayed, and the command file will be\n"
1102 " aborted with an \"`Assertion failed`\" message. Otherwise, the command\n"
1103 " file will continue to bring up the system.\n"
1104 "4Conditional Expressions\n"
1105 " The `IF` and `ASSERT` commands evaluate the following two different forms\n"
1106 " of conditional expressions.\n\n"
1107 "5Simulator State Expressions\n"
1108 " \n \n"
1109 " The values of simulator registers can be evaluated with:\n\n"
1110 "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n"
1111 " * If \"<`dev`>\" is not specified, `CPU` is assumed. \"<`reg`>\" is a\n"
1112 " register belonging to the indicated device.\n"
1113 " * The \"<`addr`>\" is an address in the address space of the indicated\n"
1114 " device.\n"
1115 " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\n"
1116 " the same as those used for \"search specifiers\" by the `EXAMINE` and\n"
1117 " `DEPOSIT` commands.\n"
1118 " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\n"
1119 " not in the radix for the device when referencing a register; when an\n"
1120 " address is referenced the device radix is used as the default.\n\n"
1121 " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\n"
1122 " register value is first altered as indicated. The result is then compared\n"
1123 " to the \"<`value`>\" via the \"<`conditional-op`>\".\n"
1124 " * * If the result is *true*, the command(s) are executed before proceeding\n"
1125 " to the next line in the command file.\n"
1126 " * * If the result is *false*, the next command in the command file is\n"
1127 " processed.\n\n"
1128 "5String Comparison Expressions\n"
1129 " \n \n"
1130 " String Values can be compared with:\n\n"
1131 "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\n\n"
1132 " * The \"`-i`\" switch, if present, causes a comparison to be case\n"
1133 " insensitive.\n"
1134 " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\n"
1135 " values which may have environment variables substituted as desired.\n"
1136 " * The \"<`compare-op`>\" may be one of:\n\n"
1137 " | | |\n"
1138 " | --------------:|:---------------------- |\n"
1139 " | \"**`==`**\" | equal |\n"
1140 " | \"**`EQU`**\" | equal |\n"
1141 " | \"**`!=`**\" | not equal |\n"
1142 " | \"**`NEQ`**\" | not equal |\n"
1143 " | \"**<**\" | less than |\n"
1144 " | \"**`LSS`**\" | less than |\n"
1145 " | \"**<=**\" | less than or equal |\n"
1146 " | \"**`LEQ`**\" | less than or equal |\n"
1147 " | \"**>**\" | greater than |\n"
1148 " | \"**`GTR`**\" | greater than |\n"
1149 " | \"**>=**\" | greater than or equal |\n"
1150 " | \"**`GEQ`**\" | greater than or equal |\n"
1151 " * **NOTE**: Comparisons are *generic*. This means that if\n"
1152 " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\n"
1153 " digits, then the strings are converted to numbers and a numeric\n"
1154 " comparison is performed. For example, the comparison\n"
1155 " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\n"
1156
1157 #define HLP_EXIT "*Commands Exiting_the_Simulator"
1158 "2Exiting the Simulator\n"
1159 " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\n"
1160 " returning control to the host operating system.\n"
1161
1162 #define HLP_SPAWN "*Commands Executing_System_Commands"
1163 "2Executing System Commands\n"
1164 " * The simulator can execute host operating system commands with\n"
1165 " the \"`!`\" (*spawn*) command.\n\n"
1166 " | | |\n"
1167 " |:----------------------- |:------------------------------------------- |\n"
1168 " | \"**`!`**\" | Spawn the hosts default command interpreter |\n"
1169 " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\n\n"
1170 " * **NOTE**: The *exit status* from the command which was executed is set\n"
1171 " as the *command completion status* for the \"`!`\" command. This may\n"
1172 " influence any enabled `ON` condition traps.\n" ;
1173
1174
1175 static CTAB cmd_table[] = {
1176 { "RESET", &reset_cmd, 0, HLP_RESET },
1177 { "EXAMINE", &exdep_cmd, EX_E, HLP_EXAMINE },
1178 { "IEXAMINE", &exdep_cmd, EX_E+EX_I, HLP_IEXAMINE },
1179 { "DEPOSIT", &exdep_cmd, EX_D, HLP_DEPOSIT },
1180 { "IDEPOSIT", &exdep_cmd, EX_D+EX_I, HLP_IDEPOSIT },
1181 { "EVALUATE", &eval_cmd, 0, HLP_EVALUATE },
1182 { "RUN", &run_cmd, RU_RUN, HLP_RUN, NULL, &run_cmd_message },
1183 { "GO", &run_cmd, RU_GO, HLP_GO, NULL, &run_cmd_message },
1184 { "STEP", &run_cmd, RU_STEP, HLP_STEP, NULL, &run_cmd_message },
1185 { "NEXT", &run_cmd, RU_NEXT, HLP_NEXT, NULL, &run_cmd_message },
1186 { "CONTINUE", &run_cmd, RU_CONT, HLP_CONTINUE, NULL, &run_cmd_message },
1187 { "BOOT", &run_cmd, RU_BOOT, HLP_BOOT, NULL, &run_cmd_message },
1188 { "BREAK", &brk_cmd, SSH_ST, HLP_BREAK },
1189 { "NOBREAK", &brk_cmd, SSH_CL, HLP_NOBREAK },
1190 { "ATTACH", &attach_cmd, 0, HLP_ATTACH },
1191 { "DETACH", &detach_cmd, 0, HLP_DETACH },
1192 { "EXIT", &exit_cmd, 0, HLP_EXIT },
1193 { "QUIT", &exit_cmd, 0, NULL },
1194 { "BYE", &exit_cmd, 0, NULL },
1195 { "SET", &set_cmd, 0, HLP_SET },
1196 { "SHOW", &show_cmd, 0, HLP_SHOW },
1197 { "DO", &do_cmd, 1, HLP_DO },
1198 { "GOTO", &goto_cmd, 1, HLP_GOTO },
1199 { "RETURN", &return_cmd, 0, HLP_RETURN },
1200 { "SHIFT", &shift_cmd, 0, HLP_SHIFT },
1201 { "CALL", &call_cmd, 0, HLP_CALL },
1202 { "ON", &on_cmd, 0, HLP_ON },
1203 { "IF", &assert_cmd, 0, HLP_IF },
1204 { "PROCEED", &noop_cmd, 0, HLP_PROCEED },
1205 { "IGNORE", &noop_cmd, 0, HLP_IGNORE },
1206 { "ECHO", &echo_cmd, 0, HLP_ECHO },
1207 { "ASSERT", &assert_cmd, 1, HLP_ASSERT },
1208 { "SEND", &send_cmd, 0 },
1209 { "EXPECT", &expect_cmd, 1 },
1210 { "NOEXPECT", &expect_cmd, 0 },
1211 { "!", &spawn_cmd, 0, HLP_SPAWN },
1212 { "HELP", &help_cmd, 0, HLP_HELP },
1213 { NULL, NULL, 0 }
1214 };
1215
1216 static CTAB set_glob_tab[] = {
1217 { "CONSOLE", &sim_set_console, 0 },
1218 { "REMOTE", &sim_set_remote_console, 0 },
1219 { "BREAK", &brk_cmd, SSH_ST },
1220 { "NOBREAK", &brk_cmd, SSH_CL },
1221 { "TELNET", &sim_set_telnet, 0 },
1222 { "NOTELNET", &sim_set_notelnet, 0 },
1223 { "LOG", &sim_set_logon, 0, HLP_SET_LOG },
1224 { "NOLOG", &sim_set_logoff, 0, HLP_SET_LOG },
1225 { "DEBUG", &sim_set_debon, 0, HLP_SET_DEBUG },
1226 { "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG },
1227 { "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON },
1228 { "ON", &set_on, 1, HLP_SET_ON },
1229 { "NOON", &set_on, 0, HLP_SET_ON },
1230 { "VERIFY", &set_verify, 1, HLP_SET_VERIFY },
1231 { "VERBOSE", &set_verify, 1, HLP_SET_VERIFY },
1232 { "NOVERIFY", &set_verify, 0, HLP_SET_VERIFY },
1233 { "NOVERBOSE", &set_verify, 0, HLP_SET_VERIFY },
1234 { "MESSAGE", &set_message, 1, HLP_SET_MESSAGE },
1235 { "NOMESSAGE", &set_message, 0, HLP_SET_MESSAGE },
1236 { "QUIET", &set_quiet, 1, HLP_SET_QUIET },
1237 { "NOQUIET", &set_quiet, 0, HLP_SET_QUIET },
1238 { "LOCALOPC", &set_localopc, 1, HLP_SET_LOCALOPC },
1239 { "NOLOCALOPC", &set_localopc, 0, HLP_SET_LOCALOPC },
1240 { "PROMPT", &set_prompt, 0, HLP_SET_PROMPT },
1241 { NULL, NULL, 0 }
1242 };
1243
1244 static C1TAB set_dev_tab[] = {
1245 { "OCTAL", &set_dev_radix, 8 },
1246 { "DECIMAL", &set_dev_radix, 10 },
1247 { "HEX", &set_dev_radix, 16 },
1248 { "ENABLED", &set_dev_enbdis, 1 },
1249 { "DISABLED", &set_dev_enbdis, 0 },
1250 { "DEBUG", &set_dev_debug, 1 },
1251 { "NODEBUG", &set_dev_debug, 0 },
1252 { NULL, NULL, 0 }
1253 };
1254
1255 static C1TAB set_unit_tab[] = {
1256 { "ENABLED", &set_unit_enbdis, 1 },
1257 { "DISABLED", &set_unit_enbdis, 0 },
1258 { NULL, NULL, 0 }
1259 };
1260
1261 static SHTAB show_glob_tab[] = {
1262 { "CONFIGURATION", &show_config, 0, HLP_SHOW_CONFIG },
1263 { "DEFAULT_BASE_SYSTEM_SCRIPT", &show_default_base_system_script, 0, HLP_SHOW_DBS },
1264 { "DEVICES", &show_config, 1, HLP_SHOW_DEVICES },
1265 { "FEATURES", &show_config, 2, HLP_SHOW_FEATURES },
1266 { "QUEUE", &show_queue, 0, HLP_SHOW_QUEUE },
1267 { "TIME", &show_time, 0, HLP_SHOW_TIME },
1268 { "MODIFIERS", &show_mod_names, 0, HLP_SHOW_MODIFIERS },
1269 { "NAMES", &show_log_names, 0, HLP_SHOW_NAMES },
1270 { "SHOW", &show_show_commands, 0, HLP_SHOW_SHOW },
1271 { "VERSION", &show_version, 1, HLP_SHOW_VERSION },
1272 { "BUILDINFO", &show_buildinfo, 1, HLP_SHOW_BUILDINFO },
1273 { "PROM", &show_prom, 0, HLP_SHOW_PROM },
1274 { "CONSOLE", &sim_show_console, 0, HLP_SHOW_CONSOLE },
1275 { "REMOTE", &sim_show_remote_console, 0, HLP_SHOW_REMOTE },
1276 { "BREAK", &show_break, 0, HLP_SHOW_BREAK },
1277 { "LOG", &sim_show_log, 0, HLP_SHOW_LOG },
1278 { "TELNET", &sim_show_telnet, 0 },
1279 { "DEBUG", &sim_show_debug, 0, HLP_SHOW_DEBUG },
1280 { "CLOCKS", &sim_show_timers, 0, HLP_SHOW_CLOCKS },
1281 { "SEND", &sim_show_send, 0, HLP_SHOW_SEND },
1282 { "EXPECT", &sim_show_expect, 0, HLP_SHOW_EXPECT },
1283 { "ON", &show_on, 0, HLP_SHOW_ON },
1284 { NULL, NULL, 0 }
1285 };
1286
1287 static SHTAB show_dev_tab[] = {
1288 { "RADIX", &show_dev_radix, 0 },
1289 { "DEBUG", &show_dev_debug, 0 },
1290 { "MODIFIERS", &show_dev_modifiers, 0 },
1291 { "NAMES", &show_dev_logicals, 0 },
1292 { "SHOW", &show_dev_show_commands, 0 },
1293 { NULL, NULL, 0 }
1294 };
1295
1296 static SHTAB show_unit_tab[] = {
1297 { NULL, NULL, 0 }
1298 };
1299
1300 #if defined(_WIN32)
1301 static
1302 int setenv(const char *envname, const char *envval, int overwrite)
1303 {
1304 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1305 int r;
1306
1307 sprintf(envstr, "%s=%s", envname, envval);
1308 r = _putenv(envstr);
1309 FREE(envstr);
1310 return r;
1311 }
1312
1313 static
1314 int unsetenv(const char *envname)
1315 {
1316 setenv(envname, "", 1);
1317 return 0;
1318 }
1319 #endif
1320
1321
1322
1323 #ifdef TESTING
1324 void *
1325 trealloc(void *ptr, size_t size)
1326 {
1327 void *r = realloc(ptr, size);
1328
1329 if (r != ptr) return r;
1330 else if (r)
1331 {
1332 void *rm = malloc(size);
1333 if (!rm)
1334 {
1335 (void)fprintf(
1336 stderr,
1337 "\rFATAL: Out of memory?! Aborting at %s[%s:%d]\r\n",
1338 __func__, __FILE__, __LINE__);
1339 # if defined(USE_BACKTRACE)
1340 # ifdef SIGUSR2
1341 (void)raise(SIGUSR2);
1342
1343 # endif
1344 # endif
1345 abort();
1346
1347 }
1348 memcpy(rm, r, size);
1349 FREE(r);
1350 return rm;
1351 }
1352 else return r;
1353 }
1354 #endif
1355
1356 #ifdef TESTING
1357 # ifdef USE_TREALLOC
1358 # undef realloc
1359 # define realloc trealloc
1360 # endif
1361 #endif
1362
1363 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1364
1365
1366
1367 #if defined(__APPLE__)
1368 int processIsTranslated(void)
1369 {
1370 int ret = 0;
1371 size_t size = sizeof(ret);
1372 if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
1373 if (errno == ENOENT)
1374 return 0;
1375 return -1; }
1376 return ret;
1377 }
1378 #endif
1379
1380
1381
1382 char *strremove(char *str, const char *sub)
1383 {
1384 char *p, *q, *r;
1385 if (*sub && (q = r = strstr(str, sub)) != NULL) {
1386 size_t len = strlen(sub);
1387 while ((r = strstr(p = r + len, sub)) != NULL) {
1388 while (p < r)
1389 *q++ = *p++;
1390 }
1391 while ((*q++ = *p++) != '\0')
1392 continue;
1393 }
1394 return str;
1395 }
1396
1397
1398
1399 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
1400 {
1401 while (*str_untrimmed != '\0') {
1402 if(!isspace((unsigned char)*str_untrimmed)) {
1403 *str_trimmed = (char)*str_untrimmed;
1404 str_trimmed++;
1405 }
1406 str_untrimmed++;
1407 }
1408 *str_trimmed = '\0';
1409 }
1410
1411 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1412 void allowCores(void)
1413 {
1414 int ret;
1415 struct rlimit limit;
1416 # ifdef RLIMIT_CORE
1417 ret = getrlimit(RLIMIT_CORE, &limit);
1418 (void)ret;
1419 # ifdef TESTING
1420 if (ret != 0)
1421 {
1422 sim_warn ("Failed to query core dump configuration.");
1423 return;
1424 }
1425 # endif
1426 limit.rlim_cur = limit.rlim_max;
1427 ret = setrlimit(RLIMIT_CORE, &limit);
1428 # ifdef TESTING
1429 if (ret != 0)
1430 {
1431 sim_warn ("Failed to enable unlimited core dumps.");
1432 return;
1433 }
1434 # endif
1435 # else
1436 # ifdef TESTING
1437 sim_warn ("Unable to query core dump configuration.");
1438 # endif
1439 # endif
1440 return;
1441 }
1442 #endif
1443
1444 #ifdef USE_DUMA
1445 void CleanDUMA(void)
1446 {
1447 (void)fflush(stdout);
1448 DUMA_CHECKALL();
1449 (void)fflush(stderr);
1450 }
1451 # undef USE_DUMA
1452 # define USE_DUMA 1
1453 #endif
1454
1455 #ifndef SIG_SETMASK
1456 # undef USE_BACKTRACE
1457 #endif
1458
1459 #ifdef PERF_STRIP
1460 # undef USE_BACKTRACE
1461 #endif
1462
1463 #ifdef USE_BACKTRACE
1464 # include <backtrace.h>
1465 # include <backtrace-supported.h>
1466 # define BACKTRACE_SKIP 1
1467 # define BACKTRACE_MAIN "main"
1468 # undef USE_BACKTRACE
1469 # define USE_BACKTRACE 1
1470 #endif
1471
1472 #ifdef BACKTRACE_SUPPORTED
1473 # ifdef BACKTRACE_SUPPORTS_THREADS
1474 # if !( BACKTRACE_SUPPORTED )
1475 # undef USE_BACKTRACE
1476 # endif
1477 # else
1478 # undef USE_BACKTRACE
1479 # endif
1480 #else
1481 # undef USE_BACKTRACE
1482 #endif
1483
1484 #ifdef USE_BACKTRACE
1485 # ifdef BACKTRACE_SUPPORTED
1486 # include "backtrace_func.c"
1487 # endif
1488 #endif
1489
1490
1491
1492 #ifndef PERF_STRIP
1493 int main (int argc, char *argv[])
1494 {
1495 char *cptr, *cptr2;
1496 char nbuf[PATH_MAX + 7];
1497 char cbuf[4*CBUFSIZE];
1498 char **targv = NULL;
1499 # ifdef USE_BACKTRACE
1500 # ifdef BACKTRACE_SUPPORTED
1501 # ifdef _INC_BACKTRACE_FUNC
1502 bt_pid = (long)getpid();
1503 (void)bt_pid;
1504 # endif
1505 # endif
1506 # endif
1507 int32 i, sw;
1508 t_bool lookswitch;
1509 t_stat stat;
1510
1511 # ifdef __MINGW32__
1512 # undef IS_WINDOWS
1513 # define IS_WINDOWS 1
1514 # ifndef NEED_CONSOLE_SETUP
1515 # define NEED_CONSOLE_SETUP
1516 # endif
1517 # endif
1518
1519 # ifdef CROSS_MINGW32
1520 # undef IS_WINDOWS
1521 # define IS_WINDOWS 1
1522 # ifndef NEED_CONSOLE_SETUP
1523 # define NEED_CONSOLE_SETUP
1524 # endif
1525 # endif
1526
1527 # ifdef __MINGW64__
1528 # undef IS_WINDOWS
1529 # define IS_WINDOWS 1
1530 # ifndef NEED_CONSOLE_SETUP
1531 # define NEED_CONSOLE_SETUP
1532 # endif
1533 # endif
1534
1535 # ifdef CROSS_MINGW64
1536 # undef IS_WINDOWS
1537 # define IS_WINDOWS 1
1538 # ifndef NEED_CONSOLE_SETUP
1539 # define NEED_CONSOLE_SETUP
1540 # endif
1541 # endif
1542
1543 # ifdef __CYGWIN__
1544 # ifdef IS_WINDOWS
1545 # undef IS_WINDOWS
1546 # endif
1547 # endif
1548
1549 # ifdef USE_DUMA
1550 # ifdef DUMA_EXPLICIT_INIT
1551 duma_init();
1552 (void)fflush(stderr);
1553 # endif
1554 # ifdef DUMA_MIN_ALIGNMENT
1555 # if DUMA_MIN_ALIGNMENT > 0
1556 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1557 # endif
1558 # endif
1559 DUMA_SET_FILL(0x2E);
1560 (void)fflush(stderr);
1561 (void)atexit(CleanDUMA);
1562 # endif
1563
1564 # ifdef USE_BACKTRACE
1565 # ifdef BACKTRACE_SUPPORTED
1566 # include "backtrace_main.c"
1567 # endif
1568 # endif
1569
1570 setlocale(LC_NUMERIC, "");
1571
1572 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1573 # include <windows.h>
1574 # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
1575 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1576 # endif
1577 # endif
1578
1579 # ifdef NEED_CONSOLE_SETUP
1580 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1581 if (handle != INVALID_HANDLE_VALUE)
1582 {
1583 DWORD mode = 0;
1584 if (GetConsoleMode(handle, &mode))
1585 {
1586 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1587 SetConsoleMode(handle, mode);
1588 }
1589 }
1590 puts ("\e[0m");
1591 # endif
1592
1593 # ifdef __HAIKU__
1594 (void)disable_debugger(1);
1595 # endif
1596
1597
1598
1599 # ifdef __clang_analyzer__
1600 fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\n");
1601 return 1;
1602 # endif
1603
1604 if (argc == 0) {
1605 fprintf (stderr, "Error: main() called directly!\n");
1606 return 1;
1607 }
1608
1609
1610 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1611 allowCores();
1612 # endif
1613
1614 int testEndian = decContextTestEndian();
1615 if (testEndian != 0) {
1616 if (testEndian == 1) {
1617 fprintf (stderr,
1618 "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\n");
1619 return 1;
1620 }
1621 if (testEndian == -1) {
1622 fprintf (stderr,
1623 "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\n");
1624 return 1;
1625 }
1626 fprintf (stderr,
1627 "Error: Unable to determine system byte order; aborting.\n");
1628 return 1;
1629 }
1630 # ifdef NEED_128
1631 test_math128();
1632 # endif
1633
1634
1635 # ifdef __DISPATCH_H_
1636 # if defined(__INTEL_COMPILER) || \
1637 defined(__INTEL_CLANG_COMPILER) || \
1638 defined(__INTEL_LLVM_COMPILER) || \
1639 defined(INTEL_MKL_VERSION) || \
1640 defined(__INTEL_MKL__)
1641 (void)agner_compiler_patch();
1642 # endif
1643 # endif
1644
1645
1646 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1647 if (!targv)
1648 {
1649 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1650 __func__, __FILE__, __LINE__);
1651 # if defined(USE_BACKTRACE)
1652 # ifdef SIGUSR2
1653 (void)raise(SIGUSR2);
1654
1655 # endif
1656 # endif
1657 abort();
1658 }
1659 for (i=0; i<argc; i++)
1660 targv[i] = argv[i];
1661 argv = targv;
1662
1663
1664 set_prompt (0, "sim>");
1665 *cbuf = 0;
1666 sim_switches = 0;
1667 lookswitch = TRUE;
1668 stdnul = fopen(NULL_DEVICE,"wb");
1669
1670
1671 for (i = 1; i < argc; i++) {
1672 if (argv[i] == NULL)
1673 continue;
1674
1675
1676 int onlyvers = strcmp(argv[i], "--version");
1677 if (onlyvers == 0) {
1678 # ifdef VER_H_GIT_VERSION
1679 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1680 # if VER_H_GIT_PATCH_INT < 1
1681 fprintf (stdout, "%s simulator %s\n",
1682 sim_name, VER_H_GIT_VERSION);
1683 # else
1684 fprintf (stdout, "%s simulator %s+%s\n",
1685 sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1686 # endif
1687 # else
1688 fprintf (stdout, "%s simulator %s\n",
1689 sim_name, VER_H_GIT_VERSION);
1690 # endif
1691 # else
1692 fprintf (stdout, "%s simulator\n", sim_name);
1693 # endif
1694 FREE (targv);
1695 return 0;
1696 }
1697
1698
1699 int longhelp = strcmp(argv[i], "--help");
1700 int shorthelp = strcmp(argv[i], "-h");
1701 if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
1702 if (longhelp == 0 || shorthelp == 0) {
1703 # ifdef VER_H_GIT_VERSION
1704 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1705 # if VER_H_GIT_PATCH_INT < 1
1706 fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1707 # else
1708 fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1709 # endif
1710 # else
1711 fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1712 # endif
1713 # else
1714 fprintf (stdout, "%s simulator", sim_name);
1715 # endif
1716 fprintf (stdout, "\n");
1717 fprintf (stdout, "\n USAGE: %s { [ SWITCHES ] ... } { < SCRIPT > }", argv[0]);
1718 fprintf (stdout, "\n");
1719 fprintf (stdout, "\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
1720 fprintf (stdout, "\n");
1721 fprintf (stdout, "\n Switches:");
1722 fprintf (stdout, "\n -e, -E Aborts script processing immediately upon any error");
1723 fprintf (stdout, "\n -h, -H, --help Prints only this informational help text and exit");
1724 fprintf (stdout, "\n -k, -K Disables all support for exclusive file locking");
1725 fprintf (stdout, "\n -l, -L Reports but ignores all exclusive file locking errors");
1726 fprintf (stdout, "\n -o, -O Makes scripting ON conditions and actions inheritable");
1727 fprintf (stdout, "\n -q, -Q Disables printing of non-fatal informational messages");
1728 fprintf (stdout, "\n -r, -R Enables an unlinked ephemeral system state file");
1729 fprintf (stdout, "\n -s, -S Enables a randomized persistent system state file");
1730 fprintf (stdout, "\n -t, -T Disables fsync and creation/usage of system state file");
1731 fprintf (stdout, "\n -v, -V Prints commands read from script file before execution");
1732 fprintf (stdout, "\n --version Prints only the simulator identification text and exit");
1733 fprintf (stdout, "\n");
1734 # ifdef USE_DUMA
1735 nodist++;
1736 # endif
1737 if (!nodist) {
1738 fprintf (stdout, "\n This software is made available under the terms of the ICU License, version");
1739 fprintf (stdout, "\n 1.8.1 or later. For complete details, see the \"LICENSE.md\" file included");
1740 fprintf (stdout, "\n with the software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\n");
1741 }
1742 else
1743 {
1744 fprintf (stdout, "\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
1745 }
1746 fprintf (stdout, "\n");
1747 FREE(argv);
1748 return 0;
1749 }
1750
1751 if ((*argv[i] == '-') && lookswitch) {
1752 if ((sw = get_switches (argv[i])) < 0) {
1753 fprintf (stderr, "Invalid switch \"%s\".\nTry \"%s -h\" for help.\n", argv[i], argv[0]);
1754 FREE(argv);
1755 return 1;
1756 }
1757 sim_switches = sim_switches | sw;
1758 }
1759
1760 else {
1761 if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
1762 fprintf (stderr, "Argument string too long\n");
1763 FREE(argv);
1764 return 1;
1765 }
1766 if (*cbuf)
1767 strcat (cbuf, " ");
1768 sprintf(&cbuf[strlen(cbuf)], "%s%s%s", strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : "");
1769 lookswitch = FALSE;
1770 }
1771 }
1772 sim_nolock = sim_switches & SWMASK ('K');
1773 sim_iglock = sim_switches & SWMASK ('L');
1774 sim_randompst = sim_switches & SWMASK ('S');
1775 sim_quiet = sim_switches & SWMASK ('Q');
1776 sim_randstate = sim_switches & SWMASK ('R');
1777 if (sim_randompst) sim_randstate = 1;
1778 sim_nostate = sim_switches & SWMASK ('T');
1779 if (sim_nostate)
1780 {
1781 sim_randompst = 0;
1782 sim_randstate = 0;
1783 }
1784 sim_on_inherit = sim_switches & SWMASK ('O');
1785
1786 sim_init_sock ();
1787 if (sim_dflt_dev == NULL)
1788 sim_dflt_dev = sim_devices[0];
1789 if (sim_vm_init != NULL)
1790 (*sim_vm_init)();
1791 sim_finit ();
1792 for (i = 0; cmd_table[i].name; i++) {
1793 size_t alias_len = strlen (cmd_table[i].name);
1794 char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
1795 if (!cmd_name)
1796 {
1797 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1798 __func__, __FILE__, __LINE__);
1799 # if defined(USE_BACKTRACE)
1800 # ifdef SIGUSR2
1801 (void)raise(SIGUSR2);
1802
1803 # endif
1804 # endif
1805 abort();
1806 }
1807
1808 strcpy (cmd_name, cmd_table[i].name);
1809 while (alias_len > 1) {
1810 cmd_name[alias_len] = '\0';
1811 --alias_len;
1812 if (getenv (cmd_name))
1813 unsetenv (cmd_name);
1814 }
1815 FREE (cmd_name);
1816 }
1817 stop_cpu = 0;
1818 sim_interval = 0;
1819 sim_time = sim_rtime = 0;
1820 noqueue_time = 0;
1821 sim_clock_queue = QUEUE_LIST_END;
1822 sim_is_running = 0;
1823 sim_log = NULL;
1824 if (sim_emax <= 0)
1825 sim_emax = 1;
1826 sim_timer_init ();
1827
1828 if ((stat = sim_ttinit ()) != SCPE_OK) {
1829 fprintf (stderr, "Fatal terminal initialization error\n%s\n",
1830 sim_error_text (stat));
1831 FREE(argv);
1832 return 1;
1833 }
1834 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
1835 fprintf (stderr, "Unable to allocate examine buffer\n");
1836 FREE(argv);
1837 return 1;
1838 };
1839 if ((stat = reset_all_p (0)) != SCPE_OK) {
1840 fprintf (stderr, "Fatal simulator initialization error\n%s\n",
1841 sim_error_text (stat));
1842 FREE(argv);
1843 return 1;
1844 }
1845 if ((stat = sim_brk_init ()) != SCPE_OK) {
1846 fprintf (stderr, "Fatal breakpoint table initialization error\n%s\n",
1847 sim_error_text (stat));
1848 FREE(argv);
1849 return 1;
1850 }
1851 if (!sim_quiet) {
1852 printf ("\n");
1853 show_version (stdout, NULL, NULL, 0, NULL);
1854 }
1855
1856 cptr = getenv("HOME");
1857 if (cptr == NULL) {
1858 cptr = getenv("HOMEPATH");
1859 cptr2 = getenv("HOMEDRIVE");
1860 }
1861 else
1862 cptr2 = NULL;
1863 (void)cptr2;
1864 if ( (*cbuf) && (strcmp(cbuf, "")) )
1865 stat = do_cmd (0, cbuf);
1866 else if (*argv[0]) {
1867 char *np;
1868 nbuf[0] = '"';
1869 stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;
1870 if (stat == SCPE_OPENERR) {
1871 np = strrchr (nbuf, '/');
1872 if (np == NULL)
1873 np = strrchr (nbuf, '\\');
1874 if (np != NULL) {
1875 *np = '"';
1876 stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;
1877 }
1878 }
1879 }
1880
1881 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
1882
1883 if (sim_vm_exit != NULL)
1884 (*sim_vm_exit)();
1885
1886 detach_all (0, TRUE);
1887 sim_set_deboff (0, NULL);
1888 sim_set_logoff (0, NULL);
1889 sim_set_notelnet (0, NULL);
1890 sim_ttclose ();
1891 sim_cleanup_sock ();
1892 fclose (stdnul);
1893 FREE (targv);
1894 FREE (sim_prompt);
1895 FREE (sim_eval);
1896 FREE (sim_internal_devices);
1897 FREE (sim_brk_tab);
1898 FREE (sim_staba.comp);
1899 FREE (sim_staba.mask);
1900 FREE (sim_stabr.comp);
1901 FREE (sim_stabr.mask);
1902 return 0;
1903 }
1904 #endif
1905
1906 t_stat process_stdin_commands (t_stat stat, char *argv[])
1907 {
1908 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
1909 CONST char *cptr;
1910 t_stat stat_nomessage;
1911 CTAB *cmdp = NULL;
1912
1913 stat = SCPE_BARE_STATUS(stat);
1914 while (stat != SCPE_EXIT) {
1915 if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))
1916 printf ("%s%s\n", sim_prompt, cptr);
1917 else if (sim_vm_read != NULL) {
1918 printf ("%s", sim_prompt);
1919 cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
1920 }
1921 else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);
1922 if (cptr == NULL) {
1923 if (sim_ttisatty()) continue;
1924 else break;
1925 }
1926 if (*cptr == 0)
1927 continue;
1928 sim_sub_args (cbuf, sizeof(cbuf), argv);
1929 if (sim_log)
1930 fprintf (sim_log, "%s%s\n", sim_prompt, cptr);
1931 if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
1932 fprintf (sim_deb, "%s%s\n", sim_prompt, cptr);
1933 cptr = get_glyph_cmd (cptr, gbuf);
1934 sim_switches = 0;
1935 if ((cmdp = find_cmd (gbuf)))
1936 stat = cmdp->action (cmdp->arg, cptr);
1937 else
1938 stat = SCPE_UNK;
1939 stat_nomessage = stat & SCPE_NOMESSAGE;
1940 stat_nomessage = stat_nomessage || (!sim_show_message);
1941 stat = SCPE_BARE_STATUS(stat);
1942 sim_last_cmd_stat = stat;
1943 if (!stat_nomessage) {
1944 if (cmdp && (cmdp->message))
1945 cmdp->message (NULL, stat);
1946 else
1947 if (stat >= SCPE_BASE)
1948 sim_printf ("%s\n", sim_error_text (stat));
1949 }
1950 if (sim_vm_post != NULL)
1951 (*sim_vm_post) (TRUE);
1952 }
1953 return stat;
1954 }
1955
1956
1957
1958 t_stat set_prompt (int32 flag, CONST char *cptr)
1959 {
1960 char gbuf[CBUFSIZE], *gptr;
1961
1962 if ((!cptr) || (*cptr == '\0'))
1963 return SCPE_ARG;
1964
1965 cptr = get_glyph_nc (cptr, gbuf, '"');
1966 if (gbuf[0] == '\0') {
1967 gbuf[sizeof (gbuf)-1] = '\0';
1968 strncpy (gbuf, cptr, sizeof (gbuf)-1);
1969 gptr = strchr (gbuf, '"');
1970 if (gptr)
1971 *gptr = '\0';
1972 }
1973 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);
1974 if (!sim_prompt)
1975 {
1976 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1977 __func__, __FILE__, __LINE__);
1978 #if defined(USE_BACKTRACE)
1979 # ifdef SIGUSR2
1980 (void)raise(SIGUSR2);
1981
1982 # endif
1983 #endif
1984 abort();
1985 }
1986 sprintf (sim_prompt, "%s ", gbuf);
1987 return SCPE_OK;
1988 }
1989
1990
1991
1992 CTAB *find_cmd (const char *gbuf)
1993 {
1994 CTAB *cmdp = NULL;
1995
1996 if (sim_vm_cmd)
1997 cmdp = find_ctab (sim_vm_cmd, gbuf);
1998 if (cmdp == NULL)
1999 cmdp = find_ctab (cmd_table, gbuf);
2000 return cmdp;
2001 }
2002
2003
2004
2005 t_stat exit_cmd (int32 flag, CONST char *cptr)
2006 {
2007 return SCPE_EXIT;
2008 }
2009
2010
2011
2012
2013 static int _cmd_name_compare (const void *pa, const void *pb)
2014 {
2015 CTAB * const *a = (CTAB * const *)pa;
2016 CTAB * const *b = (CTAB * const *)pb;
2017
2018 return strcmp((*a)->name, (*b)->name);
2019 }
2020
2021 void fprint_help (FILE *st)
2022 {
2023 CTAB *cmdp;
2024 CTAB **hlp_cmdp = NULL;
2025 int cmd_cnt = 0;
2026 int cmd_size = 0;
2027 size_t max_cmdname_size = 0;
2028 int i, line_offset;
2029
2030 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2031 if (cmdp->help) {
2032 if (cmd_cnt >= cmd_size) {
2033 cmd_size += 20;
2034 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2035 if (!hlp_cmdp)
2036 {
2037 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2038 __func__, __FILE__, __LINE__);
2039 #if defined(USE_BACKTRACE)
2040 # ifdef SIGUSR2
2041 (void)raise(SIGUSR2);
2042
2043 # endif
2044 #endif
2045 abort();
2046 }
2047 }
2048 hlp_cmdp[cmd_cnt] = cmdp;
2049 ++cmd_cnt;
2050 if (strlen(cmdp->name) > max_cmdname_size)
2051 max_cmdname_size = strlen(cmdp->name);
2052 }
2053 }
2054 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2055 if (cmdp->help && (!sim_vm_cmd || !find_ctab (sim_vm_cmd, cmdp->name))) {
2056 if (cmd_cnt >= cmd_size) {
2057 cmd_size += 20;
2058 hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2059 if (!hlp_cmdp)
2060 {
2061 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2062 __func__, __FILE__, __LINE__);
2063 #if defined(USE_BACKTRACE)
2064 # ifdef SIGUSR2
2065 (void)raise(SIGUSR2);
2066
2067 # endif
2068 #endif
2069 abort();
2070 }
2071 }
2072 hlp_cmdp[cmd_cnt] = cmdp;
2073 ++cmd_cnt;
2074 if (strlen (cmdp->name) > max_cmdname_size)
2075 max_cmdname_size = strlen(cmdp->name);
2076 }
2077 }
2078 fprintf (st, "HELP is available for the following commands:\n\n ");
2079 if (hlp_cmdp)
2080 qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2081 line_offset = 4;
2082 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2083 fputs (hlp_cmdp[i]->name, st);
2084 line_offset += 5 + max_cmdname_size;
2085 if (line_offset + max_cmdname_size > 79) {
2086 line_offset = 4;
2087 fprintf (st, "\n ");
2088 }
2089 else
2090 fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2091 }
2092 FREE (hlp_cmdp);
2093 fprintf (st, "\n");
2094 return;
2095 }
2096
2097 static void fprint_header (FILE *st, t_bool *pdone, char *context)
2098 {
2099 if (!*pdone)
2100 fprintf (st, "%s", context);
2101 *pdone = TRUE;
2102 }
2103
2104 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2105 {
2106 REG *rptr, *trptr;
2107 t_bool found = FALSE;
2108 t_bool all_unique = TRUE;
2109 size_t max_namelen = 0;
2110 DEVICE *tdptr;
2111 CONST char *tptr;
2112 char *namebuf;
2113 char rangebuf[32];
2114
2115 if (dptr->registers)
2116 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2117 if (rptr->flags & REG_HIDDEN)
2118 continue;
2119 if (rptr->depth > 1)
2120 sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2121 else
2122 strcpy (rangebuf, "");
2123 if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2124 max_namelen = strlen(rptr->name) + strlen (rangebuf);
2125 found = TRUE;
2126 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2127 if ((trptr == NULL) || (tdptr != dptr))
2128 all_unique = FALSE;
2129 }
2130 if (!found) {
2131 if (!silent)
2132 fprintf (st, "No register HELP available for the %s device\n", dptr->name);
2133 }
2134 else {
2135 namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2136 if (!namebuf)
2137 {
2138 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2139 __func__, __FILE__, __LINE__);
2140 #if defined(USE_BACKTRACE)
2141 # ifdef SIGUSR2
2142 (void)raise(SIGUSR2);
2143
2144 # endif
2145 #endif
2146 abort();
2147 }
2148 fprintf (st, "\nThe %s device implements these registers:\n\n", dptr->name);
2149 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2150 if (rptr->flags & REG_HIDDEN)
2151 continue;
2152 if (rptr->depth <= 1)
2153 sprintf (namebuf, "%*s", -((int)max_namelen), rptr->name);
2154 else {
2155 sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2156 sprintf (namebuf, "%s%*s", rptr->name, (int)(strlen(rptr->name))-((int)max_namelen), rangebuf);
2157 }
2158 if (all_unique) {
2159 fprintf (st, " %s %4d %s\n", namebuf, rptr->width, rptr->desc ? rptr->desc : "");
2160 continue;
2161 }
2162 trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2163 if ((trptr == NULL) || (tdptr != dptr))
2164 fprintf (st, " %s %s %4d %s\n", dptr->name, namebuf, rptr->width, rptr->desc ? rptr->desc : "");
2165 else
2166 fprintf (st, " %*s %s %4d %s\n", (int)strlen(dptr->name), "", namebuf, rptr->width, rptr->desc ? rptr->desc : "");
2167 }
2168 FREE (namebuf);
2169 }
2170 }
2171
2172 void fprint_reg_help (FILE *st, DEVICE *dptr)
2173 {
2174 fprint_reg_help_ex (st, dptr, TRUE);
2175 }
2176
2177 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2178 {
2179 if (dptr->attach_help) {
2180 fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2181 dptr->attach_help (st, dptr, NULL, 0, NULL);
2182 return;
2183 }
2184 if (DEV_TYPE(dptr) == DEV_DISK) {
2185 fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2186 sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2187 return;
2188 }
2189 if (DEV_TYPE(dptr) == DEV_TAPE) {
2190 fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2191 sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2192 return;
2193 }
2194 if (!silent) {
2195 fprintf (st, "No ATTACH help is available for the %s device\n", dptr->name);
2196 if (dptr->help)
2197 dptr->help (st, dptr, NULL, 0, NULL);
2198 }
2199 }
2200
2201 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2202 {
2203 MTAB *mptr;
2204 DEBTAB *dep;
2205 t_bool found = FALSE;
2206 char buf[CBUFSIZE], header[CBUFSIZE];
2207 uint32 enabled_units = dptr->numunits;
2208 uint32 unit;
2209
2210 sprintf (header, "\n%s device SET commands:\n\n", dptr->name);
2211 for (unit=0; unit < dptr->numunits; unit++)
2212 if (dptr->units[unit].flags & UNIT_DIS)
2213 --enabled_units;
2214 if (dptr->modifiers) {
2215 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2216 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2217 continue;
2218 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2219 continue;
2220 if (mptr->mstring) {
2221 fprint_header (st, &found, header);
2222 sprintf (buf, "SET %s %s%s", sim_dname (dptr), mptr->mstring, (strchr(mptr->mstring, '=')) ? "" : (MODMASK(mptr,MTAB_VALR) ? "=val" : (MODMASK(mptr,MTAB_VALO) ? "{=val}" : "")));
2223 if ((strlen (buf) < 30) || (!mptr->help))
2224 fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2225 else
2226 fprintf (st, "%s\n%-30s\t%s\n", buf, "", mptr->help);
2227 }
2228 }
2229 }
2230 if (dptr->flags & DEV_DISABLE) {
2231 fprint_header (st, &found, header);
2232 sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2233 fprintf (st, "%-30s\tEnables device %s\n", buf, sim_dname (dptr));
2234 sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2235 fprintf (st, "%-30s\tDisables device %s\n", buf, sim_dname (dptr));
2236 }
2237 if (dptr->flags & DEV_DEBUG) {
2238 fprint_header (st, &found, header);
2239 sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2240 fprintf (st, "%-30s\tEnables debugging for device %s\n", buf, sim_dname (dptr));
2241 sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2242 fprintf (st, "%-30s\tDisables debugging for device %s\n", buf, sim_dname (dptr));
2243 if (dptr->debflags) {
2244 t_bool desc_available = FALSE;
2245 strcpy (buf, "");
2246 fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2247 for (dep = dptr->debflags; dep->name != NULL; dep++) {
2248 fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2249 desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2250 }
2251 fprintf (st, "\n");
2252 fprintf (st, "%-30s\tEnables specific debugging for device %s\n", buf, sim_dname (dptr));
2253 fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2254 for (dep = dptr->debflags; dep->name != NULL; dep++)
2255 fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2256 fprintf (st, "\n");
2257 fprintf (st, "%-30s\tDisables specific debugging for device %s\n", buf, sim_dname (dptr));
2258 if (desc_available) {
2259 fprintf (st, "\n*%s device DEBUG settings:\n", sim_dname (dptr));
2260 for (dep = dptr->debflags; dep->name != NULL; dep++)
2261 fprintf (st, "%4s%-12s%s\n", "", dep->name, dep->desc ? dep->desc : "");
2262 }
2263 }
2264 }
2265 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2266 if (dptr->units->flags & UNIT_DISABLE) {
2267 fprint_header (st, &found, header);
2268 sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2269 fprintf (st, "%-30s\tEnables unit %sn\n", buf, sim_dname (dptr));
2270 sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2271 fprintf (st, "%-30s\tDisables unit %sn\n", buf, sim_dname (dptr));
2272 }
2273 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2274 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2275 continue;
2276 if ((!mptr->valid) && MODMASK(mptr,MTAB_XTD))
2277 continue;
2278 if (mptr->mstring) {
2279 fprint_header (st, &found, header);
2280 sprintf (buf, "SET %s%s %s%s", sim_dname (dptr), (dptr->numunits > 1) ? "n" : "0", mptr->mstring, (strchr(mptr->mstring, '=')) ? "" : (MODMASK(mptr,MTAB_VALR) ? "=val" : (MODMASK(mptr,MTAB_VALO) ? "{=val}": "")));
2281 fprintf (st, "%-30s\t%s\n", buf, (strchr(mptr->mstring, '=')) ? "" : (mptr->help ? mptr->help : ""));
2282 }
2283 }
2284 }
2285 if (!found && !silent)
2286 fprintf (st, "No SET help is available for the %s device\n", dptr->name);
2287 }
2288
2289 void fprint_set_help (FILE *st, DEVICE *dptr)
2290 {
2291 fprint_set_help_ex (st, dptr, TRUE);
2292 }
2293
2294 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2295 {
2296 MTAB *mptr;
2297 t_bool found = FALSE;
2298 char buf[CBUFSIZE], header[CBUFSIZE];
2299 uint32 enabled_units = dptr->numunits;
2300 uint32 unit;
2301
2302 sprintf (header, "\n%s device SHOW commands:\n\n", dptr->name);
2303 for (unit=0; unit < dptr->numunits; unit++)
2304 if (dptr->units[unit].flags & UNIT_DIS)
2305 --enabled_units;
2306 if (dptr->modifiers) {
2307 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2308 if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2309 continue;
2310 if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2311 continue;
2312 if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2313 continue;
2314 fprint_header (st, &found, header);
2315 sprintf (buf, "SHOW %s %s%s", sim_dname (dptr), mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2316 fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2317 }
2318 }
2319 if (dptr->flags & DEV_DEBUG) {
2320 fprint_header (st, &found, header);
2321 sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2322 fprintf (st, "%-30s\tDisplays debugging status for device %s\n", buf, sim_dname (dptr));
2323 }
2324 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2325 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2326 if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2327 continue;
2328 if ((!mptr->disp) || (!mptr->pstring))
2329 continue;
2330 fprint_header (st, &found, header);
2331 sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr), (dptr->numunits > 1) ? "n" : "0", mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2332 fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2333 }
2334 }
2335 if (!found && !silent)
2336 fprintf (st, "No SHOW help is available for the %s device\n", dptr->name);
2337 }
2338
2339 void fprint_show_help (FILE *st, DEVICE *dptr)
2340 {
2341 fprint_show_help_ex (st, dptr, TRUE);
2342 }
2343
2344 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
2345 {
2346 BRKTYPTAB *brkt = dptr->brk_types;
2347 char gbuf[CBUFSIZE];
2348
2349 if (sim_brk_types == 0) {
2350 if ((dptr != sim_dflt_dev) && (!silent)) {
2351 fprintf (st, "Breakpoints are not supported in the %s simulator\n", sim_name);
2352 if (dptr->help)
2353 dptr->help (st, dptr, NULL, 0, NULL);
2354 }
2355 return;
2356 }
2357 if (brkt == NULL) {
2358 int i;
2359
2360 if (dptr == sim_dflt_dev) {
2361 if (sim_brk_types & ~sim_brk_dflt) {
2362 fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2363 for (i=0; i<26; i++) {
2364 if (sim_brk_types & (1<<i))
2365 fprintf (st, " -%c\n", 'A'+i);
2366 }
2367 }
2368 fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2369 }
2370 return;
2371 }
2372 fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2373 while (brkt->btyp) {
2374 fprintf (st, " %s %s\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2375 ++brkt;
2376 }
2377 fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2378 }
2379
2380 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
2381 {
2382 char gbuf[CBUFSIZE];
2383 CTAB *cmdp;
2384
2385 if (*cptr) {
2386 (void)get_glyph (cptr, gbuf, 0);
2387 if ((cmdp = find_cmd (gbuf))) {
2388 if (cmdp->action == &exdep_cmd) {
2389 if (dptr->help)
2390 return dptr->help (st, dptr, uptr, flag, cptr);
2391 else
2392 fprintf (st, "No HELP available for the %s %s command\n", cmdp->name, sim_dname(dptr));
2393 return SCPE_OK;
2394 }
2395 if (cmdp->action == &set_cmd) {
2396 fprint_set_help_ex (st, dptr, FALSE);
2397 return SCPE_OK;
2398 }
2399 if (cmdp->action == &show_cmd) {
2400 fprint_show_help_ex (st, dptr, FALSE);
2401 return SCPE_OK;
2402 }
2403 if (cmdp->action == &attach_cmd) {
2404 fprint_attach_help_ex (st, dptr, FALSE);
2405 return SCPE_OK;
2406 }
2407 if (cmdp->action == &brk_cmd) {
2408 fprint_brk_help_ex (st, dptr, FALSE);
2409 return SCPE_OK;
2410 }
2411 if (dptr->help)
2412 return dptr->help (st, dptr, uptr, flag, cptr);
2413 fprintf (st, "No %s HELP is available for the %s device\n", cmdp->name, dptr->name);
2414 return SCPE_OK;
2415 }
2416 if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2417 fprint_reg_help_ex (st, dptr, FALSE);
2418 return SCPE_OK;
2419 }
2420 if (dptr->help)
2421 return dptr->help (st, dptr, uptr, flag, cptr);
2422 fprintf (st, "No %s HELP is available for the %s device\n", gbuf, dptr->name);
2423 return SCPE_OK;
2424 }
2425 if (dptr->help) {
2426 return dptr->help (st, dptr, uptr, flag, cptr);
2427 }
2428 if (dptr->description)
2429 fprintf (st, "%s %s HELP\n", dptr->description (dptr), dptr->name);
2430 else
2431 fprintf (st, "%s HELP\n", dptr->name);
2432 fprint_set_help_ex (st, dptr, TRUE);
2433 fprint_show_help_ex (st, dptr, TRUE);
2434 fprint_attach_help_ex (st, dptr, TRUE);
2435 fprint_reg_help_ex (st, dptr, TRUE);
2436 fprint_brk_help_ex (st, dptr, TRUE);
2437 return SCPE_OK;
2438 }
2439
2440 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
2441 {
2442 switch (help[0]) {
2443 case '*':
2444 scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2445 if (sim_log)
2446 scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2447 break;
2448 default:
2449 fputs (help, stdout);
2450 if (sim_log)
2451 fputs (help, sim_log);
2452 break;
2453 }
2454 return SCPE_OK;
2455 }
2456
2457 t_stat help_cmd (int32 flag, CONST char *cptr)
2458 {
2459 char gbuf[CBUFSIZE];
2460 CTAB *cmdp;
2461
2462 GET_SWITCHES (cptr);
2463 if (sim_switches & SWMASK ('F'))
2464 flag = flag | SCP_HELP_FLAT;
2465 if (*cptr) {
2466 cptr = get_glyph (cptr, gbuf, 0);
2467 if ((cmdp = find_cmd (gbuf))) {
2468 if (*cptr) {
2469 if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2470 DEVICE *dptr;
2471 UNIT *uptr;
2472 t_stat r;
2473 cptr = get_glyph (cptr, gbuf, 0);
2474 dptr = find_unit (gbuf, &uptr);
2475 if (dptr == NULL)
2476 dptr = find_dev (gbuf);
2477 if (dptr != NULL) {
2478 r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2479 if (sim_log)
2480 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2481 return r;
2482 }
2483 if (cmdp->action == &set_cmd) {
2484
2485 if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2486 (cmdp->help))
2487 return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2488 }
2489 else {
2490 SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2491 if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2492 return SCPE_ARG;
2493 return help_cmd_output (flag, shptr->help, NULL);
2494 }
2495 return SCPE_ARG;
2496 }
2497 else
2498 return SCPE_2MARG;
2499 }
2500 if (cmdp->help) {
2501 if (strcmp (cmdp->name, "HELP") == 0) {
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532 }
2533 else {
2534 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2535 sim_dflt_dev && sim_dflt_dev->help) {
2536 sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2537 if (sim_log)
2538 sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2539 }
2540 }
2541 help_cmd_output (flag, cmdp->help, cmdp->help_base);
2542 }
2543 else {
2544 CTAB *cmdpa;
2545 for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2546 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2547 sim_printf ("%s is an alias for the %s command:\n%s",
2548 cmdp->name, cmdpa->name, cmdpa->help);
2549 break;
2550 }
2551 if (cmdpa->name == NULL)
2552 sim_printf ("No help available for the %s command\n", cmdp->name);
2553 }
2554 }
2555 else {
2556 DEVICE *dptr;
2557 UNIT *uptr;
2558 t_stat r;
2559 dptr = find_unit (gbuf, &uptr);
2560 if (dptr == NULL) {
2561 dptr = find_dev (gbuf);
2562 if (dptr == NULL)
2563 return SCPE_ARG;
2564 if (dptr->flags & DEV_DIS)
2565 sim_printf ("Device %s is currently disabled\n", dptr->name);
2566 }
2567 r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2568 if (sim_log)
2569 help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2570 return r;
2571 }
2572 }
2573 else {
2574 fprint_help (stdout);
2575 if (sim_log)
2576 fprint_help (sim_log);
2577 }
2578 return SCPE_OK;
2579 }
2580
2581
2582
2583 t_stat spawn_cmd (int32 flag, CONST char *cptr)
2584 {
2585 t_stat status;
2586 if ((cptr == NULL) || (strlen (cptr) == 0))
2587 cptr = getenv("SHELL");
2588 if ((cptr == NULL) || (strlen (cptr) == 0))
2589 cptr = getenv("ComSpec");
2590 fflush(stdout);
2591 if (sim_log)
2592 fflush (sim_log);
2593 if (sim_deb)
2594 fflush (sim_deb);
2595 status = system (cptr);
2596
2597 return status;
2598 }
2599
2600
2601
2602 t_stat echo_cmd (int32 flag, CONST char *cptr)
2603 {
2604 sim_printf ("%s\n", cptr);
2605 return SCPE_OK;
2606 }
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628 t_stat do_cmd (int32 flag, CONST char *fcptr)
2629 {
2630 return do_cmd_label (flag, fcptr, NULL);
2631 }
2632
2633 static char *do_position(void)
2634 {
2635 static char cbuf[4*CBUFSIZE];
2636
2637 snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
2638 sim_do_label[sim_do_depth] ? "::" : "",
2639 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
2640 sim_goto_line[sim_do_depth]);
2641 return cbuf;
2642 }
2643
2644 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
2645 {
2646 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
2647 CONST char *cptr;
2648 FILE *fpin;
2649 CTAB *cmdp = NULL;
2650 int32 echo, nargs, errabort, i;
2651 int32 saved_sim_do_echo = sim_do_echo,
2652 saved_sim_show_message = sim_show_message,
2653 saved_sim_on_inherit = sim_on_inherit,
2654 saved_sim_quiet = sim_quiet;
2655 t_bool staying;
2656 t_stat stat, stat_nomessage;
2657
2658 stat = SCPE_OK;
2659 staying = TRUE;
2660 if (flag > 0)
2661 GET_SWITCHES (fcptr);
2662 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;
2663 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet;
2664 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit;
2665 errabort = sim_switches & SWMASK ('E');
2666
2667 abuf[sizeof(abuf)-1] = '\0';
2668 strncpy (abuf, fcptr, sizeof(abuf)-1);
2669 c = abuf;
2670 do_arg[10] = NULL;
2671 for (nargs = 0; nargs < 10; ) {
2672 while (sim_isspace (*c))
2673 c++;
2674 if (*c == 0)
2675 do_arg [nargs++] = NULL;
2676 else {
2677 if (*c == '\'' || *c == '"')
2678 quote = *c++;
2679 else quote = 0;
2680 do_arg[nargs++] = c;
2681 while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
2682 c++;
2683 if (*c)
2684 *c++ = 0;
2685 }
2686 }
2687
2688 if (do_arg [0] == NULL)
2689 return SCPE_2FARG;
2690 if ((fpin = fopen (do_arg[0], "r")) == NULL) {
2691 strcat (strcpy (cbuf, do_arg[0]), ".ini");
2692 if ((fpin = fopen (cbuf, "r")) == NULL) {
2693 if (flag == 0)
2694 fprintf (stderr, "Can't open file %s\n", do_arg[0]);
2695 return SCPE_OPENERR;
2696 }
2697 }
2698 if (flag >= 0) {
2699 ++sim_do_depth;
2700 if (sim_on_inherit) {
2701 sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1];
2702 for (i=0; i<SCPE_MAX_ERR; i++) {
2703 if (sim_on_actions[sim_do_depth-1][i]) {
2704 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
2705 if (NULL == sim_on_actions[sim_do_depth][i]) {
2706 while (--i >= 0) {
2707 FREE(sim_on_actions[sim_do_depth][i]);
2708 sim_on_actions[sim_do_depth][i] = NULL;
2709 }
2710 sim_on_check[sim_do_depth] = 0;
2711 sim_brk_clract ();
2712 --sim_do_depth;
2713 fclose(fpin);
2714 return SCPE_MEM;
2715 }
2716 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
2717 }
2718 }
2719 }
2720 }
2721
2722 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);
2723 sim_do_label[sim_do_depth] = label;
2724 sim_goto_line[sim_do_depth] = 0;
2725 if (label) {
2726 sim_gotofile = fpin;
2727 sim_do_echo = echo;
2728 stat = goto_cmd (0, label);
2729 if (stat != SCPE_OK) {
2730 strcpy(cbuf, "RETURN SCPE_ARG");
2731 cptr = get_glyph (cbuf, gbuf, 0);
2732 cmdp = find_cmd (gbuf);
2733 goto Cleanup_Return;
2734 }
2735 }
2736 if (errabort)
2737 set_on (1, NULL);
2738
2739 do {
2740 sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf));
2741 if (!sim_do_ocptr[sim_do_depth]) {
2742 sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);
2743 sim_goto_line[sim_do_depth] += 1;
2744 }
2745 sim_sub_args (cbuf, sizeof(cbuf), do_arg);
2746 if (cptr == NULL) {
2747 stat = SCPE_OK;
2748 break;
2749 }
2750 if (*cptr == 0)
2751 continue;
2752 if (echo)
2753 sim_printf("%s> %s\n", do_position(), cptr);
2754 if (*cptr == ':')
2755 continue;
2756 cptr = get_glyph_cmd (cptr, gbuf);
2757 sim_switches = 0;
2758 sim_gotofile = fpin;
2759 sim_do_echo = echo;
2760 if ((cmdp = find_cmd (gbuf))) {
2761 if (cmdp->action == &return_cmd)
2762 break;
2763 if (cmdp->action == &do_cmd) {
2764 if (sim_do_depth >= MAX_DO_NEST_LVL)
2765 stat = SCPE_NEST;
2766 else
2767 stat = do_cmd (sim_do_depth+1, cptr);
2768 }
2769 else
2770 stat = cmdp->action (cmdp->arg, cptr);
2771 }
2772 else stat = SCPE_UNK;
2773 echo = sim_do_echo;
2774 stat_nomessage = stat & SCPE_NOMESSAGE;
2775 stat_nomessage = stat_nomessage || (!sim_show_message);
2776 stat = SCPE_BARE_STATUS(stat);
2777 if (cmdp)
2778 if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
2779 ((cmdp->action != &return_cmd) &&
2780 (cmdp->action != &goto_cmd) &&
2781 (cmdp->action != &on_cmd) &&
2782 (cmdp->action != &echo_cmd)))
2783 sim_last_cmd_stat = stat;
2784 switch (stat) {
2785 case SCPE_AFAIL:
2786 staying = (sim_on_check[sim_do_depth] &&
2787 sim_on_actions[sim_do_depth][stat]);
2788 break;
2789 case SCPE_EXIT:
2790 staying = FALSE;
2791 break;
2792 case SCPE_OK:
2793 case SCPE_STEP:
2794 break;
2795 default:
2796 break;
2797 }
2798 if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&
2799 (stat != SCPE_STEP)) {
2800 if (!echo && !sim_quiet &&
2801 !stat_nomessage &&
2802 !(cmdp && cmdp->message)) {
2803 sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
2804 }
2805 }
2806 if (!stat_nomessage) {
2807 if (cmdp && cmdp->message)
2808 cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
2809 else
2810 if (stat >= SCPE_BASE)
2811 sim_printf ("%s\n", sim_error_text (stat));
2812 }
2813 if (stat == SCPE_EXPECT)
2814 stat = SCPE_OK;
2815 if (staying &&
2816 (sim_on_check[sim_do_depth]) &&
2817 (stat != SCPE_OK) &&
2818 (stat != SCPE_STEP)) {
2819 if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
2820 sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
2821 else
2822 sim_brk_setact (sim_on_actions[sim_do_depth][0]);
2823 }
2824 if (sim_vm_post != NULL)
2825 (*sim_vm_post) (TRUE);
2826 } while (staying);
2827 Cleanup_Return:
2828 if (fpin)
2829 fclose (fpin);
2830 sim_gotofile = NULL;
2831 if (flag >= 0) {
2832 sim_do_echo = saved_sim_do_echo;
2833 sim_show_message = saved_sim_show_message;
2834 sim_on_inherit = saved_sim_on_inherit;
2835 }
2836 sim_quiet = saved_sim_quiet;
2837 if ((flag >= 0) || (!sim_on_inherit)) {
2838 for (i=0; i<SCPE_MAX_ERR; i++) {
2839 FREE (sim_on_actions[sim_do_depth][i]);
2840 sim_on_actions[sim_do_depth][i] = NULL;
2841 }
2842 sim_on_check[sim_do_depth] = 0;
2843 }
2844 if (flag >= 0)
2845 --sim_do_depth;
2846 sim_brk_clract ();
2847 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) {
2848 sim_string_to_stat (cptr, &stat);
2849 sim_last_cmd_stat = stat;
2850 if (sim_switches & SWMASK ('Q'))
2851 stat |= SCPE_NOMESSAGE;
2852 return stat;
2853 }
2854 return stat | SCPE_NOMESSAGE;
2855 }
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
2900 {
2901 char gbuf[CBUFSIZE];
2902 char *ip = instr, *op, *oend, *tmpbuf;
2903 const char *ap;
2904 char rbuf[CBUFSIZE];
2905 int i;
2906 time_t now;
2907 struct tm *tmnow;
2908
2909 time(&now);
2910 tmnow = localtime(&now);
2911 tmpbuf = (char *)malloc(instr_size);
2912 if (!tmpbuf)
2913 {
2914 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2915 __func__, __FILE__, __LINE__);
2916 #if defined(USE_BACKTRACE)
2917 # ifdef SIGUSR2
2918 (void)raise(SIGUSR2);
2919
2920 # endif
2921 #endif
2922 abort();
2923 }
2924 op = tmpbuf;
2925 oend = tmpbuf + instr_size - 2;
2926 while (sim_isspace (*ip))
2927 *op++ = *ip++;
2928 for (; *ip && (op < oend); ) {
2929 if ((ip [0] == '\\') &&
2930 ((ip [1] == '%') || (ip [1] == '\\'))) {
2931 ip++;
2932 *op++ = *ip++;
2933 }
2934 else
2935 if ((*ip == '%') &&
2936 (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {
2937 if ((ip[1] >= '0') && (ip[1] <= ('9'))) {
2938 ap = do_arg[ip[1] - '0'];
2939 for (i=0; i<ip[1] - '0'; ++i)
2940 if (do_arg[i] == NULL) {
2941 ap = NULL;
2942 break;
2943 }
2944 ip = ip + 2;
2945 }
2946 else if (ip[1] == '*') {
2947 memset (rbuf, '\0', sizeof(rbuf));
2948 ap = rbuf;
2949 for (i=1; i<=9; ++i)
2950 if (do_arg[i] == NULL)
2951 break;
2952 else
2953 if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
2954 if (strchr(do_arg[i], ' ')) {
2955 char quote = '"';
2956 if (strchr(do_arg[i], quote))
2957 quote = '\'';
2958 sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"", (i != 1) ? " " : "", quote, do_arg[i], quote);
2959 }
2960 else
2961 sprintf(&rbuf[strlen(rbuf)], "%s%s", (i != 1) ? " " : "", do_arg[i]);
2962 }
2963 else
2964 break;
2965 ip = ip + 2;
2966 }
2967 else {
2968 ap = NULL;
2969 (void)get_glyph_nc (ip+1, gbuf, '%');
2970 ap = getenv(gbuf);
2971 if (!ap) {
2972 (void)get_glyph (ip+1, gbuf, '%');
2973 ap = getenv(gbuf);
2974 }
2975 ip += 1 + strlen (gbuf);
2976 if (*ip == '%') ++ip;
2977 if (!ap) {
2978
2979 if (!strcmp ("DATE", gbuf)) {
2980 sprintf (rbuf, "%4d-%02d-%02d", tmnow->tm_year+1900, tmnow->tm_mon+1, tmnow->tm_mday);
2981 ap = rbuf;
2982 }
2983 else if (!strcmp ("TIME", gbuf)) {
2984 sprintf (rbuf, "%02d:%02d:%02d", tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec);
2985 ap = rbuf;
2986 }
2987 else if (!strcmp ("DATETIME", gbuf)) {
2988 sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d", tmnow->tm_year+1900, tmnow->tm_mon+1, tmnow->tm_mday, tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec);
2989 ap = rbuf;
2990 }
2991
2992 if (!strcmp ("LDATE", gbuf)) {
2993 strftime (rbuf, sizeof(rbuf), "%x", tmnow);
2994 ap = rbuf;
2995 }
2996 else if (!strcmp ("LTIME", gbuf)) {
2997 strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
2998 ap = rbuf;
2999 }
3000 else if (!strcmp ("CTIME", gbuf)) {
3001 strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3002 ap = rbuf;
3003 }
3004
3005 else if (!strcmp ("DATE_YYYY", gbuf)) {
3006 strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3007 ap = rbuf;
3008 }
3009 else if (!strcmp ("DATE_YY", gbuf)) {
3010 strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3011 ap = rbuf;
3012 }
3013 else if (!strcmp ("DATE_YC", gbuf)) {
3014 sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3015 ap = rbuf;
3016 }
3017 else if ((!strcmp ("DATE_19XX_YY", gbuf)) ||
3018 (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3019 int year = tmnow->tm_year + 1900;
3020 int days = year - 2001;
3021 int leaps = days/4 - days/100 + days/400;
3022 int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3023 int selector = ((days + leaps + 7) % 7) + lyear * 7;
3024 static int years[] = {90, 91, 97, 98, 99, 94, 89,
3025 96, 80, 92, 76, 88, 72, 84};
3026 int cal_year = years[selector];
3027
3028 if (!strcmp ("DATE_19XX_YY", gbuf))
3029 sprintf (rbuf, "%d", cal_year);
3030 else
3031 sprintf (rbuf, "%d", cal_year + 1900);
3032 ap = rbuf;
3033 }
3034 else if (!strcmp ("DATE_MM", gbuf)) {
3035 strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3036 ap = rbuf;
3037 }
3038 else if (!strcmp ("DATE_MMM", gbuf)) {
3039 strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3040 ap = rbuf;
3041 }
3042 else if (!strcmp ("DATE_DD", gbuf)) {
3043 strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3044 ap = rbuf;
3045 }
3046 else if (!strcmp ("DATE_D", gbuf)) {
3047 sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3048 ap = rbuf;
3049 }
3050 else if ((!strcmp ("DATE_WW", gbuf)) ||
3051 (!strcmp ("DATE_WYYYY", gbuf))) {
3052 int iso_yr = tmnow->tm_year + 1900;
3053 int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3054
3055 if (iso_wk == 0) {
3056 iso_yr = iso_yr - 1;
3057 tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);
3058 iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3059 }
3060 else
3061 if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3062 ++iso_yr;
3063 iso_wk = 1;
3064 }
3065 if (!strcmp ("DATE_WW", gbuf))
3066 sprintf (rbuf, "%02d", iso_wk);
3067 else
3068 sprintf (rbuf, "%04d", iso_yr);
3069 ap = rbuf;
3070 }
3071 else if (!strcmp ("DATE_JJJ", gbuf)) {
3072 strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3073 ap = rbuf;
3074 }
3075 else if (!strcmp ("TIME_HH", gbuf)) {
3076 strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3077 ap = rbuf;
3078 }
3079 else if (!strcmp ("TIME_MM", gbuf)) {
3080 strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3081 ap = rbuf;
3082 }
3083 else if (!strcmp ("TIME_SS", gbuf)) {
3084 strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3085 ap = rbuf;
3086 }
3087 else if (!strcmp ("STATUS", gbuf)) {
3088 sprintf (rbuf, "%08X", sim_last_cmd_stat);
3089 ap = rbuf;
3090 }
3091 else if (!strcmp ("TSTATUS", gbuf)) {
3092 sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3093 ap = rbuf;
3094 }
3095 else if (!strcmp ("SIM_VERIFY", gbuf)) {
3096 sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3097 ap = rbuf;
3098 }
3099 else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3100 sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3101 ap = rbuf;
3102 }
3103 else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3104 sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3105 ap = rbuf;
3106 }
3107 else if (!strcmp ("SIM_QUIET", gbuf)) {
3108 sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3109 ap = rbuf;
3110 }
3111 else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3112 sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3113 ap = rbuf;
3114 }
3115 else if (!strcmp ("HOSTID", gbuf)) {
3116 #if defined( HAVE_UNISTD ) && !defined ( __HAIKU__ ) && !defined ( __ANDROID__ ) && !defined ( __serenity__ )
3117 sprintf (rbuf, "%ld", (long)gethostid());
3118 #else
3119 sprintf (rbuf, "00000000");
3120 #endif
3121 ap = rbuf;
3122 }
3123 else if (!strcmp ("UID", gbuf)) {
3124 #ifdef HAVE_UNISTD
3125 sprintf (rbuf, "%ld", (long)getuid());
3126 #else
3127 sprintf (rbuf, "0");
3128 #endif
3129 ap = rbuf;
3130 }
3131 else if (!strcmp ("GID", gbuf)) {
3132 #ifdef HAVE_UNISTD
3133 sprintf (rbuf, "%ld", (long)getgid());
3134 #else
3135 sprintf (rbuf, "0");
3136 #endif
3137 ap = rbuf;
3138 }
3139 else if (!strcmp ("EUID", gbuf)) {
3140 #ifdef HAVE_UNISTD
3141 sprintf (rbuf, "%ld", (long)geteuid());
3142 #else
3143 sprintf (rbuf, "0");
3144 #endif
3145 ap = rbuf;
3146 }
3147 else if (!strcmp ("EGID", gbuf)) {
3148 #ifdef HAVE_UNISTD
3149 sprintf (rbuf, "%ld", (long)getegid());
3150 #else
3151 sprintf (rbuf, "0");
3152 #endif
3153 ap = rbuf;
3154 }
3155 else if (!strcmp ("PID", gbuf)) {
3156 #ifdef HAVE_UNISTD
3157 sprintf (rbuf, "%ld", (long)getpid());
3158 #else
3159 sprintf (rbuf, "0");
3160 #endif
3161 ap = rbuf;
3162 }
3163 else if (!strcmp ("PPID", gbuf)) {
3164 #ifdef HAVE_UNISTD
3165 sprintf (rbuf, "%ld", (long)getppid());
3166 #else
3167 sprintf (rbuf, "0");
3168 #endif
3169 ap = rbuf;
3170 }
3171 else if (!strcmp ("PGID", gbuf)) {
3172 #ifdef HAVE_UNISTD
3173 sprintf (rbuf, "%ld", (long)getpgid(getpid()));
3174 #else
3175 sprintf (rbuf, "0");
3176 #endif
3177 ap = rbuf;
3178 }
3179 else if (!strcmp ("SID", gbuf)) {
3180 #ifdef HAVE_UNISTD
3181 sprintf (rbuf, "%ld", (long)getsid(getpid()));
3182 #else
3183 sprintf (rbuf, "0");
3184 #endif
3185 ap = rbuf;
3186 }
3187 else if (!strcmp ("ENDIAN", gbuf)) {
3188 #if ( defined(DECLITEND) && DECLITEND == 1 )
3189 sprintf (rbuf, "LITTLE");
3190 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3191 sprintf (rbuf, "BIG");
3192 #else
3193 sprintf (rbuf, "UNKNOWN");
3194 #endif
3195 ap = rbuf;
3196 }
3197 else if (!strcmp("SIM_NAME", gbuf)) {
3198 sprintf (rbuf, "%s", sim_name);
3199 ap = rbuf;
3200 }
3201 else if (!strcmp("SIM_VERSION", gbuf)) {
3202 #if defined(VER_H_GIT_VERSION)
3203 sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3204 #else
3205 sprintf (rbuf, "UNKNOWN");
3206 #endif
3207 ap = rbuf;
3208 }
3209 else if (!strcmp("SIM_HASH", gbuf)) {
3210 #if defined(VER_H_GIT_HASH)
3211 sprintf (rbuf, "%s", VER_H_GIT_HASH);
3212 #else
3213 sprintf (rbuf, "0000000000000000000000000000000000000000");
3214 #endif
3215 ap = rbuf;
3216 }
3217 else if (!strcmp("SIM_RELT", gbuf)) {
3218 #if defined(VER_H_GIT_RELT)
3219 sprintf (rbuf, "%s", VER_H_GIT_RELT);
3220 #else
3221 sprintf (rbuf, "X");
3222 #endif
3223 ap = rbuf;
3224 }
3225 else if (!strcmp("SIM_DATE", gbuf)) {
3226 #if defined(VER_H_GIT_DATE)
3227 sprintf (rbuf, "%s", VER_H_GIT_DATE);
3228 #else
3229 sprintf (rbuf, "UNKNOWN");
3230 #endif
3231 ap = rbuf;
3232 }
3233 else if ( (!strcmp("CPUS", gbuf)) \
3234 || (!strcmp("PROCESSORS", gbuf) ) ) {
3235 #if defined(LINUX_OS) && !defined(__ANDROID__)
3236 sprintf(rbuf, "%ld", (long)get_nprocs());
3237 #elif defined ( __HAIKU__ )
3238 system_info hinfo;
3239 get_system_info(&hinfo);
3240 sprintf (rbuf, "%llu",
3241 (long long unsigned int)hinfo.cpu_count);
3242 #else
3243 sprintf(rbuf, "1");
3244 #endif
3245 ap = rbuf;
3246 }
3247 }
3248 }
3249 if (ap) {
3250 while (*ap && (op < oend))
3251 *op++ = *ap++;
3252 }
3253 }
3254 else
3255 *op++ = *ip++;
3256 }
3257 *op = 0;
3258 strcpy (instr, tmpbuf);
3259 FREE (tmpbuf);
3260 return;
3261 }
3262
3263 static
3264 int sim_cmp_string (const char *s1, const char *s2)
3265 {
3266 long int v1, v2;
3267 char *ep1, *ep2;
3268
3269 v1 = strtol(s1+1, &ep1, 0);
3270 v2 = strtol(s2+1, &ep2, 0);
3271 if ((ep1 != s1 + strlen (s1) - 1) ||
3272 (ep2 != s2 + strlen (s2) - 1))
3273 return strcmp (s1, s2);
3274 if (v1 == v2)
3275 return 0;
3276 if (v1 < v2)
3277 return -1;
3278 return 1;
3279 }
3280
3281
3282
3283 t_stat assert_cmd (int32 flag, CONST char *cptr)
3284 {
3285 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3286 CONST char *tptr, *gptr;
3287 REG *rptr;
3288 uint32 idx = 0;
3289 t_value val;
3290 t_stat r;
3291 t_bool Not = FALSE;
3292 t_bool result;
3293 t_addr addr = 0;
3294 t_stat reason;
3295
3296 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3297
3298 sim_stabr.boolop = sim_staba.boolop = -1;
3299 if (*cptr == 0)
3300 return SCPE_2FARG;
3301 tptr = get_glyph (cptr, gbuf, 0);
3302 if (!strcmp (gbuf, "NOT")) {
3303 Not = TRUE;
3304 cptr = (CONST char *)tptr;
3305 }
3306 if (*cptr == '"') {
3307 char op[CBUFSIZE];
3308 static struct {
3309 const char *op;
3310 int aval;
3311 int bval;
3312 t_bool invert;
3313 } *optr, compare_ops[] =
3314 {
3315 { "==", 0, 0, FALSE },
3316 { "EQU", 0, 0, FALSE },
3317 { "!=", 0, 0, TRUE },
3318 { "NEQ", 0, 0, TRUE },
3319 { "<", -1, -1, FALSE },
3320 { "LSS", -1, -1, FALSE },
3321 { "<=", 0, -1, FALSE },
3322 { "LEQ", 0, -1, FALSE },
3323 { ">", 1, 1, FALSE },
3324 { "GTR", 1, 1, FALSE },
3325 { ">=", 0, 1, FALSE },
3326 { "GEQ", 0, 1, FALSE },
3327 { NULL }
3328 };
3329
3330 tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3331
3332 if (!*tptr)
3333 return SCPE_2FARG;
3334 cptr += strlen (gbuf);
3335 while (sim_isspace (*cptr))
3336 ++cptr;
3337 (void)get_glyph (cptr, op, '"');
3338 for (optr = compare_ops; optr->op; optr++)
3339 if (0 == strcmp (op, optr->op))
3340 break;
3341 if (!optr->op)
3342 return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op);
3343 cptr += strlen (op);
3344 while (sim_isspace (*cptr))
3345 ++cptr;
3346 cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3347
3348 if (*cptr) {
3349 if (flag)
3350 return SCPE_2MARG;
3351 }
3352 else {
3353 if (!flag)
3354 return SCPE_2FARG;
3355 }
3356 result = sim_cmp_string (gbuf, gbuf2);
3357 result = ((result == optr->aval) || (result == optr->bval));
3358 if (optr->invert)
3359 result = !result;
3360 }
3361 else {
3362 cptr = get_glyph (cptr, gbuf, 0);
3363 rptr = find_reg (gbuf, &gptr, sim_dfdev);
3364 if (rptr) {
3365 if (*gptr == '[') {
3366 if (rptr->depth <= 1)
3367 return SCPE_ARG;
3368 idx = (uint32) strtotv (++gptr, &tptr, 10);
3369 if ((gptr == tptr) || (*tptr++ != ']'))
3370 return SCPE_ARG;
3371 gptr = tptr;
3372 }
3373 else idx = 0;
3374 if (idx >= rptr->depth)
3375 return SCPE_SUB;
3376 }
3377 else {
3378 if (sim_dfdev && sim_vm_parse_addr)
3379 addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3380 else
3381 addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
3382 if (gbuf == gptr)
3383 return SCPE_NXREG;
3384 }
3385 if (*gptr != 0)
3386 (void)get_glyph (gptr, gbuf, 0);
3387 else {
3388 if (*cptr == 0)
3389 return SCPE_2FARG;
3390 cptr = get_glyph (cptr, gbuf, 0);
3391 }
3392 if (*cptr) {
3393 if (flag)
3394 return SCPE_2MARG;
3395 }
3396 else {
3397 if (!flag)
3398 return SCPE_2FARG;
3399 }
3400 if (rptr) {
3401 if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||
3402 (sim_stabr.boolop == -1))
3403 return SCPE_MISVAL;
3404 val = get_rval (rptr, idx);
3405 result = test_search (&val, &sim_stabr);
3406 }
3407 else {
3408 if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||
3409 (sim_staba.boolop == -1))
3410 return SCPE_MISVAL;
3411 reason = get_aval (addr, sim_dfdev, sim_dfunit);
3412 if (reason != SCPE_OK)
3413 return reason;
3414 result = test_search (sim_eval, &sim_staba);
3415 }
3416 }
3417 if (Not ^ result) {
3418 if (!flag)
3419 sim_brk_setact (cptr);
3420 }
3421 else
3422 if (flag)
3423 return SCPE_AFAIL;
3424 return SCPE_OK;
3425 }
3426
3427
3428
3429 t_stat send_cmd (int32 flag, CONST char *cptr)
3430 {
3431 char gbuf[CBUFSIZE];
3432 CONST char *tptr;
3433 uint8 dbuf[CBUFSIZE];
3434 uint32 dsize = 0;
3435 uint32 delay = 0;
3436 uint32 after = 0;
3437 t_stat r;
3438 SEND *snd = NULL;
3439
3440 GET_SWITCHES (cptr);
3441 tptr = get_glyph (cptr, gbuf, ',');
3442 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3443 r = tmxr_locate_line_send (gbuf, &snd);
3444 if (r != SCPE_OK)
3445 return r;
3446 cptr = tptr;
3447 tptr = get_glyph (tptr, gbuf, ',');
3448 }
3449 else
3450 snd = sim_cons_get_send ();
3451
3452 while (*cptr) {
3453 if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3454 delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3455 if (r != SCPE_OK)
3456 return sim_messagef (SCPE_ARG, "Invalid Delay Value\n");
3457 cptr = tptr;
3458 tptr = get_glyph (cptr, gbuf, ',');
3459 continue;
3460 }
3461 if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3462 after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3463 if (r != SCPE_OK)
3464 return sim_messagef (SCPE_ARG, "Invalid After Value\n");
3465 cptr = tptr;
3466 tptr = get_glyph (cptr, gbuf, ',');
3467 continue;
3468 }
3469 if ((*cptr == '"') || (*cptr == '\''))
3470 break;
3471 return SCPE_ARG;
3472 }
3473 if (*cptr) {
3474 if ((*cptr != '"') && (*cptr != '\''))
3475 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
3476 cptr = get_glyph_quoted (cptr, gbuf, 0);
3477 if (*cptr != '\0')
3478 return SCPE_2MARG;
3479
3480 if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3481 return sim_messagef (SCPE_ARG, "Invalid String\n");
3482 }
3483 if ((dsize == 0) && (delay == 0) && (after == 0))
3484 return SCPE_2FARG;
3485 return sim_send_input (snd, dbuf, dsize, after, delay);
3486 }
3487
3488 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3489 {
3490 char gbuf[CBUFSIZE];
3491 CONST char *tptr;
3492 t_stat r;
3493 SEND *snd = NULL;
3494
3495 tptr = get_glyph (cptr, gbuf, ',');
3496 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3497 r = tmxr_locate_line_send (gbuf, &snd);
3498 if (r != SCPE_OK)
3499 return r;
3500 cptr = tptr;
3501 }
3502 else
3503 snd = sim_cons_get_send ();
3504 if (*cptr)
3505 return SCPE_2MARG;
3506 return sim_show_send_input (st, snd);
3507 }
3508
3509 t_stat expect_cmd (int32 flag, CONST char *cptr)
3510 {
3511 char gbuf[CBUFSIZE];
3512 CONST char *tptr;
3513 EXPECT *exp = NULL;
3514
3515 GET_SWITCHES (cptr);
3516 tptr = get_glyph (cptr, gbuf, ',');
3517 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3518 cptr = tptr;
3519 }
3520 else
3521 exp = sim_cons_get_expect ();
3522 if (flag)
3523 return sim_set_expect (exp, cptr);
3524 else
3525 return sim_set_noexpect (exp, cptr);
3526 }
3527
3528 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3529 {
3530 char gbuf[CBUFSIZE];
3531 CONST char *tptr;
3532 EXPECT *exp = NULL;
3533 t_stat r;
3534
3535 tptr = get_glyph (cptr, gbuf, ',');
3536 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3537 r = tmxr_locate_line_expect (gbuf, &exp);
3538 if (r != SCPE_OK)
3539 return r;
3540 cptr = tptr;
3541 }
3542 else
3543 exp = sim_cons_get_expect ();
3544 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3545 return SCPE_ARG;
3546 tptr = get_glyph_quoted (cptr, gbuf, 0);
3547 if (*tptr != '\0')
3548 return SCPE_2MARG;
3549 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3550 return SCPE_ARG;
3551 return sim_exp_show (st, exp, gbuf);
3552 }
3553
3554
3555
3556 t_stat goto_cmd (int32 flag, CONST char *fcptr)
3557 {
3558 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3559 const char *cptr;
3560 long fpos;
3561 int32 saved_do_echo = sim_do_echo;
3562 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3563
3564 if (NULL == sim_gotofile) return SCPE_UNK;
3565 (void)get_glyph (fcptr, gbuf1, 0);
3566 if ('\0' == gbuf1[0]) return SCPE_ARG;
3567 fpos = ftell(sim_gotofile);
3568 rewind(sim_gotofile);
3569 sim_goto_line[sim_do_depth] = 0;
3570 sim_do_echo = 0;
3571 while (1) {
3572 cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);
3573 if (cptr == NULL) break;
3574 sim_goto_line[sim_do_depth] += 1;
3575 if (*cptr == 0) continue;
3576 if (*cptr != ':') continue;
3577 ++cptr;
3578 while (sim_isspace (*cptr)) ++cptr;
3579 cptr = get_glyph (cptr, gbuf, 0);
3580 if (0 == strcmp(gbuf, gbuf1)) {
3581 sim_brk_clract ();
3582 sim_do_echo = saved_do_echo;
3583 if (sim_do_echo)
3584 sim_printf("%s> %s\n", do_position(), cbuf);
3585 return SCPE_OK;
3586 }
3587 }
3588 sim_do_echo = saved_do_echo;
3589 fseek(sim_gotofile, fpos, SEEK_SET);
3590 sim_goto_line[sim_do_depth] = saved_goto_line;
3591 return SCPE_ARG;
3592 }
3593
3594
3595
3596
3597
3598
3599
3600
3601 t_stat return_cmd (int32 flag, CONST char *fcptr)
3602 {
3603 return SCPE_UNK;
3604 }
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614 t_stat shift_cmd (int32 flag, CONST char *fcptr)
3615 {
3616 return SCPE_UNK;
3617 }
3618
3619
3620
3621
3622
3623
3624
3625
3626 t_stat call_cmd (int32 flag, CONST char *fcptr)
3627 {
3628 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
3629 const char *cptr;
3630
3631 if (NULL == sim_gotofile) return SCPE_UNK;
3632 cptr = get_glyph (fcptr, gbuf, 0);
3633 if ('\0' == gbuf[0]) return SCPE_ARG;
3634 snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
3635 sim_switches |= SWMASK ('O');
3636 return do_cmd_label (flag, cbuf, gbuf);
3637 }
3638
3639
3640
3641 t_stat on_cmd (int32 flag, CONST char *cptr)
3642 {
3643 char gbuf[CBUFSIZE];
3644 t_stat cond;
3645
3646 cptr = get_glyph (cptr, gbuf, 0);
3647 if ('\0' == gbuf[0]) return SCPE_ARG;
3648 if (0 == strcmp("ERROR", gbuf))
3649 cond = 0;
3650 else
3651 if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
3652 return SCPE_ARG;
3653 if ((NULL == cptr) || ('\0' == *cptr)) {
3654 FREE(sim_on_actions[sim_do_depth][cond]);
3655 sim_on_actions[sim_do_depth][cond] = NULL; }
3656 else {
3657 sim_on_actions[sim_do_depth][cond] =
3658 (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
3659 if (!sim_on_actions[sim_do_depth][cond])
3660 {
3661 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3662 __func__, __FILE__, __LINE__);
3663 #if defined(USE_BACKTRACE)
3664 # ifdef SIGUSR2
3665 (void)raise(SIGUSR2);
3666
3667 # endif
3668 #endif
3669 abort();
3670 }
3671 strcpy(sim_on_actions[sim_do_depth][cond], cptr);
3672 }
3673 return SCPE_OK;
3674 }
3675
3676
3677
3678 t_stat noop_cmd (int32 flag, CONST char *cptr)
3679 {
3680 if (cptr && (*cptr != 0))
3681 return SCPE_2MARG;
3682 return SCPE_OK;
3683 }
3684
3685
3686
3687 t_stat set_on (int32 flag, CONST char *cptr)
3688 {
3689 if ((flag) && (cptr) && (*cptr)) {
3690 char gbuf[CBUFSIZE];
3691
3692 cptr = get_glyph (cptr, gbuf, 0);
3693 if (((MATCH_CMD(gbuf,"INHERIT")) &&
3694 (MATCH_CMD(gbuf,"NOINHERIT"))) ||
3695 (*cptr))
3696 return SCPE_2MARG;
3697 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT")))
3698 sim_on_inherit = 1;
3699 if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT")))
3700 sim_on_inherit = 0;
3701 return SCPE_OK;
3702 }
3703 if (cptr && (*cptr != 0))
3704 return SCPE_2MARG;
3705 sim_on_check[sim_do_depth] = flag;
3706 if ((sim_do_depth != 0) &&
3707 (NULL == sim_on_actions[sim_do_depth][0])) {
3708 sim_on_actions[sim_do_depth][0] =
3709 (char *)malloc(1+strlen("RETURN"));
3710 strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
3711 }
3712 if ((sim_do_depth != 0) &&
3713 (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {
3714 sim_on_actions[sim_do_depth][SCPE_AFAIL] =
3715 (char *)malloc(1+strlen("RETURN"));
3716 strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
3717 }
3718 return SCPE_OK;
3719 }
3720
3721
3722
3723 t_stat set_verify (int32 flag, CONST char *cptr)
3724 {
3725 if (cptr && (*cptr != 0))
3726 return SCPE_2MARG;
3727 if (flag == sim_do_echo)
3728 return SCPE_OK;
3729 sim_do_echo = flag;
3730 return SCPE_OK;
3731 }
3732
3733
3734
3735 t_stat set_message (int32 flag, CONST char *cptr)
3736 {
3737 if (cptr && (*cptr != 0))
3738 return SCPE_2MARG;
3739 if (flag == sim_show_message)
3740 return SCPE_OK;
3741 sim_show_message = flag;
3742 return SCPE_OK;
3743 }
3744
3745
3746
3747 t_stat set_localopc (int32 flag, CONST char *cptr)
3748 {
3749 if (cptr && (*cptr != 0))
3750 return SCPE_2MARG;
3751 if (flag == sim_localopc)
3752 return SCPE_OK;
3753 sim_localopc = flag;
3754 return SCPE_OK;
3755 }
3756
3757
3758 t_stat set_quiet (int32 flag, CONST char *cptr)
3759 {
3760 if (cptr && (*cptr != 0))
3761 return SCPE_2MARG;
3762 if (flag == sim_quiet)
3763 return SCPE_OK;
3764 sim_quiet = flag;
3765 return SCPE_OK;
3766 }
3767
3768
3769
3770 t_stat sim_set_environment (int32 flag, CONST char *cptr)
3771 {
3772 char varname[CBUFSIZE];
3773
3774 if ((!cptr) || (*cptr == 0))
3775 return SCPE_2FARG;
3776 cptr = get_glyph (cptr, varname, '=');
3777 setenv(varname, cptr, 1);
3778 return SCPE_OK;
3779 }
3780
3781
3782
3783 t_stat set_cmd (int32 flag, CONST char *cptr)
3784 {
3785 uint32 lvl = 0;
3786 t_stat r;
3787 char gbuf[CBUFSIZE], *cvptr;
3788 CONST char *svptr;
3789 DEVICE *dptr;
3790 UNIT *uptr;
3791 MTAB *mptr;
3792 CTAB *gcmdp;
3793 C1TAB *ctbr = NULL, *glbr;
3794
3795 GET_SWITCHES (cptr);
3796 if (*cptr == 0)
3797 return SCPE_2FARG;
3798 cptr = get_glyph (svptr = cptr, gbuf, 0);
3799
3800 if ((dptr = find_dev (gbuf))) {
3801 uptr = dptr->units;
3802 ctbr = set_dev_tab;
3803 lvl = MTAB_VDV;
3804 GET_SWITCHES (cptr);
3805 }
3806 else if ((dptr = find_unit (gbuf, &uptr))) {
3807 if (uptr == NULL)
3808 return SCPE_NXUN;
3809 ctbr = set_unit_tab;
3810 lvl = MTAB_VUN;
3811 GET_SWITCHES (cptr);
3812 }
3813 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {
3814 GET_SWITCHES (cptr);
3815 return gcmdp->action (gcmdp->arg, cptr);
3816 }
3817 else {
3818 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
3819 if ((cvptr = strchr (gbuf, '=')))
3820 *cvptr++ = 0;
3821 for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
3822 if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
3823 dptr = sim_dflt_dev;
3824 cptr = svptr;
3825 while (sim_isspace(*cptr))
3826 ++cptr;
3827 break;
3828 }
3829 }
3830 }
3831 if (!dptr)
3832 return SCPE_NXDEV;
3833 lvl = MTAB_VDV;
3834 uptr = dptr->units;
3835 }
3836 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
3837 return SCPE_2FARG;
3838 GET_SWITCHES (cptr);
3839
3840 while (*cptr != 0) {
3841 cptr = get_glyph (svptr = cptr, gbuf, ',');
3842 if (0 == strcmp (gbuf, ";"))
3843 break;
3844 if ((cvptr = strchr (gbuf, '=')))
3845 *cvptr++ = 0;
3846 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
3847 if ((mptr->mstring) &&
3848 (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
3849 if (mptr->mask & MTAB_XTD) {
3850 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
3851 return SCPE_ARG;
3852 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
3853 return SCPE_UDIS;
3854 if (mptr->valid) {
3855 if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
3856 svptr = get_glyph_quoted (svptr, gbuf, ',');
3857 if ((cvptr = strchr (gbuf, '='))) {
3858 *cvptr++ = 0;
3859 cptr = svptr;
3860 }
3861 }
3862 else {
3863 if (cvptr && MODMASK(mptr,MTAB_NC)) {
3864 (void)get_glyph_nc (svptr, gbuf, ',');
3865 if ((cvptr = strchr (gbuf, '=')))
3866 *cvptr++ = 0;
3867 }
3868 }
3869 r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
3870 if (r != SCPE_OK)
3871 return r;
3872 }
3873 else if (!mptr->desc)
3874 break;
3875 else if (cvptr)
3876 return SCPE_ARG;
3877 else *((int32 *) mptr->desc) = mptr->match;
3878 }
3879 else {
3880 if (cvptr)
3881 return SCPE_ARG;
3882 if (uptr->flags & UNIT_DIS)
3883 return SCPE_UDIS;
3884 if ((mptr->valid) &&
3885 ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
3886 return r;
3887 uptr->flags = (uptr->flags & ~(mptr->mask)) |
3888 (mptr->match & mptr->mask);
3889 }
3890 break;
3891 }
3892 }
3893 if (!mptr || (mptr->mask == 0)) {
3894 if ((glbr = find_c1tab (ctbr, gbuf))) {
3895 r = glbr->action (dptr, uptr, glbr->arg, cvptr);
3896 if (r != SCPE_OK)
3897 return r;
3898 }
3899 else if (!dptr->modifiers)
3900 return SCPE_NOPARAM;
3901 else return SCPE_NXPAR;
3902 }
3903 }
3904 return SCPE_OK;
3905 }
3906
3907
3908
3909 CTAB *find_ctab (CTAB *tab, const char *gbuf)
3910 {
3911 if (!tab)
3912 return NULL;
3913 for (; tab->name != NULL; tab++) {
3914 if (MATCH_CMD (gbuf, tab->name) == 0)
3915 return tab;
3916 }
3917 return NULL;
3918 }
3919
3920 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
3921 {
3922 if (!tab)
3923 return NULL;
3924 for (; tab->name != NULL; tab++) {
3925 if (MATCH_CMD (gbuf, tab->name) == 0)
3926 return tab;
3927 }
3928 return NULL;
3929 }
3930
3931
3932
3933 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3934 {
3935 if (cptr)
3936 return SCPE_ARG;
3937 dptr->dradix = flag & 037;
3938 return SCPE_OK;
3939 }
3940
3941
3942
3943 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3944 {
3945 UNIT *up;
3946 uint32 i;
3947
3948 if (cptr)
3949 return SCPE_ARG;
3950 if ((dptr->flags & DEV_DISABLE) == 0)
3951 return SCPE_NOFNC;
3952 if (flag) {
3953 if ((dptr->flags & DEV_DIS) == 0)
3954 return SCPE_OK;
3955 dptr->flags = dptr->flags & ~DEV_DIS;
3956 }
3957 else {
3958 if (dptr->flags & DEV_DIS)
3959 return SCPE_OK;
3960 for (i = 0; i < dptr->numunits; i++) {
3961 up = (dptr->units) + i;
3962 if ((up->flags & UNIT_ATT) || sim_is_active (up))
3963 return SCPE_NOFNC;
3964 }
3965 dptr->flags = dptr->flags | DEV_DIS;
3966 }
3967 if (dptr->reset)
3968 return dptr->reset (dptr);
3969 else return SCPE_OK;
3970 }
3971
3972
3973
3974 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3975 {
3976 if (cptr)
3977 return SCPE_ARG;
3978 if (!(uptr->flags & UNIT_DISABLE))
3979 return SCPE_NOFNC;
3980 if (flag)
3981 uptr->flags = uptr->flags & ~UNIT_DIS;
3982 else {
3983 if ((uptr->flags & UNIT_ATT) ||
3984 sim_is_active (uptr))
3985 return SCPE_NOFNC;
3986 uptr->flags = uptr->flags | UNIT_DIS;
3987 }
3988 return SCPE_OK;
3989 }
3990
3991
3992
3993 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
3994 {
3995 char gbuf[CBUFSIZE];
3996 DEBTAB *dep;
3997
3998 if ((dptr->flags & DEV_DEBUG) == 0)
3999 return SCPE_NOFNC;
4000 if (cptr == NULL) {
4001 dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;
4002 if (flag && dptr->debflags) {
4003 for (dep = dptr->debflags; dep->name != NULL; dep++)
4004 dptr->dctrl = dptr->dctrl | dep->mask;
4005 }
4006 return SCPE_OK;
4007 }
4008 if (dptr->debflags == NULL)
4009 return SCPE_ARG;
4010 while (*cptr) {
4011 cptr = get_glyph (cptr, gbuf, ';');
4012 for (dep = dptr->debflags; dep->name != NULL; dep++) {
4013 if (strcmp (dep->name, gbuf) == 0) {
4014 if (flag)
4015 dptr->dctrl = dptr->dctrl | dep->mask;
4016 else dptr->dctrl = dptr->dctrl & ~dep->mask;
4017 break;
4018 }
4019 }
4020 if (dep->mask == 0)
4021 return SCPE_ARG;
4022 }
4023 return SCPE_OK;
4024 }
4025
4026
4027
4028 t_stat show_cmd (int32 flag, CONST char *cptr)
4029 {
4030 t_stat r = SCPE_IERR;
4031
4032 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4033
4034 if (!cptr)
4035 return r;
4036 if (sim_ofile) {
4037 r = show_cmd_fi (sim_ofile, flag, cptr);
4038 fclose (sim_ofile);
4039 }
4040 else {
4041 r = show_cmd_fi (stdout, flag, cptr);
4042 if (sim_log && (sim_log != stdout))
4043 show_cmd_fi (sim_log, flag, cptr);
4044 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4045 show_cmd_fi (sim_deb, flag, cptr);
4046 }
4047 return r;
4048 }
4049
4050 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
4051 {
4052 uint32 lvl = 0xFFFFFFFF;
4053 char gbuf[CBUFSIZE], *cvptr;
4054 CONST char *svptr;
4055 DEVICE *dptr;
4056 UNIT *uptr;
4057 MTAB *mptr;
4058 SHTAB *shtb = NULL, *shptr;
4059
4060 GET_SWITCHES (cptr);
4061 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))
4062 return SCPE_2FARG;
4063 cptr = get_glyph (svptr = cptr, gbuf, 0);
4064
4065 if ((dptr = find_dev (gbuf))) {
4066 uptr = dptr->units;
4067 shtb = show_dev_tab;
4068 lvl = MTAB_VDV;
4069 GET_SWITCHES (cptr);
4070 }
4071 else if ((dptr = find_unit (gbuf, &uptr))) {
4072 if (uptr == NULL)
4073 return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\n", gbuf);
4074 if (uptr->flags & UNIT_DIS)
4075 return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", gbuf);
4076 shtb = show_unit_tab;
4077 lvl = MTAB_VUN;
4078 GET_SWITCHES (cptr);
4079 }
4080 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {
4081 GET_SWITCHES (cptr);
4082 return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4083 }
4084 else {
4085 if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4086 if ((cvptr = strchr (gbuf, '=')))
4087 *cvptr++ = 0;
4088 for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4089 if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4090 (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) ||
4091 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4092 dptr = sim_dflt_dev;
4093 lvl = MTAB_VDV;
4094 cptr = svptr;
4095 while (sim_isspace(*cptr))
4096 ++cptr;
4097 break;
4098 }
4099 }
4100 }
4101 if (!dptr) {
4102 if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))
4103 return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4104 else
4105 return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf);
4106 }
4107 }
4108
4109 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) {
4110 return (lvl == MTAB_VDV)?
4111 show_device (ofile, dptr, 0):
4112 show_unit (ofile, dptr, uptr, -1);
4113 }
4114 GET_SWITCHES (cptr);
4115
4116 while (*cptr != 0) {
4117 cptr = get_glyph (cptr, gbuf, ',');
4118 if ((cvptr = strchr (gbuf, '=')))
4119 *cvptr++ = 0;
4120 for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4121 if (((mptr->mask & MTAB_XTD)?
4122 ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4123 ((mptr->disp && mptr->pstring &&
4124 (MATCH_CMD (gbuf, mptr->pstring) == 0))
4125 )) {
4126 if (cvptr && !MODMASK(mptr,MTAB_SHP))
4127 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\n", gbuf, cvptr);
4128 show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4129 break;
4130 }
4131 }
4132 if (!mptr || (mptr->mask == 0)) {
4133 if (shtb && (shptr = find_shtab (shtb, gbuf))) {
4134 t_stat r;
4135
4136 r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4137 if (r != SCPE_OK)
4138 return r;
4139 }
4140 else {
4141 if (!dptr->modifiers)
4142 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\n", dptr->name);
4143 else
4144 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\n", gbuf);
4145 }
4146 }
4147 }
4148 return SCPE_OK;
4149 }
4150
4151 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
4152 {
4153 if (!tab)
4154 return NULL;
4155 for (; tab->name != NULL; tab++) {
4156 if (MATCH_CMD (gbuf, tab->name) == 0)
4157 return tab;
4158 }
4159 return NULL;
4160 }
4161
4162
4163
4164 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
4165 {
4166 uint32 j, udbl, ucnt;
4167 UNIT *uptr;
4168 int32 toks = 0;
4169
4170 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4171 fprintf (st, "%s", sim_dname (dptr));
4172 if ((flag == 2) && dptr->description) {
4173 fprintf (st, "\t%s\n", dptr->description(dptr));
4174 }
4175 else {
4176 if ((sim_switches & SWMASK ('D')) && dptr->description)
4177 fprintf (st, "\t%s\n", dptr->description(dptr));
4178 }
4179 if (qdisable (dptr)) {
4180 fprintf (st, "\tdisabled\n");
4181 return SCPE_OK;
4182 }
4183 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {
4184 uptr = dptr->units + j;
4185 if (!(uptr->flags & UNIT_DIS))
4186 ucnt++;
4187 else if (uptr->flags & UNIT_DISABLE)
4188 udbl++;
4189 }
4190
4191 if (dptr->numunits == 0) {
4192 if (toks)
4193 fprintf (st, "\n");
4194 }
4195 else {
4196 if (ucnt == 0) {
4197 fprint_sep (st, &toks);
4198 fprintf (st, "all units disabled\n");
4199 }
4200 else if ((ucnt + udbl) == 1) {
4201 fprint_sep (st, &toks);
4202 fprintf (st, " 1 unit\n");
4203 }
4204 else if ((ucnt > 1) || (udbl > 0)) {
4205 fprint_sep (st, &toks);
4206 fprintf (st, "%2.d units\n", ucnt + udbl);
4207 }
4208 else
4209 if ((flag != 2) || !dptr->description || toks)
4210 fprintf (st, "\n");
4211 toks = 0;
4212 }
4213 if (flag)
4214 return SCPE_OK;
4215 for (j = 0; j < dptr->numunits; j++) {
4216 uptr = dptr->units + j;
4217 if ((uptr->flags & UNIT_DIS) == 0)
4218 show_unit (st, dptr, uptr, ucnt + udbl);
4219 }
4220 }
4221 return SCPE_OK;
4222 }
4223
4224 void fprint_sep (FILE *st, int32 *tokens)
4225 {
4226 fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4227 *tokens += 1;
4228 }
4229
4230 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
4231 {
4232 int32 u = (int32)(uptr - dptr->units);
4233 int32 toks = 0;
4234
4235 if (flag > 1)
4236 fprintf (st, " %s%d \n", sim_dname (dptr), u);
4237 else if (flag < 0)
4238 fprintf (st, " %s%d ", sim_dname (dptr), u);
4239 if (uptr->flags & UNIT_ATT) {
4240 fprint_sep (st, &toks);
4241 fprintf (st, "status : attached to %s", uptr->filename);
4242 if (uptr->flags & UNIT_RO)
4243 fprintf (st, ", read only");
4244 }
4245 else {
4246 if (uptr->flags & UNIT_ATTABLE) {
4247 fprint_sep (st, &toks);
4248 fprintf (st, "status : not attached");
4249 }
4250 }
4251 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4252 fprint_sep (st, &toks);
4253 fprint_capac (st, dptr, uptr);
4254 }
4255 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);
4256 if (toks || (flag < 0) || (flag > 1))
4257 fprintf (st, "\n");
4258 return SCPE_OK;
4259 }
4260
4261 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
4262 {
4263 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4264 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4265 t_offset mval;
4266 t_offset psize = (t_offset)uptr->capac;
4267 char *scale, *width;
4268
4269 if (sim_switches & SWMASK ('B'))
4270 kval = 1024;
4271 mval = kval * kval;
4272 if (dptr->flags & DEV_SECTORS) {
4273 kval = kval / 512;
4274 mval = mval / 512;
4275 }
4276 if ((dptr->dwidth / dptr->aincr) > 8)
4277 width = "W";
4278 else
4279 width = "B";
4280 if ((psize < (kval * 10)) &&
4281 (0 != (psize % kval))) {
4282 scale = "";
4283 }
4284 else if ((psize < (mval * 10)) &&
4285 (0 != (psize % mval))){
4286 scale = "K";
4287 psize = psize / kval;
4288 }
4289 else {
4290 scale = "M";
4291 psize = psize / mval;
4292 }
4293 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4294 sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4295 return capac_buf;
4296 }
4297
4298 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
4299 {
4300 fprintf (st, " %s", sprint_capac (dptr, uptr));
4301 }
4302
4303
4304
4305 extern void print_default_base_system_script (void);
4306 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4307 {
4308 #ifndef PERF_STRIP
4309 print_default_base_system_script();
4310 #endif
4311 return 0;
4312 }
4313
4314 static void printp (unsigned char * PROM, char * label, int offset, int length) {
4315 sim_printf (" %s '", label);
4316 for (int l = 0; l < length; l ++) {
4317 unsigned int byte = PROM[offset + l];
4318 sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4319 }
4320 sim_printf ("'\r\n");
4321 }
4322
4323 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4324 {
4325 unsigned char PROM[1024];
4326 setupPROM (0, PROM);
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342 printp (PROM, "CPU Model: ", 0, 11);
4343 printp (PROM, "CPU Serial: ", 11, 11);
4344 printp (PROM, "Ship Date: ", 22, 6);
4345 return 0;
4346 }
4347
4348 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4349 {
4350 fprintf (st, "\r\n\r Build Information:\n");
4351 #if defined(BUILDINFO_scp) && defined(SYSDEFS_USED)
4352 fprintf (st, "\r\n Compilation info: %s\n", BUILDINFO_scp );
4353 # ifndef __OPEN64__
4354 fprintf (st, "\r\n Relevant definitions: %s\n", SYSDEFS_USED );
4355 # endif
4356 #elif defined(BUILDINFO_scp)
4357 fprintf (st, "\r\n Compilation info: %s\n", BUILDINFO_scp );
4358 #else
4359 fprintf (st, "\r\n Compilation info: Not available\n" );
4360 #endif
4361 #if defined (UV_VERSION_MAJOR) && \
4362 defined (UV_VERSION_MINOR) && \
4363 defined (UV_VERSION_PATCH)
4364 # ifdef UV_VERSION_MAJOR
4365 # ifndef UV_VERSION_MINOR
4366 # ifndef UV_VERSION_PATCH
4367 # ifndef UV_VERSION_SUFFIX
4368 fprintf (st, "\r\n Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4369 # endif
4370 # endif
4371 # endif
4372 # ifdef UV_VERSION_MINOR
4373 # ifndef UV_VERSION_PATCH
4374 # ifndef UV_VERSION_SUFFIX
4375 fprintf (st, "\r\n Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4376 UV_VERSION_MINOR);
4377 # endif
4378 # endif
4379 # ifdef UV_VERSION_PATCH
4380 # ifndef UV_VERSION_SUFFIX
4381 fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4382 UV_VERSION_MINOR, UV_VERSION_PATCH);
4383 # endif
4384 # ifdef UV_VERSION_SUFFIX
4385 fprintf (st, "\r\n Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4386 UV_VERSION_MINOR, UV_VERSION_PATCH);
4387 # ifdef UV_VERSION_IS_RELEASE
4388 # if UV_VERSION_IS_RELEASE == 1
4389 # define UV_RELEASE_TYPE " (release)"
4390 # endif
4391 # if UV_VERSION_IS_RELEASE == 0
4392 # define UV_RELEASE_TYPE "-dev"
4393 # endif
4394 # ifndef UV_RELEASE_TYPE
4395 # define UV_RELEASE_TYPE ""
4396 # endif
4397 # ifdef UV_RELEASE_TYPE
4398 fprintf (st, "%s", UV_RELEASE_TYPE);
4399 # endif
4400 # endif
4401 # endif
4402 # endif
4403 # endif
4404 unsigned int CurrentUvVersion = uv_version();
4405 if (CurrentUvVersion > 0)
4406 if (uv_version_string() != NULL)
4407 fprintf (st, "; %s in use", uv_version_string());
4408 # endif
4409 #else
4410 fprintf (st, "\r\n Event loop library: Using libuv (or compatible) library, unknown version");
4411 #endif
4412
4413
4414
4415 #ifdef DECNUMBERLOC
4416 # ifdef DECVERSION
4417 # ifdef DECVERSEXT
4418 fprintf (st, "\r\n Math library: %s-%s", DECVERSION, DECVERSEXT);
4419 # else
4420 # ifdef DECNLAUTHOR
4421 fprintf (st, "\r\n Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4422 # else
4423 fprintf (st, "\r\n Math library: %s", DECVERSION);
4424 # endif
4425 # endif
4426 # else
4427 fprintf (st, "\r\n Math library: decNumber, unknown version");
4428 # endif
4429 #endif
4430 #ifdef LOCKLESS
4431 fprintf (st, "\r\n Atomic operations: ");
4432 # if defined(AIX_ATOMICS)
4433 fprintf (st, "IBM AIX-style");
4434 # elif defined(BSD_ATOMICS)
4435 fprintf (st, "FreeBSD-style");
4436 # elif defined(GNU_ATOMICS)
4437 fprintf (st, "GNU-style");
4438 # elif defined(SYNC_ATOMICS)
4439 fprintf (st, "GNU sync-style");
4440 # elif defined(ISO_ATOMICS)
4441 fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4442 # elif defined(NT_ATOMICS)
4443 fprintf (st, "Windows NT interlocked operations");
4444 # endif
4445 #endif
4446 fprintf (st, "\r\n File locking: ");
4447 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4448 fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4449 #endif
4450 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4451 fprintf (st, "POSIX-style fcntl() locking");
4452 #endif
4453 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4454 fprintf (st, "BSD-style flock() locking");
4455 #endif
4456 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4457 fprintf (st, "No file locking available");
4458 #endif
4459 #if defined(USE_BACKTRACE)
4460 fprintf (st, "\r\n Backtrace support: ");
4461 fprintf (st, "libbacktrace");
4462 #endif
4463 fprintf (st, "\r\n");
4464 return 0;
4465 }
4466
4467 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4468 {
4469 const char *arch = "";
4470 int dirty = 0;
4471
4472 if (cptr && (*cptr != 0))
4473 return SCPE_2MARG;
4474 if (flag) {
4475 fprintf (st, " %s Simulator:", sim_name);
4476 #if defined(USE_DUMA)
4477 # undef NO_SUPPORT_VERSION
4478 # define NO_SUPPORT_VERSION 1
4479 nodist++;
4480 #endif
4481 #if defined(NO_SUPPORT_VERSION) || \
4482 defined(TESTING) || \
4483 defined(ISOLTS) || \
4484 defined(USE_DUMA)
4485 # ifndef NO_SUPPORT_VERSION
4486 # define NO_SUPPORT_VERSION 1
4487 # endif
4488 #endif
4489 #if defined(NO_SUPPORT_VERSION)
4490 dirty++;
4491 #endif
4492 #if defined(GENERATED_MAKE_VER_H)
4493 # if defined(VER_H_GIT_VERSION)
4494
4495
4496 if (strstr(VER_H_GIT_VERSION, "*"))
4497 {
4498 dirty++;
4499 }
4500
4501
4502 if (strstr(VER_H_GIT_VERSION, "+"))
4503 {
4504 dirty++;
4505 }
4506
4507
4508 if ((strstr(VER_H_GIT_VERSION, "Z")) || \
4509 (strstr(VER_H_GIT_VERSION, "D")) || \
4510 (strstr(VER_H_GIT_VERSION, "A")) || \
4511 (strstr(VER_H_GIT_VERSION, "B"))) {
4512 dirty++;
4513 }
4514 # if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
4515 # if defined(VER_H_GIT_HASH)
4516 # if VER_H_GIT_PATCH_INT < 1
4517 fprintf (st, "\n Version: %s (%ld-bit)\n Commit: %s",
4518 VER_H_GIT_VERSION,
4519 (long)(CHAR_BIT*sizeof(void *)),
4520 VER_H_GIT_HASH);
4521 # else
4522 # define NO_SUPPORT_VERSION 1
4523 fprintf (st, "\n Version: %s+%s (%ld-bit)\n Commit: %s",
4524 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
4525 (long)(CHAR_BIT*sizeof(void *)),
4526 VER_H_GIT_HASH);
4527 # endif
4528 # else
4529 # if VER_H_GIT_PATCH_INT < 1
4530 fprintf (st, "\n Version: %s (%ld-bit)",
4531 VER_H_GIT_VERSION,
4532 (long)(CHAR_BIT*sizeof(void *)));
4533 # else
4534 # define NO_SUPPORT_VERSION 1
4535 fprintf (st, "\n Version: %s+%s (%ld-bit)",
4536 VER_H_GIT_VERSION, VER_H_GIT_PATCH,
4537 (long)(CHAR_BIT*sizeof(void *)));
4538 # endif
4539 # endif
4540 # else
4541 # if defined(VER_H_GIT_HASH)
4542 fprintf (st, "\n Version: %s (%ld-bit)\n Commit: %s",
4543 VER_H_GIT_VERSION,
4544 (long)(CHAR_BIT*sizeof(void *)),
4545 VER_H_GIT_HASH);
4546 # else
4547 fprintf (st, "\n Version: %s (%ld-bit)",
4548 VER_H_GIT_VERSION,
4549 (long)(CHAR_BIT*sizeof(void *)));
4550 # endif
4551 # endif
4552 # endif
4553 #endif
4554 #ifdef TESTING
4555 fprintf (st, "\n Options: ");
4556 # ifndef HAVE_DPSOPT
4557 # define HAVE_DPSOPT 1
4558 # endif
4559 fprintf (st, "TESTING");
4560 #endif
4561 #ifdef ISOLTS
4562 # ifdef HAVE_DPSOPT
4563 fprintf (st, ", ");
4564 # else
4565 fprintf (st, "\n Options: ");
4566 # endif
4567 # ifndef HAVE_DPSOPT
4568 # define HAVE_DPSOPT 1
4569 # endif
4570 fprintf (st, "ISOLTS");
4571 #endif
4572 #ifdef NEED_128
4573 # ifdef HAVE_DPSOPT
4574 fprintf (st, ", ");
4575 # else
4576 fprintf (st, "\n Options: ");
4577 # endif
4578 # ifndef HAVE_DPSOPT
4579 # define HAVE_DPSOPT 1
4580 # endif
4581 fprintf (st, "NEED_128");
4582 #endif
4583 #ifdef WAM
4584 # ifdef HAVE_DPSOPT
4585 fprintf (st, ", ");
4586 # else
4587 fprintf (st, "\n Options: ");
4588 # endif
4589 # ifndef HAVE_DPSOPT
4590 # define HAVE_DPSOPT 1
4591 # endif
4592 fprintf (st, "WAM");
4593 #endif
4594 #ifdef ROUND_ROBIN
4595 # ifdef HAVE_DPSOPT
4596 fprintf (st, ", ");
4597 # else
4598 fprintf (st, "\n Options: ");
4599 # endif
4600 # ifndef HAVE_DPSOPT
4601 # define HAVE_DPSOPT 1
4602 # endif
4603 fprintf (st, "ROUND_ROBIN");
4604 #endif
4605 #ifndef LOCKLESS
4606 # ifdef HAVE_DPSOPT
4607 fprintf (st, ", ");
4608 # else
4609 fprintf (st, "\n Options: ");
4610 # endif
4611 # ifndef HAVE_DPSOPT
4612 # define HAVE_DPSOPT 1
4613 # endif
4614 fprintf (st, "NO_LOCKLESS");
4615 #endif
4616 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
4617 # if defined(NO_SUPPORT_VERSION)
4618 fprintf (st, "\n Modified: %s", VER_H_GIT_DATE);
4619 # else
4620 fprintf (st, "\n Released: %s", VER_H_GIT_DATE);
4621 # endif
4622 #endif
4623 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
4624 fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
4625 #endif
4626 #ifdef VER_CURRENT_TIME
4627 fprintf (st, "\n Compiled: %s", VER_CURRENT_TIME);
4628 #endif
4629 if (dirty)
4630 {
4631 fprintf (st, "\r\n\r\n ****** THIS BUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******");
4632 }
4633 fprintf (st, "\r\n\r\n Build Information:");
4634 #if defined (BUILD_PROM_OSV_TEXT) && defined (BUILD_PROM_OSA_TEXT)
4635 char build_os_version_raw[255];
4636 char build_os_arch_raw[255];
4637 sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
4638 sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
4639 char *build_os_version = strdup(build_os_version_raw);
4640 if (!build_os_version)
4641 {
4642 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4643 __func__, __FILE__, __LINE__);
4644 # if defined(USE_BACKTRACE)
4645 # ifdef SIGUSR2
4646 (void)raise(SIGUSR2);
4647
4648 # endif
4649 # endif
4650 abort();
4651 }
4652 char *build_os_arch = strdup(build_os_arch_raw);
4653 if (!build_os_arch)
4654 {
4655 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4656 __func__, __FILE__, __LINE__);
4657 # if defined(USE_BACKTRACE)
4658 # ifdef SIGUSR2
4659 (void)raise(SIGUSR2);
4660
4661 # endif
4662 # endif
4663 abort();
4664 }
4665 strtrimspace(build_os_version, build_os_version_raw);
4666 strtrimspace(build_os_arch, build_os_arch_raw);
4667 fprintf (st, "\n Build OS: %s %s", build_os_version, build_os_arch);
4668 FREE(build_os_version);
4669 FREE(build_os_arch);
4670 #endif
4671 #if defined (__VERSION__)
4672 char gnumver[2];
4673 char postver[1024];
4674 sprintf(gnumver, "%.1s", __VERSION__);
4675 sprintf(postver, "%.1023s", __VERSION__);
4676 strremove(postver, "(TM)");
4677 strremove(postver, "(R)");
4678 strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
4679 strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
4680 strremove(postver, "4.2.1 Compatible ");
4681 strremove(postver, "git@github.com:llvm/llvm-project.git ");
4682 strremove(postver, "https://github.com/llvm/llvm-project.git ");
4683 strremove(postver, " (https://github.com/yrnkrn/zapcc)");
4684 strremove(postver, "https://github.com/yrnkrn/zapcc ");
4685 #endif
4686 #if ( defined (__GNUC__) && defined (__VERSION__) ) && !defined (__EDG__)
4687 # ifndef __clang_version__
4688 if (isdigit((unsigned char)gnumver[0])) {
4689 fprintf (st, "\n Compiler: GCC %s", postver);
4690 } else {
4691 fprintf (st, "\n Compiler: %s", postver);
4692 }
4693 # endif
4694 # if defined (__clang_analyzer__ )
4695 fprintf (st, "\n Compiler: Clang C/C++ Static Analyzer");
4696 # elif defined (__clang_version__) && defined (__VERSION__)
4697 char clangllvmver[1024];
4698 sprintf(clangllvmver, "%.1023s", __clang_version__);
4699 strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
4700 strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
4701 if (gnumver[0] == 'c' || gnumver[0] == 'C') {
4702 fprintf (st, "\n Compiler: Clang %s", clangllvmver);
4703 } else {
4704 fprintf (st, "\n Compiler: %s", postver);
4705 }
4706 # elif defined (__clang_version__)
4707 fprintf (st, "\n Compiler: %s", postver);
4708 # endif
4709 #elif defined (__PGI) && !defined(__NVCOMPILER)
4710 fprintf (st, "\n Compiler: Portland Group, Inc. (PGI) C Compiler ");
4711 # ifdef __PGIC__
4712 fprintf (st, "%d", __PGIC__);
4713 # ifdef __PGIC_MINOR__
4714 fprintf (st, ".%d", __PGIC_MINOR__);
4715 # ifdef __PGIC_PATCHLEVEL__
4716 fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
4717 # endif
4718 # endif
4719 # endif
4720 #elif defined(__NVCOMPILER)
4721 fprintf (st, "\n Compiler: NVIDIA HPC SDK C Compiler ");
4722 # ifdef __NVCOMPILER_MAJOR__
4723 fprintf (st, "%d", __NVCOMPILER_MAJOR__);
4724 # ifdef __NVCOMPILER_MINOR__
4725 fprintf (st, ".%d", __NVCOMPILER_MINOR__);
4726 # ifdef __NVCOMPILER_PATCHLEVEL__
4727 fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
4728 # endif
4729 # endif
4730 # endif
4731 #elif defined (_MSC_FULL_VER) && defined (_MSC_BUILD)
4732 fprintf (st, "\n Compiler: Microsoft C %d.%02d.%05d.%02d",
4733 _MSC_FULL_VER/10000000,
4734 (_MSC_FULL_VER/100000)%100,
4735 _MSC_FULL_VER%100000,
4736 _MSC_BUILD);
4737 #elif ( defined (__xlc__) && !defined(__clang_version__) )
4738 # if defined (_AIX) && defined (PASE)
4739 fprintf (st, "\n Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
4740 # endif
4741 # if defined (_AIX) && !defined (PASE)
4742 fprintf (st, "\n Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
4743 # endif
4744 # if defined (__linux__) && ( !defined(_AIX) || !defined(PASE) )
4745 fprintf (st, "\n Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
4746 # endif
4747 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(PASE) && !defined(__linux__) && defined(__xlc__) )
4748 fprintf (st, "\n Compiler: IBM XL C/C++ V%s", __xlc__);
4749 # endif
4750 #elif defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__SUNPRO_CC_COMPAT)
4751 fprintf (st, "\n Compiler: Oracle Developer Studio C/C++");
4752 #elif defined (__DMC__)
4753 fprintf (st, "\n Compiler: Digital Mars C/C++");
4754 #elif defined (__PCC__)
4755 fprintf (st, "\n Compiler: Portable C Compiler");
4756 #elif defined (KENC) || defined (KENCC) || defined (__KENC__) || defined (__KENCC__)
4757 fprintf (st, "\n Compiler: Plan 9 Compiler Suite");
4758 #elif defined (__ACK__)
4759 fprintf (st, "\n Compiler: Amsterdam Compiler Kit");
4760 #elif defined (__COMO__)
4761 fprintf (st, "\n Compiler: Comeau C++");
4762 #elif defined (__COMPCERT__)
4763 fprintf (st, "\n Compiler: CompCert C");
4764 #elif defined (__COVERITY__)
4765 fprintf (st, "\n Compiler: Coverity C/C++ Static Analyzer");
4766 #elif defined (__LCC__)
4767 fprintf (st, "\n Compiler: Local C Compiler (lcc)");
4768 #elif defined (sgi) || defined (__sgi) || defined (_sgi) || defined (_SGI_COMPILER_VERSION)
4769 fprintf (st, "\n Compiler: SGI MIPSpro");
4770 #elif defined (__OPEN64__)
4771 fprintf (st, "\n Compiler: Open64 %s", __OPEN64__);
4772 #elif defined (__PGI) || defined (__PGIC__)
4773 fprintf (st, "\n Compiler: Portland Group/PGI C/C++");
4774 #elif defined (__VBCC__)
4775 fprintf (st, "\n Compiler: Volker Barthelmann C Compiler (vbcc)");
4776 #elif defined (__WATCOMC__)
4777 fprintf (st, "\n Compiler: Watcom C/C++ %d.%d",
4778 __WATCOMC__ / 100,
4779 __WATCOMC__ % 100);
4780 #elif defined (__xlC__)
4781 fprintf (st, "\n Compiler: IBM XL C/C++");
4782 #elif defined (SIM_COMPILER)
4783 # define S_xstr(a) S_str(a)
4784 # define S_str(a) #a
4785 fprintf (st, "\n Compiler: %s", S_xstr(SIM_COMPILER));
4786 # undef S_str
4787 # undef S_xstr
4788 #else
4789 fprintf (st, "\n Compiler: Unknown");
4790 #endif
4791 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
4792 arch = " x86_64";
4793 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
4794 arch = " x86";
4795 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
4796 arch = " arm64";
4797 #elif defined(_M_ARM) || defined(__arm__)
4798 arch = " arm";
4799 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
4800 arch = " ia64";
4801 #elif defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
4802 # if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
4803 arch = " ppc64be";
4804 # else
4805 arch = " ppc64el";
4806 # endif
4807 #elif defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || defined(__PPC32)
4808 # if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
4809 arch = " ppc";
4810 # else
4811 arch = " ppcel";
4812 # endif
4813 #elif defined(__s390x__)
4814 arch = " s390x";
4815 #elif defined(__s390__)
4816 arch = " s390";
4817 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
4818 arch = " j2";
4819 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
4820 arch = " sh4";
4821 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
4822 arch = " sh2";
4823 #elif defined(__alpha__)
4824 arch = " alpha";
4825 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
4826 arch = " hppa";
4827 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
4828 arch = " ice9";
4829 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
4830 # if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
4831 arch = " mips64be";
4832 # else
4833 arch = " mips64el";
4834 # endif
4835 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
4836 # if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
4837 arch = " mipsbe";
4838 # else
4839 arch = " mipsel";
4840 # endif
4841 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
4842 arch = " openrisc";
4843 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
4844 arch = " sparc64";
4845 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
4846 arch = " sparc";
4847 #elif defined(__riscv) || defined(__riscv__)
4848 arch = " riscv";
4849 #elif defined(__myriad2__)
4850 arch = " myriad2";
4851 #else
4852 arch = " ";
4853 #endif
4854 fprintf (st, "%s", arch);
4855 #if defined(BUILD_BY_USER)
4856 fprintf (st, "\n Built by: %s", BUILD_BY_USER);
4857 #else
4858 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
4859 fprintf (st, "\n Built by: %s", VER_H_PREP_USER);
4860 # endif
4861 #endif
4862 fprintf (st, "\n\n Host System Information:");
4863 #if defined(_WIN32)
4864 if (1) {
4865 char *arch = getenv ("PROCESSOR_ARCHITECTURE");
4866 char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
4867 char osversion[PATH_MAX+1] = "";
4868 FILE *f;
4869
4870 if ((f = _popen ("ver", "r"))) {
4871 memset (osversion, 0, sizeof(osversion));
4872 do {
4873 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
4874 break;
4875 sim_trim_endspc (osversion);
4876 } while (osversion[0] == '\0');
4877 _pclose (f);
4878 }
4879 fprintf (st, "\n Host OS: %s", osversion);
4880 fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "");
4881 }
4882 #else
4883 if (1) {
4884 char osversion[2*PATH_MAX+1] = "";
4885 FILE *f;
4886 # ifndef _AIX
4887 if ((f = popen ("uname -mrs 2> /dev/null", "r"))) {
4888 # else
4889 if ((f = popen \
4890 ("sh -c 'command -p env uname -svM 2> /dev/null' \
4891 2> /dev/null || \
4892 /bin/sh -c 'command -p env uname -svM \
4893 2> /dev/null' \
4894 2> /dev/null || \
4895 uname -svM 2> /dev/null || \
4896 sh -c 'command -p env uname -svp \
4897 2> /dev/null' \
4898 2> /dev/null || \
4899 /bin/sh -c 'command -p env uname -svp \
4900 2> /dev/null' \
4901 2> /dev/null || \
4902 uname -svp 2> /dev/null \
4903 ", "r"))) \
4904 {
4905 # endif
4906 memset (osversion, 0, sizeof(osversion));
4907 do {
4908 if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
4909 break;
4910 }
4911 sim_trim_endspc (osversion);
4912 } while (osversion[0] == '\0');
4913 pclose (f);
4914 strremove(osversion, "0000000000000000 ");
4915 strremove(osversion, " 0000000000000000");
4916 strremove(osversion, "000000000000 ");
4917 strremove(osversion, " 000000000000");
4918 strremove(osversion, "IBM ");
4919 strremove(osversion, " (emulated by qemu)");
4920 strremove(osversion, " (emulated by QEMU)");
4921 }
4922 # ifndef _AIX
4923 fprintf (st, "\n Host OS: %s", osversion);
4924 # else
4925 strremove(osversion, "AIX ");
4926 fprintf (st, "\n Host OS: IBM AIX %s", osversion);
4927 # endif
4928 } else {
4929 # ifndef _AIX
4930 fprintf (st, "\n Host OS: Unknown");
4931 # else
4932 fprintf (st, "\n Host OS: IBM AIX");
4933 # endif
4934 }
4935 #endif
4936 #if defined(__APPLE__)
4937 int isRosetta = processIsTranslated();
4938 if (isRosetta == 1) {
4939 sim_printf ("\n\n ****** RUNNING UNDER APPLE ROSETTA 2, EXPECT REDUCED PERFORMANCE ******");
4940 }
4941 #endif
4942 if (nodist)
4943 {
4944 sim_printf ("\n\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\n");
4945 }
4946 else
4947 {
4948 fprintf (st, "\n");
4949 fprintf (st, "\n This software is made available under the terms of the ICU License,");
4950 fprintf (st, "\n version 1.8.1 or later. For complete details, see the \"LICENSE.md\"");
4951 fprintf (st, "\n included or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
4952 }
4953 fprintf (st, "\n");
4954 }
4955 return SCPE_OK;
4956 }
4957
4958 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
4959 {
4960 int32 i;
4961 DEVICE *dptr;
4962 t_bool only_enabled = (sim_switches & SWMASK ('E'));
4963
4964 if (cptr && (*cptr != 0))
4965 return SCPE_2MARG;
4966 fprintf (st, "%s simulator configuration%s\n\n", sim_name, only_enabled ? " (enabled devices)" : "");
4967 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
4968 if (!only_enabled || !qdisable (dptr))
4969 show_device (st, dptr, flag);
4970 return SCPE_OK;
4971 }
4972
4973 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
4974 {
4975 int32 i;
4976 DEVICE *dptr;
4977
4978 if (cptr && (*cptr != 0))
4979 return SCPE_2MARG;
4980 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
4981 show_dev_logicals (st, dptr, NULL, 1, cptr);
4982 return SCPE_OK;
4983 }
4984
4985 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
4986 {
4987 if (dptr->lname)
4988 fprintf (st, "%s -> %s\n", dptr->lname, dptr->name);
4989 else if (!flag)
4990 fputs ("no logical name assigned\n", st);
4991 return SCPE_OK;
4992 }
4993
4994 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
4995 {
4996 DEVICE *dptr;
4997 UNIT *uptr;
4998 int32 accum;
4999
5000 if (cptr && (*cptr != 0))
5001 return SCPE_2MARG;
5002 if (sim_clock_queue == QUEUE_LIST_END)
5003 fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\n",
5004 sim_name, sim_time, sim_timer_inst_per_sec ());
5005 else {
5006 const char *tim;
5007
5008 fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\n",
5009 sim_name, sim_time, sim_timer_inst_per_sec ());
5010 accum = 0;
5011 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5012 if (uptr == &sim_step_unit)
5013 fprintf (st, " Step timer");
5014 else
5015 if (uptr == &sim_expect_unit)
5016 fprintf (st, " Expect fired");
5017 else
5018 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5019 fprintf (st, " %s", sim_dname (dptr));
5020 if (dptr->numunits > 1)
5021 fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5022 }
5023 else
5024 fprintf (st, " Unknown");
5025 tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5026 fprintf (st, " at %d%s%s%s%s\n", accum + uptr->time,
5027 (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5028 (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5029 accum = accum + uptr->time;
5030 }
5031 }
5032 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5033 return SCPE_OK;
5034 }
5035
5036 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5037 {
5038 if (cptr && (*cptr != 0))
5039 return SCPE_2MARG;
5040 fprintf (st, "Time:\t%.0f\n", sim_gtime());
5041 return SCPE_OK;
5042 }
5043
5044 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5045 {
5046 t_stat r;
5047
5048 if (cptr && (*cptr != 0))
5049 r = ssh_break (st, cptr, 1);
5050 else
5051 r = sim_brk_showall (st, sim_switches);
5052 return r;
5053 }
5054
5055 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5056 {
5057 fprintf (st, "Radix=%d\n", dptr->dradix);
5058 return SCPE_OK;
5059 }
5060
5061 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5062 {
5063 int32 any = 0;
5064 DEBTAB *dep;
5065
5066 if (dptr->flags & DEV_DEBUG) {
5067 if (dptr->dctrl == 0)
5068 fputs ("Debugging disabled", st);
5069 else if (dptr->debflags == NULL)
5070 fputs ("Debugging enabled", st);
5071 else {
5072 uint32 dctrl = dptr->dctrl;
5073
5074 fputs ("Debug=", st);
5075 for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5076 if ((dctrl & dep->mask) == dep->mask) {
5077 dctrl &= ~dep->mask;
5078 if (any)
5079 fputc (';', st);
5080 fputs (dep->name, st);
5081 any = 1;
5082 }
5083 }
5084 }
5085 fputc ('\n', st);
5086 return SCPE_OK;
5087 }
5088 else return SCPE_NOFNC;
5089 }
5090
5091
5092
5093 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5094 {
5095 int32 lvl, i;
5096
5097 if (cptr && (*cptr != 0)) return SCPE_2MARG;
5098 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5099 if (lvl > 0)
5100 fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5101 else
5102 fprintf(st, "On Processing for input commands");
5103 fprintf(st, " is %s\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5104 for (i=1; i<SCPE_BASE; ++i) {
5105 if (sim_on_actions[lvl][i])
5106 fprintf(st, " on %5d %s\n", i, sim_on_actions[lvl][i]); }
5107 for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5108 if (sim_on_actions[lvl][i])
5109 fprintf(st, " on %-5s %s\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5110 if (sim_on_actions[lvl][0])
5111 fprintf(st, " on ERROR %s\n", sim_on_actions[lvl][0]);
5112 fprintf(st, "\n");
5113 }
5114 if (sim_on_inherit)
5115 fprintf(st, "on state and actions are inherited by nested do commands and subroutines\n");
5116 return SCPE_OK;
5117 }
5118
5119
5120
5121 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5122 {
5123 int32 i;
5124 DEVICE *dptr;
5125
5126 if (cptr && (*cptr != 0))
5127 return SCPE_2MARG;
5128 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5129 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5130 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5131 show_dev_modifiers (st, dptr, NULL, flag, cptr);
5132 return SCPE_OK;
5133 }
5134
5135 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5136 {
5137 fprint_set_help (st, dptr);
5138 return SCPE_OK;
5139 }
5140
5141 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
5142 {
5143 MTAB *mptr;
5144 t_stat r = SCPE_OK;
5145
5146 if (dptr->modifiers == NULL)
5147 return SCPE_OK;
5148 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5149 if (mptr->pstring &&
5150 ((mptr->mask & MTAB_XTD)?
5151 (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5152 ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5153 if (*toks > 0) {
5154 fprintf (st, "\n");
5155 *toks = 0;
5156 }
5157 if (r == SCPE_OK)
5158 fprint_sep (st, toks);
5159 r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5160 }
5161 }
5162 return SCPE_OK;
5163 }
5164
5165 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
5166 CONST char *cptr, int32 flag)
5167 {
5168 t_stat r = SCPE_OK;
5169
5170 if (mptr->disp)
5171 r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5172 else
5173 fputs (mptr->pstring, st);
5174 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5175 fputc ('\n', st);
5176 return r;
5177 }
5178
5179
5180
5181 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
5182 {
5183 int32 i;
5184 DEVICE *dptr;
5185
5186 if (cptr && (*cptr != 0))
5187 return SCPE_2MARG;
5188 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5189 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5190 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5191 show_dev_show_commands (st, dptr, NULL, flag, cptr);
5192 return SCPE_OK;
5193 }
5194
5195 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
5196 {
5197 fprint_show_help (st, dptr);
5198 return SCPE_OK;
5199 }
5200
5201
5202
5203 t_stat brk_cmd (int32 flg, CONST char *cptr)
5204 {
5205 GET_SWITCHES (cptr);
5206 return ssh_break (NULL, cptr, flg);
5207 }
5208
5209 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
5210 {
5211 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5212 CONST char *tptr, *t1ptr;
5213 DEVICE *dptr = sim_dflt_dev;
5214 UNIT *uptr;
5215 t_stat r;
5216 t_addr lo, hi, max;
5217 int32 cnt;
5218
5219 if (sim_brk_types == 0)
5220 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5221 if (dptr == NULL)
5222 return SCPE_IERR;
5223 uptr = dptr->units;
5224 if (uptr == NULL)
5225 return SCPE_IERR;
5226 max = uptr->capac - 1;
5227 abuf[sizeof(abuf)-1] = '\0';
5228 strncpy (abuf, cptr, sizeof(abuf)-1);
5229 cptr = abuf;
5230 if ((aptr = strchr (abuf, ';'))) {
5231 if (flg != SSH_ST)
5232 return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", aptr);
5233 *aptr++ = 0;
5234 }
5235 if (*cptr == 0) {
5236 lo = (t_addr) get_rval (sim_PC, 0);
5237 return ssh_break_one (st, flg, lo, 0, aptr);
5238 }
5239 while (*cptr) {
5240 cptr = get_glyph (cptr, gbuf, ',');
5241 tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5242 if (tptr == NULL)
5243 return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\n", gbuf);
5244 if (*tptr == '[') {
5245 cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5246 if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5247 return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\n", tptr + 1);
5248 tptr = t1ptr + 1;
5249 }
5250 else cnt = 0;
5251 if (*tptr != 0)
5252 return sim_messagef (SCPE_ARG, "Unexpected argument: %s\n", tptr);
5253 if ((lo == 0) && (hi == max)) {
5254 if (flg == SSH_CL)
5255 sim_brk_clrall (sim_switches);
5256 else
5257 if (flg == SSH_SH)
5258 sim_brk_showall (st, sim_switches);
5259 else
5260 return SCPE_ARG;
5261 }
5262 else {
5263 for ( ; lo <= hi; lo = lo + 1) {
5264 r = ssh_break_one (st, flg, lo, cnt, aptr);
5265 if (r != SCPE_OK)
5266 return r;
5267 }
5268 }
5269 }
5270 return SCPE_OK;
5271 }
5272
5273 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
5274 {
5275 if (!sim_brk_types)
5276 return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5277 switch (flg) {
5278
5279 case SSH_ST:
5280 return sim_brk_set (lo, sim_switches, cnt, aptr);
5281
5282 break;
5283
5284 case SSH_CL:
5285 return sim_brk_clr (lo, sim_switches);
5286
5287 break;
5288
5289 case SSH_SH:
5290 return sim_brk_show (st, lo, sim_switches);
5291
5292 break;
5293
5294 default:
5295 return SCPE_ARG;
5296 }
5297 }
5298
5299
5300
5301 static t_bool run_cmd_did_reset = FALSE;
5302
5303 t_stat reset_cmd (int32 flag, CONST char *cptr)
5304 {
5305 char gbuf[CBUFSIZE];
5306 DEVICE *dptr;
5307
5308 GET_SWITCHES (cptr);
5309 run_cmd_did_reset = FALSE;
5310 if (*cptr == 0)
5311 return (reset_all (0));
5312 cptr = get_glyph (cptr, gbuf, 0);
5313 if (*cptr != 0)
5314 return SCPE_2MARG;
5315 if (strcmp (gbuf, "ALL") == 0)
5316 return (reset_all (0));
5317 dptr = find_dev (gbuf);
5318 if (dptr == NULL)
5319 return SCPE_NXDEV;
5320 if (dptr->reset != NULL)
5321 return dptr->reset (dptr);
5322 else return SCPE_OK;
5323 }
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333 t_stat reset_all (uint32 start)
5334 {
5335 DEVICE *dptr;
5336 uint32 i;
5337 t_stat reason;
5338
5339 for (i = 0; i < start; i++) {
5340 if (sim_devices[i] == NULL)
5341 return SCPE_IERR;
5342 }
5343 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
5344 if (dptr->reset != NULL) {
5345 reason = dptr->reset (dptr);
5346 if (reason != SCPE_OK)
5347 return reason;
5348 }
5349 }
5350 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
5351 if (dptr->reset != NULL) {
5352 reason = dptr->reset (dptr);
5353 if (reason != SCPE_OK)
5354 return reason;
5355 }
5356 }
5357 return SCPE_OK;
5358 }
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368 t_stat reset_all_p (uint32 start)
5369 {
5370 t_stat r;
5371 int32 old_sw = sim_switches;
5372
5373 sim_switches = SWMASK ('P');
5374 r = reset_all (start);
5375 sim_switches = old_sw;
5376 return r;
5377 }
5378
5379
5380
5381 t_stat attach_cmd (int32 flag, CONST char *cptr)
5382 {
5383 char gbuf[4*CBUFSIZE];
5384 DEVICE *dptr;
5385 UNIT *uptr;
5386 t_stat r;
5387
5388 GET_SWITCHES (cptr);
5389 if (*cptr == 0)
5390 return SCPE_2FARG;
5391 cptr = get_glyph (cptr, gbuf, 0);
5392 GET_SWITCHES (cptr);
5393 if (*cptr == 0)
5394 return SCPE_2FARG;
5395 dptr = find_unit (gbuf, &uptr);
5396 if (dptr == NULL)
5397 return SCPE_NXDEV;
5398 if (uptr == NULL)
5399 return SCPE_NXUN;
5400 if (uptr->flags & UNIT_ATT) {
5401 if (!(uptr->dynflags & UNIT_ATTMULT) &&
5402 !(dptr->flags & DEV_DONTAUTO)) {
5403 r = scp_detach_unit (dptr, uptr);
5404 if (r != SCPE_OK)
5405 return r; }
5406 else {
5407 if (!(uptr->dynflags & UNIT_ATTMULT))
5408 return SCPE_ALATT;
5409 }
5410 }
5411 gbuf[sizeof(gbuf)-1] = '\0';
5412 strncpy (gbuf, cptr, sizeof(gbuf)-1);
5413 sim_trim_endspc (gbuf);
5414 return scp_attach_unit (dptr, uptr, gbuf);
5415 }
5416
5417
5418
5419 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
5420 {
5421 if (dptr->attach != NULL)
5422 return dptr->attach (uptr, (CONST char *)cptr);
5423 return attach_unit (uptr, (CONST char *)cptr);
5424 }
5425
5426
5427
5428 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
5429 {
5430 DEVICE *dptr;
5431
5432 if (uptr->flags & UNIT_DIS)
5433 return SCPE_UDIS;
5434 if (!(uptr->flags & UNIT_ATTABLE))
5435 return SCPE_NOATT;
5436 if ((dptr = find_dev_from_unit (uptr)) == NULL)
5437 return SCPE_NOATT;
5438 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
5439 if (uptr->filename == NULL)
5440 return SCPE_MEM;
5441 strncpy (uptr->filename, cptr, CBUFSIZE-1);
5442 if ((sim_switches & SWMASK ('R')) ||
5443 ((uptr->flags & UNIT_RO) != 0)) {
5444 if (((uptr->flags & UNIT_ROABLE) == 0) &&
5445 ((uptr->flags & UNIT_RO) == 0))
5446 return attach_err (uptr, SCPE_NORO);
5447 uptr->fileref = sim_fopen (cptr, "rb");
5448 if (uptr->fileref == NULL)
5449 return attach_err (uptr, SCPE_OPENERR);
5450 uptr->flags = uptr->flags | UNIT_RO;
5451 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
5452 sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
5453 }
5454 }
5455 else {
5456 if (sim_switches & SWMASK ('N')) {
5457 uptr->fileref = sim_fopen (cptr, "wb+");
5458 if (uptr->fileref == NULL)
5459 return attach_err (uptr, SCPE_OPENERR);
5460 if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
5461 sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
5462 }
5463 }
5464 else {
5465 uptr->fileref = sim_fopen (cptr, "rb+");
5466 if (uptr->fileref == NULL) {
5467 #if defined (EWOULDBLOCK)
5468 if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
5469 #else
5470 if ((errno == EAGAIN))
5471 #endif
5472 return attach_err (uptr, SCPE_OPENERR);
5473
5474 #if defined(EPERM)
5475 if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {
5476 #else
5477 if ((errno == EROFS) || (errno == EACCES)) {
5478 #endif
5479 if ((uptr->flags & UNIT_ROABLE) == 0)
5480 return attach_err (uptr, SCPE_NORO);
5481 uptr->fileref = sim_fopen (cptr, "rb");
5482 if (uptr->fileref == NULL)
5483 return attach_err (uptr, SCPE_OPENERR);
5484 uptr->flags = uptr->flags | UNIT_RO;
5485 if (!sim_quiet) {
5486 sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
5487 }
5488 }
5489 else {
5490 if (sim_switches & SWMASK ('E'))
5491 return attach_err (uptr, SCPE_OPENERR);
5492 uptr->fileref = sim_fopen (cptr, "wb+");
5493 if (uptr->fileref == NULL)
5494 return attach_err (uptr, SCPE_OPENERR);
5495 if (!sim_quiet) {
5496 sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
5497 }
5498 }
5499 }
5500 }
5501 }
5502 if (uptr->flags & UNIT_BUFABLE) {
5503 uint32 cap = ((uint32) uptr->capac) / dptr->aincr;
5504 if (uptr->flags & UNIT_MUSTBUF)
5505 uptr->filebuf = calloc (cap, SZ_D (dptr));
5506 if (uptr->filebuf == NULL)
5507 return attach_err (uptr, SCPE_MEM);
5508 if (!sim_quiet) {
5509 sim_printf ("%s: buffering file in memory\n", sim_dname (dptr));
5510 }
5511 uptr->hwmark = (uint32)sim_fread (uptr->filebuf,
5512 SZ_D (dptr), cap, uptr->fileref);
5513 uptr->flags = uptr->flags | UNIT_BUF;
5514 }
5515 uptr->flags = uptr->flags | UNIT_ATT;
5516 uptr->pos = 0;
5517 return SCPE_OK;
5518 }
5519
5520 t_stat attach_err (UNIT *uptr, t_stat stat)
5521 {
5522 FREE (uptr->filename);
5523 uptr->filename = NULL;
5524 return stat;
5525 }
5526
5527
5528
5529 t_stat detach_cmd (int32 flag, CONST char *cptr)
5530 {
5531 char gbuf[CBUFSIZE];
5532 DEVICE *dptr;
5533 UNIT *uptr;
5534
5535 GET_SWITCHES (cptr);
5536 if (*cptr == 0)
5537 return SCPE_2FARG;
5538 cptr = get_glyph (cptr, gbuf, 0);
5539 if (*cptr != 0)
5540 return SCPE_2MARG;
5541 if (strcmp (gbuf, "ALL") == 0)
5542 return (detach_all (0, FALSE));
5543 dptr = find_unit (gbuf, &uptr);
5544 if (dptr == NULL)
5545 return SCPE_NXDEV;
5546 if (uptr == NULL)
5547 return SCPE_NXUN;
5548 return scp_detach_unit (dptr, uptr);
5549 }
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564 t_stat detach_all (int32 start, t_bool shutdown)
5565 {
5566 uint32 i, j;
5567 DEVICE *dptr;
5568 UNIT *uptr;
5569 t_stat r;
5570
5571 if ((start < 0) || (start > 1))
5572 return SCPE_IERR;
5573 if (shutdown)
5574 sim_switches = sim_switches | SIM_SW_SHUT;
5575 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
5576 for (j = 0; j < dptr->numunits; j++) {
5577 uptr = (dptr->units) + j;
5578 if ((uptr->flags & UNIT_ATT) ||
5579 (shutdown && dptr->detach &&
5580 !(uptr->flags & UNIT_ATTABLE))) {
5581 r = scp_detach_unit (dptr, uptr);
5582
5583 if ((r != SCPE_OK) && !shutdown)
5584 return r;
5585 }
5586 }
5587 }
5588 return SCPE_OK;
5589 }
5590
5591
5592
5593 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
5594 {
5595 if (dptr->detach != NULL)
5596 return dptr->detach (uptr);
5597 return detach_unit (uptr);
5598 }
5599
5600
5601
5602 t_stat detach_unit (UNIT *uptr)
5603 {
5604 DEVICE *dptr;
5605
5606 if (uptr == NULL)
5607 return SCPE_IERR;
5608 if (!(uptr->flags & UNIT_ATTABLE))
5609 return SCPE_NOATT;
5610 if (!(uptr->flags & UNIT_ATT)) {
5611 if (sim_switches & SIM_SW_REST)
5612 return SCPE_OK;
5613 else
5614 return SCPE_NOTATT;
5615 }
5616 if ((dptr = find_dev_from_unit (uptr)) == NULL)
5617 return SCPE_OK;
5618 if (uptr->flags & UNIT_BUF) {
5619 uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
5620 if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
5621 if (!sim_quiet) {
5622 sim_printf ("%s: writing buffer to file\n", sim_dname (dptr));
5623 }
5624 rewind (uptr->fileref);
5625 sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
5626 if (ferror (uptr->fileref))
5627 sim_printf ("%s: I/O error - %s", sim_dname (dptr), strerror (errno));
5628 }
5629 if (uptr->flags & UNIT_MUSTBUF) {
5630 FREE (uptr->filebuf);
5631 uptr->filebuf = NULL;
5632 }
5633 uptr->flags = uptr->flags & ~UNIT_BUF;
5634 }
5635 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
5636 FREE (uptr->filename);
5637 uptr->filename = NULL;
5638 if (fclose (uptr->fileref) == EOF)
5639 return SCPE_IOERR;
5640 return SCPE_OK;
5641 }
5642
5643
5644
5645 const char *sim_dname (DEVICE *dptr)
5646 {
5647 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
5648 }
5649
5650
5651
5652 const char *sim_uname (UNIT *uptr)
5653 {
5654 DEVICE *d = find_dev_from_unit(uptr);
5655 static char uname[CBUFSIZE];
5656
5657 if (!d)
5658 return "";
5659 if (d->numunits == 1)
5660 return sim_dname (d);
5661 sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
5662 return uname;
5663 }
5664
5665
5666
5667 t_stat run_cmd (int32 flag, CONST char *cptr)
5668 {
5669 char gbuf[CBUFSIZE] = "";
5670 CONST char *tptr;
5671 uint32 i, j;
5672 int32 sim_next = 0;
5673 int32 unitno;
5674 t_value pcv, orig_pcv;
5675 t_stat r;
5676 DEVICE *dptr;
5677 UNIT *uptr;
5678
5679 GET_SWITCHES (cptr);
5680 sim_step = 0;
5681 if ((flag == RU_RUN) || (flag == RU_GO)) {
5682 orig_pcv = get_rval (sim_PC, 0);
5683 if (*cptr != 0) {
5684 cptr = get_glyph (cptr, gbuf, 0);
5685 if (MATCH_CMD (gbuf, "UNTIL") != 0) {
5686 if (sim_dflt_dev && sim_vm_parse_addr)
5687 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
5688 else pcv = strtotv (gbuf, &tptr, sim_PC->radix);
5689 if ((tptr == gbuf) || (*tptr != 0) ||
5690 (pcv > width_mask[sim_PC->width]))
5691 return SCPE_ARG;
5692 put_rval (sim_PC, 0, pcv);
5693 }
5694 }
5695 if ((flag == RU_RUN) &&
5696 ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {
5697 put_rval (sim_PC, 0, orig_pcv);
5698 return r;
5699 }
5700 if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) {
5701 int32 saved_switches = sim_switches;
5702
5703 if (MATCH_CMD (gbuf, "UNTIL") != 0)
5704 cptr = get_glyph (cptr, gbuf, 0);
5705 if (MATCH_CMD (gbuf, "UNTIL") != 0)
5706 return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\n",
5707 (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
5708 sim_switches = 0;
5709 GET_SWITCHES (cptr);
5710 if ((*cptr == '\'') || (*cptr == '"')) {
5711 r = expect_cmd (1, cptr);
5712 if (r != SCPE_OK)
5713 return r;
5714 }
5715 else {
5716 if (sim_switches == 0)
5717 sim_switches = sim_brk_dflt;
5718 sim_switches |= BRK_TYP_TEMP;
5719 sim_brk_types |= BRK_TYP_TEMP;
5720 r = ssh_break (NULL, cptr, SSH_ST);
5721 if (r != SCPE_OK)
5722 return sim_messagef (r, "Unable to establish breakpoint at: %s\n", cptr);
5723 }
5724 sim_switches = saved_switches;
5725 }
5726 }
5727
5728 else if ((flag == RU_STEP) ||
5729 ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) {
5730 static t_bool not_implemented_message = FALSE;
5731
5732 if ((!not_implemented_message) && (flag == RU_NEXT)) {
5733 not_implemented_message = TRUE;
5734 flag = RU_STEP;
5735 }
5736 if (*cptr != 0) {
5737 cptr = get_glyph (cptr, gbuf, 0);
5738 if (*cptr != 0)
5739 return SCPE_2MARG;
5740 sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
5741 if ((r != SCPE_OK) || (sim_step <= 0))
5742 return SCPE_ARG;
5743 }
5744 else sim_step = 1;
5745 if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
5746 sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
5747 }
5748 else if (flag == RU_NEXT) {
5749 t_addr *addrs;
5750
5751 if (*cptr != 0) {
5752 cptr = get_glyph (cptr, gbuf, 0);
5753 if (*cptr != 0)
5754 return SCPE_2MARG;
5755 sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
5756 if ((r != SCPE_OK) || (sim_next <= 0))
5757 return SCPE_ARG;
5758 }
5759 else sim_next = 1;
5760 if (sim_vm_is_subroutine_call(&addrs)) {
5761 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
5762 for (i=0; addrs[i]; i++)
5763 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
5764 }
5765 else
5766 sim_step = 1;
5767 }
5768 else if (flag == RU_BOOT) {
5769 if (*cptr == 0)
5770 return SCPE_2FARG;
5771 cptr = get_glyph (cptr, gbuf, 0);
5772 if (*cptr != 0)
5773 return SCPE_2MARG;
5774 dptr = find_unit (gbuf, &uptr);
5775 if (dptr == NULL)
5776 return SCPE_NXDEV;
5777 if (uptr == NULL)
5778 return SCPE_NXUN;
5779 if (dptr->boot == NULL)
5780 return SCPE_NOFNC;
5781 if (uptr->flags & UNIT_DIS)
5782 return SCPE_UDIS;
5783 if ((uptr->flags & UNIT_ATTABLE) &&
5784 !(uptr->flags & UNIT_ATT))
5785 return SCPE_UNATT;
5786 unitno = (int32) (uptr - dptr->units);
5787 if ((r = sim_run_boot_prep (flag)) != SCPE_OK)
5788 return r;
5789 if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)
5790 return r;
5791 }
5792
5793 else
5794 if (flag != RU_CONT)
5795 return SCPE_IERR;
5796 else
5797 if (*cptr != 0)
5798 return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\n");
5799
5800 if (sim_switches & SIM_SW_HIDE)
5801 return SCPE_OK;
5802
5803 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
5804 for (j = 0; j < dptr->numunits; j++) {
5805 uptr = dptr->units + j;
5806 if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
5807 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
5808 }
5809 }
5810 stop_cpu = 0;
5811 sim_is_running = 1;
5812 if (sim_ttrun () != SCPE_OK) {
5813 sim_is_running = 0;
5814 sim_ttcmd ();
5815 return SCPE_TTYERR;
5816 }
5817 if ((r = sim_check_console (30)) != SCPE_OK) {
5818 sim_is_running = 0;
5819 sim_ttcmd ();
5820 return r;
5821 }
5822 #ifndef IS_WINDOWS
5823 # ifdef SIGINT
5824 if (signal (SIGINT, int_handler) == SIG_ERR) {
5825 sim_is_running = 0;
5826 sim_ttcmd ();
5827 return SCPE_SIGERR;
5828 }
5829 # endif
5830 #endif
5831 #ifndef IS_WINDOWS
5832 # ifdef SIGHUP
5833 if (signal (SIGHUP, int_handler) == SIG_ERR) {
5834 sim_is_running = 0;
5835 sim_ttcmd ();
5836 return SCPE_SIGERR;
5837 }
5838 # endif
5839 #endif
5840 #ifndef IS_WINDOWS
5841 # ifdef SIGTERM
5842 if (signal (SIGTERM, int_handler) == SIG_ERR) {
5843 sim_is_running = 0;
5844 sim_ttcmd ();
5845 return SCPE_SIGERR;
5846 }
5847 # endif
5848 #endif
5849 if (sim_step)
5850 sim_activate (&sim_step_unit, sim_step);
5851 fflush(stdout);
5852 if (sim_log)
5853 fflush (sim_log);
5854 sim_rtcn_init_all ();
5855 sim_start_timer_services ();
5856
5857 do {
5858 t_addr *addrs;
5859
5860 while (1) {
5861 r = sim_instr();
5862 if (r != SCPE_REMOTE)
5863 break;
5864 sim_remote_process_command ();
5865 }
5866 if ((flag != RU_NEXT) ||
5867 (--sim_next <=0))
5868 break;
5869 if (sim_step == 0) {
5870 t_addr val;
5871 BRKTAB *bp;
5872
5873 if (SCPE_BARE_STATUS(r) >= SCPE_BASE)
5874 break;
5875 if (sim_vm_pc_value)
5876 val = (t_addr)(*sim_vm_pc_value)();
5877 else
5878 val = (t_addr)get_rval (sim_PC, 0);
5879 if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
5880 break;
5881 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
5882 }
5883 else {
5884 if (r != SCPE_STEP)
5885 break;
5886 }
5887
5888 sim_step = 0;
5889 if (sim_vm_is_subroutine_call(&addrs)) {
5890 sim_brk_types |= BRK_TYP_DYN_STEPOVER;
5891 for (i=0; addrs[i]; i++)
5892 sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
5893 }
5894 else
5895 sim_step = 1;
5896 if (sim_step)
5897 sim_activate (&sim_step_unit, sim_step);
5898 } while (1);
5899
5900 sim_is_running = 0;
5901 sim_stop_timer_services ();
5902 sim_ttcmd ();
5903 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);
5904 signal (SIGINT, SIG_DFL);
5905 #ifdef SIGHUP
5906 signal (SIGHUP, SIG_DFL);
5907 #endif
5908 signal (SIGTERM, SIG_DFL);
5909 if (sim_log)
5910 fflush (sim_log);
5911 if (sim_deb)
5912 sim_debug_flush ();
5913 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
5914 for (j = 0; j < dptr->numunits; j++) {
5915 uptr = dptr->units + j;
5916 if (uptr->flags & UNIT_ATT) {
5917 if (uptr->io_flush)
5918 uptr->io_flush (uptr);
5919 else {
5920 if (!(uptr->flags & UNIT_BUF) &&
5921 (uptr->fileref) &&
5922 !(uptr->dynflags & UNIT_NO_FIO) &&
5923 !(uptr->flags & UNIT_RO))
5924 fflush (uptr->fileref);
5925 }
5926 }
5927 }
5928 }
5929 sim_cancel (&sim_step_unit);
5930 UPDATE_SIM_TIME;
5931 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
5932 }
5933
5934
5935
5936 void
5937 run_cmd_message (const char *unechoed_cmdline, t_stat r)
5938 {
5939 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
5940 sim_printf("%s> %s\n", do_position(), unechoed_cmdline);
5941 #ifdef WIN_STDIO
5942 (void)fflush(stderr);
5943 (void)fflush(stdout);
5944 #endif
5945 fprint_stopped (stdout, r);
5946 if (sim_log && (sim_log != stdout))
5947 fprint_stopped (sim_log, r);
5948 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
5949 fprint_stopped (sim_deb, r);
5950 #ifdef WIN_STDIO
5951 (void)fflush(stderr);
5952 (void)fflush(stdout);
5953 #endif
5954 }
5955
5956
5957
5958 t_stat sim_run_boot_prep (int32 flag)
5959 {
5960 UNIT *uptr;
5961 t_stat r;
5962
5963 sim_interval = 0;
5964 sim_time = sim_rtime = 0;
5965 noqueue_time = 0;
5966 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
5967 sim_clock_queue = uptr->next;
5968 uptr->next = NULL;
5969 }
5970 r = reset_all (0);
5971 if ((r == SCPE_OK) && (flag == RU_RUN)) {
5972 if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
5973 sim_printf ("Resetting all devices... This may not have been your intention.\n");
5974 sim_printf ("The GO and CONTINUE commands do not reset devices.\n");
5975 }
5976 run_cmd_did_reset = TRUE;
5977 }
5978 return r;
5979 }
5980
5981
5982
5983
5984
5985
5986
5987
5988 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
5989 {
5990 int32 i;
5991 t_stat r = 0;
5992 t_addr k;
5993 t_value pcval;
5994
5995 fputc ('\n', st);
5996
5997 if (v >= SCPE_BASE)
5998 fputs (sim_error_text (v), st);
5999 else {
6000 fputs (sim_stop_messages [v], st);
6001
6002 if ((sim_vm_fprint_stopped != NULL) &&
6003 (!sim_vm_fprint_stopped (st, v)))
6004 return;
6005 }
6006
6007 fprintf (st, ", %s: ", pc->name);
6008
6009 pcval = get_rval (pc, 0);
6010 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)
6011 sim_vm_fprint_addr (st, dptr, (t_addr) pcval);
6012 else fprint_val (st, pcval, pc->radix, pc->width,
6013 pc->flags & REG_FMT);
6014 if ((dptr != NULL) && (dptr->examine != NULL)) {
6015 for (i = 0; i < sim_emax; i++)
6016 sim_eval[i] = 0;
6017 for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6018 if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6019 break;
6020 }
6021 if ((r == SCPE_OK) || (i > 0)) {
6022 fprintf (st, " (");
6023 if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6024 fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6025 fprintf (st, ")");
6026 }
6027 }
6028 fprintf (st, "\n");
6029 return;
6030 }
6031
6032 void fprint_stopped (FILE *st, t_stat v)
6033 {
6034 #ifdef WIN_STDIO
6035 (void)fflush(stderr);
6036 (void)fflush(stdout);
6037 #endif
6038 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6039 return;
6040 }
6041
6042
6043
6044
6045 t_stat step_svc (UNIT *uptr)
6046 {
6047 return SCPE_STEP;
6048 }
6049
6050
6051
6052
6053 t_stat expect_svc (UNIT *uptr)
6054 {
6055 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6056 }
6057
6058
6059
6060 void int_handler (int sig)
6061 {
6062 stop_cpu = 1;
6063 return;
6064 }
6065
6066
6067
6068 t_stat exdep_cmd (int32 flag, CONST char *cptr)
6069 {
6070 char gbuf[CBUFSIZE];
6071 CONST char *gptr;
6072 CONST char *tptr = NULL;
6073 int32 opt;
6074 t_addr low, high;
6075 t_stat reason = SCPE_IERR;
6076 DEVICE *tdptr;
6077 REG *lowr, *highr;
6078 FILE *ofile;
6079
6080 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;
6081 if (flag == EX_E)
6082 opt = opt | CMD_OPT_OF;
6083 cptr = get_sim_opt (opt, cptr, &reason);
6084 if (!cptr)
6085 return reason;
6086 if (*cptr == 0)
6087 return SCPE_2FARG;
6088 if (sim_dfunit == NULL)
6089 return SCPE_NXUN;
6090 cptr = get_glyph (cptr, gbuf, 0);
6091 if ((flag == EX_D) && (*cptr == 0))
6092
6093 return SCPE_2FARG;
6094 ofile = sim_ofile? sim_ofile: stdout;
6095
6096 for (gptr = gbuf, reason = SCPE_OK;
6097 (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6098 tdptr = sim_dfdev;
6099 if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6100 tptr = gptr + strlen ("STATE");
6101 if (*tptr && (*tptr++ != ','))
6102 return SCPE_ARG;
6103 if ((lowr = sim_dfdev->registers) == NULL)
6104 return SCPE_NXREG;
6105 for (highr = lowr; highr->name != NULL; highr++) ;
6106 sim_switches = sim_switches | SIM_SW_HIDE;
6107 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6108 lowr, --highr, 0, 0);
6109 continue;
6110 }
6111
6112
6113 if ((lowr = find_reg (gptr, &tptr, tdptr)) ||
6114 (!(sim_opt_out & CMD_OPT_DFT) &&
6115 (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6116 low = high = 0;
6117 if ((*tptr == '-') || (*tptr == ':')) {
6118 highr = find_reg (tptr + 1, &tptr, tdptr);
6119 if (highr == NULL)
6120 return SCPE_NXREG;
6121 }
6122 else {
6123 highr = lowr;
6124 if (*tptr == '[') {
6125 if (lowr->depth <= 1)
6126 return SCPE_ARG;
6127 tptr = get_range (NULL, tptr + 1, &low, &high,
6128 10, lowr->depth - 1, ']');
6129 if (tptr == NULL)
6130 return SCPE_ARG;
6131 }
6132 }
6133 if (*tptr && (*tptr++ != ','))
6134 return SCPE_ARG;
6135 reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6136 lowr, highr, (uint32) low, (uint32) high);
6137 continue;
6138 }
6139
6140 tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6141 (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6142 sim_dfunit->capac - sim_dfdev->aincr), 0);
6143 if (tptr == NULL)
6144 return SCPE_ARG;
6145 if (*tptr && (*tptr++ != ','))
6146 return SCPE_ARG;
6147 reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6148 sim_dfdev, sim_dfunit);
6149 }
6150 if (sim_ofile)
6151 fclose (sim_ofile);
6152 return reason;
6153 }
6154
6155
6156
6157
6158
6159
6160
6161 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
6162 REG *lowr, REG *highr, uint32 lows, uint32 highs)
6163 {
6164 t_stat reason;
6165 uint32 idx, val_start=lows;
6166 t_value val, last_val;
6167 REG *rptr;
6168
6169 if ((lowr == NULL) || (highr == NULL))
6170 return SCPE_IERR;
6171 if (lowr > highr)
6172 return SCPE_ARG;
6173 for (rptr = lowr; rptr <= highr; rptr++) {
6174 if ((sim_switches & SIM_SW_HIDE) &&
6175 (rptr->flags & REG_HIDDEN))
6176 continue;
6177 val = last_val = 0;
6178 for (idx = lows; idx <= highs; idx++) {
6179 if (idx >= rptr->depth)
6180 return SCPE_SUB;
6181 val = get_rval (rptr, idx);
6182 if (schptr && !test_search (&val, schptr))
6183 continue;
6184 if (flag == EX_E) {
6185 if ((idx > lows) && (val == last_val))
6186 continue;
6187 if (idx > val_start+1) {
6188 if (idx-1 == val_start+1) {
6189 reason = ex_reg (ofile, val, flag, rptr, idx-1);
6190 if (reason != SCPE_OK)
6191 return reason;
6192 if (sim_log && (ofile == stdout))
6193 ex_reg (sim_log, val, flag, rptr, idx-1);
6194 }
6195 else {
6196 if (val_start+1 != idx-1) {
6197 Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6198 if (sim_log && (ofile == stdout))
6199 Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6200 }
6201 else {
6202 Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6203 if (sim_log && (ofile == stdout))
6204 Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6205 }
6206 }
6207 }
6208 sim_last_val = last_val = val;
6209 val_start = idx;
6210 reason = ex_reg (ofile, val, flag, rptr, idx);
6211 if (reason != SCPE_OK)
6212 return reason;
6213 if (sim_log && (ofile == stdout))
6214 ex_reg (sim_log, val, flag, rptr, idx);
6215 }
6216 if (flag != EX_E) {
6217 reason = dep_reg (flag, cptr, rptr, idx);
6218 if (reason != SCPE_OK)
6219 return reason;
6220 }
6221 }
6222 if ((flag == EX_E) && (val_start != highs)) {
6223 if (highs == val_start+1) {
6224 reason = ex_reg (ofile, val, flag, rptr, highs);
6225 if (reason != SCPE_OK)
6226 return reason;
6227 if (sim_log && (ofile == stdout))
6228 ex_reg (sim_log, val, flag, rptr, highs);
6229 }
6230 else {
6231 if (val_start+1 != highs) {
6232 Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6233 if (sim_log && (ofile == stdout))
6234 Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6235 }
6236 else {
6237 Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6238 if (sim_log && (ofile == stdout))
6239 Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6240 }
6241 }
6242 }
6243 }
6244 return SCPE_OK;
6245 }
6246
6247 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
6248 t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6249 {
6250 t_addr i, mask;
6251 t_stat reason;
6252
6253 if (uptr->flags & UNIT_DIS)
6254 return SCPE_UDIS;
6255 mask = (t_addr) width_mask[dptr->awidth];
6256 if ((low > mask) || (high > mask) || (low > high))
6257 return SCPE_ARG;
6258 for (i = low; i <= high; ) {
6259 reason = get_aval (i, dptr, uptr);
6260 if (reason != SCPE_OK)
6261 return reason;
6262 if (schptr && !test_search (sim_eval, schptr))
6263 i = i + dptr->aincr;
6264 else {
6265 if (flag != EX_D) {
6266 reason = ex_addr (ofile, flag, i, dptr, uptr);
6267 if (reason > SCPE_OK)
6268 return reason;
6269 if (sim_log && (ofile == stdout))
6270 ex_addr (sim_log, flag, i, dptr, uptr);
6271 }
6272 else reason = 1 - dptr->aincr;
6273 if (flag != EX_E) {
6274 reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
6275 if (reason > SCPE_OK)
6276 return reason;
6277 }
6278 i = i + (1 - reason);
6279 }
6280 }
6281 return SCPE_OK;
6282 }
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
6297 {
6298 int32 rdx;
6299
6300 if (rptr == NULL)
6301 return SCPE_IERR;
6302 if (rptr->depth > 1)
6303 Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
6304 else Fprintf (ofile, "%s:\t", rptr->name);
6305 if (!(flag & EX_E))
6306 return SCPE_OK;
6307 GET_RADIX (rdx, rptr->radix);
6308 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
6309 sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
6310 else if (!(rptr->flags & REG_VMFLAGS) ||
6311 (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
6312 NULL, sim_switches | SIM_SW_REG) > 0)) {
6313 fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
6314 if (rptr->fields) {
6315 Fprintf (ofile, "\t");
6316 fprint_fields (ofile, val, val, rptr->fields);
6317 }
6318 }
6319 if (flag & EX_I)
6320 Fprintf (ofile, "\t");
6321 else Fprintf (ofile, "\n");
6322 return SCPE_OK;
6323 }
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334 t_value get_rval (REG *rptr, uint32 idx)
6335 {
6336 size_t sz;
6337 t_value val;
6338 uint32 *ptr;
6339
6340 sz = SZ_R (rptr);
6341 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
6342 idx = idx + rptr->qptr;
6343 if (idx >= rptr->depth) idx = idx - rptr->depth;
6344 }
6345 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
6346 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
6347 if (sz <= sizeof (uint32))
6348 val = *ptr;
6349 else val = *((t_uint64 *) ptr);
6350 }
6351 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
6352 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
6353 if (sz <= sizeof (uint32))
6354 val = *ptr;
6355 else val = *((t_uint64 *) ptr);
6356 }
6357 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
6358 (sz == sizeof (uint8)))
6359 val = *(((uint8 *) rptr->loc) + idx);
6360 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
6361 (sz == sizeof (uint16)))
6362 val = *(((uint16 *) rptr->loc) + idx);
6363 else if (sz <= sizeof (uint32))
6364 val = *(((uint32 *) rptr->loc) + idx);
6365 else val = *(((t_uint64 *) rptr->loc) + idx);
6366 val = (val >> rptr->offset) & width_mask[rptr->width];
6367 return val;
6368 }
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
6382 {
6383 t_stat r;
6384 t_value val, mask;
6385 int32 rdx;
6386 CONST char *tptr;
6387 char gbuf[CBUFSIZE];
6388
6389 if ((cptr == NULL) || (rptr == NULL))
6390 return SCPE_IERR;
6391 if (rptr->flags & REG_RO)
6392 return SCPE_RO;
6393 if (flag & EX_I) {
6394 cptr = read_line (gbuf, sizeof(gbuf), stdin);
6395 if (sim_log)
6396 fprintf (sim_log, "%s\n", cptr? cptr: "");
6397 if (cptr == NULL)
6398 return 1;
6399 if (*cptr == 0)
6400 return SCPE_OK;
6401 }
6402 mask = width_mask[rptr->width];
6403 GET_RADIX (rdx, rptr->radix);
6404 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {
6405 val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
6406 if ((tptr == cptr) || (*tptr != 0) || (val > mask))
6407 return SCPE_ARG;
6408 }
6409 else
6410 if (!(rptr->flags & REG_VMFLAGS) ||
6411 (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
6412 &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
6413 val = get_uint (cptr, rdx, mask, &r);
6414 if (r != SCPE_OK)
6415 return SCPE_ARG;
6416 }
6417 if ((rptr->flags & REG_NZ) && (val == 0))
6418 return SCPE_ARG;
6419 put_rval (rptr, idx, val);
6420 return SCPE_OK;
6421 }
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434 void put_rval (REG *rptr, uint32 idx, t_value val)
6435 {
6436 size_t sz;
6437 t_value mask;
6438 uint32 *ptr;
6439
6440 #define PUT_RVAL(sz,rp,id,v,m) \
6441 *(((sz *) rp->loc) + id) = \
6442 (sz)((*(((sz *) rp->loc) + id) & \
6443 ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
6444
6445 if (rptr == sim_PC)
6446 sim_brk_npc (0);
6447 sz = SZ_R (rptr);
6448 mask = width_mask[rptr->width];
6449 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
6450 idx = idx + rptr->qptr;
6451 if (idx >= rptr->depth)
6452 idx = idx - rptr->depth;
6453 }
6454 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
6455 ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
6456 if (sz <= sizeof (uint32))
6457 *ptr = (*ptr &
6458 ~(((uint32) mask) << rptr->offset)) |
6459 (((uint32) val) << rptr->offset);
6460 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
6461 & ~(mask << rptr->offset)) | (val << rptr->offset);
6462 }
6463 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
6464 ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
6465 if (sz <= sizeof (uint32))
6466 *((uint32 *) ptr) = (*((uint32 *) ptr) &
6467 ~(((uint32) mask) << rptr->offset)) |
6468 (((uint32) val) << rptr->offset);
6469 else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
6470 & ~(mask << rptr->offset)) | (val << rptr->offset);
6471 }
6472 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
6473 (sz == sizeof (uint8)))
6474 PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
6475 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
6476 (sz == sizeof (uint16)))
6477 PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
6478 else if (sz <= sizeof (uint32))
6479 PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
6480 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
6481 return;
6482 }
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
6498 {
6499 t_stat reason;
6500 int32 rdx;
6501
6502 if (sim_vm_fprint_addr)
6503 sim_vm_fprint_addr (ofile, dptr, addr);
6504 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
6505 Fprintf (ofile, ":\t");
6506 if (!(flag & EX_E))
6507 return (1 - dptr->aincr);
6508
6509 GET_RADIX (rdx, dptr->dradix);
6510 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
6511 fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
6512 reason = 1 - dptr->aincr;
6513 }
6514 if (flag & EX_I)
6515 Fprintf (ofile, "\t");
6516 else Fprintf (ofile, "\n");
6517 return reason;
6518 }
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
6532 {
6533 int32 i;
6534 t_value mask;
6535 t_addr j, loc;
6536 size_t sz;
6537 t_stat reason = SCPE_OK;
6538
6539 if ((dptr == NULL) || (uptr == NULL))
6540 return SCPE_IERR;
6541 mask = width_mask[dptr->dwidth];
6542 for (i = 0; i < sim_emax; i++)
6543 sim_eval[i] = 0;
6544 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
6545 if (dptr->examine != NULL) {
6546 reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
6547 if (reason != SCPE_OK)
6548 break;
6549 }
6550 else {
6551 if (!(uptr->flags & UNIT_ATT))
6552 return SCPE_UNATT;
6553 if (uptr->dynflags & UNIT_NO_FIO)
6554 return SCPE_NOFNC;
6555 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
6556 reason = SCPE_NXM;
6557 break;
6558 }
6559 sz = SZ_D (dptr);
6560 loc = j / dptr->aincr;
6561 if (uptr->flags & UNIT_BUF) {
6562 SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
6563 }
6564 else {
6565 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
6566 sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
6567 if ((feof (uptr->fileref)) &&
6568 !(uptr->flags & UNIT_FIX)) {
6569 reason = SCPE_EOF;
6570 break;
6571 }
6572 else if (ferror (uptr->fileref)) {
6573 clearerr (uptr->fileref);
6574 reason = SCPE_IOERR;
6575 break;
6576 }
6577 }
6578 }
6579 sim_last_val = sim_eval[i] = sim_eval[i] & mask;
6580 }
6581 if ((reason != SCPE_OK) && (i == 0))
6582 return reason;
6583 return SCPE_OK;
6584 }
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
6601 UNIT *uptr, int32 dfltinc)
6602 {
6603 int32 i, count, rdx;
6604 t_addr j, loc;
6605 t_stat r, reason;
6606 t_value mask;
6607 size_t sz;
6608 char gbuf[CBUFSIZE];
6609
6610 if (dptr == NULL)
6611 return SCPE_IERR;
6612 if (flag & EX_I) {
6613 cptr = read_line (gbuf, sizeof(gbuf), stdin);
6614 if (sim_log)
6615 fprintf (sim_log, "%s\n", cptr? cptr: "");
6616 if (cptr == NULL)
6617 return 1;
6618 if (*cptr == 0)
6619 return dfltinc;
6620 }
6621 if (uptr->flags & UNIT_RO)
6622 return SCPE_RO;
6623 mask = width_mask[dptr->dwidth];
6624
6625 GET_RADIX (rdx, dptr->dradix);
6626 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
6627 sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
6628 if (reason != SCPE_OK)
6629 return reason;
6630 reason = dfltinc;
6631 }
6632 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
6633
6634 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
6635 sim_eval[i] = sim_eval[i] & mask;
6636 if (dptr->deposit != NULL) {
6637 r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
6638 if (r != SCPE_OK)
6639 return r;
6640 }
6641 else {
6642 if (!(uptr->flags & UNIT_ATT))
6643 return SCPE_UNATT;
6644 if (uptr->dynflags & UNIT_NO_FIO)
6645 return SCPE_NOFNC;
6646 if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
6647 return SCPE_NXM;
6648 sz = SZ_D (dptr);
6649 loc = j / dptr->aincr;
6650 if (uptr->flags & UNIT_BUF) {
6651 SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
6652 if (loc >= uptr->hwmark)
6653 uptr->hwmark = (uint32) loc + 1;
6654 }
6655 else {
6656 sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
6657 sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
6658 if (ferror (uptr->fileref)) {
6659 clearerr (uptr->fileref);
6660 return SCPE_IOERR;
6661 }
6662 }
6663 }
6664 }
6665 return reason;
6666 }
6667
6668
6669
6670 t_stat eval_cmd (int32 flg, CONST char *cptr)
6671 {
6672 if (!sim_dflt_dev)
6673 return SCPE_ARG;
6674 DEVICE *dptr = sim_dflt_dev;
6675 int32 i, rdx, a, lim;
6676 t_stat r;
6677
6678 GET_SWITCHES (cptr);
6679 GET_RADIX (rdx, dptr->dradix);
6680 for (i = 0; i < sim_emax; i++)
6681 sim_eval[i] = 0;
6682 if (*cptr == 0)
6683 return SCPE_2FARG;
6684 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
6685 sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
6686 if (r != SCPE_OK)
6687 return r;
6688 }
6689 lim = 1 - r;
6690 for (i = a = 0; a < lim; ) {
6691 sim_printf ("%d:\t", a);
6692 if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
6693 r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
6694 if (sim_log) {
6695 if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
6696 r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
6697 }
6698 sim_printf ("\n");
6699 if (r < 0)
6700 a = a + 1 - r;
6701 else a = a + dptr->aincr;
6702 i = a / dptr->aincr;
6703 }
6704 return SCPE_OK;
6705 }
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720 char *read_line (char *cptr, int32 size, FILE *stream)
6721 {
6722 return read_line_p (NULL, cptr, size, stream);
6723 }
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
6738 {
6739 char *tptr;
6740
6741 if (prompt) {
6742 #ifdef HAVE_LINEHISTORY
6743 char *tmpc = linenoise (prompt);
6744 if (tmpc == NULL)
6745 cptr = NULL;
6746 else {
6747 strncpy (cptr, tmpc, size-1);
6748 linenoiseHistoryAdd (tmpc);
6749 FREE (tmpc);
6750 }
6751 }
6752 #else
6753 fflush (stdout);
6754 printf ("%s", prompt);
6755 fflush (stdout);
6756 cptr = fgets (cptr, size, stream);
6757 }
6758 #endif
6759 else cptr = fgets (cptr, size, stream);
6760
6761 if (cptr == NULL) {
6762 clearerr (stream);
6763 return NULL;
6764 }
6765 for (tptr = cptr; tptr < (cptr + size); tptr++) {
6766 if ((*tptr == '\n') || (*tptr == '\r') ||
6767 (tptr == (cptr + size - 1))) {
6768 *tptr = 0;
6769 break;
6770 }
6771 }
6772 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))
6773 memmove (cptr, cptr + 3, strlen (cptr + 3));
6774 while (sim_isspace (*cptr))
6775 cptr++;
6776 if ((*cptr == ';') || (*cptr == '#')) {
6777 if (sim_do_echo)
6778 sim_printf("%s> %s\n", do_position(), cptr);
6779 *cptr = 0;
6780 }
6781
6782 return cptr;
6783 }
6784
6785
6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
6804 {
6805 t_bool quoting = FALSE;
6806 t_bool escaping = FALSE;
6807 char quote_char = 0;
6808
6809 while ((*iptr != 0) &&
6810 ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
6811 if (quote) {
6812 if (quoting) {
6813 if (!escaping) {
6814 if (*iptr == escape_char)
6815 escaping = TRUE;
6816 else
6817 if (*iptr == quote_char)
6818 quoting = FALSE;
6819 }
6820 else
6821 escaping = FALSE;
6822 }
6823 else {
6824 if ((*iptr == '"') || (*iptr == '\'')) {
6825 quoting = TRUE;
6826 quote_char = *iptr;
6827 }
6828 }
6829 }
6830 if (sim_islower (*iptr) && uc)
6831 *optr = (char)toupper (*iptr);
6832 else *optr = *iptr;
6833 iptr++; optr++;
6834 }
6835 if (mchar && (*iptr == mchar))
6836 iptr++;
6837 *optr = 0;
6838 while (sim_isspace (*iptr))
6839 iptr++;
6840 return iptr;
6841 }
6842
6843 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
6844 {
6845 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
6846 }
6847
6848 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
6849 {
6850 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
6851 }
6852
6853 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
6854 {
6855 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
6856 }
6857
6858 CONST char *get_glyph_cmd (const char *iptr, char *optr)
6859 {
6860
6861 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
6862 strcpy (optr, "!");
6863 return (CONST char *)(iptr + 1);
6864 }
6865 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
6866 }
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876 char *sim_trim_endspc (char *cptr)
6877 {
6878 char *tptr;
6879
6880 tptr = cptr + strlen (cptr);
6881 while ((--tptr >= cptr) && sim_isspace (*tptr))
6882 *tptr = 0;
6883 return cptr;
6884 }
6885
6886 int sim_isspace (char c)
6887 {
6888 return (c & 0x80) ? 0 : isspace (c);
6889 }
6890
6891 int sim_islower (char c)
6892 {
6893 return (c & 0x80) ? 0 : islower (c);
6894 }
6895
6896 int sim_isalpha (char c)
6897 {
6898 return (c & 0x80) ? 0 : isalpha (c);
6899 }
6900
6901 int sim_isprint (char c)
6902 {
6903 return (c & 0x80) ? 0 : isprint (c);
6904 }
6905
6906 int sim_isdigit (char c)
6907 {
6908 return (c & 0x80) ? 0 : isdigit (c);
6909 }
6910
6911 int sim_isgraph (char c)
6912 {
6913 return (c & 0x80) ? 0 : isgraph (c);
6914 }
6915
6916 int sim_isalnum (char c)
6917 {
6918 return (c & 0x80) ? 0 : isalnum (c);
6919 }
6920
6921
6922
6923
6924
6925
6926
6927
6928
6929
6930
6931
6932 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
6933 {
6934 t_value val;
6935 CONST char *tptr;
6936
6937 *status = SCPE_OK;
6938 val = strtotv ((CONST char *)cptr, &tptr, radix);
6939 if ((cptr == tptr) || (val > max))
6940 *status = SCPE_ARG;
6941 else {
6942 while (sim_isspace (*tptr)) tptr++;
6943 if (*tptr != 0)
6944 *status = SCPE_ARG;
6945 }
6946 return val;
6947 }
6948
6949
6950
6951
6952
6953
6954
6955
6956
6957
6958
6959
6960
6961
6962
6963
6964 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
6965 uint32 rdx, t_addr max, char term)
6966 {
6967 CONST char *tptr;
6968
6969 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {
6970 tptr = cptr + strlen ("ALL");
6971 *lo = 0;
6972 *hi = max;
6973 }
6974 else {
6975 if ((strncmp (cptr, ".", strlen (".")) == 0) &&
6976 ((cptr[1] == '\0') ||
6977 (cptr[1] == '-') ||
6978 (cptr[1] == ':') ||
6979 (cptr[1] == '/'))) {
6980 tptr = cptr + strlen (".");
6981 *lo = *hi = sim_last_addr;
6982 }
6983 else {
6984 if (strncmp (cptr, "$", strlen ("$")) == 0) {
6985 tptr = cptr + strlen ("$");
6986 *hi = *lo = (t_addr)sim_last_val;
6987 }
6988 else {
6989 if (dptr && sim_vm_parse_addr)
6990 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
6991 else
6992 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
6993 if (cptr == tptr)
6994 return NULL;
6995 }
6996 }
6997 if ((*tptr == '-') || (*tptr == ':')) {
6998 cptr = tptr + 1;
6999 if (dptr && sim_vm_parse_addr)
7000 *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7001 else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7002 if (cptr == tptr)
7003 return NULL;
7004 if (*lo > *hi)
7005 return NULL;
7006 }
7007 else if (*tptr == '/') {
7008 cptr = tptr + 1;
7009 *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7010 if ((cptr == tptr) || (*hi == 0))
7011 return NULL;
7012 *hi = *lo + *hi - 1;
7013 }
7014 else *hi = *lo;
7015 }
7016 sim_last_addr = *hi;
7017 if (term && (*tptr++ != term))
7018 return NULL;
7019 return tptr;
7020 }
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
7041 {
7042 char quote_char;
7043 uint8 *ostart = optr;
7044
7045 *osize = 0;
7046 if ((strlen(iptr) == 1) ||
7047 (iptr[0] != iptr[strlen(iptr)-1]) ||
7048 ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7049 return SCPE_ARG;
7050 quote_char = *iptr++;
7051 while (iptr[1]) {
7052 if (*iptr != '\\') {
7053 if (*iptr == quote_char)
7054 return SCPE_ARG;
7055 *(optr++) = (uint8)(*(iptr++));
7056 continue;
7057 }
7058 ++iptr;
7059 switch (*iptr) {
7060 case 'r':
7061 *(optr++) = 13; ++iptr;
7062 break;
7063 case 'n':
7064 *(optr++) = 10; ++iptr;
7065 break;
7066 case 'f':
7067 *(optr++) = 12; ++iptr;
7068 break;
7069 case 't':
7070 *(optr++) = 9; ++iptr;
7071 break;
7072 case 'v':
7073 *(optr++) = 11; ++iptr;
7074 break;
7075 case 'b':
7076 *(optr++) = 8; ++iptr;
7077 break;
7078 case '\\':
7079 *(optr++) = 92; ++iptr;
7080 break;
7081 case 'e':
7082 *(optr++) = 27; ++iptr;
7083 break;
7084 case '\'':
7085 *(optr++) = 39; ++iptr;
7086 break;
7087 case '"':
7088 *(optr++) = 34; ++iptr;
7089 break;
7090 case '?':
7091 *(optr++) = 63; ++iptr;
7092 break;
7093 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7094 *optr = *(iptr++) - '0';
7095 if ((*iptr >= '0') && (*iptr <= '7'))
7096 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7097 if ((*iptr >= '0') && (*iptr <= '7'))
7098 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7099 ++optr;
7100 break;
7101 case 'x':
7102 if (1) {
7103 static const char *hex_digits = "0123456789ABCDEF";
7104 const char *c;
7105
7106 ++iptr;
7107 *optr = 0;
7108 c = strchr (hex_digits, toupper(*iptr));
7109 if (c) {
7110 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7111 ++iptr;
7112 }
7113 c = strchr (hex_digits, toupper(*iptr));
7114 if (c) {
7115 *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7116 ++iptr;
7117 }
7118 ++optr;
7119 }
7120 break;
7121 default:
7122 return SCPE_ARG;
7123 }
7124 }
7125 *optr = '\0';
7126 *osize = (uint32)(optr-ostart);
7127 return SCPE_OK;
7128 }
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143 char *sim_encode_quoted_string (const uint8 *iptr, uint32 size)
7144 {
7145 uint32 i;
7146 t_bool double_quote_found = FALSE;
7147 t_bool single_quote_found = FALSE;
7148 char quote = '"';
7149 char *tptr, *optr;
7150
7151 optr = (char *)malloc (4*size + 3);
7152 if (optr == NULL)
7153 return NULL;
7154 tptr = optr;
7155 for (i=0; i<size; i++)
7156 switch ((char)iptr[i]) {
7157 case '"':
7158 double_quote_found = TRUE;
7159 break;
7160 case '\'':
7161 single_quote_found = TRUE;
7162 break;
7163 }
7164 if (double_quote_found && (!single_quote_found))
7165 quote = '\'';
7166 *tptr++ = quote;
7167 while (size--) {
7168 switch (*iptr) {
7169 case '\r':
7170 *tptr++ = '\\'; *tptr++ = 'r'; break;
7171 case '\n':
7172 *tptr++ = '\\'; *tptr++ = 'n'; break;
7173 case '\f':
7174 *tptr++ = '\\'; *tptr++ = 'f'; break;
7175 case '\t':
7176 *tptr++ = '\\'; *tptr++ = 't'; break;
7177 case '\v':
7178 *tptr++ = '\\'; *tptr++ = 'v'; break;
7179 case '\b':
7180 *tptr++ = '\\'; *tptr++ = 'b'; break;
7181 case '\\':
7182 *tptr++ = '\\'; *tptr++ = '\\'; break;
7183 case '"':
7184 case '\'':
7185 if (quote == *iptr)
7186 *tptr++ = '\\';
7187
7188 default:
7189 if (sim_isprint (*iptr))
7190 *tptr++ = *iptr;
7191 else {
7192 sprintf (tptr, "\\%03o", *iptr);
7193 tptr += 4;
7194 }
7195 break;
7196 }
7197 ++iptr;
7198 }
7199 *tptr++ = quote;
7200 *tptr++ = '\0';
7201 return optr;
7202 }
7203
7204 void fprint_buffer_string (FILE *st, const uint8 *buf, uint32 size)
7205 {
7206 char *string;
7207
7208 string = sim_encode_quoted_string (buf, size);
7209 fprintf (st, "%s", string);
7210 FREE (string);
7211 }
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221 DEVICE *find_dev (const char *cptr)
7222 {
7223 int32 i;
7224 DEVICE *dptr;
7225
7226 if (cptr == NULL)
7227 return NULL;
7228 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7229 if ((strcmp (cptr, dptr->name) == 0) ||
7230 (dptr->lname &&
7231 (strcmp (cptr, dptr->lname) == 0)))
7232 return dptr;
7233 }
7234 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7235 if ((strcmp (cptr, dptr->name) == 0) ||
7236 (dptr->lname &&
7237 (strcmp (cptr, dptr->lname) == 0)))
7238 return dptr;
7239 }
7240 return NULL;
7241 }
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254 DEVICE *find_unit (const char *cptr, UNIT **uptr)
7255 {
7256 uint32 i, u;
7257 const char *nptr;
7258 const char *tptr;
7259 t_stat r;
7260 DEVICE *dptr;
7261
7262 if (uptr == NULL)
7263 return NULL;
7264 *uptr = NULL;
7265 if ((dptr = find_dev (cptr))) {
7266 if (qdisable (dptr))
7267 return NULL;
7268 *uptr = dptr->units;
7269 return dptr;
7270 }
7271
7272 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7273 if (qdisable (dptr))
7274 continue;
7275 if (dptr->numunits &&
7276 (((nptr = dptr->name) &&
7277 (strncmp (cptr, nptr, strlen (nptr)) == 0)) ||
7278 ((nptr = dptr->lname) &&
7279 (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
7280 tptr = cptr + strlen (nptr);
7281 if (sim_isdigit (*tptr)) {
7282 if (qdisable (dptr))
7283 return NULL;
7284 u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
7285 if (r != SCPE_OK)
7286 *uptr = NULL;
7287 else
7288 *uptr = dptr->units + u;
7289 return dptr;
7290 }
7291 }
7292 for (u = 0; u < dptr->numunits; u++) {
7293 if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
7294 *uptr = &dptr->units[u];
7295 return dptr;
7296 }
7297 }
7298 }
7299 return NULL;
7300 }
7301
7302
7303
7304
7305
7306
7307
7308 t_stat sim_register_internal_device (DEVICE *dptr)
7309 {
7310 uint32 i;
7311
7312 for (i = 0; (sim_devices[i] != NULL); i++)
7313 if (sim_devices[i] == dptr)
7314 return SCPE_OK;
7315 for (i = 0; i < sim_internal_device_count; i++)
7316 if (sim_internal_devices[i] == dptr)
7317 return SCPE_OK;
7318 ++sim_internal_device_count;
7319 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
7320 if (!sim_internal_devices)
7321 {
7322 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
7323 __func__, __FILE__, __LINE__);
7324 #if defined(USE_BACKTRACE)
7325 # ifdef SIGUSR2
7326 (void)raise(SIGUSR2);
7327
7328 # endif
7329 #endif
7330 abort();
7331 }
7332 sim_internal_devices[sim_internal_device_count-1] = dptr;
7333 sim_internal_devices[sim_internal_device_count] = NULL;
7334 return SCPE_OK;
7335 }
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345 DEVICE *find_dev_from_unit (UNIT *uptr)
7346 {
7347 DEVICE *dptr;
7348 uint32 i, j;
7349
7350 if (uptr == NULL)
7351 return NULL;
7352 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7353 for (j = 0; j < dptr->numunits; j++) {
7354 if (uptr == (dptr->units + j))
7355 return dptr;
7356 }
7357 }
7358 for (i = 0; i<sim_internal_device_count; i++) {
7359 dptr = sim_internal_devices[i];
7360 for (j = 0; j < dptr->numunits; j++) {
7361 if (uptr == (dptr->units + j))
7362 return dptr;
7363 }
7364 }
7365 return NULL;
7366 }
7367
7368
7369
7370 t_bool qdisable (DEVICE *dptr)
7371 {
7372 return (dptr->flags & DEV_DIS? TRUE: FALSE);
7373 }
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
7388 {
7389 int32 i;
7390 DEVICE *dptr;
7391 REG *rptr, *srptr = NULL;
7392
7393 *gdptr = NULL;
7394 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {
7395 if (dptr->flags & DEV_DIS)
7396 continue;
7397 if ((rptr = find_reg (cptr, optr, dptr))) {
7398 if (srptr)
7399 return NULL;
7400 srptr = rptr;
7401 *gdptr = dptr;
7402 }
7403 }
7404 return srptr;
7405 }
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
7419 {
7420 CONST char *tptr;
7421 REG *rptr;
7422 size_t slnt;
7423
7424 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
7425 return NULL;
7426 tptr = cptr;
7427 do {
7428 tptr++;
7429 } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
7430 slnt = tptr - cptr;
7431 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
7432 if ((slnt == strlen (rptr->name)) &&
7433 (strncmp (cptr, rptr->name, slnt) == 0)) {
7434 if (optr != NULL)
7435 *optr = tptr;
7436 return rptr;
7437 }
7438 }
7439 return NULL;
7440 }
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451 int32 get_switches (const char *cptr)
7452 {
7453 int32 sw;
7454
7455 if (*cptr != '-')
7456 return 0;
7457 sw = 0;
7458 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
7459 if (sim_isalpha (*cptr) == 0)
7460 return -1;
7461 sw = sw | SWMASK (toupper (*cptr));
7462 }
7463 return sw;
7464 }
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475 CONST char *get_sim_sw (CONST char *cptr)
7476 {
7477 int32 lsw;
7478 char gbuf[CBUFSIZE];
7479
7480 while (*cptr == '-') {
7481 cptr = get_glyph (cptr, gbuf, 0);
7482 lsw = get_switches (gbuf);
7483 if (lsw <= 0)
7484 return NULL;
7485 sim_switches = sim_switches | lsw;
7486 }
7487 return cptr;
7488 }
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
7501 {
7502 int32 t;
7503 char gbuf[CBUFSIZE];
7504 CONST char *svptr;
7505 DEVICE *tdptr;
7506 UNIT *tuptr;
7507
7508 sim_switches = 0;
7509 sim_ofile = NULL;
7510 sim_schrptr = NULL;
7511 sim_schaptr = NULL;
7512 sim_stabr.logic = sim_staba.logic = SCH_OR;
7513 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
7514 sim_stabr.count = 1;
7515 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
7516 if (!sim_stabr.mask)
7517 {
7518 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
7519 __func__, __FILE__, __LINE__);
7520 #if defined(USE_BACKTRACE)
7521 # ifdef SIGUSR2
7522 (void)raise(SIGUSR2);
7523
7524 # endif
7525 #endif
7526 abort();
7527 }
7528 memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
7529 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
7530 if (!sim_stabr.comp)
7531 {
7532 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
7533 __func__, __FILE__, __LINE__);
7534 #if defined(USE_BACKTRACE)
7535 # ifdef SIGUSR2
7536 (void)raise(SIGUSR2);
7537
7538 # endif
7539 #endif
7540 abort();
7541 }
7542 memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
7543 sim_staba.count = sim_emax;
7544 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
7545 if (!sim_staba.mask)
7546 {
7547 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
7548 __func__, __FILE__, __LINE__);
7549 #if defined(USE_BACKTRACE)
7550 # ifdef SIGUSR2
7551 (void)raise(SIGUSR2);
7552
7553 # endif
7554 #endif
7555 abort();
7556 }
7557 memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
7558 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
7559 if (!sim_staba.comp)
7560 {
7561 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
7562 __func__, __FILE__, __LINE__);
7563 #if defined(USE_BACKTRACE)
7564 # ifdef SIGUSR2
7565 (void)raise(SIGUSR2);
7566
7567 # endif
7568 #endif
7569 abort();
7570 }
7571 memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
7572 if (! sim_dflt_dev)
7573 return NULL;
7574 sim_dfdev = sim_dflt_dev;
7575 sim_dfunit = sim_dfdev->units;
7576 sim_opt_out = 0;
7577 *st = SCPE_OK;
7578 while (*cptr) {
7579 svptr = cptr;
7580 if ((opt & CMD_OPT_OF) && (*cptr == '@')) {
7581 if (sim_ofile) {
7582 fclose (sim_ofile);
7583 *st = SCPE_ARG;
7584 return NULL;
7585 }
7586 cptr = get_glyph (cptr + 1, gbuf, 0);
7587 sim_ofile = sim_fopen (gbuf, "a");
7588 if (sim_ofile == NULL) {
7589 *st = SCPE_OPENERR;
7590 return NULL;
7591 }
7592 sim_opt_out |= CMD_OPT_OF;
7593 continue;
7594 }
7595 cptr = get_glyph (cptr, gbuf, 0);
7596 if ((t = get_switches (gbuf)) != 0) {
7597 if (t < 0) {
7598 *st = SCPE_INVSW;
7599 return NULL;
7600 }
7601 sim_switches = sim_switches | t;
7602 }
7603 else if ((opt & CMD_OPT_SCH) &&
7604 get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) {
7605 sim_schrptr = &sim_stabr;
7606 sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);
7607 sim_opt_out |= CMD_OPT_SCH;
7608 }
7609 else if ((opt & CMD_OPT_DFT) &&
7610 ((sim_opt_out & CMD_OPT_DFT) == 0) &&
7611 (tdptr = find_unit (gbuf, &tuptr)) &&
7612 (tuptr != NULL)) {
7613 sim_dfdev = tdptr;
7614 sim_dfunit = tuptr;
7615 sim_opt_out |= CMD_OPT_DFT;
7616 }
7617 else return svptr;
7618 }
7619 return cptr;
7620 }
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630
7631
7632 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
7633 {
7634 char *optr = buf;
7635 int32 bit;
7636
7637 memset (buf, 0, bufsize);
7638 if ((sw == 0) || (bufsize < 3))
7639 return buf;
7640 --bufsize;
7641 *optr++ = '-';
7642 for (bit=0; bit <= ('Z'-'A'); bit++)
7643 if (sw & (1 << bit))
7644 if ((size_t)(optr - buf) < bufsize)
7645 *optr++ = 'A' + bit;
7646 return buf;
7647 }
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
7661 {
7662 int32 c, logop, cmpop;
7663 t_value logval, cmpval;
7664 const char *sptr;
7665 CONST char *tptr;
7666 const char logstr[] = "|&^", cmpstr[] = "=!><";
7667
7668 logval = cmpval = 0;
7669 if (*cptr == 0)
7670 return NULL;
7671
7672 for (logop = cmpop = -1; (c = *cptr++); ) {
7673 if ((sptr = strchr (logstr, c))) {
7674 logop = (int32)(sptr - logstr);
7675 logval = strtotv (cptr, &tptr, radix);
7676 if (cptr == tptr)
7677 return NULL;
7678 cptr = tptr;
7679 }
7680 else if ((sptr = strchr (cmpstr, c))) {
7681 cmpop = (int32)(sptr - cmpstr);
7682 if (*cptr == '=') {
7683 cmpop = cmpop + strlen (cmpstr);
7684 cptr++;
7685 }
7686 cmpval = strtotv (cptr, &tptr, radix);
7687 if (cptr == tptr)
7688 return NULL;
7689 cptr = tptr;
7690 }
7691 else return NULL;
7692 }
7693 if (schptr->count != 1) {
7694 FREE (schptr->mask);
7695 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
7696 FREE (schptr->comp);
7697 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
7698 }
7699 if (logop >= 0) {
7700 schptr->logic = logop;
7701 schptr->mask[0] = logval;
7702 }
7703 if (cmpop >= 0) {
7704 schptr->boolop = cmpop;
7705 schptr->comp[0] = cmpval;
7706 }
7707 schptr->count = 1;
7708 return schptr;
7709 }
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
7723 {
7724 int32 c, logop, cmpop;
7725 t_value *logval, *cmpval;
7726 t_stat reason = SCPE_OK;
7727 CONST char *ocptr = cptr;
7728 const char *sptr;
7729 char gbuf[CBUFSIZE];
7730 const char logstr[] = "|&^", cmpstr[] = "=!><";
7731
7732 if (*cptr == 0)
7733 return NULL;
7734 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
7735 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
7736
7737 for (logop = cmpop = -1; (c = *cptr++); ) {
7738 if ((sptr = strchr (logstr, c))) {
7739 logop = (int32)(sptr - logstr);
7740 cptr = get_glyph (cptr, gbuf, 0);
7741 reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
7742 if (reason > 0) {
7743 FREE (logval);
7744 FREE (cmpval);
7745 return get_rsearch (ocptr, radix, schptr);
7746 }
7747 }
7748 else if ((sptr = strchr (cmpstr, c))) {
7749 cmpop = (int32)(sptr - cmpstr);
7750 if (*cptr == '=') {
7751 cmpop = cmpop + strlen (cmpstr);
7752 cptr++;
7753 }
7754 cptr = get_glyph (cptr, gbuf, 0);
7755 reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
7756 if (reason > 0) {
7757 FREE (logval);
7758 FREE (cmpval);
7759 return get_rsearch (ocptr, radix, schptr);
7760 }
7761 }
7762 else {
7763 FREE (logval);
7764 FREE (cmpval);
7765 return NULL;
7766 }
7767 }
7768 if (schptr->count != (uint32)(1 - reason)) {
7769 schptr->count = 1 - reason;
7770 FREE (schptr->mask);
7771 schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
7772 FREE (schptr->comp);
7773 schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
7774 }
7775 if (logop >= 0) {
7776 schptr->logic = logop;
7777 FREE (schptr->mask);
7778 schptr->mask = logval;
7779 }
7780 else {
7781 FREE (logval);
7782 }
7783 if (cmpop >= 0) {
7784 schptr->boolop = cmpop;
7785 FREE (schptr->comp);
7786 schptr->comp = cmpval;
7787 }
7788 else {
7789 FREE (cmpval);
7790 }
7791 return schptr;
7792 }
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803 int32 test_search (t_value *values, SCHTAB *schptr)
7804 {
7805 t_value *val = NULL;
7806 int32 i, updown;
7807 int32 ret = 0;
7808
7809 if (schptr == NULL)
7810 return ret;
7811
7812 val = (t_value *)malloc (schptr->count * sizeof (*values));
7813 if (!val)
7814 {
7815 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
7816 __func__, __FILE__, __LINE__);
7817 #if defined(USE_BACKTRACE)
7818 # ifdef SIGUSR2
7819 (void)raise(SIGUSR2);
7820
7821 # endif
7822 #endif
7823 abort();
7824 }
7825 for (i=0; i<(int32)schptr->count; i++) {
7826 val[i] = values[i];
7827 switch (schptr->logic) {
7828
7829 case SCH_OR:
7830 val[i] = val[i] | schptr->mask[i];
7831 break;
7832
7833 case SCH_AND:
7834 val[i] = val[i] & schptr->mask[i];
7835 break;
7836
7837 case SCH_XOR:
7838 val[i] = val[i] ^ schptr->mask[i];
7839 break;
7840 }
7841 }
7842
7843 ret = 1;
7844 if (1) {
7845 updown = -1;
7846 i=schptr->count-1;
7847 }
7848 else {
7849 updown = 1;
7850 i=0;
7851 }
7852 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
7853 switch (schptr->boolop) {
7854
7855 case SCH_E: case SCH_EE:
7856 if (val[i] != schptr->comp[i])
7857 ret = 0;
7858 break;
7859
7860 case SCH_N: case SCH_NE:
7861 if (val[i] == schptr->comp[i])
7862 ret = 0;
7863 break;
7864
7865 case SCH_G:
7866 if (val[i] <= schptr->comp[i])
7867 ret = 0;
7868 break;
7869
7870 case SCH_GE:
7871 if (val[i] < schptr->comp[i])
7872 ret = 0;
7873 break;
7874
7875 case SCH_L:
7876 if (val[i] >= schptr->comp[i])
7877 ret = 0;
7878 break;
7879
7880 case SCH_LE:
7881 if (val[i] > schptr->comp[i])
7882 ret = 0;
7883 break;
7884 }
7885 }
7886 FREE (val);
7887 return ret;
7888 }
7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
7905 {
7906 int32 nodigit;
7907 t_value val;
7908 uint32 c, digit;
7909
7910 *endptr = inptr;
7911 if ((radix < 2) || (radix > 36))
7912 return 0;
7913 while (sim_isspace (*inptr))
7914 inptr++;
7915 val = 0;
7916 nodigit = 1;
7917 for (c = *inptr; sim_isalnum(c); c = *++inptr) {
7918 if (sim_islower (c))
7919 c = toupper (c);
7920 if (sim_isdigit (c))
7921 digit = c - (uint32) '0';
7922 else if (radix <= 10)
7923 break;
7924 else digit = c + 10 - (uint32) 'A';
7925 if (digit >= radix)
7926 return 0;
7927 val = (val * radix) + digit;
7928 nodigit = 0;
7929 }
7930 if (nodigit)
7931 return 0;
7932 *endptr = inptr;
7933 return val;
7934 }
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
7951 uint32 width, uint32 format)
7952 {
7953 #define MAX_WIDTH ((int) ((CHAR_BIT * sizeof (t_value) * 4 + 3)/3))
7954 t_value owtest, wtest;
7955 int32 d, digit, ndigits, commas = 0;
7956 char dbuf[MAX_WIDTH + 1];
7957
7958 for (d = 0; d < MAX_WIDTH; d++)
7959 dbuf[d] = (format == PV_RZRO)? '0': ' ';
7960 dbuf[MAX_WIDTH] = 0;
7961 d = MAX_WIDTH;
7962 do {
7963 d = d - 1;
7964 digit = (int32) (val % radix);
7965 val = val / radix;
7966 dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
7967 } while ((d > 0) && (val != 0));
7968
7969 switch (format) {
7970 case PV_LEFT:
7971 break;
7972 case PV_RCOMMA:
7973 for (digit = 0; digit < MAX_WIDTH; digit++)
7974 if (dbuf[digit] != ' ')
7975 break;
7976 ndigits = MAX_WIDTH - digit;
7977 commas = (ndigits - 1)/3;
7978 for (digit=0; digit<ndigits-3; digit++)
7979 dbuf[MAX_WIDTH + (digit - ndigits) - (ndigits - digit - 1)/3] = dbuf[MAX_WIDTH + (digit - ndigits)];
7980 for (digit=1; digit<=commas; digit++)
7981 dbuf[MAX_WIDTH - (digit * 4)] = ',';
7982 d = d - commas;
7983 if (width > MAX_WIDTH) {
7984 if (!buffer)
7985 return width;
7986 sprintf (buffer, "%*s", -((int)width), dbuf);
7987 return SCPE_OK;
7988 }
7989 else
7990 if (width > 0)
7991 d = MAX_WIDTH - width;
7992 break;
7993 case PV_RZRO:
7994 case PV_RSPC:
7995 wtest = owtest = radix;
7996 ndigits = 1;
7997 while ((wtest < width_mask[width]) && (wtest >= owtest)) {
7998 owtest = wtest;
7999 wtest = wtest * radix;
8000 ndigits = ndigits + 1;
8001 }
8002 if ((MAX_WIDTH - (ndigits + commas)) < d)
8003 d = MAX_WIDTH - (ndigits + commas);
8004 break;
8005 }
8006 if (!buffer)
8007 return strlen(dbuf+d);
8008 *buffer = '\0';
8009 if (width < strlen(dbuf+d))
8010 return SCPE_IOERR;
8011 strcpy(buffer, dbuf+d);
8012 return SCPE_OK;
8013 }
8014
8015 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
8016 uint32 width, uint32 format)
8017 {
8018 char dbuf[MAX_WIDTH + 1];
8019
8020 if (!stream)
8021 return sprint_val (NULL, val, radix, width, format);
8022 if (width > MAX_WIDTH)
8023 width = MAX_WIDTH;
8024 sprint_val (dbuf, val, radix, width, format);
8025 if (Fprintf (stream, "%s", dbuf) < 0)
8026 return SCPE_IOERR;
8027 return SCPE_OK;
8028 }
8029
8030 const char *sim_fmt_secs (double seconds)
8031 {
8032 static char buf[60];
8033 char frac[16] = "";
8034 const char *sign = "";
8035 double val = seconds;
8036 double days, hours, mins, secs, msecs, usecs;
8037
8038 if (val == 0.0)
8039 return "";
8040 if (val < 0.0) {
8041 sign = "-";
8042 val = -val;
8043 }
8044 days = floor (val / (24.0*60.0*60.0));
8045 val -= (days * 24.0*60.0*60.0);
8046 hours = floor (val / (60.0*60.0));
8047 val -= (hours * 60.0 * 60.0);
8048 mins = floor (val / 60.0);
8049 val -= (mins * 60.0);
8050 secs = floor (val);
8051 val -= secs;
8052 val *= 1000.0;
8053 msecs = floor (val);
8054 val -= msecs;
8055 val *= 1000.0;
8056 usecs = floor (val+0.5);
8057 if (usecs == 1000.0) {
8058 usecs = 0.0;
8059 msecs += 1;
8060 }
8061 if ((msecs > 0.0) || (usecs > 0.0)) {
8062 sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8063 while (frac[strlen (frac) - 1] == '0')
8064 frac[strlen (frac) - 1] = '\0';
8065 if (strlen (frac) == 1)
8066 frac[0] = '\0';
8067 }
8068 if (days > 0)
8069 sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s", sign, days, (days != 1)? "s" : "", hours, mins, secs, frac, (days == 1) ? "s" : "");
8070 else
8071 if (hours > 0)
8072 sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour", sign, hours, mins, secs, frac);
8073 else
8074 if (mins > 0)
8075 sprintf (buf, "%s%.0f:%02.0f%s minute", sign, mins, secs, frac);
8076 else
8077 if (secs > 0)
8078 sprintf (buf, "%s%.0f%s second", sign, secs, frac);
8079 else
8080 if (msecs > 0) {
8081 if (usecs > 0)
8082 sprintf (buf, "%s%.0f.%s msec", sign, msecs, frac+4);
8083 else
8084 sprintf (buf, "%s%.0f msec", sign, msecs);
8085 }
8086 else
8087 sprintf (buf, "%s%.0f usec", sign, usecs);
8088 if (0 != strncmp ("1 ", buf, 2))
8089 strcpy (&buf[strlen (buf)], "s");
8090 return buf;
8091 }
8092
8093
8094
8095
8096
8097
8098
8099
8100
8101
8102
8103
8104
8105
8106
8107
8108 t_stat sim_process_event (void)
8109 {
8110 UNIT *uptr;
8111 t_stat reason;
8112
8113 if (stop_cpu)
8114 {
8115 #ifdef WIN_STDIO
8116 (void)fflush(stdout);
8117 (void)fflush(stderr);
8118 #endif
8119 return SCPE_STOP;
8120 }
8121 UPDATE_SIM_TIME;
8122
8123 if (sim_clock_queue == QUEUE_LIST_END) {
8124 sim_interval = noqueue_time = NOQUEUE_WAIT;
8125 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Queue Empty New Interval = %d\n", sim_interval);
8126 return SCPE_OK;
8127 }
8128 sim_processing_event = TRUE;
8129 do {
8130 uptr = sim_clock_queue;
8131 sim_clock_queue = uptr->next;
8132 uptr->next = NULL;
8133 sim_interval -= uptr->time;
8134 uptr->time = 0;
8135 if (sim_clock_queue != QUEUE_LIST_END)
8136 sim_interval = sim_clock_queue->time;
8137 else
8138 sim_interval = noqueue_time = NOQUEUE_WAIT;
8139 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Processing Event for %s\n", sim_uname (uptr));
8140 if (uptr->action != NULL)
8141 reason = uptr->action (uptr);
8142 else
8143 reason = SCPE_OK;
8144 } while ((reason == SCPE_OK) &&
8145 (sim_interval <= 0) &&
8146 (sim_clock_queue != QUEUE_LIST_END) &&
8147 (!stop_cpu));
8148
8149 if (sim_clock_queue == QUEUE_LIST_END) {
8150 sim_interval = noqueue_time = NOQUEUE_WAIT;
8151 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Processing Queue Complete New Interval = %d\n", sim_interval);
8152 }
8153 else
8154 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Processing Queue Complete New Interval = %d(%s)\n", sim_interval, sim_uname(sim_clock_queue));
8155
8156 if ((reason == SCPE_OK) && stop_cpu)
8157 {
8158 #ifdef WIN_STDIO
8159 (void)fflush(stdout);
8160 (void)fflush(stderr);
8161 #endif
8162 reason = SCPE_STOP;
8163 }
8164 sim_processing_event = FALSE;
8165 return reason;
8166 }
8167
8168
8169
8170
8171
8172
8173
8174
8175
8176
8177 t_stat sim_activate (UNIT *uptr, int32 event_time)
8178 {
8179 if (uptr->dynflags & UNIT_TMR_UNIT)
8180 return sim_timer_activate (uptr, event_time);
8181 return _sim_activate (uptr, event_time);
8182 }
8183
8184 t_stat _sim_activate (UNIT *uptr, int32 event_time)
8185 {
8186 UNIT *cptr, *prvptr;
8187 int32 accum;
8188
8189 if (sim_is_active (uptr))
8190 return SCPE_OK;
8191 UPDATE_SIM_TIME;
8192
8193 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\n", sim_uname (uptr), event_time);
8194
8195 prvptr = NULL;
8196 accum = 0;
8197 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8198 if (event_time < (accum + cptr->time))
8199 break;
8200 accum = accum + cptr->time;
8201 prvptr = cptr;
8202 }
8203 if (prvptr == NULL) {
8204 cptr = uptr->next = sim_clock_queue;
8205 sim_clock_queue = uptr;
8206 }
8207 else {
8208 cptr = uptr->next = prvptr->next;
8209 prvptr->next = uptr;
8210 }
8211 uptr->time = event_time - accum;
8212 if (cptr != QUEUE_LIST_END)
8213 cptr->time = cptr->time - uptr->time;
8214 sim_interval = sim_clock_queue->time;
8215 return SCPE_OK;
8216 }
8217
8218
8219
8220
8221
8222
8223
8224
8225
8226
8227 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
8228 {
8229 sim_cancel (uptr);
8230 return _sim_activate (uptr, event_time);
8231 }
8232
8233
8234
8235
8236
8237
8238
8239
8240
8241
8242 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
8243 {
8244 return _sim_activate_after (uptr, usec_delay);
8245 }
8246
8247 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
8248 {
8249 if (sim_is_active (uptr))
8250 return SCPE_OK;
8251 return sim_timer_activate_after (uptr, usec_delay);
8252 }
8253
8254
8255
8256
8257
8258
8259
8260
8261
8262
8263 t_stat sim_cancel (UNIT *uptr)
8264 {
8265 UNIT *cptr, *nptr;
8266
8267 if (sim_clock_queue == QUEUE_LIST_END)
8268 return SCPE_OK;
8269 if (!sim_is_active (uptr))
8270 return SCPE_OK;
8271 UPDATE_SIM_TIME;
8272 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\n", sim_uname(uptr));
8273 nptr = QUEUE_LIST_END;
8274
8275 if (sim_clock_queue == uptr) {
8276 nptr = sim_clock_queue = uptr->next;
8277 uptr->next = NULL;
8278 }
8279 else {
8280 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8281 if (cptr->next == uptr) {
8282 nptr = cptr->next = uptr->next;
8283 uptr->next = NULL;
8284 break;
8285 }
8286 }
8287 }
8288 if (nptr != QUEUE_LIST_END)
8289 nptr->time += (uptr->next) ? 0 : uptr->time;
8290 if (!uptr->next)
8291 uptr->time = 0;
8292 if (sim_clock_queue != QUEUE_LIST_END)
8293 sim_interval = sim_clock_queue->time;
8294 else sim_interval = noqueue_time = NOQUEUE_WAIT;
8295 if (uptr->next) {
8296 sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
8297 if (sim_deb)
8298 fclose(sim_deb);
8299 fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
8300 __func__, __FILE__, __LINE__);
8301 abort ();
8302 }
8303 return SCPE_OK;
8304 }
8305
8306
8307
8308
8309
8310
8311
8312
8313
8314 t_bool sim_is_active (UNIT *uptr)
8315 {
8316 if (uptr->next == NULL)
8317 return FALSE;
8318 else
8319 return TRUE;
8320 }
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330 int32 sim_activate_time (UNIT *uptr)
8331 {
8332 UNIT *cptr;
8333 int32 accum = 0;
8334
8335 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8336 if (cptr == sim_clock_queue) {
8337 if (sim_interval > 0)
8338 accum = accum + sim_interval;
8339 }
8340 else
8341 accum = accum + cptr->time;
8342 if (cptr == uptr)
8343 return accum + 1;
8344 }
8345 return 0;
8346 }
8347
8348
8349
8350
8351
8352
8353
8354
8355 double sim_gtime (void)
8356 {
8357 return sim_time;
8358 }
8359
8360
8361
8362
8363
8364
8365
8366
8367 int32 sim_qcount (void)
8368 {
8369 int32 cnt;
8370 UNIT *uptr;
8371
8372 cnt = 0;
8373 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
8374 cnt++;
8375 return cnt;
8376 }
8377
8378
8379
8380
8381
8382
8383
8384
8385
8386
8387
8388
8389
8390
8391
8392
8393
8394
8395
8396
8397
8398
8399
8400
8401
8402
8403
8404
8405
8406
8407
8408
8409
8410
8411
8412
8413 t_stat sim_brk_init (void)
8414 {
8415 int32 i;
8416
8417 for (i=0; i<sim_brk_lnt; i++) {
8418 BRKTAB *bp;
8419 if (sim_brk_tab)
8420 {
8421 bp = sim_brk_tab[i];
8422
8423 while (bp)
8424 {
8425 BRKTAB *bpt = bp->next;
8426
8427 FREE (bp->act);
8428 FREE (bp);
8429 bp = bpt;
8430 }
8431 }
8432 }
8433 if (sim_brk_tab != NULL)
8434 memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
8435 sim_brk_lnt = SIM_BRK_INILNT;
8436 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
8437 if (sim_brk_tab == NULL)
8438 return SCPE_MEM;
8439 memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
8440 sim_brk_ent = sim_brk_ins = 0;
8441 sim_brk_clract ();
8442 sim_brk_npc (0);
8443 return SCPE_OK;
8444 }
8445
8446
8447
8448 BRKTAB *sim_brk_fnd (t_addr loc)
8449 {
8450 int32 lo, hi, p;
8451 BRKTAB *bp;
8452
8453 if (sim_brk_ent == 0) {
8454 sim_brk_ins = 0;
8455 return NULL;
8456 }
8457 lo = 0;
8458 hi = sim_brk_ent - 1;
8459 do {
8460 p = (lo + hi) >> 1;
8461 bp = sim_brk_tab[p];
8462 if (loc == bp->addr) {
8463 sim_brk_ins = p;
8464 return bp;
8465 }
8466 else if (loc < bp->addr)
8467 hi = p - 1;
8468 else lo = p + 1;
8469 } while (lo <= hi);
8470 if (loc < bp->addr)
8471 sim_brk_ins = p;
8472 else sim_brk_ins = p + 1;
8473 return NULL;
8474 }
8475
8476 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
8477 {
8478 BRKTAB *bp = sim_brk_fnd (loc);
8479
8480 while (bp) {
8481 if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
8482 (bp->typ == btyp))
8483 return bp;
8484 bp = bp->next;
8485 }
8486 return bp;
8487 }
8488
8489
8490
8491 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
8492 {
8493 int32 i, t;
8494 BRKTAB *bp, **newp;
8495
8496 if (sim_brk_ins < 0)
8497 return NULL;
8498 if (sim_brk_ent >= sim_brk_lnt) {
8499 t = sim_brk_lnt + SIM_BRK_INILNT;
8500 newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));
8501 if (newp == NULL)
8502 return NULL;
8503 memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));
8504 memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));
8505 FREE (sim_brk_tab);
8506 sim_brk_tab = newp;
8507 sim_brk_lnt = t;
8508 }
8509 if ((sim_brk_ins == sim_brk_ent) ||
8510 ((sim_brk_ins != sim_brk_ent) &&
8511 (sim_brk_tab[sim_brk_ins]->addr != loc))) {
8512 for (i = sim_brk_ent; i > sim_brk_ins; --i)
8513 sim_brk_tab[i] = sim_brk_tab[i - 1];
8514 sim_brk_tab[sim_brk_ins] = NULL;
8515 }
8516 bp = (BRKTAB *)calloc (1, sizeof (*bp));
8517 if (!bp)
8518 {
8519 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8520 __func__, __FILE__, __LINE__);
8521 #if defined(USE_BACKTRACE)
8522 # ifdef SIGUSR2
8523 (void)raise(SIGUSR2);
8524
8525 # endif
8526 #endif
8527 abort();
8528 }
8529 bp->next = sim_brk_tab[sim_brk_ins];
8530 sim_brk_tab[sim_brk_ins] = bp;
8531 if (bp->next == NULL)
8532 sim_brk_ent += 1;
8533 bp->addr = loc;
8534 bp->typ = btyp;
8535 bp->cnt = 0;
8536 bp->act = NULL;
8537 for (i = 0; i < SIM_BKPT_N_SPC; i++)
8538 bp->time_fired[i] = -1.0;
8539 return bp;
8540 }
8541
8542
8543
8544 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
8545 {
8546 BRKTAB *bp;
8547
8548 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
8549 sw |= sim_brk_dflt;
8550 if (~sim_brk_types & sw) {
8551 char gbuf[CBUFSIZE];
8552
8553 return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
8554 }
8555 if ((sw & BRK_TYP_DYN_ALL) && act)
8556 return SCPE_ARG;
8557 bp = sim_brk_fnd (loc);
8558 if (!bp)
8559 bp = sim_brk_new (loc, sw);
8560 else {
8561 while (bp && (bp->typ != (uint32)sw))
8562 bp = bp->next;
8563 if (!bp)
8564 bp = sim_brk_new (loc, sw);
8565 }
8566 if (!bp)
8567 return SCPE_MEM;
8568 bp->cnt = ncnt;
8569 if ((!(sw & BRK_TYP_DYN_ALL)) &&
8570 (bp->act != NULL) && (act != NULL)) {
8571 FREE (bp->act);
8572 bp->act = NULL;
8573 }
8574 if ((act != NULL) && (*act != 0)) {
8575 char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char));
8576 if (newp == NULL)
8577 return SCPE_MEM;
8578 strncpy (newp, act, CBUFSIZE);
8579 bp->act = newp;
8580 }
8581 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
8582 return SCPE_OK;
8583 }
8584
8585
8586
8587 t_stat sim_brk_clr (t_addr loc, int32 sw)
8588 {
8589 BRKTAB *bpl = NULL;
8590 BRKTAB *bp = sim_brk_fnd (loc);
8591 int32 i;
8592
8593 if (!bp)
8594 return SCPE_OK;
8595 if (sw == 0)
8596 sw = SIM_BRK_ALLTYP;
8597
8598 #ifndef __clang_analyzer__
8599 while (bp) {
8600 if (bp->typ == (bp->typ & sw)) {
8601 FREE (bp->act);
8602 if (bp == sim_brk_tab[sim_brk_ins])
8603 bpl = sim_brk_tab[sim_brk_ins] = bp->next;
8604 else
8605 {
8606 if (bpl)
8607 bpl->next = bp->next;
8608 }
8609 FREE (bp);
8610 bp = bpl;
8611 }
8612 else {
8613 bpl = bp;
8614 bp = bp->next;
8615 }
8616 }
8617 #endif
8618 if (sim_brk_tab[sim_brk_ins] == NULL) {
8619 sim_brk_ent = sim_brk_ent - 1;
8620 for (i = sim_brk_ins; i < sim_brk_ent; i++)
8621 sim_brk_tab[i] = sim_brk_tab[i+1];
8622 }
8623 sim_brk_summ = 0;
8624 for (i = 0; i < sim_brk_ent; i++) {
8625 bp = sim_brk_tab[i];
8626 while (bp) {
8627 sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
8628 bp = bp->next;
8629 }
8630 }
8631 return SCPE_OK;
8632 }
8633
8634
8635
8636 t_stat sim_brk_clrall (int32 sw)
8637 {
8638 int32 i;
8639
8640 if (sw == 0)
8641 sw = SIM_BRK_ALLTYP;
8642 for (i = 0; i < sim_brk_ent;) {
8643 t_addr loc = sim_brk_tab[i]->addr;
8644 sim_brk_clr (loc, sw);
8645 if ((i < sim_brk_ent) &&
8646 (loc == sim_brk_tab[i]->addr))
8647 ++i;
8648 }
8649 return SCPE_OK;
8650 }
8651
8652
8653
8654 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
8655 {
8656 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
8657 DEVICE *dptr;
8658 int32 i, any;
8659
8660 if ((sw == 0) || (sw == SWMASK ('C')))
8661 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
8662 if (!bp || (!(bp->typ & sw)))
8663 return SCPE_OK;
8664 dptr = sim_dflt_dev;
8665 if (dptr == NULL)
8666 return SCPE_OK;
8667 if (sw & SWMASK ('C'))
8668 fprintf (st, "SET BREAK ");
8669 else {
8670 if (sim_vm_fprint_addr)
8671 sim_vm_fprint_addr (st, dptr, loc);
8672 else fprint_val (st, loc, dptr->aradix, dptr->awidth, PV_LEFT);
8673 fprintf (st, ":\t");
8674 }
8675 for (i = any = 0; i < 26; i++) {
8676 if ((bp->typ >> i) & 1) {
8677 if ((sw & SWMASK ('C')) == 0) {
8678 if (any)
8679 fprintf (st, ", ");
8680 fputc (i + 'A', st);
8681 }
8682 else
8683 fprintf (st, "-%c", i + 'A');
8684 any = 1;
8685 }
8686 }
8687 if (sw & SWMASK ('C')) {
8688 fprintf (st, " ");
8689 if (sim_vm_fprint_addr)
8690 sim_vm_fprint_addr (st, dptr, loc);
8691 else fprint_val (st, loc, dptr->aradix, dptr->awidth, PV_LEFT);
8692 }
8693 if (bp->cnt > 0)
8694 fprintf (st, "[%d]", bp->cnt);
8695 if (bp->act != NULL)
8696 fprintf (st, "; %s", bp->act);
8697 fprintf (st, "\n");
8698 return SCPE_OK;
8699 }
8700
8701
8702
8703 t_stat sim_brk_showall (FILE *st, int32 sw)
8704 {
8705 int32 bit, mask, types;
8706 BRKTAB **bpt;
8707
8708 if ((sw == 0) || (sw == SWMASK ('C')))
8709 sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
8710 for (types=bit=0; bit <= ('Z'-'A'); bit++)
8711 if (sim_brk_types & (1 << bit))
8712 ++types;
8713 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
8714 fprintf (st, "Supported Breakpoint Types:");
8715 for (bit=0; bit <= ('Z'-'A'); bit++)
8716 if (sim_brk_types & (1 << bit))
8717 fprintf (st, " -%c", 'A' + bit);
8718 fprintf (st, "\n");
8719 }
8720 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
8721 mask = (sw & sim_brk_types);
8722 fprintf (st, "Displaying Breakpoint Types:");
8723 for (bit=0; bit <= ('Z'-'A'); bit++)
8724 if (mask & (1 << bit))
8725 fprintf (st, " -%c", 'A' + bit);
8726 fprintf (st, "\n");
8727 }
8728 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
8729 BRKTAB *prev = NULL;
8730 BRKTAB *cur = *bpt;
8731 BRKTAB *next;
8732
8733 while (cur) {
8734 next = cur->next;
8735 cur->next = prev;
8736 prev = cur;
8737 cur = next;
8738 }
8739
8740 *bpt = prev;
8741
8742 cur = prev;
8743 while (cur) {
8744 if (cur->typ & sw)
8745 sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
8746 cur = cur->next;
8747 }
8748
8749 cur = prev;
8750 prev = NULL;
8751 while (cur) {
8752 next = cur->next;
8753 cur->next = prev;
8754 prev = cur;
8755 cur = next;
8756 }
8757
8758 *bpt = prev;
8759 }
8760 return SCPE_OK;
8761 }
8762
8763
8764
8765 uint32 sim_brk_test (t_addr loc, uint32 btyp)
8766 {
8767 BRKTAB *bp;
8768 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
8769
8770 if (sim_brk_summ & BRK_TYP_DYN_ALL)
8771 btyp |= BRK_TYP_DYN_ALL;
8772
8773 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {
8774 double s_gtime = sim_gtime ();
8775
8776 if (bp->time_fired[spc] == s_gtime)
8777 return 0;
8778 bp->time_fired[spc] = s_gtime;
8779 if (--bp->cnt > 0)
8780 return 0;
8781 bp->cnt = 0;
8782 sim_brk_setact (bp->act);
8783 sim_brk_match_type = btyp & bp->typ;
8784 if (bp->typ & BRK_TYP_TEMP)
8785 sim_brk_clr (loc, bp->typ);
8786 sim_brk_match_addr = loc;
8787 return sim_brk_match_type;
8788 }
8789 return 0;
8790 }
8791
8792
8793
8794 CONST char *sim_brk_getact (char *buf, int32 size)
8795 {
8796 char *ep;
8797 size_t lnt;
8798
8799 if (sim_brk_act[sim_do_depth] == NULL)
8800 return NULL;
8801 while (sim_isspace (*sim_brk_act[sim_do_depth]))
8802 sim_brk_act[sim_do_depth]++;
8803 if (*sim_brk_act[sim_do_depth] == 0) {
8804 return sim_brk_clract ();
8805 }
8806 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {
8807 lnt = ep - sim_brk_act[sim_do_depth];
8808 memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);
8809 buf[lnt] = 0;
8810 sim_brk_act[sim_do_depth] += lnt + 1;
8811 }
8812 else {
8813 strncpy (buf, sim_brk_act[sim_do_depth], size);
8814 sim_brk_clract ();
8815 }
8816 return buf;
8817 }
8818
8819
8820
8821 char *sim_brk_clract (void)
8822 {
8823 FREE (sim_brk_act_buf[sim_do_depth]);
8824 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
8825 }
8826
8827
8828
8829 void sim_brk_setact (const char *action)
8830 {
8831 if (action) {
8832 sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
8833 if (!sim_brk_act_buf[sim_do_depth])
8834 {
8835 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8836 __func__, __FILE__, __LINE__);
8837 #if defined(USE_BACKTRACE)
8838 # ifdef SIGUSR2
8839 (void)raise(SIGUSR2);
8840
8841 # endif
8842 #endif
8843 abort();
8844 }
8845 strcpy (sim_brk_act_buf[sim_do_depth], action);
8846 sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
8847 }
8848 else
8849 sim_brk_clract ();
8850 }
8851
8852
8853
8854 void sim_brk_npc (uint32 cnt)
8855 {
8856 uint32 spc;
8857 BRKTAB **bpt, *bp;
8858
8859 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
8860 cnt = SIM_BKPT_N_SPC;
8861 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
8862 for (bp = *bpt; bp; bp = bp->next) {
8863 for (spc = 0; spc < cnt; spc++)
8864 bp->time_fired[spc] = -1.0;
8865 }
8866 }
8867 }
8868
8869
8870
8871 void sim_brk_clrspc (uint32 spc, uint32 btyp)
8872 {
8873 BRKTAB **bpt, *bp;
8874
8875 if (spc < SIM_BKPT_N_SPC) {
8876 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
8877 for (bp = *bpt; bp; bp = bp->next) {
8878 if (bp->typ & btyp)
8879 bp->time_fired[spc] = -1.0;
8880 }
8881 }
8882 }
8883 }
8884
8885 const char *sim_brk_message(void)
8886 {
8887 static char msg[256];
8888 char addr[65];
8889 char buf[32];
8890
8891 msg[0] = '\0';
8892 if (sim_dflt_dev) {
8893 if (sim_vm_sprint_addr)
8894 sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
8895 else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
8896 }
8897 if (sim_brk_type_desc) {
8898 BRKTYPTAB *brk = sim_brk_type_desc;
8899
8900 while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
8901 if (brk->btyp == sim_brk_match_type) {
8902 sprintf (msg, "%s: %s", brk->desc, addr);
8903 break;
8904 }
8905 brk++;
8906 }
8907 }
8908 if (!msg[0])
8909 sprintf (msg, "%s Breakpoint at: %s\n", put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
8910
8911 return msg;
8912 }
8913
8914
8915
8916
8917
8918
8919
8920
8921
8922
8923
8924
8925
8926
8927
8928
8929
8930
8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944
8945
8946
8947
8948
8949
8950 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
8951 {
8952 char gbuf[CBUFSIZE];
8953 CONST char *tptr;
8954 CONST char *c1ptr;
8955 t_bool after_set = FALSE;
8956 uint32 after;
8957 int32 cnt = 0;
8958 t_stat r;
8959
8960 if (exp == NULL)
8961 return sim_messagef (SCPE_ARG, "Null exp!\n");
8962 after = exp->after;
8963
8964 if ((cptr == NULL) || (*cptr == 0))
8965 return SCPE_2FARG;
8966 if (*cptr == '[') {
8967 cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
8968 if ((cptr == c1ptr) || (*c1ptr != ']'))
8969 return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n");
8970 cptr = c1ptr + 1;
8971 while (sim_isspace(*cptr))
8972 ++cptr;
8973 }
8974 tptr = get_glyph (cptr, gbuf, ',');
8975 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
8976 after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
8977 if (r != SCPE_OK)
8978 return sim_messagef (SCPE_ARG, "Invalid Halt After Value\n");
8979 after_set = TRUE;
8980 cptr = tptr;
8981 }
8982 if ((*cptr != '"') && (*cptr != '\''))
8983 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
8984 cptr = get_glyph_quoted (cptr, gbuf, 0);
8985
8986 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
8987 }
8988
8989
8990
8991 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
8992 {
8993 char gbuf[CBUFSIZE];
8994
8995 if (!cptr || !*cptr)
8996 return sim_exp_clrall (exp);
8997 if ((*cptr != '"') && (*cptr != '\''))
8998 return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
8999 cptr = get_glyph_quoted (cptr, gbuf, 0);
9000 if (*cptr != '\0')
9001 return SCPE_2MARG;
9002 return sim_exp_clr (exp, gbuf);
9003 }
9004
9005
9006
9007 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, int32 start_rule)
9008 {
9009 int32 i;
9010
9011 if (!exp->rules)
9012 return NULL;
9013 for (i=start_rule; i<exp->size; i++)
9014 if (!strcmp (exp->rules[i].match_pattern, match))
9015 return &exp->rules[i];
9016 return NULL;
9017 }
9018
9019
9020
9021 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
9022 {
9023 int32 i;
9024
9025 if (!ep)
9026 return SCPE_OK;
9027 FREE (ep->match);
9028 FREE (ep->match_pattern);
9029 FREE (ep->act);
9030 exp->size -= 1;
9031 #ifndef __clang_analyzer__
9032 for (i=ep-exp->rules; i<exp->size; i++)
9033 exp->rules[i] = exp->rules[i+1];
9034 if (exp->size == 0) {
9035 FREE (exp->rules);
9036 exp->rules = NULL;
9037 }
9038 #endif
9039 return SCPE_OK;
9040 }
9041
9042 t_stat sim_exp_clr (EXPECT *exp, const char *match)
9043 {
9044 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9045
9046 while (ep) {
9047 sim_exp_clr_tab (exp, ep);
9048 ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9049 }
9050 return SCPE_OK;
9051 }
9052
9053
9054
9055 t_stat sim_exp_clrall (EXPECT *exp)
9056 {
9057 int32 i;
9058
9059 for (i=0; i<exp->size; i++) {
9060 FREE (exp->rules[i].match);
9061 FREE (exp->rules[i].match_pattern);
9062 FREE (exp->rules[i].act);
9063 }
9064 FREE (exp->rules);
9065 exp->rules = NULL;
9066 exp->size = 0;
9067 FREE (exp->buf);
9068 exp->buf = NULL;
9069 exp->buf_size = 0;
9070 exp->buf_ins = 0;
9071 return SCPE_OK;
9072 }
9073
9074
9075
9076 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
9077 {
9078 EXPTAB *ep;
9079 uint8 *match_buf;
9080 uint32 match_size;
9081 int i;
9082
9083
9084 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9085 if (!match_buf)
9086 return SCPE_MEM;
9087 if (switches & EXP_TYP_REGEX) {
9088 FREE (match_buf);
9089 return sim_messagef (SCPE_ARG, "RegEx support not available\n");
9090 }
9091 else {
9092 if (switches & EXP_TYP_REGEX_I) {
9093 FREE (match_buf);
9094 return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\n");
9095 }
9096 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9097 if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9098 FREE (match_buf);
9099 return sim_messagef (SCPE_ARG, "Invalid quoted string\n");
9100 }
9101 }
9102 FREE (match_buf);
9103 for (i=0; i<exp->size; i++) {
9104 if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9105 (exp->rules[i].switches & EXP_TYP_PERSIST))
9106 return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\n");
9107 }
9108 if (after && exp->size)
9109 return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n");
9110 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9111 if (!exp->rules)
9112 {
9113 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9114 __func__, __FILE__, __LINE__);
9115 #if defined(USE_BACKTRACE)
9116 # ifdef SIGUSR2
9117 (void)raise(SIGUSR2);
9118
9119 # endif
9120 #endif
9121 abort();
9122 }
9123 ep = &exp->rules[exp->size];
9124 exp->size += 1;
9125 exp->after = after;
9126 memset (ep, 0, sizeof(*ep));
9127 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9128 if (ep->match_pattern)
9129 strcpy (ep->match_pattern, match);
9130 ep->cnt = cnt;
9131 ep->switches = switches;
9132 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9133 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9134 sim_exp_clr_tab (exp, ep);
9135 FREE (match_buf);
9136 return SCPE_MEM;
9137 }
9138 if (switches & EXP_TYP_REGEX) {
9139 FREE (match_buf);
9140 match_buf = NULL;
9141 }
9142 else {
9143 sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9144 sim_decode_quoted_string (match, match_buf, &match_size);
9145 ep->match = match_buf;
9146 ep->size = match_size;
9147 }
9148 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9149 if (!ep->match_pattern)
9150 {
9151 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9152 __func__, __FILE__, __LINE__);
9153 #if defined(USE_BACKTRACE)
9154 # ifdef SIGUSR2
9155 (void)raise(SIGUSR2);
9156
9157 # endif
9158 #endif
9159 abort();
9160 }
9161 strcpy (ep->match_pattern, match);
9162 if (ep->act) {
9163 FREE (ep->act);
9164 ep->act = NULL;
9165 }
9166 if (act) while (sim_isspace(*act)) ++act;
9167 if ((act != NULL) && (*act != 0)) {
9168 char *newp = (char *) calloc (strlen (act)+1, sizeof (*act));
9169 if (newp == NULL)
9170 return SCPE_MEM;
9171 strcpy (newp, act);
9172 ep->act = newp;
9173 }
9174
9175 for (i=0; i<exp->size; i++) {
9176 uint32 compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9177 if (compare_size >= exp->buf_size) {
9178 exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2);
9179 exp->buf_size = compare_size + 1;
9180 }
9181 }
9182 return SCPE_OK;
9183 }
9184
9185
9186
9187 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
9188 {
9189 if (!ep)
9190 return SCPE_OK;
9191 fprintf (st, "EXPECT");
9192 if (ep->switches & EXP_TYP_PERSIST)
9193 fprintf (st, " -p");
9194 if (ep->switches & EXP_TYP_CLEARALL)
9195 fprintf (st, " -c");
9196 if (ep->switches & EXP_TYP_REGEX)
9197 fprintf (st, " -r");
9198 if (ep->switches & EXP_TYP_REGEX_I)
9199 fprintf (st, " -i");
9200 fprintf (st, " %s", ep->match_pattern);
9201 if (ep->cnt > 0)
9202 fprintf (st, " [%d]", ep->cnt);
9203 if (ep->act)
9204 fprintf (st, " %s", ep->act);
9205 fprintf (st, "\n");
9206 return SCPE_OK;
9207 }
9208
9209 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
9210 {
9211 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9212
9213 if (exp->buf_size) {
9214 char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9215
9216 fprintf (st, "Match Buffer Size: %d\n", exp->buf_size);
9217 fprintf (st, "Buffer Insert Offset: %d\n", exp->buf_ins);
9218 fprintf (st, "Buffer Contents: %s\n", bstr);
9219 FREE (bstr);
9220 }
9221 if (exp->after)
9222 fprintf (st, "Halt After: %d instructions\n", exp->after);
9223 if (exp->dptr && exp->dbit)
9224 fprintf (st, "Debugging via: SET %s DEBUG%s%s\n", sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "", exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
9225 fprintf (st, "Match Rules:\n");
9226 if (!*match)
9227 return sim_exp_showall (st, exp);
9228 if (!ep) {
9229 fprintf (st, "No Rules match '%s'\n", match);
9230 return SCPE_ARG;
9231 }
9232 do {
9233 sim_exp_show_tab (st, exp, ep);
9234 ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
9235 } while (ep);
9236 return SCPE_OK;
9237 }
9238
9239
9240
9241 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
9242 {
9243 int32 i;
9244
9245 for (i=0; i < exp->size; i++)
9246 sim_exp_show_tab (st, exp, &exp->rules[i]);
9247 return SCPE_OK;
9248 }
9249
9250
9251
9252 t_stat sim_exp_check (EXPECT *exp, uint8 data)
9253 {
9254 int32 i;
9255 EXPTAB *ep = NULL;
9256 char *tstr = NULL;
9257
9258 if ((!exp) || (!exp->rules))
9259 return SCPE_OK;
9260
9261 exp->buf[exp->buf_ins++] = data;
9262 exp->buf[exp->buf_ins] = '\0';
9263
9264 for (i=0; i < exp->size; i++) {
9265 ep = &exp->rules[i];
9266 if (ep == NULL)
9267 break;
9268 if (ep->switches & EXP_TYP_REGEX) {
9269 }
9270 else {
9271 if (exp->buf_ins < ep->size) {
9272
9273
9274
9275
9276 if (exp->buf_ins) {
9277 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9278 char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9279 char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
9280
9281 sim_debug (exp->dbit, exp->dptr, "Checking String[0:%d]: %s\n", exp->buf_ins, estr);
9282 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9283 FREE (estr);
9284 FREE (mstr);
9285 }
9286 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
9287 continue;
9288 }
9289 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9290 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
9291 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
9292
9293 sim_debug (exp->dbit, exp->dptr, "Checking String[%d:%d]: %s\n", exp->buf_size-(ep->size-exp->buf_ins), ep->size-exp->buf_ins, estr);
9294 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9295 FREE (estr);
9296 FREE (mstr);
9297 }
9298 if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
9299 continue;
9300 break;
9301 }
9302 else {
9303 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9304 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
9305 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
9306
9307 sim_debug (exp->dbit, exp->dptr, "Checking String[%d:%d]: %s\n", exp->buf_ins-ep->size, ep->size, estr);
9308 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9309 FREE (estr);
9310 FREE (mstr);
9311 }
9312 if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
9313 continue;
9314 break;
9315 }
9316 }
9317 }
9318 if (exp->buf_ins == exp->buf_size) {
9319 exp->buf_ins = 0;
9320 sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\n");
9321 }
9322 if ((ep != NULL) && (i != exp->size)) {
9323 sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\n");
9324 if (ep->cnt > 0) {
9325 ep->cnt -= 1;
9326 sim_debug (exp->dbit, exp->dptr, "Waiting for %d more match%s before stopping\n",
9327 ep->cnt, (ep->cnt == 1) ? "" : "es");
9328 }
9329 else {
9330 uint32 after = exp->after;
9331 int32 switches = ep->switches;
9332 if (ep->act && *ep->act) {
9333 sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\n", ep->act);
9334 }
9335 else {
9336 sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\n");
9337 }
9338 sim_brk_setact (ep->act);
9339 if (ep->switches & EXP_TYP_CLEARALL)
9340 sim_exp_clrall (exp);
9341 else {
9342 if (!(ep->switches & EXP_TYP_PERSIST))
9343 sim_exp_clr_tab (exp, ep);
9344 }
9345 sim_activate (&sim_expect_unit,
9346 (switches & EXP_TYP_TIME) ?
9347 (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
9348 after);
9349 }
9350
9351 exp->buf_ins = 0;
9352 }
9353 if (tstr)
9354 FREE (tstr);
9355 return SCPE_OK;
9356 }
9357
9358
9359
9360 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
9361 {
9362 if (snd->extoff != 0) {
9363 if (snd->insoff-snd->extoff > 0)
9364 memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
9365 snd->insoff -= snd->extoff;
9366 snd->extoff -= snd->extoff;
9367 }
9368 if (snd->insoff+size > snd->bufsize) {
9369 snd->bufsize = snd->insoff+size;
9370 snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize);
9371 if (!snd->buffer)
9372 {
9373 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9374 __func__, __FILE__, __LINE__);
9375 #if defined(USE_BACKTRACE)
9376 # ifdef SIGUSR2
9377 (void)raise(SIGUSR2);
9378
9379 # endif
9380 #endif
9381 abort();
9382 }
9383 }
9384 memcpy(snd->buffer+snd->insoff, data, size);
9385 snd->insoff += size;
9386 if (delay)
9387 snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
9388 if (after)
9389 snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
9390 if (snd->after == 0)
9391 snd->after = snd->delay;
9392 snd->next_time = sim_gtime() + snd->after;
9393 return SCPE_OK;
9394 }
9395
9396
9397 t_stat sim_send_clear (SEND *snd)
9398 {
9399 snd->insoff = 0;
9400 snd->extoff = 0;
9401 return SCPE_OK;
9402 }
9403
9404
9405
9406 t_stat sim_show_send_input (FILE *st, const SEND *snd)
9407 {
9408 if (snd->extoff < snd->insoff) {
9409 fprintf (st, "%d bytes of pending input Data:\n ", snd->insoff-snd->extoff);
9410 fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
9411 fprintf (st, "\n");
9412 }
9413 else
9414 fprintf (st, "No Pending Input Data\n");
9415 if ((snd->next_time - sim_gtime()) > 0) {
9416 if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
9417 fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\n", (int)(snd->next_time - sim_gtime()),
9418 (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
9419 else
9420 fprintf (st, "Minimum of %d instructions before sending first character\n", (int)(snd->next_time - sim_gtime()));
9421 }
9422 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
9423 fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\n", (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
9424 else
9425 fprintf (st, "Minimum of %d instructions between characters\n", (int)snd->delay);
9426 if (snd->dptr && snd->dbit)
9427 fprintf (st, "Debugging via: SET %s DEBUG%s%s\n", sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "", snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
9428 return SCPE_OK;
9429 }
9430
9431
9432
9433 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
9434 {
9435 if (snd && (snd->extoff < snd->insoff)) {
9436 if (sim_gtime() < snd->next_time) {
9437 *stat = SCPE_OK;
9438 sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\n");
9439 }
9440 else {
9441 char dstr[8] = "";
9442 *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;
9443 snd->next_time = sim_gtime() + snd->delay;
9444 if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
9445 sprintf (dstr, " '%c'", *stat & 0xFF);
9446 sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\n", *stat & 0xFF, dstr);
9447 }
9448 return TRUE;
9449 }
9450 return FALSE;
9451 }
9452
9453
9454
9455 const char *sim_error_text (t_stat stat)
9456 {
9457 static char msgbuf[64];
9458
9459 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);
9460 if (stat == SCPE_OK)
9461 return "No Error";
9462 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
9463 return scp_errors[stat-SCPE_BASE].message;
9464 sprintf(msgbuf, "Error %d", stat);
9465 return msgbuf;
9466 }
9467
9468 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
9469 {
9470 char gbuf[CBUFSIZE];
9471 int32 cond;
9472
9473 *stat = SCPE_ARG;
9474 cptr = get_glyph (cptr, gbuf, 0);
9475 if (0 == memcmp("SCPE_", gbuf, 5))
9476 memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));
9477 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
9478 if (0 == strcmp(scp_errors[cond].code, gbuf)) {
9479 cond += SCPE_BASE;
9480 break;
9481 }
9482 if (0 == strcmp(gbuf, "OK"))
9483 cond = SCPE_OK;
9484 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {
9485 if (0 == (cond = strtol(gbuf, NULL, 0)))
9486 return SCPE_ARG;
9487 }
9488 if (cond > SCPE_MAX_ERR)
9489 return SCPE_ARG;
9490 *stat = cond;
9491 return SCPE_OK;
9492 }
9493
9494
9495
9496 const char* debug_bstates = "01_^";
9497 char debug_line_prefix[256];
9498 int32 debug_unterm = 0;
9499
9500
9501
9502 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
9503 {
9504 static const char *debtab_none = "DEBTAB_ISNULL";
9505 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
9506 const char *some_match = NULL;
9507 int32 offset = 0;
9508
9509 if (dptr->debflags == 0)
9510 return debtab_none;
9511
9512 dbits &= dptr->dctrl;
9513
9514
9515
9516 while ((offset < 32) && dptr->debflags[offset].name) {
9517 if (dptr->debflags[offset].mask == dbits)
9518 return dptr->debflags[offset].name;
9519 if (dptr->debflags[offset].mask & dbits)
9520 some_match = dptr->debflags[offset].name;
9521 offset++;
9522 }
9523 return some_match ? some_match : debtab_nomatch;
9524 }
9525
9526
9527
9528 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
9529 {
9530 const char* debug_type = get_dbg_verb (dbits, dptr);
9531 char tim_t[32] = "";
9532 char tim_a[32] = "";
9533 char pc_s[64] = "";
9534 struct timespec time_now;
9535
9536 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
9537 clock_gettime(CLOCK_REALTIME, &time_now);
9538 if (sim_deb_switches & SWMASK ('R'))
9539 sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
9540 if (sim_deb_switches & SWMASK ('T')) {
9541 time_t tnow = (time_t)time_now.tv_sec;
9542 struct tm *now = gmtime(&tnow);
9543 sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
9544 (int)now->tm_hour,
9545 (int)now->tm_min,
9546 (int)now->tm_sec,
9547 (long)(time_now.tv_nsec/1000000));
9548 }
9549 if (sim_deb_switches & SWMASK ('A')) {
9550 sprintf(tim_t, "%d.%03ld ",
9551 (int)(time_now.tv_sec),
9552 (long)(time_now.tv_nsec/1000000));
9553 }
9554 }
9555 if (sim_deb_switches & SWMASK ('P')) {
9556 t_value val;
9557
9558 if (sim_vm_pc_value)
9559 val = (*sim_vm_pc_value)();
9560 else
9561 val = get_rval (sim_PC, 0);
9562 sprintf(pc_s, "-%s:", sim_PC->name);
9563 sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
9564 }
9565 sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ", tim_t, tim_a, sim_gtime(), pc_s, "", dptr->name, debug_type);
9566 return debug_line_prefix;
9567 }
9568
9569 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
9570 {
9571 int32 i, fields, offset;
9572 uint32 value, beforevalue, mask;
9573
9574 for (fields=offset=0; bitdefs[fields].name; ++fields) {
9575 if (bitdefs[fields].offset == 0xffffffff)
9576 bitdefs[fields].offset = offset;
9577 offset += bitdefs[fields].width;
9578 }
9579 for (i = fields-1; i >= 0; i--) {
9580 if (bitdefs[i].name[0] == '\0')
9581 continue;
9582 if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
9583 int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
9584 Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
9585 }
9586 else {
9587 const char *delta = "";
9588 mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
9589 value = (uint32)((after >> bitdefs[i].offset) & mask);
9590 beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
9591 if (value < beforevalue)
9592 delta = "_";
9593 if (value > beforevalue)
9594 delta = "^";
9595 if (bitdefs[i].valuenames)
9596 Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
9597 else
9598 if (bitdefs[i].format) {
9599 Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
9600 Fprintf(stream, bitdefs[i].format, value);
9601 Fprintf(stream, " ");
9602 }
9603 else
9604 Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
9605 }
9606 }
9607 }
9608
9609
9610
9611
9612
9613 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
9614 BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
9615 {
9616 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
9617 if (!debug_unterm)
9618 fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));
9619 if (header)
9620 fprintf(sim_deb, "%s: ", header);
9621 fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs);
9622 if (terminate)
9623 fprintf(sim_deb, "\r\n");
9624 debug_unterm = terminate ? 0 : 1;
9625 }
9626 }
9627 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
9628 uint32 before, uint32 after, int terminate)
9629 {
9630 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
9631 }
9632
9633
9634 void sim_printf (const char* fmt, ...)
9635 {
9636 char stackbuf[STACKBUFSIZE];
9637 int32 bufsize = sizeof(stackbuf);
9638 char *buf = stackbuf;
9639 int32 len;
9640 va_list arglist;
9641
9642 while (1) {
9643 va_start (arglist, fmt);
9644 len = vsnprintf (buf, bufsize-1, fmt, arglist);
9645 va_end (arglist);
9646
9647
9648
9649 if ((len < 0) || (len >= bufsize-1)) {
9650 if (buf != stackbuf)
9651 FREE (buf);
9652 bufsize = bufsize * 2;
9653 if (bufsize < len + 2)
9654 bufsize = len + 2;
9655 buf = (char *) malloc (bufsize);
9656 if (buf == NULL)
9657 return;
9658 buf[bufsize-1] = '\0';
9659 continue;
9660 }
9661 break;
9662 }
9663
9664 if (sim_is_running) {
9665 char *c, *remnant = buf;
9666 while ((c = strchr(remnant, '\n'))) {
9667 if ((c != buf) && (*(c - 1) != '\r'))
9668 printf("%.*s\r\n", (int)(c-remnant), remnant);
9669 else
9670 printf("%.*s\n", (int)(c-remnant), remnant);
9671 remnant = c + 1;
9672 }
9673 printf("%s", remnant);
9674 }
9675 else
9676 printf("%s", buf);
9677 if (sim_log && (sim_log != stdout))
9678 fprintf (sim_log, "%s", buf);
9679 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
9680 fprintf (sim_deb, "%s", buf);
9681
9682 if (buf != stackbuf)
9683 FREE (buf);
9684 }
9685
9686
9687 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
9688 {
9689 char stackbuf[STACKBUFSIZE];
9690 int32 bufsize = sizeof(stackbuf);
9691 char *buf = stackbuf;
9692 int32 len;
9693 va_list arglist;
9694 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
9695
9696 while (1) {
9697 va_start (arglist, fmt);
9698 len = vsnprintf (buf, bufsize-1, fmt, arglist);
9699 va_end (arglist);
9700
9701
9702
9703 if ((len < 0) || (len >= bufsize-1)) {
9704 if (buf != stackbuf)
9705 FREE (buf);
9706 bufsize = bufsize * 2;
9707 if (bufsize < len + 2)
9708 bufsize = len + 2;
9709 buf = (char *) malloc (bufsize);
9710 if (buf == NULL)
9711 return SCPE_MEM;
9712 buf[bufsize-1] = '\0';
9713 continue;
9714 }
9715 break;
9716 }
9717
9718 if (sim_do_ocptr[sim_do_depth]) {
9719 if (!sim_do_echo && !sim_quiet && !inhibit_message)
9720 sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
9721 else {
9722 if (sim_deb)
9723 fprintf (sim_deb, "%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
9724 }
9725 }
9726 if (sim_is_running && !inhibit_message) {
9727 char *c, *remnant = buf;
9728 while ((c = strchr(remnant, '\n'))) {
9729 if ((c != buf) && (*(c - 1) != '\r'))
9730 printf("%.*s\r\n", (int)(c-remnant), remnant);
9731 else
9732 printf("%.*s\n", (int)(c-remnant), remnant);
9733 remnant = c + 1;
9734 }
9735 printf("%s", remnant);
9736 }
9737 else {
9738 if (!inhibit_message)
9739 printf("%s", buf);
9740 }
9741 if (sim_log && (sim_log != stdout) && !inhibit_message)
9742 fprintf (sim_log, "%s", buf);
9743 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))
9744 fprintf (sim_deb, "%s", buf);
9745
9746 if (buf != stackbuf)
9747 FREE (buf);
9748 return stat | SCPE_NOMESSAGE;
9749 }
9750
9751
9752
9753
9754
9755
9756
9757
9758
9759 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
9760 {
9761 DEVICE *dptr = (DEVICE *)vdptr;
9762 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
9763 char stackbuf[STACKBUFSIZE];
9764 int32 bufsize = sizeof(stackbuf);
9765 char *buf = stackbuf;
9766 va_list arglist;
9767 int32 i, j, len;
9768 const char* debug_prefix = sim_debug_prefix(dbits, dptr);
9769
9770 buf[bufsize-1] = '\0';
9771 while (1) {
9772 va_start (arglist, fmt);
9773 len = vsnprintf (buf, bufsize-1, fmt, arglist);
9774 va_end (arglist);
9775
9776
9777
9778 if ((len < 0) || (len >= bufsize-1)) {
9779 if (buf != stackbuf)
9780 FREE (buf);
9781 bufsize = bufsize * 2;
9782 if (bufsize < len + 2)
9783 bufsize = len + 2;
9784 buf = (char *) malloc (bufsize);
9785 if (buf == NULL)
9786 return;
9787 buf[bufsize-1] = '\0';
9788 continue;
9789 }
9790 break;
9791 }
9792
9793
9794
9795 for (i = j = 0; i < len; ++i) {
9796 if ('\n' == buf[i]) {
9797 if (i >= j) {
9798 if ((i != j) || (i == 0)) {
9799 if (debug_unterm)
9800 fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
9801 else
9802 fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
9803 }
9804 debug_unterm = 0;
9805 }
9806 j = i + 1;
9807 }
9808 }
9809 if (i > j) {
9810 if (debug_unterm)
9811 fprintf (sim_deb, "%.*s", i-j, &buf[j]);
9812 else
9813 fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
9814 }
9815
9816
9817
9818 debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
9819 if (buf != stackbuf)
9820 FREE (buf);
9821 }
9822 return;
9823 }
9824
9825 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
9826 {
9827
9828 if (sim_deb && (dptr->dctrl & reason)) {
9829 sim_debug (reason, dptr, "%s %s %slen: %08X\n", sim_uname(uptr), txt, position, (unsigned int)len);
9830 if (data && len) {
9831 unsigned int i, same, group, sidx, oidx, ridx, eidx, soff;
9832 char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
9833 static char hex[] = "0123456789ABCDEF";
9834 static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
9835 static unsigned char ebcdic2ascii[] = {
9836 0000,0001,0002,0003,0234,0011,0206,0177,
9837 0227,0215,0216,0013,0014,0015,0016,0017,
9838 0020,0021,0022,0023,0235,0205,0010,0207,
9839 0030,0031,0222,0217,0034,0035,0036,0037,
9840 0200,0201,0202,0203,0204,0012,0027,0033,
9841 0210,0211,0212,0213,0214,0005,0006,0007,
9842 0220,0221,0026,0223,0224,0225,0226,0004,
9843 0230,0231,0232,0233,0024,0025,0236,0032,
9844 0040,0240,0241,0242,0243,0244,0245,0246,
9845 0247,0250,0133,0056,0074,0050,0053,0041,
9846 0046,0251,0252,0253,0254,0255,0256,0257,
9847 0260,0261,0135,0044,0052,0051,0073,0136,
9848 0055,0057,0262,0263,0264,0265,0266,0267,
9849 0270,0271,0174,0054,0045,0137,0076,0077,
9850 0272,0273,0274,0275,0276,0277,0300,0301,
9851 0302,0140,0072,0043,0100,0047,0075,0042,
9852 0303,0141,0142,0143,0144,0145,0146,0147,
9853 0150,0151,0304,0305,0306,0307,0310,0311,
9854 0312,0152,0153,0154,0155,0156,0157,0160,
9855 0161,0162,0313,0314,0315,0316,0317,0320,
9856 0321,0176,0163,0164,0165,0166,0167,0170,
9857 0171,0172,0322,0323,0324,0325,0326,0327,
9858 0330,0331,0332,0333,0334,0335,0336,0337,
9859 0340,0341,0342,0343,0344,0345,0346,0347,
9860 0173,0101,0102,0103,0104,0105,0106,0107,
9861 0110,0111,0350,0351,0352,0353,0354,0355,
9862 0175,0112,0113,0114,0115,0116,0117,0120,
9863 0121,0122,0356,0357,0360,0361,0362,0363,
9864 0134,0237,0123,0124,0125,0126,0127,0130,
9865 0131,0132,0364,0365,0366,0367,0370,0371,
9866 0060,0061,0062,0063,0064,0065,0066,0067,
9867 0070,0071,0372,0373,0374,0375,0376,0377,
9868 };
9869
9870 for (i=same=0; i<len; i += 16) {
9871 if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
9872 ++same;
9873 continue;
9874 }
9875 if (same > 0) {
9876 sim_debug (reason, dptr, "%04X thru %04X same as above\n", i-(16*same), i-1);
9877 same = 0;
9878 }
9879 group = (((len - i) > 16) ? 16 : (len - i));
9880 strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
9881 eidx = strlen(ebcdicbuf);
9882 strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
9883 ridx = strlen(rad50buf);
9884 strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
9885 soff = strlen(strbuf);
9886 for (sidx=oidx=0; sidx<group; ++sidx) {
9887 outbuf[oidx++] = ' ';
9888 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
9889 outbuf[oidx++] = hex[data[i+sidx]&0xf];
9890 if (sim_isprint (data[i+sidx]))
9891 strbuf[soff+sidx] = data[i+sidx];
9892 else
9893 strbuf[soff+sidx] = '.';
9894 if (ridx && ((sidx&1) == 0)) {
9895 uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
9896
9897 if (word >= 64000) {
9898 rad50buf[ridx++] = '|';
9899 rad50buf[ridx++] = '|';
9900 rad50buf[ridx++] = '|';
9901 }
9902 else {
9903 rad50buf[ridx++] = rad50[word/1600];
9904 rad50buf[ridx++] = rad50[(word/40)%40];
9905 rad50buf[ridx++] = rad50[word%40];
9906 }
9907 }
9908 if (eidx) {
9909 if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
9910 ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
9911 else
9912 ebcdicbuf[eidx++] = '.';
9913 }
9914 }
9915 outbuf[oidx] = '\0';
9916 strbuf[soff+sidx] = '\0';
9917 ebcdicbuf[eidx] = '\0';
9918 rad50buf[ridx] = '\0';
9919 sim_debug (reason, dptr, "%04X%-48s %s%s%s\n", i, outbuf, strbuf, ebcdicbuf, rad50buf);
9920 }
9921 if (same > 0) {
9922 sim_debug (reason, dptr, "%04X thru %04X same as above\n", i-(16*same), (unsigned int)(len-1));
9923 }
9924 }
9925 }
9926 }
9927
9928 int Fprintf (FILE *f, const char* fmt, ...)
9929 {
9930 int ret = 0;
9931 va_list args;
9932
9933 va_start (args, fmt);
9934 ret = vfprintf (f, fmt, args);
9935 va_end (args);
9936 return ret;
9937 }
9938
9939
9940
9941
9942
9943
9944
9945
9946
9947
9948
9949
9950
9951
9952
9953
9954
9955
9956
9957 #define blankch(x) ((x) == ' ' || (x) == '\t')
9958
9959 typedef struct topic {
9960 uint32 level;
9961 char *title;
9962 char *label;
9963 struct topic *parent;
9964 struct topic **children;
9965 uint32 kids;
9966 char *text;
9967 size_t len;
9968 uint32 flags;
9969 uint32 kidwid;
9970 #define HLP_MAGIC_TOPIC 1
9971 } TOPIC;
9972
9973 static volatile struct {
9974 const char *error;
9975 const char *prox;
9976 size_t block;
9977 size_t line;
9978 } help_where = { "", NULL, 0, 0 };
9979 jmp_buf help_env;
9980
9981 #define FAIL(why,text,here) \
9982 { \
9983 help_where.error = #text; \
9984 help_where.prox = here; \
9985 longjmp ( help_env, (why) ); \
9986 \
9987 }
9988
9989
9990
9991
9992
9993
9994 static void appendText (TOPIC *topic, const char *text, size_t len)
9995 {
9996 char *newt;
9997
9998 if (!len)
9999 return;
10000
10001 newt = (char *)realloc (topic->text, topic->len + len +1);
10002 if (!newt) {
10003 #ifndef SUNLINT
10004 FAIL (SCPE_MEM, No memory, NULL);
10005 #endif
10006 }
10007 topic->text = newt;
10008 memcpy (newt + topic->len, text, len);
10009 topic->len +=len;
10010 newt[topic->len] = '\0';
10011 return;
10012 }
10013
10014
10015
10016 static void cleanHelp (TOPIC *topic)
10017 {
10018 TOPIC *child;
10019 size_t i;
10020
10021 FREE (topic->title);
10022 FREE (topic->text);
10023 FREE (topic->label);
10024 for (i = 0; i < topic->kids; i++) {
10025 child = topic->children[i];
10026 cleanHelp (child);
10027 FREE (child);
10028 }
10029 FREE (topic->children);
10030 return;
10031 }
10032
10033
10034
10035
10036 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
10037 UNIT *uptr, const char *htext, va_list ap)
10038 {
10039 char *end;
10040 size_t n, ilvl;
10041 #define VSMAX 100
10042 char *vstrings[VSMAX];
10043 size_t vsnum = 0;
10044 char * astrings[VSMAX+1];
10045 size_t asnum = 0;
10046 char *const *hblock;
10047 const char *ep;
10048 t_bool excluded = FALSE;
10049
10050
10051
10052
10053
10054
10055
10056 memset (vstrings, 0, sizeof (vstrings));
10057 memset (astrings, 0, sizeof (astrings));
10058 astrings[asnum++] = (char *) htext;
10059
10060 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10061 help_where.block = hblock - astrings;
10062 help_where.line = 0;
10063 while (*htext) {
10064 const char *start;
10065
10066 help_where.line++;
10067 if (sim_isspace (*htext) || *htext == '+') {
10068 if (excluded) {
10069 while (*htext && *htext != '\n')
10070 htext++;
10071 if (*htext)
10072 ++htext;
10073 continue;
10074 }
10075 ilvl = 1;
10076 appendText (topic, " ", 4);
10077 if (*htext == '+') {
10078 while (*htext == '+') {
10079 ilvl++;
10080 appendText (topic, " ", 4);
10081 htext++;
10082 }
10083 }
10084 while (*htext && *htext != '\n' && sim_isspace (*htext))
10085 htext++;
10086 if (!*htext)
10087 break;
10088 start = htext;
10089 while (*htext) {
10090 if (*htext == '%') {
10091 appendText (topic, start, htext - start);
10092 switch (*++htext) {
10093 case 'U':
10094 if (dptr) {
10095 char buf[129];
10096 n = uptr? uptr - dptr->units: 0;
10097 sprintf (buf, "%s%u", dptr->name, (int)n);
10098 appendText (topic, buf, strlen (buf));
10099 }
10100 break;
10101 case 'D':
10102 if (dptr != NULL)
10103 appendText (topic, dptr->name, strlen (dptr->name));
10104 break;
10105 case 'S':
10106 appendText (topic, sim_name, strlen (sim_name));
10107 break;
10108 case '%':
10109 appendText (topic, "%", 1);
10110 break;
10111 case '+':
10112 appendText (topic, "+", 1);
10113 break;
10114 default:
10115 if (sim_isdigit (*htext)) {
10116 n = 0;
10117 while (sim_isdigit (*htext))
10118 n += (n * 10) + (*htext++ - '0');
10119 if (( *htext != 'H' && *htext != 's') ||
10120 n == 0 || n >= VSMAX) {
10121 #ifndef SUNLINT
10122 FAIL (SCPE_ARG, Invalid escape, htext);
10123 #endif
10124 }
10125 while (n > vsnum)
10126 vstrings[vsnum++] = va_arg (ap, char *);
10127 start = vstrings[n-1];
10128 if (*htext == 'H') {
10129 if (asnum >= VSMAX) {
10130 #ifndef SUNLINT
10131 FAIL (SCPE_ARG, Too many blocks, htext);
10132 #endif
10133 }
10134 astrings[asnum++] = (char *)start;
10135 break;
10136 }
10137 ep = start;
10138 while (*ep) {
10139 if (*ep == '\n') {
10140 ep++;
10141 appendText (topic, start, ep - start);
10142 if (*ep) {
10143 size_t i;
10144 for (i = 0; i < ilvl; i++)
10145 appendText (topic, " ", 4);
10146 }
10147 start = ep;
10148 }
10149 else
10150 ep++;
10151 }
10152 appendText (topic, start, ep-start);
10153 break;
10154 }
10155 #ifndef SUNLINT
10156 FAIL (SCPE_ARG, Invalid escape, htext);
10157 #endif
10158 }
10159 start = ++htext;
10160 continue;
10161 }
10162 if (*htext == '\n') {
10163 htext++;
10164 appendText (topic, start, htext - start);
10165 break;
10166 }
10167 htext++;
10168 }
10169 continue;
10170 }
10171 if (sim_isdigit (*htext)) {
10172 TOPIC **children;
10173 TOPIC *newt;
10174 char nbuf[100];
10175
10176 n = 0;
10177 start = htext;
10178 while (sim_isdigit (*htext))
10179 n += (n * 10) + (*htext++ - '0');
10180 if ((htext == start) || !n) {
10181 #ifndef SUNLINT
10182 FAIL (SCPE_ARG, Invalid topic heading, htext);
10183 #endif
10184 }
10185 if (n <= topic->level) {
10186 while (n <= topic->level)
10187 topic = topic->parent;
10188 }
10189 else {
10190 if (n > topic->level +1) {
10191 #ifndef SUNLINT
10192 FAIL (SCPE_ARG, Level not contiguous, htext);
10193 #endif
10194 }
10195 }
10196 while (*htext && (*htext != '\n') && sim_isspace (*htext))
10197 htext++;
10198 if (!*htext || (*htext == '\n')) {
10199 #ifndef SUNLINT
10200 FAIL (SCPE_ARG, Missing topic name, htext);
10201 #endif
10202 }
10203 start = htext;
10204 while (*htext && (*htext != '\n'))
10205 htext++;
10206 if (start == htext) {
10207 #ifndef SUNLINT
10208 FAIL (SCPE_ARG, Null topic name, htext);
10209 #endif
10210 }
10211 excluded = FALSE;
10212 if (*start == '?') {
10213 size_t n = 0;
10214 start++;
10215 while (sim_isdigit (*start))
10216 n += (n * 10) + (*start++ - '0');
10217 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
10218 #ifndef SUNLINT
10219 FAIL (SCPE_ARG, Invalid parameter number, start);
10220 #endif
10221 }
10222 while (n > vsnum)
10223 vstrings[vsnum++] = va_arg (ap, char *);
10224 end = vstrings[n-1];
10225 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
10226 excluded = TRUE;
10227 if (*htext)
10228 htext++;
10229 continue;
10230 }
10231 }
10232 newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
10233 if (!newt) {
10234 #ifndef SUNLINT
10235 FAIL (SCPE_MEM, No memory, NULL);
10236 #endif
10237 }
10238 newt->title = (char *) malloc ((htext - start)+1);
10239 if (!newt->title) {
10240 FREE (newt);
10241 #ifndef SUNLINT
10242 FAIL (SCPE_MEM, No memory, NULL);
10243 #endif
10244 }
10245 memcpy (newt->title, start, htext - start);
10246 newt->title[htext - start] = '\0';
10247 if (*htext)
10248 htext++;
10249
10250 if (newt->title[0] == '$')
10251 newt->flags |= HLP_MAGIC_TOPIC;
10252
10253 children = (TOPIC **) realloc (topic->children,
10254 (topic->kids +1) * sizeof (TOPIC *));
10255 if (!children) {
10256 FREE (newt->title);
10257 FREE (newt);
10258 #ifndef SUNLINT
10259 FAIL (SCPE_MEM, No memory, NULL);
10260 #endif
10261 }
10262 topic->children = children;
10263 topic->children[topic->kids++] = newt;
10264 newt->level = n;
10265 newt->parent = topic;
10266 n = strlen (newt->title);
10267 if (n > topic->kidwid)
10268 topic->kidwid = n;
10269 sprintf (nbuf, ".%u", topic->kids);
10270 n = strlen (topic->label) + strlen (nbuf) + 1;
10271 newt->label = (char *) malloc (n);
10272 if (!newt->label) {
10273 FREE (newt->title);
10274 topic->children[topic->kids -1] = NULL;
10275 FREE (newt);
10276 #ifndef SUNLINT
10277 FAIL (SCPE_MEM, No memory, NULL);
10278 #endif
10279 }
10280 sprintf (newt->label, "%s%s", topic->label, nbuf);
10281 topic = newt;
10282 continue;
10283 }
10284 if (*htext == ';') {
10285 while (*htext && *htext != '\n')
10286 htext++;
10287 continue;
10288 }
10289 #ifndef SUNLINT
10290 FAIL (SCPE_ARG, Unknown line type, htext);
10291 #endif
10292 }
10293 memset (vstrings, 0, VSMAX * sizeof (char *));
10294 vsnum = 0;
10295 }
10296
10297 return topic;
10298 }
10299
10300
10301
10302
10303
10304 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
10305 {
10306 char *prefix;
10307 char *newp, *newt;
10308
10309 if (topic->level == 0) {
10310 prefix = (char *) calloc (2,1);
10311 if (!prefix) {
10312 #ifndef SUNLINT
10313 FAIL (SCPE_MEM, No memory, NULL);
10314 #endif
10315 }
10316 prefix[0] = '\n';
10317 }
10318 else
10319 prefix = helpPrompt (topic->parent, "", oneword);
10320
10321 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
10322 strlen (pstring) +1);
10323 if (!newp) {
10324 FREE (prefix);
10325 #ifndef SUNLINT
10326 FAIL (SCPE_MEM, No memory, NULL);
10327 #endif
10328 }
10329 strcpy (newp, prefix);
10330 if (topic->children) {
10331 if (topic->level != 0)
10332 strcat (newp, " ");
10333 newt = (topic->flags & HLP_MAGIC_TOPIC)?
10334 topic->title+1: topic->title;
10335 if (oneword) {
10336 char *np = newp + strlen (newp);
10337 while (*newt) {
10338 *np++ = blankch (*newt)? '_' : *newt;
10339 newt++;
10340 }
10341 *np = '\0';
10342 }
10343 else
10344 strcat (newp, newt);
10345 if (*pstring && *pstring != '?')
10346 strcat (newp, " ");
10347 }
10348 strcat (newp, pstring);
10349 FREE (prefix);
10350 return newp;
10351 }
10352
10353 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
10354 {
10355 char tbuf[CBUFSIZE];
10356 size_t i, skiplines;
10357 #ifdef _WIN32
10358 FILE *tmp;
10359 char *tmpnam;
10360
10361 do {
10362 int fd;
10363 tmpnam = _tempnam (NULL, "simh");
10364 fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
10365 if (fd != -1) {
10366 tmp = _fdopen (fd, "w+");
10367 break;
10368 }
10369 } while (1);
10370 #else
10371 FILE *tmp = tmpfile();
10372 #endif
10373
10374 if (!tmp) {
10375 fprintf (st, "Unable to create temporary file: %s\n", strerror (errno));
10376 return;
10377 }
10378
10379 if (topic->title)
10380 fprintf (st, "%s\n", topic->title+1);
10381
10382 skiplines = 0;
10383 if (topic->title) {
10384 if (!strcmp (topic->title+1, "Registers")) {
10385 fprint_reg_help (tmp, dptr) ;
10386 skiplines = 1;
10387 }
10388 else
10389 if (!strcmp (topic->title+1, "Set commands")) {
10390 fprint_set_help (tmp, dptr);
10391 skiplines = 3;
10392 }
10393 else
10394 if (!strcmp (topic->title+1, "Show commands")) {
10395 fprint_show_help (tmp, dptr);
10396 skiplines = 3;
10397 }
10398 }
10399 rewind (tmp);
10400
10401
10402
10403 for (i =0; i < skiplines; i++)
10404 if (fgets (tbuf, sizeof (tbuf), tmp)) {};
10405
10406 while (fgets (tbuf, sizeof (tbuf), tmp)) {
10407 if (tbuf[0] != '\n')
10408 fputs (" ", st);
10409 fputs (tbuf, st);
10410 }
10411 fclose (tmp);
10412 #ifdef _WIN32
10413 remove (tmpnam);
10414 FREE (tmpnam);
10415 #endif
10416 return;
10417 }
10418
10419
10420 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
10421 UNIT *uptr, int32 flag,
10422 TOPIC *topic, va_list ap )
10423 {
10424 size_t i;
10425
10426 if (topic->flags & HLP_MAGIC_TOPIC) {
10427 fprintf (st, "\n%s ", topic->label);
10428 displayMagicTopic (st, dptr, topic);
10429 }
10430 else
10431 fprintf (st, "\n%s %s\n", topic->label, topic->title);
10432
10433
10434
10435
10436
10437
10438 if (topic->text)
10439 fputs (topic->text, st);
10440
10441 for (i = 0; i < topic->kids; i++)
10442 displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
10443
10444 return SCPE_OK;
10445 }
10446
10447 #define HLP_MATCH_AMBIGUOUS (~0u)
10448 #define HLP_MATCH_WILDCARD (~1U)
10449 #define HLP_MATCH_NONE 0
10450 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
10451 {
10452 size_t i, match;
10453 char cbuf[CBUFSIZE], *cptr;
10454
10455 if (!strcmp (token, "*"))
10456 return HLP_MATCH_WILDCARD;
10457
10458 match = 0;
10459 for (i = 0; i < topic->kids; i++) {
10460 strcpy (cbuf,topic->children[i]->title +
10461 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
10462 cptr = cbuf;
10463 while (*cptr) {
10464 if (blankch (*cptr)) {
10465 *cptr++ = '_';
10466 }
10467 else {
10468 *cptr = (char)toupper (*cptr);
10469 cptr++;
10470 }
10471 }
10472 if (!strcmp (cbuf, token))
10473 return i+1;
10474 if (!strncmp (cbuf, token, strlen (token))) {
10475 if (match)
10476 return HLP_MATCH_AMBIGUOUS;
10477 match = i+1;
10478 }
10479 }
10480 return match;
10481 }
10482
10483
10484
10485 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
10486 UNIT *uptr, int32 flag,
10487 const char *help, const char *cptr, va_list ap)
10488 {
10489
10490 TOPIC top;
10491 TOPIC *topic = ⊤
10492 int failed;
10493 size_t match;
10494 size_t i;
10495 const char *p;
10496 t_bool flat_help = FALSE;
10497 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
10498
10499 static const char attach_help[] = { " ATTACH" };
10500 static const char brief_help[] = { "%s help. Type <CR> to exit, HELP for navigation help.\n" };
10501 static const char onecmd_help[] = { "%s help.\n" };
10502 static const char help_help[] = {
10503
10504
10505 " To see more HELP information, type the listed subtopic name. To move\n"
10506 " up a level, just type <CR>. To review the current subtopic, type \"?\".\n"
10507 " To view all subtopics, type \"*\". To exit type \"EXIT\", \"^C\", or \"^D\".\n\n"
10508 };
10509
10510 memset (&top, 0, sizeof(top));
10511 top.parent = ⊤
10512 if ((failed = setjmp (help_env)) != 0) {
10513 fprintf (stderr, "\nHELP was unable to process HELP for this device.\n"
10514 "Error in block %u line %u: %s\n"
10515 "%s%*.*s%s\n",
10516 (int)help_where.block, (int)help_where.line, help_where.error,
10517 help_where.prox ? "Near '" : "",
10518 help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
10519 help_where.prox ? help_where.prox : "",
10520 help_where.prox ? "'" : "");
10521 cleanHelp (&top);
10522 return failed;
10523 }
10524
10525
10526
10527
10528
10529 if (dptr) {
10530 p = dptr->name;
10531 flat_help = (dptr->flags & DEV_FLATHELP) != 0;
10532 }
10533 else
10534 p = sim_name;
10535 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
10536 if (!top.title)
10537 {
10538 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10539 __func__, __FILE__, __LINE__);
10540 #if defined(USE_BACKTRACE)
10541 # ifdef SIGUSR2
10542 (void)raise(SIGUSR2);
10543
10544 # endif
10545 #endif
10546 abort();
10547 }
10548 for (i = 0; p[i]; i++ )
10549 top.title[i] = (char)toupper (p[i]);
10550 top.title[i] = '\0';
10551 if (flag & SCP_HELP_ATTACH)
10552 strcpy (top.title+i, attach_help);
10553
10554 top.label = (char *) malloc (sizeof ("1"));
10555 if (!top.label)
10556 {
10557 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10558 __func__, __FILE__, __LINE__);
10559 #if defined(USE_BACKTRACE)
10560 # ifdef SIGUSR2
10561 (void)raise(SIGUSR2);
10562
10563 # endif
10564 #endif
10565 abort();
10566 }
10567 strcpy (top.label, "1");
10568
10569 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
10570
10571 if (flat_help) {
10572 flag |= SCP_HELP_FLAT;
10573 if (sim_ttisatty())
10574 fprintf (st, "%s help.\nThis help is also available in hierarchical form.\n", top.title);
10575 else
10576 fprintf (st, "%s help.\n", top.title);
10577 }
10578 else
10579 fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
10580
10581
10582
10583 (void) buildHelp (&top, dptr, uptr, help, ap);
10584
10585
10586
10587 while (cptr && *cptr) {
10588 cptr = get_glyph (cptr, gbuf, 0);
10589 if (!gbuf[0])
10590 break;
10591 if (!strcmp (gbuf, "HELP")) {
10592 fprintf (st, "\n");
10593 fputs (help_help, st);
10594 break;
10595 }
10596 match = matchHelpTopicName (topic, gbuf);
10597 if (match == HLP_MATCH_WILDCARD) {
10598 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
10599 cleanHelp (&top);
10600 return SCPE_OK;
10601 }
10602 if (match == HLP_MATCH_AMBIGUOUS) {
10603 fprintf (st, "\n%s is ambiguous in %s\n", gbuf, topic->title);
10604 break;
10605 }
10606 if (match == HLP_MATCH_NONE) {
10607 fprintf (st, "\n%s is not available in %s\n", gbuf, topic->title);
10608 break;
10609 }
10610 topic = topic->children[match-1];
10611 }
10612 cptr = NULL;
10613
10614 if (flat_help) {
10615 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
10616 cleanHelp (&top);
10617 return SCPE_OK;
10618 }
10619
10620
10621
10622 while (TRUE) {
10623 char *pstring;
10624 const char *prompt[2] = {"? ", "Subtopic? "};
10625
10626
10627
10628 if (topic->flags & HLP_MAGIC_TOPIC) {
10629 fputc ('\n', st);
10630 displayMagicTopic (st, dptr, topic);
10631 }
10632 else
10633 fprintf (st, "\n%s\n", topic->title);
10634
10635
10636
10637
10638
10639 if (topic->text)
10640 fputs (topic->text, st);
10641
10642 if (topic->kids) {
10643 size_t w = 0;
10644 char *p;
10645 char tbuf[CBUFSIZE];
10646
10647 fprintf (st, "\n Additional information available:\n\n");
10648 for (i = 0; i < topic->kids; i++) {
10649 strcpy (tbuf, topic->children[i]->title +
10650 ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
10651 for (p = tbuf; *p; p++) {
10652 if (blankch (*p))
10653 *p = '_';
10654 }
10655 w += 4 + topic->kidwid;
10656 if (w > 80) {
10657 w = 4 + topic->kidwid;
10658 fputc ('\n', st);
10659 }
10660 fprintf (st, " %-*s", topic->kidwid, tbuf);
10661 }
10662 fprintf (st, "\n\n");
10663 if (flag & SCP_HELP_ONECMD) {
10664 pstring = helpPrompt (topic, "", TRUE);
10665 fprintf (st, "To view additional topics, type HELP %s topicname\n", pstring+1);
10666 FREE (pstring);
10667 break;
10668 }
10669 }
10670
10671 if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
10672 break;
10673
10674 reprompt:
10675 if (!cptr || !*cptr) {
10676 if (topic->kids == 0)
10677 topic = topic->parent;
10678 pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
10679
10680 cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
10681 FREE (pstring);
10682 if ((cptr != NULL) &&
10683 ((0 == strcmp (cptr, "\x04")) ||
10684 (0 == strcmp (cptr, "\x1A"))))
10685 cptr = NULL;
10686 }
10687
10688 if (!cptr)
10689 break;
10690
10691 cptr = get_glyph (cptr, gbuf, 0);
10692 if (!strcmp (gbuf, "*")) {
10693 displayFlatHelp (st, dptr, uptr, flag, topic, ap);
10694 gbuf[0] = '\0';
10695 }
10696 if (!gbuf[0]) {
10697 if (topic->level == 0)
10698 break;
10699 topic = topic->parent;
10700 continue;
10701 }
10702 if (!strcmp (gbuf, "?"))
10703 continue;
10704 if (!strcmp (gbuf, "HELP")) {
10705 fputs (help_help, st);
10706 goto reprompt;
10707 }
10708 if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))
10709 break;
10710
10711
10712
10713 if (!topic->kids) {
10714 fprintf (st, "No additional help at this level.\n");
10715 cptr = NULL;
10716 goto reprompt;
10717 }
10718 match = matchHelpTopicName (topic, gbuf);
10719 if (match == HLP_MATCH_AMBIGUOUS) {
10720 fprintf (st, "%s is ambiguous, please type more of the topic name\n", gbuf);
10721 cptr = NULL;
10722 goto reprompt;
10723 }
10724
10725 if (match == HLP_MATCH_NONE) {
10726 fprintf (st, "Help for %s is not available\n", gbuf);
10727 cptr = NULL;
10728 goto reprompt;
10729 }
10730
10731
10732 topic = topic->children[match-1];
10733 }
10734
10735
10736
10737 cleanHelp (&top);
10738
10739 return SCPE_OK;
10740 }
10741
10742
10743
10744 t_stat scp_help (FILE *st, DEVICE *dptr,
10745 UNIT *uptr, int32 flag,
10746 const char *help, const char *cptr, ...)
10747 {
10748 t_stat r;
10749 va_list ap;
10750
10751 va_start (ap, cptr);
10752 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
10753 va_end (ap);
10754
10755 return r;
10756 }
10757
10758 #if defined(_MSC_VER)
10759 # pragma warning(pop)
10760 #endif