root/src/simh/scp.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. setenv
  2. unsetenv
  3. xstrerror_l
  4. strremove
  5. strtrimspace
  6. allowCores
  7. CleanDUMA
  8. dl_iterate_phdr_callback
  9. GetUCRTVersion
  10. dps8_sir_report_error
  11. main
  12. process_stdin_commands
  13. set_prompt
  14. find_cmd
  15. exit_cmd
  16. _cmd_name_compare
  17. fprint_help
  18. fprint_header
  19. fprint_reg_help_ex
  20. fprint_reg_help
  21. fprint_attach_help_ex
  22. fprint_set_help_ex
  23. fprint_set_help
  24. fprint_show_help_ex
  25. fprint_show_help
  26. fprint_brk_help_ex
  27. help_dev_help
  28. help_cmd_output
  29. help_cmd
  30. spawn_cmd
  31. echo_cmd
  32. do_cmd
  33. do_position
  34. do_cmd_label
  35. sim_sub_args
  36. sim_cmp_string
  37. assert_cmd
  38. send_cmd
  39. sim_show_send
  40. expect_cmd
  41. sim_show_expect
  42. goto_cmd
  43. return_cmd
  44. shift_cmd
  45. call_cmd
  46. on_cmd
  47. noop_cmd
  48. set_on
  49. set_verify
  50. set_message
  51. set_localopc
  52. set_quiet
  53. sim_set_environment
  54. set_cmd
  55. find_ctab
  56. find_c1tab
  57. set_dev_radix
  58. set_dev_enbdis
  59. set_unit_enbdis
  60. set_dev_debug
  61. show_cmd
  62. show_cmd_fi
  63. find_shtab
  64. show_device
  65. fprint_sep
  66. show_unit
  67. sprint_capac
  68. fprint_capac
  69. show_default_base_system_script
  70. printp
  71. strip_spaces
  72. printpq
  73. show_prom
  74. show_buildinfo
  75. removehex
  76. show_version
  77. show_config
  78. show_log_names
  79. show_dev_logicals
  80. show_queue
  81. show_time
  82. show_break
  83. show_dev_radix
  84. show_dev_debug
  85. show_on
  86. show_mod_names
  87. show_dev_modifiers
  88. show_all_mods
  89. show_one_mod
  90. show_show_commands
  91. show_dev_show_commands
  92. brk_cmd
  93. ssh_break
  94. ssh_break_one
  95. reset_cmd
  96. reset_all
  97. reset_all_p
  98. attach_cmd
  99. scp_attach_unit
  100. attach_unit
  101. attach_err
  102. detach_cmd
  103. detach_all
  104. scp_detach_unit
  105. detach_unit
  106. sim_dname
  107. sim_uname
  108. run_cmd
  109. run_cmd_message
  110. sim_run_boot_prep
  111. fprint_stopped_gen
  112. fprint_stopped
  113. step_svc
  114. expect_svc
  115. int_handler
  116. exdep_cmd
  117. exdep_reg_loop
  118. exdep_addr_loop
  119. ex_reg
  120. get_rval
  121. dep_reg
  122. put_rval
  123. ex_addr
  124. get_aval
  125. dep_addr
  126. eval_cmd
  127. read_line
  128. read_line_p
  129. get_glyph_gen
  130. get_glyph
  131. get_glyph_nc
  132. get_glyph_quoted
  133. get_glyph_cmd
  134. sim_trim_endspc
  135. sim_isspace
  136. sim_islower
  137. sim_isalpha
  138. sim_isprint
  139. sim_isdigit
  140. sim_isgraph
  141. sim_isalnum
  142. get_uint
  143. get_range
  144. sim_decode_quoted_string
  145. sim_encode_quoted_string
  146. fprint_buffer_string
  147. find_dev
  148. find_unit
  149. sim_register_internal_device
  150. find_dev_from_unit
  151. qdisable
  152. find_reg_glob
  153. find_reg
  154. get_switches
  155. get_sim_sw
  156. get_sim_opt
  157. put_switches
  158. get_rsearch
  159. get_asearch
  160. test_search
  161. strtotv
  162. sprint_val
  163. fprint_val
  164. sim_fmt_secs
  165. sim_process_event
  166. sim_activate
  167. _sim_activate
  168. sim_activate_abs
  169. sim_activate_after
  170. _sim_activate_after
  171. sim_cancel
  172. sim_is_active
  173. sim_activate_time
  174. sim_gtime
  175. sim_qcount
  176. sim_brk_init
  177. sim_brk_fnd
  178. sim_brk_fnd_ex
  179. sim_brk_new
  180. sim_brk_set
  181. sim_brk_clr
  182. sim_brk_clrall
  183. sim_brk_show
  184. sim_brk_showall
  185. sim_brk_test
  186. sim_brk_getact
  187. sim_brk_clract
  188. sim_brk_setact
  189. sim_brk_npc
  190. sim_brk_clrspc
  191. sim_brk_message
  192. sim_set_expect
  193. sim_set_noexpect
  194. sim_exp_fnd
  195. sim_exp_clr_tab
  196. sim_exp_clr
  197. sim_exp_clrall
  198. sim_exp_set
  199. sim_exp_show_tab
  200. sim_exp_show
  201. sim_exp_showall
  202. sim_exp_check
  203. sim_send_input
  204. sim_send_clear
  205. sim_show_send_input
  206. sim_send_poll_data
  207. sim_error_text
  208. sim_string_to_stat
  209. get_dbg_verb
  210. sim_debug_prefix
  211. fprint_fields
  212. sim_debug_bits_hdr
  213. sim_debug_bits
  214. sim_printf
  215. sim_messagef
  216. _sim_debug
  217. sim_data_trace
  218. Fprintf
  219. appendText
  220. cleanHelp
  221. buildHelp
  222. helpPrompt
  223. displayMagicTopic
  224. displayFlatHelp
  225. matchHelpTopicName
  226. scp_vhelp
  227. scp_help

   1 /*
   2  * scp.c: simulator control program
   3  *
   4  * vim: filetype=c:tabstop=4:ai:colorcolumn=84:expandtab
   5  * SPDX-License-Identifier: MIT
   6  * scspell-id: 7cde852c-f62a-11ec-8444-80ee73e9b8e7
   7  *
   8  * ---------------------------------------------------------------------------
   9  *
  10  * Copyright (c) 1993-2022 Robert M. Supnik
  11  * Copyright (c) 2026 Eric Swenson
  12  * Copyright (c) 2021-2026 Jeffrey H. Johnson
  13  * Copyright (c) 2006-2026 The DPS8M Development Team
  14  *
  15  * Permission is hereby granted, free of charge, to any person obtaining a
  16  * copy of this software and associated documentation files (the "Software"),
  17  * to deal in the Software without restriction, including without limitation
  18  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19  * and/or sell copies of the Software, and to permit persons to whom the
  20  * Software is furnished to do so, subject to the following conditions:
  21  *
  22  * The above copyright notice and this permission notice shall be included in
  23  * all copies or substantial portions of the Software.
  24  *
  25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  28  * ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  29  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  30  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31  * SOFTWARE.
  32  *
  33  * Except as contained in this notice, the name of Robert M. Supnik shall not
  34  * be used in advertising or otherwise to promote the sale, use or other
  35  * dealings in this Software without prior written authorization from
  36  * Robert M. Supnik.
  37  *
  38  * ---------------------------------------------------------------------------
  39  */
  40 
  41 //-V::701
  42 
  43 #if !defined(__EXTENSIONS__)
  44 # define __EXTENSIONS__
  45 #endif
  46 
  47 #if !defined(__STDC_WANT_LIB_EXT1__)
  48 # define __STDC_WANT_LIB_EXT1__ 1
  49 #endif
  50 
  51 #if !defined(_GNU_SOURCE)
  52 # define _GNU_SOURCE
  53 #endif
  54 
  55 /* Macros and data structures */
  56 
  57 #include "sim_defs.h"
  58 #include "sim_disk.h"
  59 #include "sim_hints.h"
  60 #include "sim_tape.h"
  61 #include "sim_sock.h"
  62 #include "sim_os_mem.h"
  63 
  64 #include <signal.h>
  65 #include <ctype.h>
  66 #include <time.h>
  67 #include <math.h>
  68 #include <stddef.h>
  69 #if defined(_WIN32)
  70 # if !defined(WIN32_LEAN_AND_MEAN)
  71 #  define WIN32_LEAN_AND_MEAN
  72 # endif /* if !defined(WIN32_LEAN_AND_MEAN) */
  73 # if defined(_MSC_VER)
  74 #  pragma warning(push, 3)
  75 # endif
  76 # include <direct.h>
  77 # include <io.h>
  78 # include <fcntl.h>
  79 #else
  80 # include <unistd.h>
  81 # define HAVE_UNISTD 1
  82 #endif
  83 #include <sys/stat.h>
  84 #include <sys/types.h>
  85 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
  86 # include <sys/resource.h>
  87 #endif
  88 #include <setjmp.h>
  89 #include <stdint.h>
  90 #include <limits.h>
  91 #if defined(__APPLE__)
  92 # include <xlocale.h>
  93 #endif
  94 #include <locale.h>
  95 
  96 #include "linehistory.h"
  97 
  98 #if defined(__APPLE__)
  99 # include <sys/sysctl.h>
 100 #endif /* if defined(_APPLE_) */
 101 
 102 #if ( defined(__linux__) || defined(__linux) || defined(_linux) || defined(linux) ) //-V1040
 103 # include <sys/sysinfo.h>
 104 # define LINUX_OS
 105 #endif
 106 
 107 #include <uv.h>
 108 
 109 #if !defined(HAVE_UNISTD)
 110 # undef USE_BACKTRACE
 111 #endif /* if !defined(HAVE_UNISTD) */
 112 
 113 #if defined(USE_BACKTRACE)
 114 # include <string.h>
 115 # include <signal.h>
 116 #endif /* if defined(USE_BACKTRACE) */
 117 
 118 #if defined(__HAIKU__)
 119 # include <OS.h>
 120 #endif /* if defined(__HAIKU__) */
 121 
 122 #if !defined(__CYGWIN__)
 123 # if !defined(__APPLE__)
 124 #  if !defined(_AIX)
 125 #   if !defined(__MINGW32__)
 126 #    if !defined(__MINGW64__)
 127 #     if !defined(CROSS_MINGW32)
 128 #      if !defined(CROSS_MINGW64)
 129 #       if !defined(_WIN32)
 130 #        if !defined(__HAIKU__)
 131 #         if !defined(__QNX__)
 132 #          include <link.h>
 133 #         endif
 134 #        endif
 135 #       endif
 136 #      endif
 137 #     endif
 138 #    endif
 139 #   endif
 140 #  endif
 141 # endif
 142 #endif
 143 
 144 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
 145 # include <windows.h>
 146 #endif
 147 
 148 #if defined(__CYGWIN__)
 149 # include <windows.h>
 150 # include <sys/utsname.h>
 151 # include <sys/cygwin.h>
 152 # include <cygwin/version.h>
 153 #endif
 154 
 155 #define DBG_CTR 0
 156 
 157 #include "../dps8/dps8.h"
 158 #include "../dps8/dps8_cpu.h"
 159 #include "../dps8/dps8_rt.h"
 160 #include "../dps8/dps8_priv.h"
 161 #include "../dps8/dps8_topo.h"
 162 #include "../dps8/ver.h"
 163 
 164 #include "../dps8/dps8_iom.h"
 165 #include "../dps8/dps8_fnp2.h"
 166 
 167 #include "../decNumber/decContext.h"
 168 #include "../decNumber/decNumberLocal.h"
 169 
 170 #include "../dps8/dps8_math128.h"
 171 
 172 #include "../dps8/dps8_sir.h"
 173 
 174 #if !defined(__CYGWIN__)
 175 # if !defined(__APPLE__)
 176 #  if !defined(_AIX)
 177 #   if !defined(__MINGW32__)
 178 #    if !defined(__MINGW64__)
 179 #     if !defined(CROSS_MINGW32)
 180 #      if !defined(CROSS_MINGW64)
 181 #       if !defined(_WIN32)
 182 #        if !defined(__HAIKU__)
 183 #         if !defined(__QNX__)
 184 #          if !defined(__FILC__)
 185 static unsigned int dl_iterate_phdr_callback_called = 0;
 186 #          endif
 187 #         endif
 188 #        endif
 189 #       endif
 190 #      endif
 191 #     endif
 192 #    endif
 193 #   endif
 194 #  endif
 195 # endif
 196 #endif
 197 
 198 #if defined(MAX)
 199 # undef MAX
 200 #endif /* if defined(MAX) */
 201 #define MAX(a,b)  (((a) >= (b)) ? (a) : (b))
 202 
 203 #if defined(FREE)
 204 # undef FREE
 205 #endif /* if defined(FREE) */
 206 #define FREE(p) do  \
 207   {                 \
 208     free((p));      \
 209     (p) = NULL;     \
 210   } while(0)
 211 
 212 /* search logical and boolean ops */
 213 
 214 #define SCH_OR          0                               /* search logicals */
 215 #define SCH_AND         1
 216 #define SCH_XOR         2
 217 #define SCH_E           0                               /* search booleans */
 218 #define SCH_N           1
 219 #define SCH_G           2
 220 #define SCH_L           3
 221 #define SCH_EE          4
 222 #define SCH_NE          5
 223 #define SCH_GE          6
 224 #define SCH_LE          7
 225 
 226 #define MAX_DO_NEST_LVL 20                              /* DO cmd nesting level */
 227 #define SRBSIZ          1024                            /* save/restore buffer */
 228 #define SIM_BRK_INILNT  4096                            /* bpt tbl length */
 229 #define SIM_BRK_ALLTYP  0xFFFFFFFB
 230 
 231 #define UPDATE_SIM_TIME                                         \
 232     if (1) {                                                    \
 233         int32 _x;                                               \
 234         if (sim_clock_queue == QUEUE_LIST_END)                  \
 235             _x = noqueue_time;                                  \
 236         else                                                    \
 237             _x = sim_clock_queue->time;                         \
 238         sim_time = sim_time + (_x - sim_interval);              \
 239         sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
 240         if (sim_clock_queue == QUEUE_LIST_END)                  \
 241             noqueue_time = sim_interval;                        \
 242         else                                                    \
 243             sim_clock_queue->time = sim_interval;               \
 244         }                                                       \
 245     else                                                        \
 246         (void)0
 247 
 248 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
 249 
 250 #define SZ_R(rp) \
 251     (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
 252 
 253 #define SZ_LOAD(sz,v,mb,j)                                                 \
 254     if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j));        \
 255     else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
 256     else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
 257     else v = *(((t_uint64 *) mb) + ((uint32) j));
 258 
 259 #define SZ_STORE(sz,v,mb,j)                                                         \
 260     if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v;                    \
 261     else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
 262     else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
 263     else *(((t_uint64 *) mb) + ((uint32) j)) = v;
 264 
 265 #define GET_SWITCHES(cp) \
 266     if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
 267 
 268 #define GET_RADIX(val,dft)                          \
 269     if (sim_switches & SWMASK ('O')) val = 8;       \
 270     else if (sim_switches & SWMASK ('D')) val = 10; \
 271     else if (sim_switches & SWMASK ('H')) val = 16; \
 272     else val = dft;
 273 
 274 /*
 275  * The per-simulator init routine is a weak global that defaults to NULL
 276  * The other per-simulator pointers can be overridden by the init routine
 277  */
 278 
 279 t_bool sim_asynch_enabled = FALSE;
 280 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
 281 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
 282 extern void (*sim_vm_init) (void);
 283 extern void (*sim_vm_exit) (void);
 284 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
 285 void (*sim_vm_post) (t_bool from_scp) = NULL;
 286 CTAB *sim_vm_cmd = NULL;
 287 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
 288 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
 289 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
 290 t_value (*sim_vm_pc_value) (void) = NULL;
 291 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
 292 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
 293 unsigned int nprocs;
 294 unsigned int ncores;
 295 bool mlock_failure = false;
 296 char* sim_appfilename;
 297 
 298 /* Prototypes */
 299 
 300 /* Set and show command processors */
 301 
 302 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 303 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 304 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 305 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 306 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
 307 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
 308 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 309 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 310 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 311 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 312 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 313 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 314 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 315 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 316 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 317 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 318 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 319 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 320 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
 321 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 322 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 323 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 324 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 325 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 326 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 327 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 328 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
 329 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
 330 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
 331 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
 332 t_stat sim_save (FILE *sfile);
 333 t_stat sim_rest (FILE *rfile);
 334 
 335 /* Breakpoint package */
 336 
 337 t_stat sim_brk_init (void);
 338 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
 339 t_stat sim_brk_clr (t_addr loc, int32 sw);
 340 t_stat sim_brk_clrall (int32 sw);
 341 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
 342 t_stat sim_brk_showall (FILE *st, uint32 sw);
 343 CONST char *sim_brk_getact (char *buf, int32 size);
 344 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
 345 char *sim_brk_clract (void);
 346 
 347 FILE *stdnul;
 348 
 349 /* Command support routines */
 350 
 351 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 352 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 353 int32 test_search (t_value *val, SCHTAB *schptr);
 354 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
 355 int32 get_switches (const char *cptr);
 356 CONST char *get_sim_sw (CONST char *cptr);
 357 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
 358 t_value get_rval (REG *rptr, uint32 idx);
 359 void put_rval (REG *rptr, uint32 idx, t_value val);
 360 void fprint_help (FILE *st);
 361 void fprint_stopped (FILE *st, t_stat r);
 362 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
 363 void fprint_sep (FILE *st, int32 *tokens);
 364 char *read_line (char *ptr, int32 size, FILE *stream);
 365 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
 366 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
 367 char *sim_trim_endspc (char *cptr);
 368 
 369 /* Forward references */
 370 
 371 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
 372 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
 373 t_bool qdisable (DEVICE *dptr);
 374 t_stat attach_err (UNIT *uptr, t_stat stat);
 375 t_stat detach_all (int32 start_device, t_bool shutdown);
 376 t_stat assign_device (DEVICE *dptr, const char *cptr);
 377 t_stat deassign_device (DEVICE *dptr);
 378 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
 379 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
 380     REG *lowr, REG *highr, uint32 lows, uint32 highs);
 381 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
 382 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
 383 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
 384     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
 385 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
 386 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
 387     UNIT *uptr, int32 dfltinc);
 388 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
 389 t_stat step_svc (UNIT *ptr);
 390 t_stat expect_svc (UNIT *ptr);
 391 t_stat set_on (int32 flag, CONST char *cptr);
 392 t_stat set_verify (int32 flag, CONST char *cptr);
 393 t_stat set_message (int32 flag, CONST char *cptr);
 394 t_stat set_quiet (int32 flag, CONST char *cptr);
 395 t_stat set_localopc (int32 flag, CONST char *cptr);
 396 t_stat set_asynch (int32 flag, CONST char *cptr);
 397 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 398 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
 399 void int_handler (int signal);
 400 t_stat set_prompt (int32 flag, CONST char *cptr);
 401 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
 402 t_stat sim_set_environment (int32 flag, CONST char *cptr);
 403 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
 404 
 405 /* Global data */
 406 
 407 DEVICE *sim_dflt_dev             = NULL;
 408 UNIT *sim_clock_queue            = QUEUE_LIST_END;
 409 int32 sim_interval               = 0;
 410 int32 sim_switches               = 0;
 411 FILE *sim_ofile                  = NULL;
 412 SCHTAB *sim_schrptr              = NULL;
 413 SCHTAB *sim_schaptr              = NULL;
 414 DEVICE *sim_dfdev                = NULL;
 415 UNIT *sim_dfunit                 = NULL;
 416 DEVICE **sim_internal_devices    = NULL;
 417 uint32 sim_internal_device_count = 0;
 418 int32 sim_opt_out                = 0;
 419 int32 sim_is_running             = 0;
 420 t_bool sim_processing_event      = FALSE;
 421 uint32 sim_brk_summ              = 0;
 422 uint32 sim_brk_types             = 0;
 423 BRKTYPTAB *sim_brk_type_desc     = NULL;         /* type descriptions */
 424 uint32 sim_brk_dflt              = 0;
 425 uint32 sim_brk_match_type;
 426 t_addr sim_brk_match_addr;
 427 char *sim_brk_act[MAX_DO_NEST_LVL];
 428 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
 429 BRKTAB **sim_brk_tab             = NULL;
 430 int32 sim_brk_ent                = 0;
 431 int32 sim_brk_lnt                = 0;
 432 int32 sim_brk_ins                = 0;
 433 int32 sim_iglock                 = 0;
 434 int32 sim_nolock                 = 0;
 435 int32 sim_quiet                  = 0;
 436 int32 sim_localopc               = 1;
 437 int32 sim_randompst              = 0;
 438 int32 sim_randstate              = 0;
 439 int32 sim_step                   = 0;
 440 int nodist                       = 0;
 441 #if defined(PERF_STRIP)
 442 int32 sim_nostate                = 1;
 443 #else
 444 int32 sim_nostate                = 0;
 445 #endif /* if defined(PERF_STRIP) */
 446 static double sim_time;
 447 static uint32 sim_rtime;
 448 static int32 noqueue_time;
 449 volatile int32 stop_cpu          = 0;
 450 t_value *sim_eval                = NULL;
 451 static t_value sim_last_val;
 452 static t_addr sim_last_addr;
 453 FILE *sim_log                    = NULL;         /* log file */
 454 FILEREF *sim_log_ref             = NULL;         /* log file file reference */
 455 FILE *sim_deb                    = NULL;         /* debug file */
 456 FILEREF *sim_deb_ref             = NULL;         /* debug file file reference */
 457 int32 sim_deb_switches           = 0;            /* debug switches */
 458 struct timespec sim_deb_basetime;                /* debug timestamp relative base time */
 459 char *sim_prompt                 = NULL;         /* prompt string */
 460 static FILE *sim_gotofile;                       /* the currently open do file */
 461 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];   /* the current line number in the currently open do file */
 462 static int32 sim_do_echo         = 0;            /* the echo status of the currently open do file */
 463 static int32 sim_show_message    = 1;            /* the message display status of the currently open do file */
 464 static int32 sim_on_inherit      = 0;            /* the inherit status of on state and conditions when executing do files */
 465 #if !defined(PERF_STRIP)
 466 static int32 sim_realtime        = 0;            /* user requested real-time mode */
 467 #endif
 468 static int32 sim_do_depth        = 0;
 469 uint64_t sim_free_memory         = 0;
 470 
 471 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
 472 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
 473 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
 474 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
 475 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
 476 
 477 t_stat sim_last_cmd_stat;                        /* Command Status */
 478 
 479 static SCHTAB sim_stabr;                         /* Register search specifier */
 480 static SCHTAB sim_staba;                         /* Memory search specifier */
 481 
 482 static UNIT sim_step_unit   = { UDATA (&step_svc, 0, 0)  };
 483 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0)  };
 484 
 485 pthread_t main_thread_id;
 486 
 487 /* Tables and strings */
 488 
 489 const char save_vercur[] = "V4.1";
 490 const char save_ver40[]  = "V4.0";
 491 const char save_ver35[]  = "V3.5";
 492 const char save_ver32[]  = "V3.2";
 493 const char save_ver30[]  = "V3.0";
 494 const struct scp_error {
 495     const char *code;
 496     const char *message;
 497     } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
 498         {{"NXM",     "Address space exceeded"},
 499          {"UNATT",   "Unit not attached"},
 500          {"IOERR",   "I/O error"},
 501          {"CSUM",    "Checksum error"},
 502          {"FMT",     "Format error"},
 503          {"NOATT",   "Unit not attachable"},
 504          {"OPENERR", "File open error"},
 505          {"MEM",     "Memory exhausted"},
 506          {"ARG",     "Invalid argument"},
 507          {"STEP",    "Step expired"},
 508          {"UNK",     "Unknown command"},
 509          {"RO",      "Read only argument"},
 510          {"INCOMP",  "Command not completed"},
 511          {"STOP",    "Simulation stopped"},
 512          {"EXIT",    "Goodbye"},
 513          {"TTIERR",  "Console input I/O error"},
 514          {"TTOERR",  "Console output I/O error"},
 515          {"EOF",     "End of file"},
 516          {"REL",     "Relocation error"},
 517          {"NOPARAM", "No settable parameters"},
 518          {"ALATT",   "Unit already attached"},
 519          {"TIMER",   "Hardware timer error"},
 520          {"SIGERR",  "Signal handler setup error"},
 521          {"TTYERR",  "Console terminal setup error"},
 522          {"SUB",     "Subscript out of range"},
 523          {"NOFNC",   "Command not allowed"},
 524          {"UDIS",    "Unit disabled"},
 525          {"NORO",    "Read only operation not allowed"},
 526          {"INVSW",   "Invalid switch"},
 527          {"MISVAL",  "Missing value"},
 528          {"2FARG",   "Too few arguments"},
 529          {"2MARG",   "Too many arguments"},
 530          {"NXDEV",   "Non-existent device"},
 531          {"NXUN",    "Non-existent unit"},
 532          {"NXREG",   "Non-existent register"},
 533          {"NXPAR",   "Non-existent parameter"},
 534          {"NEST",    "Nested DO command limit exceeded"},
 535          {"IERR",    "Internal error"},
 536          {"MTRLNT",  "Invalid magtape record length"},
 537          {"LOST",    "Console Telnet connection lost"},
 538          {"TTMO",    "Console Telnet connection timed out"},
 539          {"STALL",   "Console Telnet output stall"},
 540          {"AFAIL",   "Assertion failed"},
 541          {"INVREM",  "Invalid remote console command"},
 542          {"NOTATT",  "Not attached"},
 543          {"EXPECT",  "Expect matched"},
 544          {"REMOTE",  "Remote console command"},
 545     };
 546 
 547 const size_t size_map[] = { sizeof (int8),
 548     sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
 549     , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
 550 };
 551 
 552 const t_value width_mask[] = { 0,
 553     0x1, 0x3, 0x7, 0xF,
 554     0x1F, 0x3F, 0x7F, 0xFF,
 555     0x1FF, 0x3FF, 0x7FF, 0xFFF,
 556     0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
 557     0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
 558     0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
 559     0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
 560     0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
 561     0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
 562     0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
 563     0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
 564     0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
 565     0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
 566     0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
 567     0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
 568     0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
 569     };
 570 
 571 static const char simh_help[] =
 572        /***************** 80 character line width template *************************/
 573       "1Commands\n" //-NLOK
 574 #define HLP_RESET       "*Commands Resetting Devices"
 575        /***************** 80 character line width template *************************/
 576       "2Resetting Devices\n" //-NLOK
 577       " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\r\n"
 578       " simulator to a predefined condition.  If the switch \"`-p`\" is specified,\r\n"
 579       " the device is reset to its initial power-on state:\r\n\r\n"
 580       "++RESET                  resets all devices\r\n"
 581       "++RESET -p               power-cycle all devices\r\n"
 582       "++RESET ALL              resets all devices\r\n"
 583       "++RESET <device>         resets the specified <device>\r\n\r\n"
 584       " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\r\n"
 585       " interrupt requests, and returns the device to a quiescent state.\r\n\r\n"
 586       " * It does **NOT** clear the main memory or affect associated I/O\r\n"
 587       " connections.\r\n"
 588 #define HLP_EXAMINE     "*Commands Examining_and_Changing_State"
 589 #define HLP_IEXAMINE    "*Commands Examining_and_Changing_State"
 590 #define HLP_DEPOSIT     "*Commands Examining_and_Changing_State"
 591 #define HLP_IDEPOSIT    "*Commands Examining_and_Changing_State"
 592        /***************** 80 character line width template *************************/
 593       "2Examining and Changing State\n" //-NLOK
 594       " There are four commands to examine and change state:\r\n\r\n"
 595       " * `EXAMINE` (*abbreviated* `E`) examines state\r\n"
 596       " * `DEPOSIT` (*abbreviated* `D`) changes state\r\n"
 597       " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\r\n"
 598       "    and allows the user to interactively change it\r\n"
 599       " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\r\n"
 600       "    interactively change state\r\n\r\n"
 601       " All four commands take the form:\r\n\r\n"
 602       "++command {modifiers} <object list>\r\n\r\n"
 603       " The `DEPOSIT` command requires the deposit value at the end of the command.\r\n\r\n"
 604       " There are four kinds of modifiers: **switches**, **device/unit name**,\r\n"
 605       " **search specifier**, and for `EXAMINE`, **output file**.\r\n\r\n"
 606       " * **Switches** have been described previously.\r\n"
 607       " * A **device/unit name** identifies the device and unit whose address\r\n"
 608       " space is to be examined or modified. If no device is specified, the CPU\r\n"
 609       " main memory is selected. If a device but no unit is specified, unit `0`\r\n"
 610       " of the specified device is selected automatically.\r\n"
 611       " * The **search specifier** provides criteria for testing addresses or\r\n"
 612       " registers to see if they should be processed.  The search specifier\r\n"
 613       " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\r\n"
 614       " both, optionally separated by spaces:\r\n\r\n"
 615       "++{ < logical op >  < value > }  < relational op >  < value >\r\n\r\n"
 616        /***************** 80 character line width template *************************/
 617       " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\r\n"
 618       " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\r\n"
 619       " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\r\n"
 620       " equal*), \">=\" (*greater than or equal*), \">\" (*greater\r\n"
 621       " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\r\n"
 622       " * * If any \"<`logical operator`>\" is specified without\r\n"
 623       " a \"<`relational operator`>\", it is ignored.\r\n"
 624       " * * If any \"<`relational operator`>\" is specified without\r\n"
 625       " a \"<`logical operator`>\", no logical operation is performed.\r\n"
 626       " * * All comparisons are unsigned.\r\n\r\n"
 627       " * The **output file** modifier redirects the command output to a file\r\n"
 628       " instead of the console.  The **output file** modifier is specified with\r\n"
 629       " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\r\n\r\n"
 630       " **NOTE**: Modifiers may be specified in any order.  If multiple\r\n"
 631       " modifiers of the same type are specified, later modifiers override earlier\r\n"
 632       " modifiers. If the **device/unit name** comes *after* the search specifier,\r\n"
 633       " the search values will interpreted in the *radix of the CPU*, rather than\r\n"
 634       " of the device/unit.\r\n\r\n"
 635       " The \"<`object list`>\" argument consists of one or more of the following,\r\n"
 636       " separated by commas:\r\n\r\n"
 637        /***************** 80 character line width template *************************/
 638       "++register                the specified register\r\n"
 639       "++register[sub1-sub2]     the specified register array locations,\r\n"
 640       "++++++++                  starting at location sub1 up to and\r\n"
 641       "++++++++                  including location sub2\r\n"
 642       "++register[sub1/length]   the specified register array locations,\r\n"
 643       "++++++++                  starting at location sub1 up to but\r\n"
 644       "++++++++                  not including sub1+length\r\n"
 645       "++register[ALL]           all locations in the specified register\r\n"
 646       "++++++++                  array\r\n"
 647       "++register1-register2     all the registers starting at register1\r\n"
 648       "++++++++                  up to and including register2\r\n"
 649       "++address                 the specified location\r\n"
 650       "++address1-address2       all locations starting at address1 up to\r\n"
 651       "++++++++                  and including address2\r\n"
 652       "++address/length          all location starting at address up to\r\n"
 653       "++++++++                  but not including address+length\r\n"
 654       "++STATE                   all registers in the device\r\n"
 655       "++ALL                     all locations in the unit\r\n"
 656       "++$                       the last value displayed by an EXAMINE\r\n"
 657       "++++++++                  command interpreted as an address\r\n"
 658       "3Switches\n" //-NLOK
 659       "4Formatting Control\n" //-NLOK
 660       " Switches can be used to control the format of the displayed information:\r\n\r\n"
 661        /***************** 80 character line width template *************************/
 662       "5`-a`\n" //-NLOK
 663       " display as ASCII\r\n"
 664       "5`-c`\n" //-NLOK
 665       " display as character string\r\n"
 666       "5`-m`\n" //-NLOK
 667       " display as instruction mnemonics\r\n"
 668       "5`-o`\n" //-NLOK
 669       " display as octal\r\n"
 670       "5`-d`\n" //-NLOK
 671       " display as decimal\r\n"
 672       "5`-h`\n" //-NLOK
 673       " display as hexadecimal\r\n\r\n"
 674       "3Examples\n" //-NLOK
 675       "++ex 1000-1100                examine 1000 to 1100\r\n"
 676       "++de PC 1040                  set PC to 1040\r\n"
 677       "++ie 40-50                    interactively examine 40:50\r\n"
 678       "++ie >1000 40-50              interactively examine the subset\r\n"
 679       "+++++++++                     of locations 40:50 that are >1000\r\n"
 680       "++ex rx0 50060                examine 50060, RX unit 0\r\n"
 681       "++ex rx sbuf[3-6]             examine SBUF[3] to SBUF[6] in RX\r\n"
 682       "++de all 0                    set main memory to 0\r\n"
 683       "++de &77>0 0                  set all addresses whose low order\r\n"
 684       "+++++++++                     bits are non-zero to 0\r\n"
 685       "++ex -m @memdump.txt 0-7777   dump memory to file\r\n\r\n"
 686       " * **NOTE**: To terminate an interactive command, simply type any bad value\r\n"
 687       "           (*e.g.* `XYZ`) when input is requested.\r\n"
 688 #define HLP_EVALUATE    "*Commands Evaluating_Instructions"
 689        /***************** 80 character line width template *************************/
 690       "2Evaluating Instructions\n" //-NLOK
 691       " The `EVAL` command evaluates a symbolic expression and returns the\r\n"
 692       " equivalent numeric value.\r\n\r\n"
 693        /***************** 80 character line width template *************************/
 694       "2Running A Simulated Program\n" //-NLOK
 695 #define HLP_RUN         "*Commands Running_A_Simulated_Program RUN"
 696       "3RUN\n" //-NLOK
 697       " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\r\n"
 698       " argument, if given, in the PC (program counter), and starts execution.\r\n"
 699       " If no argument is given execution starts at the current PC.\r\n"
 700 #define HLP_GO          "*Commands Running_A_Simulated_Program GO"
 701       "3GO\n" //-NLOK
 702       " The `GO` command does *not* reset devices, deposits its argument (if\r\n"
 703       " given) in the PC, and starts execution.  If no argument is given,\r\n"
 704       " execution starts at the current PC (program counter).\r\n"
 705 #define HLP_CONTINUE    "*Commands Running_A_Simulated_Program Continuing_Execution"
 706       "3Continuing Execution\n" //-NLOK
 707       " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\r\n"
 708       " (if execution was stopped, possibly due to hitting a breakpoint) at the\r\n"
 709       " current program counter without resetting any devices.\r\n"
 710 #define HLP_STEP        "*Commands Running_A_Simulated_Program Step_Execution"
 711       "3Step Execution\n" //-NLOK
 712       " The `STEP` command (*abbreviated* `S`) resumes execution at the current\r\n"
 713       " PC for the number of instructions given by its argument.  If no argument\r\n"
 714       " is supplied, one instruction is executed.\r\n"
 715       "4Switches\n" //-NLOK
 716       "5`-T`\n" //-NLOK
 717       " If the `STEP` command is invoked with the \"`-T`\" switch, the step\r\n"
 718       " command will cause execution to run for *microseconds* rather than\r\n"
 719       " instructions.\r\n"
 720 #define HLP_NEXT        "*Commands Running_A_Simulated_Program NEXT"
 721       "3NEXT\n" //-NLOK
 722       " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\r\n"
 723       " for one instruction, attempting to execute *through* subroutine calls.\r\n"
 724       " If the next instruction to be executed is *not* a subroutine call, then\r\n"
 725       " one instruction is executed.\r\n"
 726 #define HLP_BOOT        "*Commands Running_A_Simulated_Program Booting_the_system"
 727       "3Booting the system\n" //-NLOK
 728       " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\r\n"
 729       " the device and unit given by its argument. If no unit is supplied,\r\n"
 730       " unit `0` is bootstrapped.  The specified unit must be `ATTACH`'ed.\r\n\r\n"
 731       " When booting Multics, the boot device should always be `iom0`.\r\n"
 732       " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\r\n"
 733       " into memory and the system will transfer control to the boot record.\r\n\r\n"
 734       " **Example**\r\n\r\n"
 735       "++; Boot Multics using iom0\r\n"
 736       "++boot iom0\r\n\r\n"
 737        /***************** 80 character line width template *************************/
 738       "2Stopping The Simulator\n" //-NLOK
 739       " The simulator runs until the simulated hardware encounters an error, or\r\n"
 740       " until the user forces a stop condition.\r\n"
 741       "3Simulator Detected Stop Conditions\n" //-NLOK
 742       " These simulator-detected conditions stop simulation:\r\n\r\n"
 743       "++-  HALT instruction.  If a HALT instruction is decoded, simulation stops.\r\n\r\n"
 744       "++-  I/O error.  If an I/O error occurs during simulation of an I/O\r\n"
 745       "+++operation, and the device stop-on-I/O-error flag is set, simulation\r\n"
 746       "+++usually stops.\r\n\r\n"
 747       "++-  Processor condition.  Certain processor conditions can stop\r\n"
 748       "+++the simulation.\r\n"
 749       "3User Specified Stop Conditions\n" //-NLOK
 750       " Typing the interrupt character stops simulation.  The interrupt character\r\n"
 751       " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\r\n"
 752       " set to `005` (`^E`).\r\n\r\n"
 753        /***************** 80 character line width template *************************/
 754 #define HLP_BREAK       "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 755 #define HLP_NOBREAK     "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 756       "4Breakpoints\n" //-NLOK
 757       " The simulator offers breakpoint capability for debugging. Users may define\r\n"
 758       " breakpoints of different types, identified by letter (for example, `E`\r\n"
 759       " for *execution*, `R` for *read*, `W` for *write*, etc).\r\n\r\n"
 760       " Associated with each breakpoint is a count and, optionally, one or more\r\n"
 761       " actions.  Each time a breakpoint occurs, the associated count\r\n"
 762       " is *decremented*.  If the count is less than or equal to `0`, the breakpoint\r\n"
 763       " occurs; otherwise, it is deferred.  When the breakpoint occurs, any\r\n"
 764       " optional actions are automatically executed.\r\n\r\n"
 765       " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\r\n\r\n"
 766       "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\r\n\r\n"
 767       " If no type is specified, the default breakpoint type (`E`, *execution*) is\r\n"
 768       " used.  If no address range is specified, the current PC is used.  As\r\n"
 769       " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\r\n"
 770       " range of addresses low-high, or a relative range of address/length.\r\n"
 771        /***************** 80 character line width template *************************/
 772       "5Displaying Breakpoints\n" //-NLOK
 773       " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\r\n\r\n"
 774       "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\r\n\r\n"
 775       " Locations with breakpoints of the specified type are displayed.\r\n\r\n"
 776       " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\r\n"
 777       " commands which may be subsequently used to establish the same\r\n"
 778       " breakpoint(s).\r\n\r\n"
 779       "5Removing Breakpoints\n" //-NLOK
 780       " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\r\n"
 781       "5Examples\n" //-NLOK
 782       " The following examples illustrate breakpoint usage:\r\n\r\n"
 783       "++BREAK                      set E break at current PC\r\n"
 784       "++BREAK -e 200               set E break at 200\r\n"
 785       "++BREAK 2000/2[2]            set E breaks at 2000,2001 with count = 2\r\n"
 786       "++BREAK 100;EX AC;D MQ 0     set E break at 100 with actions EX AC and\r\n"
 787       "+++++++++D MQ 0\r\n"
 788       "++BREAK 100;                 delete action on break at 100\r\n\r\n"
 789        /***************** 80 character line width template *************************/
 790       "2Connecting and Disconnecting Devices\n" //-NLOK
 791       " Units are simulated as files on the host file system.  Before using any\r\n"
 792       " simulated unit, the user must specify the file to be accessed by that unit.\r\n"
 793 #define HLP_ATTACH      "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
 794       "3Attaching devices\n" //-NLOK
 795       " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\r\n\r\n"
 796       "++ATTACH <unit> <filename>\r\n\r\n"
 797       " Some devices have more detailed or specific help available with:\r\n\r\n"
 798       "++HELP <device> ATTACH\r\n\r\n"
 799       "4Switches\n" //-NLOK
 800       "5`-n`\n" //-NLOK
 801       " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\r\n"
 802       " file will be created when the filename specified does not exist, or an\r\n"
 803       " existing file will have it's size truncated to zero, and an appropriate\r\n"
 804       " message is printed.\r\n"
 805       "5`-e`\n" //-NLOK
 806       " If the file does not exist, and the \"`-e`\" switch *was not* specified,\r\n"
 807       " a new file is created, and an appropriate message is printed.  If\r\n"
 808       " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\r\n"
 809       " error message is printed.\r\n"
 810       "5`-r`\n" //-NLOK
 811       " If the \"`-r`\" switch is specified, or the file is write protected by\r\n"
 812       " host operating system, `ATTACH` tries to open the file in read only mode.\r\n"
 813       " If the file does not exist, or the unit does not support read only\r\n"
 814       " operation, an error occurs.  Input-only devices, such as card readers, or\r\n"
 815       " storage devices with write locking switches, such as disks or tapes,\r\n"
 816       " support read only operation - other devices do not.  If a file is\r\n"
 817       " attached read only, its contents can be examined but not modified.\r\n"
 818       "5`-q`\n" //-NLOK
 819       " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\r\n"
 820       " or opening one read only (\"`-r`\"), the message announcing this fact\r\n"
 821       " is suppressed.\r\n"
 822       "5`-f`\n" //-NLOK
 823       " For simulated magnetic tapes, the `ATTACH` command can specify the format\r\n"
 824       " of the attached tape image file:\r\n\r\n"
 825       "++ATTACH -f <tape_unit> <format> <filename>\r\n\r\n"
 826       " * The currently supported magnetic tape image file formats are:\r\n\r\n"
 827       " |                  |                                                      |\r\n"
 828       " | ----------------:|:---------------------------------------------------- |\r\n"
 829       " | \"**`SIMH`**\"   | The **SIMH** / **DPS8M** native portable tape format |\r\n"
 830       " | \"**`E11`**\"    | The *D Bit* **Ersatz-11** simulator format           |\r\n"
 831       " | \"**`TPC`**\"    | The **TPC** format (*used by _SIMH_ prior to V2.3*)  |\r\n"
 832       " | \"**`P7B`**\"    | The **Paul Pierce** `7`-track tape archive format    |\r\n\r\n"
 833        /***************** 80 character line width template *************************/
 834       " * The default tape format can also be specified with the `SET` command\r\n"
 835       " prior to using the `ATTACH` command:\r\n\r\n"
 836       "++SET <tape_unit> FORMAT=<format>\r\n"
 837       "++ATTACH <tape_unit> <filename>\r\n\r\n"
 838       " * The format of a currently attached tape image can be displayed with\r\n"
 839       "   the `SHOW FORMAT` command:\r\n\r\n"
 840       "++SHOW <unit> FORMAT\r\n\r\n"
 841       " **Examples**\r\n\r\n"
 842       " The following example illustrates common `ATTACH` usage:\r\n"
 843       "++; Associate the tape image file \"12.8MULTICS.tap\" with the tape0 unit\r\n"
 844       "++; in read-only mode, where tape0 corresponds to the first tape device.\r\n"
 845       "++ATTACH -r tape0 12.8MULTICS.tap\r\n\r\n"
 846       "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\r\n"
 847       "++; The disk0 unit corresponds to the first disk device.\r\n"
 848       "++ATTACH disk0 root.dsk\r\n\r\n"
 849        /***************** 80 character line width template *************************/
 850 #define HLP_DETACH      "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
 851       "3Detaching devices\n" //-NLOK
 852       " The `DETACH` (*abbreviation* `DET`) command breaks the association between\r\n"
 853       " a unit and its backing file or device:\r\n\r\n"
 854       "++DETACH ALL             Detach all units\r\n"
 855       "++DETACH <unit>          Detach specified unit\r\n\r\n"
 856       " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\r\n"
 857 #define HLP_SET         "*Commands SET"
 858       "2SET\n" //-NLOK
 859        /***************** 80 character line width template *************************/
 860 #define HLP_SET_LOG    "*Commands SET Logging"
 861       "3Logging\n" //-NLOK
 862       " Interactions with the simulator session can be recorded to a log file.\r\n\r\n"
 863       "+SET LOG log_file            Specify the log destination\r\n"
 864       "++++++++                     (STDOUT, DEBUG, or filename)\r\n"
 865       "+SET NOLOG                   Disables any currently active logging\r\n"
 866       "4Switches\n" //-NLOK
 867       "5`-N`\n" //-NLOK
 868       " By default, log output is written at the *end* of the specified log file.\r\n"
 869       " A new log file can created if the \"`-N`\" switch is used on the command\r\n"
 870       " line.\r\n\r\n"
 871       "5`-B`\n" //-NLOK
 872       " By default, log output is written in *text* mode.  The log file can be\r\n"
 873       " opened for *binary* mode writing if the \"`-B`\" switch is used on the\r\n"
 874       " command line.\r\n"
 875 #define HLP_SET_DEBUG  "*Commands SET Debug_Messages"
 876        /***************** 80 character line width template *************************/
 877       "3Debug Messages\n" //-NLOK
 878       "+SET DEBUG debug_file        Specify the debug destination\r\n"
 879       "++++++++                     (STDOUT, STDERR, LOG, or filename)\r\n"
 880       "+SET NODEBUG                 Disables any currently active debug output\r\n"
 881       "4Switches\n" //-NLOK
 882       " Debug message output contains a timestamp which indicates the number of\r\n"
 883       " simulated instructions which have been executed prior to the debug event.\r\n\r\n"
 884       " Debug message output can be enhanced to contain additional, potentially\r\n"
 885       " useful information.\r\n\r\n\r\n"
 886       " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\r\n"
 887       "5`-T`\n" //-NLOK
 888       " The \"`-T`\" switch causes debug output to contain a time of day displayed\r\n"
 889       " as `hh:mm:ss.msec`.\r\n"
 890       "5`-A`\n" //-NLOK
 891       " The \"`-A`\" switch causes debug output to contain a time of day displayed\r\n"
 892       " as `seconds.msec`.\r\n"
 893       "5`-R`\n" //-NLOK
 894       " The \"`-R`\" switch causes timing to be relative to the start of debugging.\r\n"
 895       "5`-P`\n" //-NLOK
 896       " The \"`-P`\" switch adds the output of the PC (program counter) to each\r\n"
 897       " debug message.\r\n"
 898       "5`-N`\n" //-NLOK
 899       " The \"`-N`\" switch causes a new (empty) file to be written to.\r\n"
 900       " (The default is to append to an existing debug log file).\r\n"
 901       "5`-D`\n" //-NLOK
 902       " The \"`-D`\" switch causes data blob output to also display the data\r\n"
 903       " as **`RADIX-50`** characters.\r\n"
 904       "5`-E`\n" //-NLOK
 905       " The \"`-E`\" switch causes data blob output to also display the data\r\n"
 906       " as \"**EBCDIC**\" characters.\r\n"
 907        /***************** 80 character line width template *************************/
 908 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
 909       "3Environment Variables\n" //-NLOK
 910       "+SET ENVIRONMENT NAME=val    Set environment variable\r\n"
 911       "+SET ENVIRONMENT NAME        Clear environment variable\r\n"
 912 #define HLP_SET_ON      "*Commands SET Command_Status_Trap_Dispatching"
 913       "3Command Status Trap Dispatching\n" //-NLOK
 914       "+SET ON                      Enables error checking command execution\r\n"
 915       "+SET NOON                    Disables error checking command execution\r\n"
 916       "+SET ON INHERIT              Enables inheritance of ON state and actions\r\n"
 917       "+SET ON NOINHERIT            Disables inheritance of ON state and actions\r\n"
 918 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
 919       "3Command Execution Display\n" //-NLOK
 920       "+SET VERIFY                  Enables display of processed script commands\r\n"
 921       "+SET VERBOSE                 Enables display of processed script commands\r\n"
 922       "+SET NOVERIFY                Disables display of processed script commands\r\n"
 923       "+SET NOVERBOSE               Disables display of processed script commands\r\n"
 924 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
 925       "3Command Error Status Display\n" //-NLOK
 926       "+SET MESSAGE                 Re-enables display of script error messages\r\n"
 927       "+SET NOMESSAGE               Disables display of script error messages\r\n"
 928 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
 929       "3Command Output Display\n" //-NLOK
 930       "+SET QUIET                   Disables suppression of some messages\r\n"
 931       "+SET NOQUIET                 Re-enables suppression of some messages\r\n"
 932 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
 933       "3Local Operator Console\n" //-NLOK
 934       "+SET LOCALOPC                Enables local operator console\r\n"
 935       "+SET NOLOCALOPC              Disables local operator console\r\n"
 936 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
 937       "3Command Prompt\n" //-NLOK
 938       "+SET PROMPT \"string\"         Sets an alternate simulator prompt string\r\n"
 939       "3Device and Unit Settings\n" //-NLOK
 940       "+SET <dev> OCT|DEC|HEX       Set device display radix\r\n"
 941       "+SET <dev> ENABLED           Enable device\r\n"
 942       "+SET <dev> DISABLED          Disable device\r\n"
 943       "+SET <dev> DEBUG{=arg}       Set device debug flags\r\n"
 944       "+SET <dev> NODEBUG={arg}     Clear device debug flags\r\n"
 945       "+SET <dev> arg{,arg...}      Set device parameters\r\n"
 946       "+SET <unit> ENABLED          Enable unit\r\n"
 947       "+SET <unit> DISABLED         Disable unit\r\n"
 948       "+SET <unit> arg{,arg...}     Set unit parameters\r\n"
 949       "+HELP <dev> SET              Displays any device specific SET commands\r\n"
 950       " \r\n\r\n"
 951       " See the Omnibus documentation for a complete SET command reference.\r\n"
 952        /***************** 80 character line width template *************************/
 953 #define HLP_SHOW        "*Commands SHOW"
 954       "2SHOW\n" //-NLOK
 955       "+SH{OW} B{UILDINFO}               Show build-time compilation information\r\n"
 956       "+SH{OW} CL{OCKS}                  Show wall clock and timer information\r\n"
 957       "+SH{OW} C{ONFIGURATION}           Show simulator configuration\r\n"
 958       "+SH{OW} D{EFAULT_BASE_SYSTEM}     Show default base system script\r\n"
 959       "+SH{OW} DEV{ICES}                 Show devices\r\n"
 960       "+SH{OW} H{INTS}                   Show configuration hints\r\n"
 961       "+SH{OW} M{ODIFIERS}               Show SET commands for all devices\r\n"
 962       "+SH{OW} O{N}                      Show ON condition actions\r\n"
 963       "+SH{OW} P{ROM}                    Show CPU ID PROM initialization data\r\n"
 964       "+SH{OW} Q{UEUE}                   Show event queue\r\n"
 965       "+SH{OW} S{HOW}                    Show SHOW commands for all devices\r\n"
 966       "+SH{OW} T{IME}                    Show simulated timer\r\n"
 967       "+SH{OW} VE{RSION}                 Show simulator version\r\n"
 968       "+H{ELP} <dev> SHOW                Show device-specific SHOW commands\r\n"
 969       "+SH{OW} <dev> {arg,...}           Show device parameters\r\n"
 970       "+SH{OW} <dev> DEBUG               Show device debug flags\r\n"
 971       "+SH{OW} <dev> MODIFIERS           Show device modifiers\r\n"
 972       "+SH{OW} <dev> RADIX               Show device display radix\r\n"
 973       "+SH{OW} <dev> SHOW                Show device SHOW commands\r\n"
 974       "+SH{OW} <unit> {arg,...}          Show unit parameters\r\n\r\n"
 975       " See the Omnibus documentation for a complete SHOW command reference.\r\n\r\n"
 976 #define HLP_SHOW_CONFIG         "*Commands SHOW"
 977 #define HLP_SHOW_DEVICES        "*Commands SHOW"
 978 #define HLP_SHOW_FEATURES       "*Commands SHOW"
 979 #define HLP_SHOW_QUEUE          "*Commands SHOW"
 980 #define HLP_SHOW_TIME           "*Commands SHOW"
 981 #define HLP_SHOW_MODIFIERS      "*Commands SHOW"
 982 #define HLP_SHOW_NAMES          "*Commands SHOW"
 983 #define HLP_SHOW_SHOW           "*Commands SHOW"
 984 #define HLP_SHOW_VERSION        "*Commands SHOW"
 985 #define HLP_SHOW_BUILDINFO      "*Commands SHOW"
 986 #define HLP_SHOW_PROM           "*Commands SHOW"
 987 #define HLP_SHOW_HINTS          "*Commands SHOW"
 988 #define HLP_SHOW_DBS            "*Commands SHOW"
 989 #define HLP_SHOW_DEFAULT        "*Commands SHOW"
 990 #define HLP_SHOW_CONSOLE        "*Commands SHOW"
 991 #define HLP_SHOW_REMOTE         "*Commands SHOW"
 992 #define HLP_SHOW_BREAK          "*Commands SHOW"
 993 #define HLP_SHOW_LOG            "*Commands SHOW"
 994 #define HLP_SHOW_DEBUG          "*Commands SHOW"
 995 #define HLP_SHOW_CLOCKS         "*Commands SHOW"
 996 #define HLP_SHOW_ON             "*Commands SHOW"
 997 #define HLP_SHOW_SEND           "*Commands SHOW"
 998 #define HLP_SHOW_EXPECT         "*Commands SHOW"
 999 #define HLP_HELP                "*Commands HELP"
1000        /***************** 80 character line width template *************************/
1001       "2HELP\n" //-NLOK
1002       "+H{ELP}                      Show this message\r\n"
1003       "+H{ELP} <command>            Show help for command\r\n"
1004       "+H{ELP} <dev>                Show help for device\r\n"
1005       "+H{ELP} <dev> REGISTERS      Show help for device register variables\r\n"
1006       "+H{ELP} <dev> ATTACH         Show help for device specific ATTACH command\r\n"
1007       "+H{ELP} <dev> SET            Show help for device specific SET commands\r\n"
1008       "+H{ELP} <dev> SHOW           Show help for device specific SHOW commands\r\n"
1009       "+H{ELP} <dev> <command>      Show help for device specific <command> command\r\n"
1010        /***************** 80 character line width template *************************/
1011       "2Altering The Simulated Configuration\n" //-NLOK
1012       " The \"SET <device> DISABLED\" command removes a device from the configuration.\r\n"
1013       " A `DISABLED` device is invisible to running programs.  The device can still\r\n"
1014       " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\r\n\r\n"
1015       " The \"SET <device> ENABLED\" command restores a disabled device to a\r\n"
1016       " configuration.\r\n\r\n"
1017       " Most multi-unit devices allow units to be enabled or disabled:\r\n\r\n"
1018       "++SET <unit> ENABLED\r\n"
1019       "++SET <unit> DISABLED\r\n\r\n"
1020       " When a unit is disabled, it will not be displayed by SHOW DEVICE.\r\n\r\n"
1021        /***************** 80 character line width template *************************/
1022 #define HLP_DO          "*Commands Executing_Command_Files Processing_Command_Files"
1023       "2Executing Command Files\n" //-NLOK
1024       "3Processing Command Files\n" //-NLOK
1025       " The simulator can invoke another script file with the \"`DO`\" command:\r\n\r\n"
1026       "++DO <filename> {arguments...}       execute commands in specified file\r\n\r\n"
1027       " The \"`DO`\" command allows command files to contain substitutable\r\n"
1028       " arguments. The string \"`%%n`\", where \"`n`\" is a number\r\n"
1029       " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\r\n"
1030       " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\r\n"
1031       " The string \"`%%0`\" is replaced with \"<`filename`>\"\r\n"
1032       " The sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\r\n"
1033       " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\r\n"
1034       " be enclosed in matching single or double quotation marks.\r\n\r\n"
1035       " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\r\n"
1036       " deep.\r\n\r\n"
1037       "4Switches\n" //-NLOK
1038       "5`-v`\n\n" //-NLOK
1039       " If the switch \"`-v`\" is specified, commands in the command file are\r\n"
1040       " echoed *before* they are executed.\r\n\r\n"
1041       "5`-e`\n\n" //-NLOK
1042       " If the switch \"`-e`\" is specified, command processing (including nested\r\n"
1043       " command invocations) will be aborted if any command error is encountered.\r\n"
1044       " (A simulation stop **never** aborts processing; use `ASSERT` to catch\r\n"
1045       " unexpected stops.) Without this switch, all errors except `ASSERT` failures\r\n"
1046       " will be ignored, and command processing will continue.\r\n\r\n"
1047       "5`-o`\n\n" //-NLOK
1048       " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\r\n"
1049       " the calling command file will be inherited by the command file being\r\n"
1050       " invoked.\r\n"
1051       "5`-q`\n\n" //-NLOK
1052       " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\r\n"
1053       " enabled for the called command file, otherwise the *quiet mode* setting\r\n"
1054       " is inherited from the calling context.\r\n"
1055        /***************** 80 character line width template *************************/
1056 #define HLP_GOTO        "*Commands Executing_Command_Files GOTO"
1057       "3GOTO\n" //-NLOK
1058       " Commands in a command file execute in sequence until either an error\r\n"
1059       " trap occurs (when a command completes with an error status), or when an\r\n"
1060       " explicit request is made to start command execution elsewhere with\r\n"
1061       " the `GOTO` command:\r\n\r\n"
1062       "++GOTO <label>\r\n\r\n"
1063       " * Labels are lines in a command file which the first non-whitespace\r\n"
1064       " character is a \"`:`\".\r\n"
1065       " * The target of a `GOTO` is the first matching label in the current `DO`\r\n"
1066       " command file which is encountered.\r\n\r\n"
1067       " **Example**\r\n\r\n"
1068       " The following example illustrates usage of the `GOTO` command (by\r\n"
1069       " creating an infinite loop):\r\n\r\n"
1070       "++:Label\r\n"
1071       "++:: This is a loop.\r\n"
1072       "++GOTO Label\r\n\r\n"
1073 #define HLP_RETURN      "*Commands Executing_Command_Files RETURN"
1074        /***************** 80 character line width template *************************/
1075       "3RETURN\n" //-NLOK
1076       " The `RETURN` command causes the current procedure call to be restored to\r\n"
1077       " the calling context, possibly returning a specific return status.\r\n"
1078       " If no return status is specified, the return status from the last command\r\n"
1079       " executed will be returned.  The calling context may have `ON` traps defined\r\n"
1080       " which may redirect command flow in that context.\r\n\r\n"
1081       "++RETURN                 return from command file with last command status\r\n"
1082       "++RETURN {-Q} <status>   return from command file with specific status\r\n\r\n"
1083       " * The status return can be any numeric value or one of the standard SCPE_\r\n"
1084       " condition names.\r\n\r\n"
1085       " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\r\n"
1086       " status to be returned, but normal error status message printing to be\r\n"
1087       " suppressed.\r\n\r\n"
1088       " **Condition Names**\r\n\r\n"
1089       " The available standard SCPE_ condition names and their meanings are:\r\n\r\n"
1090       " | Name    | Meaning                         | Name    | Meaning                             |\r\n"
1091       " | ------- | --------------------------------| ------- | ----------------------------------- |\r\n"
1092       " | NXM     | Address space exceeded          | UNATT   | Unit not attached                   |\r\n"
1093       " | IOERR   | I/O error                       | CSUM    | Checksum error                      |\r\n"
1094       " | FMT     | Format error                    | NOATT   | Unit not attachable                 |\r\n"
1095       " | OPENERR | File open error                 | MEM     | Memory exhausted                    |\r\n"
1096       " | ARG     | Invalid argument                | STEP    | Step expired                        |\r\n"
1097       " | UNK     | Unknown command                 | RO      | Read only argument                  |\r\n"
1098       " | INCOMP  | Command not completed           | STOP    | Simulation stopped                  |\r\n"
1099       " | EXIT    | Goodbye                         | TTIERR  | Console input I/O error             |\r\n"
1100       " | TTOERR  | Console output I/O error        | EOF     | End of file                         |\r\n"
1101       " | REL     | Relocation error                | NOPARAM | No settable parameters              |\r\n"
1102       " | ALATT   | Unit already attached           | TIMER   | Hardware timer error                |\r\n"
1103       " | SIGERR  | Signal handler setup error      | TTYERR  | Console terminal setup error        |\r\n"
1104       " | NOFNC   | Command not allowed             | UDIS    | Unit disabled                       |\r\n"
1105       " | NORO    | Read only operation not allowed | INVSW   | Invalid switch                      |\r\n"
1106       " | MISVAL  | Missing value                   | 2FARG   | Too few arguments                   |\r\n"
1107       " | 2MARG   | Too many arguments              | NXDEV   | Non-existent device                 |\r\n"
1108       " | NXUN    | Non-existent unit               | NXREG   | Non-existent register               |\r\n"
1109       " | NXPAR   | Non-existent parameter          | NEST    | Nested DO command limit exceeded    |\r\n"
1110       " | IERR    | Internal error                  | MTRLNT  | Invalid magtape record length       |\r\n"
1111       " | LOST    | Console Telnet connection lost  | TTMO    | Console Telnet connection timed out |\r\n"
1112       " | STALL   | Console Telnet output stall     | AFAIL   | Assertion failed                    |\r\n"
1113       " | INVREM  | Invalid remote console command  |         |                                     |\r\n"
1114       "\r\n\r\n"
1115 #define HLP_SHIFT       "*Commands Executing_Command_Files Shift_Parameters"
1116       "3Shift Parameters\n" //-NLOK
1117       " Shift the command files positional parameters\r\n"
1118 #define HLP_CALL        "*Commands Executing_Command_Files Call_a_subroutine"
1119       "3Call a subroutine\n" //-NLOK
1120       " Control can be transferred to a labeled subroutine using `CALL`.\r\n\r\n"
1121       " **Example**\r\n\r\n"
1122       "++CALL routine\r\n"
1123       "++BYE\r\n"
1124       "++\r\n"
1125       "++:routine\r\n"
1126       "++ECHO routine called\r\n"
1127       "++RETURN\r\n\r\n"
1128 #define HLP_ON          "*Commands Executing_Command_Files ON"
1129       "3ON\n" //-NLOK
1130       " The `ON` command performs actions after a condition, or clears a condition.\r\n"
1131       "++ON <condition> <action>  Perform action after condition\r\n"
1132       "++ON <condition>           Clears action of specified condition\r\n"
1133 #define HLP_PROCEED     "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1134 #define HLP_IGNORE      "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1135        /***************** 80 character line width template *************************/
1136       "3PROCEED or IGNORE\n" //-NLOK
1137       " The `PROCEED` (or `IGNORE`) command does nothing.  It is potentially\r\n"
1138       " useful as a placeholder for any `ON` action condition that should be\r\n"
1139       " explicitly ignored, allowing command file execution to continue without\r\n"
1140       " taking any specific action.\r\n"
1141 #define HLP_ECHO        "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1142        /***************** 80 character line width template *************************/
1143       "3Displaying Arbitrary Text\n" //-NLOK
1144       " The `ECHO` command is a useful way of annotating command files.  `ECHO`\r\n"
1145       " prints out its arguments to the console (and to any applicable log file):\r\n\r\n"
1146       "++ECHO <string>      Output string to console\r\n\r\n"
1147       " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\r\n"
1148       " This may be used to provide spacing for console messages or log file\r\n"
1149       " output.\r\n"
1150        /***************** 80 character line width template *************************/
1151 #define HLP_ASSERT      "*Commands Executing_Command_Files Testing_Assertions"
1152       "3Testing Assertions\n" //-NLOK
1153       " The `ASSERT` command tests a simulator state condition and halts command\r\n"
1154       " file execution if the condition is false:\r\n\r\n"
1155       "++ASSERT <Simulator State Expressions>\r\n\r\n"
1156       " * If the indicated expression evaluates to false, the command completes\r\n"
1157       " with an `AFAIL` condition.  By default, when a command file encounters a\r\n"
1158       " command which returns the `AFAIL` condition, it will exit the running\r\n"
1159       " command file with the `AFAIL` status to the calling command file.  This\r\n"
1160       " behavior can be changed with the `ON` command as well as switches to the\r\n"
1161       " invoking `DO` command.\r\n\r\n"
1162       " **Examples**\r\n\r\n"
1163       " The command file below might be used to bootstrap a hypothetical system\r\n"
1164       " that halts after the initial load from disk. The `ASSERT` command can then\r\n"
1165       " be used to confirm that the load completed successfully by examining the\r\n"
1166       " CPU's \"`A`\" register for the expected value:`\r\n\r\n"
1167       "++; Example INI file\r\n"
1168       "++BOOT\r\n"
1169       "++; A register contains error code; 0 = good boot\r\n"
1170       "++ASSERT A=0\r\n"
1171       "++RUN\r\n\r\n"
1172        /***************** 80 character line width template *************************/
1173       " * In the above example, if the \"`A`\" register is *not* `0`,\r\n"
1174       " the \"`ASSERT A=0`\" command will be displayed to the user, and the\r\n"
1175       " command file will be aborted with an \"`Assertion failed`\" message.\r\n"
1176       " Otherwise, the command file will continue to bring up the system.\r\n\r\n"
1177       " * See the **`IF`** command documentation for more information and details\r\n"
1178       " regarding simulator state expressions.\r\n\r\n"
1179 #define HLP_IF          "*Commands Executing_Command_Files Testing_Conditions"
1180       "3Testing Conditions\n" //-NLOK
1181       " The `IF` command tests a simulator state condition and executes additional\r\n"
1182       " commands if the condition is true:\r\n\r\n"
1183       "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\r\n\r\n"
1184       " **Examples**\r\n\r\n"
1185       " The command file below might be used to bootstrap a hypothetical system\r\n"
1186       " that halts after the initial load from disk. The `IF` command can then\r\n"
1187       " be used to confirm that the load completed successfully by examining the\r\n"
1188       " CPU's \"`A`\" register for an expected value:\r\n\r\n"
1189       "++; Example INI file\r\n"
1190       "++BOOT\r\n"
1191       "++; A register contains error code; 0 = good boot\r\n"
1192       "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\r\n"
1193       "++RUN\r\n\r\n"
1194        /***************** 80 character line width template *************************/
1195       " * In the above example, if the \"`A`\" register is *not* `0`, the\r\n"
1196       " message \"`Boot failed - Failure Code `\" will be displayed, the contents\r\n"
1197       " of the \"`A`\" register will be displayed, and the command file will be\r\n"
1198       " aborted with an \"`Assertion failed`\" message.  Otherwise, the command\r\n"
1199       " file will continue to bring up the system.\r\n"
1200       "4Conditional Expressions\n" //-NLOK
1201       " The `IF` and `ASSERT` commands evaluate the following two different forms\r\n"
1202       " of conditional expressions.\r\n\r\n"
1203       "5Simulator State Expressions\n" //-NLOK
1204       "  &nbsp;\r\n \r\n"
1205       " The values of simulator registers can be evaluated with:\r\n\r\n"
1206       "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\r\n\r\n"
1207       " * If \"<`dev`>\" is not specified, `CPU` is assumed.  \"<`reg`>\" is a\r\n"
1208       " register belonging to the indicated device.\r\n"
1209       " * The \"<`addr`>\" is an address in the address space of the indicated\r\n"
1210       " device.\r\n"
1211       " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\r\n"
1212       " the same as those used for \"search specifiers\" by the `EXAMINE` and\r\n"
1213       " `DEPOSIT` commands.\r\n"
1214       " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\r\n"
1215       " not in the radix for the device when referencing a register; when an\r\n"
1216       " address is referenced the device radix is used as the default.\r\n\r\n"
1217       " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\r\n"
1218       " register value is first altered as indicated.  The result is then compared\r\n"
1219       " to the \"<`value`>\" via the \"<`conditional-op`>\".\r\n"
1220       " * * If the result is *true*, the command(s) are executed before proceeding\r\n"
1221       " to the next line in the command file.\r\n"
1222       " * * If the result is *false*, the next command in the command file is\r\n"
1223       " processed.\r\n\r\n"
1224       "5String Comparison Expressions\n" //-NLOK
1225       "  &nbsp;\r\n \r\n"
1226       " String Values can be compared with:\r\n\r\n"
1227       "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\r\n\r\n"
1228       " * The \"`-i`\" switch, if present, causes a comparison to be case\r\n"
1229       "   insensitive.\r\n"
1230       " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\r\n"
1231       "   values which may have environment variables substituted as desired.\r\n"
1232       " * The \"<`compare-op`>\" may be one of:\r\n\r\n"
1233       " |                |                        |\r\n"
1234       " | --------------:|:---------------------- |\r\n"
1235       " | \"**`==`**\"     |  equal                 |\r\n"
1236       " | \"**`EQU`**\"    |  equal                 |\r\n"
1237       " | \"**`!=`**\"     |  not equal             |\r\n"
1238       " | \"**`NEQ`**\"    |  not equal             |\r\n"
1239       " | \"**<**\"        |  less than             |\r\n"
1240       " | \"**`LSS`**\"    |  less than             |\r\n"
1241       " | \"**<=**\"       |  less than or equal    |\r\n"
1242       " | \"**`LEQ`**\"    |  less than or equal    |\r\n"
1243       " | \"**>**\"        |  greater than          |\r\n"
1244       " | \"**`GTR`**\"    |  greater than          |\r\n"
1245       " | \"**>=**\"       |  greater than or equal |\r\n"
1246       " | \"**`GEQ`**\"    |  greater than or equal |\r\n"
1247       " * **NOTE**: Comparisons are *generic*.  This means that if\r\n"
1248       " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\r\n"
1249       " digits, then the strings are converted to numbers and a numeric\r\n"
1250       " comparison is performed.  For example, the comparison\r\n"
1251       " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\r\n"
1252        /***************** 80 character line width template *************************/
1253 #define HLP_EXIT        "*Commands Exiting_the_Simulator"
1254       "2Exiting the Simulator\n" //-NLOK
1255       " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\r\n"
1256       " returning control to the host operating system.\r\n"
1257        /***************** 80 character line width template *************************/
1258 #define HLP_SPAWN       "*Commands Executing_System_Commands"
1259       "2Executing System Commands\n" //-NLOK
1260       " * The simulator can execute host operating system commands with\r\n"
1261       " the \"`!`\" (*spawn*) command.\r\n\r\n"
1262       " |                         |                                             |\r\n"
1263       " |:----------------------- |:------------------------------------------- |\r\n"
1264       " | \"**`!`**\"             | Spawn the hosts default command interpreter |\r\n"
1265       " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\r\n\r\n"
1266       " * **NOTE**: The *exit status* from the command which was executed is set\r\n"
1267       " as the *command completion status* for the \"`!`\" command.  This may\r\n"
1268       " influence any enabled `ON` condition traps.\r\n" ;
1269        /***************** 80 character line width template *************************/
1270 
1271 static CTAB cmd_table[] = {
1272     { "RESET",    &reset_cmd,  0,         HLP_RESET     },
1273     { "EXAMINE",  &exdep_cmd,  EX_E,      HLP_EXAMINE   },
1274     { "IEXAMINE", &exdep_cmd,  EX_E+EX_I, HLP_IEXAMINE  },
1275     { "DEPOSIT",  &exdep_cmd,  EX_D,      HLP_DEPOSIT   },
1276     { "IDEPOSIT", &exdep_cmd,  EX_D+EX_I, HLP_IDEPOSIT  },
1277     { "EVALUATE", &eval_cmd,   0,         HLP_EVALUATE  },
1278     { "RUN",      &run_cmd,    RU_RUN,    HLP_RUN,      NULL, &run_cmd_message },
1279     { "GO",       &run_cmd,    RU_GO,     HLP_GO,       NULL, &run_cmd_message },
1280     { "STEP",     &run_cmd,    RU_STEP,   HLP_STEP,     NULL, &run_cmd_message },
1281     { "NEXT",     &run_cmd,    RU_NEXT,   HLP_NEXT,     NULL, &run_cmd_message },
1282     { "CONTINUE", &run_cmd,    RU_CONT,   HLP_CONTINUE, NULL, &run_cmd_message },
1283     { "BOOT",     &run_cmd,    RU_BOOT,   HLP_BOOT,     NULL, &run_cmd_message },
1284     { "BREAK",    &brk_cmd,    SSH_ST,    HLP_BREAK     },
1285     { "NOBREAK",  &brk_cmd,    SSH_CL,    HLP_NOBREAK   },
1286     { "ATTACH",   &attach_cmd, 0,         HLP_ATTACH    },
1287     { "DETACH",   &detach_cmd, 0,         HLP_DETACH    },
1288     { "EXIT",     &exit_cmd,   0,         HLP_EXIT      },
1289     { "QUIT",     &exit_cmd,   0,         NULL          },
1290     { "BYE",      &exit_cmd,   0,         NULL          },
1291     { "SET",      &set_cmd,    0,         HLP_SET       },
1292     { "SHOW",     &show_cmd,   0,         HLP_SHOW      },
1293     { "DO",       &do_cmd,     1,         HLP_DO        },
1294     { "GOTO",     &goto_cmd,   1,         HLP_GOTO      },
1295     { "RETURN",   &return_cmd, 0,         HLP_RETURN    },
1296     { "SHIFT",    &shift_cmd,  0,         HLP_SHIFT     },
1297     { "CALL",     &call_cmd,   0,         HLP_CALL      },
1298     { "ON",       &on_cmd,     0,         HLP_ON        },
1299     { "IF",       &assert_cmd, 0,         HLP_IF        },
1300     { "PROCEED",  &noop_cmd,   0,         HLP_PROCEED   },
1301     { "IGNORE",   &noop_cmd,   0,         HLP_IGNORE    },
1302     { "ECHO",     &echo_cmd,   0,         HLP_ECHO      },
1303     { "ASSERT",   &assert_cmd, 1,         HLP_ASSERT    },
1304     { "SEND",     &send_cmd,   0          },            /* deprecated */
1305     { "EXPECT",   &expect_cmd, 1          },            /* deprecated */
1306     { "NOEXPECT", &expect_cmd, 0          },            /* deprecated */
1307     { "!",        &spawn_cmd,  0,         HLP_SPAWN     },
1308     { "HELP",     &help_cmd,   0,         HLP_HELP      },
1309     { NULL,       NULL,        0          }
1310     };
1311 
1312 static CTAB set_glob_tab[] = {
1313     { "CONSOLE",     &sim_set_console,        0      }, /* deprecated */
1314     { "REMOTE",      &sim_set_remote_console, 0      }, /* deprecated */
1315     { "BREAK",       &brk_cmd,                SSH_ST }, /* deprecated */
1316     { "NOBREAK",     &brk_cmd,                SSH_CL }, /* deprecated */
1317     { "TELNET",      &sim_set_telnet,         0      }, /* deprecated */
1318     { "NOTELNET",    &sim_set_notelnet,       0      }, /* deprecated */
1319     { "LOG",         &sim_set_logon,          0,     HLP_SET_LOG      },
1320     { "NOLOG",       &sim_set_logoff,         0,     HLP_SET_LOG      },
1321     { "DEBUG",       &sim_set_debon,          0,     HLP_SET_DEBUG    },
1322     { "NODEBUG",     &sim_set_deboff,         0,     HLP_SET_DEBUG    },
1323     { "ENVIRONMENT", &sim_set_environment,    1,     HLP_SET_ENVIRON  },
1324     { "ON",          &set_on,                 1,     HLP_SET_ON       },
1325     { "NOON",        &set_on,                 0,     HLP_SET_ON       },
1326     { "VERIFY",      &set_verify,             1,     HLP_SET_VERIFY   },
1327     { "VERBOSE",     &set_verify,             1,     HLP_SET_VERIFY   },
1328     { "NOVERIFY",    &set_verify,             0,     HLP_SET_VERIFY   },
1329     { "NOVERBOSE",   &set_verify,             0,     HLP_SET_VERIFY   },
1330     { "MESSAGE",     &set_message,            1,     HLP_SET_MESSAGE  },
1331     { "NOMESSAGE",   &set_message,            0,     HLP_SET_MESSAGE  },
1332     { "QUIET",       &set_quiet,              1,     HLP_SET_QUIET    },
1333     { "NOQUIET",     &set_quiet,              0,     HLP_SET_QUIET    },
1334     { "LOCALOPC",    &set_localopc,           1,     HLP_SET_LOCALOPC },
1335     { "NOLOCALOPC",  &set_localopc,           0,     HLP_SET_LOCALOPC },
1336     { "PROMPT",      &set_prompt,             0,     HLP_SET_PROMPT   },
1337     { NULL,          NULL,                    0      }
1338     };
1339 
1340 static C1TAB set_dev_tab[] = {
1341     { "OCTAL",    &set_dev_radix,   8  },
1342     { "DECIMAL",  &set_dev_radix,  10  },
1343     { "HEX",      &set_dev_radix,  16  },
1344     { "ENABLED",  &set_dev_enbdis,  1  },
1345     { "DISABLED", &set_dev_enbdis,  0  },
1346     { "DEBUG",    &set_dev_debug,   1  },
1347     { "NODEBUG",  &set_dev_debug,   0  },
1348     { NULL,       NULL,             0  }
1349     };
1350 
1351 static C1TAB set_unit_tab[] = {
1352     { "ENABLED",  &set_unit_enbdis, 1 },
1353     { "DISABLED", &set_unit_enbdis, 0 },
1354     { NULL,       NULL,             0 }
1355     };
1356 
1357 static SHTAB show_glob_tab[] = {
1358     { "CONFIGURATION",  &show_config,        0, HLP_SHOW_CONFIG    },
1359     { "DEFAULT_BASE_SYSTEM_SCRIPT",
1360            &show_default_base_system_script, 0, HLP_SHOW_DBS       },
1361     { "DEVICES",   &show_config,             1, HLP_SHOW_DEVICES   },
1362     { "FEATURES",  &show_config,             2, HLP_SHOW_FEATURES  },
1363     { "QUEUE",     &show_queue,              0, HLP_SHOW_QUEUE     },
1364     { "TIME",      &show_time,               0, HLP_SHOW_TIME      },
1365     { "MODIFIERS", &show_mod_names,          0, HLP_SHOW_MODIFIERS },
1366     { "NAMES",     &show_log_names,          0, HLP_SHOW_NAMES     },
1367     { "SHOW",      &show_show_commands,      0, HLP_SHOW_SHOW      },
1368     { "VERSION",   &show_version,            1, HLP_SHOW_VERSION   },
1369     { "BUILDINFO", &show_buildinfo,          1, HLP_SHOW_BUILDINFO },
1370     { "PROM",      &show_prom,               0, HLP_SHOW_PROM      },
1371     { "HINTS",     &show_hints,              0, HLP_SHOW_HINTS     },
1372     { "CONSOLE",   &sim_show_console,        0, HLP_SHOW_CONSOLE   },
1373     { "REMOTE",    &sim_show_remote_console, 0, HLP_SHOW_REMOTE    },
1374     { "BREAK",     &show_break,              0, HLP_SHOW_BREAK     },
1375     { "LOG",       &sim_show_log,            0, HLP_SHOW_LOG       },
1376     { "TELNET",    &sim_show_telnet,         0  },  /* deprecated */
1377     { "DEBUG",     &sim_show_debug,          0, HLP_SHOW_DEBUG     },
1378     { "CLOCKS",    &sim_show_timers,         0, HLP_SHOW_CLOCKS    },
1379     { "SEND",      &sim_show_send,           0, HLP_SHOW_SEND      },
1380     { "EXPECT",    &sim_show_expect,         0, HLP_SHOW_EXPECT    },
1381     { "ON",        &show_on,                 0, HLP_SHOW_ON        },
1382     { NULL,        NULL,                     0  }
1383     };
1384 
1385 static SHTAB show_dev_tab[] = {
1386     { "RADIX",     &show_dev_radix,         0 },
1387     { "DEBUG",     &show_dev_debug,         0 },
1388     { "MODIFIERS", &show_dev_modifiers,     0 },
1389     { "NAMES",     &show_dev_logicals,      0 },
1390     { "SHOW",      &show_dev_show_commands, 0 },
1391     { NULL,        NULL,                    0 }
1392     };
1393 
1394 static SHTAB show_unit_tab[] = {
1395     { NULL, NULL, 0 }
1396     };
1397 
1398 #if defined(_WIN32)
1399 static
1400 int setenv(const char *envname, const char *envval, int overwrite)
     /* [previous][next][first][last][top][bottom][index][help] */
1401 {
1402 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1403 int r;
1404 
1405 (void)sprintf(envstr, "%s=%s", envname, envval);
1406 r = _putenv(envstr);
1407 FREE(envstr);
1408 return r;
1409 }
1410 
1411 static
1412 int unsetenv(const char *envname)
     /* [previous][next][first][last][top][bottom][index][help] */
1413 {
1414 setenv(envname, "", 1);
1415 return 0;
1416 }
1417 #endif /* if defined(_WIN32) */
1418 
1419 #if !defined(NO_LOCALE)
1420 # define XSTR_EMAXLEN 32767
1421 
1422 const char
1423 *xstrerror_l(int errnum)
     /* [previous][next][first][last][top][bottom][index][help] */
1424 {
1425   int saved = errno;
1426   const char *ret = NULL;
1427   static __thread char buf[XSTR_EMAXLEN];
1428 
1429 # if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1430      defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1431 #  if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1432   if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1433 #  else
1434   if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1435 #  endif
1436 # else
1437 #  if defined(__NetBSD__)
1438   locale_t loc = LC_GLOBAL_LOCALE;
1439 #  else
1440   locale_t loc = uselocale((locale_t)0);
1441 #  endif
1442   locale_t copy = loc;
1443   if (copy == LC_GLOBAL_LOCALE)
1444     copy = duplocale(copy);
1445 
1446   if (copy != (locale_t)0)
1447     {
1448       ret = strerror_l(errnum, copy); /*LINTOK: xstrerror_l*/
1449       if (loc == LC_GLOBAL_LOCALE)
1450         {
1451           freelocale(copy);
1452         }
1453     }
1454 # endif
1455 
1456   if (!ret)
1457     {
1458       (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1459       ret = buf;
1460     }
1461 
1462   errno = saved;
1463   return ret;
1464 }
1465 #else
1466 # define xstrerror_l strerror
1467 #endif
1468 
1469 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1470 
1471 /* Substring removal hack */
1472 
1473 char *strremove(char *str, const char *sub)
     /* [previous][next][first][last][top][bottom][index][help] */
1474 {
1475     char *p, *q, *r;
1476     if (*sub && (q = r = strstr(str, sub)) != NULL) {
1477         size_t len = strlen(sub);
1478         while ((r = strstr(p = r + len, sub)) != NULL) {
1479             while (p < r)
1480                 *q++ = *p++;
1481         }
1482         while ((*q++ = *p++) != '\0')
1483             continue;
1484     }
1485     return str;
1486 }
1487 
1488 /* Trim whitespace */
1489 
1490 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
     /* [previous][next][first][last][top][bottom][index][help] */
1491 {
1492     while (*str_untrimmed != '\0') {
1493       if(!isspace((unsigned char)*str_untrimmed)) {
1494         *str_trimmed = (char)*str_untrimmed;
1495         str_trimmed++;
1496       }
1497       str_untrimmed++;
1498     }
1499     *str_trimmed = '\0';
1500 }
1501 
1502 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1503 void allowCores(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1504 {
1505   int ret;
1506   struct rlimit limit;
1507 # if defined(RLIMIT_CORE)
1508   ret = getrlimit(RLIMIT_CORE, &limit);
1509   (void)ret;
1510 #  if defined(TESTING)
1511   if (ret != 0)
1512     {
1513       sim_warn ("Failed to query core dump configuration.");
1514       return;
1515     }
1516 #  endif /* if defined(TESTING) */
1517   limit.rlim_cur = limit.rlim_max;
1518   ret = setrlimit(RLIMIT_CORE, &limit);
1519 #  if defined(TESTING)
1520   if (ret != 0)
1521     {
1522       sim_warn ("Failed to enable unlimited core dumps.");
1523       return;
1524     }
1525 #  endif /* if defined(TESTING) */
1526 # else
1527 #  if defined(TESTING)
1528   sim_warn ("Unable to query core dump configuration.");
1529 #  endif /* if defined(TESTING) */
1530 # endif /* if defined(RLIMIT_CORE) */
1531   return;
1532 }
1533 #endif
1534 
1535 #if defined(USE_DUMA)
1536 void CleanDUMA(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1537 {
1538   (void)fflush(stdout);
1539   DUMA_CHECKALL();
1540   (void)fflush(stderr);
1541 }
1542 # undef USE_DUMA
1543 # define USE_DUMA 1
1544 #endif /* if defined(USE_DUMA) */
1545 
1546 #if !defined(SIG_SETMASK)
1547 # undef USE_BACKTRACE
1548 #endif /* if !defined(SIG_SETMASK) */
1549 
1550 #if defined(PERF_STRIP)
1551 # undef USE_BACKTRACE
1552 #endif /* if defined(PERF_STRIP) */
1553 
1554 #if defined(USE_BACKTRACE)
1555 # include <backtrace.h>
1556 # include <backtrace-supported.h>
1557 # define BACKTRACE_SKIP 1
1558 # define BACKTRACE_MAIN "main"
1559 # undef USE_BACKTRACE
1560 # define USE_BACKTRACE 1
1561 #endif /* if defined(USE_BACKTRACE) */
1562 
1563 #if defined(BACKTRACE_SUPPORTED)
1564 # if defined(BACKTRACE_SUPPORTS_THREADS)
1565 #  if !(BACKTRACE_SUPPORTED)
1566 #   undef USE_BACKTRACE
1567 #  endif /* if !(BACKTRACE_SUPPORTED) */
1568 # else  /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1569 #  undef USE_BACKTRACE
1570 # endif /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1571 #else  /* if defined(BACKTRACE_SUPPORTED) */
1572 # undef USE_BACKTRACE
1573 #endif /* if defined(BACKTRACE_SUPPORTED) */
1574 
1575 #if defined(USE_BACKTRACE)
1576 # if defined(BACKTRACE_SUPPORTED)
1577 #  include "backtrace_func.c"
1578 # endif /* if defined(BACKTRACE_SUPPORTED) */
1579 #endif /* if defined(USE_BACKTRACE) */
1580 
1581 #if !defined(__CYGWIN__)
1582 # if !defined(__APPLE__)
1583 #  if !defined(_AIX)
1584 #   if !defined(__MINGW32__)
1585 #    if !defined(__MINGW64__)
1586 #     if !defined(CROSS_MINGW32)
1587 #      if !defined(CROSS_MINGW64)
1588 #       if !defined(_WIN32)
1589 #        if !defined(__HAIKU__)
1590 #         if !defined(__QNX__)
1591 #          if !defined(__FILC__)
1592 static int
1593 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1594 {
1595   (void)size;
1596   (void)data;
1597 
1598   if (strlen(info->dlpi_name) >= 2) {
1599       if (!dl_iterate_phdr_callback_called)
1600           (void)printf ("\r\n Loaded shared objects: ");
1601 
1602       dl_iterate_phdr_callback_called++;
1603       (void)printf ("%s ", info->dlpi_name);
1604   }
1605 
1606   return 0;
1607 }
1608 #          endif
1609 #         endif
1610 #        endif
1611 #       endif
1612 #      endif
1613 #     endif
1614 #    endif
1615 #   endif
1616 #  endif
1617 # endif
1618 #endif
1619 
1620 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1621 # if defined(_UCRT)
1622 #  define MINGW_CRT "UCRT"
1623 # else
1624 #  define MINGW_CRT "MSVCRT"
1625 # endif
1626 #endif
1627 
1628 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1629 struct UCRTVersion
1630 {
1631   uint16_t ProductVersion[4];
1632 };
1633 
1634 int
1635 GetUCRTVersion (struct UCRTVersion *ucrtversion)
     /* [previous][next][first][last][top][bottom][index][help] */
1636 {
1637 # ifdef _DEBUG
1638   static const wchar_t *DllName = L"ucrtbased.dll";
1639 # else
1640   static const wchar_t *DllName = L"ucrtbase.dll";
1641 # endif
1642 
1643   HMODULE ucrt = GetModuleHandleW (DllName);
1644   if (!ucrt)
1645     return GetLastError ();
1646 
1647   wchar_t path[SIR_MAXPATH];
1648   if (!GetModuleFileNameW (ucrt, path, SIR_MAXPATH))
1649     return GetLastError ();
1650 
1651   DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1652   if (!versionInfoSize)
1653     return GetLastError ();
1654 
1655   uint8_t versionInfo[versionInfoSize];
1656 
1657   if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1658     return GetLastError ();
1659 
1660   VS_FIXEDFILEINFO *fixedFileInfo;
1661   UINT fixedFileInfoSize;
1662   if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1663     return GetLastError ();
1664 
1665   memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1666 
1667   return 0;
1668 }
1669 #endif
1670 
1671 /* libsir support */
1672 
1673 #if !defined(PERF_STRIP)
1674 static int dps8_sir_report_error(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1675 {
1676   char message[SIR_MAXERROR] = {0};
1677   (void)sir_geterror(message);
1678   (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1679   return EXIT_FAILURE;
1680 }
1681 
1682 /* Main command loop */
1683 
1684 int main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
1685 {
1686 char *cptr, *cptr2;
1687 char nbuf[PATH_MAX + 7];
1688 char cbuf[4*CBUFSIZE];
1689 char **targv = NULL;
1690 int32 i, sw;
1691 t_bool lookswitch;
1692 t_stat stat;
1693 
1694 /* Check for improper setuid root */
1695 # if !defined(__sun) && !defined(__illumos__) && !defined(_WIN32)
1696 uid_t real_uid = getuid();
1697 uid_t eff_uid = geteuid();
1698 if (0 == eff_uid && 0 != real_uid) {
1699   (void)fprintf(stderr, "FATAL: Running with improper setuid root privileges!\r\n");
1700   exit(EXIT_FAILURE);
1701 }
1702 # endif
1703 
1704 sunos_obtain_realtime_privileges(); /* Keep as early as possible */
1705 
1706 sim_free_memory = sim_memory_available(); /* stash free memory */
1707 
1708 sim_appfilename = _sir_getappfilename(); /* stash app filename */
1709 if (sim_appfilename == NULL) {
1710   sim_appfilename = "dps8";
1711 }
1712 
1713 /* libsir init */
1714 
1715 sirinit si;
1716 if (!sir_makeinit(&si))
1717     return dps8_sir_report_error();
1718 
1719 /* Levels for stdout: send debug, information, warning, and notice there. */
1720 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1721 
1722 /* Options for stdout: don't show the name, level, timestamp, hostname, or PID. */
1723 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1724 
1725 /* Levels for stderr: send error and above there. */
1726 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1727 
1728 /* Options for stderr: don't show the hostname. */
1729 si.d_stderr.opts = SIRO_NOHOST;
1730 
1731 /* Levels for the system logger: don't send any output there. */
1732 si.d_syslog.levels = SIRL_NONE;
1733 
1734 /* Options for the system logger: use the default value. */
1735 si.d_syslog.opts = SIRO_DEFAULT;
1736 
1737 /* Configure a name to associate with our output. */
1738 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1739 
1740 /* Initialize libsir. */
1741 if (!sir_init(&si))
1742     return dps8_sir_report_error();
1743 
1744 # if defined(_AIX)
1745 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1746   if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1747     (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1748                   __func__, __FILE__, __LINE__);
1749     abort();
1750   }
1751 
1752   if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1753     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1754   }
1755 
1756   if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1757     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1758   }
1759 
1760   if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1761     (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1762   }
1763 
1764 #  if !defined(__PASE__)
1765   if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1766     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1767   }
1768 #  else
1769 #   if !defined(TESTING)
1770   if (setenv("PASE_SYSCALL_NOSIGILL", "ALL", 1)) {
1771     (void)fprintf(stderr, "\rWARN: Failed to set \"PASE_SYSCALL_NOSIGILL=ALL\".\r\n");
1772   }
1773 #   endif
1774 #  endif
1775 
1776   if (execvp(argv[0], argv) == -1) {
1777     (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1778                   __func__, __FILE__, __LINE__);
1779     abort();
1780   }
1781 }
1782 # endif
1783 
1784 # if defined(USE_BACKTRACE)
1785 #  if defined(BACKTRACE_SUPPORTED)
1786 #   if defined(_INC_BACKTRACE_FUNC)
1787 bt_pid = (long)_sir_getpid();
1788 (void)bt_pid;
1789 #   endif /* if defined(_INC_BACKTRACE_FUNC) */
1790 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1791 # endif /* if defined(USE_BACKTRACE) */
1792 
1793 # if defined(__MINGW32__)
1794 #  undef IS_WINDOWS
1795 #  define IS_WINDOWS 1
1796 #  if !defined(NEED_CONSOLE_SETUP)
1797 #   define NEED_CONSOLE_SETUP
1798 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1799 # endif /* if defined(__MINGW32__)*/
1800 
1801 # if defined(CROSS_MINGW32)
1802 #  undef IS_WINDOWS
1803 #  define IS_WINDOWS 1
1804 #  if !defined(NEED_CONSOLE_SETUP)
1805 #   define NEED_CONSOLE_SETUP
1806 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1807 # endif /* if defined(CROSS_MINGW32) */
1808 
1809 # if defined(__MINGW64__)
1810 #  undef IS_WINDOWS
1811 #  define IS_WINDOWS 1
1812 #  if !defined(NEED_CONSOLE_SETUP)
1813 #   define NEED_CONSOLE_SETUP
1814 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1815 # endif /* if defined(__MINGW64__) */
1816 
1817 # if defined(CROSS_MINGW64)
1818 #  undef IS_WINDOWS
1819 #  define IS_WINDOWS 1
1820 #  if !defined(NEED_CONSOLE_SETUP)
1821 #   define NEED_CONSOLE_SETUP
1822 #  endif /* if !defined(NEED_CONSOLE_SETUP */
1823 # endif /* if defined(CROSS_MINGW64) */
1824 
1825 # if defined(__CYGWIN__)
1826 #  if defined(IS_WINDOWS)
1827 #   undef IS_WINDOWS
1828 #  endif /* if defined(IS_WINDOWS) */
1829 # endif /* if defined(__CYGWIN__) */
1830 
1831 # if defined(USE_DUMA)
1832 #  if defined(DUMA_EXPLICIT_INIT)
1833 duma_init();
1834 (void)fflush(stderr);
1835 #  endif /* if defined(DUMA_EXPLICIT_INIT) */
1836 #  if defined(DUMA_MIN_ALIGNMENT)
1837 #   if DUMA_MIN_ALIGNMENT > 0
1838 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1839 #   endif /* if DUMA_MIN_ALIGNMENT > 0 */
1840 #  endif /* if defined(DUMA_MIN_ALIGNMENT) */
1841 DUMA_SET_FILL(0x2E);
1842 (void)fflush(stderr);
1843 (void)atexit(CleanDUMA);
1844 # endif /* if defined(USE_DUMA) */
1845 
1846 # if defined(USE_BACKTRACE)
1847 #  if defined(BACKTRACE_SUPPORTED)
1848 #   include "backtrace_main.c"
1849 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1850 # endif /* if defined(USE_BACKTRACE) */
1851 
1852 # if !defined(NO_LOCALE)
1853 (void)setlocale(LC_ALL, "");
1854 # endif
1855 
1856 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1857 #  if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1858 #   define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1859 #  endif /* if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) */
1860 # endif /* if defined(NEED_CONSOLE_SETUP) && defined(_WIN32) */
1861 
1862 # if defined(NEED_CONSOLE_SETUP)
1863 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1864 if (handle != INVALID_HANDLE_VALUE)
1865   {
1866     DWORD mode = 0;
1867     if (GetConsoleMode(handle, &mode))
1868       {
1869         mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1870         SetConsoleMode(handle, mode);
1871       }
1872   }
1873 puts ("\e[0m");
1874 # endif /* if defined(NEED_CONSOLE_SETUP) */
1875 
1876 # if defined(__HAIKU__)
1877 (void)disable_debugger(1);
1878 # endif /* if defined(__HAIKU__) */
1879 
1880 running_perf_test = false;
1881 
1882 /* Set a friendly name for the current thread. */
1883 char thread_name[SIR_MAXPID] = {0};
1884 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1885 (void)_sir_setthreadname(thread_name);
1886 
1887 /* sanity checks */
1888 
1889 # if defined(__clang_analyzer__)
1890 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\r\n");
1891 return 1;
1892 # endif /* if defined(__clang_analyzer__) */
1893 
1894 if (argc == 0) {
1895     (void)fprintf (stderr, "Error: main() called directly!\r\n");
1896     return 1;
1897 }
1898 
1899 /* Enable unlimited core dumps */
1900 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1901 allowCores();
1902 # endif
1903 
1904 int testEndian = decContextTestEndian();
1905 if (testEndian != 0) {
1906   if (testEndian == 1) {
1907     (void)fprintf (stderr,
1908                    "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\r\n");
1909     return 1;
1910   }
1911   if (testEndian == -1) {
1912     (void)fprintf (stderr,
1913                    "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\r\n");
1914     return 1;
1915   }
1916   (void)fprintf (stderr,
1917                  "Error: Unable to determine system byte order; aborting.\r\n");
1918   return 1;
1919 }
1920 # if defined(NEED_128)
1921 test_math128();
1922 # endif /* if defined(NEED_128) */
1923 
1924 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1925 
1926 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1927 // Only use uv_available_parallelism on Linux and only on libuv 1.44.0 or higher.
1928 // This will return a value less than the actual number of CPUs if, for example,
1929 // the CPU affinity mask has been pinned to specific CPUs.  On all other systems,
1930 // prefer the _sir_nprocs routine to query the number of actual CPUs available.
1931 nprocs = (unsigned int)uv_available_parallelism();
1932 # else
1933 nprocs = (unsigned int)_sir_nprocs();
1934 # endif
1935 ncores = (unsigned int)get_core_count();
1936 
1937 /* Make sure that argv has at least 10 elements and that it ends in a NULL pointer */
1938 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1939 if (!targv)
1940   {
1941     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1942                    __func__, __FILE__, __LINE__);
1943 # if defined(USE_BACKTRACE)
1944 #  if defined(SIGUSR2)
1945     (void)raise(SIGUSR2);
1946     /*NOTREACHED*/ /* unreachable */
1947 #  endif /* if defined(SIGUSR2) */
1948 # endif /* if defined(USE_BACKTRACE) */
1949     abort();
1950   }
1951 for (i=0; i<argc; i++)
1952     targv[i] = argv[i];
1953 argv = targv;
1954 
1955 /* setup defaults */
1956 set_prompt (0, "sim>");                                 /* start with set standard prompt */
1957 *cbuf = 0;                                              /* init arg buffer */
1958 sim_switches = 0;                                       /* init switches */
1959 lookswitch = TRUE;
1960 stdnul = fopen(NULL_DEVICE,"wb");
1961 
1962 /* process arguments */
1963 for (i = 1; i < argc; i++) {                            /* loop thru args */
1964     if (argv[i] == NULL)                                /* paranoia */
1965         continue;
1966 
1967 # if defined(THREADZ) || defined(LOCKLESS)
1968 /* performance test */
1969     int perftestflag  = strcmp(argv[i], "--perftest");
1970     if (perftestflag == 0) {
1971       char * testName = NULL;
1972       if (i + 1 < argc)
1973         testName = argv[i + 1];
1974       perfTest (testName);
1975       return 0;
1976     }
1977 # endif
1978 
1979 /* requested only version? */
1980     int onlyvers  = strcmp(argv[i], "--version");
1981     if (onlyvers == 0) {
1982 # if defined(VER_H_GIT_VERSION)
1983 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1984 #   if VER_H_GIT_PATCH_INT < 1
1985         (void)fprintf (stdout, "%s simulator %s\r\n",
1986                        sim_name, VER_H_GIT_VERSION);
1987 #   else
1988         (void)fprintf (stdout, "%s simulator %s+%s\r\n",
1989                        sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1990 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
1991 #  else
1992         (void)fprintf (stdout, "%s simulator %s\r\n",
1993                        sim_name, VER_H_GIT_VERSION);
1994 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
1995 # else
1996         (void)fprintf (stdout, "%s simulator\r\n", sim_name);
1997 # endif /* if defined(VER_H_GIT_VERSION) */
1998         FREE (targv);
1999         return 0;
2000     }
2001 
2002 /* requested short or long help? */
2003     int longhelp  = strcmp(argv[i], "--help");
2004     int shorthelp = strcmp(argv[i], "-h");
2005     if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
2006     if (longhelp == 0 || shorthelp == 0) {
2007 # if defined(VER_H_GIT_VERSION)
2008 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
2009 #   if VER_H_GIT_PATCH_INT < 1
2010         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2011 #   else
2012         (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
2013 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
2014 #  else
2015         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2016 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
2017 # else
2018         (void)fprintf (stdout, "%s simulator", sim_name);
2019 # endif /* if defined(VER_H_GIT_VERSION) */
2020         (void)fprintf (stdout, "\r\n");
2021         (void)fprintf (stdout, "\r\n USAGE: %s [ [ SWITCH ] ... ] [ SCRIPT ]", argv[0]);
2022         (void)fprintf (stdout, "\r\n");
2023         (void)fprintf (stdout, "\r\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
2024         (void)fprintf (stdout, "\r\n");
2025         (void)fprintf (stdout, "\r\n Switches:");
2026         (void)fprintf (stdout, "\r\n  -e, -E            Aborts script processing immediately upon any error");
2027         (void)fprintf (stdout, "\r\n  -h, -H, --help    Prints only this informational help text and exits");
2028         (void)fprintf (stdout, "\r\n  -k, -K            Disables all support for exclusive file locking");
2029         (void)fprintf (stdout, "\r\n  -l, -L            Reports but ignores all exclusive file locking errors");
2030         (void)fprintf (stdout, "\r\n  -o, -O            Makes scripting ON conditions and actions inheritable");
2031 # if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2032         (void)fprintf (stdout, "\r\n  -p, -P            Enables real-time scheduling (may require privileges)");
2033 # endif
2034         (void)fprintf (stdout, "\r\n  -q, -Q            Disables printing of non-fatal informational messages");
2035         (void)fprintf (stdout, "\r\n  -r, -R            Enables an unlinked ephemeral system state file");
2036         (void)fprintf (stdout, "\r\n  -s, -S            Enables a randomized persistent system state file");
2037         (void)fprintf (stdout, "\r\n  -t, -T            Disables fsync and creation/usage of system state file");
2038         (void)fprintf (stdout, "\r\n  -v, -V            Prints commands read from script file before execution");
2039         (void)fprintf (stdout, "\r\n  --version         Prints only the simulator identification text and exits");
2040         (void)fprintf (stdout, "\r\n");
2041 # if defined(USE_DUMA)
2042         nodist++;
2043 # endif /* if defined(USE_DUMA) */
2044 if (!nodist) {
2045         (void)fprintf (stdout, "\r\n This software is made available under the terms of the ICU License.");
2046         (void)fprintf (stdout, "\r\n For complete license details, see the LICENSE file included with the");
2047         (void)fprintf (stdout, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\r\n");
2048 }
2049 else
2050 {
2051         (void)fprintf (stdout, "\r\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2052 }
2053         (void)fprintf (stdout, "\r\n");
2054         FREE(argv); //-V726
2055         return 0;
2056     }
2057     /* invalid arguments? */
2058     if ((*argv[i] == '-') && lookswitch) {              /* switch? */
2059         if ((sw = get_switches (argv[i])) < 0) {
2060             (void)fprintf (stderr, "Invalid switch \"%s\".\r\nTry \"%s -h\" for help.\r\n", argv[i], argv[0]);
2061             FREE(argv); //-V726
2062             return 1;
2063             }
2064         sim_switches = sim_switches | sw;
2065         }
2066     /* parse arguments */
2067     else {
2068         if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2069             (void)fprintf (stderr, "Argument string too long\r\n");
2070             FREE(argv); //-V726
2071             return 1;
2072             }
2073         if (*cbuf)                                  /* concat args */
2074             strcat (cbuf, " ");
2075         (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s", //-V755
2076                       strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : ""); //-V755
2077         lookswitch = FALSE;                         /* no more switches */
2078         }
2079     }                                               /* end for */
2080 sim_nolock = sim_switches & SWMASK ('K');           /* -k means skip locking     */
2081 sim_iglock = sim_switches & SWMASK ('L');           /* -l means ignore locking   */
2082 sim_randompst = sim_switches & SWMASK ('S');        /* -s means persist random   */
2083 sim_quiet = sim_switches & SWMASK ('Q');            /* -q means quiet            */
2084 sim_randstate = sim_switches & SWMASK ('R');        /* -r means random sys_state */
2085 if (sim_randompst) sim_randstate = 1;               /*    and is implied with -s */
2086 sim_nostate = sim_switches & SWMASK ('T');          /* -t means no sys_state     */
2087 if (sim_nostate)                                    /*    and disables -s and -r */
2088   {
2089     sim_randompst = 0;
2090     sim_randstate = 0;
2091   }
2092 sim_on_inherit = sim_switches & SWMASK ('O');       /* -o means inherit on state */
2093 
2094 # if !defined(__MVS__) && !defined(__MINGW32__) && !defined(__MINGW64__) && \
2095      !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2096 sim_realtime = sim_switches & SWMASK ('P');         /* -p means real-time priority */
2097 # endif
2098 
2099 sim_init_sock ();                                   /* init socket capabilities */
2100 if (sim_dflt_dev == NULL)                           /* if no default */
2101     sim_dflt_dev = sim_devices[0];
2102 if (sim_vm_init != NULL)                            /* call once only */
2103     (*sim_vm_init)();
2104 sim_finit ();                                       /* init fio package */
2105 for (i = 0; cmd_table[i].name; i++) {
2106     size_t alias_len = strlen (cmd_table[i].name);
2107     char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2108     if (!cmd_name)
2109       {
2110         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2111                        __func__, __FILE__, __LINE__);
2112 # if defined(USE_BACKTRACE)
2113 #  if defined(SIGUSR2)
2114         (void)raise(SIGUSR2);
2115         /*NOTREACHED*/ /* unreachable */
2116 #  endif /* if defined(SIGUSR2) */
2117 # endif /* if defined(USE_BACKTRACE) */
2118         abort();
2119       }
2120 
2121     strcpy (cmd_name, cmd_table[i].name);
2122     while (alias_len > 1) {
2123         cmd_name[alias_len] = '\0';                 /* Possible short form command name */
2124         --alias_len;
2125         if (getenv (cmd_name))                      /* Externally defined command alias? */
2126             unsetenv (cmd_name);                    /* Remove it to protect against possibly malicious aliases */
2127         }
2128     FREE (cmd_name);
2129     }
2130 stop_cpu = 0;
2131 sim_interval = 0;
2132 sim_time = sim_rtime = 0;
2133 noqueue_time = 0;
2134 sim_clock_queue = QUEUE_LIST_END;
2135 sim_is_running = 0;
2136 sim_log = NULL;
2137 if (sim_emax <= 0)
2138     sim_emax = 1;
2139 
2140 /* stash our pthread_id */
2141 main_thread_id = pthread_self();
2142 
2143 /* stash current (default) thread scheduler and priority */
2144 save_thread_sched(pthread_self());
2145 
2146 /* real-time priority (always call before sim_timer_init) */
2147 if (sim_realtime) {
2148     if (nprocs < 2) {
2149         sir_emerg("FATAL: Real-time requires >1 CPU but only %u detected!", nprocs);
2150         exit(EXIT_FAILURE);
2151     } else {
2152         watchdog_startup();
2153     }
2154 }
2155 
2156 /* do setup for realtime or normal operation */
2157 if (realtime_ok) {
2158     set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2159     check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2160 } else {
2161 # if !defined(__QNX__)
2162     (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2163 # endif
2164 }
2165 
2166 sim_timer_init ();
2167 
2168 if ((stat = sim_ttinit ()) != SCPE_OK) {
2169     (void)fprintf (stderr, "Fatal terminal initialization error\r\n%s\r\n",
2170                    sim_error_text (stat));
2171     FREE(argv); //-V726
2172     return 1;
2173     }
2174 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2175     (void)fprintf (stderr, "Unable to allocate examine buffer\r\n");
2176     FREE(argv); //-V726
2177     return 1;
2178     };
2179 if ((stat = reset_all_p (0)) != SCPE_OK) {
2180     (void)fprintf (stderr, "Fatal simulator initialization error\r\n%s\r\n",
2181                    sim_error_text (stat));
2182     FREE(argv); //-V726
2183     return 1;
2184     }
2185 if ((stat = sim_brk_init ()) != SCPE_OK) {
2186     (void)fprintf (stderr, "Fatal breakpoint table initialization error\r\n%s\r\n",
2187                    sim_error_text (stat));
2188     FREE(argv); //-V726
2189     return 1;
2190     }
2191 if (!sim_quiet) {
2192     (void)printf ("\r\n");
2193     show_version (stdout, NULL, NULL, 0, NULL);
2194     }
2195 
2196 cptr = getenv("HOME");
2197 if (cptr == NULL) {
2198     cptr = getenv("HOMEPATH");
2199     cptr2 = getenv("HOMEDRIVE");
2200     }
2201 else
2202     cptr2 = NULL;
2203 (void)cptr2;
2204 if ( (*cbuf) && (strcmp(cbuf, "")) )                    /* cmd file arg? */
2205     stat = do_cmd (0, cbuf);                            /* proc cmd file */
2206 else if (*argv[0]) {                                    /* sim name arg? */
2207     char *np;                                           /* "path.ini" */
2208     nbuf[0] = '"';                                      /* starting " */
2209     stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;         /* proc default cmd file */
2210     if (stat == SCPE_OPENERR) {                         /* didn't exist/can't open? */
2211         np = strrchr (nbuf, '/');                       /* strip path and try again in cwd */
2212         if (np == NULL)
2213             np = strrchr (nbuf, '\\');                  /* windows path separator */
2214         if (np != NULL) {
2215             *np = '"';
2216             stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;   /* proc default cmd file */
2217             }
2218         }
2219     }
2220 
2221 argv = uv_setup_args(argc, argv);
2222 
2223 /* show if hints are not disabled and empty cbuf and not quiet mode */
2224 if (getenv("DPS8M_NO_HINTS") == NULL)
2225   if (!sim_quiet && 0 == strcmp(cbuf, ""))
2226     (void)show_hints(0, 0, 0, 1, 0);
2227 
2228 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2229 
2230 if (sim_vm_exit != NULL)                                /* call once only */
2231     (*sim_vm_exit)();
2232 
2233 detach_all (0, TRUE);                                   /* close files */
2234 sim_set_deboff (0, NULL);                               /* close debug */
2235 sim_set_logoff (0, NULL);                               /* close log */
2236 sim_set_notelnet (0, NULL);                             /* close Telnet */
2237 sim_ttclose ();                                         /* close console */
2238 sim_cleanup_sock ();                                    /* cleanup sockets */
2239 fclose (stdnul);                                        /* close bit bucket file handle */
2240 FREE (targv);                                           /* release any argv copy that was made */
2241 FREE (sim_prompt);
2242 FREE (sim_eval);
2243 FREE (sim_internal_devices);
2244 FREE (sim_brk_tab);
2245 FREE (sim_staba.comp);
2246 FREE (sim_staba.mask);
2247 FREE (sim_stabr.comp);
2248 FREE (sim_stabr.mask);
2249 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2250 }
2251 #endif
2252 
2253 t_stat process_stdin_commands (t_stat stat, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
2254 {
2255 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2256 CONST char *cptr;
2257 t_stat stat_nomessage;
2258 CTAB *cmdp = NULL;
2259 
2260 stat = SCPE_BARE_STATUS(stat);                          /* remove possible flag */
2261 while (stat != SCPE_EXIT) {                             /* in case exit */
2262     if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))   /* pending action? */
2263         (void)printf ("%s%s\r\n", sim_prompt, cptr);    /* echo */
2264     else if (sim_vm_read != NULL) {                     /* sim routine? */
2265         (void)printf ("%s", sim_prompt);                /* prompt */
2266         cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2267         }
2268     else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prompt*/
2269     if (cptr == NULL) {                                 /* EOF? */
2270         if (sim_ttisatty()) continue;                   /* ignore tty EOF */
2271         else break;                                     /* otherwise exit */
2272         }
2273     if (*cptr == 0)                                     /* ignore blank */
2274         continue;
2275     sim_sub_args (cbuf, sizeof(cbuf), argv);
2276     if (sim_log)                                        /* log cmd */
2277         (void)fprintf (sim_log, "%s%s\r\n", sim_prompt, cptr);
2278     if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2279         (void)fprintf (sim_deb, "%s%s\r\n", sim_prompt, cptr);
2280     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
2281     sim_switches = 0;                                   /* init switches */
2282     if ((cmdp = find_cmd (gbuf)))                       /* lookup command */
2283         stat = cmdp->action (cmdp->arg, cptr);          /* if found, exec */
2284     else
2285         stat = SCPE_UNK;
2286     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
2287     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
2288     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
2289     sim_last_cmd_stat = stat;                           /* save command error status */
2290     if (!stat_nomessage) {                              /* displaying message status? */
2291         if (cmdp && (cmdp->message))                    /* special message handler? */
2292             cmdp->message (NULL, stat);                 /* let it deal with display */
2293         else
2294             if (stat >= SCPE_BASE)                      /* error? */
2295                 sim_printf ("%s\r\n", sim_error_text (stat));
2296         }
2297     if (sim_vm_post != NULL)
2298         (*sim_vm_post) (TRUE);
2299     }                                                   /* end while */
2300 return stat;
2301 }
2302 
2303 /* Set prompt routine */
2304 
2305 t_stat set_prompt (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2306 {
2307 char gbuf[CBUFSIZE], *gptr;
2308 
2309 if ((NULL == cptr) || (*cptr == '\0'))
2310     return SCPE_ARG;
2311 
2312 cptr = get_glyph_nc (cptr, gbuf, '"');                  /* get quote delimited token */
2313 if (gbuf[0] == '\0') {                                  /* Token started with quote */
2314     gbuf[sizeof (gbuf)-1] = '\0';
2315     strncpy (gbuf, cptr, sizeof (gbuf)-1);
2316     gptr = strchr (gbuf, '"');
2317     if (NULL != gptr)
2318         *gptr = '\0';
2319     }
2320 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);   /* nul terminator and trailing blank */
2321 if (!sim_prompt)
2322   {
2323     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2324                    __func__, __FILE__, __LINE__);
2325 #if defined(USE_BACKTRACE)
2326 # if defined(SIGUSR2)
2327     (void)raise(SIGUSR2);
2328     /*NOTREACHED*/ /* unreachable */
2329 # endif /* if defined(SIGUSR2) */
2330 #endif /* if defined(USE_BACKTRACE) */
2331     abort();
2332   }
2333 (void)sprintf (sim_prompt, "%s ", gbuf);
2334 return SCPE_OK;
2335 }
2336 
2337 /* Find command routine */
2338 
2339 CTAB *find_cmd (const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
2340 {
2341 CTAB *cmdp = NULL;
2342 
2343 if (sim_vm_cmd)                                         /* try ext commands */
2344     cmdp = find_ctab (sim_vm_cmd, gbuf);
2345 if (cmdp == NULL)                                       /* try regular cmds */
2346     cmdp = find_ctab (cmd_table, gbuf);
2347 return cmdp;
2348 }
2349 
2350 /* Exit command */
2351 
2352 t_stat exit_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2353 {
2354 return SCPE_EXIT;
2355 }
2356 
2357 /* Help command */
2358 
2359 /* Used when sorting a list of command names */
2360 static int _cmd_name_compare (const void *pa, const void *pb)
     /* [previous][next][first][last][top][bottom][index][help] */
2361 {
2362 CTAB * const *a = (CTAB * const *)pa;
2363 CTAB * const *b = (CTAB * const *)pb;
2364 
2365 return strcmp((*a)->name, (*b)->name);
2366 }
2367 
2368 void fprint_help (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
2369 {
2370 CTAB *cmdp;
2371 CTAB **hlp_cmdp = NULL;
2372 size_t cmd_cnt = 0;
2373 size_t cmd_size = 0;
2374 size_t max_cmdname_size = 0;
2375 size_t i, line_offset;
2376 
2377 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2378     if (cmdp->help) {
2379         if (cmd_cnt >= cmd_size) {
2380             cmd_size += 20;
2381             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2382             if (!hlp_cmdp)
2383               {
2384                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2385                                __func__, __FILE__, __LINE__);
2386 #if defined(USE_BACKTRACE)
2387 # if defined(SIGUSR2)
2388                 (void)raise(SIGUSR2);
2389                 /*NOTREACHED*/ /* unreachable */
2390 # endif /* if defined(SIGUSR2) */
2391 #endif /* if defined(USE_BACKTRACE) */
2392                 abort();
2393               }
2394             }
2395         hlp_cmdp[cmd_cnt] = cmdp;
2396         ++cmd_cnt;
2397         if (strlen(cmdp->name) > max_cmdname_size)
2398             max_cmdname_size = strlen(cmdp->name);
2399         }
2400     }
2401 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2402     if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2403         if (cmd_cnt >= cmd_size) {
2404             cmd_size += 20;
2405             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2406             if (!hlp_cmdp)
2407               {
2408                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2409                                __func__, __FILE__, __LINE__);
2410 #if defined(USE_BACKTRACE)
2411 # if defined(SIGUSR2)
2412                 (void)raise(SIGUSR2);
2413                 /*NOTREACHED*/ /* unreachable */
2414 # endif /* if defined(SIGUSR2) */
2415 #endif /* if defined(USE_BACKTRACE) */
2416                 abort();
2417               }
2418             }
2419         hlp_cmdp[cmd_cnt] = cmdp;
2420         ++cmd_cnt;
2421         if (strlen (cmdp->name) > max_cmdname_size)
2422             max_cmdname_size = strlen(cmdp->name);
2423         }
2424     }
2425 (void)fprintf (st, "HELP is available for the following commands:\r\n\r\n    ");
2426 if (hlp_cmdp)
2427   qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2428 line_offset = 4;
2429 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2430     fputs (hlp_cmdp[i]->name, st);
2431     line_offset += 5 + max_cmdname_size;
2432     if (line_offset + max_cmdname_size > 79) {
2433         line_offset = 4;
2434         (void)fprintf (st, "\r\n    ");
2435         }
2436     else
2437         (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2438     }
2439 FREE (hlp_cmdp);
2440 (void)fprintf (st, "\r\n");
2441 return;
2442 }
2443 
2444 static void fprint_header (FILE *st, t_bool *pdone, char *context)
     /* [previous][next][first][last][top][bottom][index][help] */
2445 {
2446 if (!*pdone)
2447     (void)fprintf (st, "%s", context);
2448 *pdone = TRUE;
2449 }
2450 
2451 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2452 {
2453 REG *rptr, *trptr;
2454 t_bool found = FALSE;
2455 t_bool all_unique = TRUE;
2456 size_t max_namelen = 0;
2457 DEVICE *tdptr;
2458 CONST char *tptr;
2459 char *namebuf;
2460 char rangebuf[32];
2461 
2462 if (dptr->registers)
2463     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2464         if (rptr->flags & REG_HIDDEN)
2465             continue;
2466         if (rptr->depth > 1)
2467             (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2468         else
2469             strcpy (rangebuf, "");
2470         if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2471             max_namelen = strlen(rptr->name) + strlen (rangebuf);
2472         found = TRUE;
2473         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2474         if ((trptr == NULL) || (tdptr != dptr))
2475             all_unique = FALSE;
2476         }
2477 if (!found) {
2478     if (!silent)
2479         (void)fprintf (st, "No register HELP available for the %s device\r\n",
2480                        dptr->name);
2481     }
2482 else {
2483     namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2484     if (!namebuf)
2485       {
2486         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2487                        __func__, __FILE__, __LINE__);
2488 #if defined(USE_BACKTRACE)
2489 # if defined(SIGUSR2)
2490         (void)raise(SIGUSR2);
2491         /*NOTREACHED*/ /* unreachable */
2492 # endif /* if defined(SIGUSR2) */
2493 #endif /* if defined(USE_BACKTRACE) */
2494         abort();
2495       }
2496     (void)fprintf (st, "\r\nThe %s device implements these registers:\r\n\r\n",
2497                    dptr->name);
2498     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2499         if (rptr->flags & REG_HIDDEN)
2500             continue;
2501         if (rptr->depth <= 1)
2502             (void)sprintf (namebuf, "%*s",
2503                            -((int)max_namelen),
2504                            rptr->name);
2505         else {
2506             (void)sprintf (rangebuf, "[%d:%d]",
2507                            0,
2508                            rptr->depth-1);
2509             (void)sprintf (namebuf, "%s%*s",
2510                            rptr->name,
2511                            (int)(strlen(rptr->name))-((int)max_namelen),
2512                            rangebuf);
2513             }
2514         if (all_unique) {
2515             (void)fprintf (st, "  %s %4d  %s\r\n",
2516                            namebuf,
2517                            rptr->width,
2518                            rptr->desc ? rptr->desc : "");
2519             continue;
2520             }
2521         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2522         if ((trptr == NULL) || (tdptr != dptr))
2523             (void)fprintf (st, "  %s %s %4d  %s\r\n",
2524                            dptr->name,
2525                            namebuf,
2526                            rptr->width,
2527                            rptr->desc ? rptr->desc : "");
2528         else
2529             (void)fprintf (st, "  %*s %s %4d  %s\r\n",
2530                            (int)strlen(dptr->name), "",
2531                            namebuf,
2532                            rptr->width,
2533                            rptr->desc ? rptr->desc : "");
2534         }
2535     FREE (namebuf);
2536     }
2537 }
2538 
2539 void fprint_reg_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2540 {
2541 fprint_reg_help_ex (st, dptr, TRUE);
2542 }
2543 
2544 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2545 {
2546 if (dptr->attach_help) {
2547     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2548     dptr->attach_help (st, dptr, NULL, 0, NULL);
2549     return;
2550     }
2551 if (DEV_TYPE(dptr) == DEV_DISK) {
2552     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2553     sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2554     return;
2555     }
2556 if (DEV_TYPE(dptr) == DEV_TAPE) {
2557     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2558     sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2559     return;
2560     }
2561 if (!silent) {
2562     (void)fprintf (st, "No ATTACH help is available for the %s device\r\n", dptr->name);
2563     if (dptr->help)
2564         dptr->help (st, dptr, NULL, 0, NULL);
2565     }
2566 }
2567 
2568 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2569 {
2570 MTAB *mptr;
2571 DEBTAB *dep;
2572 t_bool found = FALSE;
2573 char buf[CBUFSIZE], header[CBUFSIZE];
2574 uint32 enabled_units = dptr->numunits;
2575 uint32 unit;
2576 
2577 (void)sprintf (header, "\r\n%s device SET commands:\r\n\r\n", dptr->name);
2578 for (unit=0; unit < dptr->numunits; unit++)
2579     if (dptr->units[unit].flags & UNIT_DIS)
2580         --enabled_units;
2581 if (dptr->modifiers) {
2582     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2583         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2584             continue;                                       /* skip unit only extended modifiers */
2585         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2586             continue;                                       /* skip unit only simple modifiers */
2587         if (mptr->mstring) {
2588             fprint_header (st, &found, header);
2589             (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2590                            mptr->mstring,
2591                            (strchr(mptr->mstring, '=')) \
2592                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2593                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2594                                ? "{=val}" : "")));
2595             if ((strlen (buf) < 30) || (NULL == mptr->help))
2596                 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2597             else
2598                 (void)fprintf (st, "%s\r\n%-30s\t%s\r\n", buf, "", mptr->help);
2599             }
2600         }
2601     }
2602 if (dptr->flags & DEV_DISABLE) {
2603     fprint_header (st, &found, header);
2604     (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2605     (void)fprintf (st,  "%-30s\tEnables device %s\r\n", buf, sim_dname (dptr));
2606     (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2607     (void)fprintf (st,  "%-30s\tDisables device %s\r\n", buf, sim_dname (dptr));
2608     }
2609 if (dptr->flags & DEV_DEBUG) {
2610     fprint_header (st, &found, header);
2611     (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2612     (void)fprintf (st,  "%-30s\tEnables debugging for device %s\r\n", buf, sim_dname (dptr));
2613     (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2614     (void)fprintf (st,  "%-30s\tDisables debugging for device %s\r\n", buf, sim_dname (dptr));
2615     if (dptr->debflags) {
2616         t_bool desc_available = FALSE;
2617         strcpy (buf, "");
2618         (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2619         for (dep = dptr->debflags; dep->name != NULL; dep++) {
2620             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2621             desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2622             }
2623         (void)fprintf (st, "\r\n");
2624         (void)fprintf (st,  "%-30s\tEnables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2625         (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2626         for (dep = dptr->debflags; dep->name != NULL; dep++)
2627             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2628         (void)fprintf (st, "\r\n");
2629         (void)fprintf (st,  "%-30s\tDisables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2630         if (desc_available) {
2631             (void)fprintf (st, "\r\n*%s device DEBUG settings:\r\n", sim_dname (dptr));
2632             for (dep = dptr->debflags; dep->name != NULL; dep++)
2633                 (void)fprintf (st, "%4s%-12s%s\r\n", "", dep->name, dep->desc ? dep->desc : "");
2634             }
2635         }
2636     }
2637 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2638     if (dptr->units->flags & UNIT_DISABLE) {
2639         fprint_header (st, &found, header);
2640         (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2641         (void)fprintf (st,  "%-30s\tEnables unit %sn\r\n", buf, sim_dname (dptr));
2642         (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2643         (void)fprintf (st,  "%-30s\tDisables unit %sn\r\n", buf, sim_dname (dptr));
2644         }
2645     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2646         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2647             continue;                                           /* skip device only modifiers */
2648         if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2649             continue;                                           /* skip show only modifiers */
2650         if (mptr->mstring) {
2651             fprint_header (st, &found, header);
2652             (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2653                            (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2654                            (strchr(mptr->mstring, '=')) \
2655                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2656                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2657                                ? "{=val}" : "")));
2658             (void)fprintf (st, "%-30s\t%s\r\n", buf,
2659                            (strchr(mptr->mstring, '=')) \
2660                                ? "" : (mptr->help ? mptr->help : ""));
2661             }
2662         }
2663     }
2664 if (!found && !silent)
2665     (void)fprintf (st, "No SET help is available for the %s device\r\n", dptr->name);
2666 }
2667 
2668 void fprint_set_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2669 {
2670   fprint_set_help_ex (st, dptr, TRUE);
2671 }
2672 
2673 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2674 {
2675 MTAB *mptr;
2676 t_bool found = FALSE;
2677 char buf[CBUFSIZE], header[CBUFSIZE];
2678 uint32 enabled_units = dptr->numunits;
2679 uint32 unit;
2680 
2681 (void)sprintf (header, "\r\n%s device SHOW commands:\r\n\r\n", dptr->name);
2682 for (unit=0; unit < dptr->numunits; unit++)
2683     if (dptr->units[unit].flags & UNIT_DIS)
2684         --enabled_units;
2685 if (dptr->modifiers) {
2686     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2687         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2688             continue;                                       /* skip unit only extended modifiers */
2689         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2690             continue;                                       /* skip unit only simple modifiers */
2691         if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2692             continue;
2693         fprint_header (st, &found, header);
2694         (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2695                        mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2696         (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2697         }
2698     }
2699 if (dptr->flags & DEV_DEBUG) {
2700     fprint_header (st, &found, header);
2701     (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2702     (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\r\n", buf, sim_dname (dptr));
2703     }
2704 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2705     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2706         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2707             continue;                                           /* skip device only modifiers */
2708         if ((!mptr->disp) || (!mptr->pstring))
2709             continue;
2710         fprint_header (st, &found, header);
2711         (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2712                        (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2713                        MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2714         (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2715         }
2716     }
2717 if (!found && !silent)
2718     (void)fprintf (st, "No SHOW help is available for the %s device\r\n", dptr->name);
2719 }
2720 
2721 void fprint_show_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2722     {
2723     fprint_show_help_ex (st, dptr, TRUE);
2724     }
2725 
2726 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2727 {
2728 BRKTYPTAB *brkt = dptr->brk_types;
2729 char gbuf[CBUFSIZE];
2730 
2731 if (sim_brk_types == 0) {
2732     if ((dptr != sim_dflt_dev) && (!silent)) {
2733         (void)fprintf (st, "Breakpoints are not supported in the %s simulator\r\n", sim_name);
2734         if (dptr->help)
2735             dptr->help (st, dptr, NULL, 0, NULL);
2736         }
2737     return;
2738     }
2739 if (brkt == NULL) {
2740     int i;
2741 
2742     if (dptr == sim_dflt_dev) {
2743         if (sim_brk_types & ~sim_brk_dflt) {
2744             (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2745             for (i=0; i<26; i++) {
2746                 if (sim_brk_types & (1<<i))
2747                     (void)fprintf (st, "  -%c\r\n", 'A'+i);
2748                 }
2749             }
2750         (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2751         }
2752     return;
2753     }
2754 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2755 while (brkt->btyp) {
2756     (void)fprintf (st, "  %s     %s\r\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2757     ++brkt;
2758     }
2759 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2760 }
2761 
2762 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2763 {
2764 char gbuf[CBUFSIZE];
2765 CTAB *cmdp;
2766 
2767 if (*cptr) {
2768     (void)get_glyph (cptr, gbuf, 0);
2769     if ((cmdp = find_cmd (gbuf))) {
2770         if (cmdp->action == &exdep_cmd) {
2771             if (dptr->help) /* Shouldn't this pass cptr so the device knows which command invoked? */
2772                 return dptr->help (st, dptr, uptr, flag, cptr);
2773             else
2774                 (void)fprintf (st, "No HELP available for the %s %s command\r\n", cmdp->name, sim_dname(dptr));
2775             return SCPE_OK;
2776             }
2777         if (cmdp->action == &set_cmd) {
2778             fprint_set_help_ex (st, dptr, FALSE);
2779             return SCPE_OK;
2780             }
2781         if (cmdp->action == &show_cmd) {
2782             fprint_show_help_ex (st, dptr, FALSE);
2783             return SCPE_OK;
2784             }
2785         if (cmdp->action == &attach_cmd) {
2786             fprint_attach_help_ex (st, dptr, FALSE);
2787             return SCPE_OK;
2788             }
2789         if (cmdp->action == &brk_cmd) {
2790             fprint_brk_help_ex (st, dptr, FALSE);
2791             return SCPE_OK;
2792             }
2793         if (dptr->help)
2794             return dptr->help (st, dptr, uptr, flag, cptr);
2795         (void)fprintf (st, "No %s HELP is available for the %s device\r\n", cmdp->name, dptr->name);
2796         return SCPE_OK;
2797         }
2798     if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2799         fprint_reg_help_ex (st, dptr, FALSE);
2800         return SCPE_OK;
2801         }
2802     if (dptr->help)
2803         return dptr->help (st, dptr, uptr, flag, cptr);
2804     (void)fprintf (st, "No %s HELP is available for the %s device\r\n", gbuf, dptr->name);
2805     return SCPE_OK;
2806     }
2807 if (dptr->help) {
2808     return dptr->help (st, dptr, uptr, flag, cptr);
2809     }
2810 if (dptr->description)
2811     (void)fprintf (st, "%s %s HELP\r\n", dptr->description (dptr), dptr->name);
2812 else
2813     (void)fprintf (st, "%s HELP\r\n", dptr->name);
2814 fprint_set_help_ex    (st, dptr, TRUE);
2815 fprint_show_help_ex   (st, dptr, TRUE);
2816 fprint_attach_help_ex (st, dptr, TRUE);
2817 fprint_reg_help_ex    (st, dptr, TRUE);
2818 fprint_brk_help_ex    (st, dptr, TRUE);
2819 return SCPE_OK;
2820 }
2821 
2822 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
     /* [previous][next][first][last][top][bottom][index][help] */
2823 {
2824 switch (help[0]) {
2825     case '*':
2826         scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2827         if (sim_log)
2828             scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2829         break;
2830     default:
2831         fputs (help, stdout);
2832         if (sim_log)
2833             fputs (help, sim_log);
2834         break;
2835     }
2836 return SCPE_OK;
2837 }
2838 
2839 t_stat help_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2840 {
2841 char gbuf[CBUFSIZE];
2842 CTAB *cmdp;
2843 
2844 GET_SWITCHES (cptr);
2845 if (sim_switches & SWMASK ('F'))
2846     flag = flag | SCP_HELP_FLAT;
2847 if (*cptr) {
2848     cptr = get_glyph (cptr, gbuf, 0);
2849     if ((cmdp = find_cmd (gbuf))) {
2850         if (*cptr) {
2851             if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2852                 DEVICE *dptr;
2853                 UNIT *uptr;
2854                 t_stat r;
2855                 cptr = get_glyph (cptr, gbuf, 0);
2856                 dptr = find_unit (gbuf, &uptr);
2857                 if (dptr == NULL)
2858                     dptr = find_dev (gbuf);
2859                 if (dptr != NULL) {
2860                     r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2861                     if (sim_log)
2862                         help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2863                     return r;
2864                     }
2865                 if (cmdp->action == &set_cmd) { /* HELP SET xxx (not device or unit) */
2866                     /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
2867                     if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2868                          (cmdp->help))
2869                         return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2870                     }
2871                 else { /* HELP SHOW xxx (not device or unit) */
2872                     SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2873                     if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2874                         return SCPE_ARG;
2875                     return help_cmd_output (flag, shptr->help, NULL);
2876                     }
2877                 return SCPE_ARG;
2878                 }
2879             else
2880                 return SCPE_2MARG;
2881             }
2882         if (cmdp->help) {
2883             if (strcmp (cmdp->name, "HELP") == 0) {
2884 
2885 
2886 
2887 
2888 
2889 
2890 
2891 
2892 
2893 
2894 
2895 
2896 
2897 
2898 
2899 
2900 
2901 
2902 
2903 
2904 
2905 
2906 
2907 
2908 
2909 
2910 
2911 
2912 
2913 
2914 
2915 
2916 
2917 
2918                 }
2919             else {
2920                 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2921                     sim_dflt_dev && sim_dflt_dev->help) {
2922                         sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2923                         if (sim_log)
2924                             sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2925                     }
2926                 }
2927             help_cmd_output (flag, cmdp->help, cmdp->help_base);
2928             }
2929         else { /* no help so it is likely a command alias */
2930             CTAB *cmdpa;
2931             for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2932                 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2933                     sim_printf ("%s is an alias for the %s command:\r\n%s",
2934                                 cmdp->name, cmdpa->name, cmdpa->help);
2935                     break;
2936                     }
2937             if (cmdpa->name == NULL)                /* not found? */
2938                 sim_printf ("No help available for the %s command\r\n", cmdp->name);
2939             }
2940         }
2941     else {
2942         DEVICE *dptr;
2943         UNIT *uptr;
2944         t_stat r;
2945         dptr = find_unit (gbuf, &uptr);
2946         if (dptr == NULL) {
2947             dptr = find_dev (gbuf);
2948             if (dptr == NULL)
2949                 return SCPE_ARG;
2950             if (dptr->flags & DEV_DIS)
2951                 sim_printf ("Device %s is currently disabled\r\n", dptr->name);
2952             }
2953         r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2954         if (sim_log)
2955             help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2956         return r;
2957         }
2958     }
2959 else {
2960     fprint_help (stdout);
2961     if (sim_log)
2962         fprint_help (sim_log);
2963     }
2964 return SCPE_OK;
2965 }
2966 
2967 /* Spawn command */
2968 
2969 t_stat spawn_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2970 {
2971 t_stat status;
2972 if ((cptr == NULL) || (strlen (cptr) == 0))
2973     cptr = getenv("SHELL");
2974 if ((cptr == NULL) || (strlen (cptr) == 0))
2975     cptr = getenv("ComSpec");
2976 (void)fflush(stdout);                                   /* flush stdout */
2977 if (sim_log)                                            /* flush log if enabled */
2978     (void)fflush (sim_log);
2979 if (sim_deb)                                            /* flush debug if enabled */
2980     (void)fflush (sim_deb);
2981 status = system (cptr);
2982 
2983 return status;
2984 }
2985 
2986 /* Echo command */
2987 
2988 t_stat echo_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2989 {
2990 sim_printf ("%s\r\n", cptr);
2991 return SCPE_OK;
2992 }
2993 
2994 /*
2995  * DO command
2996  *
2997  * Note that SCPE_STEP ("Step expired") is considered a note and
2998  * not an error; it does not abort command execution when using -E.
2999  *
3000  * Inputs:
3001  *      flag    =   caller and nesting level indicator
3002  *      fcptr   =   filename and optional arguments, space-separated
3003  * Outputs:
3004  *      status  =   error status
3005  *
3006  * The "flag" input value indicates the source of the call, as follows:
3007  *
3008  *      -1      =   initialization file (no error if not found)
3009  *       0      =   command line file
3010  *       1      =   "DO" command
3011  *      >1      =   nested "DO" command
3012  */
3013 
3014 t_stat do_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3015 {
3016 return do_cmd_label (flag, fcptr, NULL);
3017 }
3018 
3019 static char *do_position(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3020 {
3021 static char cbuf[4*CBUFSIZE];
3022 
3023 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
3024                 sim_do_label[sim_do_depth] ? "::" : "",
3025                 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
3026                 sim_goto_line[sim_do_depth]);
3027 return cbuf;
3028 }
3029 
3030 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
     /* [previous][next][first][last][top][bottom][index][help] */
3031 {
3032 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
3033 CONST char *cptr;
3034 FILE *fpin;
3035 CTAB *cmdp = NULL;
3036 int32 echo, nargs, errabort, i;
3037 int32 saved_sim_do_echo = sim_do_echo,
3038       saved_sim_show_message = sim_show_message,
3039       saved_sim_on_inherit = sim_on_inherit,
3040       saved_sim_quiet = sim_quiet;
3041 t_bool staying;
3042 t_stat stat, stat_nomessage;
3043 
3044 stat = SCPE_OK;
3045 staying = TRUE;
3046 if (flag > 0)                                           /* need switches? */
3047     GET_SWITCHES (fcptr);                               /* get switches */
3048 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;    /* -v means echo */
3049 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet; /* -q means quiet */
3050 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit; /* -o means inherit ON condition actions */
3051 errabort = sim_switches & SWMASK ('E');                 /* -e means abort on error */
3052 
3053 abuf[sizeof(abuf)-1] = '\0';
3054 strncpy (abuf, fcptr, sizeof(abuf)-1);
3055 c = abuf;
3056 do_arg[10] = NULL;                                      /* make sure the argument list always ends with a NULL */
3057 for (nargs = 0; nargs < 10; ) {                         /* extract arguments */
3058     while (sim_isspace (*c))                            /* skip blanks */
3059         c++;
3060     if (*c == 0)                                        /* all done? */
3061         do_arg [nargs++] = NULL;                        /* null argument */
3062     else {
3063         if (*c == '\'' || *c == '"')                    /* quoted string? */
3064             quote = *c++;
3065         else quote = 0;
3066         do_arg[nargs++] = c;                            /* save start */
3067         while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
3068             c++;
3069         if (*c)                                         /* term at quote/spc */
3070             *c++ = 0;
3071         }
3072     }                                                   /* end for */
3073 
3074 if (do_arg [0] == NULL)                                 /* need at least 1 */
3075     return SCPE_2FARG;
3076 if ((fpin = fopen (do_arg[0], "r")) == NULL) {          /* file failed to open? */
3077     strcat (strcpy (cbuf, do_arg[0]), ".ini");          /* try again with .ini extension */
3078     if ((fpin = fopen (cbuf, "r")) == NULL) {           /* failed a second time? */
3079         if (flag == 0)                                  /* cmd line file? */
3080              (void)fprintf (stderr, "Can't open file %s\r\n", do_arg[0]);
3081         return SCPE_OPENERR;                            /* return failure */
3082         }
3083     }
3084 if (flag >= 0) {                                        /* Only bump nesting from command or nested */
3085     ++sim_do_depth;
3086     if (sim_on_inherit) {                               /* inherit ON condition actions? */
3087         sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1]; /* inherit On mode */
3088         for (i=0; i<SCPE_MAX_ERR; i++) {                /* replicate any on commands */
3089             if (sim_on_actions[sim_do_depth-1][i]) {
3090                 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3091                 if (NULL == sim_on_actions[sim_do_depth][i]) {
3092                     while (--i >= 0) {
3093                         FREE(sim_on_actions[sim_do_depth][i]);
3094                         sim_on_actions[sim_do_depth][i] = NULL;
3095                         }
3096                     sim_on_check[sim_do_depth] = 0;
3097                     sim_brk_clract ();                  /* defang breakpoint actions */
3098                     --sim_do_depth;                     /* unwind nesting */
3099                     fclose(fpin);
3100                     return SCPE_MEM;
3101                     }
3102                 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3103                 }
3104             }
3105         }
3106     }
3107 
3108 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);      /* stash away do file name for possible use by 'call' command */
3109 sim_do_label[sim_do_depth] = label;                     /* stash away do label for possible use in messages */
3110 sim_goto_line[sim_do_depth] = 0;
3111 if (label) {
3112     sim_gotofile = fpin;
3113     sim_do_echo = echo;
3114     stat = goto_cmd (0, label);
3115     if (stat != SCPE_OK) {
3116         strcpy(cbuf, "RETURN SCPE_ARG");
3117         cptr = get_glyph (cbuf, gbuf, 0);               /* get command glyph */
3118         cmdp = find_cmd (gbuf);                         /* return the errorStage things to the stat will be returned */
3119         goto Cleanup_Return;
3120         }
3121     }
3122 if (errabort)                                           /* -e flag? */
3123     set_on (1, NULL);                                   /* equivalent to ON ERROR RETURN */
3124 
3125 do {
3126     sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */
3127     if (!sim_do_ocptr[sim_do_depth]) {                  /* no pending action? */
3128         sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */
3129         sim_goto_line[sim_do_depth] += 1;
3130         }
3131     if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {  /* validate */
3132         sim_sub_args(cbuf, sizeof(cbuf), do_arg);       /* substitute args */
3133         }
3134     sim_sub_args (cbuf, sizeof(cbuf), do_arg);          /* substitute args */
3135     if (cptr == NULL) {                                 /* EOF? */
3136         stat = SCPE_OK;                                 /* set good return */
3137         break;
3138         }
3139     if (*cptr == 0)                                     /* ignore blank */
3140         continue;
3141     if (echo)                                           /* echo if -v */
3142         sim_printf("%s> %s\r\n", do_position(), cptr);
3143     if (*cptr == ':')                                   /* ignore label */
3144         continue;
3145     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
3146     sim_switches = 0;                                   /* init switches */
3147     sim_gotofile = fpin;
3148     sim_do_echo = echo;
3149     if ((cmdp = find_cmd (gbuf))) {                     /* lookup command */
3150         if (cmdp->action == &return_cmd)                /* RETURN command? */
3151             break;                                      /*    done! */
3152         if (cmdp->action == &do_cmd) {                  /* DO command? */
3153             if (sim_do_depth >= MAX_DO_NEST_LVL)        /* nest too deep? */
3154                 stat = SCPE_NEST;
3155             else
3156                 stat = do_cmd (sim_do_depth+1, cptr);   /* exec DO cmd */
3157             }
3158         else
3159             stat = cmdp->action (cmdp->arg, cptr);      /* exec other cmd */
3160         }
3161     else stat = SCPE_UNK;                               /* bad cmd given */
3162     echo = sim_do_echo;                                 /* Allow for SET VERIFY */
3163     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
3164     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
3165     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
3166     if (cmdp)
3167       if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3168           ((cmdp->action != &return_cmd) &&
3169            (cmdp->action != &goto_cmd) &&
3170            (cmdp->action != &on_cmd) &&
3171            (cmdp->action != &echo_cmd)))
3172         sim_last_cmd_stat = stat;                       /* save command error status */
3173     switch (stat) {
3174         case SCPE_AFAIL:
3175             staying = (sim_on_check[sim_do_depth] &&        /* if trap action defined */
3176                        sim_on_actions[sim_do_depth][stat]); /* use it, otherwise exit */
3177             break;
3178         case SCPE_EXIT:
3179             staying = FALSE;
3180             break;
3181         case SCPE_OK:
3182         case SCPE_STEP:
3183             break;
3184         default:
3185             break;
3186         }
3187     if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&   /* error from cmd? */
3188         (stat != SCPE_STEP)) {
3189         if (!echo && !sim_quiet &&                      /* report if not echoing */
3190             !stat_nomessage &&                          /* and not suppressing messages */
3191             !(cmdp && cmdp->message)) {                 /* and not handling them specially */
3192             sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
3193             }
3194         }
3195     if (!stat_nomessage) {                              /* report error if not suppressed */
3196         if (cmdp && cmdp->message)                      /* special message handler */
3197             cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3198         else
3199             if (stat >= SCPE_BASE)                      /* report error if not suppressed */
3200                 sim_printf ("%s\r\n", sim_error_text (stat));
3201         }
3202     if (stat == SCPE_EXPECT)                            /* EXPECT status is non actionable */
3203         stat = SCPE_OK;                                 /* so adjust it to SCPE_OK */
3204     if (staying &&
3205         (sim_on_check[sim_do_depth]) &&
3206         (stat != SCPE_OK) &&
3207         (stat != SCPE_STEP)) {
3208         if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3209             sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3210         else
3211             sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3212         }
3213     if (sim_vm_post != NULL)
3214         (*sim_vm_post) (TRUE);
3215     } while (staying);
3216 Cleanup_Return:
3217 if (fpin) //-V547
3218     fclose (fpin);                                      /* close file */
3219 sim_gotofile = NULL;
3220 if (flag >= 0) {
3221     sim_do_echo = saved_sim_do_echo;                    /* restore echo state we entered with */
3222     sim_show_message = saved_sim_show_message;          /* restore message display state we entered with */
3223     sim_on_inherit = saved_sim_on_inherit;              /* restore ON inheritance state we entered with */
3224     }
3225 sim_quiet = saved_sim_quiet;                            /* restore quiet mode we entered with */
3226 if ((flag >= 0) || (!sim_on_inherit)) {
3227     for (i=0; i<SCPE_MAX_ERR; i++) {                    /* release any on commands */
3228         FREE (sim_on_actions[sim_do_depth][i]);
3229         sim_on_actions[sim_do_depth][i] = NULL;
3230         }
3231     sim_on_check[sim_do_depth] = 0;                     /* clear on mode */
3232     }
3233 if (flag >= 0)
3234     --sim_do_depth;                                     /* unwind nesting */
3235 sim_brk_clract ();                                      /* defang breakpoint actions */
3236 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) { /* return command with argument? */
3237     sim_string_to_stat (cptr, &stat);
3238     sim_last_cmd_stat = stat;                           /* save explicit status as command error status */
3239     if (sim_switches & SWMASK ('Q'))
3240         stat |= SCPE_NOMESSAGE;                         /* suppress error message display (in caller) if requested */
3241     return stat;                                        /* return with explicit return status */
3242     }
3243 return stat | SCPE_NOMESSAGE;                           /* suppress message since we've already done that here */
3244 }
3245 
3246 /*
3247  * Substitute_args - replace %n tokens in 'instr' with the do command's arguments
3248  *                   and other environment variables
3249  *
3250  * Calling sequence
3251  * instr        =       input string
3252  * instr_size   =       sizeof input string buffer
3253  * do_arg[10]   =       arguments
3254  *
3255  * Token "%0" expands to the command file name.
3256  * Token %n (n being a single digit) expands to the n'th argument
3257  * Tonen %* expands to the whole set of arguments (%1 ... %9)
3258  *
3259  * The input sequence "\%" represents a literal "%", and "\\" represents a
3260  * literal "\".  All other character combinations are rendered literally.
3261  *
3262  * Omitted parameters result in null-string substitutions.
3263  *
3264  * A Tokens preceded and followed by % characters are expanded as environment
3265  * variables, and if one isn't found then can be one of several special
3266  * variables:
3267  *   %DATE%              yyyy-mm-dd
3268  *   %TIME%              hh:mm:ss
3269  *   %STIME%             hh_mm_ss
3270  *   %CTIME%             Www Mmm dd hh:mm:ss yyyy
3271  *   %STATUS%            Status value from the last command executed
3272  *   %TSTATUS%           The text form of the last status value
3273  *   %SIM_VERIFY%        The Verify/Verbose mode of the current Do command file
3274  *   %SIM_VERBOSE%       The Verify/Verbose mode of the current Do command file
3275  *   %SIM_QUIET%         The Quiet mode of the current Do command file
3276  *   %SIM_MESSAGE%       The message display status of the current Do command file
3277  * Environment variable lookups are done first with the precise name between
3278  * the % characters and if that fails, then the name between the % characters
3279  * is upcased and a lookup of that value is attempted.
3280 
3281  * The first Space delimited token on the line is extracted in uppercase and
3282  * then looked up as an environment variable.  If found it the value is
3283  * substituted for the original string before expanding everything else.  If
3284  * it is not found, then the original beginning token on the line is left
3285  * untouched.
3286  */
3287 
3288 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
     /* [previous][next][first][last][top][bottom][index][help] */
3289 {
3290 char gbuf[CBUFSIZE];
3291 char *ip = instr, *op, *oend, *tmpbuf;
3292 const char *ap;
3293 char rbuf[CBUFSIZE];
3294 int i;
3295 time_t now;
3296 struct tm *tmnow;
3297 
3298 time(&now);
3299 tmnow = localtime(&now);
3300 tmpbuf = (char *)malloc(instr_size);
3301 if (!tmpbuf)
3302   {
3303      (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3304                    __func__, __FILE__, __LINE__);
3305 #if defined(USE_BACKTRACE)
3306 # if defined(SIGUSR2)
3307      (void)raise(SIGUSR2);
3308      /*NOTREACHED*/ /* unreachable */
3309 # endif /* if defined(SIGUSR2) */
3310 #endif /* if defined(USE_BACKTRACE) */
3311      abort();
3312   }
3313 op = tmpbuf;
3314 oend = tmpbuf + instr_size - 2;
3315 while (sim_isspace (*ip))                               /* skip leading spaces */
3316     *op++ = *ip++;
3317 for (; *ip && (op < oend); ) {
3318     if ((ip [0] == '\\') &&                             /* literal escape? */
3319         ((ip [1] == '%') || (ip [1] == '\\'))) {        /*   and followed by '%' or '\'? */
3320         ip++;                                           /* skip '\' */
3321         *op++ = *ip++;                                  /* copy escaped char */
3322         }
3323     else
3324         if ((*ip == '%') &&
3325             (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */
3326             if ((ip[1] >= '0') && (ip[1] <= ('9'))) {   /* %n = sub */
3327                 ap = do_arg[ip[1] - '0'];
3328                 for (i=0; i<ip[1] - '0'; ++i)           /* make sure we're not past the list end */
3329                     if (do_arg[i] == NULL) {
3330                         ap = NULL;
3331                         break;
3332                         }
3333                 ip = ip + 2;
3334                 }
3335             else if (ip[1] == '*') {                    /* %1 ... %9 = sub */
3336                 (void)memset (rbuf, '\0', sizeof(rbuf));
3337                 ap = rbuf;
3338                 for (i=1; i<=9; ++i)
3339                     if (do_arg[i] == NULL)
3340                         break;
3341                     else
3342                         if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3343                             if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
3344                                 char quote = '"';
3345                                 if (strchr(do_arg[i], quote))
3346                                     quote = '\'';
3347                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3348                                               (i != 1) ? " " : "", quote,
3349                                               do_arg[i], quote);
3350                                 }
3351                             else
3352                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3353                                               (i != 1) ? " " : "", do_arg[i]);
3354                             }
3355                         else
3356                             break;
3357                 ip = ip + 2;
3358                 }
3359             else {                                      /* environment variable */
3360                 ap = NULL;
3361                 (void)get_glyph_nc (ip+1, gbuf, '%');   /* first try using the literal name */
3362                 ap = getenv(gbuf);
3363                 if (!ap) {
3364                     (void)get_glyph (ip+1, gbuf, '%');  /* now try using the upcased name */
3365                     ap = getenv(gbuf);
3366                     }
3367                 ip += 1 + strlen (gbuf);
3368                 if (*ip == '%') ++ip;
3369                 if (!ap) {
3370                     /* ISO 8601 format date/time info */
3371                     if (!strcmp ("DATE", gbuf)) {
3372                         (void)sprintf (rbuf, "%4d-%02d-%02d",
3373                                        tmnow->tm_year + 1900,
3374                                        tmnow->tm_mon  + 1,
3375                                        tmnow->tm_mday);
3376                         ap = rbuf;
3377                         }
3378                     else if (!strcmp ("TIME", gbuf)) {
3379                         (void)sprintf (rbuf, "%02d:%02d:%02d",
3380                                        tmnow->tm_hour,
3381                                        tmnow->tm_min,
3382                                        tmnow->tm_sec);
3383                         ap = rbuf;
3384                         }
3385                     else if (!strcmp ("DATETIME", gbuf)) {
3386                         (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3387                                        tmnow->tm_year + 1900,
3388                                        tmnow->tm_mon  + 1,
3389                                        tmnow->tm_mday,
3390                                        tmnow->tm_hour,
3391                                        tmnow->tm_min,
3392                                        tmnow->tm_sec);
3393                         ap = rbuf;
3394                         }
3395                     /* Locale oriented formatted date/time info */
3396                     if (!strcmp ("LDATE", gbuf)) {
3397                         strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3398                         ap = rbuf;
3399                         }
3400                     else if (!strcmp ("LTIME", gbuf)) {
3401                         strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3402                         ap = rbuf;
3403                         }
3404                     else if (!strcmp ("CTIME", gbuf)) {
3405                         strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3406                         ap = rbuf;
3407                         }
3408                     /* Separate Date/Time info */
3409                     else if (!strcmp ("DATE_YYYY", gbuf)) {/* Year (0000-9999) */
3410                         strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3411                         ap = rbuf;
3412                         }
3413                     else if (!strcmp ("DATE_YY", gbuf)) {/* Year (00-99) */
3414                         strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3415                         ap = rbuf;
3416                         }
3417                     else if (!strcmp ("DATE_YC", gbuf)) {/* Century (year/100) */
3418                         (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3419                         ap = rbuf;
3420                         }
3421                     else if ((!strcmp ("DATE_19XX_YY", gbuf)) || /* Year with same calendar */
3422                              (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3423                         int year = tmnow->tm_year + 1900;
3424                         int days = year - 2001;
3425                         int leaps = days/4 - days/100 + days/400;
3426                         int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3427                         int selector = ((days + leaps + 7) % 7) + lyear * 7;
3428                         static int years[] = {90, 91, 97, 98, 99, 94, 89,
3429                                               96, 80, 92, 76, 88, 72, 84};
3430                         int cal_year = years[selector];
3431 
3432                         if (!strcmp ("DATE_19XX_YY", gbuf))
3433                             (void)sprintf (rbuf, "%d", cal_year);        /* 2 digit year */
3434                         else
3435                             (void)sprintf (rbuf, "%d", cal_year + 1900); /* 4 digit year */
3436                         ap = rbuf;
3437                         }
3438                     else if (!strcmp ("DATE_MM", gbuf)) {/* Month number (01-12) */
3439                         strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3440                         ap = rbuf;
3441                         }
3442                     else if (!strcmp ("DATE_MMM", gbuf)) {/* Month number (01-12) */
3443                         strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3444                         ap = rbuf;
3445                         }
3446                     else if (!strcmp ("DATE_DD", gbuf)) {/* Day of Month (01-31) */
3447                         strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3448                         ap = rbuf;
3449                         }
3450                     else if (!strcmp ("DATE_D", gbuf)) { /* ISO 8601 weekday number (1-7) */
3451                         (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3452                         ap = rbuf;
3453                         }
3454                     else if ((!strcmp ("DATE_WW", gbuf)) ||   /* ISO 8601 week number (01-53) */
3455                              (!strcmp ("DATE_WYYYY", gbuf))) {/* ISO 8601 week year number (0000-9999) */
3456                         int iso_yr = tmnow->tm_year + 1900;
3457                         int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3458 
3459                         if (iso_wk == 0) {
3460                             iso_yr = iso_yr - 1;
3461                             tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);  /* Adjust for Leap Year (Correct thru 2099) */
3462                             iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3463                             }
3464                         else
3465                             if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3466                                 ++iso_yr;
3467                                 iso_wk = 1;
3468                                 }
3469                         if (!strcmp ("DATE_WW", gbuf))
3470                             (void)sprintf (rbuf, "%02d", iso_wk);
3471                         else
3472                             (void)sprintf (rbuf, "%04d", iso_yr);
3473                         ap = rbuf;
3474                         }
3475                     else if (!strcmp ("DATE_JJJ", gbuf)) {/* day of year (001-366) */
3476                         strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3477                         ap = rbuf;
3478                         }
3479                     else if (!strcmp ("TIME_HH", gbuf)) {/* Hour of day (00-23) */
3480                         strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3481                         ap = rbuf;
3482                         }
3483                     else if (!strcmp ("TIME_MM", gbuf)) {/* Minute of hour (00-59) */
3484                         strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3485                         ap = rbuf;
3486                         }
3487                     else if (!strcmp ("TIME_SS", gbuf)) {/* Second of minute (00-59) */
3488                         strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3489                         ap = rbuf;
3490                         }
3491                     else if (!strcmp ("STATUS", gbuf)) {
3492                         (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3493                         ap = rbuf;
3494                         }
3495                     else if (!strcmp ("TSTATUS", gbuf)) {
3496                         (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3497                         ap = rbuf;
3498                         }
3499                     else if (!strcmp ("SIM_VERIFY", gbuf)) {
3500                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3501                         ap = rbuf;
3502                         }
3503                     else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3504                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3505                         ap = rbuf;
3506                         }
3507                     else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3508                         (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3509                         ap = rbuf;
3510                         }
3511                     else if (!strcmp ("SIM_QUIET", gbuf)) {
3512                         (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3513                         ap = rbuf;
3514                         }
3515                     else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3516                         (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3517                         ap = rbuf;
3518                         }
3519                     else if (!strcmp ("HOSTID", gbuf)) {
3520 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3521                         (void)sprintf (rbuf, "%ld", (long)gethostid());
3522 #else
3523                         (void)sprintf (rbuf, "00000000");
3524 #endif /* if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) */
3525                         ap = rbuf;
3526                         }
3527                     else if (!strcmp ("UID", gbuf)) {
3528 #if defined(HAVE_UNISTD)
3529                         (void)sprintf (rbuf, "%ld", (long)getuid());
3530 #else
3531                         (void)sprintf (rbuf, "0");
3532 #endif /* if defined(HAVE_UNISTD) */
3533                         ap = rbuf;
3534                         }
3535                     else if (!strcmp ("GID", gbuf)) {
3536 #if defined(HAVE_UNISTD)
3537                         (void)sprintf (rbuf, "%ld", (long)getgid());
3538 #else
3539                         (void)sprintf (rbuf, "0");
3540 #endif /* if defined(HAVE_UNISTD) */
3541                         ap = rbuf;
3542                         }
3543                     else if (!strcmp ("EUID", gbuf)) {
3544 #if defined(HAVE_UNISTD)
3545                         (void)sprintf (rbuf, "%ld", (long)geteuid());
3546 #else
3547                         (void)sprintf (rbuf, "0");
3548 #endif /* if defined(HAVE_UNISTD) */
3549                         ap = rbuf;
3550                         }
3551                     else if (!strcmp ("EGID", gbuf)) {
3552 #if defined(HAVE_UNISTD)
3553                         (void)sprintf (rbuf, "%ld", (long)getegid());
3554 #else
3555                         (void)sprintf (rbuf, "0");
3556 #endif /* if defined(HAVE_UNISTD) */
3557                         ap = rbuf;
3558                         }
3559                     else if (!strcmp ("PID", gbuf)) {
3560 #if defined(HAVE_UNISTD)
3561                         (void)sprintf (rbuf, "%ld", (long)_sir_getpid());
3562 #else
3563                         (void)sprintf (rbuf, "0");
3564 #endif /* if defined(HAVE_UNISTD) */
3565                         ap = rbuf;
3566                         }
3567                     else if (!strcmp ("PPID", gbuf)) {
3568 #if defined(HAVE_UNISTD)
3569                         (void)sprintf (rbuf, "%ld", (long)getppid());
3570 #else
3571                         (void)sprintf (rbuf, "0");
3572 #endif /* if defined(HAVE_UNISTD) */
3573                         ap = rbuf;
3574                         }
3575                     else if (!strcmp ("PGID", gbuf)) {
3576 #if defined(HAVE_UNISTD)
3577                         (void)sprintf (rbuf, "%ld", (long)getpgid(_sir_getpid()));
3578 #else
3579                         (void)sprintf (rbuf, "0");
3580 #endif /* if defined(HAVE_UNISTD) */
3581                         ap = rbuf;
3582                         }
3583                     else if (!strcmp ("SID", gbuf)) {
3584 #if defined(HAVE_UNISTD)
3585                         (void)sprintf (rbuf, "%ld", (long)getsid(_sir_getpid()));
3586 #else
3587                         (void)sprintf (rbuf, "0");
3588 #endif /* if defined(HAVE_UNISTD) */
3589                         ap = rbuf;
3590                         }
3591                     else if (!strcmp ("ENDIAN", gbuf)) {
3592 #if ( defined(DECLITEND) && DECLITEND == 1 )
3593                         (void)sprintf (rbuf, "LITTLE");
3594 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3595                         (void)sprintf (rbuf, "BIG");
3596 #else
3597                         (void)sprintf (rbuf, "UNKNOWN");
3598 #endif /* if ( defined(DECLITEND) && DECLITEND == 1 ) */
3599                         ap = rbuf;
3600                         }
3601                     else if (!strcmp("SIM_NAME", gbuf)) {
3602                         (void)sprintf (rbuf, "%s", sim_name);
3603                         ap = rbuf;
3604                         }
3605                     else if (!strcmp("SIM_VERSION", gbuf)) {
3606 #if defined(VER_H_GIT_VERSION)
3607                         (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3608 #else
3609                         (void)sprintf (rbuf, "UNKNOWN");
3610 #endif /* if defined(VER_H_GIT_VERSION) */
3611                         ap = rbuf;
3612                         }
3613                     else if (!strcmp("SIM_HASH", gbuf)) {
3614 #if defined(VER_H_GIT_HASH)
3615                         (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3616 #else
3617                         (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3618 #endif /* if defined(VER_H_GIT_HASH) */
3619                         ap = rbuf;
3620                         }
3621                     else if (!strcmp("SIM_RELT", gbuf)) {
3622 #if defined(VER_H_GIT_RELT)
3623                         (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3624 #else
3625                         (void)sprintf (rbuf, "X");
3626 #endif /* if defined(VER_H_GIT_RELT) */
3627                         ap = rbuf;
3628                         }
3629                     else if (!strcmp("SIM_DATE", gbuf)) {
3630 #if defined(VER_H_GIT_DATE)
3631                         (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3632 #else
3633                         (void)sprintf (rbuf, "UNKNOWN");
3634 #endif /* if defined(VER_H_GIT_DATE) */
3635                         ap = rbuf;
3636                         }
3637                     else if ((!strcmp("CORES", gbuf)) ||
3638                              (!strcmp("SIM_CORES", gbuf))) {
3639                         (void)sprintf(rbuf, "%u", (ncores >= 1 && nprocs >= 1) ? ((ncores > nprocs) ? nprocs : ncores) : 1);
3640                         ap = rbuf;
3641                         }
3642                     else if ((!strcmp("CPUS", gbuf)) ||
3643                              (!strcmp("SIM_PROCESSORS", gbuf))) {
3644                         (void)sprintf(rbuf, "%u", (nprocs < 2) ? 1U : nprocs);
3645                         ap = rbuf;
3646                         }
3647                     }
3648                 }
3649             if (ap) {                                   /* non-null arg? */
3650                 while (*ap && (op < oend))              /* copy the argument */
3651                     *op++ = *ap++;
3652                 }
3653             }
3654         else
3655             *op++ = *ip++;
3656     }
3657 *op = 0;                                                /* term buffer */
3658 strcpy (instr, tmpbuf);
3659 FREE (tmpbuf);
3660 return;
3661 }
3662 
3663 static
3664 int sim_cmp_string (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help] */
3665 {
3666 long int v1, v2;
3667 char *ep1, *ep2;
3668 
3669 v1 = strtol(s1+1, &ep1, 0);
3670 v2 = strtol(s2+1, &ep2, 0);
3671 if ((ep1 != s1 + strlen (s1) - 1) ||
3672     (ep2 != s2 + strlen (s2) - 1))
3673     return strcmp (s1, s2);
3674 if (v1 == v2)
3675     return 0;
3676 if (v1 < v2)
3677     return -1;
3678 return 1;
3679 }
3680 
3681 /* Assert command */
3682 
3683 t_stat assert_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3684 {
3685 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3686 CONST char *tptr, *gptr;
3687 REG *rptr;
3688 uint32 idx = 0;
3689 t_value val;
3690 t_stat r;
3691 t_bool Not = FALSE;
3692 t_bool result;
3693 t_addr addr = 0;
3694 t_stat reason = SCPE_AFAIL; /* default fail reason */
3695 
3696 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3697                                                         /* get sw, default */
3698 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3699 # pragma diagnostic push
3700 # pragma diag_suppress = integer_sign_change
3701 #endif
3702 sim_stabr.boolop = sim_staba.boolop = -1;               /* no relational op dflt */
3703 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3704 # pragma diagnostic pop
3705 #endif
3706 if (*cptr == 0)                                         /* must be more */
3707     return SCPE_2FARG;
3708 tptr = get_glyph (cptr, gbuf, 0);                       /* get token */
3709 if (!strcmp (gbuf, "NOT")) {                            /* Conditional Inversion? */
3710     Not = TRUE;                                         /* remember that, and */
3711     cptr = (CONST char *)tptr;
3712     }
3713 if (*cptr == '"') {                                     /* quoted string comparison? */
3714     char op[CBUFSIZE];
3715     static struct {
3716         const char *op;
3717         int aval;
3718         int bval;
3719         t_bool invert;
3720         } *optr, compare_ops[] =
3721         {
3722             { "==",   0,  0, FALSE },
3723             { "EQU",  0,  0, FALSE },
3724             { "!=",   0,  0, TRUE  },
3725             { "NEQ",  0,  0, TRUE  },
3726             { "<",   -1, -1, FALSE },
3727             { "LSS", -1, -1, FALSE },
3728             { "<=",   0, -1, FALSE },
3729             { "LEQ",  0, -1, FALSE },
3730             { ">",    1,  1, FALSE },
3731             { "GTR",  1,  1, FALSE },
3732             { ">=",   0,  1, FALSE },
3733             { "GEQ",  0,  1, FALSE },
3734             { NULL }
3735         };
3736 
3737     tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3738                                                     /* get first string */
3739     if (!*tptr)
3740         return SCPE_2FARG;
3741     cptr += strlen (gbuf);
3742     while (sim_isspace (*cptr))                     /* skip spaces */
3743         ++cptr;
3744     (void)get_glyph (cptr, op, '"');
3745     for (optr = compare_ops; optr->op; optr++)
3746         if (0 == strcmp (op, optr->op))
3747             break;
3748     if (!optr->op)
3749         return sim_messagef (SCPE_ARG, "Invalid operator: %s\r\n", op);
3750     cptr += strlen (op);
3751     while (sim_isspace (*cptr))                         /* skip spaces */
3752         ++cptr;
3753     cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3754                                                         /* get second string */
3755     if (*cptr) {                                        /* more? */
3756         if (flag)                                       /* ASSERT has no more args */
3757             return SCPE_2MARG;
3758         }
3759     else {
3760         if (!flag)
3761             return SCPE_2FARG;                          /* IF needs actions! */
3762         }
3763     result = sim_cmp_string (gbuf, gbuf2);
3764     result = ((result == optr->aval) || (result == optr->bval));
3765     if (optr->invert)
3766         result = !result;
3767     }
3768 else {
3769     cptr = get_glyph (cptr, gbuf, 0);                   /* get register */
3770     rptr = find_reg (gbuf, &gptr, sim_dfdev);           /* parse register */
3771     if (rptr) {                                         /* got register? */
3772         if (*gptr == '[') {                             /* subscript? */
3773             if (rptr->depth <= 1)                       /* array register? */
3774                 return SCPE_ARG;
3775             idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */
3776             if ((gptr == tptr) || (*tptr++ != ']'))
3777                 return SCPE_ARG;
3778             gptr = tptr;                                /* update */
3779             }
3780         else idx = 0;                                   /* not array */
3781         if (idx >= rptr->depth)                         /* validate subscript */
3782             return SCPE_SUB;
3783         }
3784     else {                                              /* not reg, check for memory */
3785         if (sim_dfdev && sim_vm_parse_addr)             /* get addr */
3786             addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3787         else if (sim_dfdev) //-V547
3788             addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix); //-V547
3789         if (gbuf == gptr)                               /* error? */
3790             return SCPE_NXREG;
3791         }
3792     if (*gptr != 0)                                     /* more? must be search */
3793         (void)get_glyph (gptr, gbuf, 0);
3794     else {
3795         if (*cptr == 0)                                 /* must be more */
3796             return SCPE_2FARG;
3797         cptr = get_glyph (cptr, gbuf, 0);               /* get search cond */
3798         }
3799     if (*cptr) {                                        /* more? */
3800         if (flag)                                       /* ASSERT has no more args */
3801             return SCPE_2MARG;
3802         }
3803     else {
3804         if (!flag)
3805             return SCPE_2FARG;                          /* IF needs actions! */
3806         }
3807     if (rptr) {                                         /* Handle register case */
3808 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3809 # pragma diagnostic push
3810 # pragma diag_suppress = integer_sign_change
3811 #endif
3812         if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||  /* parse condition */
3813             (sim_stabr.boolop == -1))                   /* relational op reqd */
3814             return SCPE_MISVAL;
3815 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3816 # pragma diagnostic pop
3817 #endif
3818         val = get_rval (rptr, idx);                     /* get register value */
3819         result = test_search (&val, &sim_stabr);        /* test condition */
3820         }
3821     else {                                              /* Handle memory case */
3822 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3823 # pragma diagnostic push
3824 # pragma diag_suppress = integer_sign_change
3825 #endif
3826         if (sim_dfdev)
3827             if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||  /* parse condition */
3828                 (sim_staba.boolop == -1))                    /* relational op reqd */
3829                 return SCPE_MISVAL;
3830 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3831 # pragma diagnostic pop
3832 #endif
3833         if (sim_dfdev)
3834             reason = get_aval (addr, sim_dfdev, sim_dfunit); /* get data */
3835         if (reason != SCPE_OK)                          /* return if error */
3836             return reason;
3837         result = test_search (sim_eval, &sim_staba);    /* test condition */
3838         }
3839     }
3840 if (Not ^ result) {
3841     if (!flag)
3842         sim_brk_setact (cptr);                          /* set up IF actions */
3843     }
3844 else
3845     if (flag)
3846         return SCPE_AFAIL;                              /* return assert status */
3847 return SCPE_OK;
3848 }
3849 
3850 /* Send command */
3851 
3852 t_stat send_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3853 {
3854 char gbuf[CBUFSIZE];
3855 CONST char *tptr;
3856 uint8 dbuf[CBUFSIZE];
3857 uint32 dsize = 0;
3858 uint32 delay = 0;
3859 uint32 after = 0;
3860 t_stat r;
3861 SEND *snd = NULL;
3862 
3863 GET_SWITCHES (cptr);                                    /* get switches */
3864 tptr = get_glyph (cptr, gbuf, ',');
3865 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3866     r = tmxr_locate_line_send (gbuf, &snd);
3867     if (r != SCPE_OK)
3868       return r;
3869     cptr = tptr;
3870     tptr = get_glyph (tptr, gbuf, ',');
3871     }
3872 else
3873     snd = sim_cons_get_send ();
3874 
3875 while (*cptr) {
3876     if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3877         delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3878         if (r != SCPE_OK)
3879             return sim_messagef (SCPE_ARG, "Invalid Delay Value\r\n");
3880         cptr = tptr;
3881         tptr = get_glyph (cptr, gbuf, ',');
3882         continue;
3883         }
3884     if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3885         after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3886         if (r != SCPE_OK)
3887             return sim_messagef (SCPE_ARG, "Invalid After Value\r\n");
3888         cptr = tptr;
3889         tptr = get_glyph (cptr, gbuf, ',');
3890         continue;
3891         }
3892     if ((*cptr == '"') || (*cptr == '\''))
3893         break;
3894     return SCPE_ARG;
3895     }
3896 if (*cptr) {
3897     if ((*cptr != '"') && (*cptr != '\'')) //-V560
3898         return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
3899     cptr = get_glyph_quoted (cptr, gbuf, 0);
3900     if (*cptr != '\0')
3901         return SCPE_2MARG;                  /* No more arguments */
3902 
3903     if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3904         return sim_messagef (SCPE_ARG, "Invalid String\r\n");
3905     }
3906 if ((dsize == 0) && (delay == 0) && (after == 0))
3907     return SCPE_2FARG;
3908 return sim_send_input (snd, dbuf, dsize, after, delay);
3909 }
3910 
3911 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3912 {
3913 char gbuf[CBUFSIZE];
3914 CONST char *tptr;
3915 t_stat r;
3916 SEND *snd = NULL;
3917 
3918 tptr = get_glyph (cptr, gbuf, ',');
3919 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3920     r = tmxr_locate_line_send (gbuf, &snd);
3921     if (r != SCPE_OK)
3922       return r;
3923     cptr = tptr;
3924     }
3925 else
3926     snd = sim_cons_get_send ();
3927 if (*cptr)
3928     return SCPE_2MARG;
3929 return sim_show_send_input (st, snd);
3930 }
3931 
3932 t_stat expect_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3933 {
3934 char gbuf[CBUFSIZE];
3935 CONST char *tptr;
3936 EXPECT *exp = NULL;
3937 
3938 GET_SWITCHES (cptr);                                    /* get switches */
3939 tptr = get_glyph (cptr, gbuf, ',');
3940 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3941     cptr = tptr;
3942 } else {
3943     exp = sim_cons_get_expect ();
3944 }
3945 
3946 if (flag) {
3947     return sim_set_expect (exp, cptr);
3948 } else {
3949     if (exp == NULL) {
3950         exp = sim_cons_get_expect();
3951     }
3952     return sim_set_noexpect (exp, cptr);
3953 }
3954 }
3955 
3956 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3957 {
3958 char gbuf[CBUFSIZE];
3959 CONST char *tptr;
3960 EXPECT *exp = NULL;
3961 t_stat r;
3962 
3963 tptr = get_glyph (cptr, gbuf, ',');
3964 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3965     r = tmxr_locate_line_expect (gbuf, &exp);
3966     if (r != SCPE_OK)
3967         return r;
3968     cptr = tptr;
3969     }
3970 else
3971     exp = sim_cons_get_expect ();
3972 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3973     return SCPE_ARG;            /* String must be quote delimited */
3974 tptr = get_glyph_quoted (cptr, gbuf, 0);
3975 if (*tptr != '\0')
3976     return SCPE_2MARG;          /* No more arguments */
3977 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3978     return SCPE_ARG;            /* String must be quote delimited */
3979 return sim_exp_show (st, exp, gbuf);
3980 }
3981 
3982 /* Goto command */
3983 
3984 t_stat goto_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3985 {
3986 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3987 const char *cptr;
3988 long fpos;
3989 int32 saved_do_echo = sim_do_echo;
3990 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3991 
3992 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
3993 (void)get_glyph (fcptr, gbuf1, 0);
3994 if ('\0' == gbuf1[0]) return SCPE_ARG;                  /* unspecified goto target */
3995 fpos = ftell(sim_gotofile);                             /* Save start position */
3996 rewind(sim_gotofile);                                   /* start search for label */
3997 sim_goto_line[sim_do_depth] = 0;                        /* reset line number */
3998 sim_do_echo = 0;                                        /* Don't echo while searching for label */
3999 while (1) {
4000     cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);/* get cmd line */
4001     if (cptr == NULL) break;                            /* exit on eof */
4002     sim_goto_line[sim_do_depth] += 1;                   /* record line number */
4003     if (*cptr == 0) continue;                           /* ignore blank */
4004     if (*cptr != ':') continue;                         /* ignore non-labels */
4005     ++cptr;                                             /* skip : */
4006     while (sim_isspace (*cptr)) ++cptr;                 /* skip blanks */
4007     cptr = get_glyph (cptr, gbuf, 0);                   /* get label glyph */
4008     if (0 == strcmp(gbuf, gbuf1)) {
4009         sim_brk_clract ();                              /* goto defangs current actions */
4010         sim_do_echo = saved_do_echo;                    /* restore echo mode */
4011         if (sim_do_echo)                                /* echo if -v */
4012             sim_printf("%s> %s\r\n", do_position(), cbuf);
4013         return SCPE_OK;
4014         }
4015     }
4016 sim_do_echo = saved_do_echo;                       /* restore echo mode         */
4017 fseek(sim_gotofile, fpos, SEEK_SET);               /* restore start position    */
4018 sim_goto_line[sim_do_depth] = saved_goto_line;     /* restore start line number */
4019 return SCPE_ARG;
4020 }
4021 
4022 /* Return command */
4023 
4024 /* The return command is invalid unless encountered in a do_cmd context,    */
4025 /* and in that context, it is handled as a special case inside of do_cmd()  */
4026 /* and not dispatched here, so if we get here a return has been issued from */
4027 /* interactive input */
4028 
4029 t_stat return_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4030 {
4031 return SCPE_UNK;                                 /* only valid inside of do_cmd */
4032 }
4033 
4034 /* Shift command */
4035 
4036 /* The shift command is invalid unless encountered in a do_cmd context,    */
4037 /* and in that context, it is handled as a special case inside of do_cmd() */
4038 /* and not dispatched here, so if we get here a shift has been issued from */
4039 /* interactive input (it is not valid interactively since it would have to */
4040 /* mess with the program's argv which is owned by the C runtime library    */
4041 
4042 t_stat shift_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4043 {
4044 return SCPE_UNK;                                 /* only valid inside of do_cmd */
4045 }
4046 
4047 /* Call command */
4048 
4049 /* The call command is invalid unless encountered in a do_cmd context,     */
4050 /* and in that context, it is handled as a special case inside of do_cmd() */
4051 /* and not dispatched here, so if we get here a call has been issued from  */
4052 /* interactive input                                                       */
4053 
4054 t_stat call_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4055 {
4056 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
4057 const char *cptr;
4058 
4059 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
4060 cptr = get_glyph (fcptr, gbuf, 0);
4061 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified goto target */
4062 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
4063 sim_switches |= SWMASK ('O');                           /* inherit ON state and actions */
4064 return do_cmd_label (flag, cbuf, gbuf);
4065 }
4066 
4067 /* On command */
4068 
4069 t_stat on_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4070 {
4071 char gbuf[CBUFSIZE];
4072 t_stat cond;
4073 
4074 cptr = get_glyph (cptr, gbuf, 0);
4075 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified condition */
4076 if (0 == strcmp("ERROR", gbuf))
4077     cond = 0;
4078 else
4079     if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4080         return SCPE_ARG;
4081 if ((NULL == cptr) || ('\0' == *cptr)) {                /* Empty Action */
4082     FREE(sim_on_actions[sim_do_depth][cond]);           /* Clear existing condition */
4083     sim_on_actions[sim_do_depth][cond] = NULL; }
4084 else {
4085     sim_on_actions[sim_do_depth][cond] =
4086         (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4087     if (!sim_on_actions[sim_do_depth][cond])
4088       {
4089         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4090                        __func__, __FILE__, __LINE__);
4091 #if defined(USE_BACKTRACE)
4092 # if defined(SIGUSR2)
4093         (void)raise(SIGUSR2);
4094         /*NOTREACHED*/ /* unreachable */
4095 # endif /* if defined(SIGUSR2) */
4096 #endif /* if defined(USE_BACKTRACE) */
4097         abort();
4098       }
4099     strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4100     }
4101 return SCPE_OK;
4102 }
4103 
4104 /* noop command */
4105 
4106 t_stat noop_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4107 {
4108 if (cptr && (*cptr != 0))                               /* now eol? */
4109     return SCPE_2MARG;
4110 return SCPE_OK;                                         /* we're happy doing nothing */
4111 }
4112 
4113 /* Set on/noon routine */
4114 
4115 t_stat set_on (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4116 {
4117 if ((flag) && (cptr) && (*cptr)) {                      /* Set ON with arg */
4118     char gbuf[CBUFSIZE];
4119 
4120     cptr = get_glyph (cptr, gbuf, 0);                   /* get command glyph */
4121     if (((MATCH_CMD(gbuf,"INHERIT")) &&
4122          (MATCH_CMD(gbuf,"NOINHERIT"))) || //-V600
4123         (*cptr))
4124         return SCPE_2MARG;
4125     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT"))) //-V560
4126         sim_on_inherit = 1;
4127     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT"))) //-V560
4128         sim_on_inherit = 0;
4129     return SCPE_OK;
4130     }
4131 if (cptr && (*cptr != 0))                               /* now eol? */
4132     return SCPE_2MARG;
4133 sim_on_check[sim_do_depth] = flag;
4134 if ((sim_do_depth != 0) &&
4135     (NULL == sim_on_actions[sim_do_depth][0])) {        /* default handler set? */
4136       sim_on_actions[sim_do_depth][0] =                 /* No, so make "RETURN" */
4137           (char *)malloc(1+strlen("RETURN"));           /* be the default action */
4138       if (sim_on_actions[sim_do_depth][0] == NULL)
4139       {
4140           (void)sir_emerg ("FATAL: Out of memory! Aborting at %s[%s:%d]",
4141                            __func__, __FILE__, __LINE__);
4142 #if defined(USE_BACKTRACE)
4143 # if defined(SIGUSR2)
4144           (void)raise(SIGUSR2);
4145           /*NOTREACHED*/ /* unreachable */
4146 # endif /* if defined(SIGUSR2) */
4147 #endif /* if defined(USE_BACKTRACE) */
4148           abort();
4149       }
4150       strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4151     }
4152 if ((sim_do_depth != 0) &&
4153     (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {/* handler set for AFAIL? */
4154     sim_on_actions[sim_do_depth][SCPE_AFAIL] =           /* No, so make "RETURN" */
4155         (char *)malloc(1+strlen("RETURN"));              /* be the action */
4156       if (sim_on_actions[sim_do_depth][SCPE_AFAIL] == NULL)
4157       {
4158           (void)sir_emerg ("FATAL: Out of memory! Aborting at %s[%s:%d]",
4159                            __func__, __FILE__, __LINE__);
4160 #if defined(USE_BACKTRACE)
4161 # if defined(SIGUSR2)
4162           (void)raise(SIGUSR2);
4163           /*NOTREACHED*/ /* unreachable */
4164 # endif /* if defined(SIGUSR2) */
4165 #endif /* if defined(USE_BACKTRACE) */
4166           abort();
4167       }
4168     strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4169     }
4170 return SCPE_OK;
4171 }
4172 
4173 /* Set verify/noverify routine */
4174 
4175 t_stat set_verify (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4176 {
4177 if (cptr && (*cptr != 0))                               /* now eol? */
4178     return SCPE_2MARG;
4179 if (flag == sim_do_echo)                                /* already set correctly? */
4180     return SCPE_OK;
4181 sim_do_echo = flag;
4182 return SCPE_OK;
4183 }
4184 
4185 /* Set message/nomessage routine */
4186 
4187 t_stat set_message (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4188 {
4189 if (cptr && (*cptr != 0))                               /* now eol? */
4190     return SCPE_2MARG;
4191 if (flag == sim_show_message)                           /* already set correctly? */
4192     return SCPE_OK;
4193 sim_show_message = flag;
4194 return SCPE_OK;
4195 }
4196 
4197 /* Set localopc/nolocalopc routine */
4198 
4199 t_stat set_localopc (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4200 {
4201 if (cptr && (*cptr != 0))                               /* now eol? */
4202     return SCPE_2MARG;
4203 if (flag == sim_localopc)                               /* already set correctly? */
4204     return SCPE_OK;
4205 sim_localopc = flag;
4206 return SCPE_OK;
4207 }
4208 /* Set quiet/noquiet routine */
4209 
4210 t_stat set_quiet (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4211 {
4212 if (cptr && (*cptr != 0))                               /* now eol? */
4213     return SCPE_2MARG;
4214 if (flag == sim_quiet)                                  /* already set correctly? */
4215     return SCPE_OK;
4216 sim_quiet = flag;
4217 return SCPE_OK;
4218 }
4219 
4220 /* Set environment routine */
4221 
4222 t_stat sim_set_environment (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4223 {
4224 char varname[CBUFSIZE];
4225 
4226 if ((NULL == cptr) || (*cptr == 0))                            /* now eol? */
4227     return SCPE_2FARG;
4228 cptr = get_glyph (cptr, varname, '=');                  /* get environment variable name */
4229 setenv(varname, cptr, 1);
4230 return SCPE_OK;
4231 }
4232 
4233 /* Set command */
4234 
4235 t_stat set_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4236 {
4237 uint32 lvl = 0;
4238 t_stat r;
4239 char gbuf[CBUFSIZE], *cvptr;
4240 CONST char *svptr;
4241 DEVICE *dptr;
4242 UNIT *uptr;
4243 MTAB *mptr;
4244 CTAB *gcmdp;
4245 C1TAB *ctbr = NULL, *glbr;
4246 
4247 GET_SWITCHES (cptr);                                    /* get switches */
4248 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
4249     return SCPE_2FARG;
4250 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get glob/dev/unit */
4251 
4252 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4253     uptr = dptr->units;                                 /* first unit */
4254     ctbr = set_dev_tab;                                 /* global table */
4255     lvl = MTAB_VDV;                                     /* device match */
4256     GET_SWITCHES (cptr);                                /* get more switches */
4257     }
4258 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4259     if (uptr == NULL)                                   /* invalid unit */
4260         return SCPE_NXUN;
4261     ctbr = set_unit_tab;                                /* global table */
4262     lvl = MTAB_VUN;                                     /* unit match */
4263     GET_SWITCHES (cptr);                                /* get more switches */
4264     }
4265 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {    /* global? */
4266     GET_SWITCHES (cptr);                                /* get more switches */
4267     return gcmdp->action (gcmdp->arg, cptr);            /* do the rest */
4268     }
4269 else {
4270     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4271         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4272             *cvptr++ = 0;
4273         for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4274             if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4275                 dptr = sim_dflt_dev;
4276                 cptr = svptr;
4277                 while (sim_isspace(*cptr))
4278                     ++cptr;
4279                 break;
4280                 }
4281             }
4282         }
4283     if (!dptr)
4284         return SCPE_NXDEV;                              /* no match */
4285     lvl = MTAB_VDV;                                     /* device match */
4286     uptr = dptr->units;                                 /* first unit */
4287     }
4288 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4289     return SCPE_2FARG;
4290 GET_SWITCHES (cptr);                                    /* get more switches */
4291 
4292 while (*cptr != 0) {                                    /* do all mods */
4293     cptr = get_glyph (svptr = cptr, gbuf, ',');         /* get modifier */
4294     if (0 == strcmp (gbuf, ";"))
4295         break;
4296     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4297         *cvptr++ = 0;
4298     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4299         if ((mptr->mstring) &&                          /* match string */
4300             (MATCH_CMD (gbuf, mptr->mstring) == 0)) {   /* matches option? */
4301             if (mptr->mask & MTAB_XTD) {                /* extended? */
4302                 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4303                     return SCPE_ARG;
4304                 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4305                     return SCPE_UDIS;                   /* unit disabled? */
4306                 if (mptr->valid) {                      /* validation rtn? */
4307                     if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4308                         svptr = get_glyph_quoted (svptr, gbuf, ',');
4309                         if ((cvptr = strchr (gbuf, '='))) {
4310                             *cvptr++ = 0;
4311                             cptr = svptr;
4312                             }
4313                         }
4314                     else {
4315                         if (cvptr && MODMASK(mptr,MTAB_NC)) {
4316                             (void)get_glyph_nc (svptr, gbuf, ',');
4317                             if ((cvptr = strchr (gbuf, '=')))
4318                                 *cvptr++ = 0;
4319                             }
4320                         }
4321                     r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4322                     if (r != SCPE_OK)
4323                         return r;
4324                     }
4325                 else if (!mptr->desc)                   /* value desc? */
4326                     break;
4327                 else if (cvptr)                         /* = value? */
4328                     return SCPE_ARG;
4329                 else *((int32 *) mptr->desc) = mptr->match;
4330                 }                                       /* end if xtd */
4331             else {                                      /* old style */
4332                 if (cvptr)                              /* = value? */
4333                     return SCPE_ARG;
4334                 if (uptr->flags & UNIT_DIS)             /* disabled? */
4335                      return SCPE_UDIS;
4336                 if ((mptr->valid) &&                    /* invalid? */
4337                     ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4338                     return r;
4339                 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4340                     (mptr->match & mptr->mask);         /* set new value */
4341                 }                                       /* end else xtd */
4342             break;                                      /* terminate for */
4343             }                                           /* end if match */
4344         }                                               /* end for */
4345     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4346         if ((glbr = find_c1tab (ctbr, gbuf))) {         /* global match? */
4347             r = glbr->action (dptr, uptr, glbr->arg, cvptr);    /* do global */
4348             if (r != SCPE_OK)
4349                 return r;
4350             }
4351         else if (!dptr->modifiers)                      /* no modifiers? */
4352             return SCPE_NOPARAM;
4353         else return SCPE_NXPAR;
4354         }                                               /* end if no mat */
4355     }                                                   /* end while */
4356 return SCPE_OK;                                         /* done all */
4357 }
4358 
4359 /* Match CTAB/CTAB1 name */
4360 
4361 CTAB *find_ctab (CTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4362 {
4363 if (!tab)
4364     return NULL;
4365 for (; tab->name != NULL; tab++) {
4366     if (MATCH_CMD (gbuf, tab->name) == 0)
4367         return tab;
4368     }
4369 return NULL;
4370 }
4371 
4372 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4373 {
4374 if (!tab)
4375     return NULL;
4376 for (; tab->name != NULL; tab++) {
4377     if (MATCH_CMD (gbuf, tab->name) == 0)
4378         return tab;
4379     }
4380 return NULL;
4381 }
4382 
4383 /* Set device data radix routine */
4384 
4385 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4386 {
4387 if (cptr)
4388     return SCPE_ARG;
4389 dptr->dradix = flag & 037;
4390 return SCPE_OK;
4391 }
4392 
4393 /* Set device enabled/disabled routine */
4394 
4395 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4396 {
4397 UNIT *up;
4398 uint32 i;
4399 
4400 if (cptr)
4401     return SCPE_ARG;
4402 if ((dptr->flags & DEV_DISABLE) == 0)                   /* allowed? */
4403     return SCPE_NOFNC;
4404 if (flag) {                                             /* enable? */
4405     if ((dptr->flags & DEV_DIS) == 0)                   /* already enb? ok */
4406         return SCPE_OK;
4407     dptr->flags = dptr->flags & ~DEV_DIS;               /* no, enable */
4408     }
4409 else {
4410     if (dptr->flags & DEV_DIS)                          /* already dsb? ok */
4411         return SCPE_OK;
4412     for (i = 0; i < dptr->numunits; i++) {              /* check units */
4413         up = (dptr->units) + i;                         /* att or active? */
4414         if ((up->flags & UNIT_ATT) || sim_is_active (up))
4415             return SCPE_NOFNC;                          /* can't do it */
4416         }
4417     dptr->flags = dptr->flags | DEV_DIS;                /* disable */
4418     }
4419 if (dptr->reset)                                        /* reset device */
4420     return dptr->reset (dptr);
4421 else return SCPE_OK;
4422 }
4423 
4424 /* Set unit enabled/disabled routine */
4425 
4426 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4427 {
4428 if (cptr)
4429     return SCPE_ARG;
4430 if (!(uptr->flags & UNIT_DISABLE))                      /* allowed? */
4431     return SCPE_NOFNC;
4432 if (flag)                                               /* enb? enable */
4433     uptr->flags = uptr->flags & ~UNIT_DIS;
4434 else {
4435     if ((uptr->flags & UNIT_ATT) ||                     /* dsb */
4436         sim_is_active (uptr))                           /* more tests */
4437         return SCPE_NOFNC;
4438     uptr->flags = uptr->flags | UNIT_DIS;               /* disable */
4439     }
4440 return SCPE_OK;
4441 }
4442 
4443 /* Set device debug enabled/disabled routine */
4444 
4445 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4446 {
4447 char gbuf[CBUFSIZE];
4448 DEBTAB *dep;
4449 
4450 if ((dptr->flags & DEV_DEBUG) == 0)
4451     return SCPE_NOFNC;
4452 if (cptr == NULL) {                                     /* no arguments? */
4453     dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;/* disable/enable w/o table */
4454     if (flag && dptr->debflags) {                       /* enable with table? */
4455         for (dep = dptr->debflags; dep->name != NULL; dep++)
4456             dptr->dctrl = dptr->dctrl | dep->mask;      /* set all */
4457         }
4458     return SCPE_OK;
4459     }
4460 if (dptr->debflags == NULL)                             /* must have table */
4461     return SCPE_ARG;
4462 while (*cptr) {
4463     cptr = get_glyph (cptr, gbuf, ';');                 /* get debug flag */
4464     for (dep = dptr->debflags; dep->name != NULL; dep++) {
4465         if (strcmp (dep->name, gbuf) == 0) {            /* match? */
4466             if (flag)
4467                 dptr->dctrl = dptr->dctrl | dep->mask;
4468             else dptr->dctrl = dptr->dctrl & ~dep->mask;
4469             break;
4470             }
4471         }                                               /* end for */
4472     if (dep->mask == 0)                                 /* no match? */
4473         return SCPE_ARG;
4474     }                                                   /* end while */
4475 return SCPE_OK;
4476 }
4477 
4478 /* Show command */
4479 
4480 t_stat show_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4481 {
4482 t_stat r = SCPE_IERR;
4483 
4484 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4485                                                         /* get sw, ofile */
4486 if (NULL == cptr)                                              /* error? */
4487     return r;
4488 if (sim_ofile) {                                        /* output file? */
4489     r = show_cmd_fi (sim_ofile, flag, cptr);            /* do show */
4490     fclose (sim_ofile);
4491     }
4492 else {
4493     r = show_cmd_fi (stdout, flag, cptr);               /* no, stdout, log */
4494     if (sim_log && (sim_log != stdout))
4495         show_cmd_fi (sim_log, flag, cptr);
4496     if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4497         show_cmd_fi (sim_deb, flag, cptr);
4498     }
4499 return r;
4500 }
4501 
4502 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4503 {
4504 uint32 lvl = 0xFFFFFFFF;
4505 char gbuf[CBUFSIZE], *cvptr;
4506 CONST char *svptr;
4507 DEVICE *dptr;
4508 UNIT *uptr;
4509 MTAB *mptr;
4510 SHTAB *shtb = NULL, *shptr;
4511 
4512 GET_SWITCHES (cptr);                                    /* get switches */
4513 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4514     return SCPE_2FARG;
4515 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get next glyph */
4516 
4517 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4518     uptr = dptr->units;                                 /* first unit */
4519     shtb = show_dev_tab;                                /* global table */
4520     lvl = MTAB_VDV;                                     /* device match */
4521     GET_SWITCHES (cptr);                                /* get more switches */
4522     }
4523 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4524     if (uptr == NULL)                                   /* invalid unit */
4525         return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\r\n", gbuf);
4526     if (uptr->flags & UNIT_DIS)                         /* disabled? */
4527         return sim_messagef (SCPE_UDIS, "Unit disabled: %s\r\n", gbuf);
4528     shtb = show_unit_tab;                               /* global table */
4529     lvl = MTAB_VUN;                                     /* unit match */
4530     GET_SWITCHES (cptr);                                /* get more switches */
4531     }
4532 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {  /* global? */
4533     GET_SWITCHES (cptr);                                /* get more switches */
4534     return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4535     }
4536 else {
4537     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4538         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4539             *cvptr++ = 0;
4540         for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4541             if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4542                  (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) || //-V600
4543                 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4544                 dptr = sim_dflt_dev;
4545                 lvl = MTAB_VDV;                         /* device match */
4546                 cptr = svptr;
4547                 while (sim_isspace(*cptr))
4548                     ++cptr;
4549                 break;
4550                 }
4551             }
4552         }
4553     if (!dptr) {
4554         if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))  /* global match? */
4555             return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4556         else
4557             return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\r\n", gbuf);/* no match */
4558         }
4559     }
4560 
4561 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) { /* now eol? */
4562     return (lvl == MTAB_VDV)?
4563         show_device (ofile, dptr, 0):
4564         show_unit (ofile, dptr, uptr, -1);
4565     }
4566 GET_SWITCHES (cptr);                                    /* get more switches */
4567 
4568 while (*cptr != 0) {                                    /* do all mods */
4569     cptr = get_glyph (cptr, gbuf, ',');                 /* get modifier */
4570     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4571         *cvptr++ = 0;
4572     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4573         if (((mptr->mask & MTAB_XTD)?                   /* right level? */
4574             ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4575             ((mptr->disp && mptr->pstring &&            /* named disp? */
4576             (MATCH_CMD (gbuf, mptr->pstring) == 0))
4577             )) {
4578             if (cvptr && !MODMASK(mptr,MTAB_SHP))
4579                 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\r\n", gbuf, cvptr);
4580             show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4581             break;
4582             }                                           /* end if */
4583         }                                               /* end for */
4584     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4585         if (shtb && (shptr = find_shtab (shtb, gbuf))) {/* global match? */
4586             t_stat r;
4587 
4588             r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4589             if (r != SCPE_OK)
4590                 return r;
4591             }
4592         else {
4593             if (!dptr->modifiers)                       /* no modifiers? */
4594                 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\r\n", dptr->name);
4595             else
4596                 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\r\n", gbuf);
4597             }
4598         }                                               /* end if */
4599     }                                                   /* end while */
4600 return SCPE_OK;
4601 }
4602 
4603 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4604 {
4605 if (!tab)
4606     return NULL;
4607 for (; tab->name != NULL; tab++) {
4608     if (MATCH_CMD (gbuf, tab->name) == 0)
4609         return tab;
4610     }
4611 return NULL;
4612 }
4613 
4614 /* Show device and unit */
4615 
4616 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4617 {
4618 uint32 j, udbl, ucnt;
4619 UNIT *uptr;
4620 int32 toks = 0;
4621 
4622 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4623 (void)fprintf (st, "%s", sim_dname (dptr));                   /* print dev name */
4624 if ((flag == 2) && dptr->description) {
4625     (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4626     }
4627 else {
4628     if ((sim_switches & SWMASK ('D')) && dptr->description)
4629         (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4630     }
4631 if (qdisable (dptr)) {                                  /* disabled? */
4632     (void)fprintf (st, "\tdisabled\r\n");
4633     return SCPE_OK;
4634     }
4635 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {    /* count units */
4636     uptr = dptr->units + j;
4637     if (!(uptr->flags & UNIT_DIS))                      /* count enabled units */
4638         ucnt++;
4639     else if (uptr->flags & UNIT_DISABLE)
4640         udbl++;                                         /* count user-disabled */
4641     }
4642 //show_all_mods (st, dptr, dptr->units, MTAB_VDV, &toks); /* show dev mods */
4643 if (dptr->numunits == 0) {
4644     // if (toks) //-V547
4645     //     (void)fprintf (st, "\r\n");
4646 }
4647  else
4648 {
4649     if (ucnt == 0) {
4650         fprint_sep (st, &toks);
4651         (void)fprintf (st, "all units disabled\r\n");
4652         }
4653     else if ((ucnt + udbl) == 1) {
4654         fprint_sep (st, &toks);
4655         (void)fprintf (st, " 1 unit\r\n");
4656         }
4657     else if ((ucnt > 1) || (udbl > 0)) {
4658         fprint_sep (st, &toks);
4659         (void)fprintf (st, "%2.d units\r\n", ucnt + udbl);
4660         }
4661     else
4662         if ((flag != 2) || !dptr->description || toks)
4663             (void)fprintf (st, "\r\n");
4664     toks = 0;
4665 }
4666 if (flag)                                               /* dev only? */
4667     return SCPE_OK;
4668 for (j = 0; j < dptr->numunits; j++) {                  /* loop thru units */
4669     uptr = dptr->units + j;
4670     if ((uptr->flags & UNIT_DIS) == 0)
4671         show_unit (st, dptr, uptr, ucnt + udbl);
4672     }
4673 }
4674 return SCPE_OK;
4675 }
4676 
4677 void fprint_sep (FILE *st, int32 *tokens)
     /* [previous][next][first][last][top][bottom][index][help] */
4678 {
4679 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4680 *tokens += 1;
4681 }
4682 
4683 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4684 {
4685 int32 u = (int32)(uptr - dptr->units);
4686 int32 toks = 0;
4687 
4688 if (flag > 1)
4689     (void)fprintf (st, "   %s%d\r\n", sim_dname (dptr), u);
4690 else if (flag < 0)
4691     (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4692 if (uptr->flags & UNIT_ATT) {
4693     fprint_sep (st, &toks);
4694     (void)fprintf (st, "status   : attached to %s", uptr->filename);
4695     if (uptr->flags & UNIT_RO)
4696         (void)fprintf (st, ", read only");
4697     }
4698 else {
4699     if (uptr->flags & UNIT_ATTABLE) {
4700         fprint_sep (st, &toks);
4701         (void)fprintf (st, "status   : not attached");
4702         }
4703     }
4704 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4705     fprint_sep (st, &toks);
4706     fprint_capac (st, dptr, uptr);
4707     }
4708 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);        /* show unit mods */
4709 if (toks || (flag < 0) || (flag > 1))
4710     (void)fprintf (st, "\r\n");
4711 return SCPE_OK;
4712 }
4713 
4714 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4715 {
4716 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4717 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4718 t_offset mval;
4719 t_offset psize = (t_offset)uptr->capac;
4720 char *scale, *width;
4721 
4722 if (sim_switches & SWMASK ('B'))
4723     kval = 1024;
4724 mval = kval * kval;
4725 if (dptr->flags & DEV_SECTORS) {
4726     kval = kval / 512;
4727     mval = mval / 512;
4728     }
4729 if ((dptr->dwidth / dptr->aincr) > 8)
4730     width = "W";
4731 else
4732     width = "B";
4733 if ((psize < (kval * 10)) &&
4734     (0 != (psize % kval))) {
4735     scale = "";
4736     }
4737 else if ((psize < (mval * 10)) &&
4738          (0 != (psize % mval))){
4739     scale = "K";
4740     psize = psize / kval;
4741     }
4742 else {
4743     scale = "M";
4744     psize = psize / mval;
4745     }
4746 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4747 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4748 return capac_buf;
4749 }
4750 
4751 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4752 {
4753 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4754 }
4755 
4756 /* Show <global name> processors  */
4757 
4758 extern void print_default_base_system_script (void);
4759 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4760 {
4761 #if !defined(PERF_STRIP)
4762   print_default_base_system_script();
4763 #endif /* if !defined(PERF_STRIP) */
4764   return 0;
4765 }
4766 
4767 static void printp (unsigned char * PROM, char * label, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4768   sim_printf (" %s ", label);
4769   sim_printf ("   %2d     %3o(8)     '", length, offset);
4770   for (int l = 0; l < length; l ++)
4771     {
4772       unsigned int byte = PROM[offset + l];
4773       if (byte == 255)
4774         {
4775           byte = ' ';
4776         }
4777       sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4778     }
4779   sim_printf ("'\r\n");
4780 }
4781 
4782 static void strip_spaces(char* str) {
     /* [previous][next][first][last][top][bottom][index][help] */
4783   int i, x;
4784   for (i=x=0; str[i]; ++i)
4785     {
4786       if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)]))) //-V781
4787         {
4788           str[x++] = str[i];
4789         }
4790     }
4791   str[x] = '\0';
4792   i = -1;
4793   x = 0;
4794   while (str[x] != '\0')
4795     {
4796       if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4797         {
4798           i=x;
4799         }
4800       x++;
4801     }
4802   str[i+1] = '\0';
4803 }
4804 
4805 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4806   char sx[1024];
4807   sx[1023] = '\0';
4808   unsigned int lastbyte = 0;
4809   for (int l = 0; l < length; l ++)
4810     {
4811       unsigned int byte = PROM[offset + l];
4812       if (byte == 255)
4813         {
4814           byte = 20;
4815         }
4816       if ((lastbyte != 20) && (byte != 20))
4817         {
4818           (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4819         }
4820       lastbyte = byte;
4821     }
4822   strip_spaces(sx);
4823   (void)fprintf (st, "%s", sx);
4824 }
4825 
4826 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4827 {
4828   unsigned char PROM[1024];
4829   setupPROM (0, PROM);
4830 
4831   sim_printf (" PROM size: %llu bytes\r\n",
4832               (long long unsigned)sizeof(PROM));
4833   sim_printf (" PROM initialization data:\r\n\r\n");
4834 
4835   sim_printf ("     Field Description      Length   Offset              Contents\r\n");
4836   sim_printf (" ========================= ======== ======== ==================================\r\n");
4837   sim_printf ("\r\n");
4838 
4839   //                      Field                 Offset       Length
4840   //             -------------------------    ----------   ----------
4841   printp (PROM, "CPU Model                ",       0,          11);
4842   printp (PROM, "CPU Serial               ",      11,          11);
4843   printp (PROM, "Ship Date                ",      22,           6);
4844   printp (PROM, "PROM Layout Version      ",      60,           1);
4845   printp (PROM, "Release Git Commit Date  ",      70,          10);
4846   printp (PROM, "Release Major            ",      80,           3);
4847   printp (PROM, "Release Minor            ",      83,           3);
4848   printp (PROM, "Release Patch            ",      86,           3);
4849   printp (PROM, "Release Iteration        ",      89,           3);
4850   printp (PROM, "Release Build Number     ",      92,           8);  /* Reserved */
4851   printp (PROM, "Release Type             ",     100,           1);
4852   printp (PROM, "Release Version Text     ",     101,          29);
4853   printp (PROM, "Build Architecture       ",     130,          20);
4854   printp (PROM, "Build Operating System   ",     150,          20);
4855   printp (PROM, "Target Architecture      ",     170,          20);
4856   printp (PROM, "Target Operating System  ",     190,          20);
4857 
4858   sim_printf("\r\n");
4859   return 0;
4860 }
4861 
4862 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4863 {
4864     (void)fprintf (st, "\r Build Information:\r\n");
4865 #if defined(BUILDINFO_scp)
4866     (void)fprintf (st, "\r\n      Compilation info: %s\r\n", BUILDINFO_scp );
4867 #else
4868     (void)fprintf (st, "\r\n      Compilation info: Not available\r\n" );
4869 #endif
4870 #if !defined(__CYGWIN__)
4871 # if !defined(__APPLE__)
4872 #  if !defined(_AIX)
4873 #   if !defined(__MINGW32__)
4874 #    if !defined(__MINGW64__)
4875 #     if !defined(CROSS_MINGW32)
4876 #      if !defined(CROSS_MINGW64)
4877 #       if !defined(_WIN32)
4878 #        if !defined(__HAIKU__)
4879 #         if !defined(__QNX__)
4880 #          if !defined(__FILC__)
4881     (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4882     if (dl_iterate_phdr_callback_called)
4883         (void)fprintf (st, "\r\n");
4884     dl_iterate_phdr_callback_called = 0;
4885 #          endif
4886 #         endif
4887 #        endif
4888 #       endif
4889 #      endif
4890 #     endif
4891 #    endif
4892 #   endif
4893 #  endif
4894 # endif
4895 #endif
4896 #if defined(UV_VERSION_MAJOR) && \
4897     defined(UV_VERSION_MINOR) && \
4898     defined(UV_VERSION_PATCH)
4899 # if defined(UV_VERSION_MAJOR)
4900 #  if !defined(UV_VERSION_MINOR) && \
4901       !defined(UV_VERSION_PATCH) && \
4902       !defined(UV_VERSION_SUFFIX)
4903     (void)fprintf (st, "\r\n    Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4904 #  endif /* if !defined(UV_VERSION_MINOR) && !defined(UV_VERSION_PATCH) && defined(UV_VERSION_SUFFIX) */
4905 #  if defined(UV_VERSION_MINOR)
4906 #   if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4907     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4908                    UV_VERSION_MINOR);
4909 #   endif /* if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX) */
4910 #   if defined(UV_VERSION_PATCH)
4911 #    if !defined(UV_VERSION_SUFFIX)
4912     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4913                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4914 #    endif /* if !defined(UV_VERSION_SUFFIX) */
4915 #    if defined(UV_VERSION_SUFFIX)
4916     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4917                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4918 #     if defined(UV_VERSION_IS_RELEASE)
4919 #      if UV_VERSION_IS_RELEASE == 1
4920 #       define UV_RELEASE_TYPE " (release)"
4921 #      endif /* if UV_VERSION_IS_RELEASE == 1 */
4922 #      if UV_VERSION_IS_RELEASE == 0
4923 #       define UV_RELEASE_TYPE "-dev"
4924 #      endif /* if UV_VERSION_IS_RELEASE == 0 */
4925 #      if !defined(UV_RELEASE_TYPE)
4926 #       define UV_RELEASE_TYPE ""
4927 #      endif /* if !defined(UV_RELEASE_TYPE) */
4928 #      if defined(UV_RELEASE_TYPE)
4929     (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4930 #      endif /* if defined(UV_RELEASE_TYPE) */
4931 #     endif /* if defined(UV_VERSION_IS_RELEASE) */
4932 #    endif /* if defined(UV_VERSION_SUFFIX) */
4933 #   endif /* if defined(UV_VERSION_PATCH) */
4934 #  endif /* if defined(UV_VERSION_MINOR) */
4935     unsigned int CurrentUvVersion = uv_version();
4936     if (CurrentUvVersion > 0)
4937         if (uv_version_string() != NULL)
4938             (void)fprintf (st, "; %s in use", uv_version_string());
4939 # endif /* if defined(UV_VERSION_MAJOR) */
4940 #else
4941     (void)fprintf (st, "\r\n    Event loop library: Using libuv (or compatible) library, unknown version");
4942 #endif /* if defined(UV_VERSION_MAJOR) &&  \
4943         *    defined(UV_VERSION_MINOR) &&  \
4944         *    defined(UV_VERSION_PATCH)     \
4945         */
4946     (void)fprintf (st, "\r\n   Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4947                    SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4948                    SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4949                    sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4950 #if defined(DECNUMBERLOC)
4951 # if defined(DECVERSION)
4952 #  if defined(DECVERSEXT)
4953     (void)fprintf (st, "\r\n          Math library: %s-%s", DECVERSION, DECVERSEXT);
4954 #  else
4955 #   if defined(DECNLAUTHOR)
4956     (void)fprintf (st, "\r\n          Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4957 #   else
4958     (void)fprintf (st, "\r\n          Math library: %s", DECVERSION);
4959 #   endif /* if defined(DECNLAUTHOR) */
4960 #  endif /* if defined(DECVERSEXT) */
4961 # else
4962     (void)fprintf (st, "\r\n          Math library: decNumber, unknown version");
4963 # endif /* if defined(DECVERSION) */
4964 #endif /* if defined(DECNUMBERLOC) */
4965 #if defined(LOCKLESS)
4966     (void)fprintf (st, "\r\n     Atomic operations: ");
4967 # if defined(AIX_ATOMICS)
4968     (void)fprintf (st, "C11 and IBM AIX-style");
4969 # elif defined(BSD_ATOMICS)
4970     (void)fprintf (st, "C11 and FreeBSD-style");
4971 # elif defined(GNU_ATOMICS)
4972     (void)fprintf (st, "C11 and GNU-style");
4973 # elif defined(SYNC_ATOMICS)
4974     (void)fprintf (st, "C11 and GNU sync-style");
4975 # elif defined(ISO_ATOMICS)
4976     (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4977 # elif defined(NT_ATOMICS)
4978     (void)fprintf (st, "C11 and Windows NT interlocked operations");
4979 # endif
4980 #endif /* if defined(LOCKLESS) */
4981     (void)fprintf (st, "\r\n          File locking: ");
4982 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4983     (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4984 #endif
4985 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4986     (void)fprintf (st, "POSIX-style fcntl() locking");
4987 #endif
4988 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4989     (void)fprintf (st, "BSD-style flock() locking");
4990 #endif
4991 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4992     (void)fprintf (st, "No file locking available");
4993 #endif
4994 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64) || defined(__CYGWIN__)
4995     (void)fprintf (st, "\r\n       Windows support: ");
4996 #endif
4997 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4998 # if defined(__MINGW64_VERSION_STR)
4999     (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
5000 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
5001     (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
5002 # else
5003     (void)fprintf (st, "Built with MinGW");
5004 # endif
5005 
5006 # if defined(MINGW_CRT)
5007     (void)fprintf (st, "; %s", MINGW_CRT);
5008 #  if !defined(_UCRT)
5009 #   if defined(__MSVCRT_VERSION__)
5010 #    if __MSVCRT_VERSION__ > 0x00
5011     (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
5012 #    endif
5013 #   endif
5014 #  else
5015 
5016     struct UCRTVersion ucrtversion;
5017     int result = GetUCRTVersion (&ucrtversion);
5018 
5019     if (result == 0)
5020       (void)fprintf (st, " %u.%u.%u.%u",
5021                      ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
5022                      ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
5023 #  endif
5024     (void)fprintf (st, " in use");
5025 # endif
5026 #elif defined(__CYGWIN__)
5027     struct utsname utsname;
5028     (void)fprintf (st, "Built with Cygwin %d.%d.%d",
5029                    CYGWIN_VERSION_DLL_MAJOR / 1000,
5030                    CYGWIN_VERSION_DLL_MAJOR % 1000,
5031                    CYGWIN_VERSION_DLL_MINOR);
5032     if (uname(&utsname) == 0)
5033       fprintf (st, "; %s in use", utsname.release);
5034 #endif
5035 
5036     (void)fprintf (st, "\r\n");
5037     return 0;
5038 }
5039 
5040 static void
5041 removehex(char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
5042 {
5043   if (!s) return;
5044 
5045   size_t len = strlen(s);
5046   for (size_t i = 0; i < len; i++) {
5047     if (s[i] != ' ')
5048      continue;
5049 
5050     if ((len - i) < 41)
5051       continue;
5052 
5053     size_t j;
5054     for (j = 1; j <= 40; j++) {
5055       unsigned char uc = (unsigned char)s[i + j];
5056       if (!isxdigit(uc))
5057         break;
5058     }
5059 
5060     if (j == 41) {
5061       memmove(&s[i], &s[i + 41], strlen(&s[i + 41]) + 1);
5062       return;
5063     }
5064   }
5065 }
5066 
5067 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5068 {
5069 const char *arch = "";
5070 char *whydirty = " ";
5071 int dirty = 0;
5072 
5073 if (cptr && (*cptr != 0))
5074     return SCPE_2MARG;
5075 if (flag) {
5076         (void)fprintf (st, " %s Simulator:", sim_name);
5077 #if defined(USE_DUMA)
5078 # undef NO_SUPPORT_VERSION
5079 # define NO_SUPPORT_VERSION 1
5080         nodist++;
5081 #endif /* if defined(USE_DUMA) */
5082 #if defined(NO_SUPPORT_VERSION) ||  \
5083     defined(WITH_SOCKET_DEV)    ||  \
5084     defined(WITH_ABSI_DEV)      ||  \
5085     defined(TESTING)            ||  \
5086     defined(ISOLTS)             ||  \
5087     defined(USE_DUMA)
5088 # if !defined(NO_SUPPORT_VERSION)
5089 #  define NO_SUPPORT_VERSION 1
5090 # endif /* if !defined(NO_SUPPORT_VERSION) */
5091 #endif
5092 #if defined(NO_SUPPORT_VERSION)
5093         dirty++;
5094 #endif
5095 #if defined(GENERATED_MAKE_VER_H)
5096 # if defined(VER_H_GIT_VERSION)
5097 
5098         /* Dirty if git source is dirty */
5099         if (strstr(VER_H_GIT_VERSION, "*"))
5100           {
5101                 dirty++;
5102           }
5103 
5104         /* Dirty if version contains "X", "D", "A", or "B" */
5105         if ((strstr(VER_H_GIT_VERSION, "X")) ||  \
5106             (strstr(VER_H_GIT_VERSION, "D")) ||  \
5107             (strstr(VER_H_GIT_VERSION, "A")) ||  \
5108             (strstr(VER_H_GIT_VERSION, "B")))
5109           {
5110                 dirty++;
5111           }
5112 
5113         /* Why? */
5114         if (dirty) //-V547
5115           {
5116             if ((strstr(VER_H_GIT_VERSION, "X")))
5117               {
5118                     whydirty = " ";
5119               }
5120             else if ((strstr(VER_H_GIT_VERSION, "D")))
5121               {
5122                     whydirty = " DEV ";
5123               }
5124             else if ((strstr(VER_H_GIT_VERSION, "A")))
5125               {
5126                     whydirty = " ALPHA ";
5127               }
5128             else if ((strstr(VER_H_GIT_VERSION, "B")))
5129               {
5130                     whydirty = " BETA ";
5131               }
5132           }
5133 
5134 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5135 #   if defined(VER_H_GIT_HASH)
5136 #    if VER_H_GIT_PATCH_INT < 1
5137     (void)fprintf (st, "\r\n   Version: %s (%ld-bit)\r\n    Commit: %s",
5138                    VER_H_GIT_VERSION,
5139                    (long)(CHAR_BIT*sizeof(void *)),
5140                    VER_H_GIT_HASH);
5141 #    else
5142 #     define NO_SUPPORT_VERSION 1
5143     (void)fprintf (st, "\r\n   Version: %s+%s (%ld-bit)\r\n    Commit: %s",
5144                    VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5145                    (long)(CHAR_BIT*sizeof(void *)),
5146                    VER_H_GIT_HASH);
5147 #    endif
5148 #   else
5149 #    if VER_H_GIT_PATCH_INT < 1
5150         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)",
5151                        VER_H_GIT_VERSION,
5152                        (long)(CHAR_BIT*sizeof(void *)));
5153 #    else
5154 #     define NO_SUPPORT_VERSION 1
5155         (void)fprintf (st, "\r\n   Version: %s+%s (%ld-bit)",
5156                        VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5157                        (long)(CHAR_BIT*sizeof(void *)));
5158 #    endif
5159 #   endif
5160 #  else
5161 #   if defined(VER_H_GIT_HASH)
5162         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)\r\n    Commit: %s",
5163                        VER_H_GIT_VERSION,
5164                        (long)(CHAR_BIT*sizeof(void *)),
5165                        VER_H_GIT_HASH);
5166 #   else
5167         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)",
5168                        VER_H_GIT_VERSION,
5169                        (long)(CHAR_BIT*sizeof(void *)));
5170 #   endif
5171 #  endif
5172 # endif
5173 #endif
5174 
5175 /* TESTING */
5176 #if defined(TESTING)
5177     (void)fprintf (st, "\r\n   Options: ");
5178 # if !defined(HAVE_DPSOPT)
5179 #  define HAVE_DPSOPT 1
5180 # endif
5181     (void)fprintf (st, "TESTING");
5182 #endif /* if defined(TESTING) */
5183 
5184 /* ISOLTS */
5185 #if defined(ISOLTS)
5186 # if defined(HAVE_DPSOPT)
5187     (void)fprintf (st, ", ");
5188 # else
5189     (void)fprintf (st, "\r\n   Options: ");
5190 # endif
5191 # if !defined(HAVE_DPSOPT)
5192 #  define HAVE_DPSOPT 1
5193 # endif
5194     (void)fprintf (st, "ISOLTS");
5195 #endif /* if defined(ISOLTS) */
5196 
5197 /* NEED_128 */
5198 #if defined(NEED_128)
5199 # if defined(HAVE_DPSOPT)
5200     (void)fprintf (st, ", ");
5201 # else
5202     (void)fprintf (st, "\r\n   Options: ");
5203 # endif
5204 # if !defined(HAVE_DPSOPT)
5205 #  define HAVE_DPSOPT 1
5206 # endif
5207     (void)fprintf (st, "NEED_128");
5208 #endif /* if defined(NEED_128) */
5209 
5210 /* NO_LOCKLESS */
5211 #if !defined(LOCKLESS)
5212 # if defined(HAVE_DPSOPT)
5213     (void)fprintf (st, ", ");
5214 # else
5215     (void)fprintf (st, "\r\n   Options: ");
5216 # endif
5217 # if !defined(HAVE_DPSOPT)
5218 #  define HAVE_DPSOPT 1
5219 # endif
5220     (void)fprintf (st, "NO_LOCKLESS");
5221 #endif /* if !defined(LOCKLESS) */
5222 
5223 /* PANEL68 */
5224 #if defined(PANEL68)
5225 # if defined(HAVE_DPSOPT)
5226     (void)fprintf (st, ", ");
5227 # else
5228     (void)fprintf (st, "\r\n Options: ");
5229 # endif
5230 # if !defined(HAVE_DPSOPT)
5231 #  define HAVE_DPSOPT 1
5232 # endif
5233     (void)fprintf (st, "PANEL68");
5234 #endif /* if defined(PANEL68) */
5235 
5236 /* ABSI */  /* XXX: Change to NO_ABSI once code is non-experimental */
5237 #if defined(WITH_ABSI_DEV)
5238 # if defined(HAVE_DPSOPT)
5239     (void)fprintf (st, ", ");
5240 # else
5241     (void)fprintf (st, "\r\n   Options: ");
5242 # endif
5243 # if !defined(HAVE_DPSOPT)
5244 #  define HAVE_DPSOPT 1
5245 # endif
5246     (void)fprintf (st, "ABSI");
5247 #endif /* if defined(WITH_ABSI_DEV) */
5248 
5249 /* SOCKET */  /* XXX: Change to !SOCKET once code is non-experimental */
5250 #if defined(WITH_SOCKET_DEV)
5251 # if defined(HAVE_DPSOPT)
5252     (void)fprintf (st, ", ");
5253 # else
5254     (void)fprintf (st, "\r\n   Options: ");
5255 # endif
5256 # if !defined(HAVE_DPSOPT)
5257 #  define HAVE_DPSOPT 1
5258 # endif
5259     (void)fprintf (st, "SOCKET");
5260 #endif /* if defined(WITH_SOCKET_DEV) */
5261 
5262 /* CHAOSNET */
5263 #if !defined(WITH_MGP_DEV)
5264 # if defined(HAVE_DPSOPT)
5265     (void)fprintf (st, ", ");
5266 # else
5267     (void)fprintf (st, "\r\n   Options: ");
5268 # endif
5269 # if !defined(HAVE_DPSOPT)
5270 #  define HAVE_DPSOPT 1
5271 # endif
5272     (void)fprintf (st, "NO_CHAOSNET");
5273 #endif /* if !defined(WITH_MGP_DEV) */
5274 
5275 /* INTERNET */
5276 #if !defined(WITH_NET_DEV)
5277 # if defined(HAVE_DPSOPT)
5278     (void)fprintf (st, ", ");
5279 # else
5280     (void)fprintf (st, "\r\n   Options: ");
5281 # endif
5282 # if !defined(HAVE_DPSOPT)
5283 #  define HAVE_DPSOPT 1
5284 # endif
5285     (void)fprintf (st, "NO_INTERNET");
5286 #endif /* if defined(WITH_NET_DEV) */
5287 
5288 /* DUMA */
5289 #if defined(USE_DUMA)
5290 # if defined(HAVE_DPSOPT)
5291     (void)fprintf (st, ", ");
5292 # else
5293     (void)fprintf (st, "\r\n   Options: ");
5294 # endif
5295 # if !defined(HAVE_DPSOPT)
5296 #  define HAVE_DPSOPT 1
5297 # endif
5298     (void)fprintf (st, "DUMA");
5299 #endif /* if defined(USE_DUMA) */
5300 
5301 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5302 # if defined(NO_SUPPORT_VERSION)
5303     (void)fprintf (st, "\r\n  Modified: %s", VER_H_GIT_DATE);
5304 # else
5305     (void)fprintf (st, "\r\n  Released: %s", VER_H_GIT_DATE);
5306 # endif
5307 #endif
5308 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5309     (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5310 #endif
5311 #if defined(VER_CURRENT_TIME)
5312     (void)fprintf (st, "\r\n  Compiled: %s", VER_CURRENT_TIME);
5313 #endif
5314     if (dirty) //-V547
5315       {
5316         (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5317       }
5318     (void)fprintf (st, "\r\n\r\n Build Information:");
5319 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5320     char build_os_version_raw[255];
5321     char build_os_arch_raw[255];
5322     (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5323     (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5324     char *build_os_version = strdup(build_os_version_raw);
5325     if (!build_os_version)
5326       {
5327         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5328                        __func__, __FILE__, __LINE__);
5329 # if defined(USE_BACKTRACE)
5330 #  if defined(SIGUSR2)
5331         (void)raise(SIGUSR2);
5332         /*NOTREACHED*/ /* unreachable */
5333 #  endif /* if defined(SIGUSR2) */
5334 # endif /* if defined(USE_BACKTRACE) */
5335         abort();
5336       }
5337     char *build_os_arch = strdup(build_os_arch_raw);
5338     if (!build_os_arch)
5339       {
5340         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5341                        __func__, __FILE__, __LINE__);
5342 # if defined(USE_BACKTRACE)
5343 #  if defined(SIGUSR2)
5344         (void)raise(SIGUSR2);
5345         /*NOTREACHED*/ /* unreachable */
5346 #  endif /* if defined(SIGUSR2) */
5347 # endif /* if defined(USE_BACKTRACE) */
5348         abort();
5349       }
5350     unsigned char SPROM[1024];
5351     setupPROM (0, SPROM);
5352     (void)fprintf (st, "\r\n    Target: ");
5353     printpq (SPROM, st, 190, 20);
5354     if (SPROM[170] != 20)
5355       {
5356         if (SPROM[170] != 255)
5357           {
5358             (void)fprintf (st, " on ");
5359             printpq (SPROM, st, 170, 20);
5360           }
5361       }
5362     strtrimspace(build_os_version, build_os_version_raw);
5363     strtrimspace(build_os_arch, build_os_arch_raw);
5364     (void)fprintf (st, "\r\n  Build OS: %s %s", build_os_version, build_os_arch);
5365     FREE(build_os_version);
5366     FREE(build_os_arch);
5367 #endif
5368 #if defined(__VERSION__)
5369     char gnumver[2];
5370     char postver[1024];
5371     (void)sprintf(gnumver, "%.1s", __VERSION__);
5372     (void)sprintf(postver, "%.1023s", __VERSION__);
5373     strremove(postver, "(TM)");
5374     strremove(postver, "(R)");
5375     strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5376     strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5377     strremove(postver, " gcc 4.9 mode");
5378     strremove(postver, "4.2.1 Compatible ");
5379     strremove(postver, "git@github.com:llvm/llvm-project.git ");
5380     strremove(postver, "https://github.com/llvm/llvm-project.git ");
5381     strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5382     strremove(postver, "https://github.com/yrnkrn/zapcc ");
5383     strremove(postver, "(experimental) ");
5384     strremove(postver, ".module+el8.7.0+20823+214a699d");
5385     strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5386     strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5387     strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5388     strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5389     strremove(postver, "llvmorg-16.0.6-0-");
5390     strremove(postver, " Clang 15.0.0 (build 760095e)");
5391     strremove(postver, " Clang 15.0.0 (build 6af5742)");
5392     strremove(postver, " Clang 15.0.0 (build ca7115e)");
5393     strremove(postver, " Clang 15.0.0 (build 232543c)");
5394     strremove(postver, " Clang 17.0.6 (build 19a779f)");
5395     strremove(postver, "CLANG: ");
5396     removehex(postver);
5397     strremove(postver, " (git@github.com:pizlonator/llvm-project-deluge.git)");
5398 #endif
5399 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5400 # if !defined(__clang_version__)
5401     if (isdigit((unsigned char)gnumver[0])) {
5402         (void)fprintf (st, "\r\n  Compiler: GCC %s", postver);
5403     } else {
5404         (void)fprintf (st, "\r\n  Compiler: %s", postver);
5405     }
5406 # endif
5407 # if defined(__clang_analyzer__ )
5408     (void)fprintf (st, "\r\n  Compiler: Clang C/C++ Static Analyzer");
5409 # elif defined(__clang_version__) && defined(__VERSION__)
5410     char clangllvmver[1024];
5411     (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5412     strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5413     strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5414     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5415     strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5416     strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5417     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5418     strremove(clangllvmver, " ( )");
5419     strremove(clangllvmver, " ()");
5420     if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5421         (void)fprintf (st, "\r\n  Compiler: Clang %s", clangllvmver);
5422     } else {
5423         (void)fprintf (st, "\r\n  Compiler: %s", postver);
5424     }
5425 # elif defined(__clang_version__)
5426     (void)fprintf (st, "\r\n  Compiler: %s", postver);
5427 # endif
5428 #elif defined(__PGI) && !defined(__NVCOMPILER)
5429     (void)fprintf (st, "\r\n  Compiler: Portland Group, Inc. (PGI) C Compiler ");
5430 # if defined(__PGIC__)
5431     (void)fprintf (st, "%d", __PGIC__);
5432 #  if defined(__PGIC_MINOR__)
5433     (void)fprintf (st, ".%d", __PGIC_MINOR__);
5434 #   if defined(__PGIC_PATCHLEVEL__)
5435     (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5436 #   endif
5437 #  endif
5438 # endif
5439 #elif defined(__NVCOMPILER)
5440     (void)fprintf (st, "\r\n  Compiler: NVIDIA HPC SDK C Compiler ");
5441 # if defined(__NVCOMPILER_MAJOR__)
5442     (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5443 #  if defined(__NVCOMPILER_MINOR__)
5444     (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5445 #   if defined(__NVCOMPILER_PATCHLEVEL__)
5446     (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5447 #   endif
5448 #  endif
5449 # endif
5450 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5451     (void)fprintf (st, "\r\n  Compiler: Microsoft C %d.%02d.%05d.%02d",
5452                    _MSC_FULL_VER/10000000,
5453                    (_MSC_FULL_VER/100000)%100,
5454                    _MSC_FULL_VER%100000,
5455                    _MSC_BUILD);
5456 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5457 # if defined(_AIX) && defined(__PASE__)
5458     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5459 # endif
5460 # if defined(_AIX) && !defined(__PASE__)
5461     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5462 # endif
5463 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5464     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5465 # endif
5466 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5467 #  if defined(__PPC__) && defined(__APPLE__)
5468     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5469 #  else
5470     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s", __xlc__);
5471 #  endif
5472 # endif
5473 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5474 # define VER_ENC(maj, min, rev) \
5475   (((maj) * 1000000) + ((min) * 1000) + (rev))
5476 # define VER_DEC_MAJ(ver) \
5477   ((ver) / 1000000)
5478 # define VER_DEC_MIN(ver) \
5479   (((ver) % 1000000) / 1000)
5480 # define VER_DEC_REV(ver) \
5481   ((ver) % 1000)
5482 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5483 #  define COMP_VER VER_ENC(                                        \
5484    (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5485    (((__SUNPRO_C >>  8) & 0xf) * 10) + ((__SUNPRO_C >>  4) & 0xf), \
5486      (__SUNPRO_C & 0xf) * 10)
5487 # elif defined(__SUNPRO_C)
5488 #  define COMP_VER VER_ENC(    \
5489      (__SUNPRO_C >>  8) & 0xf, \
5490      (__SUNPRO_C >>  4) & 0xf, \
5491      (__SUNPRO_C) & 0xf)
5492 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5493 #  define COMP_VER VER_ENC(                                          \
5494    (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5495    (((__SUNPRO_CC >>  8) & 0xf) * 10) + ((__SUNPRO_CC >>  4) & 0xf), \
5496      (__SUNPRO_CC & 0xf) * 10)
5497 # elif defined(__SUNPRO_CC)
5498 #  define COMP_VER VER_ENC(     \
5499      (__SUNPRO_CC >>  8) & 0xf, \
5500      (__SUNPRO_CC >>  4) & 0xf, \
5501      (__SUNPRO_CC) & 0xf)
5502 # endif
5503 # if !defined(COMP_VER)
5504 #  define COMP_VER 0
5505 # endif
5506     (void)fprintf (st, "\r\n  Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5507                    VER_DEC_MAJ(COMP_VER),
5508                    VER_DEC_MIN(COMP_VER),
5509                    VER_DEC_REV(COMP_VER));
5510 #elif defined(__DMC__)
5511     (void)fprintf (st, "\r\n  Compiler: Digital Mars C/C++");
5512 #elif defined(__PCC__)
5513     (void)fprintf (st, "\r\n  Compiler: Portable C Compiler");
5514 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5515     (void)fprintf (st, "\r\n  Compiler: Plan 9 Compiler Suite");
5516 #elif defined(__ACK__)
5517     (void)fprintf (st, "\r\n  Compiler: Amsterdam Compiler Kit");
5518 #elif defined(__COMO__)
5519     (void)fprintf (st, "\r\n  Compiler: Comeau C++");
5520 #elif defined(__COMPCERT__)
5521     (void)fprintf (st, "\r\n  Compiler: CompCert C");
5522 #elif defined(__COVERITY__)
5523     (void)fprintf (st, "\r\n  Compiler: Coverity C/C++ Static Analyzer");
5524 #elif defined(__LCC__)
5525 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5526     (void)fprintf (st, "\r\n  Compiler: MCST Elbrus C Compiler");
5527 #  if __LCC__ > 99
5528     (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5529 #   if defined(__LCC_MINOR__)
5530 #    if __LCC_MINOR__ > 0
5531     (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5532 #    endif
5533 #   endif
5534 #  endif
5535 #  if defined(__EDG__) && defined(__EDG_VERSION__)
5536 #   if __EDG_VERSION__ > 99
5537     (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5538                   (int)(((__EDG_VERSION__) % 100) % 10));
5539 #   endif
5540 #  endif
5541 # else
5542     (void)fprintf (st, "\r\n  Compiler: Local/Little C Compiler (lcc)");
5543 # endif
5544 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5545     (void)fprintf (st, "\r\n  Compiler: SGI MIPSpro");
5546 #elif defined(__OPEN64__)
5547     (void)fprintf (st, "\r\n  Compiler: Open64 %s", __OPEN64__);
5548 #elif defined(__PGI) || defined(__PGIC__)
5549     (void)fprintf (st, "\r\n  Compiler: Portland Group/PGI C/C++");
5550 #elif defined(__VBCC__)
5551     (void)fprintf (st, "\r\n  Compiler: Volker Barthelmann C Compiler (vbcc)");
5552 #elif defined(__WATCOMC__)
5553     (void)fprintf (st, "\r\n  Compiler: Watcom C/C++ %d.%d",
5554                    __WATCOMC__ / 100,
5555                    __WATCOMC__ % 100);
5556 #elif defined(__xlC__)
5557     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++");
5558 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5559 # if defined(__INTEL_COMPILER_UPDATE)
5560 #  if defined(__INTEL_COMPILER_BUILD_DATE)
5561     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d.%d (%d)",
5562                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5563                    __INTEL_COMPILER_BUILD_DATE);
5564 #  else
5565     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d.%d",
5566                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5567 #  endif
5568 # else
5569     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d",
5570                    __INTEL_COMPILER);
5571 # endif
5572 #elif defined(SIM_COMPILER)
5573 # define S_xstr(a) S_str(a)
5574 # define S_str(a) #a
5575     (void)fprintf (st, "\r\n  Compiler: %s", S_xstr(SIM_COMPILER));
5576 # undef S_str
5577 # undef S_xstr
5578 #else
5579     (void)fprintf (st, "\r\n  Compiler: Unknown");
5580 #endif
5581 
5582 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5583     defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5584 # define SC_IS_PPC64 1
5585 #else
5586 # define SC_IS_PPC64 0
5587 #endif
5588 
5589 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5590     defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5591     defined(__PPC32)
5592 # define SC_IS_PPC32 1
5593 #else
5594 # define SC_IS_PPC32 0
5595 #endif
5596 
5597 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5598     arch = " x86_64";
5599 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5600     arch = " x86";
5601 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5602     arch = " arm64";
5603 #elif defined(_M_ARM) || defined(__arm__)
5604     arch = " arm";
5605 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5606     arch = " ia64";
5607 #elif SC_IS_PPC64
5608     arch = " powerpc64";
5609 #elif SC_IS_PPC32
5610     arch = " powerpc";
5611 #elif defined(__s390x__)
5612     arch = " s390x";
5613 #elif defined(__s390__)
5614     arch = " s390";
5615 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5616     arch = " j2";
5617 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5618     arch = " sh4";
5619 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5620     arch = " sh2";
5621 #elif defined(__alpha__)
5622     arch = " alpha";
5623 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5624     arch = " hppa";
5625 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5626     arch = " ice9";
5627 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5628     arch = " mips64";
5629 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5630     arch = " mips";
5631 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5632       defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5633     arch = " openrisc";
5634 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5635     arch = " sparc64";
5636 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5637     arch = " sparc";
5638 #elif defined(__riscv) || defined(__riscv__)
5639     arch = " riscv";
5640 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5641     arch = " e2k";
5642 #elif defined(__myriad2__)
5643     arch = " myriad2";
5644 #elif defined(__loongarch64) || defined(__loongarch__)
5645     arch = " loongarch";
5646 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5647     arch = " m68k";
5648 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5649     arch = " m88k";
5650 #elif defined(__VAX__) || defined(__vax__)
5651     arch = " vax";
5652 #elif defined(__NIOS2__) || defined(__nios2__)
5653     arch = " nios2";
5654 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5655     arch = " microblaze";
5656 #else
5657     arch = " ";
5658 #endif
5659     (void)fprintf (st, "%s", arch);
5660 #if defined(BUILD_BY_USER)
5661         (void)fprintf (st, "\r\n  Built by: %s", BUILD_BY_USER);
5662 #else
5663 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5664         (void)fprintf (st, "\r\n  Built by: %s", VER_H_PREP_USER);
5665 # endif
5666 #endif
5667                 (void)fprintf (st, "\r\n\r\n Host System Information:");
5668 #if defined(_WIN32)
5669     if (1) {
5670         char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5671         char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5672         char osversion[PATH_MAX+1] = "";
5673         FILE *f;
5674 
5675         if ((f = _popen ("ver", "r"))) {
5676             (void)memset (osversion, 0, sizeof(osversion));
5677             do {
5678                 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5679                     break;
5680                 sim_trim_endspc (osversion);
5681                 } while (osversion[0] == '\0');
5682             _pclose (f);
5683             }
5684         (void)fprintf (st, "\r\n   Host OS: %s", osversion);
5685         (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264  : "");
5686         }
5687 #else
5688     if (1) {
5689         char osversion[2*PATH_MAX+1] = "";
5690         FILE *f;
5691 # if !defined(_AIX)
5692         if ((f = popen \
5693              ("uname -mrs 2> /dev/null", "r"))) {
5694 # else
5695         if ((f = popen \
5696              ("sh -c 'echo \"$(command -p env uname -v \
5697                2> /dev/null).$(command -p env uname -r \
5698                2> /dev/null) $(command -p env uname -p \
5699                2> /dev/null)\"' 2> /dev/null", "r"))) {
5700 # endif /* if !defined(_AIX) */
5701             (void)memset (osversion, 0, sizeof(osversion));
5702             do {
5703               if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5704                     break;
5705               }
5706             sim_trim_endspc (osversion);
5707             } while (osversion[0] == '\0');
5708             pclose (f);
5709             strremove(osversion, "0000000000000000 ");
5710             strremove(osversion, " 0000000000000000");
5711             strremove(osversion, "000000000000 ");
5712             strremove(osversion, " 000000000000");
5713             strremove(osversion, "IBM ");
5714             strremove(osversion, " (emulated by qemu)");
5715             strremove(osversion, " (emulated by QEMU)");
5716         }
5717 # if !defined(_AIX)
5718             (void)fprintf (st, "\r\n   Host OS: %s", osversion);
5719 # else
5720             strremove(osversion, "AIX ");
5721 #  if !defined(__PASE__)
5722             (void)fprintf (st, "\r\n   Host OS: IBM AIX %s", osversion);
5723 #  else
5724             (void)fprintf (st, "\r\n   Host OS: IBM OS/400 (PASE) %s", osversion);
5725 #  endif /* if !defined(__PASE__) */
5726 # endif /* if !defined(_AIX) */
5727     } else {
5728 # if !defined(_AIX)
5729         (void)fprintf (st, "\r\n   Host OS: Unknown");
5730 # else
5731 #  if !defined(__PASE__)
5732         (void)fprintf (st, "\r\n   Host OS: IBM AIX");
5733 #  else
5734         (void)fprintf (st, "\r\n   Host OS: IBM OS/400 (PASE)");
5735 #  endif /* if !defined(__PASE__) */
5736 # endif /* if !defined(_AIX) */
5737     }
5738 #endif
5739     if (nodist)
5740       {
5741         sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5742       }
5743     else
5744       {
5745         (void)fprintf (st, "\r\n");
5746         (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5747         (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5748         (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5749       }
5750         (void)fprintf (st, "\r\n");
5751     }
5752 return SCPE_OK;
5753 }
5754 
5755 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5756 {
5757 size_t i;
5758 DEVICE *dptr;
5759 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5760 
5761 if (cptr && (*cptr != 0))
5762     return SCPE_2MARG;
5763 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5764 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5765     if (!only_enabled || !qdisable (dptr))
5766         show_device (st, dptr, flag);
5767 return SCPE_OK;
5768 }
5769 
5770 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5771 {
5772 int32 i;
5773 DEVICE *dptr;
5774 
5775 if (cptr && (*cptr != 0))
5776     return SCPE_2MARG;
5777 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5778     show_dev_logicals (st, dptr, NULL, 1, cptr);
5779 return SCPE_OK;
5780 }
5781 
5782 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5783 {
5784 if (dptr->lname)
5785     (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5786 else if (!flag)
5787     fputs ("no logical name assigned\r\n", st);
5788 return SCPE_OK;
5789 }
5790 
5791 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5792 {
5793 DEVICE *dptr;
5794 UNIT *uptr;
5795 int32 accum;
5796 
5797 if (cptr && (*cptr != 0))
5798     return SCPE_2MARG;
5799 if (sim_clock_queue == QUEUE_LIST_END)
5800     (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5801                    sim_name, sim_time, sim_timer_inst_per_sec ());
5802 else {
5803     const char *tim;
5804 
5805     (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5806                    sim_name, sim_time, sim_timer_inst_per_sec ());
5807     accum = 0;
5808     for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5809         if (uptr == &sim_step_unit)
5810             (void)fprintf (st, "  Step timer");
5811         else
5812             if (uptr == &sim_expect_unit)
5813                 (void)fprintf (st, "  Expect fired");
5814             else
5815                 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5816                     (void)fprintf (st, "  %s", sim_dname (dptr));
5817                     if (dptr->numunits > 1)
5818                         (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5819                     }
5820                 else
5821                     (void)fprintf (st, "  Unknown");
5822         tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5823         (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5824                        (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5825                        (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5826         accum = accum + uptr->time;
5827         }
5828     }
5829 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5830 return SCPE_OK;
5831 }
5832 
5833 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5834 {
5835 if (cptr && (*cptr != 0))
5836     return SCPE_2MARG;
5837 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5838 return SCPE_OK;
5839 }
5840 
5841 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5842 {
5843 t_stat r;
5844 
5845 if (cptr && (*cptr != 0))
5846     r = ssh_break (st, cptr, 1);  /* more? */
5847 else
5848     r = sim_brk_showall (st, (uint32)sim_switches);
5849 return r;
5850 }
5851 
5852 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5853 {
5854 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5855 return SCPE_OK;
5856 }
5857 
5858 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5859 {
5860 int32 any = 0;
5861 DEBTAB *dep;
5862 
5863 if (dptr->flags & DEV_DEBUG) {
5864     if (dptr->dctrl == 0)
5865         fputs ("Debugging disabled", st);
5866     else if (dptr->debflags == NULL)
5867         fputs ("Debugging enabled", st);
5868     else {
5869         uint32 dctrl = dptr->dctrl;
5870 
5871         fputs ("Debug=", st);
5872         for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5873             if ((dctrl & dep->mask) == dep->mask) {
5874                 dctrl &= ~dep->mask;
5875                 if (any)
5876                     fputc (';', st);
5877                 fputs (dep->name, st);
5878                 any = 1;
5879                 }
5880             }
5881         }
5882     fputc ('\n', st);
5883     return SCPE_OK;
5884     }
5885 else return SCPE_NOFNC;
5886 }
5887 
5888 /* Show On actions */
5889 
5890 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5891 {
5892 int32 lvl, i;
5893 
5894 if (cptr && (*cptr != 0)) return SCPE_2MARG;            /* now eol? */
5895 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5896     if (lvl > 0)
5897         (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5898     else
5899         (void)fprintf(st, "On Processing for input commands");
5900     (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5901     for (i=1; i<SCPE_BASE; ++i) {
5902         if (sim_on_actions[lvl][i])
5903             (void)fprintf(st, "    on %5d    %s\r\n", i, sim_on_actions[lvl][i]); }
5904     for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5905         if (sim_on_actions[lvl][i])
5906             (void)fprintf(st, "    on %-5s    %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5907     if (sim_on_actions[lvl][0])
5908         (void)fprintf(st, "    on ERROR    %s\r\n", sim_on_actions[lvl][0]);
5909     (void)fprintf(st, "\r\n");
5910     }
5911 if (sim_on_inherit)
5912     (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5913 return SCPE_OK;
5914 }
5915 
5916 /* Show modifiers */
5917 
5918 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5919 {
5920 int32 i;
5921 DEVICE *dptr;
5922 
5923 if (cptr && (*cptr != 0))                               /* now eol? */
5924     return SCPE_2MARG;
5925 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5926     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5927 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5928     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5929 return SCPE_OK;
5930 }
5931 
5932 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5933 {
5934 fprint_set_help (st, dptr);
5935 return SCPE_OK;
5936 }
5937 
5938 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
     /* [previous][next][first][last][top][bottom][index][help] */
5939 {
5940 MTAB *mptr;
5941 t_stat r = SCPE_OK;
5942 
5943 if (dptr->modifiers == NULL)
5944     return SCPE_OK;
5945 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5946     if (mptr->pstring &&
5947         ((mptr->mask & MTAB_XTD)?
5948             (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5949             ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5950         if (*toks > 0) {
5951             (void)fprintf (st, "\r\n");
5952             *toks = 0;
5953             }
5954         if (r == SCPE_OK)
5955             fprint_sep (st, toks);
5956         r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5957         }
5958     }
5959 return SCPE_OK;
5960 }
5961 
5962 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
     /* [previous][next][first][last][top][bottom][index][help] */
5963     CONST char *cptr, int32 flag)
5964 {
5965 t_stat r = SCPE_OK;
5966 
5967 if (mptr->disp)
5968     r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5969 else
5970     fputs (mptr->pstring, st);
5971 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5972     fputc ('\n', st);
5973 return r;
5974 }
5975 
5976 /* Show show commands */
5977 
5978 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5979 {
5980 int32 i;
5981 DEVICE *dptr;
5982 
5983 if (cptr && (*cptr != 0))                               /* now eol? */
5984     return SCPE_2MARG;
5985 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5986     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5987 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5988     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5989 return SCPE_OK;
5990 }
5991 
5992 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5993 {
5994 fprint_show_help (st, dptr);
5995 return SCPE_OK;
5996 }
5997 
5998 /* Breakpoint commands */
5999 
6000 t_stat brk_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6001 {
6002 GET_SWITCHES (cptr);                                    /* get switches */
6003 return ssh_break (NULL, cptr, flg);                     /* call common code */
6004 }
6005 
6006 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
     /* [previous][next][first][last][top][bottom][index][help] */
6007 {
6008 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
6009 CONST char *tptr, *t1ptr;
6010 DEVICE *dptr = sim_dflt_dev;
6011 UNIT *uptr;
6012 t_stat r;
6013 t_addr lo, hi, max;
6014 int32 cnt;
6015 
6016 if (sim_brk_types == 0)
6017     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6018 if (dptr == NULL)
6019     return SCPE_IERR;
6020 uptr = dptr->units;
6021 if (uptr == NULL)
6022     return SCPE_IERR;
6023 max = uptr->capac - 1;
6024 abuf[sizeof(abuf)-1] = '\0';
6025 strncpy (abuf, cptr, sizeof(abuf)-1);
6026 cptr = abuf;
6027 if ((aptr = strchr (abuf, ';'))) {                      /* ;action? */
6028     if (flg != SSH_ST)                                  /* only on SET */
6029         return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
6030     *aptr++ = 0;                                        /* separate strings */
6031     }
6032 if (*cptr == 0) {                                       /* no argument? */
6033     lo = (t_addr) get_rval (sim_PC, 0);                 /* use PC */
6034     return ssh_break_one (st, flg, lo, 0, aptr);
6035     }
6036 while (*cptr) {
6037     cptr = get_glyph (cptr, gbuf, ',');
6038     tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
6039     if (tptr == NULL)
6040         return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
6041     if (*tptr == '[') {
6042         cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
6043         if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
6044             return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
6045         tptr = t1ptr + 1;
6046         }
6047     else cnt = 0;
6048     if (*tptr != 0)
6049         return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
6050     if ((lo == 0) && (hi == max)) {
6051         if (flg == SSH_CL)
6052             sim_brk_clrall (sim_switches);
6053         else
6054             if (flg == SSH_SH)
6055                 sim_brk_showall (st, (uint32)sim_switches);
6056             else
6057                 return SCPE_ARG;
6058         }
6059     else {
6060         for ( ; lo <= hi; lo = lo + 1) {
6061             r = ssh_break_one (st, flg, lo, cnt, aptr);
6062             if (r != SCPE_OK)
6063                 return r;
6064             }
6065         }
6066     }
6067 return SCPE_OK;
6068 }
6069 
6070 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6071 {
6072 if (!sim_brk_types)
6073     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6074 switch (flg) {
6075     case SSH_ST:
6076         return sim_brk_set (lo, sim_switches, cnt, aptr);
6077         /*NOTREACHED*/ /* unreachable */
6078         break;
6079 
6080     case SSH_CL:
6081         return sim_brk_clr (lo, sim_switches);
6082         /*NOTREACHED*/ /* unreachable */
6083         break;
6084 
6085     case SSH_SH:
6086         return sim_brk_show (st, lo, sim_switches);
6087         /*NOTREACHED*/ /* unreachable */
6088         break;
6089 
6090     default:
6091         return SCPE_ARG;
6092     }
6093 }
6094 
6095 /* Reset command and routines */
6096 
6097 static t_bool run_cmd_did_reset = FALSE;
6098 
6099 t_stat reset_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6100 {
6101 char gbuf[CBUFSIZE];
6102 DEVICE *dptr;
6103 
6104 GET_SWITCHES (cptr);                                    /* get switches */
6105 run_cmd_did_reset = FALSE;
6106 if (*cptr == 0)                                         /* reset(cr) */
6107     return (reset_all (0));
6108 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6109 if (*cptr != 0)                                         /* now eol? */
6110     return SCPE_2MARG;
6111 if (strcmp (gbuf, "ALL") == 0)
6112     return (reset_all (0));
6113 dptr = find_dev (gbuf);                                 /* locate device */
6114 if (dptr == NULL)                                       /* found it? */
6115     return SCPE_NXDEV;
6116 if (dptr->reset != NULL)
6117     return dptr->reset (dptr);
6118 else return SCPE_OK;
6119 }
6120 
6121 /* Reset devices start..end
6122 
6123    Inputs:
6124         start   =       number of starting device
6125    Outputs:
6126         status  =       error status
6127 */
6128 
6129 t_stat reset_all (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6130 {
6131 DEVICE *dptr;
6132 uint32 i;
6133 t_stat reason;
6134 
6135 for (i = 0; i < start; i++) {
6136     if (sim_devices[i] == NULL)
6137         return SCPE_IERR;
6138     }
6139 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6140     if (dptr->reset != NULL) {
6141         reason = dptr->reset (dptr);
6142         if (reason != SCPE_OK)
6143             return reason;
6144         }
6145     }
6146 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6147     if (dptr->reset != NULL) {
6148         reason = dptr->reset (dptr);
6149         if (reason != SCPE_OK)
6150             return reason;
6151         }
6152     }
6153 return SCPE_OK;
6154 }
6155 
6156 /* Reset to powerup state
6157 
6158    Inputs:
6159         start   =       number of starting device
6160    Outputs:
6161         status  =       error status
6162 */
6163 
6164 t_stat reset_all_p (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6165 {
6166 t_stat r;
6167 int32 old_sw = sim_switches;
6168 
6169 sim_switches = SWMASK ('P');
6170 r = reset_all (start);
6171 sim_switches = old_sw;
6172 return r;
6173 }
6174 
6175 /* Attach command */
6176 
6177 t_stat attach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6178 {
6179 char gbuf[4*CBUFSIZE];
6180 DEVICE *dptr;
6181 UNIT *uptr;
6182 t_stat r;
6183 
6184 GET_SWITCHES (cptr);                                    /* get switches */
6185 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6186     return SCPE_2FARG;
6187 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6188 GET_SWITCHES (cptr);                                    /* get switches */
6189 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* now eol? */
6190     return SCPE_2FARG;
6191 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6192 if (dptr == NULL)                                       /* found dev? */
6193     return SCPE_NXDEV;
6194 if (uptr == NULL)                                       /* valid unit? */
6195     return SCPE_NXUN;
6196 if (uptr->flags & UNIT_ATT) {                           /* already attached? */
6197     if (!(uptr->dynflags & UNIT_ATTMULT) &&             /* and only single attachable */
6198         !(dptr->flags & DEV_DONTAUTO)) {                /* and auto detachable */
6199         r = scp_detach_unit (dptr, uptr);               /* detach it */
6200         if (r != SCPE_OK)                               /* error? */
6201             return r; }
6202     else {
6203         if (!(uptr->dynflags & UNIT_ATTMULT))
6204             return SCPE_ALATT;                          /* Already attached */
6205         }
6206     }
6207 gbuf[sizeof(gbuf)-1] = '\0';
6208 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6209 sim_trim_endspc (gbuf);                                 /* trim trailing spc */
6210 return scp_attach_unit (dptr, uptr, gbuf);              /* attach */
6211 }
6212 
6213 /* Call device-specific or file-oriented attach unit routine */
6214 
6215 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6216 {
6217 if (dptr->attach != NULL)                               /* device routine? */
6218     return dptr->attach (uptr, (CONST char *)cptr);     /* call it */
6219 return attach_unit (uptr, (CONST char *)cptr);          /* no, std routine */
6220 }
6221 
6222 /* Attach unit to file */
6223 
6224 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6225 {
6226 DEVICE *dptr;
6227 
6228 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6229     return SCPE_UDIS;
6230 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
6231     return SCPE_NOATT;
6232 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6233     return SCPE_NOATT;
6234 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */
6235 if (uptr->filename == NULL)
6236     return SCPE_MEM;
6237 strncpy (uptr->filename, cptr, CBUFSIZE-1);             /* save name */
6238 if ((sim_switches & SWMASK ('R')) ||                    /* read only? */
6239     ((uptr->flags & UNIT_RO) != 0)) {
6240     if (((uptr->flags & UNIT_ROABLE) == 0) &&           /* allowed? */
6241         ((uptr->flags & UNIT_RO) == 0))
6242         return attach_err (uptr, SCPE_NORO);            /* no, error */
6243     uptr->fileref = sim_fopen (cptr, "rb");             /* open rd only */
6244     if (uptr->fileref == NULL)                          /* open fail? */
6245         return attach_err (uptr, SCPE_OPENERR);         /* yes, error */
6246     uptr->flags = uptr->flags | UNIT_RO;                /* set rd only */
6247     if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6248         sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6249         }
6250     }
6251 else {
6252     if (sim_switches & SWMASK ('N')) {                  /* new file only? */
6253         uptr->fileref = sim_fopen (cptr, "wb+");        /* open new file */
6254         if (uptr->fileref == NULL)                      /* open fail? */
6255             return attach_err (uptr, SCPE_OPENERR);     /* yes, error */
6256         if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6257             sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6258             }
6259         }
6260     else {                                              /* normal */
6261         uptr->fileref = sim_fopen (cptr, "rb+");        /* open r/w */
6262         if (uptr->fileref == NULL) {                    /* open fail? */
6263 #if defined(EWOULDBLOCK)
6264             if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6265 #else
6266             if ((errno == EAGAIN))
6267 #endif
6268                 return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6269 
6270 #if defined(EPERM)
6271             if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {/* read only? */
6272 #else
6273             if ((errno == EROFS) || (errno == EACCES)) {/* read only? */
6274 #endif
6275                 if ((uptr->flags & UNIT_ROABLE) == 0)   /* allowed? */
6276                     return attach_err (uptr, SCPE_NORO);/* no error */
6277                 uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */
6278                 if (uptr->fileref == NULL)              /* open fail? */
6279                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6280                 uptr->flags = uptr->flags | UNIT_RO;    /* set rd only */
6281                 if (!sim_quiet) {
6282                     sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6283                     }
6284                 }
6285             else {                                      /* doesn't exist */
6286                 if (sim_switches & SWMASK ('E'))        /* must exist? */
6287                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6288                 uptr->fileref = sim_fopen (cptr, "wb+");/* open new file */
6289                 if (uptr->fileref == NULL)              /* open fail? */
6290                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6291                 if (!sim_quiet) {
6292                     sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6293                     }
6294                 }
6295             }                                           /* end if null */
6296         }                                               /* end else */
6297     }
6298 if (uptr->flags & UNIT_BUFABLE) {                       /* buffer? */
6299     uint32 cap = ((uint32) uptr->capac) / dptr->aincr;  /* effective size */
6300     if (uptr->flags & UNIT_MUSTBUF)                     /* dyn alloc? */
6301         uptr->filebuf = calloc (cap, SZ_D (dptr));      /* allocate */
6302     if (uptr->filebuf == NULL)                          /* no buffer? */
6303         return attach_err (uptr, SCPE_MEM);             /* error */
6304     if (!sim_quiet) {
6305         sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6306         }
6307     uptr->hwmark = (uint32)sim_fread (uptr->filebuf,    /* read file */
6308         SZ_D (dptr), cap, uptr->fileref);
6309     uptr->flags = uptr->flags | UNIT_BUF;               /* set buffered */
6310     }
6311 uptr->flags = uptr->flags | UNIT_ATT;
6312 uptr->pos = 0;
6313 return SCPE_OK;
6314 }
6315 
6316 t_stat attach_err (UNIT *uptr, t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
6317 {
6318 FREE (uptr->filename);
6319 uptr->filename = NULL;
6320 return stat;
6321 }
6322 
6323 /* Detach command */
6324 
6325 t_stat detach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6326 {
6327 char gbuf[CBUFSIZE];
6328 DEVICE *dptr;
6329 UNIT *uptr;
6330 
6331 GET_SWITCHES (cptr);                                    /* get switches */
6332 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6333     return SCPE_2FARG;
6334 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6335 if (*cptr != 0)                                         /* now eol? */
6336     return SCPE_2MARG;
6337 if (strcmp (gbuf, "ALL") == 0)
6338     return (detach_all (0, FALSE));
6339 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6340 if (dptr == NULL)                                       /* found dev? */
6341     return SCPE_NXDEV;
6342 if (uptr == NULL)                                       /* valid unit? */
6343     return SCPE_NXUN;
6344 return scp_detach_unit (dptr, uptr);                    /* detach */
6345 }
6346 
6347 /* Detach devices start..end
6348 
6349    Inputs:
6350         start   =       number of starting device
6351         shutdown =      TRUE if simulator shutting down
6352    Outputs:
6353         status  =       error status
6354 
6355    Note that during shutdown, detach routines for non-attachable devices
6356    will be called.  These routines can implement simulator shutdown.  Error
6357    returns during shutdown are ignored.
6358 */
6359 
6360 t_stat detach_all (int32 start, t_bool shutdown)
     /* [previous][next][first][last][top][bottom][index][help] */
6361 {
6362 uint32 i, j;
6363 DEVICE *dptr;
6364 UNIT *uptr;
6365 t_stat r;
6366 
6367 if ((start < 0) || (start > 1))
6368     return SCPE_IERR;
6369 if (shutdown)
6370     sim_switches = sim_switches | SIM_SW_SHUT;          /* flag shutdown */
6371 for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
6372     for (j = 0; j < dptr->numunits; j++) {              /* loop thru units */
6373         uptr = (dptr->units) + j;
6374         if ((uptr->flags & UNIT_ATT) ||                 /* attached? */
6375             (shutdown && dptr->detach &&                /* shutdown, spec rtn, */
6376             !(uptr->flags & UNIT_ATTABLE))) {           /* !attachable? */
6377             r = scp_detach_unit (dptr, uptr);           /* detach unit */
6378 
6379             if ((r != SCPE_OK) && !shutdown)            /* error and not shutting down? */
6380                 return r;                               /* bail out now with error status */
6381             }
6382         }
6383     }
6384 return SCPE_OK;
6385 }
6386 
6387 /* Call device-specific or file-oriented detach unit routine */
6388 
6389 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6390 {
6391 if (dptr->detach != NULL)                               /* device routine? */
6392     return dptr->detach (uptr);
6393 return detach_unit (uptr);                              /* no, standard */
6394 }
6395 
6396 /* Detach unit from file */
6397 
6398 t_stat detach_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6399 {
6400 DEVICE *dptr;
6401 
6402 if (uptr == NULL)
6403     return SCPE_IERR;
6404 if (!(uptr->flags & UNIT_ATTABLE))                      /* attachable? */
6405     return SCPE_NOATT;
6406 if (!(uptr->flags & UNIT_ATT)) {                        /* not attached? */
6407     if (sim_switches & SIM_SW_REST)                     /* restoring? */
6408         return SCPE_OK;                                 /* allow detach */
6409     else
6410         return SCPE_NOTATT;                             /* complain */
6411     }
6412 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6413     return SCPE_OK;
6414 if (uptr->flags & UNIT_BUF) {
6415     uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6416     if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6417         if (!sim_quiet) {
6418             sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6419             }
6420         rewind (uptr->fileref);
6421         sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6422         if (ferror (uptr->fileref))
6423             sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6424                         sim_dname (dptr), xstrerror_l(errno), errno);
6425         }
6426     if (uptr->flags & UNIT_MUSTBUF) {                   /* dyn alloc? */
6427         FREE (uptr->filebuf);                           /* free buf */
6428         uptr->filebuf = NULL;
6429         }
6430     uptr->flags = uptr->flags & ~UNIT_BUF;
6431     }
6432 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6433 FREE (uptr->filename);
6434 uptr->filename = NULL;
6435 if (fclose (uptr->fileref) == EOF)
6436     return SCPE_IOERR;
6437 return SCPE_OK;
6438 }
6439 
6440 /* Get device display name */
6441 
6442 const char *sim_dname (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6443 {
6444 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6445 }
6446 
6447 /* Get unit display name */
6448 
6449 const char *sim_uname (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6450 {
6451 DEVICE *d = find_dev_from_unit(uptr);
6452 static char uname[CBUFSIZE];
6453 
6454 if (!d)
6455     return "";
6456 if (d->numunits == 1)
6457     return sim_dname (d);
6458 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6459 return uname;
6460 }
6461 
6462 /* Run, go, boot, cont, step, next commands */
6463 
6464 t_stat run_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6465 {
6466 char gbuf[CBUFSIZE] = "";
6467 CONST char *tptr;
6468 uint32 i, j;
6469 int32 sim_next = 0;
6470 int32 unitno;
6471 t_value pcv, orig_pcv;
6472 t_stat r;
6473 DEVICE *dptr;
6474 UNIT *uptr;
6475 
6476 GET_SWITCHES (cptr);                                    /* get switches */
6477 sim_step = 0;
6478 if ((flag == RU_RUN) || (flag == RU_GO)) {              /* run or go */
6479     orig_pcv = get_rval (sim_PC, 0);                    /* get current PC value */
6480     if (*cptr != 0) {                                   /* argument? */
6481         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6482         if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6483             if (sim_dflt_dev && sim_vm_parse_addr)      /* address parser? */
6484                 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6485             else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */
6486             if ((tptr == gbuf) || (*tptr != 0) ||       /* error? */
6487                 (pcv > width_mask[sim_PC->width]))
6488                 return SCPE_ARG;
6489             put_rval (sim_PC, 0, pcv);                  /* Save in PC */
6490             }
6491         }
6492     if ((flag == RU_RUN) &&                             /* run? */
6493         ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {  /* reset sim */
6494         put_rval (sim_PC, 0, orig_pcv);                 /* restore original PC */
6495         return r;
6496         }
6497     if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) { //-V600 /* should be end */
6498         int32 saved_switches = sim_switches;
6499 
6500         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6501             cptr = get_glyph (cptr, gbuf, 0);           /* get next glyph */
6502         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6503             return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6504                                              (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6505         sim_switches = 0;
6506         GET_SWITCHES (cptr);
6507         if ((*cptr == '\'') || (*cptr == '"')) {        /* Expect UNTIL condition */
6508             r = expect_cmd (1, cptr);
6509             if (r != SCPE_OK)
6510                 return r;
6511             }
6512         else {                                          /* BREAK UNTIL condition */
6513             if (sim_switches == 0)
6514                 sim_switches = sim_brk_dflt;
6515             sim_switches |= BRK_TYP_TEMP;               /* make this a one-shot breakpoint */
6516             sim_brk_types |= BRK_TYP_TEMP;
6517             r = ssh_break (NULL, cptr, SSH_ST);
6518             if (r != SCPE_OK)
6519                 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6520             }
6521         sim_switches = saved_switches;
6522         }
6523     }
6524 
6525 else if ((flag == RU_STEP) ||
6526          ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) { /* step */
6527     static t_bool not_implemented_message = FALSE;
6528 
6529     if ((!not_implemented_message) && (flag == RU_NEXT)) {
6530         not_implemented_message = TRUE;
6531         flag = RU_STEP;
6532         }
6533     if (*cptr != 0) {                                   /* argument? */
6534         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6535         if (*cptr != 0)                                 /* should be end */
6536             return SCPE_2MARG;
6537         sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6538         if ((r != SCPE_OK) || (sim_step <= 0))          /* error? */
6539             return SCPE_ARG;
6540         }
6541     else sim_step = 1;
6542     if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6543         sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6544     }
6545 else if (flag == RU_NEXT) {                             /* next */
6546     t_addr *addrs;
6547 
6548     if (*cptr != 0) {                                   /* argument? */
6549         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6550         if (*cptr != 0)                                 /* should be end */
6551             return SCPE_2MARG;
6552         sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6553         if ((r != SCPE_OK) || (sim_next <= 0))          /* error? */
6554             return SCPE_ARG;
6555         }
6556     else sim_next = 1;
6557     if (sim_vm_is_subroutine_call(&addrs)) {
6558         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6559         for (i=0; addrs[i]; i++)
6560             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6561         }
6562     else
6563         sim_step = 1;
6564     }
6565 else if (flag == RU_BOOT) {                             /* boot */
6566     if (*cptr == 0)                                     /* must be more */
6567         return SCPE_2FARG;
6568     cptr = get_glyph (cptr, gbuf, 0);                   /* get next glyph */
6569     if (*cptr != 0)                                     /* should be end */
6570         return SCPE_2MARG;
6571     dptr = find_unit (gbuf, &uptr);                     /* locate unit */
6572     if (dptr == NULL)                                   /* found dev? */
6573         return SCPE_NXDEV;
6574     if (uptr == NULL)                                   /* valid unit? */
6575         return SCPE_NXUN;
6576     if (dptr->boot == NULL)                             /* can it boot? */
6577         return SCPE_NOFNC;
6578     if (uptr->flags & UNIT_DIS)                         /* disabled? */
6579         return SCPE_UDIS;
6580     if ((uptr->flags & UNIT_ATTABLE) &&                 /* if attable, att? */
6581         !(uptr->flags & UNIT_ATT))
6582         return SCPE_UNATT;
6583     unitno = (int32) (uptr - dptr->units);              /* recover unit# */
6584     if ((r = sim_run_boot_prep (flag)) != SCPE_OK)      /* reset sim */
6585         return r;
6586     if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)     /* boot device */
6587         return r;
6588     }
6589 
6590 else
6591     if (flag != RU_CONT)                                /* must be cont */
6592         return SCPE_IERR;
6593     else                                                /* CONTINUE command */
6594         if (*cptr != 0)                                 /* should be end (no arguments allowed) */
6595             return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6596 
6597 if (sim_switches & SIM_SW_HIDE)                         /* Setup only for Remote Console Mode */
6598     return SCPE_OK;
6599 
6600 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* reposition all */
6601     for (j = 0; j < dptr->numunits; j++) {              /* seq devices */
6602         uptr = dptr->units + j;
6603         if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6604             sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6605         }
6606     }
6607 stop_cpu = 0;
6608 sim_is_running = 1;                                     /* flag running */
6609 if (sim_ttrun () != SCPE_OK) {                          /* set console mode */
6610     sim_is_running = 0;                                 /* flag idle */
6611     sim_ttcmd ();
6612     return SCPE_TTYERR;
6613     }
6614 if ((r = sim_check_console (30)) != SCPE_OK) {          /* check console, error? */
6615     sim_is_running = 0;                                 /* flag idle */
6616     sim_ttcmd ();
6617     return r;
6618     }
6619 #if !defined(IS_WINDOWS)
6620 # if defined(SIGINT)
6621 if (signal (SIGINT, int_handler) == SIG_ERR) {          /* set WRU */
6622     sim_is_running = 0;                                 /* flag idle */
6623     sim_ttcmd ();
6624     return SCPE_SIGERR;
6625     }
6626 # endif
6627 #endif
6628 #if !defined(IS_WINDOWS)
6629 # if defined(SIGHUP)
6630 if (signal (SIGHUP, int_handler) == SIG_ERR) {          /* set WRU */
6631     sim_is_running = 0;                                 /* flag idle */
6632     sim_ttcmd ();
6633     return SCPE_SIGERR;
6634     }
6635 # endif
6636 #endif
6637 #if !defined(IS_WINDOWS)
6638 # if defined(SIGTERM)
6639 if (signal (SIGTERM, int_handler) == SIG_ERR) {         /* set WRU */
6640     sim_is_running = 0;                                 /* flag idle */
6641     sim_ttcmd ();
6642     return SCPE_SIGERR;
6643     }
6644 # endif
6645 #endif
6646 if (sim_step)                                           /* set step timer */
6647     sim_activate (&sim_step_unit, sim_step);
6648 (void)fflush(stdout);                                   /* flush stdout */
6649 if (sim_log)                                            /* flush log if enabled */
6650     (void)fflush (sim_log);
6651 sim_rtcn_init_all ();                                   /* re-init clocks */
6652 sim_start_timer_services ();                            /* enable wall clock timing */
6653 
6654 do {
6655     t_addr *addrs;
6656 
6657     while (1) {
6658         r = sim_instr();
6659         if (r != SCPE_REMOTE)
6660             break;
6661         sim_remote_process_command ();                  /* Process the command and resume processing */
6662         }
6663     if ((flag != RU_NEXT) ||                            /* done if not doing NEXT */
6664         (--sim_next <=0))
6665         break;
6666     if (sim_step == 0) {                                /* doing a NEXT? */
6667         t_addr val;
6668         BRKTAB *bp;
6669 
6670         if (SCPE_BARE_STATUS(r) >= SCPE_BASE)           /* done if an error occurred */
6671             break;
6672         if (sim_vm_pc_value)                            /* done if didn't stop at a dynamic breakpoint */
6673             val = (t_addr)(*sim_vm_pc_value)();
6674         else
6675             val = (t_addr)get_rval (sim_PC, 0);
6676         if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6677             break;
6678         sim_brk_clrall (BRK_TYP_DYN_STEPOVER);          /* cancel any step/over subroutine breakpoints */
6679         }
6680     else {
6681         if (r != SCPE_STEP)                             /* done if step didn't complete with step expired */
6682             break;
6683         }
6684     /* setup another next/step */
6685     sim_step = 0;
6686     if (sim_vm_is_subroutine_call(&addrs)) {
6687         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6688         for (i=0; addrs[i]; i++)
6689             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6690         }
6691     else
6692         sim_step = 1;
6693     if (sim_step)                                       /* set step timer */
6694         sim_activate (&sim_step_unit, sim_step);
6695     } while (1);
6696 
6697 sim_is_running = 0;                                     /* flag idle */
6698 sim_stop_timer_services ();                             /* disable wall clock timing */
6699 sim_ttcmd ();                                           /* restore console */
6700 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);                  /* cancel any step/over subroutine breakpoints */
6701 signal (SIGINT, SIG_DFL);                               /* cancel WRU */
6702 #if defined(SIGHUP)
6703 signal (SIGHUP, SIG_DFL);                               /* cancel WRU */
6704 #endif
6705 signal (SIGTERM, SIG_DFL);                              /* cancel WRU */
6706 if (sim_log)                                            /* flush console log */
6707     (void)fflush (sim_log);
6708 if (sim_deb)                                            /* flush debug log */
6709     sim_debug_flush ();
6710 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* flush attached files */
6711     for (j = 0; j < dptr->numunits; j++) {              /* if not buffered in mem */
6712         uptr = dptr->units + j;
6713         if (uptr->flags & UNIT_ATT) {                   /* attached, */
6714             if (uptr->io_flush)                         /* unit specific flush routine */
6715                 uptr->io_flush (uptr);                  /* call it */
6716             else {
6717                 if (!(uptr->flags & UNIT_BUF) &&        /* not buffered, */
6718                     (uptr->fileref) &&                  /* real file, */
6719                     !(uptr->dynflags & UNIT_NO_FIO) &&  /* is FILE *, */
6720                     !(uptr->flags & UNIT_RO))           /* not read only? */
6721                     (void)fflush (uptr->fileref);
6722                 }
6723             }
6724         }
6725     }
6726 sim_cancel (&sim_step_unit);                            /* cancel step timer */
6727 UPDATE_SIM_TIME;                                        /* update sim time */
6728 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6729 }
6730 
6731 /* run command message handler */
6732 
6733 void
6734 run_cmd_message (const char *unechoed_cmdline, t_stat r)
     /* [previous][next][first][last][top][bottom][index][help] */
6735 {
6736 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6737     sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6738 #if defined(WIN_STDIO)
6739 (void)fflush(stderr);
6740 (void)fflush(stdout);
6741 #endif /* if defined(WIN_STDIO) */
6742 fprint_stopped (stdout, r);                         /* print msg */
6743 if (sim_log && (sim_log != stdout))                 /* log if enabled */
6744     fprint_stopped (sim_log, r);
6745 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))/* debug if enabled */
6746     fprint_stopped (sim_deb, r);
6747 #if defined(WIN_STDIO)
6748 (void)fflush(stderr);
6749 (void)fflush(stdout);
6750 #endif /* if defined(WIN_STDIO) */
6751 }
6752 
6753 /* Common setup for RUN or BOOT */
6754 
6755 t_stat sim_run_boot_prep (int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
6756 {
6757 UNIT *uptr;
6758 t_stat r;
6759 
6760 sim_interval = 0;                                       /* reset queue */
6761 sim_time = sim_rtime = 0;
6762 noqueue_time = 0;
6763 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6764     sim_clock_queue = uptr->next;
6765     uptr->next = NULL;
6766     }
6767 r = reset_all (0);
6768 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6769     if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6770         sim_printf ("Resetting all devices...  This may not have been your intention.\r\n");
6771         sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6772         }
6773     run_cmd_did_reset = TRUE;
6774     }
6775 return r;
6776 }
6777 
6778 /* Print stopped message
6779  * For VM stops, if a VM-specific "sim_vm_fprint_stopped" pointer is defined,
6780  * call the indicated routine to print additional information after the message
6781  * and before the PC value is printed.  If the routine returns FALSE, skip
6782  * printing the PC and its related instruction.
6783  */
6784 
6785 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6786 {
6787 int32 i;
6788 t_stat r = 0;
6789 t_addr k;
6790 t_value pcval;
6791 
6792 fputc ('\n', st);                                       /* start on a new line */
6793 
6794 if (v >= SCPE_BASE)                                     /* SCP error? */
6795     fputs (sim_error_text (v), st);                     /* print it from the SCP list */
6796 else {                                                  /* VM error */
6797     fputs (sim_stop_messages [v], st);                  /* print the VM-specific message */
6798 
6799     if ((sim_vm_fprint_stopped != NULL) &&              /* if a VM-specific stop handler is defined */
6800         (!sim_vm_fprint_stopped (st, v)))               /*   call it; if it returned FALSE, */
6801         return;                                         /*     we're done */
6802     }
6803 
6804 (void)fprintf (st, ", %s: ", pc->name);                       /* print the name of the PC register */
6805 
6806 pcval = get_rval (pc, 0);
6807 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)       /* if reg wants VM-specific printer */
6808     sim_vm_fprint_addr (st, dptr, (t_addr) pcval);      /*   call it to print the PC address */
6809 else fprint_val (st, pcval, pc->radix, pc->width,       /* otherwise, print as a numeric value */
6810     pc->flags & REG_FMT);                               /*   with the radix and formatting specified */
6811 if ((dptr != NULL) && (dptr->examine != NULL)) {
6812     for (i = 0; i < sim_emax; i++)
6813         sim_eval[i] = 0;
6814     for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6815         if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6816             break;
6817         }
6818     if ((r == SCPE_OK) || (i > 0)) {
6819         (void)fprintf (st, " (");
6820         if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6821             fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6822         (void)fprintf (st, ")");
6823         }
6824     }
6825 (void)fprintf (st, "\r\n");
6826 return;
6827 }
6828 
6829 void fprint_stopped (FILE *st, t_stat v)
     /* [previous][next][first][last][top][bottom][index][help] */
6830 {
6831 #if defined(WIN_STDIO)
6832 (void)fflush(stderr);
6833 (void)fflush(stdout);
6834 #endif /* if defined(WIN_STDIO) */
6835 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6836 return;
6837 }
6838 
6839 /* Unit service for step timeout, originally scheduled by STEP n command
6840    Return step timeout SCP code, will cause simulation to stop */
6841 
6842 t_stat step_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6843 {
6844 return SCPE_STEP;
6845 }
6846 
6847 /* Unit service to facilitate expect matching to stop simulation.
6848    Return expect SCP code, will cause simulation to stop */
6849 
6850 t_stat expect_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6851 {
6852 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6853 }
6854 
6855 /* Signal handler for ^C signal - set stop simulation flag */
6856 
6857 void int_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
6858 {
6859 stop_cpu = 1;
6860 return;
6861 }
6862 
6863 /* Examine/deposit commands */
6864 
6865 t_stat exdep_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6866 {
6867 char gbuf[CBUFSIZE];
6868 CONST char *gptr;
6869 CONST char *tptr = NULL;
6870 int32 opt;
6871 t_addr low, high;
6872 t_stat reason = SCPE_IERR;
6873 DEVICE *tdptr;
6874 REG *lowr, *highr;
6875 FILE *ofile;
6876 
6877 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;               /* options for all */
6878 if (flag == EX_E)                                       /* extra for EX */
6879     opt = opt | CMD_OPT_OF;
6880 cptr = get_sim_opt (opt, cptr, &reason);                /* get cmd options */
6881 if (NULL == cptr)                                       /* error? */
6882     return reason;
6883 if (*cptr == 0)                                         /* must be more */
6884     return SCPE_2FARG;
6885 if (sim_dfunit == NULL)                                 /* got a unit? */
6886     return SCPE_NXUN;
6887 cptr = get_glyph (cptr, gbuf, 0);                       /* get list */
6888 if ((flag == EX_D) && (*cptr == 0))                     /* deposit needs more */
6889 
6890     return SCPE_2FARG;
6891 ofile = sim_ofile? sim_ofile: stdout;                   /* no ofile? use stdout */
6892 
6893 for (gptr = gbuf, reason = SCPE_OK;
6894     (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6895     tdptr = sim_dfdev;                                  /* working dptr */
6896     if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6897         tptr = gptr + strlen ("STATE");
6898         if (*tptr && (*tptr++ != ','))
6899             return SCPE_ARG;
6900         if ((lowr = sim_dfdev->registers) == NULL)
6901             return SCPE_NXREG;
6902         for (highr = lowr; highr->name != NULL; highr++) ;
6903         sim_switches = sim_switches | SIM_SW_HIDE;
6904         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6905             lowr, --highr, 0, 0);
6906         continue;
6907         }
6908 
6909     /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
6910     if ((lowr = find_reg (gptr, &tptr, tdptr)) ||       /* local reg or */
6911         (!(sim_opt_out & CMD_OPT_DFT) &&                /* no dflt, global? */
6912         (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6913         low = high = 0;
6914         if ((*tptr == '-') || (*tptr == ':')) {
6915             highr = find_reg (tptr + 1, &tptr, tdptr);
6916             if (highr == NULL)
6917                 return SCPE_NXREG;
6918             }
6919         else {
6920             highr = lowr;
6921             if (*tptr == '[') {
6922                 if (lowr->depth <= 1)
6923                     return SCPE_ARG;
6924                 tptr = get_range (NULL, tptr + 1, &low, &high,
6925                     10, lowr->depth - 1, ']');
6926                 if (tptr == NULL)
6927                     return SCPE_ARG;
6928                 }
6929             }
6930         if (*tptr && (*tptr++ != ','))
6931             return SCPE_ARG;
6932         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6933             lowr, highr, (uint32) low, (uint32) high);
6934         continue;
6935         }
6936 
6937     tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6938         (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6939         sim_dfunit->capac - sim_dfdev->aincr), 0);
6940     if (tptr == NULL)
6941         return SCPE_ARG;
6942     if (*tptr && (*tptr++ != ','))
6943         return SCPE_ARG;
6944     reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6945         sim_dfdev, sim_dfunit);
6946     }                                                   /* end for */
6947 if (sim_ofile)                                          /* close output file */
6948     fclose (sim_ofile);
6949 return reason;
6950 }
6951 
6952 /* Loop controllers for examine/deposit
6953 
6954    exdep_reg_loop       examine/deposit range of registers
6955    exdep_addr_loop      examine/deposit range of addresses
6956 */
6957 
6958 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6959     REG *lowr, REG *highr, uint32 lows, uint32 highs)
6960 {
6961 t_stat reason;
6962 uint32 idx, val_start=lows;
6963 t_value val, last_val;
6964 REG *rptr;
6965 
6966 if ((lowr == NULL) || (highr == NULL))
6967     return SCPE_IERR;
6968 if (lowr > highr)
6969     return SCPE_ARG;
6970 for (rptr = lowr; rptr <= highr; rptr++) {
6971     if ((sim_switches & SIM_SW_HIDE) &&
6972         (rptr->flags & REG_HIDDEN))
6973         continue;
6974     val = last_val = 0;
6975     for (idx = lows; idx <= highs; idx++) {
6976         if (idx >= rptr->depth)
6977             return SCPE_SUB;
6978         val = get_rval (rptr, idx);
6979         if (schptr && !test_search (&val, schptr))
6980             continue;
6981         if (flag == EX_E) {
6982             if ((idx > lows) && (val == last_val))
6983                 continue;
6984             if (idx > val_start+1) {
6985                 if (idx-1 == val_start+1) {
6986                     reason = ex_reg (ofile, val, flag, rptr, idx-1);
6987                     if (reason != SCPE_OK)
6988                         return reason;
6989                     if (sim_log && (ofile == stdout))
6990                         ex_reg (sim_log, val, flag, rptr, idx-1);
6991                     }
6992                 else {
6993                     if (val_start+1 != idx-1) { //-V547
6994                         (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6995                         if (sim_log && (ofile == stdout))
6996                             (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6997                         }
6998                     else {
6999                         (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7000                         if (sim_log && (ofile == stdout))
7001                             (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7002                         }
7003                     }
7004                 }
7005             sim_last_val = last_val = val;
7006             val_start = idx;
7007             reason = ex_reg (ofile, val, flag, rptr, idx);
7008             if (reason != SCPE_OK)
7009                 return reason;
7010             if (sim_log && (ofile == stdout))
7011                 ex_reg (sim_log, val, flag, rptr, idx);
7012             }
7013         if (flag != EX_E) {
7014             reason = dep_reg (flag, cptr, rptr, idx);
7015             if (reason != SCPE_OK)
7016                 return reason;
7017             }
7018         }
7019     if ((flag == EX_E) && (val_start != highs)) {
7020         if (highs == val_start+1) {
7021             reason = ex_reg (ofile, val, flag, rptr, highs);
7022             if (reason != SCPE_OK)
7023                 return reason;
7024             if (sim_log && (ofile == stdout))
7025                 ex_reg (sim_log, val, flag, rptr, highs);
7026             }
7027         else {
7028             if (val_start+1 != highs) { //-V547
7029                 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
7030                 if (sim_log && (ofile == stdout))
7031                     (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
7032                 }
7033             else {
7034                 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7035                 if (sim_log && (ofile == stdout))
7036                     (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7037                 }
7038             }
7039         }
7040     }
7041 return SCPE_OK;
7042 }
7043 
7044 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
7045     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
7046 {
7047 t_addr i, mask;
7048 t_stat reason;
7049 
7050 if (uptr->flags & UNIT_DIS)                             /* disabled? */
7051     return SCPE_UDIS;
7052 mask = (t_addr) width_mask[dptr->awidth];
7053 if ((low > mask) || (high > mask) || (low > high))
7054     return SCPE_ARG;
7055 for (i = low; i <= high; ) {                            /* all paths must incr!! */
7056     reason = get_aval (i, dptr, uptr);                  /* get data */
7057     if (reason != SCPE_OK)                              /* return if error */
7058         return reason;
7059     if (schptr && !test_search (sim_eval, schptr))
7060         i = i + dptr->aincr;                            /* sch fails, incr */
7061     else {                                              /* no sch or success */
7062         if (flag != EX_D) {                             /* ex, ie, or id? */
7063             reason = ex_addr (ofile, flag, i, dptr, uptr);
7064             if (reason > SCPE_OK)
7065                 return reason;
7066             if (sim_log && (ofile == stdout))
7067                 ex_addr (sim_log, flag, i, dptr, uptr);
7068             }
7069         else reason = 1 - dptr->aincr;                  /* no, dflt incr */
7070         if (flag != EX_E) {                             /* ie, id, or d? */
7071             reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7072             if (reason > SCPE_OK)
7073                 return reason;
7074             }
7075         i = i + (1 - reason);                           /* incr */
7076         }
7077     }
7078 return SCPE_OK;
7079 }
7080 
7081 /* Examine register routine
7082 
7083    Inputs:
7084         ofile   =       output stream
7085         val     =       current register value
7086         flag    =       type of ex/mod command (ex, iex, idep)
7087         rptr    =       pointer to register descriptor
7088         idx     =       index
7089    Outputs:
7090         return  =       error status
7091 */
7092 
7093 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7094 {
7095 int32 rdx;
7096 
7097 if (rptr == NULL)
7098     return SCPE_IERR;
7099 if (rptr->depth > 1)
7100     (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7101 else
7102     (void)Fprintf (ofile, "%s:\t", rptr->name);
7103 if (!(flag & EX_E))
7104     return SCPE_OK;
7105 GET_RADIX (rdx, rptr->radix);
7106 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7107     sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7108 else if (!(rptr->flags & REG_VMFLAGS) ||
7109     (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7110                  NULL, sim_switches | SIM_SW_REG) > 0)) {
7111         fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7112         if (rptr->fields) {
7113             (void)Fprintf (ofile, "\t");
7114             fprint_fields (ofile, val, val, rptr->fields);
7115             }
7116         }
7117 if (flag & EX_I)
7118     (void)Fprintf (ofile, "\t");
7119 else
7120     (void)Fprintf (ofile, "\r\n");
7121 return SCPE_OK;
7122 }
7123 
7124 /* Get register value
7125 
7126    Inputs:
7127         rptr    =       pointer to register descriptor
7128         idx     =       index
7129    Outputs:
7130         return  =       register value
7131 */
7132 
7133 t_value get_rval (REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7134 {
7135 size_t sz;
7136 t_value val;
7137 uint32 *ptr;
7138 
7139 sz = SZ_R (rptr);
7140 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7141     idx = idx + rptr->qptr;
7142     if (idx >= rptr->depth) idx = idx - rptr->depth;
7143     }
7144 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7145     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7146     if (sz <= sizeof (uint32))
7147         val = *ptr;
7148     else val = *((t_uint64 *) ptr); //-V1032
7149     }
7150 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7151     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7152     if (sz <= sizeof (uint32))
7153         val = *ptr;
7154     else val = *((t_uint64 *) ptr);
7155     }
7156 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7157     (sz == sizeof (uint8)))
7158     val = *(((uint8 *) rptr->loc) + idx);
7159 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7160     (sz == sizeof (uint16)))
7161     val = *(((uint16 *) rptr->loc) + idx);
7162 else if (sz <= sizeof (uint32))
7163      val = *(((uint32 *) rptr->loc) + idx);
7164 else val = *(((t_uint64 *) rptr->loc) + idx);
7165 val = (val >> rptr->offset) & width_mask[rptr->width];
7166 return val;
7167 }
7168 
7169 /* Deposit register routine
7170 
7171    Inputs:
7172         flag    =       type of deposit (normal/interactive)
7173         cptr    =       pointer to input string
7174         rptr    =       pointer to register descriptor
7175         idx     =       index
7176    Outputs:
7177         return  =       error status
7178 */
7179 
7180 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7181 {
7182 t_stat r;
7183 t_value val, mask;
7184 int32 rdx;
7185 CONST char *tptr;
7186 char gbuf[CBUFSIZE];
7187 
7188 if ((cptr == NULL) || (rptr == NULL))
7189     return SCPE_IERR;
7190 if (rptr->flags & REG_RO)
7191     return SCPE_RO;
7192 if (flag & EX_I) {
7193     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7194     if (sim_log)
7195         (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7196     if (cptr == NULL)                                   /* force exit */
7197         return 1;
7198     if (*cptr == 0)                                     /* success */
7199         return SCPE_OK;
7200     }
7201 mask = width_mask[rptr->width];
7202 GET_RADIX (rdx, rptr->radix);
7203 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {    /* address form? */
7204     val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7205     if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7206         return SCPE_ARG;
7207     }
7208 else
7209     if (!(rptr->flags & REG_VMFLAGS) ||                 /* don't use sym? */
7210         (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7211                     &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7212     val = get_uint (cptr, rdx, mask, &r);
7213     if (r != SCPE_OK)
7214         return SCPE_ARG;
7215     }
7216 if ((rptr->flags & REG_NZ) && (val == 0))
7217     return SCPE_ARG;
7218 put_rval (rptr, idx, val);
7219 return SCPE_OK;
7220 }
7221 
7222 /* Put register value
7223 
7224    Inputs:
7225         rptr    =       pointer to register descriptor
7226         idx     =       index
7227         val     =       new value
7228         mask    =       mask
7229    Outputs:
7230         none
7231 */
7232 
7233 void put_rval (REG *rptr, uint32 idx, t_value val)
     /* [previous][next][first][last][top][bottom][index][help] */
7234 {
7235 size_t sz;
7236 t_value mask;
7237 uint32 *ptr;
7238 
7239 #define PUT_RVAL(sz,rp,id,v,m)            \
7240     *(((sz *) rp->loc) + id) =            \
7241         (sz)((*(((sz *) rp->loc) + id) &  \
7242             ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7243 
7244 if (rptr == sim_PC)
7245     sim_brk_npc (0);
7246 sz = SZ_R (rptr);
7247 mask = width_mask[rptr->width];
7248 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7249     idx = idx + rptr->qptr;
7250     if (idx >= rptr->depth)
7251         idx = idx - rptr->depth;
7252     }
7253 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7254     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7255     if (sz <= sizeof (uint32))
7256         *ptr = (*ptr &
7257         ~(((uint32) mask) << rptr->offset)) |
7258         (((uint32) val) << rptr->offset);
7259     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr) //-V1032
7260         & ~(mask << rptr->offset)) | (val << rptr->offset);
7261     }
7262 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7263     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7264     if (sz <= sizeof (uint32))
7265         *((uint32 *) ptr) = (*((uint32 *) ptr) &
7266         ~(((uint32) mask) << rptr->offset)) |
7267         (((uint32) val) << rptr->offset);
7268     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7269         & ~(mask << rptr->offset)) | (val << rptr->offset);
7270     }
7271 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7272     (sz == sizeof (uint8)))
7273     PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7274 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7275     (sz == sizeof (uint16)))
7276     PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7277 else if (sz <= sizeof (uint32))
7278     PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7279 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7280 return;
7281 }
7282 
7283 /* Examine address routine
7284 
7285    Inputs: (sim_eval is an implicit argument)
7286         ofile   =       output stream
7287         flag    =       type of ex/mod command (ex, iex, idep)
7288         addr    =       address to examine
7289         dptr    =       pointer to device
7290         uptr    =       pointer to unit
7291    Outputs:
7292         return  =       if > 0, error status
7293                         if <= 0,-number of extra addr units retired
7294 */
7295 
7296 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7297 {
7298 t_stat reason;
7299 int32 rdx;
7300 
7301 if (sim_vm_fprint_addr)
7302     sim_vm_fprint_addr (ofile, dptr, addr);
7303 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7304 (void)Fprintf (ofile, ":\t");
7305 if (!(flag & EX_E))
7306     return (1 - dptr->aincr);
7307 
7308 GET_RADIX (rdx, dptr->dradix);
7309 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7310     fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7311     reason = 1 - dptr->aincr;
7312     }
7313 if (flag & EX_I)
7314     (void)Fprintf (ofile, "\t");
7315 else
7316     (void)Fprintf (ofile, "\r\n");
7317 return reason;
7318 }
7319 
7320 /* Get address routine
7321 
7322    Inputs:
7323         flag    =       type of ex/mod command (ex, iex, idep)
7324         addr    =       address to examine
7325         dptr    =       pointer to device
7326         uptr    =       pointer to unit
7327    Outputs: (sim_eval is an implicit output)
7328         return  =       error status
7329 */
7330 
7331 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7332 {
7333 int32 i;
7334 t_value mask;
7335 t_addr j, loc;
7336 size_t sz;
7337 t_stat reason = SCPE_OK;
7338 
7339 if ((dptr == NULL) || (uptr == NULL))
7340     return SCPE_IERR;
7341 mask = width_mask[dptr->dwidth];
7342 for (i = 0; i < sim_emax; i++)
7343     sim_eval[i] = 0;
7344 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7345     if (dptr->examine != NULL) {
7346         reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7347         if (reason != SCPE_OK)
7348             break;
7349         }
7350     else {
7351         if (!(uptr->flags & UNIT_ATT))
7352             return SCPE_UNATT;
7353         if (uptr->dynflags & UNIT_NO_FIO)
7354             return SCPE_NOFNC;
7355         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7356             reason = SCPE_NXM;
7357             break;
7358             }
7359         sz = SZ_D (dptr);
7360         loc = j / dptr->aincr;
7361         if (uptr->flags & UNIT_BUF) {
7362             SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7363             }
7364         else {
7365             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7366             sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7367             if ((feof (uptr->fileref)) &&
7368                !(uptr->flags & UNIT_FIX)) {
7369                 reason = SCPE_EOF;
7370                 break;
7371                 }
7372             else if (ferror (uptr->fileref)) {
7373                 clearerr (uptr->fileref);
7374                 reason = SCPE_IOERR;
7375                 break;
7376                 }
7377             }
7378         }
7379     sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7380     }
7381 if ((reason != SCPE_OK) && (i == 0))
7382     return reason;
7383 return SCPE_OK;
7384 }
7385 
7386 /* Deposit address routine
7387 
7388    Inputs:
7389         flag    =       type of deposit (normal/interactive)
7390         cptr    =       pointer to input string
7391         addr    =       address to examine
7392         dptr    =       pointer to device
7393         uptr    =       pointer to unit
7394         dfltinc =       value to return on cr input
7395    Outputs:
7396         return  =       if > 0, error status
7397                         if <= 0, -number of extra address units retired
7398 */
7399 
7400 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
7401     UNIT *uptr, int32 dfltinc)
7402 {
7403 int32 i, count, rdx;
7404 t_addr j, loc;
7405 t_stat r, reason;
7406 t_value mask;
7407 size_t sz;
7408 char gbuf[CBUFSIZE];
7409 
7410 if (dptr == NULL)
7411     return SCPE_IERR;
7412 if (flag & EX_I) {
7413     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7414     if (sim_log)
7415         (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7416     if (cptr == NULL)                                   /* force exit */
7417         return 1;
7418     if (*cptr == 0)                                     /* success */
7419         return dfltinc;
7420     }
7421 if (uptr->flags & UNIT_RO)                              /* read only? */
7422     return SCPE_RO;
7423 mask = width_mask[dptr->dwidth];
7424 
7425 GET_RADIX (rdx, dptr->dradix);
7426 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7427     sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7428     if (reason != SCPE_OK)
7429         return reason;
7430     reason = dfltinc;
7431     }
7432 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7433 
7434 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7435     sim_eval[i] = sim_eval[i] & mask;
7436     if (dptr->deposit != NULL) {
7437         r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7438         if (r != SCPE_OK)
7439             return r;
7440         }
7441     else {
7442         if (!(uptr->flags & UNIT_ATT))
7443             return SCPE_UNATT;
7444         if (uptr->dynflags & UNIT_NO_FIO)
7445             return SCPE_NOFNC;
7446         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7447             return SCPE_NXM;
7448         sz = SZ_D (dptr);
7449         loc = j / dptr->aincr;
7450         if (uptr->flags & UNIT_BUF) {
7451             SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7452             if (loc >= uptr->hwmark)
7453                 uptr->hwmark = (uint32) loc + 1;
7454             }
7455         else {
7456             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7457             sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7458             if (ferror (uptr->fileref)) {
7459                 clearerr (uptr->fileref);
7460                 return SCPE_IOERR;
7461                 }
7462             }
7463         }
7464     }
7465 return reason;
7466 }
7467 
7468 /* Evaluate command */
7469 
7470 t_stat eval_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7471 {
7472 if (!sim_dflt_dev)
7473   return SCPE_ARG;
7474 DEVICE *dptr = sim_dflt_dev;
7475 int32 i, rdx, a, lim;
7476 t_stat r;
7477 
7478 GET_SWITCHES (cptr);
7479 GET_RADIX (rdx, dptr->dradix);
7480 for (i = 0; i < sim_emax; i++)
7481 sim_eval[i] = 0;
7482 if (*cptr == 0)
7483     return SCPE_2FARG;
7484 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7485     sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7486     if (r != SCPE_OK)
7487         return r;
7488     }
7489 lim = 1 - r;
7490 for (i = a = 0; a < lim; ) {
7491     sim_printf ("%d:\t", a);
7492     if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7493         r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7494     if (sim_log) {
7495         if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7496             r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7497         }
7498     sim_printf ("\r\n");
7499     if (r < 0)
7500         a = a + 1 - r;
7501     else a = a + dptr->aincr;
7502     i = a / dptr->aincr;
7503     }
7504 return SCPE_OK;
7505 }
7506 
7507 /* String processing routines
7508 
7509    read_line            read line
7510 
7511    Inputs:
7512         cptr    =       pointer to buffer
7513         size    =       maximum size
7514         stream  =       pointer to input stream
7515    Outputs:
7516         optr    =       pointer to first non-blank character
7517                         NULL if EOF
7518 */
7519 
7520 char *read_line (char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7521 {
7522 return read_line_p (NULL, cptr, size, stream);
7523 }
7524 
7525 /* read_line_p          read line with prompt
7526 
7527    Inputs:
7528         prompt  =       pointer to prompt string
7529         cptr    =       pointer to buffer
7530         size    =       maximum size
7531         stream  =       pointer to input stream
7532    Outputs:
7533         optr    =       pointer to first non-blank character
7534                         NULL if EOF
7535 */
7536 
7537 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7538 {
7539 char *tptr;
7540 
7541 if (prompt) {                                           /* interactive? */
7542 #if defined(HAVE_LINEHISTORY)
7543         char *tmpc = linenoise (prompt);                /* get cmd line */
7544         if (tmpc == NULL)                               /* bad result? */
7545             cptr = NULL;
7546         else {
7547             strncpy (cptr, tmpc, size-1);               /* copy result */
7548             linenoiseHistoryAdd (tmpc);                 /* add to history */
7549             FREE (tmpc);                                /* free temp */
7550             }
7551         }
7552 #else
7553         (void)fflush (stdout);                          /* flush output */
7554         (void)printf ("%s", prompt);                    /* display prompt */
7555         (void)fflush (stdout);                          /* flush output */
7556         cptr = fgets (cptr, size, stream);              /* get cmd line */
7557         }
7558 #endif /* if defined(HAVE_LINEHISTORY) */
7559 else cptr = fgets (cptr, size, stream);                 /* get cmd line */
7560 
7561 if (cptr == NULL) {
7562     clearerr (stream);                                  /* clear error */
7563     return NULL;                                        /* ignore EOF */
7564     }
7565 for (tptr = cptr; tptr < (cptr + size); tptr++) {       /* remove cr or nl */
7566     if ((*tptr == '\n') || (*tptr == '\r') ||
7567         (tptr == (cptr + size - 1))) {                  /* str max length? */
7568         *tptr = 0;                                      /* terminate */
7569         break;
7570         }
7571     }
7572 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))              /* Skip/ignore UTF8_BOM */
7573     memmove (cptr, cptr + 3, strlen (cptr + 3));
7574 while (sim_isspace (*cptr))                             /* trim leading spc */
7575     cptr++;
7576 if ((*cptr == ';') || (*cptr == '#')) {                 /* ignore comment */
7577     if (sim_do_echo)                                    /* echo comments if -v */
7578         sim_printf("%s> %s\r\n", do_position(), cptr);
7579     *cptr = 0;
7580     }
7581 
7582 return cptr;
7583 }
7584 
7585 /* get_glyph            get next glyph (force upper case)
7586    get_glyph_nc         get next glyph (no conversion)
7587    get_glyph_quoted     get next glyph (potentially enclosed in quotes, no conversion)
7588    get_glyph_cmd        get command glyph (force upper case, extract leading !)
7589    get_glyph_gen        get next glyph (general case)
7590 
7591    Inputs:
7592         iptr        =   pointer to input string
7593         optr        =   pointer to output string
7594         mchar       =   optional end of glyph character
7595         uc          =   TRUE for convert to upper case (_gen only)
7596         quote       =   TRUE to allow quote enclosing values (_gen only)
7597         escape_char =   optional escape character within quoted strings (_gen only)
7598 
7599    Outputs
7600         result      =   pointer to next character in input string
7601 */
7602 
7603 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
     /* [previous][next][first][last][top][bottom][index][help] */
7604 {
7605 t_bool quoting = FALSE;
7606 t_bool escaping = FALSE;
7607 char quote_char = 0;
7608 
7609 while ((*iptr != 0) &&
7610        ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7611     if (quote) {
7612         if (quoting) {
7613             if (!escaping) {
7614                 if (*iptr == escape_char)
7615                     escaping = TRUE;
7616                 else
7617                     if (*iptr == quote_char)
7618                         quoting = FALSE;
7619                 }
7620             else
7621                 escaping = FALSE;
7622             }
7623         else {
7624             if ((*iptr == '"') || (*iptr == '\'')) {
7625                 quoting = TRUE;
7626                 quote_char = *iptr;
7627                 }
7628             }
7629         }
7630     if (sim_islower (*iptr) && uc)
7631         *optr = (char)toupper (*iptr);
7632     else *optr = *iptr;
7633     iptr++; optr++;
7634     }
7635 if (mchar && (*iptr == mchar))              /* skip input terminator */
7636     iptr++;
7637 *optr = 0;                                  /* terminate result string */
7638 while (sim_isspace (*iptr))                 /* absorb additional input spaces */
7639     iptr++;
7640 return iptr;
7641 }
7642 
7643 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7644 {
7645 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7646 }
7647 
7648 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7649 {
7650 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7651 }
7652 
7653 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7654 {
7655 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7656 }
7657 
7658 CONST char *get_glyph_cmd (const char *iptr, char *optr)
     /* [previous][next][first][last][top][bottom][index][help] */
7659 {
7660 /* Tolerate "!subprocess" vs. requiring "! subprocess" */
7661 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7662     strcpy (optr, "!");                     /* return ! as command glyph */
7663     return (CONST char *)(iptr + 1);        /* and skip over the leading ! */
7664     }
7665 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7666 }
7667 
7668 /* Trim trailing spaces from a string
7669 
7670     Inputs:
7671         cptr    =       pointer to string
7672     Outputs:
7673         cptr    =       pointer to string
7674 */
7675 
7676 char *sim_trim_endspc (char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7677 {
7678 char *tptr;
7679 
7680 tptr = cptr + strlen (cptr);
7681 while ((--tptr >= cptr) && sim_isspace (*tptr))
7682     *tptr = 0;
7683 return cptr;
7684 }
7685 
7686 int sim_isspace (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7687 {
7688 return (c & 0x80) ? 0 : isspace (c);
7689 }
7690 
7691 int sim_islower (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7692 {
7693 return (c & 0x80) ? 0 : islower (c);
7694 }
7695 
7696 int sim_isalpha (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7697 {
7698 return (c & 0x80) ? 0 : isalpha (c);
7699 }
7700 
7701 int sim_isprint (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7702 {
7703 return (c & 0x80) ? 0 : isprint (c);
7704 }
7705 
7706 int sim_isdigit (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7707 {
7708 return (c & 0x80) ? 0 : isdigit (c);
7709 }
7710 
7711 int sim_isgraph (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7712 {
7713 return (c & 0x80) ? 0 : isgraph (c);
7714 }
7715 
7716 int sim_isalnum (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7717 {
7718 return (c & 0x80) ? 0 : isalnum (c);
7719 }
7720 
7721 /* get_uint             unsigned number
7722 
7723    Inputs:
7724         cptr    =       pointer to input string
7725         radix   =       input radix
7726         max     =       maximum acceptable value
7727         *status =       pointer to error status
7728    Outputs:
7729         val     =       value
7730 */
7731 
7732 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
     /* [previous][next][first][last][top][bottom][index][help] */
7733 {
7734 t_value val;
7735 CONST char *tptr;
7736 
7737 *status = SCPE_OK;
7738 val = strtotv ((CONST char *)cptr, &tptr, radix);
7739 if ((cptr == tptr) || (val > max))
7740     *status = SCPE_ARG;
7741 else {
7742     while (sim_isspace (*tptr)) tptr++;
7743     if (*tptr != 0)
7744         *status = SCPE_ARG;
7745     }
7746 return val;
7747 }
7748 
7749 /* get_range            range specification
7750 
7751    Inputs:
7752         dptr    =       pointer to device (NULL if none)
7753         cptr    =       pointer to input string
7754         *lo     =       pointer to low result
7755         *hi     =       pointer to high result
7756         aradix  =       radix
7757         max     =       default high value
7758         term    =       terminating character, 0 if none
7759    Outputs:
7760         tptr    =       input pointer after processing
7761                         NULL if error
7762 */
7763 
7764 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
     /* [previous][next][first][last][top][bottom][index][help] */
7765     uint32 rdx, t_addr max, char term)
7766 {
7767 CONST char *tptr;
7768 
7769 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {    /* ALL? */
7770     tptr = cptr + strlen ("ALL");
7771     *lo = 0;
7772     *hi = max;
7773     }
7774 else {
7775     if ((strncmp (cptr, ".", strlen (".")) == 0) &&             /* .? */
7776         ((cptr[1] == '\0') ||
7777          (cptr[1] == '-')  ||
7778          (cptr[1] == ':')  ||
7779          (cptr[1] == '/'))) {
7780         tptr = cptr + strlen (".");
7781         *lo = *hi = sim_last_addr;
7782         }
7783     else {
7784         if (strncmp (cptr, "$", strlen ("$")) == 0) {           /* $? */
7785             tptr = cptr + strlen ("$");
7786             *hi = *lo = (t_addr)sim_last_val;
7787             }
7788         else {
7789             if (dptr && sim_vm_parse_addr)                      /* get low */
7790                 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7791             else
7792                 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7793             if (cptr == tptr)                                   /* error? */
7794                     return NULL;
7795             }
7796         }
7797     if ((*tptr == '-') || (*tptr == ':')) {             /* range? */
7798         cptr = tptr + 1;
7799         if (dptr && sim_vm_parse_addr)                  /* get high */
7800             *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7801         else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7802         if (cptr == tptr)
7803             return NULL;
7804         if (*lo > *hi)
7805             return NULL;
7806         }
7807     else if (*tptr == '/') {                            /* relative? */
7808         cptr = tptr + 1;
7809         *hi = (t_addr) strtotv (cptr, &tptr, rdx);      /* get high */
7810         if ((cptr == tptr) || (*hi == 0))
7811             return NULL;
7812         *hi = *lo + *hi - 1;
7813         }
7814     else *hi = *lo;
7815     }
7816 sim_last_addr = *hi;
7817 if (term && (*tptr++ != term))
7818     return NULL;
7819 return tptr;
7820 }
7821 
7822 /* sim_decode_quoted_string
7823 
7824    Inputs:
7825         iptr        =   pointer to input string
7826         optr        =   pointer to output buffer
7827                         the output buffer must be allocated by the caller
7828                         and to avoid overrunat it must be at least as big
7829                         as the input string.
7830 
7831    Outputs
7832         result      =   status of decode SCPE_OK when good, SCPE_ARG otherwise
7833         osize       =   size of the data in the optr buffer
7834 
7835    The input string must be quoted.  Quotes may be either single or
7836    double but the opening anc closing quote characters must match.
7837    Within quotes C style character escapes are allowed.
7838 */
7839 
7840 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
     /* [previous][next][first][last][top][bottom][index][help] */
7841 {
7842 char quote_char;
7843 uint8 *ostart = optr;
7844 
7845 *osize = 0;
7846 if ((strlen(iptr) == 1) ||
7847     (iptr[0] != iptr[strlen(iptr)-1]) ||
7848     ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7849     return SCPE_ARG;            /* String must be quote delimited */
7850 quote_char = *iptr++;           /* Save quote character */
7851 while (iptr[1]) {               /* Skip trailing quote */
7852     if (*iptr != '\\') {
7853         if (*iptr == quote_char)
7854             return SCPE_ARG;    /* Embedded quotes must be escaped */
7855         *(optr++) = (uint8)(*(iptr++));
7856         continue;
7857         }
7858     ++iptr; /* Skip backslash */
7859     switch (*iptr) {
7860         case 'r':   /* ASCII Carriage Return character (Decimal value 13) */
7861             *(optr++) = 13; ++iptr;
7862             break;
7863         case 'n':   /* ASCII Linefeed character (Decimal value 10) */
7864             *(optr++) = 10; ++iptr;
7865             break;
7866         case 'f':   /* ASCII Formfeed character (Decimal value 12) */
7867             *(optr++) = 12; ++iptr;
7868             break;
7869         case 't':   /* ASCII Horizontal Tab character (Decimal value 9) */
7870             *(optr++) = 9; ++iptr;
7871             break;
7872         case 'v':   /* ASCII Vertical Tab character (Decimal value 11) */
7873             *(optr++) = 11; ++iptr;
7874             break;
7875         case 'b':   /* ASCII Backspace character (Decimal value 8) */
7876             *(optr++) = 8; ++iptr;
7877             break;
7878         case '\\':   /* ASCII Backslash character (Decimal value 92) */
7879             *(optr++) = 92; ++iptr;
7880             break;
7881         case 'e':   /* ASCII Escape character (Decimal value 27) */
7882             *(optr++) = 27; ++iptr;
7883             break;
7884         case '\'':   /* ASCII Single Quote character (Decimal value 39) */
7885             *(optr++) = 39; ++iptr;
7886             break;
7887         case '"':   /* ASCII Double Quote character (Decimal value 34) */
7888             *(optr++) = 34; ++iptr;
7889             break;
7890         case '?':   /* ASCII Question Mark character (Decimal value 63) */
7891             *(optr++) = 63; ++iptr;
7892             break;
7893         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7894             *optr = *(iptr++) - '0';
7895             if ((*iptr >= '0') && (*iptr <= '7'))
7896                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7897             if ((*iptr >= '0') && (*iptr <= '7'))
7898                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7899             ++optr;
7900             break;
7901         case 'x':
7902             if (1) {
7903                 static const char *hex_digits = "0123456789ABCDEF";
7904                 const char *c;
7905 
7906                 ++iptr;
7907                 *optr = 0;
7908                 c = strchr (hex_digits, toupper(*iptr));
7909                 if (c) {
7910                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7911                     ++iptr;
7912                     }
7913                 c = strchr (hex_digits, toupper(*iptr));
7914                 if (c) {
7915                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7916                     ++iptr;
7917                     }
7918                 ++optr;
7919                 }
7920             break;
7921         default:
7922             return SCPE_ARG;    /* Invalid escape */
7923         }
7924     }
7925 *optr = '\0';
7926 *osize = (uint32)(optr-ostart);
7927 return SCPE_OK;
7928 }
7929 
7930 /* sim_encode_quoted_string
7931 
7932    Inputs:
7933         iptr        =   pointer to input buffer
7934         size        =   number of bytes of data in the buffer
7935 
7936    Outputs
7937         optr        =   pointer to output buffer
7938                         the output buffer must be freed by the caller
7939 
7940    The input data will be encoded into a simply printable form.
7941 */
7942 
7943 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7944 {
7945 size_t i;
7946 t_bool double_quote_found = FALSE;
7947 t_bool single_quote_found = FALSE;
7948 char quote = '"';
7949 char *tptr, *optr;
7950 
7951 optr = (char *)malloc (4*size + 3);
7952 if (optr == NULL)
7953     return NULL;
7954 tptr = optr;
7955 for (i=0; i<size; i++)
7956     switch ((char)iptr[i]) {
7957         case '"':
7958             double_quote_found = TRUE;
7959             break;
7960         case '\'':
7961             single_quote_found = TRUE;
7962             break;
7963         }
7964 if (double_quote_found && (!single_quote_found))
7965     quote = '\'';
7966 *tptr++ = quote;
7967 while (size--) {
7968     switch (*iptr) {
7969         case '\r':
7970             *tptr++ = '\\'; *tptr++ = 'r'; break;
7971         case '\n':
7972             *tptr++ = '\\'; *tptr++ = 'n'; break;
7973         case '\f':
7974             *tptr++ = '\\'; *tptr++ = 'f'; break;
7975         case '\t':
7976             *tptr++ = '\\'; *tptr++ = 't'; break;
7977         case '\v':
7978             *tptr++ = '\\'; *tptr++ = 'v'; break;
7979         case '\b':
7980             *tptr++ = '\\'; *tptr++ = 'b'; break;
7981         case '\\':
7982             *tptr++ = '\\'; *tptr++ = '\\'; break;
7983         case '"':
7984         case '\'':
7985             if (quote == *iptr)
7986                 *tptr++ = '\\';
7987         /*FALLTHRU*/ /* fall through */ /* fallthrough */
7988         default:
7989             if (sim_isprint (*iptr))
7990                 *tptr++ = *iptr;
7991             else {
7992                 (void)sprintf (tptr, "\\%03o", *iptr);
7993                 tptr += 4;
7994                 }
7995             break;
7996         }
7997     ++iptr;
7998     }
7999 *tptr++ = quote;
8000 *tptr++ = '\0';
8001 return optr;
8002 }
8003 
8004 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
8005 {
8006 char *string;
8007 
8008 string = sim_encode_quoted_string (buf, size);
8009 (void)fprintf (st, "%s", string);
8010 FREE (string);
8011 }
8012 
8013 /* Find_device          find device matching input string
8014 
8015    Inputs:
8016         cptr    =       pointer to input string
8017    Outputs:
8018         result  =       pointer to device
8019 */
8020 
8021 DEVICE *find_dev (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8022 {
8023 int32 i;
8024 DEVICE *dptr;
8025 
8026 if (cptr == NULL)
8027     return NULL;
8028 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8029     if ((strcmp (cptr, dptr->name) == 0) ||
8030         (dptr->lname &&
8031         (strcmp (cptr, dptr->lname) == 0)))
8032         return dptr;
8033     }
8034 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
8035     if ((strcmp (cptr, dptr->name) == 0) ||
8036         (dptr->lname &&
8037         (strcmp (cptr, dptr->lname) == 0)))
8038         return dptr;
8039     }
8040 return NULL;
8041 }
8042 
8043 /* Find_unit            find unit matching input string
8044 
8045    Inputs:
8046         cptr    =       pointer to input string
8047         uptr    =       pointer to unit pointer
8048    Outputs:
8049         result  =       pointer to device (null if no dev)
8050         *iptr   =       pointer to unit (null if nx unit)
8051 
8052 */
8053 
8054 DEVICE *find_unit (const char *cptr, UNIT **uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8055 {
8056 uint32 i, u;
8057 const char *nptr;
8058 const char *tptr;
8059 t_stat r;
8060 DEVICE *dptr;
8061 
8062 if (uptr == NULL)                                       /* arg error? */
8063     return NULL;
8064 *uptr = NULL;
8065 if ((dptr = find_dev (cptr))) {                         /* exact match? */
8066     if (qdisable (dptr))                                /* disabled? */
8067         return NULL;
8068     *uptr = dptr->units;                                /* unit 0 */
8069     return dptr;
8070     }
8071 
8072 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {     /* base + unit#? */
8073     if (qdisable (dptr))                                /* device disabled? */
8074         continue;
8075     if (dptr->numunits && /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/ /* any units? */
8076         (((nptr = dptr->name) &&
8077           (strncmp (cptr, nptr, strlen (nptr)) == 0)) || /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8078          ((nptr = dptr->lname) &&
8079           (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8080         tptr = cptr + strlen (nptr);
8081         if (sim_isdigit (*tptr)) {
8082             if (qdisable (dptr))                        /* disabled? */
8083                 return NULL;
8084             u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8085             if (r != SCPE_OK)                           /* error? */
8086                 *uptr = NULL;
8087             else
8088                 *uptr = dptr->units + u;
8089             return dptr;
8090             }
8091         }
8092     for (u = 0; u < dptr->numunits; u++) {
8093         if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8094             *uptr = &dptr->units[u];
8095             return dptr;
8096             }
8097         }
8098     }
8099 return NULL;
8100 }
8101 
8102 /* sim_register_internal_device   Add device to internal device list
8103 
8104    Inputs:
8105         dptr    =       pointer to device
8106 */
8107 
8108 t_stat sim_register_internal_device (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8109 {
8110 uint32 i;
8111 
8112 for (i = 0; (sim_devices[i] != NULL); i++)
8113     if (sim_devices[i] == dptr)
8114         return SCPE_OK;
8115 for (i = 0; i < sim_internal_device_count; i++)
8116     if (sim_internal_devices[i] == dptr)
8117         return SCPE_OK;
8118 ++sim_internal_device_count;
8119 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8120 if (!sim_internal_devices)
8121   {
8122     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8123                    __func__, __FILE__, __LINE__);
8124 #if defined(USE_BACKTRACE)
8125 # if defined(SIGUSR2)
8126     (void)raise(SIGUSR2);
8127     /*NOTREACHED*/ /* unreachable */
8128 # endif /* if defined(SIGUSR2) */
8129 #endif /* if defined(USE_BACKTRACE) */
8130     abort();
8131   }
8132 sim_internal_devices[sim_internal_device_count-1] = dptr;
8133 sim_internal_devices[sim_internal_device_count] = NULL;
8134 return SCPE_OK;
8135 }
8136 
8137 /* Find_dev_from_unit   find device for unit
8138 
8139    Inputs:
8140         uptr    =       pointer to unit
8141    Outputs:
8142         result  =       pointer to device
8143 */
8144 
8145 DEVICE *find_dev_from_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8146 {
8147 DEVICE *dptr;
8148 uint32 i, j;
8149 
8150 if (uptr == NULL)
8151     return NULL;
8152 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8153     for (j = 0; j < dptr->numunits; j++) {
8154         if (uptr == (dptr->units + j))
8155             return dptr;
8156         }
8157     }
8158 for (i = 0; i<sim_internal_device_count; i++) {
8159     dptr = sim_internal_devices[i];
8160     for (j = 0; j < dptr->numunits; j++) {
8161         if (uptr == (dptr->units + j))
8162             return dptr;
8163         }
8164     }
8165 return NULL;
8166 }
8167 
8168 /* Test for disabled device */
8169 
8170 t_bool qdisable (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8171 {
8172 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8173 }
8174 
8175 /* find_reg_glob        find globally unique register
8176 
8177    Inputs:
8178         cptr    =       pointer to input string
8179         optr    =       pointer to output pointer (can be null)
8180         gdptr   =       pointer to global device
8181    Outputs:
8182         result  =       pointer to register, NULL if error
8183         *optr   =       pointer to next character in input string
8184         *gdptr  =       pointer to device where found
8185 */
8186 
8187 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8188 {
8189 int32 i;
8190 DEVICE *dptr;
8191 REG *rptr, *srptr = NULL;
8192 
8193 *gdptr = NULL;
8194 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {        /* all dev */
8195     if (dptr->flags & DEV_DIS)                          /* skip disabled */
8196         continue;
8197     if ((rptr = find_reg (cptr, optr, dptr))) {         /* found? */
8198         if (srptr)                                      /* ambig? err */
8199             return NULL;
8200         srptr = rptr;                                   /* save reg */
8201         *gdptr = dptr;                                  /* save unit */
8202         }
8203     }
8204 return srptr;
8205 }
8206 
8207 /* find_reg             find register matching input string
8208 
8209    Inputs:
8210         cptr    =       pointer to input string
8211         optr    =       pointer to output pointer (can be null)
8212         dptr    =       pointer to device
8213    Outputs:
8214         result  =       pointer to register, NULL if error
8215         *optr   =       pointer to next character in input string
8216 */
8217 
8218 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8219 {
8220 CONST char *tptr;
8221 REG *rptr;
8222 size_t slnt;
8223 
8224 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8225     return NULL;
8226 tptr = cptr;
8227 do {
8228     tptr++;
8229     } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8230 slnt = tptr - cptr;
8231 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8232     if ((slnt == strlen (rptr->name)) &&
8233         (strncmp (cptr, rptr->name, slnt) == 0)) {
8234         if (optr != NULL)
8235             *optr = tptr;
8236         return rptr;
8237         }
8238     }
8239 return NULL;
8240 }
8241 
8242 /* get_switches         get switches from input string
8243 
8244    Inputs:
8245         cptr    =       pointer to input string
8246    Outputs:
8247         sw      =       switch bit mask
8248                         0 if no switches, -1 if error
8249 */
8250 
8251 int32 get_switches (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8252 {
8253 int32 sw;
8254 
8255 if (*cptr != '-')
8256     return 0;
8257 sw = 0;
8258 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8259     if (sim_isalpha (*cptr) == 0)
8260         return -1;
8261     sw = sw | SWMASK (toupper (*cptr));
8262     }
8263 return sw;
8264 }
8265 
8266 /* get_sim_sw           accumulate sim_switches
8267 
8268    Inputs:
8269         cptr    =       pointer to input string
8270    Outputs:
8271         ptr     =       pointer to first non-string glyph
8272                         NULL if error
8273 */
8274 
8275 CONST char *get_sim_sw (CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8276 {
8277 int32 lsw;
8278 char gbuf[CBUFSIZE];
8279 
8280 while (*cptr == '-') {                                  /* while switches */
8281     cptr = get_glyph (cptr, gbuf, 0);                   /* get switch glyph */
8282     lsw = get_switches (gbuf);                          /* parse */
8283     if (lsw <= 0)                                       /* invalid? */
8284         return NULL;
8285     sim_switches = sim_switches | lsw;                  /* accumulate */
8286     }
8287 return cptr;
8288 }
8289 
8290 /* get_sim_opt          get simulator command options
8291 
8292    Inputs:
8293         opt     =       command options
8294         cptr    =       pointer to input string
8295    Outputs:
8296         ptr     =       pointer to next glyph, NULL if error
8297         *stat   =       error status
8298 */
8299 
8300 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
     /* [previous][next][first][last][top][bottom][index][help] */
8301 {
8302 int32 t;
8303 char gbuf[CBUFSIZE];
8304 CONST char *svptr;
8305 DEVICE *tdptr;
8306 UNIT *tuptr;
8307 
8308 sim_switches = 0;                                       /* no switches */
8309 sim_ofile = NULL;                                       /* no output file */
8310 sim_schrptr = NULL;                                     /* no search */
8311 sim_schaptr = NULL;                                     /* no search */
8312 sim_stabr.logic = sim_staba.logic = SCH_OR;             /* default search params */
8313 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8314 sim_stabr.count = 1;
8315 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8316 if (!sim_stabr.mask)
8317   {
8318     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8319                    __func__, __FILE__, __LINE__);
8320 #if defined(USE_BACKTRACE)
8321 # if defined(SIGUSR2)
8322     (void)raise(SIGUSR2);
8323     /*NOTREACHED*/ /* unreachable */
8324 # endif /* if defined(SIGUSR2) */
8325 #endif /* if defined(USE_BACKTRACE) */
8326     abort();
8327   }
8328 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8329 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8330 if (!sim_stabr.comp)
8331   {
8332     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8333                    __func__, __FILE__, __LINE__);
8334 #if defined(USE_BACKTRACE)
8335 # if defined(SIGUSR2)
8336     (void)raise(SIGUSR2);
8337     /*NOTREACHED*/ /* unreachable */
8338 # endif /* if defined(SIGUSR2) */
8339 #endif /* if defined(USE_BACKTRACE) */
8340     abort();
8341   }
8342 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8343 sim_staba.count = sim_emax;
8344 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8345 if (!sim_staba.mask)
8346   {
8347     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8348                    __func__, __FILE__, __LINE__);
8349 #if defined(USE_BACKTRACE)
8350 # if defined(SIGUSR2)
8351     (void)raise(SIGUSR2);
8352     /*NOTREACHED*/ /* unreachable */
8353 # endif /* if defined(SIGUSR2) */
8354 #endif /* if defined(USE_BACKTRACE) */
8355     abort();
8356   }
8357 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8358 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8359 if (!sim_staba.comp)
8360   {
8361     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8362                    __func__, __FILE__, __LINE__);
8363 #if defined(USE_BACKTRACE)
8364 # if defined(SIGUSR2)
8365     (void)raise(SIGUSR2);
8366     /*NOTREACHED*/ /* unreachable */
8367 # endif /* if defined(SIGUSR2) */
8368 #endif /* if defined(USE_BACKTRACE) */
8369     abort();
8370   }
8371 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8372 if (! sim_dflt_dev)
8373   return NULL;
8374 sim_dfdev = sim_dflt_dev;
8375 sim_dfunit = sim_dfdev->units;
8376 sim_opt_out = 0;                                        /* no options yet */
8377 *st = SCPE_OK;
8378 while (*cptr) {                                         /* loop through modifiers */
8379     svptr = cptr;                                       /* save current position */
8380     if ((opt & CMD_OPT_OF) && (*cptr == '@')) {         /* output file spec? */
8381         if (sim_ofile) {                                /* already got one? */
8382             fclose (sim_ofile);                         /* one per customer */
8383             *st = SCPE_ARG;
8384             return NULL;
8385             }
8386         cptr = get_glyph (cptr + 1, gbuf, 0);
8387         sim_ofile = sim_fopen (gbuf, "a");              /* open for append */
8388         if (sim_ofile == NULL) {                        /* open failed? */
8389             *st = SCPE_OPENERR;
8390             return NULL;
8391             }
8392         sim_opt_out |= CMD_OPT_OF;                      /* got output file */
8393         continue;
8394         }
8395     cptr = get_glyph (cptr, gbuf, 0);
8396     if ((t = get_switches (gbuf)) != 0) {               /* try for switches */
8397         if (t < 0) {                                    /* err if bad switch */
8398             *st = SCPE_INVSW;
8399             return NULL;
8400             }
8401         sim_switches = sim_switches | t;                /* or in new switches */
8402         }
8403     else if ((opt & CMD_OPT_SCH) &&                     /* if allowed, */
8404         get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) { /* try for search */
8405         sim_schrptr = &sim_stabr;                       /* set search */
8406         sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);/* populate memory version of the same expression */
8407         sim_opt_out |= CMD_OPT_SCH;                     /* got search */
8408         }
8409     else if ((opt & CMD_OPT_DFT) &&                     /* default allowed? */
8410         ((sim_opt_out & CMD_OPT_DFT) == 0) &&           /* none yet? */
8411         (tdptr = find_unit (gbuf, &tuptr)) &&           /* try for default */
8412         (tuptr != NULL)) {
8413         sim_dfdev = tdptr;                              /* set as default */
8414         sim_dfunit = tuptr;
8415         sim_opt_out |= CMD_OPT_DFT;                     /* got default */
8416         }
8417     else return svptr;                                  /* not rec, break out */
8418     }
8419 return cptr;
8420 }
8421 
8422 /* put_switches         put switches into string
8423 
8424    Inputs:
8425         buf     =       pointer to string buffer
8426         bufsize =       size of string buffer
8427         sw      =       switch bit mask
8428    Outputs:
8429         buf     =       buffer with switches converted to text
8430 */
8431 
8432 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
8433 {
8434 char *optr = buf;
8435 int32 bit;
8436 
8437 (void)memset (buf, 0, bufsize);
8438 if ((sw == 0) || (bufsize < 3))
8439     return buf;
8440 --bufsize;                          /* leave room for terminating NUL */
8441 *optr++ = '-';
8442 for (bit=0; bit <= ('Z'-'A'); bit++)
8443     if (sw & (1 << bit))
8444         if ((size_t)(optr - buf) < bufsize)
8445             *optr++ = 'A' + bit;
8446 return buf;
8447 }
8448 
8449 /* Get register search specification
8450 
8451    Inputs:
8452         cptr    =       pointer to input string
8453         radix   =       radix for numbers
8454         schptr =        pointer to search table
8455    Outputs:
8456         return =        NULL if error
8457                         schptr if valid search specification
8458 */
8459 
8460 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8461 {
8462 int32 c;
8463 size_t logop, cmpop;
8464 t_value logval, cmpval;
8465 const char *sptr;
8466 CONST char *tptr;
8467 const char logstr[] = "|&^", cmpstr[] = "=!><";
8468 /* Using a const instead of a #define. */
8469 const size_t invalid_op = (size_t) -1;
8470 
8471 logval = cmpval = 0;
8472 if (*cptr == 0)                                         /* check for clause */
8473     return NULL;
8474 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8475 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8476     if ((sptr = strchr (logstr, c))) {                  /* check for mask */
8477         logop = sptr - logstr;
8478         logval = strtotv (cptr, &tptr, radix);
8479         if (cptr == tptr)
8480             return NULL;
8481         cptr = tptr;
8482         }
8483     else if ((sptr = strchr (cmpstr, c))) {             /* check for boolop */
8484         cmpop = sptr - cmpstr;
8485         if (*cptr == '=') {
8486             cmpop = cmpop + strlen (cmpstr);
8487             cptr++;
8488             }
8489         cmpval = strtotv (cptr, &tptr, radix);
8490         if (cptr == tptr)
8491             return NULL;
8492         cptr = tptr;
8493         }
8494     else return NULL;
8495     }                                                   /* end for */
8496 if (schptr->count != 1) {
8497     FREE (schptr->mask);
8498     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8499     FREE (schptr->comp);
8500     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8501     }
8502 if (logop != invalid_op) {
8503     schptr->logic = logop;
8504     schptr->mask[0] = logval;
8505     }
8506 if (cmpop != invalid_op) {
8507     schptr->boolop = cmpop;
8508     schptr->comp[0] = cmpval;
8509     }
8510 schptr->count = 1;
8511 return schptr;
8512 }
8513 
8514 /* Get memory search specification
8515 
8516    Inputs:
8517         cptr    =       pointer to input string
8518         radix   =       radix for numbers
8519         schptr =        pointer to search table
8520    Outputs:
8521         return =        NULL if error
8522                         schptr if valid search specification
8523 */
8524 
8525 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8526 {
8527 int32 c;
8528 size_t logop, cmpop;
8529 t_value *logval, *cmpval;
8530 t_stat reason = SCPE_OK;
8531 CONST char *ocptr = cptr;
8532 const char *sptr;
8533 char gbuf[CBUFSIZE];
8534 const char logstr[] = "|&^", cmpstr[] = "=!><";
8535 /* Using a const instead of a #define. */
8536 const size_t invalid_op = (size_t) -1;
8537 
8538 if (*cptr == 0)                                         /* check for clause */
8539     return NULL;
8540 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8541 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8542 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8543 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8544     if (NULL != (sptr = strchr (logstr, c))) {          /* check for mask */
8545         logop = sptr - logstr;
8546         cptr = get_glyph (cptr, gbuf, 0);
8547         reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8548         if (reason > 0) {
8549             FREE (logval);
8550             FREE (cmpval);
8551             return get_rsearch (ocptr, radix, schptr);
8552             }
8553         }
8554     else if (NULL != (sptr = strchr (cmpstr, c))) {     /* check for boolop */
8555         cmpop = sptr - cmpstr;
8556         if (*cptr == '=') {
8557             cmpop = cmpop + strlen (cmpstr);
8558             cptr++;
8559             }
8560         cptr = get_glyph (cptr, gbuf, 0);
8561         reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8562         if (reason > 0) {
8563             FREE (logval);
8564             FREE (cmpval);
8565             return get_rsearch (ocptr, radix, schptr);
8566             }
8567         }
8568     else {
8569         FREE (logval);
8570         FREE (cmpval);
8571         return NULL;
8572         }
8573     }                                                   /* end for */
8574 if (schptr->count != (uint32)(1 - reason)) {
8575     schptr->count = 1 - reason;
8576     FREE (schptr->mask);
8577     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8578     FREE (schptr->comp);
8579     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8580     }
8581 if (logop != invalid_op) {
8582     schptr->logic = logop;
8583     FREE (schptr->mask);
8584     schptr->mask = logval;
8585     }
8586 else {
8587     FREE (logval);
8588     }
8589 if (cmpop != invalid_op) {
8590     schptr->boolop = cmpop;
8591     FREE (schptr->comp);
8592     schptr->comp = cmpval;
8593     }
8594 else {
8595     FREE (cmpval);
8596     }
8597 return schptr;
8598 }
8599 
8600 /* Test value against search specification
8601 
8602    Inputs:
8603         val    =        value list to test
8604         schptr =        pointer to search table
8605    Outputs:
8606         return =        1 if value passes search criteria, 0 if not
8607 */
8608 
8609 int32 test_search (t_value *values, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8610 {
8611 t_value *val = NULL;
8612 int32 i, updown;
8613 int32 ret = 0;
8614 
8615 if (schptr == NULL)
8616     return ret;
8617 
8618 val = (t_value *)malloc (schptr->count * sizeof (*values));
8619 if (!val)
8620   {
8621     (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8622                   __func__, __FILE__, __LINE__);
8623 #if defined(USE_BACKTRACE)
8624 # if defined(SIGUSR2)
8625     (void)raise(SIGUSR2);
8626     /*NOTREACHED*/ /* unreachable */
8627 # endif /* if defined(SIGUSR2) */
8628 #endif /* if defined(USE_BACKTRACE) */
8629     abort();
8630   }
8631 for (i=0; i<(int32)schptr->count; i++) {
8632     val[i] = values[i];
8633     switch (schptr->logic) {                            /* case on logical */
8634 
8635         case SCH_OR:
8636             val[i] = val[i] | schptr->mask[i];
8637             break;
8638 
8639         case SCH_AND:
8640             val[i] = val[i] & schptr->mask[i];
8641             break;
8642 
8643         case SCH_XOR:
8644             val[i] = val[i] ^ schptr->mask[i];
8645             break;
8646             }
8647     }
8648 
8649 ret = 1;
8650 if (1) {    /* Little Endian VM */
8651     updown = -1;
8652     i=schptr->count-1;
8653     }
8654 else {      /* Big Endian VM */
8655     updown = 1;
8656     i=0;
8657     }
8658 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8659     switch (schptr->boolop) {                           /* case on comparison */
8660 
8661         case SCH_E: case SCH_EE:
8662             if (val[i] != schptr->comp[i])
8663                 ret = 0;
8664             break;
8665 
8666         case SCH_N: case SCH_NE:
8667             if (val[i] == schptr->comp[i])
8668                 ret = 0;
8669             break;
8670 
8671         case SCH_G:
8672             if (val[i] <= schptr->comp[i])
8673                 ret = 0;
8674             break;
8675 
8676         case SCH_GE:
8677             if (val[i] < schptr->comp[i])
8678                 ret = 0;
8679             break;
8680 
8681         case SCH_L:
8682             if (val[i] >= schptr->comp[i])
8683                 ret = 0;
8684             break;
8685 
8686         case SCH_LE:
8687             if (val[i] > schptr->comp[i])
8688                 ret = 0;
8689             break;
8690         }
8691     }
8692 FREE (val);
8693 return ret;
8694 }
8695 
8696 /* Radix independent input/output package
8697 
8698    strtotv - general radix input routine
8699 
8700    Inputs:
8701         inptr   =       string to convert
8702         endptr  =       pointer to first unconverted character
8703         radix   =       radix for input
8704    Outputs:
8705         value   =       converted value
8706 
8707    On an error, the endptr will equal the inptr.
8708 */
8709 
8710 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
     /* [previous][next][first][last][top][bottom][index][help] */
8711 {
8712 int32 nodigit;
8713 t_value val;
8714 uint32 c, digit;
8715 
8716 *endptr = inptr;                                        /* assume fails */
8717 if ((radix < 2) || (radix > 36))
8718     return 0;
8719 while (sim_isspace (*inptr))                            /* bypass white space */
8720     inptr++;
8721 val = 0;
8722 nodigit = 1;
8723 for (c = *inptr; sim_isalnum(c); c = *++inptr) {        /* loop through char */
8724     if (sim_islower (c))
8725         c = toupper (c);
8726     if (sim_isdigit (c))                                /* digit? */
8727         digit = c - (uint32) '0';
8728     else if (radix <= 10)                               /* stop if not expected */
8729         break;
8730     else digit = c + 10 - (uint32) 'A';                 /* convert letter */
8731     if (digit >= radix)                                 /* valid in radix? */
8732         return 0;
8733     val = (val * radix) + digit;                        /* add to value */
8734     nodigit = 0;
8735     }
8736 if (nodigit)                                            /* no digits? */
8737     return 0;
8738 *endptr = inptr;                                        /* result pointer */
8739 return val;
8740 }
8741 
8742 /* fprint_val - general radix printing routine
8743 
8744    Inputs:
8745         stream  =       stream designator
8746         val     =       value to print
8747         radix   =       radix to print
8748         width   =       width to print
8749         format  =       leading zeroes format
8750    Outputs:
8751         status  =       error status
8752         if stream is NULL, returns length of output that would
8753         have been generated.
8754 */
8755 
8756 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8757                    size_t width, uint32 format)
8758 {
8759 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8760 t_value owtest, wtest;
8761 size_t d;
8762 size_t digit;
8763 size_t ndigits;
8764 size_t commas = 0;
8765 char dbuf[MAX_WIDTH + 1];
8766 
8767 for (d = 0; d < MAX_WIDTH; d++)
8768     dbuf[d] = (format == PV_RZRO)? '0': ' ';
8769 dbuf[MAX_WIDTH] = 0;
8770 d = MAX_WIDTH;
8771 do {
8772     d = d - 1;
8773     digit = val % radix;
8774     val = val / radix;
8775     dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8776     } while ((d > 0) && (val != 0));
8777 
8778 switch (format) {
8779     case PV_LEFT:
8780         break;
8781     case PV_RZRO:
8782         wtest = owtest = radix;
8783         ndigits = 1;
8784         while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8785             owtest = wtest;
8786             wtest = wtest * radix;
8787             ndigits = ndigits + 1;
8788             }
8789         if ((MAX_WIDTH - (ndigits + commas)) < d)
8790             d = MAX_WIDTH - (ndigits + commas);
8791         break;
8792     }
8793 if (NULL == buffer)                   /* Potentially unsafe wraparound if */
8794     return ((t_stat) strlen(dbuf+d)); /*  sizeof(t_stat) < sizeof(size_t) */
8795 *buffer = '\0';
8796 if (width < strlen(dbuf+d))
8797     return SCPE_IOERR;
8798 strcpy(buffer, dbuf+d);
8799 return SCPE_OK;
8800 }
8801 
8802 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8803     uint32 width, uint32 format)
8804 {
8805 char dbuf[MAX_WIDTH + 1];
8806 
8807 if (!stream)
8808     return sprint_val (NULL, val, radix, width, format);
8809 if (width > MAX_WIDTH)
8810     width = MAX_WIDTH;
8811 sprint_val (dbuf, val, radix, width, format);
8812 if (Fprintf (stream, "%s", dbuf) < 0)
8813     return SCPE_IOERR;
8814 return SCPE_OK;
8815 }
8816 
8817 const char *sim_fmt_secs (double seconds)
     /* [previous][next][first][last][top][bottom][index][help] */
8818 {
8819 static char buf[60];
8820 char frac[16] = "";
8821 const char *sign = "";
8822 double val = seconds;
8823 double days, hours, mins, secs, msecs, usecs;
8824 
8825 if (val == 0.0)
8826     return "";
8827 if (val < 0.0) {
8828     sign = "-";
8829     val = -val;
8830     }
8831 days = floor (val / (24.0*60.0*60.0));
8832 val -= (days * 24.0*60.0*60.0);
8833 hours = floor (val / (60.0*60.0));
8834 val -= (hours * 60.0 * 60.0);
8835 mins = floor (val / 60.0);
8836 val -= (mins * 60.0);
8837 secs = floor (val);
8838 val -= secs;
8839 val *= 1000.0;
8840 msecs = floor (val);
8841 val -= msecs;
8842 val *= 1000.0;
8843 usecs = floor (val+0.5);
8844 if (usecs == 1000.0) {
8845     usecs = 0.0;
8846     msecs += 1;
8847     }
8848 if ((msecs > 0.0) || (usecs > 0.0)) {
8849     (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8850     while (frac[strlen (frac) - 1] == '0') //-V557
8851         frac[strlen (frac) - 1] = '\0'; //-V557
8852     if (strlen (frac) == 1)
8853         frac[0] = '\0';
8854     }
8855 if (days > 0)
8856     (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8857                    sign, days, (days != 1) ? "s" : "", hours, mins,
8858                    secs, frac, (days == 1) ? "s" : "");
8859 else
8860     if (hours > 0)
8861         (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8862                        sign, hours, mins, secs, frac);
8863     else
8864         if (mins > 0)
8865             (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8866                            sign, mins, secs, frac);
8867         else
8868             if (secs > 0)
8869                 (void)sprintf (buf, "%s%.0f%s second",
8870                                sign, secs, frac);
8871             else
8872                 if (msecs > 0) {
8873                     if (usecs > 0)
8874                         (void)sprintf (buf, "%s%.0f.%s msec",
8875                                        sign, msecs, frac+4);
8876                     else
8877                         (void)sprintf (buf, "%s%.0f msec",
8878                                        sign, msecs);
8879                     }
8880                 else
8881                     (void)sprintf (buf, "%s%.0f usec",
8882                                    sign, usecs);
8883 if (0 != strncmp ("1 ", buf, 2))
8884     strcpy (&buf[strlen (buf)], "s");
8885 return buf;
8886 }
8887 
8888 /*
8889  * Event queue package
8890  *
8891  *      sim_activate            add entry to event queue
8892  *      sim_activate_abs        add entry to event queue even if event already scheduled
8893  *      sim_activate_after      add entry to event queue after a specified amount of wall time
8894  *      sim_cancel              remove entry from event queue
8895  *      sim_process_event       process entries on event queue
8896  *      sim_is_active           see if entry is on event queue
8897  *      sim_activate_time       return time until activation
8898  *      sim_atime               return absolute time for an entry
8899  *      sim_gtime               return global time
8900  *      sim_qcount              return event queue entry count
8901  */
8902 
8903 t_stat sim_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8904 {
8905 UNIT *uptr;
8906 t_stat reason;
8907 #if defined(TESTING)
8908 cpu_state_t * cpup = _cpup;
8909 #endif
8910 
8911 if (stop_cpu)                                           /* stop CPU? */
8912   {
8913 #if defined(WIN_STDIO)
8914     (void)fflush(stdout);
8915     (void)fflush(stderr);
8916 #endif /* if defined(WIN_STDIO) */
8917     return SCPE_STOP;
8918   }
8919 UPDATE_SIM_TIME;                                        /* update sim time */
8920 
8921 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8922     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8923     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8924                "Queue Empty New Interval = %d\r\n",
8925                sim_interval);
8926     return SCPE_OK;
8927     }
8928 sim_processing_event = TRUE;
8929 do {
8930     uptr = sim_clock_queue;                             /* get first */
8931     sim_clock_queue = uptr->next;                       /* remove first */
8932     uptr->next = NULL;                                  /* hygiene */
8933     sim_interval -= uptr->time;
8934     uptr->time = 0;
8935     if (sim_clock_queue != QUEUE_LIST_END)
8936         sim_interval = sim_clock_queue->time;
8937     else
8938         sim_interval = noqueue_time = NOQUEUE_WAIT;
8939     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8940                "Processing Event for %s\r\n", sim_uname (uptr));
8941     if (uptr->action != NULL)
8942         reason = uptr->action (uptr);
8943     else
8944         reason = SCPE_OK;
8945     } while ((reason == SCPE_OK) &&
8946              (sim_interval <= 0) &&
8947              (sim_clock_queue != QUEUE_LIST_END) &&
8948              (!stop_cpu));
8949 
8950 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8951     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8952     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8953                "Processing Queue Complete New Interval = %d\r\n",
8954                sim_interval);
8955     }
8956 else
8957     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8958                "Processing Queue Complete New Interval = %d(%s)\r\n",
8959                sim_interval, sim_uname(sim_clock_queue));
8960 
8961 if ((reason == SCPE_OK) && stop_cpu)
8962   {
8963 #if defined(WIN_STDIO)
8964     (void)fflush(stdout);
8965     (void)fflush(stderr);
8966 #endif /* if defined(WIN_STDIO) */
8967     reason = SCPE_STOP;
8968   }
8969 sim_processing_event = FALSE;
8970 return reason;
8971 }
8972 
8973 /* sim_activate - activate (queue) event
8974 
8975    Inputs:
8976         uptr    =       pointer to unit
8977         event_time =    relative timeout
8978    Outputs:
8979         reason  =       result (SCPE_OK if ok)
8980 */
8981 
8982 t_stat sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8983 {
8984 if (uptr->dynflags & UNIT_TMR_UNIT)
8985     return sim_timer_activate (uptr, event_time);
8986 return _sim_activate (uptr, event_time);
8987 }
8988 
8989 t_stat _sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8990 {
8991 UNIT *cptr, *prvptr;
8992 int32 accum;
8993 #if defined(TESTING)
8994 cpu_state_t * cpup = _cpup;
8995 #endif
8996 
8997 if (sim_is_active (uptr))                               /* already active? */
8998     return SCPE_OK;
8999 UPDATE_SIM_TIME;                                        /* update sim time */
9000 
9001 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
9002 
9003 prvptr = NULL;
9004 accum = 0;
9005 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9006     if (event_time < (accum + cptr->time))
9007         break;
9008     accum = accum + cptr->time;
9009     prvptr = cptr;
9010     }
9011 if (prvptr == NULL) {                                   /* insert at head */
9012     cptr = uptr->next = sim_clock_queue;
9013     sim_clock_queue = uptr;
9014     }
9015 else {
9016     cptr = uptr->next = prvptr->next;                   /* insert at prvptr */
9017     prvptr->next = uptr;
9018     }
9019 uptr->time = event_time - accum;
9020 if (cptr != QUEUE_LIST_END)
9021     cptr->time = cptr->time - uptr->time;
9022 sim_interval = sim_clock_queue->time;
9023 return SCPE_OK;
9024 }
9025 
9026 /* sim_activate_abs - activate (queue) event even if event already scheduled
9027 
9028    Inputs:
9029         uptr    =       pointer to unit
9030         event_time =    relative timeout
9031    Outputs:
9032         reason  =       result (SCPE_OK if ok)
9033 */
9034 
9035 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
9036 {
9037 sim_cancel (uptr);
9038 return _sim_activate (uptr, event_time);
9039 }
9040 
9041 /* sim_activate_after - activate (queue) event
9042 
9043    Inputs:
9044         uptr    =       pointer to unit
9045         usec_delay =    relative timeout (in microseconds)
9046    Outputs:
9047         reason  =       result (SCPE_OK if ok)
9048 */
9049 
9050 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
9051 {
9052 return _sim_activate_after (uptr, usec_delay);
9053 }
9054 
9055 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
9056 {
9057 if (sim_is_active (uptr))                               /* already active? */
9058     return SCPE_OK;
9059 return sim_timer_activate_after (uptr, usec_delay);
9060 }
9061 
9062 /* sim_cancel - cancel (dequeue) event
9063 
9064    Inputs:
9065         uptr    =       pointer to unit
9066    Outputs:
9067         reason  =       result (SCPE_OK if ok)
9068 
9069 */
9070 
9071 t_stat sim_cancel (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9072 {
9073 UNIT *cptr, *nptr;
9074 #if defined(TESTING)
9075 cpu_state_t * cpup = _cpup;
9076 #endif
9077 
9078 if (sim_clock_queue == QUEUE_LIST_END)
9079     return SCPE_OK;
9080 if (!sim_is_active (uptr))
9081     return SCPE_OK;
9082 UPDATE_SIM_TIME;                                        /* update sim time */
9083 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9084 nptr = QUEUE_LIST_END;
9085 
9086 if (sim_clock_queue == uptr) {
9087     nptr = sim_clock_queue = uptr->next;
9088     uptr->next = NULL;                                  /* hygiene */
9089     }
9090 else {
9091     for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9092         if (cptr->next == uptr) {
9093             nptr = cptr->next = uptr->next;
9094             uptr->next = NULL;                          /* hygiene */
9095             break;                                      /* end queue scan */
9096             }
9097         }
9098     }
9099 if (nptr != QUEUE_LIST_END)
9100     nptr->time += (uptr->next) ? 0 : uptr->time;
9101 if (!uptr->next)
9102     uptr->time = 0;
9103 if (sim_clock_queue != QUEUE_LIST_END)
9104     sim_interval = sim_clock_queue->time;
9105 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9106 if (uptr->next) {
9107     sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9108     if (sim_deb)
9109         fclose(sim_deb);
9110     (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9111                    __func__, __FILE__, __LINE__);
9112     abort ();
9113     }
9114 return SCPE_OK;
9115 }
9116 
9117 /* sim_is_active - test for entry in queue
9118 
9119    Inputs:
9120         uptr    =       pointer to unit
9121    Outputs:
9122         result =        TRUE if unit is busy, FALSE inactive
9123 */
9124 
9125 t_bool sim_is_active (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9126 {
9127 if (uptr->next == NULL)
9128   return FALSE;
9129 else
9130 return TRUE;
9131 }
9132 
9133 /* sim_activate_time - return activation time
9134 
9135    Inputs:
9136         uptr    =       pointer to unit
9137    Outputs:
9138         result =        absolute activation time + 1, 0 if inactive
9139 */
9140 
9141 int32 sim_activate_time (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9142 {
9143 UNIT *cptr;
9144 int32 accum = 0;
9145 
9146 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9147     if (cptr == sim_clock_queue) {
9148         if (sim_interval > 0)
9149             accum = accum + sim_interval;
9150         }
9151     else
9152         accum = accum + cptr->time;
9153     if (cptr == uptr)
9154         return accum + 1;
9155     }
9156 return 0;
9157 }
9158 
9159 /* sim_gtime - return global time
9160 
9161    Inputs: none
9162    Outputs:
9163         time    =       global time
9164 */
9165 
9166 double sim_gtime (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9167 {
9168 return sim_time;
9169 }
9170 
9171 /* sim_qcount - return queue entry count
9172 
9173    Inputs: none
9174    Outputs:
9175         count   =       number of entries on the queue
9176 */
9177 
9178 int32 sim_qcount (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9179 {
9180 int32 cnt;
9181 UNIT *uptr;
9182 
9183 cnt = 0;
9184 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9185     cnt++;
9186 return cnt;
9187 }
9188 
9189 /* Breakpoint package.  This module replaces the VM-implemented one
9190    instruction breakpoint capability.
9191 
9192    Breakpoints are stored in table sim_brk_tab, which is ordered by address for
9193    efficient binary searching.  A breakpoint consists of a six entry structure:
9194 
9195         addr                    address of the breakpoint
9196         type                    types of breakpoints set on the address
9197                                 a bit mask representing letters A-Z
9198         cnt                     number of iterations before breakp is taken
9199         action                  pointer command string to be executed
9200                                 when break is taken
9201         next                    list of other breakpoints with the same addr specifier
9202         time_fired              array of when this breakpoint was fired for each class
9203 
9204    sim_brk_summ is a summary of the types of breakpoints that are currently set (it
9205    is the bitwise OR of all the type fields).  A simulator need only check for
9206    a breakpoint of type X if bit SWMASK('X') is set in sim_brk_summ.
9207 
9208    The package contains the following public routines:
9209 
9210         sim_brk_init            initialize
9211         sim_brk_set             set breakpoint
9212         sim_brk_clr             clear breakpoint
9213         sim_brk_clrall          clear all breakpoints
9214         sim_brk_show            show breakpoint
9215         sim_brk_showall         show all breakpoints
9216         sim_brk_test            test for breakpoint
9217         sim_brk_npc             PC has been changed
9218         sim_brk_getact          get next action
9219         sim_brk_clract          clear pending actions
9220 
9221    Initialize breakpoint system.
9222 */
9223 
9224 t_stat sim_brk_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9225 {
9226 int32 i;
9227 
9228 for (i=0; i<sim_brk_lnt; i++) {
9229     BRKTAB *bp;
9230     if (sim_brk_tab)
9231       {
9232         bp = sim_brk_tab[i];
9233 
9234         while (bp)
9235           {
9236             BRKTAB *bpt = bp->next;
9237 
9238             FREE (bp->act);
9239             FREE (bp);
9240             bp = bpt;
9241           }
9242       }
9243 }
9244 if (sim_brk_tab != NULL)
9245     (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9246 sim_brk_lnt = SIM_BRK_INILNT;
9247 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9248 if (sim_brk_tab == NULL)
9249     return SCPE_MEM;
9250 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9251 sim_brk_ent = sim_brk_ins = 0;
9252 sim_brk_clract ();
9253 sim_brk_npc (0);
9254 return SCPE_OK;
9255 }
9256 
9257 /* Search for a breakpoint in the sorted breakpoint table */
9258 
9259 BRKTAB *sim_brk_fnd (t_addr loc)
     /* [previous][next][first][last][top][bottom][index][help] */
9260 {
9261 int32 lo, hi, p;
9262 BRKTAB *bp;
9263 
9264 if (sim_brk_ent == 0) {                                 /* table empty? */
9265     sim_brk_ins = 0;                                    /* insrt at head */
9266     return NULL;                                        /* sch fails */
9267     }
9268 lo = 0;                                                 /* initial bounds */
9269 hi = sim_brk_ent - 1;
9270 do {
9271     p = (lo + hi) >> 1;                                 /* probe */
9272     bp = sim_brk_tab[p];                                /* table addr */
9273     if (loc == bp->addr) {                              /* match? */
9274         sim_brk_ins = p;
9275         return bp;
9276         }
9277     else if (loc < bp->addr)                            /* go down? p is upper */
9278         hi = p - 1;
9279     else lo = p + 1;                                    /* go up? p is lower */
9280     } while (lo <= hi);
9281 if (loc < bp->addr)                                     /* insrt before or */
9282     sim_brk_ins = p;
9283 else sim_brk_ins = p + 1;                               /* after last sch */
9284 return NULL;
9285 }
9286 
9287 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
     /* [previous][next][first][last][top][bottom][index][help] */
9288 {
9289 BRKTAB *bp = sim_brk_fnd (loc);
9290 
9291 while (bp) {
9292     if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9293                   (bp->typ == btyp))
9294         return bp;
9295     bp = bp->next;
9296     }
9297 return bp;
9298 }
9299 
9300 /* Insert a breakpoint */
9301 
9302 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9303 {
9304 int32 i, t;
9305 BRKTAB *bp, **newp;
9306 
9307 if (sim_brk_ins < 0)
9308     return NULL;
9309 if (sim_brk_ent >= sim_brk_lnt) {                       /* out of space? */
9310     t = sim_brk_lnt + SIM_BRK_INILNT;                   /* new size */
9311     newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));    /* new table */
9312     if (newp == NULL)                                   /* can't extend */
9313         return NULL;
9314     memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));/* copy table */
9315     (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));/* zero new entries */
9316     FREE (sim_brk_tab);                                 /* free old table */
9317     sim_brk_tab = newp;                                 /* new base, lnt */
9318     sim_brk_lnt = t;
9319     }
9320 if ((sim_brk_ins == sim_brk_ent) ||
9321     ((sim_brk_ins != sim_brk_ent) && //-V728
9322      (sim_brk_tab[sim_brk_ins]->addr != loc))) {        /* need to open a hole? */
9323     for (i = sim_brk_ent; i > sim_brk_ins; --i)
9324         sim_brk_tab[i] = sim_brk_tab[i - 1];
9325     sim_brk_tab[sim_brk_ins] = NULL;
9326     }
9327 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9328 if (!bp)
9329   {
9330     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9331                    __func__, __FILE__, __LINE__);
9332 #if defined(USE_BACKTRACE)
9333 # if defined(SIGUSR2)
9334     (void)raise(SIGUSR2);
9335     /*NOTREACHED*/ /* unreachable */
9336 # endif /* if defined(SIGUSR2) */
9337 #endif /* if defined(USE_BACKTRACE) */
9338     abort();
9339   }
9340 bp->next = sim_brk_tab[sim_brk_ins];
9341 sim_brk_tab[sim_brk_ins] = bp;
9342 if (bp->next == NULL)
9343     sim_brk_ent += 1;
9344 bp->addr = loc;
9345 bp->typ = btyp;
9346 bp->cnt = 0;
9347 bp->act = NULL;
9348 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9349     bp->time_fired[i] = -1.0;
9350 return bp;
9351 }
9352 
9353 /* Set a breakpoint of type sw */
9354 
9355 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
     /* [previous][next][first][last][top][bottom][index][help] */
9356 {
9357 BRKTAB *bp;
9358 
9359 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9360     sw |= sim_brk_dflt;
9361 if (~sim_brk_types & sw) {
9362     char gbuf[CBUFSIZE];
9363 
9364     return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9365     }
9366 if ((sw & BRK_TYP_DYN_ALL) && act)                      /* can't specify an action with a dynamic breakpoint */
9367     return SCPE_ARG;
9368 bp = sim_brk_fnd (loc);                                 /* loc present? */
9369 if (!bp)                                                /* no, allocate */
9370     bp = sim_brk_new (loc, sw);
9371 else {
9372     while (bp && (bp->typ != (uint32)sw))
9373         bp = bp->next;
9374     if (!bp)
9375         bp = sim_brk_new (loc, sw);
9376     }
9377 if (!bp)                                                /* still no? mem err */
9378     return SCPE_MEM;
9379 bp->cnt = ncnt;                                         /* set count */
9380 if ((!(sw & BRK_TYP_DYN_ALL)) &&                        /* Not Dynamic and */
9381     (bp->act != NULL) && (act != NULL)) {               /* replace old action? */
9382     FREE (bp->act);                                     /* deallocate */
9383     bp->act = NULL;                                     /* now no action */
9384     }
9385 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9386     char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char)); /* alloc buf */
9387     if (newp == NULL)                                   /* mem err? */
9388         return SCPE_MEM;
9389     strncpy (newp, act, CBUFSIZE);                      /* copy action */
9390     bp->act = newp;                                     /* set pointer */
9391     }
9392 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9393 return SCPE_OK;
9394 }
9395 
9396 /* Clear a breakpoint */
9397 
9398 t_stat sim_brk_clr (t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9399 {
9400 BRKTAB *bpl = NULL;
9401 BRKTAB *bp = sim_brk_fnd (loc);
9402 int32 i;
9403 
9404 if (!bp)                                                /* not there? ok */
9405     return SCPE_OK;
9406 if (sw == 0)
9407     sw = SIM_BRK_ALLTYP;
9408 
9409 #if !defined(__clang_analyzer__)
9410 while (bp) {
9411     if (bp->typ == (bp->typ & sw)) {
9412         FREE (bp->act);                                 /* deallocate action */
9413         if (bp == sim_brk_tab[sim_brk_ins])
9414             bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9415         else
9416           {
9417             if (bpl)
9418               bpl->next = bp->next;
9419           }
9420         FREE (bp);
9421         bp = bpl;
9422         }
9423     else {
9424         bpl = bp;
9425         bp = bp->next;
9426         }
9427     }
9428 #endif /* if !defined(__clang_analyzer__) */
9429 if (sim_brk_tab[sim_brk_ins] == NULL) {                 /* erased entry */
9430     sim_brk_ent = sim_brk_ent - 1;                      /* decrement count */
9431     for (i = sim_brk_ins; i < sim_brk_ent; i++)         /* shuffle remaining entries */
9432         sim_brk_tab[i] = sim_brk_tab[i+1];
9433     }
9434 sim_brk_summ = 0;                                       /* recalc summary */
9435 for (i = 0; i < sim_brk_ent; i++) {
9436     bp = sim_brk_tab[i];
9437     while (bp) {
9438         sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9439         bp = bp->next;
9440         }
9441     }
9442 return SCPE_OK;
9443 }
9444 
9445 /* Clear all breakpoints */
9446 
9447 t_stat sim_brk_clrall (int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9448 {
9449 int32 i;
9450 
9451 if (sw == 0)
9452     sw = SIM_BRK_ALLTYP;
9453 for (i = 0; i < sim_brk_ent;) {
9454     t_addr loc = sim_brk_tab[i]->addr;
9455     sim_brk_clr (loc, sw);
9456     if ((i < sim_brk_ent) &&
9457         (loc == sim_brk_tab[i]->addr)) //-V560
9458         ++i;
9459     }
9460 return SCPE_OK;
9461 }
9462 
9463 /* Show a breakpoint */
9464 
9465 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9466 {
9467 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9468 DEVICE *dptr;
9469 uint32 i, any;
9470 
9471 if ((sw == 0) || (sw == SWMASK ('C'))) {
9472     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9473 if (!bp || (!(bp->typ & sw))) {
9474     return SCPE_OK; }
9475 dptr = sim_dflt_dev;
9476 if (dptr == NULL) {
9477     return SCPE_OK; }
9478 if (sw & SWMASK ('C')) {
9479     if (st != NULL) {
9480         (void)fprintf (st, "SET BREAK "); }
9481 } else {
9482     if (sim_vm_fprint_addr) {
9483         sim_vm_fprint_addr
9484             (st, dptr, loc);
9485     } else {
9486         fprint_val
9487             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9488     if (st != NULL) {
9489         (void)fprintf (st, ":\t"); }
9490     }
9491 for (i = any = 0; i < 26; i++) {
9492     if ((bp->typ >> i) & 1) {
9493         if ((sw & SWMASK ('C')) == 0) {
9494             if (any) {
9495                 if (st != NULL) {
9496                     (void)fprintf (st, ", "); } }
9497             if (st != NULL) {
9498                 fputc (i + 'A', st); }
9499             }
9500         } else {
9501             if (st != NULL) {
9502                 (void)fprintf (st, "-%c", i + 'A'); }
9503         any = 1;
9504         }
9505     }
9506 if (sw & SWMASK ('C')) {
9507     if (st != NULL) {
9508         (void)fprintf (st, " "); }
9509     if (sim_vm_fprint_addr) {
9510         if (st != NULL) {
9511             sim_vm_fprint_addr (st, dptr, loc); }
9512     } else {
9513         fprint_val
9514             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9515     }
9516 if (bp->cnt > 0) {
9517     if (st != NULL) {
9518         (void)fprintf (st, "[%d]", bp->cnt); } }
9519 if (bp->act != NULL) {
9520     if (st != NULL) {
9521         (void)fprintf (st, "; %s", bp->act); } }
9522 (void)fprintf (st, "\r\n");
9523 return SCPE_OK;
9524 }
9525 
9526 /* Show all breakpoints */
9527 
9528 t_stat sim_brk_showall (FILE *st, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9529 {
9530 int32 bit, mask, types;
9531 BRKTAB **bpt;
9532 
9533 if ((sw == 0) || (sw == SWMASK ('C')))
9534     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9535 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9536     if (sim_brk_types & (1 << bit))
9537         ++types;
9538 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9539     (void)fprintf (st, "Supported Breakpoint Types:"); //-V522
9540     for (bit=0; bit <= ('Z'-'A'); bit++)
9541         if (sim_brk_types & (1 << bit))
9542             (void)fprintf (st, " -%c", 'A' + bit);
9543     (void)fprintf (st, "\r\n");
9544     }
9545 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9546     mask = (sw & sim_brk_types);
9547     (void)fprintf (st, "Displaying Breakpoint Types:");
9548     for (bit=0; bit <= ('Z'-'A'); bit++)
9549         if (mask & (1 << bit))
9550             (void)fprintf (st, " -%c", 'A' + bit);
9551     (void)fprintf (st, "\r\n");
9552     }
9553 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9554     BRKTAB *prev = NULL;
9555     BRKTAB *cur = *bpt;
9556     BRKTAB *next;
9557     /* First reverse the list */
9558     while (cur) {
9559         next = cur->next;
9560         cur->next = prev;
9561         prev = cur;
9562         cur = next;
9563         }
9564     /* save reversed list in the head pointer so lookups work */
9565     *bpt = prev;
9566     /* Walk the reversed list and print it in the order it was defined in */
9567     cur = prev;
9568     while (cur) {
9569         if (cur->typ & sw)
9570             sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9571         cur = cur->next;
9572         }
9573     /* reversing the list again */
9574     cur = prev;
9575     prev = NULL;
9576     while (cur) {
9577         next = cur->next;
9578         cur->next = prev;
9579         prev = cur;
9580         cur = next;
9581         }
9582     /* restore original list */
9583     *bpt = prev;
9584     }
9585 return SCPE_OK;
9586 }
9587 
9588 /* Test for breakpoint */
9589 
9590 uint32 sim_brk_test (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9591 {
9592 BRKTAB *bp;
9593 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9594 
9595 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9596     btyp |= BRK_TYP_DYN_ALL;
9597 
9598 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {     /* in table, and type match? */
9599     double s_gtime = sim_gtime ();                      /* get time now */
9600 
9601     if (bp->time_fired[spc] == s_gtime)                 /* already taken?  */
9602         return 0;
9603     bp->time_fired[spc] = s_gtime;                      /* remember match time */
9604     if (--bp->cnt > 0)                                  /* count > 0? */
9605         return 0;
9606     bp->cnt = 0;                                        /* reset count */
9607     sim_brk_setact (bp->act);                           /* set up actions */
9608     sim_brk_match_type = btyp & bp->typ;                /* set return value */
9609     if (bp->typ & BRK_TYP_TEMP)
9610         sim_brk_clr (loc, bp->typ);                     /* delete one-shot breakpoint */
9611     sim_brk_match_addr = loc;
9612     return sim_brk_match_type;
9613     }
9614 return 0;
9615 }
9616 
9617 /* Get next pending action, if any */
9618 
9619 CONST char *sim_brk_getact (char *buf, int32 size)
     /* [previous][next][first][last][top][bottom][index][help] */
9620 {
9621 char *ep;
9622 size_t lnt;
9623 
9624 if (sim_brk_act[sim_do_depth] == NULL)                  /* any action? */
9625     return NULL;
9626 while (sim_isspace (*sim_brk_act[sim_do_depth]))        /* skip spaces */
9627     sim_brk_act[sim_do_depth]++;
9628 if (*sim_brk_act[sim_do_depth] == 0) {                  /* now empty? */
9629     return sim_brk_clract ();
9630     }
9631 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {   /* cmd delimiter? */
9632     lnt = ep - sim_brk_act[sim_do_depth];               /* cmd length */
9633     memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);   /* copy with ; */
9634     buf[lnt] = 0;                                       /* erase ; */
9635     sim_brk_act[sim_do_depth] += lnt + 1;               /* adv ptr */
9636     }
9637 else {
9638     strncpy (buf, sim_brk_act[sim_do_depth], size);     /* copy action */
9639     sim_brk_clract ();                                  /* no more */
9640     }
9641 return buf;
9642 }
9643 
9644 /* Clear pending actions */
9645 
9646 char *sim_brk_clract (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9647 {
9648 FREE (sim_brk_act_buf[sim_do_depth]);
9649 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9650 }
9651 
9652 /* Set up pending actions */
9653 
9654 void sim_brk_setact (const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
9655 {
9656 if (action) {
9657     sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9658     if (!sim_brk_act_buf[sim_do_depth])
9659       {
9660         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9661                        __func__, __FILE__, __LINE__);
9662 #if defined(USE_BACKTRACE)
9663 # if defined(SIGUSR2)
9664         (void)raise(SIGUSR2);
9665         /*NOTREACHED*/ /* unreachable */
9666 # endif /* if defined(SIGUSR2) */
9667 #endif /* if defined(USE_BACKTRACE) */
9668         abort();
9669       }
9670     strcpy (sim_brk_act_buf[sim_do_depth], action);
9671     sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9672     }
9673 else
9674     sim_brk_clract ();
9675 }
9676 
9677 /* New PC */
9678 
9679 void sim_brk_npc (uint32 cnt)
     /* [previous][next][first][last][top][bottom][index][help] */
9680 {
9681 uint32 spc;
9682 BRKTAB **bpt, *bp;
9683 
9684 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9685     cnt = SIM_BKPT_N_SPC;
9686 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9687     for (bp = *bpt; bp; bp = bp->next) {
9688         for (spc = 0; spc < cnt; spc++)
9689             bp->time_fired[spc] = -1.0;
9690         }
9691     }
9692 }
9693 
9694 /* Clear breakpoint space */
9695 
9696 void sim_brk_clrspc (uint32 spc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9697 {
9698 BRKTAB **bpt, *bp;
9699 
9700 if (spc < SIM_BKPT_N_SPC) {
9701     for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9702         for (bp = *bpt; bp; bp = bp->next) {
9703             if (bp->typ & btyp)
9704                 bp->time_fired[spc] = -1.0;
9705             }
9706         }
9707     }
9708 }
9709 
9710 const char *sim_brk_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
9711 {
9712 static char msg[256];
9713 char addr[65] = "";
9714 char buf[32];
9715 
9716 msg[0] = '\0';
9717 if (sim_dflt_dev) {
9718   if (sim_vm_sprint_addr)
9719     sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9720   else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9721 }
9722 if (sim_brk_type_desc) {
9723     BRKTYPTAB *brk = sim_brk_type_desc;
9724 
9725     while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9726         if (brk->btyp == sim_brk_match_type) {
9727             (void)sprintf (msg, "%s: %s", brk->desc, addr);
9728             break;
9729             }
9730         brk++;
9731         }
9732     }
9733 if (!msg[0])
9734     (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9735                    put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9736 
9737 return msg;
9738 }
9739 
9740 /* Expect package.  This code provides a mechanism to stop and control simulator
9741    execution based on traffic coming out of simulated ports and as well as a means
9742    to inject data into those ports.  It can conceptually viewed as a string
9743    breakpoint package.
9744 
9745    Expect rules are stored in tables associated with each port which can use this
9746    facility.  An expect rule consists of a five entry structure:
9747 
9748         match                   the expect match string
9749         size                    the number of bytes in the match string
9750         match_pattern           the expect match string in display format
9751         cnt                     number of iterations before match is declared
9752         action                  command string to be executed when match occurs
9753 
9754    All active expect rules are contained in an expect match context structure.
9755 
9756         rules                   the match rules
9757         size                    the count of match rules
9758         buf                     the buffer of output data which has been produced
9759         buf_ins                 the buffer insertion point for the next output data
9760         buf_size                the buffer size
9761 
9762    The package contains the following public routines:
9763 
9764         sim_set_expect          expect command parser and initializer
9765         sim_set_noexpect        noexpect command parser
9766         sim_exp_set             set or add an expect rule
9767         sim_exp_clr             clear or delete an expect rule
9768         sim_exp_clrall          clear all expect rules
9769         sim_exp_show            show an expect rule
9770         sim_exp_showall         show all expect rules
9771         sim_exp_check           test for rule match
9772 */
9773 
9774 /* Set expect */
9775 
9776 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9777 {
9778 char gbuf[CBUFSIZE];
9779 CONST char *tptr;
9780 CONST char *c1ptr;
9781 t_bool after_set = FALSE;
9782 uint32 after;
9783 int32 cnt = 0;
9784 t_stat r;
9785 
9786 if (exp == NULL)
9787     return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9788 after = exp->after;
9789 
9790 if ((cptr == NULL) || (*cptr == 0))
9791     return SCPE_2FARG;
9792 if (*cptr == '[') {
9793     cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9794     if ((cptr == c1ptr) || (*c1ptr != ']'))
9795         return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9796     cptr = c1ptr + 1;
9797     while (sim_isspace(*cptr))
9798         ++cptr;
9799     }
9800 tptr = get_glyph (cptr, gbuf, ',');
9801 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9802     after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9803     if (r != SCPE_OK)
9804         return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9805     after_set = TRUE;
9806     cptr = tptr;
9807     }
9808 if ((*cptr != '"') && (*cptr != '\''))
9809     return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9810 cptr = get_glyph_quoted (cptr, gbuf, 0);
9811 
9812 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9813 }
9814 
9815 /* Clear expect */
9816 
9817 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9818 {
9819 char gbuf[CBUFSIZE];
9820 
9821 if (NULL == cptr || !*cptr)
9822     return sim_exp_clrall (exp);                    /* clear all rules */
9823 if ((*cptr != '"') && (*cptr != '\''))
9824     return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9825 cptr = get_glyph_quoted (cptr, gbuf, 0);
9826 if (*cptr != '\0')
9827     return SCPE_2MARG;                              /* No more arguments */
9828 return sim_exp_clr (exp, gbuf);                     /* clear one rule */
9829 }
9830 
9831 /* Search for an expect rule in an expect context */
9832 
9833 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
     /* [previous][next][first][last][top][bottom][index][help] */
9834 {
9835 size_t i;
9836 
9837 if (NULL == exp->rules)
9838     return NULL;
9839 for (i=start_rule; i<exp->size; i++)
9840     if (!strcmp (exp->rules[i].match_pattern, match))
9841         return &exp->rules[i];
9842 return NULL;
9843 }
9844 
9845 /* Clear (delete) an expect rule */
9846 
9847 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9848 {
9849 size_t i;
9850 
9851 if (NULL == ep)                                         /* not there? ok */
9852     return SCPE_OK;
9853 FREE (ep->match);                                       /* deallocate match string */
9854 FREE (ep->match_pattern);                               /* deallocate the display format match string */
9855 FREE (ep->act);                                         /* deallocate action */
9856 exp->size -= 1;                                         /* decrement count */
9857 #if !defined(__clang_analyzer__)
9858 for (i=ep-exp->rules; i<exp->size; i++)                 /* shuffle up remaining rules */
9859     exp->rules[i] = exp->rules[i+1];
9860 if (exp->size == 0) {                                   /* No rules left? */
9861     FREE (exp->rules);
9862     exp->rules = NULL;
9863     }
9864 #endif /* if !defined(__clang_analyzer__) */
9865 return SCPE_OK;
9866 }
9867 
9868 t_stat sim_exp_clr (EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9869 {
9870 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9871 
9872 while (ep) {
9873     sim_exp_clr_tab (exp, ep);
9874     ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9875     }
9876 return SCPE_OK;
9877 }
9878 
9879 /* Clear all expect rules */
9880 
9881 t_stat sim_exp_clrall (EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
9882 {
9883 int32 i;
9884 
9885 for (i=0; i<exp->size; i++) {
9886     FREE (exp->rules[i].match);                         /* deallocate match string */
9887     FREE (exp->rules[i].match_pattern);                 /* deallocate display format match string */
9888     FREE (exp->rules[i].act);                           /* deallocate action */
9889     }
9890 FREE (exp->rules);
9891 exp->rules = NULL;
9892 exp->size = 0;
9893 FREE (exp->buf);
9894 exp->buf = NULL;
9895 exp->buf_size = 0;
9896 exp->buf_ins = 0;
9897 return SCPE_OK;
9898 }
9899 
9900 /* Set/Add an expect rule */
9901 
9902 t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act)
     /* [previous][next][first][last][top][bottom][index][help] */
9903 {
9904 EXPTAB *ep;
9905 uint8 *match_buf;
9906 uint32 match_size;
9907 size_t i;
9908 
9909 /* Validate the match string */
9910 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9911 if (!match_buf)
9912     return SCPE_MEM;
9913 if (switches & EXP_TYP_REGEX) {
9914     FREE (match_buf);
9915     return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9916     }
9917 else {
9918     if (switches & EXP_TYP_REGEX_I) {
9919         FREE (match_buf);
9920         return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9921         }
9922     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9923     if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9924         FREE (match_buf);
9925         return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9926         }
9927     }
9928 FREE (match_buf);
9929 for (i=0; i<exp->size; i++) {                           /* Make sure this rule won't be occluded */
9930     if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9931         (exp->rules[i].switches & EXP_TYP_PERSIST))
9932         return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9933     }
9934 if (after && exp->size)
9935     return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9936 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9937 if (!exp->rules)
9938   {
9939     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9940                    __func__, __FILE__, __LINE__);
9941 #if defined(USE_BACKTRACE)
9942 # if defined(SIGUSR2)
9943     (void)raise(SIGUSR2);
9944     /*NOTREACHED*/ /* unreachable */
9945 # endif /* if defined(SIGUSR2) */
9946 #endif /* if defined(USE_BACKTRACE) */
9947     abort();
9948   }
9949 ep = &exp->rules[exp->size];
9950 exp->size += 1;
9951 exp->after = after;                                     /* set halt after value */
9952 (void)memset (ep, 0, sizeof(*ep));
9953 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9954 if (ep->match_pattern)
9955     strcpy (ep->match_pattern, match);
9956 ep->cnt = cnt;                                          /* set proceed count */
9957 ep->switches = switches;                                /* set switches */
9958 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9959 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9960     sim_exp_clr_tab (exp, ep);                          /* clear it */
9961     FREE (match_buf);                                   /* release allocation */
9962     return SCPE_MEM;
9963     }
9964 if (switches & EXP_TYP_REGEX) {
9965     FREE (match_buf);
9966     match_buf = NULL;
9967     }
9968 else {
9969     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9970     sim_decode_quoted_string (match, match_buf, &match_size);
9971     ep->match = match_buf;
9972     ep->size = match_size;
9973     }
9974 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9975 if (!ep->match_pattern)
9976   {
9977     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9978                    __func__, __FILE__, __LINE__);
9979 #if defined(USE_BACKTRACE)
9980 # if defined(SIGUSR2)
9981     (void)raise(SIGUSR2);
9982     /*NOTREACHED*/ /* unreachable */
9983 # endif /* if defined(SIGUSR2) */
9984 #endif /* if defined(USE_BACKTRACE) */
9985     abort();
9986   }
9987 strcpy (ep->match_pattern, match);
9988 if (ep->act) {                                          /* replace old action? */
9989     FREE (ep->act);                                     /* deallocate */
9990     ep->act = NULL;                                     /* now no action */
9991     }
9992 if (act) while (sim_isspace(*act)) ++act;                   /* skip leading spaces in action string */
9993 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9994     char *newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */
9995     if (newp == NULL)                                   /* mem err? */
9996         return SCPE_MEM;
9997     strcpy (newp, act);                                 /* copy action */
9998     ep->act = newp;                                     /* set pointer */
9999     }
10000 /* Make sure that the production buffer is large enough to detect a match for all rules including a NUL termination byte */
10001 for (i=0; i<exp->size; i++) {
10002     size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
10003     if (compare_size >= exp->buf_size) {
10004         exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2); /* Extra byte to null terminate regex compares */
10005         exp->buf_size = compare_size + 1;
10006         }
10007     }
10008 return SCPE_OK;
10009 }
10010 
10011 /* Show an expect rule */
10012 
10013 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
10014 {
10015 if (!ep)
10016     return SCPE_OK;
10017 (void)fprintf (st, "EXPECT");
10018 if (ep->switches & EXP_TYP_PERSIST)
10019     (void)fprintf (st, " -p");
10020 if (ep->switches & EXP_TYP_CLEARALL)
10021     (void)fprintf (st, " -c");
10022 if (ep->switches & EXP_TYP_REGEX)
10023     (void)fprintf (st, " -r");
10024 if (ep->switches & EXP_TYP_REGEX_I)
10025     (void)fprintf (st, " -i");
10026 (void)fprintf (st, " %s", ep->match_pattern);
10027 if (ep->cnt > 0)
10028     (void)fprintf (st, " [%d]", ep->cnt);
10029 if (ep->act)
10030     (void)fprintf (st, " %s", ep->act);
10031 (void)fprintf (st, "\r\n");
10032 return SCPE_OK;
10033 }
10034 
10035 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
10036 {
10037 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
10038 
10039 if (exp->buf_size) {
10040     char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10041 
10042     (void)fprintf (st, "Match Buffer Size: %lld\r\n",
10043                    (long long)exp->buf_size);
10044     (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
10045                    (long long)exp->buf_ins);
10046     (void)fprintf (st, "Buffer Contents: %s\r\n",
10047                    bstr);
10048     FREE (bstr);
10049     }
10050 if (exp->after)
10051     (void)fprintf (st, "Halt After: %lld instructions\r\n",
10052                    (long long)exp->after);
10053 if (exp->dptr && exp->dbit)
10054     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10055                    sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
10056                    exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
10057 (void)fprintf (st, "Match Rules:\r\n");
10058 if (!*match)
10059     return sim_exp_showall (st, exp);
10060 if (!ep) {
10061     (void)fprintf (st, "No Rules match '%s'\r\n", match);
10062     return SCPE_ARG;
10063     }
10064 do {
10065     sim_exp_show_tab (st, exp, ep);
10066     ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
10067     } while (ep);
10068 return SCPE_OK;
10069 }
10070 
10071 /* Show all expect rules */
10072 
10073 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
10074 {
10075 size_t i;
10076 
10077 for (i=0; i < exp->size; i++)
10078     sim_exp_show_tab (st, exp, &exp->rules[i]);
10079 return SCPE_OK;
10080 }
10081 
10082 /* Test for expect match */
10083 
10084 t_stat sim_exp_check (EXPECT *exp, uint8 data)
     /* [previous][next][first][last][top][bottom][index][help] */
10085 {
10086 size_t i;
10087 EXPTAB *ep = NULL;
10088 char *tstr = NULL;
10089 #if defined(TESTING)
10090 cpu_state_t * cpup = _cpup;
10091 #endif
10092 
10093 if ((!exp) || (!exp->rules))                            /* Anything to check? */
10094     return SCPE_OK;
10095 
10096 exp->buf[exp->buf_ins++] = data;                        /* Save new data */
10097 exp->buf[exp->buf_ins] = '\0';                          /* Nul terminate for RegEx match */
10098 
10099 for (i=0; i < exp->size; i++) {
10100     ep = &exp->rules[i];
10101     if (ep == NULL) //-V547
10102         break;
10103     if (ep->switches & EXP_TYP_REGEX) {
10104         }
10105     else {
10106         if (exp->buf_ins < ep->size) {                          /* Match stradle end of buffer */
10107             /*
10108              * First compare the newly deposited data at the beginning
10109              * of buffer with the end of the match string
10110              */
10111             if (exp->buf_ins > 0) {
10112                 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10113                     char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10114                     char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10115 
10116                     sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10117                                (long long)exp->buf_ins, estr);
10118                     sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10119                     FREE (estr);
10120                     FREE (mstr);
10121                     }
10122                 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10123                     continue;
10124                 }
10125             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10126                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10127                 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10128 
10129                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10130                            (long long)exp->buf_size-(ep->size-exp->buf_ins),
10131                            (long long)ep->size-exp->buf_ins, estr);
10132                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10133                 FREE (estr);
10134                 FREE (mstr);
10135                 }
10136             if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10137                 continue;
10138             break;
10139             }
10140         else {
10141             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10142                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10143                 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10144 
10145                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10146                            (long long)exp->buf_ins-ep->size,
10147                            (long long)ep->size, estr);
10148                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10149                 FREE (estr);
10150                 FREE (mstr);
10151                 }
10152             if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10153                 continue;
10154             break;
10155             }
10156         }
10157     }
10158 if (exp->buf_ins == exp->buf_size) {                    /* At end of match buffer? */
10159         exp->buf_ins = 0;                               /* wrap around to beginning */
10160         sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10161     }
10162 if ((ep != NULL) && (i != exp->size)) {                 /* Found? */
10163     sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10164     if (ep->cnt > 0) {
10165         ep->cnt -= 1;
10166         sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10167                    (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10168         }
10169     else {
10170         uint32 after   = exp->after;
10171         int32 switches = ep->switches;
10172         if (ep->act && *ep->act) {
10173             sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10174             }
10175         else {
10176             sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10177             }
10178         sim_brk_setact (ep->act);                       /* set up actions */
10179         if (ep->switches & EXP_TYP_CLEARALL)            /* Clear-all expect rule? */
10180             sim_exp_clrall (exp);                       /* delete all rules */
10181         else {
10182             if (!(ep->switches & EXP_TYP_PERSIST))      /* One shot expect rule? */
10183                 sim_exp_clr_tab (exp, ep);              /* delete it */
10184             }
10185         sim_activate (&sim_expect_unit,                 /* schedule simulation stop when indicated */
10186                       (switches & EXP_TYP_TIME) ?
10187                             (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10188                              after);
10189         }
10190     /* Matched data is no longer available for future matching */
10191     exp->buf_ins = 0;
10192     }
10193 if (tstr)  //-V547
10194   FREE (tstr);
10195 return SCPE_OK;
10196 }
10197 
10198 /* Queue input data for sending */
10199 
10200 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
     /* [previous][next][first][last][top][bottom][index][help] */
10201 {
10202 if (snd->extoff != 0) {
10203     if (snd->insoff > snd->extoff)
10204         memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10205     snd->insoff -= snd->extoff;
10206     snd->extoff  = 0;
10207     }
10208 if (snd->insoff+size > snd->bufsize) {
10209     snd->bufsize = snd->insoff+size;
10210     snd->buffer  = (uint8 *)realloc(snd->buffer, snd->bufsize);
10211     if (!snd->buffer)
10212       {
10213         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10214                        __func__, __FILE__, __LINE__);
10215 #if defined(USE_BACKTRACE)
10216 # if defined(SIGUSR2)
10217         (void)raise(SIGUSR2);
10218         /*NOTREACHED*/ /* unreachable */
10219 # endif /* if defined(SIGUSR2) */
10220 #endif /* if defined(USE_BACKTRACE) */
10221         abort();
10222       }
10223     }
10224 memcpy(snd->buffer+snd->insoff, data, size);
10225 snd->insoff += size;
10226 if (delay)
10227     snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10228 if (after)
10229     snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10230 if (snd->after == 0)
10231     snd->after = snd->delay;
10232 snd->next_time = sim_gtime() + snd->after;
10233 return SCPE_OK;
10234 }
10235 
10236 /* Cancel Queued input data */
10237 t_stat sim_send_clear (SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10238 {
10239 snd->insoff = 0;
10240 snd->extoff = 0;
10241 return SCPE_OK;
10242 }
10243 
10244 /* Display console Queued input data status */
10245 
10246 t_stat sim_show_send_input (FILE *st, const SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10247 {
10248 if (snd->extoff < snd->insoff) {
10249     (void)fprintf (st, "%lld bytes of pending input Data:\r\n    ",
10250                    (long long)snd->insoff-snd->extoff);
10251     fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10252     (void)fprintf (st, "\r\n");
10253     }
10254 else
10255     (void)fprintf (st, "No Pending Input Data\r\n");
10256 if ((snd->next_time - sim_gtime()) > 0) {
10257     if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10258         (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10259                        (int)(snd->next_time - sim_gtime()),
10260         (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10261     else
10262         (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10263                        (int)(snd->next_time - sim_gtime()));
10264     }
10265 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10266     (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10267                    (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10268 else
10269     (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10270                    (int)snd->delay);
10271 if (snd->dptr && snd->dbit)
10272     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10273                    sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10274                    snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10275 return SCPE_OK;
10276 }
10277 
10278 /* Poll for Queued input data */
10279 
10280 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10281 {
10282 #if defined(TESTING)
10283 cpu_state_t * cpup = _cpup;
10284 #endif
10285 if ((NULL != snd) && (snd->extoff < snd->insoff)) {     /* pending input characters available? */
10286     if (sim_gtime() < snd->next_time) {                 /* too soon? */
10287         *stat = SCPE_OK;
10288         sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10289         }
10290     else {
10291         char dstr[8] = "";
10292         *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;/* get one */
10293         snd->next_time = sim_gtime() + snd->delay;
10294         if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10295             (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10296         sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10297         }
10298     return TRUE;
10299     }
10300 return FALSE;
10301 }
10302 
10303 /* Message Text */
10304 
10305 const char *sim_error_text (t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10306 {
10307 static char msgbuf[64];
10308 
10309 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);        /* remove any flags */
10310 if (stat == SCPE_OK)
10311     return "No Error";
10312 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10313     return scp_errors[stat-SCPE_BASE].message;
10314 (void)sprintf(msgbuf, "Error %d", stat);
10315 return msgbuf;
10316 }
10317 
10318 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10319 {
10320 char gbuf[CBUFSIZE];
10321 size_t cond;
10322 
10323 *stat = SCPE_ARG;
10324 cptr = get_glyph (cptr, gbuf, 0);
10325 if (0 == memcmp("SCPE_", gbuf, 5))
10326     memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));  /* skip leading SCPE_ */
10327 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10328     if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10329         cond += SCPE_BASE;
10330         break;
10331         }
10332 if (0 == strcmp(gbuf, "OK"))
10333     cond = SCPE_OK;
10334 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {       /* not found? */
10335     unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10336     if (0 == numeric_cond)                    /* try explicit number */
10337         return SCPE_ARG;
10338     cond = (t_stat) numeric_cond;
10339     }
10340 if (cond > SCPE_MAX_ERR)
10341     return SCPE_ARG;
10342 *stat = cond;
10343 return SCPE_OK;
10344 }
10345 
10346 /* Debug printout routines, from Dave Hittner */
10347 
10348 const char* debug_bstates = "01_^";
10349 char debug_line_prefix[256];
10350 int32 debug_unterm  = 0;
10351 
10352 /* Finds debug phrase matching bitmask from from device DEBTAB table */
10353 
10354 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10355 {
10356 static const char *debtab_none    = "DEBTAB_ISNULL";
10357 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10358 const char *some_match = NULL;
10359 int32 offset = 0;
10360 
10361 if (dptr->debflags == 0)
10362     return debtab_none;
10363 
10364 dbits &= dptr->dctrl;                           /* Look for just the bits that matched */
10365 
10366 /* Find matching words for bitmask */
10367 
10368 while ((offset < 32) && dptr->debflags[offset].name) {
10369     if (dptr->debflags[offset].mask == dbits)   /* All Bits Match */
10370         return dptr->debflags[offset].name;
10371     if (dptr->debflags[offset].mask & dbits)
10372         some_match = dptr->debflags[offset].name;
10373     offset++;
10374     }
10375 return some_match ? some_match : debtab_nomatch;
10376 }
10377 
10378 /* Prints standard debug prefix unless previous call unterminated */
10379 
10380 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10381 {
10382 const char* debug_type = get_dbg_verb (dbits, dptr);
10383 char tim_t[32] = "";
10384 char tim_a[32] = "";
10385 char  pc_s[64] = "";
10386 struct timespec time_now;
10387 
10388 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10389     clock_gettime(CLOCK_REALTIME, &time_now);
10390     if (sim_deb_switches & SWMASK ('R'))
10391         sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10392     if (sim_deb_switches & SWMASK ('T')) {
10393         time_t tnow = (time_t)time_now.tv_sec;
10394         struct tm *now = gmtime(&tnow);
10395         (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10396                       (int)now->tm_hour,
10397                       (int)now->tm_min,
10398                       (int)now->tm_sec,
10399                       (long)(time_now.tv_nsec / 1000000));
10400         }
10401     if (sim_deb_switches & SWMASK ('A')) {
10402         (void)sprintf(tim_t, "%d.%03ld ",
10403                       (int)(time_now.tv_sec),
10404                       (long)(time_now.tv_nsec / 1000000));
10405         }
10406     }
10407 if (sim_deb_switches & SWMASK ('P')) {
10408     t_value val;
10409 
10410     if (sim_vm_pc_value)
10411         val = (*sim_vm_pc_value)();
10412     else
10413         val = get_rval (sim_PC, 0);
10414     (void)sprintf(pc_s, "-%s:", sim_PC->name);
10415     sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10416     }
10417 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10418               tim_t, tim_a, sim_gtime(), pc_s,
10419               "", dptr->name, debug_type);
10420 return debug_line_prefix;
10421 }
10422 
10423 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
     /* [previous][next][first][last][top][bottom][index][help] */
10424 {
10425 int32 i, fields, offset;
10426 uint32 value, beforevalue, mask;
10427 
10428 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10429     if (bitdefs[fields].offset == 0xffffffff)       /* fixup uninitialized offsets */
10430         bitdefs[fields].offset = offset;
10431     offset += bitdefs[fields].width;
10432     }
10433 for (i = fields-1; i >= 0; i--) {                   /* print xlation, transition */
10434     if (bitdefs[i].name[0] == '\0')
10435         continue;
10436     if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10437         int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10438         (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10439         }
10440     else {
10441         const char *delta = "";
10442         mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10443         value = (uint32)((after >> bitdefs[i].offset) & mask);
10444         beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10445         if (value < beforevalue)
10446             delta = "_";
10447         if (value > beforevalue)
10448             delta = "^";
10449         if (bitdefs[i].valuenames)
10450             (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10451         else
10452             if (bitdefs[i].format) {
10453                 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10454                 (void)Fprintf(stream, bitdefs[i].format, value);
10455                 (void)Fprintf(stream, " ");
10456                 }
10457             else
10458                 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10459         }
10460     }
10461 }
10462 
10463 /* Prints state of a register: bit translation + state (0,1,_,^)
10464    indicating the state and transition of the bit and bitfields. States:
10465    0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */
10466 
10467 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
     /* [previous][next][first][last][top][bottom][index][help] */
10468     BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10469 {
10470 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10471     if (!debug_unterm)
10472         (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));         /* print prefix if required */
10473     if (header)
10474         (void)fprintf(sim_deb, "%s: ", header);
10475     fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs); /* print xlation, transition */
10476     if (terminate)
10477         (void)fprintf(sim_deb, "\r\n");
10478     debug_unterm = terminate ? 0 : 1;                   /* set unterm for next */
10479     }
10480 }
10481 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
     /* [previous][next][first][last][top][bottom][index][help] */
10482     uint32 before, uint32 after, int terminate)
10483 {
10484 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10485 }
10486 
10487 /* Print message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10488 void sim_printf (const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10489 {
10490 char stackbuf[STACKBUFSIZE];
10491 int32 bufsize = sizeof(stackbuf);
10492 char *buf = stackbuf;
10493 int32 len;
10494 va_list arglist;
10495 
10496 while (1) {                                         /* format passed string, args */
10497     va_start (arglist, fmt);
10498     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10499     va_end (arglist);
10500 
10501 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10502 
10503     if ((len < 0) || (len >= bufsize-1)) {
10504         if (buf != stackbuf)
10505             FREE (buf);
10506         if (bufsize >= (INT_MAX / 2))
10507             return;                                 /* too big */
10508         bufsize = bufsize * 2;
10509         if (bufsize < len + 2)
10510             bufsize = len + 2;
10511         buf = (char *) malloc (bufsize);
10512         if (buf == NULL)                            /* out of memory */
10513             return;
10514         buf[bufsize-1] = '\0';
10515         continue;
10516         }
10517     break;
10518     }
10519 
10520 if (sim_is_running) {
10521     char *c, *remnant = buf;
10522     while ((c = strchr(remnant, '\n'))) { //-NLOK
10523         if ((c != buf) && (*(c - 1) != '\r')) //-NLOK
10524             (void)printf("%.*s\r\n", (int)(c-remnant), remnant); //-NLOK
10525         else
10526             (void)printf("%.*s\n", (int)(c-remnant), remnant); //-NLOK
10527         remnant = c + 1;
10528         }
10529     (void)printf("%s", remnant);
10530     }
10531 else
10532     (void)printf("%s", buf);
10533 /* sim_printf carries diagnostic/warning text that must not be lost.  When
10534  * stdout is not a TTY (e.g. piped through "tee" for logging, as done by
10535  * per-instance boot scripts), the C library defaults to full block
10536  * buffering instead of line buffering, so infrequent messages -- exactly
10537  * the kind sim_printf is used for -- can sit unflushed for the entire run
10538  * of a long-lived headless daemon. Flush explicitly so every message is
10539  * visible immediately, regardless of how stdout is connected. */
10540 (void)fflush (stdout);
10541 if (sim_log && (sim_log != stdout)) {
10542     (void)fprintf (sim_log, "%s", buf);
10543     (void)fflush (sim_log);
10544     }
10545 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log)) {
10546     (void)fprintf (sim_deb, "%s", buf);
10547     (void)fflush (sim_deb);
10548     }
10549 
10550 if (buf != stackbuf)
10551     FREE (buf);
10552 }
10553 
10554 /* Print command result message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10555 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10556 {
10557 char stackbuf[STACKBUFSIZE];
10558 size_t bufsize = sizeof(stackbuf);
10559 char *buf = stackbuf;
10560 size_t len;
10561 va_list arglist;
10562 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10563 
10564 while (1) {                                         /* format passed string, args */
10565     va_start (arglist, fmt);
10566     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10567     va_end (arglist);
10568 
10569 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10570 
10571     if (len >= bufsize - 1) {
10572         if (buf != stackbuf)
10573             FREE (buf);
10574         bufsize = bufsize * 2;
10575         if (bufsize < len + 2)
10576             bufsize = len + 2;
10577         buf = (char *) malloc (bufsize);
10578         if (buf == NULL)                            /* out of memory */
10579             return SCPE_MEM;
10580         buf[bufsize-1] = '\0';
10581         continue;
10582         }
10583     break;
10584     }
10585 
10586 if (sim_do_ocptr[sim_do_depth]) {
10587     if (!sim_do_echo && !sim_quiet && !inhibit_message)
10588         sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10589     else {
10590         if (sim_deb)                        /* Always put context in debug output */
10591             (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10592         }
10593     }
10594 if (sim_is_running && !inhibit_message) {
10595     char *c, *remnant = buf;
10596     while ((c = strchr(remnant, '\n'))) { //-NLOK
10597         if ((c != buf) && (*(c - 1) != '\r')) //-NLOK
10598             (void)printf("%.*s\r\n", (int)(c-remnant), remnant); //-NLOK
10599         else
10600             (void)printf("%.*s\n", (int)(c-remnant), remnant); //-NLOK
10601         remnant = c + 1;
10602         }
10603     (void)printf("%s", remnant);
10604     }
10605 else {
10606     if (!inhibit_message)
10607         (void)printf("%s", buf);
10608     }
10609 if (sim_log && (sim_log != stdout) && !inhibit_message)
10610     (void)fprintf (sim_log, "%s", buf);
10611 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))/* Always display messages in debug output */
10612     (void)fprintf (sim_deb, "%s", buf);
10613 
10614 if (buf != stackbuf)
10615     FREE (buf);
10616 return stat | SCPE_NOMESSAGE;
10617 }
10618 
10619 /* Inline debugging - will print debug message if debug file is
10620    set and the bitmask matches the current device debug options.
10621    Extra returns are added for un*x systems, since the output
10622    device is set into 'raw' mode when the cpu is booted,
10623    and the extra returns don't hurt any other systems.
10624    Callers should be calling sim_debug() which is a macro
10625    defined in scp.h which evaluates the action condition before
10626    incurring call overhead. */
10627 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10628 {
10629 DEVICE *dptr = (DEVICE *)vdptr;
10630 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10631     char stackbuf[STACKBUFSIZE];
10632     int32 bufsize = sizeof(stackbuf);
10633     char *buf = stackbuf;
10634     va_list arglist;
10635     int32 i, j, len;
10636     const char* debug_prefix = sim_debug_prefix(dbits, dptr);   /* prefix to print if required */
10637 
10638     buf[bufsize-1] = '\0';
10639     while (1) {                                         /* format passed string, args */
10640         va_start (arglist, fmt);
10641         len = vsnprintf (buf, bufsize-1, fmt, arglist);
10642         va_end (arglist);
10643 
10644 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10645 
10646         if ((len < 0) || (len >= bufsize-1)) {
10647             if (buf != stackbuf)
10648                 FREE (buf);
10649             if (bufsize >= (INT_MAX / 2))
10650                 return;                                 /* too big */
10651             bufsize = bufsize * 2;
10652             if (bufsize < len + 2)
10653                 bufsize = len + 2;
10654             buf = (char *) malloc (bufsize);
10655             if (buf == NULL)                            /* out of memory */
10656                 return;
10657             buf[bufsize-1] = '\0';
10658             continue;
10659             }
10660         break;
10661         }
10662 
10663 /* Output the formatted data expanding newlines where they exist */
10664 
10665     for (i = j = 0; i < len; ++i) {
10666         if ('\n' == buf[i]) {
10667             if (i >= j) {
10668                 if ((i != j) || (i == 0)) {
10669                     if (debug_unterm)
10670                         (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10671                     else                                /* print prefix when required */
10672                         (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10673                     }
10674                 debug_unterm = 0;
10675                 }
10676             j = i + 1;
10677             }
10678         }
10679     if (i > j) {
10680         if (debug_unterm)
10681             (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10682         else                                        /* print prefix when required */
10683             (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10684         }
10685 
10686 /* Set unterminated flag for next time */
10687 
10688     debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10689     if (buf != stackbuf)
10690         FREE (buf);
10691     }
10692 return;
10693 }
10694 
10695 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
     /* [previous][next][first][last][top][bottom][index][help] */
10696 {
10697 #if defined(TESTING)
10698 cpu_state_t * cpup = _cpup;
10699 #endif
10700 if (sim_deb && (dptr->dctrl & reason)) {
10701     sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10702     if (data && len) {
10703         size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10704         char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10705         static char hex[] = "0123456789ABCDEF";
10706         static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10707         static unsigned char ebcdic2ascii[] = {
10708             0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10709             0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10710             0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10711             0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10712             0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10713             0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10714             0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10715             0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10716             0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10717             0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10718             0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10719             0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10720             0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10721             0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10722             0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10723             0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10724             0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10725             0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10726             0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10727             0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10728             0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10729             0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10730             0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10731             0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10732             0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10733             0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10734             0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10735             0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10736             0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10737             0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10738             0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10739             0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10740             };
10741 
10742         for (i=same=0; i<len; i += 16) {
10743             if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10744                 ++same;
10745                 continue;
10746                 }
10747             if (same > 0) {
10748                 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10749                            (unsigned long int)(i - (16*same)),
10750                            (unsigned long int)(i - 1));
10751                 same = 0;
10752                 }
10753             group = (((len - i) > 16) ? 16 : (len - i));
10754             strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10755             eidx = strlen(ebcdicbuf);
10756             strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10757             ridx = strlen(rad50buf);
10758             strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10759             soff = strlen(strbuf);
10760             for (sidx=oidx=0; sidx<group; ++sidx) {
10761                 outbuf[oidx++] = ' ';
10762                 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10763                 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10764                 if (sim_isprint (data[i+sidx]))
10765                     strbuf[soff+sidx] = data[i+sidx];
10766                 else
10767                     strbuf[soff+sidx] = '.';
10768                 if (ridx && ((sidx&1) == 0)) {
10769                     uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10770 
10771                     if (word >= 64000) {
10772                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10773                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10774                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10775                         }
10776                     else {
10777                         rad50buf[ridx++] = rad50[word/1600];
10778                         rad50buf[ridx++] = rad50[(word/40)%40];
10779                         rad50buf[ridx++] = rad50[word%40];
10780                         }
10781                     }
10782                 if (eidx) {
10783                     if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10784                         ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10785                     else
10786                         ebcdicbuf[eidx++] = '.';
10787                     }
10788                 }
10789             outbuf[oidx] = '\0';
10790             strbuf[soff+sidx] = '\0';
10791             ebcdicbuf[eidx] = '\0';
10792             rad50buf[ridx] = '\0';
10793             sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10794                     (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10795             }
10796         if (same > 0) {
10797             sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10798                     (unsigned long int)(i-(16*same)),
10799                     (unsigned long int)(len-1));
10800             }
10801         }
10802     }
10803 }
10804 
10805 int Fprintf (FILE *f, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10806 {
10807 int ret = 0;
10808 va_list args;
10809 
10810 va_start (args, fmt);
10811     ret = vfprintf (f, fmt, args);
10812 va_end (args);
10813 return ret;
10814 }
10815 
10816 /* Hierarchical help presentation
10817  *
10818  * Device help can be presented hierarchically by calling
10819  *
10820  * t_stat scp_help (FILE *st, DEVICE *dptr,
10821  *                  UNIT *uptr, int flag, const char *help, char *cptr)
10822  *
10823  * or one of its three cousins from the device HELP routine.
10824  *
10825  * *help is the pointer to the structured help text to be displayed.
10826  *
10827  * The format and usage, and some helper macros can be found in scp_help.h
10828  * If you don't use the macros, it is not necessary to #include "scp_help.h".
10829  *
10830  * Actually, if you don't specify a DEVICE pointer and don't include
10831  * other device references, it can be used for non-device help.
10832  */
10833 
10834 #define blankch(x) ((x) == ' ' || (x) == '\t')
10835 
10836 typedef struct topic {
10837     size_t         level;
10838     char          *title;
10839     char          *label;
10840     struct topic  *parent;
10841     struct topic **children;
10842     uint32         kids;
10843     char          *text;
10844     size_t         len;
10845     uint32         flags;
10846     size_t         kidwid;
10847 #define HLP_MAGIC_TOPIC  1
10848     } TOPIC;
10849 
10850 static volatile struct {
10851     const char *error;
10852     const char *prox;
10853     size_t block;
10854     size_t line;
10855     } help_where = { "", NULL, 0, 0 };
10856 jmp_buf help_env;
10857 
10858 #define FAIL(why,text,here)        \
10859   {                                \
10860     help_where.error = #text;      \
10861     help_where.prox = here;        \
10862     longjmp ( help_env, (why) );   \
10863     /*LINTED E_STMT_NOT_REACHED*/  \
10864   }
10865 
10866 /*
10867  * Add to topic text.
10868  * Expands text buffer as necessary.
10869  */
10870 
10871 static void appendText (TOPIC *topic, const char *text, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
10872 {
10873 char *newt;
10874 
10875 if (!len)
10876     return;
10877 
10878 newt = (char *)realloc (topic->text, topic->len + len +1);
10879 if (!newt) {
10880 #if !defined(SUNLINT)
10881     FAIL (SCPE_MEM, No memory, NULL);
10882 #endif /* if !defined(SUNLINT) */
10883     }
10884 topic->text = newt;
10885 memcpy (newt + topic->len, text, len);
10886 topic->len +=len;
10887 newt[topic->len] = '\0';
10888 return;
10889 }
10890 
10891 /* Release memory held by a topic and its children.
10892  */
10893 static void cleanHelp (TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
10894 {
10895 TOPIC *child;
10896 size_t i;
10897 
10898 FREE (topic->title);
10899 FREE (topic->text);
10900 FREE (topic->label);
10901 for (i = 0; i < topic->kids; i++) {
10902     child = topic->children[i];
10903     cleanHelp (child);
10904     FREE (child);
10905     }
10906 FREE (topic->children);
10907 return;
10908 }
10909 
10910 /* Build a help tree from a string.
10911  * Handles substitutions, formatting.
10912  */
10913 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
10914                          UNIT *uptr, const char *htext, va_list ap)
10915 {
10916 char *end;
10917 size_t n, ilvl;
10918 #define VSMAX 100
10919 char *vstrings[VSMAX];
10920 size_t vsnum = 0;
10921 char * astrings[VSMAX+1];
10922 size_t asnum = 0;
10923 char *const *hblock;
10924 const char *ep;
10925 t_bool excluded = FALSE;
10926 
10927 /* variable arguments consumed table.
10928  * The scheme used allows arguments to be accessed in random
10929  * order, but for portability, all arguments must be char *.
10930  * If you try to violate this, there ARE machines that WILL break.
10931  */
10932 
10933 (void)memset (vstrings, 0, sizeof (vstrings));
10934 (void)memset (astrings, 0, sizeof (astrings));
10935 astrings[asnum++] = (char *) htext;
10936 
10937 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10938     help_where.block = hblock - astrings;
10939     help_where.line = 0;
10940     while (*htext) {
10941         const char *start;
10942 
10943         help_where.line++;
10944         if (sim_isspace (*htext) || *htext == '+') {/* Topic text, indented topic text */
10945             if (excluded) {                     /* Excluded topic text */
10946                 while (*htext && *htext != '\n')
10947                     htext++;
10948                 if (*htext)
10949                     ++htext;
10950                 continue;
10951                 }
10952             ilvl = 1;
10953             appendText (topic, "    ", 4);      /* Basic indentation */
10954             if (*htext == '+') {                /* More for each + */
10955                 while (*htext == '+') {
10956                     ilvl++;
10957                     appendText (topic, "    ", 4);
10958                     htext++;
10959                     }
10960                 }
10961             while (*htext && *htext != '\n' && sim_isspace (*htext))
10962                 htext++;
10963             if (!*htext)                        /* Empty after removing leading spaces */
10964                 break;
10965             start = htext;
10966             while (*htext) {                    /* Process line for substitutions */
10967                 if (*htext == '%') {
10968                     appendText (topic, start, htext - start); /* Flush up to escape */
10969                     switch (*++htext) {         /* Evaluate escape */
10970                         case 'U':
10971                             if (dptr) {
10972                                 char buf[129];
10973                                 n = uptr? uptr - dptr->units: 0;
10974                                 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10975                                 appendText (topic, buf, strlen (buf));
10976                                 }
10977                             break;
10978                         case 'D':
10979                             if (dptr != NULL)
10980                                 appendText (topic, dptr->name, strlen (dptr->name));
10981                             break;
10982                         case 'S':
10983                             appendText (topic, sim_name, strlen (sim_name));
10984                             break;
10985                         case '%':
10986                             appendText (topic, "%", 1);
10987                             break;
10988                         case '+':
10989                             appendText (topic, "+", 1);
10990                             break;
10991                         default:                    /* Check for vararg # */
10992                             if (sim_isdigit (*htext)) {
10993                                 n = 0;
10994                                 while (sim_isdigit (*htext))
10995                                     n += (n * 10) + (*htext++ - '0');
10996                                 if (( *htext != 'H' && *htext != 's') ||
10997                                     n == 0 || n >= VSMAX) {
10998 #if !defined(SUNLINT)
10999                                     FAIL (SCPE_ARG, Invalid escape, htext);
11000 #endif /* if !defined(SUNLINT) */
11001                                     }
11002                                 while (n > vsnum)   /* Get arg pointer if not cached */
11003                                     vstrings[vsnum++] = va_arg (ap, char *);
11004                                 start = vstrings[n-1]; /* Insert selected string */
11005                                 if (*htext == 'H') {   /* Append as more input */
11006                                     if (asnum >= VSMAX) {
11007 #if !defined(SUNLINT)
11008                                         FAIL (SCPE_ARG, Too many blocks, htext);
11009 #endif /* if !defined(SUNLINT) */
11010                                         }
11011                                     astrings[asnum++] = (char *)start;
11012                                     break;
11013                                     }
11014                                 ep = start;
11015                                 while (*ep) {
11016                                     if (*ep == '\n') {
11017                                         ep++;       /* Segment to \n */
11018                                         appendText (topic, start, ep - start);
11019                                         if (*ep) {  /* More past \n, indent */
11020                                             size_t i;
11021                                             for (i = 0; i < ilvl; i++)
11022                                                 appendText (topic, "    ", 4);
11023                                             }
11024                                         start = ep;
11025                                         }
11026                                     else
11027                                         ep++;
11028                                     }
11029                                 appendText (topic, start, ep-start);
11030                                 break;
11031                                 }
11032 #if !defined(SUNLINT)
11033                             FAIL (SCPE_ARG, Invalid escape, htext);
11034 #endif /* if !defined(SUNLINT) */
11035                         } /* switch (escape) */
11036                     start = ++htext;
11037                     continue;                   /* Current line */
11038                     } /* if (escape) */
11039                 if (*htext == '\n') {           /* End of line, append last segment */
11040                     htext++;
11041                     appendText (topic, start, htext - start);
11042                     break;                      /* To next line */
11043                     }
11044                 htext++;                        /* Regular character */
11045                 }
11046             continue;
11047             } /* topic text line */
11048         if (sim_isdigit (*htext)) {             /* Topic heading */
11049             TOPIC **children;
11050             TOPIC *newt;
11051             char nbuf[100];
11052 
11053             n = 0;
11054             start = htext;
11055             while (sim_isdigit (*htext))
11056                 n += (n * 10) + (*htext++ - '0');
11057             if ((htext == start) || !n) {
11058 #if !defined(SUNLINT)
11059                 FAIL (SCPE_ARG, Invalid topic heading, htext);
11060 #endif /* if !defined(SUNLINT) */
11061                 }
11062             if (n <= topic->level) {            /* Find level for new topic */
11063                 while (n <= topic->level)
11064                     topic = topic->parent;
11065                 }
11066             else {
11067                 if (n > topic->level + 1) {     /* Skipping down more than 1 */
11068 #if !defined(SUNLINT)
11069                     FAIL (SCPE_ARG, Level not contiguous, htext); /* E.g. 1 3, not reasonable */
11070 #endif /* if !defined(SUNLINT) */
11071                     }
11072                 }
11073             while (*htext && (*htext != '\n') && sim_isspace (*htext))
11074                 htext++;
11075             if (!*htext || (*htext == '\n')) {  /* Name missing */
11076 #if !defined(SUNLINT)
11077                 FAIL (SCPE_ARG, Missing topic name, htext);
11078 #endif /* if !defined(SUNLINT) */
11079                 }
11080             start = htext;
11081             while (*htext && (*htext != '\n'))
11082                 htext++;
11083             if (start == htext) {               /* Name NULL */
11084 #if !defined(SUNLINT)
11085                 FAIL (SCPE_ARG, Null topic name, htext);
11086 #endif /* if !defined(SUNLINT) */
11087                 }
11088             excluded = FALSE;
11089             if (*start == '?') {                /* Conditional topic? */
11090                 size_t n = 0;
11091                 start++;
11092                 while (sim_isdigit (*start))    /* Get param # */
11093                     n += (n * 10) + (*start++ - '0');
11094                 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11095 #if !defined(SUNLINT)
11096                     FAIL (SCPE_ARG, Invalid parameter number, start);
11097 #endif /* if !defined(SUNLINT) */
11098                     }
11099                 while (n > vsnum)               /* Get arg pointer if not cached */
11100                     vstrings[vsnum++] = va_arg (ap, char *);
11101                 end = vstrings[n-1];            /* Check for True */
11102                 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11103                     excluded = TRUE;            /* False, skip topic this time */
11104                     if (*htext)
11105                         htext++;
11106                     continue;
11107                     }
11108                 }
11109             newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11110             if (!newt) {
11111 #if !defined(SUNLINT)
11112                 FAIL (SCPE_MEM, No memory, NULL);
11113 #endif /* if !defined(SUNLINT) */
11114                 }
11115             size_t len = (htext > start) ? (htext - start) : 0;
11116             newt->title = (char *) malloc(len + 1);
11117             if (!newt->title) {
11118                 FREE (newt);
11119 #if !defined(SUNLINT)
11120                 FAIL (SCPE_MEM, No memory, NULL);
11121 #endif /* if !defined(SUNLINT) */
11122                 }
11123             memcpy (newt->title, start, htext - start);
11124             newt->title[htext - start] = '\0';
11125             if (*htext)
11126                 htext++;
11127 
11128             if (newt->title[0] == '$')
11129                 newt->flags |= HLP_MAGIC_TOPIC;
11130 
11131             children = (TOPIC **) realloc (topic->children,
11132                                            (topic->kids +1) * sizeof (TOPIC *));
11133             if (NULL == children) {
11134                 FREE (newt->title);
11135                 FREE (newt);
11136 #if !defined(SUNLINT)
11137                 FAIL (SCPE_MEM, No memory, NULL);
11138 #endif /* if !defined(SUNLINT) */
11139                 }
11140             topic->children = children;
11141             topic->children[topic->kids++] = newt;
11142             newt->level = n;
11143             newt->parent = topic;
11144             n = strlen (newt->title);
11145             if (n > topic->kidwid)
11146                 topic->kidwid = n;
11147             (void)sprintf (nbuf, ".%u", topic->kids);
11148             n = strlen (topic->label) + strlen (nbuf) + 1;
11149             newt->label = (char *) malloc (n);
11150             if (NULL == newt->label) {
11151                 FREE (newt->title);
11152                 topic->children[topic->kids -1] = NULL;
11153                 FREE (newt);
11154 #if !defined(SUNLINT)
11155                 FAIL (SCPE_MEM, No memory, NULL);
11156 #endif /* if !defined(SUNLINT) */
11157                 }
11158             (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11159             topic = newt;
11160             continue;
11161             } /* digits introducing a topic */
11162         if (*htext == ';') {                    /* Comment */
11163             while (*htext && *htext != '\n')
11164                 htext++;
11165             continue;
11166             }
11167 #if !defined(SUNLINT)
11168         FAIL (SCPE_ARG, Unknown line type, htext);     /* Unknown line */
11169 #endif /* if !defined(SUNLINT) */
11170         } /* htext not at end */
11171     (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11172     vsnum = 0;
11173     } /* all strings */
11174 
11175 return topic;
11176 }
11177 
11178 /*
11179  * Create prompt string - top thru current topic
11180  * Add prompt at end.
11181  */
11182 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
     /* [previous][next][first][last][top][bottom][index][help] */
11183 {
11184 char *prefix;
11185 char *newp, *newt;
11186 
11187 if (topic->level == 0) {
11188     prefix = (char *) calloc (2,1);
11189     if (!prefix) {
11190 #if !defined(SUNLINT)
11191         FAIL (SCPE_MEM, No memory, NULL);
11192 #endif /* if !defined(SUNLINT) */
11193         }
11194     prefix[0] = '\n';
11195     }
11196 else
11197     prefix = helpPrompt (topic->parent, "", oneword);
11198 
11199 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11200                         strlen (pstring) +1);
11201 if (!newp) {
11202     FREE (prefix);
11203 #if !defined(SUNLINT)
11204     FAIL (SCPE_MEM, No memory, NULL);
11205 #endif /* if !defined(SUNLINT) */
11206     }
11207 strcpy (newp, prefix);
11208 if (topic->children) {
11209     if (topic->level != 0)
11210         strcat (newp, " ");
11211     newt = (topic->flags & HLP_MAGIC_TOPIC)?
11212             topic->title+1: topic->title;
11213     if (oneword) {
11214         char *np = newp + strlen (newp);
11215         while (*newt) {
11216             *np++ = blankch (*newt)? '_' : *newt;
11217             newt++;
11218             }
11219         *np = '\0';
11220         }
11221     else
11222         strcat (newp, newt);
11223     if (*pstring && *pstring != '?')
11224         strcat (newp, " ");
11225     }
11226 strcat (newp, pstring);
11227 FREE (prefix);
11228 return newp;
11229 }
11230 
11231 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
11232 {
11233 char tbuf[CBUFSIZE];
11234 size_t i, skiplines;
11235 #if defined(_WIN32)
11236 FILE *tmp;
11237 char *tmpnam;
11238 
11239 do {
11240     int fd;
11241     tmpnam = _tempnam (NULL, "simh");
11242     fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11243     if (fd != -1) {
11244         tmp = _fdopen (fd, "w+");
11245         break;
11246         }
11247     } while (1);
11248 #else
11249 FILE *tmp = tmpfile();
11250 #endif /* if defined(_WIN32) */
11251 
11252 if (!tmp) {
11253     (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11254                    xstrerror_l(errno), errno);
11255     return;
11256     }
11257 
11258 if (topic->title)
11259     (void)fprintf (st, "%s\r\n", topic->title+1);
11260 
11261 skiplines = 0;
11262 if (topic->title) {
11263   if (!strcmp (topic->title+1, "Registers")) {
11264       fprint_reg_help (tmp, dptr) ;
11265       skiplines = 1;
11266       }
11267   else
11268       if (!strcmp (topic->title+1, "Set commands")) {
11269           fprint_set_help (tmp, dptr);
11270           skiplines = 3;
11271           }
11272       else
11273           if (!strcmp (topic->title+1, "Show commands")) {
11274               fprint_show_help (tmp, dptr);
11275               skiplines = 3;
11276               }
11277   }
11278 rewind (tmp);
11279 if (errno) {
11280     (void)fprintf (st, "rewind: error %d\r\n", errno);
11281 }
11282 
11283 /* Discard leading blank lines/redundant titles */
11284 
11285 for (i =0; i < skiplines; i++)
11286     if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11287 
11288 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11289     if (tbuf[0] != '\n')
11290         fputs ("    ", st);
11291     fputs (tbuf, st);
11292     }
11293 fclose (tmp);
11294 #if defined(_WIN32)
11295 remove (tmpnam);
11296 FREE (tmpnam);
11297 #endif /* if defined(_WIN32) */
11298 return;
11299 }
11300 /* Flatten and display help for those who say they prefer it. */
11301 
11302 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11303                                UNIT *uptr, int32 flag,
11304                                TOPIC *topic, va_list ap )
11305 {
11306 size_t i;
11307 
11308 if (topic->flags & HLP_MAGIC_TOPIC) {
11309     (void)fprintf (st, "\r\n%s ", topic->label);
11310     displayMagicTopic (st, dptr, topic);
11311     }
11312 else
11313     (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11314 
11315 /*
11316  * Topic text (for magic topics, follows for explanations)
11317  * It's possible/reasonable for a magic topic to have no text.
11318  */
11319 
11320 if (topic->text)
11321     fputs (topic->text, st);
11322 
11323 for (i = 0; i < topic->kids; i++)
11324     displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11325 
11326 return SCPE_OK;
11327 }
11328 
11329 #define HLP_MATCH_AMBIGUOUS (~0u)
11330 #define HLP_MATCH_WILDCARD  (~1U)
11331 #define HLP_MATCH_NONE      0
11332 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
     /* [previous][next][first][last][top][bottom][index][help] */
11333 {
11334 size_t i, match;
11335 char cbuf[CBUFSIZE], *cptr;
11336 
11337 if (!strcmp (token, "*"))
11338     return HLP_MATCH_WILDCARD;
11339 
11340 match = 0;
11341 for (i = 0; i < topic->kids; i++) {
11342     strcpy (cbuf,topic->children[i]->title +
11343             ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11344     cptr = cbuf;
11345     while (*cptr) {
11346         if (blankch (*cptr)) {
11347             *cptr++ = '_';
11348             }
11349         else {
11350             *cptr = (char)toupper (*cptr);
11351             cptr++;
11352             }
11353         }
11354     if (!strcmp (cbuf, token))      /* Exact Match */
11355         return i+1;
11356     if (!strncmp (cbuf, token, strlen (token))) {
11357         if (match)
11358             return HLP_MATCH_AMBIGUOUS;
11359         match = i+1;
11360         }
11361     }
11362 return match;
11363 }
11364 
11365 /* Main help routine */
11366 
11367 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11368                   UNIT *uptr, int32 flag,
11369                   const char *help, const char *cptr, va_list ap)
11370 {
11371 TOPIC top;
11372 TOPIC *topic = &top;
11373 int failed;
11374 size_t match;
11375 size_t i;
11376 const char *p;
11377 t_bool flat_help = FALSE;
11378 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11379 
11380 static const char attach_help[] = { " ATTACH" };
11381 static const char  brief_help[] = { "%s help.  Type <CR> to exit, HELP for navigation help.\r\n" };
11382 static const char onecmd_help[] = { "%s help.\r\n" };
11383 static const char   help_help[] = {
11384     /****|***********************80 column width guide********************************/
11385     "    To see more HELP information, type the listed subtopic name.  To move\r\n"
11386     "    up a level, just type <CR>.  To review the current subtopic, type \"?\".\r\n"
11387     "    To view all subtopics, type \"*\".  To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11388     };
11389 
11390 (void)memset (&top, 0, sizeof(top));
11391 top.parent = &top;
11392 if ((failed = setjmp (help_env)) != 0) {
11393     (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11394                            "Error in block %u line %u: %s\r\n"
11395                            "%s%*.*s%s\r\n",
11396                    (int)help_where.block, (int)help_where.line, help_where.error, //-V567
11397                    help_where.prox ? "Near '" : "",
11398                    help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11399                    help_where.prox ? help_where.prox : "",
11400                    help_where.prox ? "'" : "");
11401     cleanHelp (&top);
11402     return failed;
11403     }
11404 
11405 /* Compile string into navigation tree */
11406 
11407 /* Root */
11408 
11409 if (dptr) {
11410     p = dptr->name;
11411     flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11412     }
11413 else
11414     p = sim_name;
11415 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11416 if (!top.title)
11417   {
11418     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11419                    __func__, __FILE__, __LINE__);
11420 #if defined(USE_BACKTRACE)
11421 # if defined(SIGUSR2)
11422     (void)raise(SIGUSR2);
11423     /*NOTREACHED*/ /* unreachable */
11424 # endif /* if defined(SIGUSR2) */
11425 #endif /* if defined(USE_BACKTRACE) */
11426     abort();
11427   }
11428 for (i = 0; p[i]; i++ )
11429     top.title[i] = (char)toupper (p[i]);
11430 top.title[i] = '\0';
11431 if (flag & SCP_HELP_ATTACH)
11432     strcpy (top.title+i, attach_help);
11433 
11434 top.label = (char *) malloc (sizeof ("1"));
11435 if (!top.label)
11436   {
11437     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11438                    __func__, __FILE__, __LINE__);
11439 #if defined(USE_BACKTRACE)
11440 # if defined(SIGUSR2)
11441     (void)raise(SIGUSR2);
11442     /*NOTREACHED*/ /* unreachable */
11443 # endif /* if defined(SIGUSR2) */
11444 #endif /* if defined(USE_BACKTRACE) */
11445     abort();
11446   }
11447 strcpy (top.label, "1");
11448 
11449 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11450 
11451 if (flat_help) {
11452     flag |= SCP_HELP_FLAT;
11453     if (sim_ttisatty())
11454         (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11455     else
11456         (void)fprintf (st, "%s help.\r\n", top.title);
11457     }
11458 else
11459     (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11460 
11461 /* Add text and subtopics */
11462 
11463 (void) buildHelp (&top, dptr, uptr, help, ap);
11464 
11465 /* Go to initial topic if provided */
11466 
11467 while (cptr && *cptr) {
11468     cptr = get_glyph (cptr, gbuf, 0);
11469     if (!gbuf[0])
11470         break;
11471     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11472         (void)fprintf (st, "\r\n");
11473         fputs (help_help, st);
11474         break;
11475         }
11476     match =  matchHelpTopicName (topic, gbuf);
11477     if (match == HLP_MATCH_WILDCARD) {
11478         if (dptr)
11479             displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11480         cleanHelp (&top);
11481         return SCPE_OK;
11482         }
11483     if (match == HLP_MATCH_AMBIGUOUS) {
11484         (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11485         break;
11486         }
11487     if (match == HLP_MATCH_NONE) {
11488         (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11489         break;
11490         }
11491     topic = topic->children[match-1];
11492     }
11493 cptr = NULL;
11494 
11495 if (flat_help) {
11496     displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11497     cleanHelp (&top);
11498     return SCPE_OK;
11499     }
11500 
11501 /* Interactive loop displaying help */
11502 
11503 while (TRUE) {
11504     char *pstring;
11505     const char *prompt[2] = {"? ", "Subtopic? "};
11506 
11507     /* Some magic topic names for help from data structures */
11508 
11509     if (topic->flags & HLP_MAGIC_TOPIC) {
11510         fputc ('\n', st);
11511         displayMagicTopic (st, dptr, topic);
11512         }
11513     else
11514         (void)fprintf (st, "\r\n%s\r\n", topic->title);
11515 
11516     /* Topic text (for magic topics, follows for explanations)
11517      * It's possible/reasonable for a magic topic to have no text.
11518      */
11519 
11520     if (topic->text)
11521         fputs (topic->text, st);
11522 
11523     if (topic->kids) {
11524         size_t w = 0;
11525         char *p;
11526         char tbuf[CBUFSIZE];
11527 
11528         (void)fprintf (st, "\r\n    Additional information available:\r\n\r\n");
11529         for (i = 0; i < topic->kids; i++) {
11530             strcpy (tbuf, topic->children[i]->title +
11531                     ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11532             for (p = tbuf; *p; p++) {
11533                 if (blankch (*p))
11534                     *p = '_';
11535                 }
11536             w += 4 + topic->kidwid;
11537             if (w > 80) {
11538                 w = 4 + topic->kidwid;
11539                 fputc ('\r', st);
11540                 fputc ('\n', st);
11541                 }
11542             (void)fprintf (st, "    %-*s", (int32_t)topic->kidwid, tbuf);
11543             }
11544         (void)fprintf (st, "\r\n\r\n");
11545         if (flag & SCP_HELP_ONECMD) {
11546             pstring = helpPrompt (topic, "", TRUE);
11547             (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11548             FREE (pstring);
11549             break;
11550             }
11551         }
11552 
11553     if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11554         break;
11555 
11556   reprompt:
11557     if (NULL == cptr || !*cptr) {
11558         if (topic->kids == 0)
11559             topic = topic->parent;
11560         pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11561 
11562         cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11563         FREE (pstring);
11564         if ((cptr != NULL) &&                   /* Got something? */
11565             ((0 == strcmp (cptr, "\x04")) ||    /* was it a bare ^D? */
11566              (0 == strcmp (cptr, "\x1A"))))     /* was it a bare ^Z? */
11567             cptr = NULL;                        /* These are EOF synonyms */
11568         }
11569 
11570     if (NULL == cptr)                           /* EOF, exit help */
11571         break;
11572 
11573     cptr = get_glyph (cptr, gbuf, 0);
11574     if (!strcmp (gbuf, "*")) {              /* Wildcard */
11575         displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11576         gbuf[0] = '\0';                     /* Displayed all subtopics, go up */
11577         }
11578     if (!gbuf[0]) {                         /* Blank, up a level */
11579         if (topic->level == 0)
11580             break;
11581         topic = topic->parent;
11582         continue;
11583         }
11584     if (!strcmp (gbuf, "?"))                /* ?, repaint current topic */
11585         continue;
11586     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11587         fputs (help_help, st);
11588         goto reprompt;
11589         }
11590     if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))   /* EXIT (help) */
11591         break;
11592 
11593     /* String - look for that topic */
11594 
11595     if (!topic->kids) {
11596         (void)fprintf (st, "No additional help at this level.\r\n");
11597         cptr = NULL;
11598         goto reprompt;
11599         }
11600     match = matchHelpTopicName (topic, gbuf);
11601     if (match == HLP_MATCH_AMBIGUOUS) {
11602         (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11603         cptr = NULL;
11604         goto reprompt;
11605         }
11606 
11607     if (match == HLP_MATCH_NONE) {
11608         (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11609         cptr = NULL;
11610         goto reprompt;
11611         }
11612     /* Found, display subtopic */
11613 
11614     topic = topic->children[match-1];
11615     }
11616 
11617 /* Free structures and return */
11618 
11619 cleanHelp (&top);
11620 
11621 return SCPE_OK;
11622 }
11623 
11624 /* variable argument list shell - most commonly used */
11625 
11626 t_stat scp_help (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11627                  UNIT *uptr, int32 flag,
11628                  const char *help, const char *cptr, ...)
11629 {
11630 t_stat r;
11631 va_list ap;
11632 
11633 va_start (ap, cptr);
11634 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11635 va_end (ap);
11636 
11637 return r;
11638 }
11639 
11640 #if defined(_MSC_VER)
11641 # pragma warning(pop)
11642 #endif

/* [previous][next][first][last][top][bottom][index][help] */