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