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. processIsTranslated
  5. strremove
  6. strtrimspace
  7. allowCores
  8. CleanDUMA
  9. dl_iterate_phdr_callback
  10. GetUCRTVersion
  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. show_version
  76. show_config
  77. show_log_names
  78. show_dev_logicals
  79. show_queue
  80. show_time
  81. show_break
  82. show_dev_radix
  83. show_dev_debug
  84. show_on
  85. show_mod_names
  86. show_dev_modifiers
  87. show_all_mods
  88. show_one_mod
  89. show_show_commands
  90. show_dev_show_commands
  91. brk_cmd
  92. ssh_break
  93. ssh_break_one
  94. reset_cmd
  95. reset_all
  96. reset_all_p
  97. attach_cmd
  98. scp_attach_unit
  99. attach_unit
  100. attach_err
  101. detach_cmd
  102. detach_all
  103. scp_detach_unit
  104. detach_unit
  105. sim_dname
  106. sim_uname
  107. run_cmd
  108. run_cmd_message
  109. sim_run_boot_prep
  110. fprint_stopped_gen
  111. fprint_stopped
  112. step_svc
  113. expect_svc
  114. int_handler
  115. exdep_cmd
  116. exdep_reg_loop
  117. exdep_addr_loop
  118. ex_reg
  119. get_rval
  120. dep_reg
  121. put_rval
  122. ex_addr
  123. get_aval
  124. dep_addr
  125. eval_cmd
  126. read_line
  127. read_line_p
  128. get_glyph_gen
  129. get_glyph
  130. get_glyph_nc
  131. get_glyph_quoted
  132. get_glyph_cmd
  133. sim_trim_endspc
  134. sim_isspace
  135. sim_islower
  136. sim_isalpha
  137. sim_isprint
  138. sim_isdigit
  139. sim_isgraph
  140. sim_isalnum
  141. get_uint
  142. get_range
  143. sim_decode_quoted_string
  144. sim_encode_quoted_string
  145. fprint_buffer_string
  146. find_dev
  147. find_unit
  148. sim_register_internal_device
  149. find_dev_from_unit
  150. qdisable
  151. find_reg_glob
  152. find_reg
  153. get_switches
  154. get_sim_sw
  155. get_sim_opt
  156. put_switches
  157. get_rsearch
  158. get_asearch
  159. test_search
  160. strtotv
  161. sprint_val
  162. fprint_val
  163. sim_fmt_secs
  164. sim_process_event
  165. sim_activate
  166. _sim_activate
  167. sim_activate_abs
  168. sim_activate_after
  169. _sim_activate_after
  170. sim_cancel
  171. sim_is_active
  172. sim_activate_time
  173. sim_gtime
  174. sim_qcount
  175. sim_brk_init
  176. sim_brk_fnd
  177. sim_brk_fnd_ex
  178. sim_brk_new
  179. sim_brk_set
  180. sim_brk_clr
  181. sim_brk_clrall
  182. sim_brk_show
  183. sim_brk_showall
  184. sim_brk_test
  185. sim_brk_getact
  186. sim_brk_clract
  187. sim_brk_setact
  188. sim_brk_npc
  189. sim_brk_clrspc
  190. sim_brk_message
  191. sim_set_expect
  192. sim_set_noexpect
  193. sim_exp_fnd
  194. sim_exp_clr_tab
  195. sim_exp_clr
  196. sim_exp_clrall
  197. sim_exp_set
  198. sim_exp_show_tab
  199. sim_exp_show
  200. sim_exp_showall
  201. sim_exp_check
  202. sim_send_input
  203. sim_send_clear
  204. sim_show_send_input
  205. sim_send_poll_data
  206. sim_error_text
  207. sim_string_to_stat
  208. get_dbg_verb
  209. sim_debug_prefix
  210. fprint_fields
  211. sim_debug_bits_hdr
  212. sim_debug_bits
  213. sim_printf
  214. sim_messagef
  215. _sim_debug
  216. sim_data_trace
  217. Fprintf
  218. appendText
  219. cleanHelp
  220. buildHelp
  221. helpPrompt
  222. displayMagicTopic
  223. displayFlatHelp
  224. matchHelpTopicName
  225. scp_vhelp
  226. 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) 2021-2023 Jeffrey H. Johnson
  12  * Copyright (c) 2006-2024 The DPS8M Development Team
  13  *
  14  * Permission is hereby granted, free of charge, to any person obtaining a
  15  * copy of this software and associated documentation files (the "Software"),
  16  * to deal in the Software without restriction, including without limitation
  17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  18  * and/or sell copies of the Software, and to permit persons to whom the
  19  * Software is furnished to do so, subject to the following conditions:
  20  *
  21  * The above copyright notice and this permission notice shall be included in
  22  * all copies or substantial portions of the Software.
  23  *
  24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  27  * ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  28  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  29  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30  * SOFTWARE.
  31  *
  32  * Except as contained in this notice, the name of Robert M. Supnik shall not
  33  * be used in advertising or otherwise to promote the sale, use or other
  34  * dealings in this Software without prior written authorization from
  35  * Robert M. Supnik.
  36  *
  37  * ---------------------------------------------------------------------------
  38  */
  39 
  40 //-V::701
  41 
  42 #if !defined(__EXTENSIONS__)
  43 # define __EXTENSIONS__
  44 #endif
  45 
  46 #if !defined(__STDC_WANT_LIB_EXT1__)
  47 # define __STDC_WANT_LIB_EXT1__ 1
  48 #endif
  49 
  50 #if !defined(_GNU_SOURCE)
  51 # define _GNU_SOURCE
  52 #endif
  53 
  54 /* Macros and data structures */
  55 
  56 #include "sim_defs.h"
  57 #include "sim_disk.h"
  58 #include "sim_tape.h"
  59 #include "sim_sock.h"
  60 
  61 #include <signal.h>
  62 #include <ctype.h>
  63 #include <time.h>
  64 #include <math.h>
  65 #include <stddef.h>
  66 #if defined(_WIN32)
  67 # if !defined(WIN32_LEAN_AND_MEAN)
  68 #  define WIN32_LEAN_AND_MEAN
  69 # endif /* if !defined(WIN32_LEAN_AND_MEAN) */
  70 # if defined(_MSC_VER)
  71 #  pragma warning(push, 3)
  72 # endif
  73 # include <direct.h>
  74 # include <io.h>
  75 # include <fcntl.h>
  76 #else
  77 # include <unistd.h>
  78 # define HAVE_UNISTD 1
  79 #endif
  80 #include <sys/stat.h>
  81 #include <sys/types.h>
  82 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
  83 # include <sys/resource.h>
  84 #endif
  85 #include <setjmp.h>
  86 #include <stdint.h>
  87 #include <limits.h>
  88 #if defined(__APPLE__)
  89 # include <xlocale.h>
  90 #endif
  91 #include <locale.h>
  92 
  93 #include "linehistory.h"
  94 
  95 #if defined(__APPLE__)
  96 # include <sys/sysctl.h>
  97 #endif /* if defined(_APPLE_) */
  98 
  99 #if ( defined(__linux__) || defined(__linux) || defined(_linux) || defined(linux) ) //-V1040
 100 # include <sys/sysinfo.h>
 101 # define LINUX_OS
 102 #endif
 103 
 104 #include <uv.h>
 105 
 106 #if !defined(HAVE_UNISTD)
 107 # undef USE_BACKTRACE
 108 #endif /* if !defined(HAVE_UNISTD) */
 109 
 110 #if defined(USE_BACKTRACE)
 111 # include <string.h>
 112 # include <signal.h>
 113 #endif /* if defined(USE_BACKTRACE) */
 114 
 115 #if defined(__HAIKU__)
 116 # include <OS.h>
 117 #endif /* if defined(__HAIKU__) */
 118 
 119 #if !defined(__CYGWIN__)
 120 # if !defined(__APPLE__)
 121 #  if !defined(_AIX)
 122 #   if !defined(__MINGW32__)
 123 #    if !defined(__MINGW64__)
 124 #     if !defined(CROSS_MINGW32)
 125 #      if !defined(CROSS_MINGW64)
 126 #       if !defined(_WIN32)
 127 #        if !defined(__HAIKU__)
 128 #         include <link.h>
 129 #        endif
 130 #       endif
 131 #      endif
 132 #     endif
 133 #    endif
 134 #   endif
 135 #  endif
 136 # endif
 137 #endif
 138 
 139 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
 140 # include <windows.h>
 141 #endif
 142 
 143 #if defined(__CYGWIN__)
 144 # include <windows.h>
 145 # include <sys/utsname.h>
 146 # include <sys/cygwin.h>
 147 # include <cygwin/version.h>
 148 #endif
 149 
 150 #define DBG_CTR 0
 151 
 152 #include "../dps8/dps8.h"
 153 #include "../dps8/dps8_cpu.h"
 154 #include "../dps8/ver.h"
 155 #include "../dps8/sysdefs.h"
 156 
 157 #include "../dps8/dps8_iom.h"
 158 #include "../dps8/dps8_fnp2.h"
 159 
 160 #include "../decNumber/decContext.h"
 161 #include "../decNumber/decNumberLocal.h"
 162 
 163 #include "../dps8/dps8_math128.h"
 164 
 165 #if !defined(__CYGWIN__)
 166 # if !defined(__APPLE__)
 167 #  if !defined(_AIX)
 168 #   if !defined(__MINGW32__)
 169 #    if !defined(__MINGW64__)
 170 #     if !defined(CROSS_MINGW32)
 171 #      if !defined(CROSS_MINGW64)
 172 #       if !defined(_WIN32)
 173 #        if !defined(__HAIKU__)
 174 static unsigned int dl_iterate_phdr_callback_called = 0;
 175 #        endif
 176 #       endif
 177 #      endif
 178 #     endif
 179 #    endif
 180 #   endif
 181 #  endif
 182 # endif
 183 #endif
 184 
 185 #if defined(MAX)
 186 # undef MAX
 187 #endif /* if defined(MAX) */
 188 #define MAX(a,b)  (((a) >= (b)) ? (a) : (b))
 189 
 190 #if defined(FREE)
 191 # undef FREE
 192 #endif /* if defined(FREE) */
 193 #define FREE(p) do  \
 194   {                 \
 195     free((p));      \
 196     (p) = NULL;     \
 197   } while(0)
 198 
 199 /* search logical and boolean ops */
 200 
 201 #define SCH_OR          0                               /* search logicals */
 202 #define SCH_AND         1
 203 #define SCH_XOR         2
 204 #define SCH_E           0                               /* search booleans */
 205 #define SCH_N           1
 206 #define SCH_G           2
 207 #define SCH_L           3
 208 #define SCH_EE          4
 209 #define SCH_NE          5
 210 #define SCH_GE          6
 211 #define SCH_LE          7
 212 
 213 #define MAX_DO_NEST_LVL 20                              /* DO cmd nesting level */
 214 #define SRBSIZ          1024                            /* save/restore buffer */
 215 #define SIM_BRK_INILNT  4096                            /* bpt tbl length */
 216 #define SIM_BRK_ALLTYP  0xFFFFFFFB
 217 
 218 #define UPDATE_SIM_TIME                                         \
 219     if (1) {                                                    \
 220         int32 _x;                                               \
 221         if (sim_clock_queue == QUEUE_LIST_END)                  \
 222             _x = noqueue_time;                                  \
 223         else                                                    \
 224             _x = sim_clock_queue->time;                         \
 225         sim_time = sim_time + (_x - sim_interval);              \
 226         sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
 227         if (sim_clock_queue == QUEUE_LIST_END)                  \
 228             noqueue_time = sim_interval;                        \
 229         else                                                    \
 230             sim_clock_queue->time = sim_interval;               \
 231         }                                                       \
 232     else                                                        \
 233         (void)0
 234 
 235 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
 236 
 237 #define SZ_R(rp) \
 238     (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
 239 
 240 #define SZ_LOAD(sz,v,mb,j)                                                 \
 241     if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j));        \
 242     else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
 243     else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
 244     else v = *(((t_uint64 *) mb) + ((uint32) j));
 245 
 246 #define SZ_STORE(sz,v,mb,j)                                                         \
 247     if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v;                    \
 248     else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
 249     else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
 250     else *(((t_uint64 *) mb) + ((uint32) j)) = v;
 251 
 252 #define GET_SWITCHES(cp) \
 253     if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
 254 
 255 #define GET_RADIX(val,dft)                          \
 256     if (sim_switches & SWMASK ('O')) val = 8;       \
 257     else if (sim_switches & SWMASK ('D')) val = 10; \
 258     else if (sim_switches & SWMASK ('H')) val = 16; \
 259     else val = dft;
 260 
 261 /*
 262  * The per-simulator init routine is a weak global that defaults to NULL
 263  * The other per-simulator pointers can be overridden by the init routine
 264  */
 265 
 266 t_bool sim_asynch_enabled = FALSE;
 267 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
 268 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
 269 extern void (*sim_vm_init) (void);
 270 extern void (*sim_vm_exit) (void);
 271 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
 272 void (*sim_vm_post) (t_bool from_scp) = NULL;
 273 CTAB *sim_vm_cmd = NULL;
 274 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
 275 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
 276 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
 277 t_value (*sim_vm_pc_value) (void) = NULL;
 278 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
 279 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
 280 
 281 /* Prototypes */
 282 
 283 /* Set and show command processors */
 284 
 285 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 286 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 287 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 288 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 289 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
 290 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
 291 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 292 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 293 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 294 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 295 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 296 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 297 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 298 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 299 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 300 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 301 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 302 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 303 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
 304 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 305 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 306 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 307 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 308 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 309 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 310 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 311 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
 312 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
 313 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
 314 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
 315 t_stat sim_save (FILE *sfile);
 316 t_stat sim_rest (FILE *rfile);
 317 
 318 /* Breakpoint package */
 319 
 320 t_stat sim_brk_init (void);
 321 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
 322 t_stat sim_brk_clr (t_addr loc, int32 sw);
 323 t_stat sim_brk_clrall (int32 sw);
 324 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
 325 t_stat sim_brk_showall (FILE *st, int32 sw);
 326 CONST char *sim_brk_getact (char *buf, int32 size);
 327 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
 328 char *sim_brk_clract (void);
 329 
 330 FILE *stdnul;
 331 
 332 /* Command support routines */
 333 
 334 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 335 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 336 int32 test_search (t_value *val, SCHTAB *schptr);
 337 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
 338 int32 get_switches (const char *cptr);
 339 CONST char *get_sim_sw (CONST char *cptr);
 340 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
 341 t_value get_rval (REG *rptr, uint32 idx);
 342 void put_rval (REG *rptr, uint32 idx, t_value val);
 343 void fprint_help (FILE *st);
 344 void fprint_stopped (FILE *st, t_stat r);
 345 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
 346 void fprint_sep (FILE *st, int32 *tokens);
 347 char *read_line (char *ptr, int32 size, FILE *stream);
 348 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
 349 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
 350 char *sim_trim_endspc (char *cptr);
 351 
 352 /* Forward references */
 353 
 354 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
 355 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
 356 t_bool qdisable (DEVICE *dptr);
 357 t_stat attach_err (UNIT *uptr, t_stat stat);
 358 t_stat detach_all (int32 start_device, t_bool shutdown);
 359 t_stat assign_device (DEVICE *dptr, const char *cptr);
 360 t_stat deassign_device (DEVICE *dptr);
 361 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
 362 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
 363     REG *lowr, REG *highr, uint32 lows, uint32 highs);
 364 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
 365 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
 366 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
 367     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
 368 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
 369 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
 370     UNIT *uptr, int32 dfltinc);
 371 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
 372 t_stat step_svc (UNIT *ptr);
 373 t_stat expect_svc (UNIT *ptr);
 374 t_stat set_on (int32 flag, CONST char *cptr);
 375 t_stat set_verify (int32 flag, CONST char *cptr);
 376 t_stat set_message (int32 flag, CONST char *cptr);
 377 t_stat set_quiet (int32 flag, CONST char *cptr);
 378 t_stat set_localopc (int32 flag, CONST char *cptr);
 379 t_stat set_asynch (int32 flag, CONST char *cptr);
 380 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 381 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
 382 void int_handler (int signal);
 383 t_stat set_prompt (int32 flag, CONST char *cptr);
 384 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
 385 t_stat sim_set_environment (int32 flag, CONST char *cptr);
 386 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
 387 
 388 /* Global data */
 389 
 390 DEVICE *sim_dflt_dev             = NULL;
 391 UNIT *sim_clock_queue            = QUEUE_LIST_END;
 392 int32 sim_interval               = 0;
 393 int32 sim_switches               = 0;
 394 FILE *sim_ofile                  = NULL;
 395 SCHTAB *sim_schrptr              = FALSE;
 396 SCHTAB *sim_schaptr              = FALSE;
 397 DEVICE *sim_dfdev                = NULL;
 398 UNIT *sim_dfunit                 = NULL;
 399 DEVICE **sim_internal_devices    = NULL;
 400 uint32 sim_internal_device_count = 0;
 401 int32 sim_opt_out                = 0;
 402 int32 sim_is_running             = 0;
 403 t_bool sim_processing_event      = FALSE;
 404 uint32 sim_brk_summ              = 0;
 405 uint32 sim_brk_types             = 0;
 406 BRKTYPTAB *sim_brk_type_desc     = NULL;         /* type descriptions */
 407 uint32 sim_brk_dflt              = 0;
 408 uint32 sim_brk_match_type;
 409 t_addr sim_brk_match_addr;
 410 char *sim_brk_act[MAX_DO_NEST_LVL];
 411 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
 412 BRKTAB **sim_brk_tab             = NULL;
 413 int32 sim_brk_ent                = 0;
 414 int32 sim_brk_lnt                = 0;
 415 int32 sim_brk_ins                = 0;
 416 int32 sim_iglock                 = 0;
 417 int32 sim_nolock                 = 0;
 418 int32 sim_quiet                  = 0;
 419 int32 sim_localopc               = 1;
 420 int32 sim_randompst              = 0;
 421 int32 sim_randstate              = 0;
 422 int32 sim_step                   = 0;
 423 int nodist                       = 0;
 424 #if defined(PERF_STRIP)
 425 int32 sim_nostate                = 1;
 426 #else
 427 int32 sim_nostate                = 0;
 428 #endif /* if defined(PERF_STRIP) */
 429 static double sim_time;
 430 static uint32 sim_rtime;
 431 static int32 noqueue_time;
 432 volatile int32 stop_cpu          = 0;
 433 t_value *sim_eval                = NULL;
 434 static t_value sim_last_val;
 435 static t_addr sim_last_addr;
 436 FILE *sim_log                    = NULL;         /* log file */
 437 FILEREF *sim_log_ref             = NULL;         /* log file file reference */
 438 FILE *sim_deb                    = NULL;         /* debug file */
 439 FILEREF *sim_deb_ref             = NULL;         /* debug file file reference */
 440 int32 sim_deb_switches           = 0;            /* debug switches */
 441 struct timespec sim_deb_basetime;                /* debug timestamp relative base time */
 442 char *sim_prompt                 = NULL;         /* prompt string */
 443 static FILE *sim_gotofile;                       /* the currently open do file */
 444 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];   /* the current line number in the currently open do file */
 445 static int32 sim_do_echo         = 0;            /* the echo status of the currently open do file */
 446 static int32 sim_show_message    = 1;            /* the message display status of the currently open do file */
 447 static int32 sim_on_inherit      = 0;            /* the inherit status of on state and conditions when executing do files */
 448 static int32 sim_do_depth        = 0;
 449 
 450 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
 451 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
 452 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
 453 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
 454 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
 455 
 456 t_stat sim_last_cmd_stat;                        /* Command Status */
 457 
 458 static SCHTAB sim_stabr;                         /* Register search specifier */
 459 static SCHTAB sim_staba;                         /* Memory search specifier */
 460 
 461 static UNIT sim_step_unit   = { UDATA (&step_svc, 0, 0)  };
 462 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0)  };
 463 
 464 /* Tables and strings */
 465 
 466 const char save_vercur[] = "V4.1";
 467 const char save_ver40[]  = "V4.0";
 468 const char save_ver35[]  = "V3.5";
 469 const char save_ver32[]  = "V3.2";
 470 const char save_ver30[]  = "V3.0";
 471 const struct scp_error {
 472     const char *code;
 473     const char *message;
 474     } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
 475         {{"NXM",     "Address space exceeded"},
 476          {"UNATT",   "Unit not attached"},
 477          {"IOERR",   "I/O error"},
 478          {"CSUM",    "Checksum error"},
 479          {"FMT",     "Format error"},
 480          {"NOATT",   "Unit not attachable"},
 481          {"OPENERR", "File open error"},
 482          {"MEM",     "Memory exhausted"},
 483          {"ARG",     "Invalid argument"},
 484          {"STEP",    "Step expired"},
 485          {"UNK",     "Unknown command"},
 486          {"RO",      "Read only argument"},
 487          {"INCOMP",  "Command not completed"},
 488          {"STOP",    "Simulation stopped"},
 489          {"EXIT",    "Goodbye"},
 490          {"TTIERR",  "Console input I/O error"},
 491          {"TTOERR",  "Console output I/O error"},
 492          {"EOF",     "End of file"},
 493          {"REL",     "Relocation error"},
 494          {"NOPARAM", "No settable parameters"},
 495          {"ALATT",   "Unit already attached"},
 496          {"TIMER",   "Hardware timer error"},
 497          {"SIGERR",  "Signal handler setup error"},
 498          {"TTYERR",  "Console terminal setup error"},
 499          {"SUB",     "Subscript out of range"},
 500          {"NOFNC",   "Command not allowed"},
 501          {"UDIS",    "Unit disabled"},
 502          {"NORO",    "Read only operation not allowed"},
 503          {"INVSW",   "Invalid switch"},
 504          {"MISVAL",  "Missing value"},
 505          {"2FARG",   "Too few arguments"},
 506          {"2MARG",   "Too many arguments"},
 507          {"NXDEV",   "Non-existent device"},
 508          {"NXUN",    "Non-existent unit"},
 509          {"NXREG",   "Non-existent register"},
 510          {"NXPAR",   "Non-existent parameter"},
 511          {"NEST",    "Nested DO command limit exceeded"},
 512          {"IERR",    "Internal error"},
 513          {"MTRLNT",  "Invalid magtape record length"},
 514          {"LOST",    "Console Telnet connection lost"},
 515          {"TTMO",    "Console Telnet connection timed out"},
 516          {"STALL",   "Console Telnet output stall"},
 517          {"AFAIL",   "Assertion failed"},
 518          {"INVREM",  "Invalid remote console command"},
 519          {"NOTATT",  "Not attached"},
 520          {"EXPECT",  "Expect matched"},
 521          {"REMOTE",  "Remote console command"},
 522     };
 523 
 524 const size_t size_map[] = { sizeof (int8),
 525     sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
 526     , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
 527 };
 528 
 529 const t_value width_mask[] = { 0,
 530     0x1, 0x3, 0x7, 0xF,
 531     0x1F, 0x3F, 0x7F, 0xFF,
 532     0x1FF, 0x3FF, 0x7FF, 0xFFF,
 533     0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
 534     0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
 535     0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
 536     0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
 537     0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
 538     0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
 539     0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
 540     0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
 541     0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
 542     0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
 543     0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
 544     0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
 545     0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
 546     };
 547 
 548 static const char simh_help[] =
 549        /***************** 80 character line width template *************************/
 550       "1Commands\n"
 551 #define HLP_RESET       "*Commands Resetting Devices"
 552        /***************** 80 character line width template *************************/
 553       "2Resetting Devices\n"
 554       " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\n"
 555       " simulator to a predefined condition.  If the switch \"`-p`\" is specified,\n"
 556       " the device is reset to its initial power-on state:\n\n"
 557       "++RESET                  resets all devices\n"
 558       "++RESET -p               power-cycle all devices\n"
 559       "++RESET ALL              resets all devices\n"
 560       "++RESET <device>         resets the specified <device>\n\n"
 561       " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\n"
 562       " interrupt requests, and returns the device to a quiescent state.\n\n"
 563       " * It does **NOT** clear the main memory or affect associated I/O\n"
 564       " connections.\n"
 565 #define HLP_EXAMINE     "*Commands Examining_and_Changing_State"
 566 #define HLP_IEXAMINE    "*Commands Examining_and_Changing_State"
 567 #define HLP_DEPOSIT     "*Commands Examining_and_Changing_State"
 568 #define HLP_IDEPOSIT    "*Commands Examining_and_Changing_State"
 569        /***************** 80 character line width template *************************/
 570       "2Examining and Changing State\n"
 571       " There are four commands to examine and change state:\n\n"
 572       " * `EXAMINE` (*abbreviated* `E`) examines state\n"
 573       " * `DEPOSIT` (*abbreviated* `D`) changes state\n"
 574       " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\n"
 575       "    and allows the user to interactively change it\n"
 576       " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\n"
 577       "    interactively change state\n\n"
 578       " All four commands take the form:\n\n"
 579       "++command {modifiers} <object list>\n\n"
 580       " The `DEPOSIT` command requires the deposit value at the end of the command.\n\n"
 581       " There are four kinds of modifiers: **switches**, **device/unit name**,\n"
 582       " **search specifier**, and for `EXAMINE`, **output file**.\n\n"
 583       " * **Switches** have been described previously.\n"
 584       " * A **device/unit name** identifies the device and unit whose address\n"
 585       " space is to be examined or modified. If no device is specified, the CPU\n"
 586       " main memory is selected. If a device but no unit is specified, unit `0`\n"
 587       " of the specified device is selected automatically.\n"
 588       " * The **search specifier** provides criteria for testing addresses or\n"
 589       " registers to see if they should be processed.  The search specifier\n"
 590       " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\n"
 591       " both, optionally separated by spaces:\n\n"
 592       "++{ < logical op >  < value > }  < relational op >  < value >\n\n"
 593        /***************** 80 character line width template *************************/
 594       " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\n"
 595       " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\n"
 596       " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\n"
 597       " equal*), \">=\" (*greater than or equal*), \">\" (*greater\n"
 598       " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\n"
 599       " * * If any \"<`logical operator`>\" is specified without\n"
 600       " a \"<`relational operator`>\", it is ignored.\n"
 601       " * * If any \"<`relational operator`>\" is specified without\n"
 602       " a \"<`logical operator`>\", no logical operation is performed.\n"
 603       " * * All comparisons are unsigned.\n\n"
 604       " * The **output file** modifier redirects the command output to a file\n"
 605       " instead of the console.  The **output file** modifier is specified with\n"
 606       " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\n\n"
 607       " **NOTE**: Modifiers may be specified in any order.  If multiple\n"
 608       " modifiers of the same type are specified, later modifiers override earlier\n"
 609       " modifiers. If the **device/unit name** comes *after* the search specifier,\n"
 610       " the search values will interpreted in the *radix of the CPU*, rather than\n"
 611       " of the device/unit.\n\n"
 612       " The \"<`object list`>\" argument consists of one or more of the following,\n"
 613       " separated by commas:\n\n"
 614        /***************** 80 character line width template *************************/
 615       "++register                the specified register\n"
 616       "++register[sub1-sub2]     the specified register array locations,\n"
 617       "++++++++                  starting at location sub1 up to and\n"
 618       "++++++++                  including location sub2\n"
 619       "++register[sub1/length]   the specified register array locations,\n"
 620       "++++++++                  starting at location sub1 up to but\n"
 621       "++++++++                  not including sub1+length\n"
 622       "++register[ALL]           all locations in the specified register\n"
 623       "++++++++                  array\n"
 624       "++register1-register2     all the registers starting at register1\n"
 625       "++++++++                  up to and including register2\n"
 626       "++address                 the specified location\n"
 627       "++address1-address2       all locations starting at address1 up to\n"
 628       "++++++++                  and including address2\n"
 629       "++address/length          all location starting at address up to\n"
 630       "++++++++                  but not including address+length\n"
 631       "++STATE                   all registers in the device\n"
 632       "++ALL                     all locations in the unit\n"
 633       "++$                       the last value displayed by an EXAMINE\n"
 634       "++++++++                  command interpreted as an address\n"
 635       "3Switches\n"
 636       "4Formatting Control\n"
 637       " Switches can be used to control the format of the displayed information:\n\n"
 638        /***************** 80 character line width template *************************/
 639       "5-a\n"
 640       " display as ASCII\n"
 641       "5-c\n"
 642       " display as character string\n"
 643       "5-m\n"
 644       " display as instruction mnemonics\n"
 645       "5-o\n"
 646       " display as octal\n"
 647       "5-d\n"
 648       " display as decimal\n"
 649       "5-h\n"
 650       " display as hexadecimal\n\n"
 651       "3Examples\n"
 652       "++ex 1000-1100                examine 1000 to 1100\n"
 653       "++de PC 1040                  set PC to 1040\n"
 654       "++ie 40-50                    interactively examine 40:50\n"
 655       "++ie >1000 40-50              interactively examine the subset\n"
 656       "+++++++++                     of locations 40:50 that are >1000\n"
 657       "++ex rx0 50060                examine 50060, RX unit 0\n"
 658       "++ex rx sbuf[3-6]             examine SBUF[3] to SBUF[6] in RX\n"
 659       "++de all 0                    set main memory to 0\n"
 660       "++de &77>0 0                  set all addresses whose low order\n"
 661       "+++++++++                     bits are non-zero to 0\n"
 662       "++ex -m @memdump.txt 0-7777   dump memory to file\n\n"
 663       " * **NOTE**: To terminate an interactive command, simply type any bad value\n"
 664       "           (*e.g.* `XYZ`) when input is requested.\n"
 665 #define HLP_EVALUATE    "*Commands Evaluating_Instructions"
 666        /***************** 80 character line width template *************************/
 667       "2Evaluating Instructions\n"
 668       " The `EVAL` command evaluates a symbolic expression and returns the\n"
 669       " equivalent numeric value.\n\n"
 670        /***************** 80 character line width template *************************/
 671       "2Running A Simulated Program\n"
 672 #define HLP_RUN         "*Commands Running_A_Simulated_Program RUN"
 673       "3RUN\n"
 674       " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\n"
 675       " argument, if given, in the PC (program counter), and starts execution.\n"
 676       " If no argument is given execution starts at the current PC.\n"
 677 #define HLP_GO          "*Commands Running_A_Simulated_Program GO"
 678       "3GO\n"
 679       " The `GO` command does *not* reset devices, deposits its argument (if\n"
 680       " given) in the PC, and starts execution.  If no argument is given,\n"
 681       " execution starts at the current PC (program counter).\n"
 682 #define HLP_CONTINUE    "*Commands Running_A_Simulated_Program Continuing_Execution"
 683       "3Continuing Execution\n"
 684       " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\n"
 685       " (if execution was stopped, possibly due to hitting a breakpoint) at the\n"
 686       " current program counter without resetting any devices.\n"
 687 #define HLP_STEP        "*Commands Running_A_Simulated_Program Step_Execution"
 688       "3Step Execution\n"
 689       " The `STEP` command (*abbreviated* `S`) resumes execution at the current\n"
 690       " PC for the number of instructions given by its argument.  If no argument\n"
 691       " is supplied, one instruction is executed.\n"
 692       "4Switches\n"
 693       "5`-T`\n"
 694       " If the `STEP` command is invoked with the \"`-T`\" switch, the step\n"
 695       " command will cause execution to run for *microseconds* rather than\n"
 696       " instructions.\n"
 697 #define HLP_NEXT        "*Commands Running_A_Simulated_Program NEXT"
 698       "3NEXT\n"
 699       " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\n"
 700       " for one instruction, attempting to execute *through* subroutine calls.\n"
 701       " If the next instruction to be executed is *not* a subroutine call, then\n"
 702       " one instruction is executed.\n"
 703 #define HLP_BOOT        "*Commands Running_A_Simulated_Program Booting_the_system"
 704       "3Booting the system\n"
 705       " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\n"
 706       " the device and unit given by its argument. If no unit is supplied,\n"
 707       " unit `0` is bootstrapped.  The specified unit must be `ATTACH`'ed.\n\n"
 708       " When booting Multics, the boot device should always be `iom0`.\n"
 709       " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\n"
 710       " into memory and the system will transfer control to the boot record.\n\n"
 711       " **Example**\n\n"
 712       "++; Boot Multics using iom0\n"
 713       "++boot iom0\n\n"
 714        /***************** 80 character line width template *************************/
 715       "2Stopping The Simulator\n"
 716       " The simulator runs until the simulated hardware encounters an error, or\n"
 717       " until the user forces a stop condition.\n"
 718       "3Simulator Detected Stop Conditions\n"
 719       " These simulator-detected conditions stop simulation:\n\n"
 720       "++-  HALT instruction.  If a HALT instruction is decoded, simulation stops.\n\n"
 721       "++-  I/O error.  If an I/O error occurs during simulation of an I/O\n"
 722       "+++operation, and the device stop-on-I/O-error flag is set, simulation\n"
 723       "+++usually stops.\n\n"
 724       "++-  Processor condition.  Certain processor conditions can stop\n"
 725       "+++the simulation.\n"
 726       "3User Specified Stop Conditions\n"
 727       " Typing the interrupt character stops simulation.  The interrupt character\n"
 728       " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\n"
 729       " set to `005` (`^E`).\n\n"
 730        /***************** 80 character line width template *************************/
 731 #define HLP_BREAK       "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 732 #define HLP_NOBREAK     "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 733       "4Breakpoints\n"
 734       " The simulator offers breakpoint capability for debugging. Users may define\n"
 735       " breakpoints of different types, identified by letter (for example, `E`\n"
 736       " for *execution*, `R` for *read*, `W` for *write*, etc).\n\n"
 737       " Associated with each breakpoint is a count and, optionally, one or more\n"
 738       " actions.  Each time a breakpoint occurs, the associated count\n"
 739       " is *decremented*.  If the count is less than or equal to `0`, the breakpoint\n"
 740       " occurs; otherwise, it is deferred.  When the breakpoint occurs, any\n"
 741       " optional actions are automatically executed.\n\n"
 742       " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\n\n"
 743       "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\n\n"
 744       " If no type is specified, the default breakpoint type (`E`, *execution*) is\n"
 745       " used.  If no address range is specified, the current PC is used.  As\n"
 746       " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\n"
 747       " range of addresses low-high, or a relative range of address/length.\n"
 748        /***************** 80 character line width template *************************/
 749       "5Displaying Breakpoints\n"
 750       " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\n\n"
 751       "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\n\n"
 752       " Locations with breakpoints of the specified type are displayed.\n\n"
 753       " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\n"
 754       " commands which may be subsequently used to establish the same\n"
 755       " breakpoint(s).\n\n"
 756       "5Removing Breakpoints\n"
 757       " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\n"
 758       "5Examples\n"
 759       " The following examples illustrate breakpoint usage:\n\n"
 760       "++BREAK                      set E break at current PC\n"
 761       "++BREAK -e 200               set E break at 200\n"
 762       "++BREAK 2000/2[2]            set E breaks at 2000,2001 with count = 2\n"
 763       "++BREAK 100;EX AC;D MQ 0     set E break at 100 with actions EX AC and\n"
 764       "+++++++++D MQ 0\n"
 765       "++BREAK 100;                 delete action on break at 100\n\n"
 766        /***************** 80 character line width template *************************/
 767       "2Connecting and Disconnecting Devices\n"
 768       " Units are simulated as files on the host file system.  Before using any\n"
 769       " simulated unit, the user must specify the file to be accessed by that unit.\n"
 770 #define HLP_ATTACH      "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
 771       "3Attaching devices\n"
 772       " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\n\n"
 773       "++ATTACH <unit> <filename>\n\n"
 774       " Some devices have more detailed or specific help available with:\n\n"
 775       "++HELP <device> ATTACH\n\n"
 776       "4Switches\n"
 777       "5-n\n"
 778       " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\n"
 779       " file will be created when the filename specified does not exist, or an\n"
 780       " existing file will have it's size truncated to zero, and an appropriate\n"
 781       " message is printed.\n"
 782       "5-e\n"
 783       " If the file does not exist, and the \"`-e`\" switch *was not* specified,\n"
 784       " a new file is created, and an appropriate message is printed.  If\n"
 785       " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\n"
 786       " error message is printed.\n"
 787       "5-r\n"
 788       " If the \"`-r`\" switch is specified, or the file is write protected by\n"
 789       " host operating system, `ATTACH` tries to open the file in read only mode.\n"
 790       " If the file does not exist, or the unit does not support read only\n"
 791       " operation, an error occurs.  Input-only devices, such as card readers, or\n"
 792       " storage devices with write locking switches, such as disks or tapes,\n"
 793       " support read only operation - other devices do not.  If a file is\n"
 794       " attached read only, its contents can be examined but not modified.\n"
 795       "5-q\n"
 796       " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\n"
 797       " or opening one read only (\"`-r`\"), the message announcing this fact\n"
 798       " is suppressed.\n"
 799       "5-f\n"
 800       " For simulated magnetic tapes, the `ATTACH` command can specify the format\n"
 801       " of the attached tape image file:\n\n"
 802       "++ATTACH -f <tape_unit> <format> <filename>\n\n"
 803       " * The currently supported magnetic tape image file formats are:\n\n"
 804       " |                  |                                                      |\n"
 805       " | ----------------:|:---------------------------------------------------- |\n"
 806       " | \"**`SIMH`**\"   | The **SIMH** / **DPS8M** native portable tape format |\n"
 807       " | \"**`E11`**\"    | The *D Bit* **Ersatz-11** simulator format           |\n"
 808       " | \"**`TPC`**\"    | The **TPC** format (*used by _SIMH_ prior to V2.3*)  |\n"
 809       " | \"**`P7B`**\"    | The **Paul Pierce** `7`-track tape archive format    |\n\n"
 810        /***************** 80 character line width template *************************/
 811       " * The default tape format can also be specified with the `SET` command\n"
 812       " prior to using the `ATTACH` command:\n\n"
 813       "++SET <tape_unit> FORMAT=<format>\n"
 814       "++ATTACH <tape_unit> <filename>\n\n"
 815       " * The format of a currently attached tape image can be displayed with\n"
 816       "   the `SHOW FORMAT` command:\n\n"
 817       "++SHOW <unit> FORMAT\n\n"
 818       " **Examples**\n\n"
 819       " The following example illustrates common `ATTACH` usage:\n"
 820       "++; Associate the tape image file \"12.7MULTICS.tap\" with the tape0 unit\n"
 821       "++; in read-only mode, where tape0 corresponds to the first tape device.\n"
 822       "++ATTACH -r tape0 12.7MULTICS.tap\n\n"
 823       "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\n"
 824       "++; The disk0 unit corresponds to the first disk device.\n"
 825       "++ATTACH disk0 root.dsk\n\n"
 826        /***************** 80 character line width template *************************/
 827 #define HLP_DETACH      "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
 828       "3Detaching devices\n"
 829       " The `DETACH` (*abbreviation* `DET`) command breaks the association between\n"
 830       " a unit and its backing file or device:\n\n"
 831       "++DETACH ALL             Detach all units\n"
 832       "++DETACH <unit>          Detach specified unit\n\n"
 833       " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\n"
 834 #define HLP_SET         "*Commands SET"
 835       "2SET\n"
 836        /***************** 80 character line width template *************************/
 837 #define HLP_SET_LOG    "*Commands SET Logging"
 838       "3Logging\n"
 839       " Interactions with the simulator session can be recorded to a log file.\n\n"
 840       "+SET LOG log_file            Specify the log destination\n"
 841       "++++++++                     (STDOUT, DEBUG, or filename)\n"
 842       "+SET NOLOG                   Disables any currently active logging\n"
 843       "4Switches\n"
 844       "5`-N`\n"
 845       " By default, log output is written at the *end* of the specified log file.\n"
 846       " A new log file can created if the \"`-N`\" switch is used on the command\n"
 847       " line.\n\n"
 848       "5`-B`\n"
 849       " By default, log output is written in *text* mode.  The log file can be\n"
 850       " opened for *binary* mode writing if the \"`-B`\" switch is used on the\n"
 851       " command line.\n"
 852 #define HLP_SET_DEBUG  "*Commands SET Debug_Messages"
 853        /***************** 80 character line width template *************************/
 854       "3Debug Messages\n"
 855       "+SET DEBUG debug_file        Specify the debug destination\n"
 856       "++++++++                     (STDOUT, STDERR, LOG, or filename)\n"
 857       "+SET NODEBUG                 Disables any currently active debug output\n"
 858       "4Switches\n"
 859       " Debug message output contains a timestamp which indicates the number of\n"
 860       " simulated instructions which have been executed prior to the debug event.\n\n"
 861       " Debug message output can be enhanced to contain additional, potentially\n"
 862       " useful information.\n\n\n"
 863       " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\n"
 864       "5-T\n"
 865       " The \"`-T`\" switch causes debug output to contain a time of day displayed\n"
 866       " as `hh:mm:ss.msec`.\n"
 867       "5-A\n"
 868       " The \"`-A`\" switch causes debug output to contain a time of day displayed\n"
 869       " as `seconds.msec`.\n"
 870       "5-R\n"
 871       " The \"`-R`\" switch causes timing to be relative to the start of debugging.\n"
 872       "5-P\n"
 873       " The \"`-P`\" switch adds the output of the PC (program counter) to each\n"
 874       " debug message.\n"
 875       "5-N\n"
 876       " The \"`-N`\" switch causes a new (empty) file to be written to.\n"
 877       " (The default is to append to an existing debug log file).\n"
 878       "5-D\n"
 879       " The \"`-D`\" switch causes data blob output to also display the data\n"
 880       " as **`RADIX-50`** characters.\n"
 881       "5-E\n"
 882       " The \"`-E`\" switch causes data blob output to also display the data\n"
 883       " as \"**EBCDIC**\" characters.\n"
 884        /***************** 80 character line width template *************************/
 885 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
 886       "3Environment Variables\n"
 887       "+SET ENVIRONMENT NAME=val    Set environment variable\n"
 888       "+SET ENVIRONMENT NAME        Clear environment variable\n"
 889 #define HLP_SET_ON      "*Commands SET Command_Status_Trap_Dispatching"
 890       "3Command Status Trap Dispatching\n"
 891       "+SET ON                      Enables error checking command execution\n"
 892       "+SET NOON                    Disables error checking command execution\n"
 893       "+SET ON INHERIT              Enables inheritance of ON state and actions\n"
 894       "+SET ON NOINHERIT            Disables inheritance of ON state and actions\n"
 895 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
 896       "3Command Execution Display\n"
 897       "+SET VERIFY                  Enables display of processed script commands\n"
 898       "+SET VERBOSE                 Enables display of processed script commands\n"
 899       "+SET NOVERIFY                Disables display of processed script commands\n"
 900       "+SET NOVERBOSE               Disables display of processed script commands\n"
 901 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
 902       "3Command Error Status Display\n"
 903       "+SET MESSAGE                 Re-enables display of script error messages\n"
 904       "+SET NOMESSAGE               Disables display of script error messages\n"
 905 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
 906       "3Command Output Display\n"
 907       "+SET QUIET                   Disables suppression of some messages\n"
 908       "+SET NOQUIET                 Re-enables suppression of some messages\n"
 909 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
 910       "3Local Operator Console\n"
 911       "+SET LOCALOPC                Enables local operator console\n"
 912       "+SET NOLOCALOPC              Disables local operator console\n"
 913 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
 914       "3Command Prompt\n"
 915       "+SET PROMPT \"string\"         Sets an alternate simulator prompt string\n"
 916       "3Device and Unit Settings\n"
 917       "+SET <dev> OCT|DEC|HEX       Set device display radix\n"
 918       "+SET <dev> ENABLED           Enable device\n"
 919       "+SET <dev> DISABLED          Disable device\n"
 920       "+SET <dev> DEBUG{=arg}       Set device debug flags\n"
 921       "+SET <dev> NODEBUG={arg}     Clear device debug flags\n"
 922       "+SET <dev> arg{,arg...}      Set device parameters\n"
 923       "+SET <unit> ENABLED          Enable unit\n"
 924       "+SET <unit> DISABLED         Disable unit\n"
 925       "+SET <unit> arg{,arg...}     Set unit parameters\n"
 926       "+HELP <dev> SET              Displays any device specific SET commands\n"
 927       " \n\n"
 928       " See the Omnibus documentation for a complete SET command reference.\n"
 929        /***************** 80 character line width template *************************/
 930 #define HLP_SHOW        "*Commands SHOW"
 931       "2SHOW\n"
 932       "+SH{OW} B{UILDINFO}               Show build-time compilation information\n"
 933       "+SH{OW} CL{OCKS}                  Show wall clock and timer information\n"
 934       "+SH{OW} C{ONFIGURATION}           Show simulator configuration\n"
 935       "+SH{OW} D{EFAULT_BASE_SYSTEM}     Show default base system script\n"
 936       "+SH{OW} DEV{ICES}                 Show devices\n"
 937       "+SH{OW} M{ODIFIERS}               Show SET commands for all devices\n"
 938       "+SH{OW} O{N}                      Show ON condition actions\n"
 939       "+SH{OW} P{ROM}                    Show CPU ID PROM initialization data\n"
 940       "+SH{OW} Q{UEUE}                   Show event queue\n"
 941       "+SH{OW} S{HOW}                    Show SHOW commands for all devices\n"
 942       "+SH{OW} T{IME}                    Show simulated timer\n"
 943       "+SH{OW} VE{RSION}                 Show simulator version\n"
 944       "+H{ELP} <dev> SHOW                Show device-specific SHOW commands\n"
 945       "+SH{OW} <dev> {arg,...}           Show device parameters\n"
 946       "+SH{OW} <dev> DEBUG               Show device debug flags\n"
 947       "+SH{OW} <dev> MODIFIERS           Show device modifiers\n"
 948       "+SH{OW} <dev> RADIX               Show device display radix\n"
 949       "+SH{OW} <dev> SHOW                Show device SHOW commands\n"
 950       "+SH{OW} <unit> {arg,...}          Show unit parameters\n\n"
 951       " See the Omnibus documentation for a complete SHOW command reference.\n\n"
 952 #define HLP_SHOW_CONFIG         "*Commands SHOW"
 953 #define HLP_SHOW_DEVICES        "*Commands SHOW"
 954 #define HLP_SHOW_FEATURES       "*Commands SHOW"
 955 #define HLP_SHOW_QUEUE          "*Commands SHOW"
 956 #define HLP_SHOW_TIME           "*Commands SHOW"
 957 #define HLP_SHOW_MODIFIERS      "*Commands SHOW"
 958 #define HLP_SHOW_NAMES          "*Commands SHOW"
 959 #define HLP_SHOW_SHOW           "*Commands SHOW"
 960 #define HLP_SHOW_VERSION        "*Commands SHOW"
 961 #define HLP_SHOW_BUILDINFO      "*Commands SHOW"
 962 #define HLP_SHOW_PROM           "*Commands SHOW"
 963 #define HLP_SHOW_DBS            "*Commands SHOW"
 964 #define HLP_SHOW_DEFAULT        "*Commands SHOW"
 965 #define HLP_SHOW_CONSOLE        "*Commands SHOW"
 966 #define HLP_SHOW_REMOTE         "*Commands SHOW"
 967 #define HLP_SHOW_BREAK          "*Commands SHOW"
 968 #define HLP_SHOW_LOG            "*Commands SHOW"
 969 #define HLP_SHOW_DEBUG          "*Commands SHOW"
 970 #define HLP_SHOW_CLOCKS         "*Commands SHOW"
 971 #define HLP_SHOW_ON             "*Commands SHOW"
 972 #define HLP_SHOW_SEND           "*Commands SHOW"
 973 #define HLP_SHOW_EXPECT         "*Commands SHOW"
 974 #define HLP_HELP                "*Commands HELP"
 975        /***************** 80 character line width template *************************/
 976       "2HELP\n"
 977       "+H{ELP}                      Show this message\n"
 978       "+H{ELP} <command>            Show help for command\n"
 979       "+H{ELP} <dev>                Show help for device\n"
 980       "+H{ELP} <dev> REGISTERS      Show help for device register variables\n"
 981       "+H{ELP} <dev> ATTACH         Show help for device specific ATTACH command\n"
 982       "+H{ELP} <dev> SET            Show help for device specific SET commands\n"
 983       "+H{ELP} <dev> SHOW           Show help for device specific SHOW commands\n"
 984       "+H{ELP} <dev> <command>      Show help for device specific <command> command\n"
 985        /***************** 80 character line width template *************************/
 986       "2Altering The Simulated Configuration\n"
 987       " The \"SET <device> DISABLED\" command removes a device from the configuration.\n"
 988       " A `DISABLED` device is invisible to running programs.  The device can still\n"
 989       " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\n\n"
 990       " The \"SET <device> ENABLED\" command restores a disabled device to a\n"
 991       " configuration.\n\n"
 992       " Most multi-unit devices allow units to be enabled or disabled:\n\n"
 993       "++SET <unit> ENABLED\n"
 994       "++SET <unit> DISABLED\n\n"
 995       " When a unit is disabled, it will not be displayed by SHOW DEVICE.\n\n"
 996        /***************** 80 character line width template *************************/
 997 #define HLP_DO          "*Commands Executing_Command_Files Processing_Command_Files"
 998       "2Executing Command Files\n"
 999       "3Processing Command Files\n"
1000       " The simulator can invoke another script file with the \"`DO`\" command:\n\n"
1001       "++DO <filename> {arguments...}       execute commands in specified file\n\n"
1002       " The \"`DO`\" command allows command files to contain substitutable\n"
1003       " arguments. The string \"`%%n`\", where \"`n`\" is a number\n"
1004       " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\n"
1005       " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\n"
1006       " The string \"`%%0`\" is replaced with \"<`filename`>\".\n The\n"
1007       " sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\n"
1008       " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\n"
1009       " be enclosed in matching single or double quotation marks.\n\n"
1010       " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\n"
1011       " deep.\n\n"
1012       "4Switches\n"
1013       "5`-v`\n\n"
1014       " If the switch \"`-v`\" is specified, commands in the command file are\n"
1015       " echoed *before* they are executed.\n\n"
1016       "5`-e`\n\n"
1017       " If the switch \"`-e`\" is specified, command processing (including nested\n"
1018       " command invocations) will be aborted if any command error is encountered.\n"
1019       " (A simulation stop **never** aborts processing; use `ASSERT` to catch\n"
1020       " unexpected stops.) Without this switch, all errors except `ASSERT` failures\n"
1021       " will be ignored, and command processing will continue.\n\n"
1022       "5`-o`\n\n"
1023       " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\n"
1024       " the calling command file will be inherited by the command file being\n"
1025       " invoked.\n"
1026       "5`-q`\n\n"
1027       " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\n"
1028       " enabled for the called command file, otherwise the *quiet mode* setting\n"
1029       " is inherited from the calling context.\n"
1030        /***************** 80 character line width template *************************/
1031 #define HLP_GOTO        "*Commands Executing_Command_Files GOTO"
1032       "3GOTO\n"
1033       " Commands in a command file execute in sequence until either an error\n"
1034       " trap occurs (when a command completes with an error status), or when an\n"
1035       " explicit request is made to start command execution elsewhere with\n"
1036       " the `GOTO` command:\n\n"
1037       "++GOTO <label>\n\n"
1038       " * Labels are lines in a command file which the first non-whitespace\n"
1039       " character is a \"`:`\".\n"
1040       " * The target of a `GOTO` is the first matching label in the current `DO`\n"
1041       " command file which is encountered.\n\n"
1042       " **Example**\n\n"
1043       " The following example illustrates usage of the `GOTO` command (by\n"
1044       " creating an infinite loop):\n\n"
1045       "++:Label\n"
1046       "++:: This is a loop.\n"
1047       "++GOTO Label\n\n"
1048 #define HLP_RETURN      "*Commands Executing_Command_Files RETURN"
1049        /***************** 80 character line width template *************************/
1050       "3RETURN\n"
1051       " The `RETURN` command causes the current procedure call to be restored to\n"
1052       " the calling context, possibly returning a specific return status.\n"
1053       " If no return status is specified, the return status from the last command\n"
1054       " executed will be returned.  The calling context may have `ON` traps defined\n"
1055       " which may redirect command flow in that context.\n\n"
1056       "++RETURN                 return from command file with last command status\n"
1057       "++RETURN {-Q} <status>   return from command file with specific status\n\n"
1058       " * The status return can be any numeric value or one of the standard SCPE_\n"
1059       " condition names.\n\n"
1060       " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\n"
1061       " status to be returned, but normal error status message printing to be\n"
1062       " suppressed.\n\n"
1063       " **Condition Names**\n\n"
1064       " The available standard SCPE_ condition names and their meanings are:\n\n"
1065       " | Name    | Meaning                         | Name    | Meaning                             |\n"
1066       " | ------- | --------------------------------| ------- | ----------------------------------- |\n"
1067       " | NXM     | Address space exceeded          | UNATT   | Unit not attached                   |\n"
1068       " | IOERR   | I/O error                       | CSUM    | Checksum error                      |\n"
1069       " | FMT     | Format error                    | NOATT   | Unit not attachable                 |\n"
1070       " | OPENERR | File open error                 | MEM     | Memory exhausted                    |\n"
1071       " | ARG     | Invalid argument                | STEP    | Step expired                        |\n"
1072       " | UNK     | Unknown command                 | RO      | Read only argument                  |\n"
1073       " | INCOMP  | Command not completed           | STOP    | Simulation stopped                  |\n"
1074       " | EXIT    | Goodbye                         | TTIERR  | Console input I/O error             |\n"
1075       " | TTOERR  | Console output I/O error        | EOF     | End of file                         |\n"
1076       " | REL     | Relocation error                | NOPARAM | No settable parameters              |\n"
1077       " | ALATT   | Unit already attached           | TIMER   | Hardware timer error                |\n"
1078       " | SIGERR  | Signal handler setup error      | TTYERR  | Console terminal setup error        |\n"
1079       " | NOFNC   | Command not allowed             | UDIS    | Unit disabled                       |\n"
1080       " | NORO    | Read only operation not allowed | INVSW   | Invalid switch                      |\n"
1081       " | MISVAL  | Missing value                   | 2FARG   | Too few arguments                   |\n"
1082       " | 2MARG   | Too many arguments              | NXDEV   | Non-existent device                 |\n"
1083       " | NXUN    | Non-existent unit               | NXREG   | Non-existent register               |\n"
1084       " | NXPAR   | Non-existent parameter          | NEST    | Nested DO command limit exceeded    |\n"
1085       " | IERR    | Internal error                  | MTRLNT  | Invalid magtape record length       |\n"
1086       " | LOST    | Console Telnet connection lost  | TTMO    | Console Telnet connection timed out |\n"
1087       " | STALL   | Console Telnet output stall     | AFAIL   | Assertion failed                    |\n"
1088       " | INVREM  | Invalid remote console command  |         |                                     |\n"
1089       "\n\n"
1090 #define HLP_SHIFT       "*Commands Executing_Command_Files Shift_Parameters"
1091       "3Shift Parameters\n"
1092       " Shift the command files positional parameters\n"
1093 #define HLP_CALL        "*Commands Executing_Command_Files Call_a_subroutine"
1094       "3Call a subroutine\n"
1095       " Control can be transferred to a labeled subroutine using `CALL`.\n\n"
1096       " **Example**\n\n"
1097       "++CALL routine\n"
1098       "++BYE\n"
1099       "++\n"
1100       "++:routine\n"
1101       "++ECHO routine called\n"
1102       "++RETURN\n\n"
1103 #define HLP_ON          "*Commands Executing_Command_Files ON"
1104       "3ON\n"
1105       " The `ON` command performs actions after a condition, or clears a condition.\n"
1106       "++ON <condition> <action>  Perform action after condition\n"
1107       "++ON <condition>           Clears action of specified condition\n"
1108 #define HLP_PROCEED     "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1109 #define HLP_IGNORE      "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1110        /***************** 80 character line width template *************************/
1111       "3PROCEED or IGNORE\n"
1112       " The `PROCEED` (or `IGNORE`) command does nothing.  It is potentially\n"
1113       " useful as a placeholder for any `ON` action condition that should be\n"
1114       " explicitly ignored, allowing command file execution to continue without\n"
1115       " taking any specific action.\n"
1116 #define HLP_ECHO        "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1117        /***************** 80 character line width template *************************/
1118       "3Displaying Arbitrary Text\n"
1119       " The `ECHO` command is a useful way of annotating command files.  `ECHO`\n"
1120       " prints out its arguments to the console (and to any applicable log file):\n\n"
1121       "++ECHO <string>      Output string to console\n\n"
1122       " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\n"
1123       " This may be used to provide spacing for console messages or log file\n"
1124       " output.\n"
1125        /***************** 80 character line width template *************************/
1126 #define HLP_ASSERT      "*Commands Executing_Command_Files Testing_Assertions"
1127       "3Testing Assertions\n"
1128       " The `ASSERT` command tests a simulator state condition and halts command\n"
1129       " file execution if the condition is false:\n\n"
1130       "++ASSERT <Simulator State Expressions>\n\n"
1131       " * If the indicated expression evaluates to false, the command completes\n"
1132       " with an `AFAIL` condition.  By default, when a command file encounters a\n"
1133       " command which returns the `AFAIL` condition, it will exit the running\n"
1134       " command file with the `AFAIL` status to the calling command file.  This\n"
1135       " behavior can be changed with the `ON` command as well as switches to the\n"
1136       " invoking `DO` command.\n\n"
1137       " **Examples**\n\n"
1138       " The command file below might be used to bootstrap a hypothetical system\n"
1139       " that halts after the initial load from disk. The `ASSERT` command can then\n"
1140       " be used to confirm that the load completed successfully by examining the\n"
1141       " CPU's \"`A`\" register for the expected value:\n\n"
1142       "++; Example INI file\n"
1143       "++BOOT\n"
1144       "++; A register contains error code; 0 = good boot\n"
1145       "++ASSERT A=0\n"
1146       "++RUN\n\n"
1147        /***************** 80 character line width template *************************/
1148       " * In the above example, if the \"`A`\" register is *not* `0`,\n"
1149       " the \"`ASSERT A=0`\" command will be displayed to the user, and the\n"
1150       " command file will be aborted with an \"`Assertion failed`\" message.\n"
1151       " Otherwise, the command file will continue to bring up the system.\n\n"
1152       " * See the **`IF`** command documentation for more information and details\n"
1153       " regarding simulator state expressions.\n\n"
1154 #define HLP_IF          "*Commands Executing_Command_Files Testing_Conditions"
1155       "3Testing Conditions\n"
1156       " The `IF` command tests a simulator state condition and executes additional\n"
1157       " commands if the condition is true:\n\n"
1158       "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\n\n"
1159       " **Examples**\n\n"
1160       " The command file below might be used to bootstrap a hypothetical system\n"
1161       " that halts after the initial load from disk. The `IF` command can then\n"
1162       " be used to confirm that the load completed successfully by examining the\n"
1163       " CPU's \"`A`\" register for an expected value:\n\n"
1164       "++; Example INI file\n"
1165       "++BOOT\n"
1166       "++; A register contains error code; 0 = good boot\n"
1167       "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\n"
1168       "++RUN\n\n"
1169        /***************** 80 character line width template *************************/
1170       " * In the above example, if the \"`A`\" register is *not* `0`, the\n"
1171       " message \"`Boot failed - Failure Code `\" will be displayed, the contents\n"
1172       " of the \"`A`\" register will be displayed, and the command file will be\n"
1173       " aborted with an \"`Assertion failed`\" message.  Otherwise, the command\n"
1174       " file will continue to bring up the system.\n"
1175       "4Conditional Expressions\n"
1176       " The `IF` and `ASSERT` commands evaluate the following two different forms\n"
1177       " of conditional expressions.\n\n"
1178       "5Simulator State Expressions\n"
1179       "  &nbsp;\n \n"
1180       " The values of simulator registers can be evaluated with:\n\n"
1181       "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n"
1182       " * If \"<`dev`>\" is not specified, `CPU` is assumed.  \"<`reg`>\" is a\n"
1183       " register belonging to the indicated device.\n"
1184       " * The \"<`addr`>\" is an address in the address space of the indicated\n"
1185       " device.\n"
1186       " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\n"
1187       " the same as those used for \"search specifiers\" by the `EXAMINE` and\n"
1188       " `DEPOSIT` commands.\n"
1189       " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\n"
1190       " not in the radix for the device when referencing a register; when an\n"
1191       " address is referenced the device radix is used as the default.\n\n"
1192       " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\n"
1193       " register value is first altered as indicated.  The result is then compared\n"
1194       " to the \"<`value`>\" via the \"<`conditional-op`>\".\n"
1195       " * * If the result is *true*, the command(s) are executed before proceeding\n"
1196       " to the next line in the command file.\n"
1197       " * * If the result is *false*, the next command in the command file is\n"
1198       " processed.\n\n"
1199       "5String Comparison Expressions\n"
1200       "  &nbsp;\n \n"
1201       " String Values can be compared with:\n\n"
1202       "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\n\n"
1203       " * The \"`-i`\" switch, if present, causes a comparison to be case\n"
1204       "   insensitive.\n"
1205       " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\n"
1206       "   values which may have environment variables substituted as desired.\n"
1207       " * The \"<`compare-op`>\" may be one of:\n\n"
1208       " |                |                        |\n"
1209       " | --------------:|:---------------------- |\n"
1210       " | \"**`==`**\"     |  equal                 |\n"
1211       " | \"**`EQU`**\"    |  equal                 |\n"
1212       " | \"**`!=`**\"     |  not equal             |\n"
1213       " | \"**`NEQ`**\"    |  not equal             |\n"
1214       " | \"**<**\"        |  less than             |\n"
1215       " | \"**`LSS`**\"    |  less than             |\n"
1216       " | \"**<=**\"       |  less than or equal    |\n"
1217       " | \"**`LEQ`**\"    |  less than or equal    |\n"
1218       " | \"**>**\"        |  greater than          |\n"
1219       " | \"**`GTR`**\"    |  greater than          |\n"
1220       " | \"**>=**\"       |  greater than or equal |\n"
1221       " | \"**`GEQ`**\"    |  greater than or equal |\n"
1222       " * **NOTE**: Comparisons are *generic*.  This means that if\n"
1223       " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\n"
1224       " digits, then the strings are converted to numbers and a numeric\n"
1225       " comparison is performed.  For example, the comparison\n"
1226       " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\n"
1227        /***************** 80 character line width template *************************/
1228 #define HLP_EXIT        "*Commands Exiting_the_Simulator"
1229       "2Exiting the Simulator\n"
1230       " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\n"
1231       " returning control to the host operating system.\n"
1232        /***************** 80 character line width template *************************/
1233 #define HLP_SPAWN       "*Commands Executing_System_Commands"
1234       "2Executing System Commands\n"
1235       " * The simulator can execute host operating system commands with\n"
1236       " the \"`!`\" (*spawn*) command.\n\n"
1237       " |                         |                                             |\n"
1238       " |:----------------------- |:------------------------------------------- |\n"
1239       " | \"**`!`**\"             | Spawn the hosts default command interpreter |\n"
1240       " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\n\n"
1241       " * **NOTE**: The *exit status* from the command which was executed is set\n"
1242       " as the *command completion status* for the \"`!`\" command.  This may\n"
1243       " influence any enabled `ON` condition traps.\n" ;
1244        /***************** 80 character line width template *************************/
1245 
1246 static CTAB cmd_table[] = {
1247     { "RESET",    &reset_cmd,  0,         HLP_RESET     },
1248     { "EXAMINE",  &exdep_cmd,  EX_E,      HLP_EXAMINE   },
1249     { "IEXAMINE", &exdep_cmd,  EX_E+EX_I, HLP_IEXAMINE  },
1250     { "DEPOSIT",  &exdep_cmd,  EX_D,      HLP_DEPOSIT   },
1251     { "IDEPOSIT", &exdep_cmd,  EX_D+EX_I, HLP_IDEPOSIT  },
1252     { "EVALUATE", &eval_cmd,   0,         HLP_EVALUATE  },
1253     { "RUN",      &run_cmd,    RU_RUN,    HLP_RUN,      NULL, &run_cmd_message },
1254     { "GO",       &run_cmd,    RU_GO,     HLP_GO,       NULL, &run_cmd_message },
1255     { "STEP",     &run_cmd,    RU_STEP,   HLP_STEP,     NULL, &run_cmd_message },
1256     { "NEXT",     &run_cmd,    RU_NEXT,   HLP_NEXT,     NULL, &run_cmd_message },
1257     { "CONTINUE", &run_cmd,    RU_CONT,   HLP_CONTINUE, NULL, &run_cmd_message },
1258     { "BOOT",     &run_cmd,    RU_BOOT,   HLP_BOOT,     NULL, &run_cmd_message },
1259     { "BREAK",    &brk_cmd,    SSH_ST,    HLP_BREAK     },
1260     { "NOBREAK",  &brk_cmd,    SSH_CL,    HLP_NOBREAK   },
1261     { "ATTACH",   &attach_cmd, 0,         HLP_ATTACH    },
1262     { "DETACH",   &detach_cmd, 0,         HLP_DETACH    },
1263     { "EXIT",     &exit_cmd,   0,         HLP_EXIT      },
1264     { "QUIT",     &exit_cmd,   0,         NULL          },
1265     { "BYE",      &exit_cmd,   0,         NULL          },
1266     { "SET",      &set_cmd,    0,         HLP_SET       },
1267     { "SHOW",     &show_cmd,   0,         HLP_SHOW      },
1268     { "DO",       &do_cmd,     1,         HLP_DO        },
1269     { "GOTO",     &goto_cmd,   1,         HLP_GOTO      },
1270     { "RETURN",   &return_cmd, 0,         HLP_RETURN    },
1271     { "SHIFT",    &shift_cmd,  0,         HLP_SHIFT     },
1272     { "CALL",     &call_cmd,   0,         HLP_CALL      },
1273     { "ON",       &on_cmd,     0,         HLP_ON        },
1274     { "IF",       &assert_cmd, 0,         HLP_IF        },
1275     { "PROCEED",  &noop_cmd,   0,         HLP_PROCEED   },
1276     { "IGNORE",   &noop_cmd,   0,         HLP_IGNORE    },
1277     { "ECHO",     &echo_cmd,   0,         HLP_ECHO      },
1278     { "ASSERT",   &assert_cmd, 1,         HLP_ASSERT    },
1279     { "SEND",     &send_cmd,   0          },            /* deprecated */
1280     { "EXPECT",   &expect_cmd, 1          },            /* deprecated */
1281     { "NOEXPECT", &expect_cmd, 0          },            /* deprecated */
1282     { "!",        &spawn_cmd,  0,         HLP_SPAWN     },
1283     { "HELP",     &help_cmd,   0,         HLP_HELP      },
1284     { NULL,       NULL,        0          }
1285     };
1286 
1287 static CTAB set_glob_tab[] = {
1288     { "CONSOLE",     &sim_set_console,        0      }, /* deprecated */
1289     { "REMOTE",      &sim_set_remote_console, 0      }, /* deprecated */
1290     { "BREAK",       &brk_cmd,                SSH_ST }, /* deprecated */
1291     { "NOBREAK",     &brk_cmd,                SSH_CL }, /* deprecated */
1292     { "TELNET",      &sim_set_telnet,         0      }, /* deprecated */
1293     { "NOTELNET",    &sim_set_notelnet,       0      }, /* deprecated */
1294     { "LOG",         &sim_set_logon,          0,     HLP_SET_LOG      },
1295     { "NOLOG",       &sim_set_logoff,         0,     HLP_SET_LOG      },
1296     { "DEBUG",       &sim_set_debon,          0,     HLP_SET_DEBUG    },
1297     { "NODEBUG",     &sim_set_deboff,         0,     HLP_SET_DEBUG    },
1298     { "ENVIRONMENT", &sim_set_environment,    1,     HLP_SET_ENVIRON  },
1299     { "ON",          &set_on,                 1,     HLP_SET_ON       },
1300     { "NOON",        &set_on,                 0,     HLP_SET_ON       },
1301     { "VERIFY",      &set_verify,             1,     HLP_SET_VERIFY   },
1302     { "VERBOSE",     &set_verify,             1,     HLP_SET_VERIFY   },
1303     { "NOVERIFY",    &set_verify,             0,     HLP_SET_VERIFY   },
1304     { "NOVERBOSE",   &set_verify,             0,     HLP_SET_VERIFY   },
1305     { "MESSAGE",     &set_message,            1,     HLP_SET_MESSAGE  },
1306     { "NOMESSAGE",   &set_message,            0,     HLP_SET_MESSAGE  },
1307     { "QUIET",       &set_quiet,              1,     HLP_SET_QUIET    },
1308     { "NOQUIET",     &set_quiet,              0,     HLP_SET_QUIET    },
1309     { "LOCALOPC",    &set_localopc,           1,     HLP_SET_LOCALOPC },
1310     { "NOLOCALOPC",  &set_localopc,           0,     HLP_SET_LOCALOPC },
1311     { "PROMPT",      &set_prompt,             0,     HLP_SET_PROMPT   },
1312     { NULL,          NULL,                    0      }
1313     };
1314 
1315 static C1TAB set_dev_tab[] = {
1316     { "OCTAL",    &set_dev_radix,   8  },
1317     { "DECIMAL",  &set_dev_radix,  10  },
1318     { "HEX",      &set_dev_radix,  16  },
1319     { "ENABLED",  &set_dev_enbdis,  1  },
1320     { "DISABLED", &set_dev_enbdis,  0  },
1321     { "DEBUG",    &set_dev_debug,   1  },
1322     { "NODEBUG",  &set_dev_debug,   0  },
1323     { NULL,       NULL,             0  }
1324     };
1325 
1326 static C1TAB set_unit_tab[] = {
1327     { "ENABLED",  &set_unit_enbdis, 1 },
1328     { "DISABLED", &set_unit_enbdis, 0 },
1329     { NULL,       NULL,             0 }
1330     };
1331 
1332 static SHTAB show_glob_tab[] = {
1333     { "CONFIGURATION",  &show_config,        0, HLP_SHOW_CONFIG    },
1334     { "DEFAULT_BASE_SYSTEM_SCRIPT",
1335            &show_default_base_system_script, 0, HLP_SHOW_DBS       },
1336     { "DEVICES",   &show_config,             1, HLP_SHOW_DEVICES   },
1337     { "FEATURES",  &show_config,             2, HLP_SHOW_FEATURES  },
1338     { "QUEUE",     &show_queue,              0, HLP_SHOW_QUEUE     },
1339     { "TIME",      &show_time,               0, HLP_SHOW_TIME      },
1340     { "MODIFIERS", &show_mod_names,          0, HLP_SHOW_MODIFIERS },
1341     { "NAMES",     &show_log_names,          0, HLP_SHOW_NAMES     },
1342     { "SHOW",      &show_show_commands,      0, HLP_SHOW_SHOW      },
1343     { "VERSION",   &show_version,            1, HLP_SHOW_VERSION   },
1344     { "BUILDINFO", &show_buildinfo,          1, HLP_SHOW_BUILDINFO },
1345     { "PROM",      &show_prom,               0, HLP_SHOW_PROM      },
1346     { "CONSOLE",   &sim_show_console,        0, HLP_SHOW_CONSOLE   },
1347     { "REMOTE",    &sim_show_remote_console, 0, HLP_SHOW_REMOTE    },
1348     { "BREAK",     &show_break,              0, HLP_SHOW_BREAK     },
1349     { "LOG",       &sim_show_log,            0, HLP_SHOW_LOG       },
1350     { "TELNET",    &sim_show_telnet,         0  },  /* deprecated */
1351     { "DEBUG",     &sim_show_debug,          0, HLP_SHOW_DEBUG     },
1352     { "CLOCKS",    &sim_show_timers,         0, HLP_SHOW_CLOCKS    },
1353     { "SEND",      &sim_show_send,           0, HLP_SHOW_SEND      },
1354     { "EXPECT",    &sim_show_expect,         0, HLP_SHOW_EXPECT    },
1355     { "ON",        &show_on,                 0, HLP_SHOW_ON        },
1356     { NULL,        NULL,                     0  }
1357     };
1358 
1359 static SHTAB show_dev_tab[] = {
1360     { "RADIX",     &show_dev_radix,         0 },
1361     { "DEBUG",     &show_dev_debug,         0 },
1362     { "MODIFIERS", &show_dev_modifiers,     0 },
1363     { "NAMES",     &show_dev_logicals,      0 },
1364     { "SHOW",      &show_dev_show_commands, 0 },
1365     { NULL,        NULL,                    0 }
1366     };
1367 
1368 static SHTAB show_unit_tab[] = {
1369     { NULL, NULL, 0 }
1370     };
1371 
1372 #if defined(_WIN32)
1373 static
1374 int setenv(const char *envname, const char *envval, int overwrite)
     /* [previous][next][first][last][top][bottom][index][help] */
1375 {
1376 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1377 int r;
1378 
1379 (void)sprintf(envstr, "%s=%s", envname, envval);
1380 r = _putenv(envstr);
1381 FREE(envstr);
1382 return r;
1383 }
1384 
1385 static
1386 int unsetenv(const char *envname)
     /* [previous][next][first][last][top][bottom][index][help] */
1387 {
1388 setenv(envname, "", 1);
1389 return 0;
1390 }
1391 #endif /* if defined(_WIN32) */
1392 
1393 #define XSTR_EMAXLEN 32767
1394 
1395 const char
1396 *xstrerror_l(int errnum)
     /* [previous][next][first][last][top][bottom][index][help] */
1397 {
1398   int saved = errno;
1399   const char *ret = NULL;
1400   static __thread char buf[XSTR_EMAXLEN];
1401 
1402 #if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1403     defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1404 # if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1405   if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1406 # else
1407   if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1408 # endif
1409 #else
1410 # if defined(__NetBSD__)
1411   locale_t loc = LC_GLOBAL_LOCALE;
1412 # else
1413   locale_t loc = uselocale((locale_t)0);
1414 # endif
1415   locale_t copy = loc;
1416   if (copy == LC_GLOBAL_LOCALE)
1417     copy = duplocale(copy);
1418 
1419   if (copy != (locale_t)0)
1420     {
1421       ret = strerror_l(errnum, copy); /*LINTOK: xstrerror_l*/
1422       if (loc == LC_GLOBAL_LOCALE)
1423         {
1424           freelocale(copy);
1425         }
1426     }
1427 #endif
1428 
1429   if (!ret)
1430     {
1431       (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1432       ret = buf;
1433     }
1434 
1435   errno = saved;
1436   return ret;
1437 }
1438 
1439 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1440 
1441 /* Check if running on Rosetta 2 */
1442 
1443 #if defined(__APPLE__)
1444 int processIsTranslated(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1445 {
1446     int ret = 0;
1447     size_t size = sizeof(ret);
1448     if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
1449         if (errno == ENOENT)
1450             return 0;
1451         return -1; }
1452     return ret;
1453 }
1454 #endif /* if defined(_APPLE_) */
1455 
1456 /* Substring removal hack */
1457 
1458 char *strremove(char *str, const char *sub)
     /* [previous][next][first][last][top][bottom][index][help] */
1459 {
1460     char *p, *q, *r;
1461     if (*sub && (q = r = strstr(str, sub)) != NULL) {
1462         size_t len = strlen(sub);
1463         while ((r = strstr(p = r + len, sub)) != NULL) {
1464             while (p < r)
1465                 *q++ = *p++;
1466         }
1467         while ((*q++ = *p++) != '\0')
1468             continue;
1469     }
1470     return str;
1471 }
1472 
1473 /* Trim whitespace */
1474 
1475 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
     /* [previous][next][first][last][top][bottom][index][help] */
1476 {
1477     while (*str_untrimmed != '\0') {
1478       if(!isspace((unsigned char)*str_untrimmed)) {
1479         *str_trimmed = (char)*str_untrimmed;
1480         str_trimmed++;
1481       }
1482       str_untrimmed++;
1483     }
1484     *str_trimmed = '\0';
1485 }
1486 
1487 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1488 void allowCores(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1489 {
1490   int ret;
1491   struct rlimit limit;
1492 # if defined(RLIMIT_CORE)
1493   ret = getrlimit(RLIMIT_CORE, &limit);
1494   (void)ret;
1495 #  if defined(TESTING)
1496   if (ret != 0)
1497     {
1498       sim_warn ("Failed to query core dump configuration.");
1499       return;
1500     }
1501 #  endif /* if defined(TESTING) */
1502   limit.rlim_cur = limit.rlim_max;
1503   ret = setrlimit(RLIMIT_CORE, &limit);
1504 #  if defined(TESTING)
1505   if (ret != 0)
1506     {
1507       sim_warn ("Failed to enable unlimited core dumps.");
1508       return;
1509     }
1510 #  endif /* if defined(TESTING) */
1511 # else
1512 #  if defined(TESTING)
1513   sim_warn ("Unable to query core dump configuration.");
1514 #  endif /* if defined(TESTING) */
1515 # endif /* if defined(RLIMIT_CORE) */
1516   return;
1517 }
1518 #endif
1519 
1520 #if defined(USE_DUMA)
1521 void CleanDUMA(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1522 {
1523   (void)fflush(stdout);
1524   DUMA_CHECKALL();
1525   (void)fflush(stderr);
1526 }
1527 # undef USE_DUMA
1528 # define USE_DUMA 1
1529 #endif /* if defined(USE_DUMA) */
1530 
1531 #if !defined(SIG_SETMASK)
1532 # undef USE_BACKTRACE
1533 #endif /* if !defined(SIG_SETMASK) */
1534 
1535 #if defined(PERF_STRIP)
1536 # undef USE_BACKTRACE
1537 #endif /* if defined(PERF_STRIP) */
1538 
1539 #if defined(USE_BACKTRACE)
1540 # include <backtrace.h>
1541 # include <backtrace-supported.h>
1542 # define BACKTRACE_SKIP 1
1543 # define BACKTRACE_MAIN "main"
1544 # undef USE_BACKTRACE
1545 # define USE_BACKTRACE 1
1546 #endif /* if defined(USE_BACKTRACE) */
1547 
1548 #if defined(BACKTRACE_SUPPORTED)
1549 # if defined(BACKTRACE_SUPPORTS_THREADS)
1550 #  if !(BACKTRACE_SUPPORTED)
1551 #   undef USE_BACKTRACE
1552 #  endif /* if !(BACKTRACE_SUPPORTED) */
1553 # else  /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1554 #  undef USE_BACKTRACE
1555 # endif /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1556 #else  /* if defined(BACKTRACE_SUPPORTED) */
1557 # undef USE_BACKTRACE
1558 #endif /* if defined(BACKTRACE_SUPPORTED) */
1559 
1560 #if defined(USE_BACKTRACE)
1561 # if defined(BACKTRACE_SUPPORTED)
1562 #  include "backtrace_func.c"
1563 # endif /* if defined(BACKTRACE_SUPPORTED) */
1564 #endif /* if defined(USE_BACKTRACE) */
1565 
1566 #if !defined(__CYGWIN__)
1567 # if !defined(__APPLE__)
1568 #  if !defined(_AIX)
1569 #   if !defined(__MINGW32__)
1570 #    if !defined(__MINGW64__)
1571 #     if !defined(CROSS_MINGW32)
1572 #      if !defined(CROSS_MINGW64)
1573 #       if !defined(_WIN32)
1574 #        if !defined(__HAIKU__)
1575 static int
1576 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1577 {
1578   (void)size;
1579   (void)data;
1580 
1581   if (strlen(info->dlpi_name) >= 2) {
1582       if (!dl_iterate_phdr_callback_called)
1583           (void)printf ("\r\n Loaded shared objects: ");
1584 
1585       dl_iterate_phdr_callback_called++;
1586       (void)printf ("%s ", info->dlpi_name);
1587   }
1588 
1589   return 0;
1590 }
1591 #        endif
1592 #       endif
1593 #      endif
1594 #     endif
1595 #    endif
1596 #   endif
1597 #  endif
1598 # endif
1599 #endif
1600 
1601 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1602 # if defined(_UCRT)
1603 #  define MINGW_CRT "UCRT"
1604 # else
1605 #  define MINGW_CRT "MSVCRT"
1606 # endif
1607 #endif
1608 
1609 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1610 struct UCRTVersion
1611 {
1612   uint16_t ProductVersion[4];
1613 };
1614 
1615 int
1616 GetUCRTVersion (struct UCRTVersion *ucrtversion)
     /* [previous][next][first][last][top][bottom][index][help] */
1617 {
1618 # ifdef _DEBUG
1619   static const wchar_t *DllName = L"ucrtbased.dll";
1620 # else
1621   static const wchar_t *DllName = L"ucrtbase.dll";
1622 # endif
1623 
1624   HMODULE ucrt = GetModuleHandleW (DllName);
1625   if (!ucrt)
1626     return GetLastError ();
1627 
1628   wchar_t path[MAX_PATH];
1629   if (!GetModuleFileNameW (ucrt, path, MAX_PATH))
1630     return GetLastError ();
1631 
1632   DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1633   if (!versionInfoSize)
1634     return GetLastError ();
1635 
1636   uint8_t versionInfo[versionInfoSize];
1637 
1638   if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1639     return GetLastError ();
1640 
1641   VS_FIXEDFILEINFO *fixedFileInfo;
1642   UINT fixedFileInfoSize;
1643   if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1644     return GetLastError ();
1645 
1646   memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1647 
1648   return 0;
1649 }
1650 #endif
1651 
1652 /* Main command loop */
1653 
1654 #if !defined(PERF_STRIP)
1655 int main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
1656 {
1657 char *cptr, *cptr2;
1658 char nbuf[PATH_MAX + 7];
1659 char cbuf[4*CBUFSIZE];
1660 char **targv = NULL;
1661 # if defined(USE_BACKTRACE)
1662 #  if defined(BACKTRACE_SUPPORTED)
1663 #   if defined(_INC_BACKTRACE_FUNC)
1664 bt_pid = (long)getpid();
1665 (void)bt_pid;
1666 #   endif /* if defined(_INC_BACKTRACE_FUNC) */
1667 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1668 # endif /* if defined(USE_BACKTRACE) */
1669 int32 i, sw;
1670 t_bool lookswitch;
1671 t_stat stat;
1672 
1673 # if defined(__MINGW32__)
1674 #  undef IS_WINDOWS
1675 #  define IS_WINDOWS 1
1676 #  if !defined(NEED_CONSOLE_SETUP)
1677 #   define NEED_CONSOLE_SETUP
1678 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1679 # endif /* if defined(__MINGW32__)*/
1680 
1681 # if defined(CROSS_MINGW32)
1682 #  undef IS_WINDOWS
1683 #  define IS_WINDOWS 1
1684 #  if !defined(NEED_CONSOLE_SETUP)
1685 #   define NEED_CONSOLE_SETUP
1686 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1687 # endif /* if defined(CROSS_MINGW32) */
1688 
1689 # if defined(__MINGW64__)
1690 #  undef IS_WINDOWS
1691 #  define IS_WINDOWS 1
1692 #  if !defined(NEED_CONSOLE_SETUP)
1693 #   define NEED_CONSOLE_SETUP
1694 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1695 # endif /* if defined(__MINGW64__) */
1696 
1697 # if defined(CROSS_MINGW64)
1698 #  undef IS_WINDOWS
1699 #  define IS_WINDOWS 1
1700 #  if !defined(NEED_CONSOLE_SETUP)
1701 #   define NEED_CONSOLE_SETUP
1702 #  endif /* if !defined(NEED_CONSOLE_SETUP */
1703 # endif /* if defined(CROSS_MINGW64) */
1704 
1705 # if defined(__CYGWIN__)
1706 #  if defined(IS_WINDOWS)
1707 #   undef IS_WINDOWS
1708 #  endif /* if defined(IS_WINDOWS) */
1709 # endif /* if defined(__CYGWIN__) */
1710 
1711 # if defined(USE_DUMA)
1712 #  if defined(DUMA_EXPLICIT_INIT)
1713 duma_init();
1714 (void)fflush(stderr);
1715 #  endif /* if defined(DUMA_EXPLICIT_INIT) */
1716 #  if defined(DUMA_MIN_ALIGNMENT)
1717 #   if DUMA_MIN_ALIGNMENT > 0
1718 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1719 #   endif /* if DUMA_MIN_ALIGNMENT > 0 */
1720 #  endif /* if defined(DUMA_MIN_ALIGNMENT) */
1721 DUMA_SET_FILL(0x2E);
1722 (void)fflush(stderr);
1723 (void)atexit(CleanDUMA);
1724 # endif /* if defined(USE_DUMA) */
1725 
1726 # if defined(USE_BACKTRACE)
1727 #  if defined(BACKTRACE_SUPPORTED)
1728 #   include "backtrace_main.c"
1729 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1730 # endif /* if defined(USE_BACKTRACE) */
1731 
1732 (void)setlocale(LC_ALL, "");
1733 
1734 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1735 #  if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1736 #   define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1737 #  endif /* if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) */
1738 # endif /* if defined(NEED_CONSOLE_SETUP) && defined(_WIN32) */
1739 
1740 # if defined(NEED_CONSOLE_SETUP)
1741 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1742 if (handle != INVALID_HANDLE_VALUE)
1743   {
1744     DWORD mode = 0;
1745     if (GetConsoleMode(handle, &mode))
1746       {
1747         mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1748         SetConsoleMode(handle, mode);
1749       }
1750   }
1751 puts ("\e[0m");
1752 # endif /* if defined(NEED_CONSOLE_SETUP) */
1753 
1754 # if defined(__HAIKU__)
1755 (void)disable_debugger(1);
1756 # endif /* if defined(__HAIKU__) */
1757 
1758 /* sanity checks */
1759 
1760 # if defined(__clang_analyzer__)
1761 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\n");
1762 return 1;
1763 # endif /* if defined(__clang_analyzer__) */
1764 
1765 if (argc == 0) {
1766     (void)fprintf (stderr, "Error: main() called directly!\n");
1767     return 1;
1768 }
1769 
1770 /* Enable unlimited core dumps */
1771 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1772 allowCores();
1773 # endif
1774 
1775 int testEndian = decContextTestEndian();
1776 if (testEndian != 0) {
1777   if (testEndian == 1) {
1778     (void)fprintf (stderr,
1779                    "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\n");
1780     return 1;
1781   }
1782   if (testEndian == -1) {
1783     (void)fprintf (stderr,
1784                    "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\n");
1785     return 1;
1786   }
1787   (void)fprintf (stderr,
1788                  "Error: Unable to determine system byte order; aborting.\n");
1789   return 1;
1790 }
1791 # if defined(NEED_128)
1792 test_math128();
1793 # endif /* if defined(NEED_128) */
1794 
1795 /* Make sure that argv has at least 10 elements and that it ends in a NULL pointer */
1796 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1797 if (!targv)
1798   {
1799     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1800                    __func__, __FILE__, __LINE__);
1801 # if defined(USE_BACKTRACE)
1802 #  if defined(SIGUSR2)
1803     (void)raise(SIGUSR2);
1804     /*NOTREACHED*/ /* unreachable */
1805 #  endif /* if defined(SIGUSR2) */
1806 # endif /* if defined(USE_BACKTRACE) */
1807     abort();
1808   }
1809 for (i=0; i<argc; i++)
1810     targv[i] = argv[i];
1811 argv = targv;
1812 
1813 /* setup defaults */
1814 set_prompt (0, "sim>");                                 /* start with set standard prompt */
1815 *cbuf = 0;                                              /* init arg buffer */
1816 sim_switches = 0;                                       /* init switches */
1817 lookswitch = TRUE;
1818 stdnul = fopen(NULL_DEVICE,"wb");
1819 
1820 /* process arguments */
1821 for (i = 1; i < argc; i++) {                            /* loop thru args */
1822     if (argv[i] == NULL)                                /* paranoia */
1823         continue;
1824 
1825 /* requested only version? */
1826     int onlyvers  = strcmp(argv[i], "--version");
1827     if (onlyvers == 0) {
1828 # if defined(VER_H_GIT_VERSION)
1829 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1830 #   if VER_H_GIT_PATCH_INT < 1
1831         (void)fprintf (stdout, "%s simulator %s\n",
1832                        sim_name, VER_H_GIT_VERSION);
1833 #   else
1834         (void)fprintf (stdout, "%s simulator %s+%s\n",
1835                        sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1836 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
1837 #  else
1838         (void)fprintf (stdout, "%s simulator %s\n",
1839                        sim_name, VER_H_GIT_VERSION);
1840 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
1841 # else
1842         (void)fprintf (stdout, "%s simulator\n", sim_name);
1843 # endif /* if defined(VER_H_GIT_VERSION) */
1844         FREE (targv);
1845         return 0;
1846     }
1847 
1848 /* requested short or long help? */
1849     int longhelp  = strcmp(argv[i], "--help");
1850     int shorthelp = strcmp(argv[i], "-h");
1851     if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
1852     if (longhelp == 0 || shorthelp == 0) {
1853 # if defined(VER_H_GIT_VERSION)
1854 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1855 #   if VER_H_GIT_PATCH_INT < 1
1856         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1857 #   else
1858         (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1859 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
1860 #  else
1861         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1862 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
1863 # else
1864         (void)fprintf (stdout, "%s simulator", sim_name);
1865 # endif /* if defined(VER_H_GIT_VERSION) */
1866         (void)fprintf (stdout, "\n");
1867         (void)fprintf (stdout, "\n USAGE: %s { [ SWITCHES ] ... } { < SCRIPT > }", argv[0]);
1868         (void)fprintf (stdout, "\n");
1869         (void)fprintf (stdout, "\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
1870         (void)fprintf (stdout, "\n");
1871         (void)fprintf (stdout, "\n Switches:");
1872         (void)fprintf (stdout, "\n  -e, -E            Aborts script processing immediately upon any error");
1873         (void)fprintf (stdout, "\n  -h, -H, --help    Prints only this informational help text and exit");
1874         (void)fprintf (stdout, "\n  -k, -K            Disables all support for exclusive file locking");
1875         (void)fprintf (stdout, "\n  -l, -L            Reports but ignores all exclusive file locking errors");
1876         (void)fprintf (stdout, "\n  -o, -O            Makes scripting ON conditions and actions inheritable");
1877         (void)fprintf (stdout, "\n  -q, -Q            Disables printing of non-fatal informational messages");
1878         (void)fprintf (stdout, "\n  -r, -R            Enables an unlinked ephemeral system state file");
1879         (void)fprintf (stdout, "\n  -s, -S            Enables a randomized persistent system state file");
1880         (void)fprintf (stdout, "\n  -t, -T            Disables fsync and creation/usage of system state file");
1881         (void)fprintf (stdout, "\n  -v, -V            Prints commands read from script file before execution");
1882         (void)fprintf (stdout, "\n  --version         Prints only the simulator identification text and exit");
1883         (void)fprintf (stdout, "\n");
1884 # if defined(USE_DUMA)
1885         nodist++;
1886 # endif /* if defined(USE_DUMA) */
1887 if (!nodist) {
1888         (void)fprintf (stdout, "\n This software is made available under the terms of the ICU License.");
1889         (void)fprintf (stdout, "\n For complete license details, see the LICENSE file included with the");
1890         (void)fprintf (stdout, "\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\n");
1891 }
1892 else
1893 {
1894         (void)fprintf (stdout, "\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
1895 }
1896         (void)fprintf (stdout, "\n");
1897         FREE(argv); //-V726
1898         return 0;
1899     }
1900     /* invalid arguments? */
1901     if ((*argv[i] == '-') && lookswitch) {              /* switch? */
1902         if ((sw = get_switches (argv[i])) < 0) {
1903             (void)fprintf (stderr, "Invalid switch \"%s\".\nTry \"%s -h\" for help.\n", argv[i], argv[0]);
1904             FREE(argv); //-V726
1905             return 1;
1906             }
1907         sim_switches = sim_switches | sw;
1908         }
1909     /* parse arguments */
1910     else {
1911         if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
1912             (void)fprintf (stderr, "Argument string too long\n");
1913             FREE(argv); //-V726
1914             return 1;
1915             }
1916         if (*cbuf)                                  /* concat args */
1917             strcat (cbuf, " ");
1918         (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s", //-V755
1919                       strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : ""); //-V755
1920         lookswitch = FALSE;                         /* no more switches */
1921         }
1922     }                                               /* end for */
1923 sim_nolock = sim_switches & SWMASK ('K');           /* -k means skip locking     */
1924 sim_iglock = sim_switches & SWMASK ('L');           /* -l means ignore locking   */
1925 sim_randompst = sim_switches & SWMASK ('S');        /* -s means persist random   */
1926 sim_quiet = sim_switches & SWMASK ('Q');            /* -q means quiet            */
1927 sim_randstate = sim_switches & SWMASK ('R');        /* -r means random sys_state */
1928 if (sim_randompst) sim_randstate = 1;               /*    and is implied with -s */
1929 sim_nostate = sim_switches & SWMASK ('T');          /* -t means no sys_state     */
1930 if (sim_nostate)                                    /*    and disables -s and -r */
1931   {
1932     sim_randompst = 0;
1933     sim_randstate = 0;
1934   }
1935 sim_on_inherit = sim_switches & SWMASK ('O');       /* -o means inherit on state */
1936 
1937 sim_init_sock ();                                   /* init socket capabilities */
1938 if (sim_dflt_dev == NULL)                           /* if no default */
1939     sim_dflt_dev = sim_devices[0];
1940 if (sim_vm_init != NULL)                            /* call once only */
1941     (*sim_vm_init)();
1942 sim_finit ();                                       /* init fio package */
1943 for (i = 0; cmd_table[i].name; i++) {
1944     size_t alias_len = strlen (cmd_table[i].name);
1945     char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
1946     if (!cmd_name)
1947       {
1948         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1949                        __func__, __FILE__, __LINE__);
1950 # if defined(USE_BACKTRACE)
1951 #  if defined(SIGUSR2)
1952         (void)raise(SIGUSR2);
1953         /*NOTREACHED*/ /* unreachable */
1954 #  endif /* if defined(SIGUSR2) */
1955 # endif /* if defined(USE_BACKTRACE) */
1956         abort();
1957       }
1958 
1959     strcpy (cmd_name, cmd_table[i].name);
1960     while (alias_len > 1) {
1961         cmd_name[alias_len] = '\0';                 /* Possible short form command name */
1962         --alias_len;
1963         if (getenv (cmd_name))                      /* Externally defined command alias? */
1964             unsetenv (cmd_name);                    /* Remove it to protect against possibly malicious aliases */
1965         }
1966     FREE (cmd_name);
1967     }
1968 stop_cpu = 0;
1969 sim_interval = 0;
1970 sim_time = sim_rtime = 0;
1971 noqueue_time = 0;
1972 sim_clock_queue = QUEUE_LIST_END;
1973 sim_is_running = 0;
1974 sim_log = NULL;
1975 if (sim_emax <= 0)
1976     sim_emax = 1;
1977 sim_timer_init ();
1978 
1979 if ((stat = sim_ttinit ()) != SCPE_OK) {
1980     (void)fprintf (stderr, "Fatal terminal initialization error\n%s\n",
1981                    sim_error_text (stat));
1982     FREE(argv); //-V726
1983     return 1;
1984     }
1985 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
1986     (void)fprintf (stderr, "Unable to allocate examine buffer\n");
1987     FREE(argv); //-V726
1988     return 1;
1989     };
1990 if ((stat = reset_all_p (0)) != SCPE_OK) {
1991     (void)fprintf (stderr, "Fatal simulator initialization error\n%s\n",
1992                    sim_error_text (stat));
1993     FREE(argv); //-V726
1994     return 1;
1995     }
1996 if ((stat = sim_brk_init ()) != SCPE_OK) {
1997     (void)fprintf (stderr, "Fatal breakpoint table initialization error\n%s\n",
1998                    sim_error_text (stat));
1999     FREE(argv); //-V726
2000     return 1;
2001     }
2002 if (!sim_quiet) {
2003     (void)printf ("\n");
2004     show_version (stdout, NULL, NULL, 0, NULL);
2005     }
2006 
2007 cptr = getenv("HOME");
2008 if (cptr == NULL) {
2009     cptr = getenv("HOMEPATH");
2010     cptr2 = getenv("HOMEDRIVE");
2011     }
2012 else
2013     cptr2 = NULL;
2014 (void)cptr2;
2015 if ( (*cbuf) && (strcmp(cbuf, "")) )                    /* cmd file arg? */
2016     stat = do_cmd (0, cbuf);                            /* proc cmd file */
2017 else if (*argv[0]) {                                    /* sim name arg? */
2018     char *np;                                           /* "path.ini" */
2019     nbuf[0] = '"';                                      /* starting " */
2020     stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;         /* proc default cmd file */
2021     if (stat == SCPE_OPENERR) {                         /* didn't exist/can't open? */
2022         np = strrchr (nbuf, '/');                       /* strip path and try again in cwd */
2023         if (np == NULL)
2024             np = strrchr (nbuf, '\\');                  /* windows path separator */
2025         if (np != NULL) {
2026             *np = '"';
2027             stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;   /* proc default cmd file */
2028             }
2029         }
2030     }
2031 
2032 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2033 
2034 if (sim_vm_exit != NULL)                                /* call once only */
2035     (*sim_vm_exit)();
2036 
2037 detach_all (0, TRUE);                                   /* close files */
2038 sim_set_deboff (0, NULL);                               /* close debug */
2039 sim_set_logoff (0, NULL);                               /* close log */
2040 sim_set_notelnet (0, NULL);                             /* close Telnet */
2041 sim_ttclose ();                                         /* close console */
2042 sim_cleanup_sock ();                                    /* cleanup sockets */
2043 fclose (stdnul);                                        /* close bit bucket file handle */
2044 FREE (targv);                                           /* release any argv copy that was made */
2045 FREE (sim_prompt);
2046 FREE (sim_eval);
2047 FREE (sim_internal_devices);
2048 FREE (sim_brk_tab);
2049 FREE (sim_staba.comp);
2050 FREE (sim_staba.mask);
2051 FREE (sim_stabr.comp);
2052 FREE (sim_stabr.mask);
2053 return 0;
2054 }
2055 #endif
2056 
2057 t_stat process_stdin_commands (t_stat stat, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
2058 {
2059 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2060 CONST char *cptr;
2061 t_stat stat_nomessage;
2062 CTAB *cmdp = NULL;
2063 
2064 stat = SCPE_BARE_STATUS(stat);                          /* remove possible flag */
2065 while (stat != SCPE_EXIT) {                             /* in case exit */
2066     if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))   /* pending action? */
2067         (void)printf ("%s%s\n", sim_prompt, cptr);      /* echo */
2068     else if (sim_vm_read != NULL) {                     /* sim routine? */
2069         (void)printf ("%s", sim_prompt);                /* prompt */
2070         cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2071         }
2072     else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prompt*/
2073     if (cptr == NULL) {                                 /* EOF? */
2074         if (sim_ttisatty()) continue;                   /* ignore tty EOF */
2075         else break;                                     /* otherwise exit */
2076         }
2077     if (*cptr == 0)                                     /* ignore blank */
2078         continue;
2079     sim_sub_args (cbuf, sizeof(cbuf), argv);
2080     if (sim_log)                                        /* log cmd */
2081         (void)fprintf (sim_log, "%s%s\n", sim_prompt, cptr);
2082     if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2083         (void)fprintf (sim_deb, "%s%s\n", sim_prompt, cptr);
2084     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
2085     sim_switches = 0;                                   /* init switches */
2086     if ((cmdp = find_cmd (gbuf)))                       /* lookup command */
2087         stat = cmdp->action (cmdp->arg, cptr);          /* if found, exec */
2088     else
2089         stat = SCPE_UNK;
2090     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
2091     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
2092     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
2093     sim_last_cmd_stat = stat;                           /* save command error status */
2094     if (!stat_nomessage) {                              /* displaying message status? */
2095         if (cmdp && (cmdp->message))                    /* special message handler? */
2096             cmdp->message (NULL, stat);                 /* let it deal with display */
2097         else
2098             if (stat >= SCPE_BASE)                      /* error? */
2099                 sim_printf ("%s\n", sim_error_text (stat));
2100         }
2101     if (sim_vm_post != NULL)
2102         (*sim_vm_post) (TRUE);
2103     }                                                   /* end while */
2104 return stat;
2105 }
2106 
2107 /* Set prompt routine */
2108 
2109 t_stat set_prompt (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2110 {
2111 char gbuf[CBUFSIZE], *gptr;
2112 
2113 if ((NULL == cptr) || (*cptr == '\0'))
2114     return SCPE_ARG;
2115 
2116 cptr = get_glyph_nc (cptr, gbuf, '"');                  /* get quote delimited token */
2117 if (gbuf[0] == '\0') {                                  /* Token started with quote */
2118     gbuf[sizeof (gbuf)-1] = '\0';
2119     strncpy (gbuf, cptr, sizeof (gbuf)-1);
2120     gptr = strchr (gbuf, '"');
2121     if (NULL != gptr)
2122         *gptr = '\0';
2123     }
2124 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);   /* nul terminator and trailing blank */
2125 if (!sim_prompt)
2126   {
2127     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2128                    __func__, __FILE__, __LINE__);
2129 #if defined(USE_BACKTRACE)
2130 # if defined(SIGUSR2)
2131     (void)raise(SIGUSR2);
2132     /*NOTREACHED*/ /* unreachable */
2133 # endif /* if defined(SIGUSR2) */
2134 #endif /* if defined(USE_BACKTRACE) */
2135     abort();
2136   }
2137 (void)sprintf (sim_prompt, "%s ", gbuf);
2138 return SCPE_OK;
2139 }
2140 
2141 /* Find command routine */
2142 
2143 CTAB *find_cmd (const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
2144 {
2145 CTAB *cmdp = NULL;
2146 
2147 if (sim_vm_cmd)                                         /* try ext commands */
2148     cmdp = find_ctab (sim_vm_cmd, gbuf);
2149 if (cmdp == NULL)                                       /* try regular cmds */
2150     cmdp = find_ctab (cmd_table, gbuf);
2151 return cmdp;
2152 }
2153 
2154 /* Exit command */
2155 
2156 t_stat exit_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2157 {
2158 return SCPE_EXIT;
2159 }
2160 
2161 /* Help command */
2162 
2163 /* Used when sorting a list of command names */
2164 static int _cmd_name_compare (const void *pa, const void *pb)
     /* [previous][next][first][last][top][bottom][index][help] */
2165 {
2166 CTAB * const *a = (CTAB * const *)pa;
2167 CTAB * const *b = (CTAB * const *)pb;
2168 
2169 return strcmp((*a)->name, (*b)->name);
2170 }
2171 
2172 void fprint_help (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
2173 {
2174 CTAB *cmdp;
2175 CTAB **hlp_cmdp = NULL;
2176 size_t cmd_cnt = 0;
2177 size_t cmd_size = 0;
2178 size_t max_cmdname_size = 0;
2179 size_t i, line_offset;
2180 
2181 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2182     if (cmdp->help) {
2183         if (cmd_cnt >= cmd_size) {
2184             cmd_size += 20;
2185             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2186             if (!hlp_cmdp)
2187               {
2188                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2189                                __func__, __FILE__, __LINE__);
2190 #if defined(USE_BACKTRACE)
2191 # if defined(SIGUSR2)
2192                 (void)raise(SIGUSR2);
2193                 /*NOTREACHED*/ /* unreachable */
2194 # endif /* if defined(SIGUSR2) */
2195 #endif /* if defined(USE_BACKTRACE) */
2196                 abort();
2197               }
2198             }
2199         hlp_cmdp[cmd_cnt] = cmdp;
2200         ++cmd_cnt;
2201         if (strlen(cmdp->name) > max_cmdname_size)
2202             max_cmdname_size = strlen(cmdp->name);
2203         }
2204     }
2205 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2206     if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2207         if (cmd_cnt >= cmd_size) {
2208             cmd_size += 20;
2209             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2210             if (!hlp_cmdp)
2211               {
2212                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2213                                __func__, __FILE__, __LINE__);
2214 #if defined(USE_BACKTRACE)
2215 # if defined(SIGUSR2)
2216                 (void)raise(SIGUSR2);
2217                 /*NOTREACHED*/ /* unreachable */
2218 # endif /* if defined(SIGUSR2) */
2219 #endif /* if defined(USE_BACKTRACE) */
2220                 abort();
2221               }
2222             }
2223         hlp_cmdp[cmd_cnt] = cmdp;
2224         ++cmd_cnt;
2225         if (strlen (cmdp->name) > max_cmdname_size)
2226             max_cmdname_size = strlen(cmdp->name);
2227         }
2228     }
2229 (void)fprintf (st, "HELP is available for the following commands:\n\n    ");
2230 if (hlp_cmdp)
2231   qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2232 line_offset = 4;
2233 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2234     fputs (hlp_cmdp[i]->name, st);
2235     line_offset += 5 + max_cmdname_size;
2236     if (line_offset + max_cmdname_size > 79) {
2237         line_offset = 4;
2238         (void)fprintf (st, "\n    ");
2239         }
2240     else
2241         (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2242     }
2243 FREE (hlp_cmdp);
2244 (void)fprintf (st, "\n");
2245 return;
2246 }
2247 
2248 static void fprint_header (FILE *st, t_bool *pdone, char *context)
     /* [previous][next][first][last][top][bottom][index][help] */
2249 {
2250 if (!*pdone)
2251     (void)fprintf (st, "%s", context);
2252 *pdone = TRUE;
2253 }
2254 
2255 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2256 {
2257 REG *rptr, *trptr;
2258 t_bool found = FALSE;
2259 t_bool all_unique = TRUE;
2260 size_t max_namelen = 0;
2261 DEVICE *tdptr;
2262 CONST char *tptr;
2263 char *namebuf;
2264 char rangebuf[32];
2265 
2266 if (dptr->registers)
2267     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2268         if (rptr->flags & REG_HIDDEN)
2269             continue;
2270         if (rptr->depth > 1)
2271             (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2272         else
2273             strcpy (rangebuf, "");
2274         if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2275             max_namelen = strlen(rptr->name) + strlen (rangebuf);
2276         found = TRUE;
2277         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2278         if ((trptr == NULL) || (tdptr != dptr))
2279             all_unique = FALSE;
2280         }
2281 if (!found) {
2282     if (!silent)
2283         (void)fprintf (st, "No register HELP available for the %s device\n",
2284                        dptr->name);
2285     }
2286 else {
2287     namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2288     if (!namebuf)
2289       {
2290         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2291                        __func__, __FILE__, __LINE__);
2292 #if defined(USE_BACKTRACE)
2293 # if defined(SIGUSR2)
2294         (void)raise(SIGUSR2);
2295         /*NOTREACHED*/ /* unreachable */
2296 # endif /* if defined(SIGUSR2) */
2297 #endif /* if defined(USE_BACKTRACE) */
2298         abort();
2299       }
2300     (void)fprintf (st, "\nThe %s device implements these registers:\n\n",
2301                    dptr->name);
2302     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2303         if (rptr->flags & REG_HIDDEN)
2304             continue;
2305         if (rptr->depth <= 1)
2306             (void)sprintf (namebuf, "%*s",
2307                            -((int)max_namelen),
2308                            rptr->name);
2309         else {
2310             (void)sprintf (rangebuf, "[%d:%d]",
2311                            0,
2312                            rptr->depth-1);
2313             (void)sprintf (namebuf, "%s%*s",
2314                            rptr->name,
2315                            (int)(strlen(rptr->name))-((int)max_namelen),
2316                            rangebuf);
2317             }
2318         if (all_unique) {
2319             (void)fprintf (st, "  %s %4d  %s\n",
2320                            namebuf,
2321                            rptr->width,
2322                            rptr->desc ? rptr->desc : "");
2323             continue;
2324             }
2325         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2326         if ((trptr == NULL) || (tdptr != dptr))
2327             (void)fprintf (st, "  %s %s %4d  %s\n",
2328                            dptr->name,
2329                            namebuf,
2330                            rptr->width,
2331                            rptr->desc ? rptr->desc : "");
2332         else
2333             (void)fprintf (st, "  %*s %s %4d  %s\n",
2334                            (int)strlen(dptr->name), "",
2335                            namebuf,
2336                            rptr->width,
2337                            rptr->desc ? rptr->desc : "");
2338         }
2339     FREE (namebuf);
2340     }
2341 }
2342 
2343 void fprint_reg_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2344 {
2345 fprint_reg_help_ex (st, dptr, TRUE);
2346 }
2347 
2348 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2349 {
2350 if (dptr->attach_help) {
2351     (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2352     dptr->attach_help (st, dptr, NULL, 0, NULL);
2353     return;
2354     }
2355 if (DEV_TYPE(dptr) == DEV_DISK) {
2356     (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2357     sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2358     return;
2359     }
2360 if (DEV_TYPE(dptr) == DEV_TAPE) {
2361     (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2362     sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2363     return;
2364     }
2365 if (!silent) {
2366     (void)fprintf (st, "No ATTACH help is available for the %s device\n", dptr->name);
2367     if (dptr->help)
2368         dptr->help (st, dptr, NULL, 0, NULL);
2369     }
2370 }
2371 
2372 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2373 {
2374 MTAB *mptr;
2375 DEBTAB *dep;
2376 t_bool found = FALSE;
2377 char buf[CBUFSIZE], header[CBUFSIZE];
2378 uint32 enabled_units = dptr->numunits;
2379 uint32 unit;
2380 
2381 (void)sprintf (header, "\n%s device SET commands:\n\n", dptr->name);
2382 for (unit=0; unit < dptr->numunits; unit++)
2383     if (dptr->units[unit].flags & UNIT_DIS)
2384         --enabled_units;
2385 if (dptr->modifiers) {
2386     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2387         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2388             continue;                                       /* skip unit only extended modifiers */
2389         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2390             continue;                                       /* skip unit only simple modifiers */
2391         if (mptr->mstring) {
2392             fprint_header (st, &found, header);
2393             (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2394                            mptr->mstring,
2395                            (strchr(mptr->mstring, '=')) \
2396                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2397                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2398                                ? "{=val}" : "")));
2399             if ((strlen (buf) < 30) || (NULL == mptr->help))
2400                 (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2401             else
2402                 (void)fprintf (st, "%s\n%-30s\t%s\n", buf, "", mptr->help);
2403             }
2404         }
2405     }
2406 if (dptr->flags & DEV_DISABLE) {
2407     fprint_header (st, &found, header);
2408     (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2409     (void)fprintf (st,  "%-30s\tEnables device %s\n", buf, sim_dname (dptr));
2410     (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2411     (void)fprintf (st,  "%-30s\tDisables device %s\n", buf, sim_dname (dptr));
2412     }
2413 if (dptr->flags & DEV_DEBUG) {
2414     fprint_header (st, &found, header);
2415     (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2416     (void)fprintf (st,  "%-30s\tEnables debugging for device %s\n", buf, sim_dname (dptr));
2417     (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2418     (void)fprintf (st,  "%-30s\tDisables debugging for device %s\n", buf, sim_dname (dptr));
2419     if (dptr->debflags) {
2420         t_bool desc_available = FALSE;
2421         strcpy (buf, "");
2422         (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2423         for (dep = dptr->debflags; dep->name != NULL; dep++) {
2424             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2425             desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2426             }
2427         (void)fprintf (st, "\n");
2428         (void)fprintf (st,  "%-30s\tEnables specific debugging for device %s\n", buf, sim_dname (dptr));
2429         (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2430         for (dep = dptr->debflags; dep->name != NULL; dep++)
2431             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2432         (void)fprintf (st, "\n");
2433         (void)fprintf (st,  "%-30s\tDisables specific debugging for device %s\n", buf, sim_dname (dptr));
2434         if (desc_available) {
2435             (void)fprintf (st, "\n*%s device DEBUG settings:\n", sim_dname (dptr));
2436             for (dep = dptr->debflags; dep->name != NULL; dep++)
2437                 (void)fprintf (st, "%4s%-12s%s\n", "", dep->name, dep->desc ? dep->desc : "");
2438             }
2439         }
2440     }
2441 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2442     if (dptr->units->flags & UNIT_DISABLE) {
2443         fprint_header (st, &found, header);
2444         (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2445         (void)fprintf (st,  "%-30s\tEnables unit %sn\n", buf, sim_dname (dptr));
2446         (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2447         (void)fprintf (st,  "%-30s\tDisables unit %sn\n", buf, sim_dname (dptr));
2448         }
2449     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2450         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2451             continue;                                           /* skip device only modifiers */
2452         if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2453             continue;                                           /* skip show only modifiers */
2454         if (mptr->mstring) {
2455             fprint_header (st, &found, header);
2456             (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2457                            (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2458                            (strchr(mptr->mstring, '=')) \
2459                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2460                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2461                                ? "{=val}" : "")));
2462             (void)fprintf (st, "%-30s\t%s\n", buf,
2463                            (strchr(mptr->mstring, '=')) \
2464                                ? "" : (mptr->help ? mptr->help : ""));
2465             }
2466         }
2467     }
2468 if (!found && !silent)
2469     (void)fprintf (st, "No SET help is available for the %s device\n", dptr->name);
2470 }
2471 
2472 void fprint_set_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2473 {
2474   fprint_set_help_ex (st, dptr, TRUE);
2475 }
2476 
2477 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2478 {
2479 MTAB *mptr;
2480 t_bool found = FALSE;
2481 char buf[CBUFSIZE], header[CBUFSIZE];
2482 uint32 enabled_units = dptr->numunits;
2483 uint32 unit;
2484 
2485 (void)sprintf (header, "\n%s device SHOW commands:\n\n", dptr->name);
2486 for (unit=0; unit < dptr->numunits; unit++)
2487     if (dptr->units[unit].flags & UNIT_DIS)
2488         --enabled_units;
2489 if (dptr->modifiers) {
2490     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2491         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2492             continue;                                       /* skip unit only extended modifiers */
2493         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2494             continue;                                       /* skip unit only simple modifiers */
2495         if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2496             continue;
2497         fprint_header (st, &found, header);
2498         (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2499                        mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2500         (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2501         }
2502     }
2503 if (dptr->flags & DEV_DEBUG) {
2504     fprint_header (st, &found, header);
2505     (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2506     (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\n", buf, sim_dname (dptr));
2507     }
2508 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2509     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2510         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2511             continue;                                           /* skip device only modifiers */
2512         if ((!mptr->disp) || (!mptr->pstring))
2513             continue;
2514         fprint_header (st, &found, header);
2515         (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2516                        (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2517                        MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2518         (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2519         }
2520     }
2521 if (!found && !silent)
2522     (void)fprintf (st, "No SHOW help is available for the %s device\n", dptr->name);
2523 }
2524 
2525 void fprint_show_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2526     {
2527     fprint_show_help_ex (st, dptr, TRUE);
2528     }
2529 
2530 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2531 {
2532 BRKTYPTAB *brkt = dptr->brk_types;
2533 char gbuf[CBUFSIZE];
2534 
2535 if (sim_brk_types == 0) {
2536     if ((dptr != sim_dflt_dev) && (!silent)) {
2537         (void)fprintf (st, "Breakpoints are not supported in the %s simulator\n", sim_name);
2538         if (dptr->help)
2539             dptr->help (st, dptr, NULL, 0, NULL);
2540         }
2541     return;
2542     }
2543 if (brkt == NULL) {
2544     int i;
2545 
2546     if (dptr == sim_dflt_dev) {
2547         if (sim_brk_types & ~sim_brk_dflt) {
2548             (void)fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2549             for (i=0; i<26; i++) {
2550                 if (sim_brk_types & (1<<i))
2551                     (void)fprintf (st, "  -%c\n", 'A'+i);
2552                 }
2553             }
2554         (void)fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2555         }
2556     return;
2557     }
2558 (void)fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2559 while (brkt->btyp) {
2560     (void)fprintf (st, "  %s     %s\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2561     ++brkt;
2562     }
2563 (void)fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2564 }
2565 
2566 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2567 {
2568 char gbuf[CBUFSIZE];
2569 CTAB *cmdp;
2570 
2571 if (*cptr) {
2572     (void)get_glyph (cptr, gbuf, 0);
2573     if ((cmdp = find_cmd (gbuf))) {
2574         if (cmdp->action == &exdep_cmd) {
2575             if (dptr->help) /* Shouldn't this pass cptr so the device knows which command invoked? */
2576                 return dptr->help (st, dptr, uptr, flag, cptr);
2577             else
2578                 (void)fprintf (st, "No HELP available for the %s %s command\n", cmdp->name, sim_dname(dptr));
2579             return SCPE_OK;
2580             }
2581         if (cmdp->action == &set_cmd) {
2582             fprint_set_help_ex (st, dptr, FALSE);
2583             return SCPE_OK;
2584             }
2585         if (cmdp->action == &show_cmd) {
2586             fprint_show_help_ex (st, dptr, FALSE);
2587             return SCPE_OK;
2588             }
2589         if (cmdp->action == &attach_cmd) {
2590             fprint_attach_help_ex (st, dptr, FALSE);
2591             return SCPE_OK;
2592             }
2593         if (cmdp->action == &brk_cmd) {
2594             fprint_brk_help_ex (st, dptr, FALSE);
2595             return SCPE_OK;
2596             }
2597         if (dptr->help)
2598             return dptr->help (st, dptr, uptr, flag, cptr);
2599         (void)fprintf (st, "No %s HELP is available for the %s device\n", cmdp->name, dptr->name);
2600         return SCPE_OK;
2601         }
2602     if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2603         fprint_reg_help_ex (st, dptr, FALSE);
2604         return SCPE_OK;
2605         }
2606     if (dptr->help)
2607         return dptr->help (st, dptr, uptr, flag, cptr);
2608     (void)fprintf (st, "No %s HELP is available for the %s device\n", gbuf, dptr->name);
2609     return SCPE_OK;
2610     }
2611 if (dptr->help) {
2612     return dptr->help (st, dptr, uptr, flag, cptr);
2613     }
2614 if (dptr->description)
2615     (void)fprintf (st, "%s %s HELP\n", dptr->description (dptr), dptr->name);
2616 else
2617     (void)fprintf (st, "%s HELP\n", dptr->name);
2618 fprint_set_help_ex    (st, dptr, TRUE);
2619 fprint_show_help_ex   (st, dptr, TRUE);
2620 fprint_attach_help_ex (st, dptr, TRUE);
2621 fprint_reg_help_ex    (st, dptr, TRUE);
2622 fprint_brk_help_ex    (st, dptr, TRUE);
2623 return SCPE_OK;
2624 }
2625 
2626 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
     /* [previous][next][first][last][top][bottom][index][help] */
2627 {
2628 switch (help[0]) {
2629     case '*':
2630         scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2631         if (sim_log)
2632             scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2633         break;
2634     default:
2635         fputs (help, stdout);
2636         if (sim_log)
2637             fputs (help, sim_log);
2638         break;
2639     }
2640 return SCPE_OK;
2641 }
2642 
2643 t_stat help_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2644 {
2645 char gbuf[CBUFSIZE];
2646 CTAB *cmdp;
2647 
2648 GET_SWITCHES (cptr);
2649 if (sim_switches & SWMASK ('F'))
2650     flag = flag | SCP_HELP_FLAT;
2651 if (*cptr) {
2652     cptr = get_glyph (cptr, gbuf, 0);
2653     if ((cmdp = find_cmd (gbuf))) {
2654         if (*cptr) {
2655             if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2656                 DEVICE *dptr;
2657                 UNIT *uptr;
2658                 t_stat r;
2659                 cptr = get_glyph (cptr, gbuf, 0);
2660                 dptr = find_unit (gbuf, &uptr);
2661                 if (dptr == NULL)
2662                     dptr = find_dev (gbuf);
2663                 if (dptr != NULL) {
2664                     r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2665                     if (sim_log)
2666                         help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2667                     return r;
2668                     }
2669                 if (cmdp->action == &set_cmd) { /* HELP SET xxx (not device or unit) */
2670                     /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
2671                     if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2672                          (cmdp->help))
2673                         return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2674                     }
2675                 else { /* HELP SHOW xxx (not device or unit) */
2676                     SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2677                     if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2678                         return SCPE_ARG;
2679                     return help_cmd_output (flag, shptr->help, NULL);
2680                     }
2681                 return SCPE_ARG;
2682                 }
2683             else
2684                 return SCPE_2MARG;
2685             }
2686         if (cmdp->help) {
2687             if (strcmp (cmdp->name, "HELP") == 0) {
2688 
2689 
2690 
2691 
2692 
2693 
2694 
2695 
2696 
2697 
2698 
2699 
2700 
2701 
2702 
2703 
2704 
2705 
2706 
2707 
2708 
2709 
2710 
2711 
2712 
2713 
2714 
2715 
2716 
2717 
2718 
2719 
2720 
2721 
2722                 }
2723             else {
2724                 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2725                     sim_dflt_dev && sim_dflt_dev->help) {
2726                         sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2727                         if (sim_log)
2728                             sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2729                     }
2730                 }
2731             help_cmd_output (flag, cmdp->help, cmdp->help_base);
2732             }
2733         else { /* no help so it is likely a command alias */
2734             CTAB *cmdpa;
2735             for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2736                 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2737                     sim_printf ("%s is an alias for the %s command:\n%s",
2738                                 cmdp->name, cmdpa->name, cmdpa->help);
2739                     break;
2740                     }
2741             if (cmdpa->name == NULL)                /* not found? */
2742                 sim_printf ("No help available for the %s command\n", cmdp->name);
2743             }
2744         }
2745     else {
2746         DEVICE *dptr;
2747         UNIT *uptr;
2748         t_stat r;
2749         dptr = find_unit (gbuf, &uptr);
2750         if (dptr == NULL) {
2751             dptr = find_dev (gbuf);
2752             if (dptr == NULL)
2753                 return SCPE_ARG;
2754             if (dptr->flags & DEV_DIS)
2755                 sim_printf ("Device %s is currently disabled\n", dptr->name);
2756             }
2757         r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2758         if (sim_log)
2759             help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2760         return r;
2761         }
2762     }
2763 else {
2764     fprint_help (stdout);
2765     if (sim_log)
2766         fprint_help (sim_log);
2767     }
2768 return SCPE_OK;
2769 }
2770 
2771 /* Spawn command */
2772 
2773 t_stat spawn_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2774 {
2775 t_stat status;
2776 if ((cptr == NULL) || (strlen (cptr) == 0))
2777     cptr = getenv("SHELL");
2778 if ((cptr == NULL) || (strlen (cptr) == 0))
2779     cptr = getenv("ComSpec");
2780 (void)fflush(stdout);                                   /* flush stdout */
2781 if (sim_log)                                            /* flush log if enabled */
2782     (void)fflush (sim_log);
2783 if (sim_deb)                                            /* flush debug if enabled */
2784     (void)fflush (sim_deb);
2785 status = system (cptr);
2786 
2787 return status;
2788 }
2789 
2790 /* Echo command */
2791 
2792 t_stat echo_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2793 {
2794 sim_printf ("%s\n", cptr);
2795 return SCPE_OK;
2796 }
2797 
2798 /*
2799  * DO command
2800  *
2801  * Note that SCPE_STEP ("Step expired") is considered a note and
2802  * not an error; it does not abort command execution when using -E.
2803  *
2804  * Inputs:
2805  *      flag    =   caller and nesting level indicator
2806  *      fcptr   =   filename and optional arguments, space-separated
2807  * Outputs:
2808  *      status  =   error status
2809  *
2810  * The "flag" input value indicates the source of the call, as follows:
2811  *
2812  *      -1      =   initialization file (no error if not found)
2813  *       0      =   command line file
2814  *       1      =   "DO" command
2815  *      >1      =   nested "DO" command
2816  */
2817 
2818 t_stat do_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2819 {
2820 return do_cmd_label (flag, fcptr, NULL);
2821 }
2822 
2823 static char *do_position(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2824 {
2825 static char cbuf[4*CBUFSIZE];
2826 
2827 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
2828                 sim_do_label[sim_do_depth] ? "::" : "",
2829                 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
2830                 sim_goto_line[sim_do_depth]);
2831 return cbuf;
2832 }
2833 
2834 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
     /* [previous][next][first][last][top][bottom][index][help] */
2835 {
2836 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
2837 CONST char *cptr;
2838 FILE *fpin;
2839 CTAB *cmdp = NULL;
2840 int32 echo, nargs, errabort, i;
2841 int32 saved_sim_do_echo = sim_do_echo,
2842       saved_sim_show_message = sim_show_message,
2843       saved_sim_on_inherit = sim_on_inherit,
2844       saved_sim_quiet = sim_quiet;
2845 t_bool staying;
2846 t_stat stat, stat_nomessage;
2847 
2848 stat = SCPE_OK;
2849 staying = TRUE;
2850 if (flag > 0)                                           /* need switches? */
2851     GET_SWITCHES (fcptr);                               /* get switches */
2852 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;    /* -v means echo */
2853 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet; /* -q means quiet */
2854 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit; /* -o means inherit ON condition actions */
2855 errabort = sim_switches & SWMASK ('E');                 /* -e means abort on error */
2856 
2857 abuf[sizeof(abuf)-1] = '\0';
2858 strncpy (abuf, fcptr, sizeof(abuf)-1);
2859 c = abuf;
2860 do_arg[10] = NULL;                                      /* make sure the argument list always ends with a NULL */
2861 for (nargs = 0; nargs < 10; ) {                         /* extract arguments */
2862     while (sim_isspace (*c))                            /* skip blanks */
2863         c++;
2864     if (*c == 0)                                        /* all done? */
2865         do_arg [nargs++] = NULL;                        /* null argument */
2866     else {
2867         if (*c == '\'' || *c == '"')                    /* quoted string? */
2868             quote = *c++;
2869         else quote = 0;
2870         do_arg[nargs++] = c;                            /* save start */
2871         while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
2872             c++;
2873         if (*c)                                         /* term at quote/spc */
2874             *c++ = 0;
2875         }
2876     }                                                   /* end for */
2877 
2878 if (do_arg [0] == NULL)                                 /* need at least 1 */
2879     return SCPE_2FARG;
2880 if ((fpin = fopen (do_arg[0], "r")) == NULL) {          /* file failed to open? */
2881     strcat (strcpy (cbuf, do_arg[0]), ".ini");          /* try again with .ini extension */
2882     if ((fpin = fopen (cbuf, "r")) == NULL) {           /* failed a second time? */
2883         if (flag == 0)                                  /* cmd line file? */
2884              (void)fprintf (stderr, "Can't open file %s\n", do_arg[0]);
2885         return SCPE_OPENERR;                            /* return failure */
2886         }
2887     }
2888 if (flag >= 0) {                                        /* Only bump nesting from command or nested */
2889     ++sim_do_depth;
2890     if (sim_on_inherit) {                               /* inherit ON condition actions? */
2891         sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1]; /* inherit On mode */
2892         for (i=0; i<SCPE_MAX_ERR; i++) {                /* replicate any on commands */
2893             if (sim_on_actions[sim_do_depth-1][i]) {
2894                 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
2895                 if (NULL == sim_on_actions[sim_do_depth][i]) {
2896                     while (--i >= 0) {
2897                         FREE(sim_on_actions[sim_do_depth][i]);
2898                         sim_on_actions[sim_do_depth][i] = NULL;
2899                         }
2900                     sim_on_check[sim_do_depth] = 0;
2901                     sim_brk_clract ();                  /* defang breakpoint actions */
2902                     --sim_do_depth;                     /* unwind nesting */
2903                     fclose(fpin);
2904                     return SCPE_MEM;
2905                     }
2906                 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
2907                 }
2908             }
2909         }
2910     }
2911 
2912 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);      /* stash away do file name for possible use by 'call' command */
2913 sim_do_label[sim_do_depth] = label;                     /* stash away do label for possible use in messages */
2914 sim_goto_line[sim_do_depth] = 0;
2915 if (label) {
2916     sim_gotofile = fpin;
2917     sim_do_echo = echo;
2918     stat = goto_cmd (0, label);
2919     if (stat != SCPE_OK) {
2920         strcpy(cbuf, "RETURN SCPE_ARG");
2921         cptr = get_glyph (cbuf, gbuf, 0);               /* get command glyph */
2922         cmdp = find_cmd (gbuf);                         /* return the errorStage things to the stat will be returned */
2923         goto Cleanup_Return;
2924         }
2925     }
2926 if (errabort)                                           /* -e flag? */
2927     set_on (1, NULL);                                   /* equivalent to ON ERROR RETURN */
2928 
2929 do {
2930     sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */
2931     if (!sim_do_ocptr[sim_do_depth]) {                  /* no pending action? */
2932         sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */
2933         sim_goto_line[sim_do_depth] += 1;
2934         }
2935     sim_sub_args (cbuf, sizeof(cbuf), do_arg);          /* substitute args */
2936     if (cptr == NULL) {                                 /* EOF? */
2937         stat = SCPE_OK;                                 /* set good return */
2938         break;
2939         }
2940     if (*cptr == 0)                                     /* ignore blank */
2941         continue;
2942     if (echo)                                           /* echo if -v */
2943         sim_printf("%s> %s\n", do_position(), cptr);
2944     if (*cptr == ':')                                   /* ignore label */
2945         continue;
2946     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
2947     sim_switches = 0;                                   /* init switches */
2948     sim_gotofile = fpin;
2949     sim_do_echo = echo;
2950     if ((cmdp = find_cmd (gbuf))) {                     /* lookup command */
2951         if (cmdp->action == &return_cmd)                /* RETURN command? */
2952             break;                                      /*    done! */
2953         if (cmdp->action == &do_cmd) {                  /* DO command? */
2954             if (sim_do_depth >= MAX_DO_NEST_LVL)        /* nest too deep? */
2955                 stat = SCPE_NEST;
2956             else
2957                 stat = do_cmd (sim_do_depth+1, cptr);   /* exec DO cmd */
2958             }
2959         else
2960             stat = cmdp->action (cmdp->arg, cptr);      /* exec other cmd */
2961         }
2962     else stat = SCPE_UNK;                               /* bad cmd given */
2963     echo = sim_do_echo;                                 /* Allow for SET VERIFY */
2964     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
2965     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
2966     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
2967     if (cmdp)
2968       if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
2969           ((cmdp->action != &return_cmd) &&
2970            (cmdp->action != &goto_cmd) &&
2971            (cmdp->action != &on_cmd) &&
2972            (cmdp->action != &echo_cmd)))
2973         sim_last_cmd_stat = stat;                       /* save command error status */
2974     switch (stat) {
2975         case SCPE_AFAIL:
2976             staying = (sim_on_check[sim_do_depth] &&        /* if trap action defined */
2977                        sim_on_actions[sim_do_depth][stat]); /* use it, otherwise exit */
2978             break;
2979         case SCPE_EXIT:
2980             staying = FALSE;
2981             break;
2982         case SCPE_OK:
2983         case SCPE_STEP:
2984             break;
2985         default:
2986             break;
2987         }
2988     if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&   /* error from cmd? */
2989         (stat != SCPE_STEP)) {
2990         if (!echo && !sim_quiet &&                      /* report if not echoing */
2991             !stat_nomessage &&                          /* and not suppressing messages */
2992             !(cmdp && cmdp->message)) {                 /* and not handling them specially */
2993             sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
2994             }
2995         }
2996     if (!stat_nomessage) {                              /* report error if not suppressed */
2997         if (cmdp && cmdp->message)                      /* special message handler */
2998             cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
2999         else
3000             if (stat >= SCPE_BASE)                      /* report error if not suppressed */
3001                 sim_printf ("%s\n", sim_error_text (stat));
3002         }
3003     if (stat == SCPE_EXPECT)                            /* EXPECT status is non actionable */
3004         stat = SCPE_OK;                                 /* so adjust it to SCPE_OK */
3005     if (staying &&
3006         (sim_on_check[sim_do_depth]) &&
3007         (stat != SCPE_OK) &&
3008         (stat != SCPE_STEP)) {
3009         if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3010             sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3011         else
3012             sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3013         }
3014     if (sim_vm_post != NULL)
3015         (*sim_vm_post) (TRUE);
3016     } while (staying);
3017 Cleanup_Return:
3018 if (fpin) //-V547
3019     fclose (fpin);                                      /* close file */
3020 sim_gotofile = NULL;
3021 if (flag >= 0) {
3022     sim_do_echo = saved_sim_do_echo;                    /* restore echo state we entered with */
3023     sim_show_message = saved_sim_show_message;          /* restore message display state we entered with */
3024     sim_on_inherit = saved_sim_on_inherit;              /* restore ON inheritance state we entered with */
3025     }
3026 sim_quiet = saved_sim_quiet;                            /* restore quiet mode we entered with */
3027 if ((flag >= 0) || (!sim_on_inherit)) {
3028     for (i=0; i<SCPE_MAX_ERR; i++) {                    /* release any on commands */
3029         FREE (sim_on_actions[sim_do_depth][i]);
3030         sim_on_actions[sim_do_depth][i] = NULL;
3031         }
3032     sim_on_check[sim_do_depth] = 0;                     /* clear on mode */
3033     }
3034 if (flag >= 0)
3035     --sim_do_depth;                                     /* unwind nesting */
3036 sim_brk_clract ();                                      /* defang breakpoint actions */
3037 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) { /* return command with argument? */
3038     sim_string_to_stat (cptr, &stat);
3039     sim_last_cmd_stat = stat;                           /* save explicit status as command error status */
3040     if (sim_switches & SWMASK ('Q'))
3041         stat |= SCPE_NOMESSAGE;                         /* suppress error message display (in caller) if requested */
3042     return stat;                                        /* return with explicit return status */
3043     }
3044 return stat | SCPE_NOMESSAGE;                           /* suppress message since we've already done that here */
3045 }
3046 
3047 /*
3048  * Substitute_args - replace %n tokens in 'instr' with the do command's arguments
3049  *                   and other environment variables
3050  *
3051  * Calling sequence
3052  * instr        =       input string
3053  * instr_size   =       sizeof input string buffer
3054  * do_arg[10]   =       arguments
3055  *
3056  * Token "%0" expands to the command file name.
3057  * Token %n (n being a single digit) expands to the n'th argument
3058  * Tonen %* expands to the whole set of arguments (%1 ... %9)
3059  *
3060  * The input sequence "\%" represents a literal "%", and "\\" represents a
3061  * literal "\".  All other character combinations are rendered literally.
3062  *
3063  * Omitted parameters result in null-string substitutions.
3064  *
3065  * A Tokens preceded and followed by % characters are expanded as environment
3066  * variables, and if one isn't found then can be one of several special
3067  * variables:
3068  *   %DATE%              yyyy-mm-dd
3069  *   %TIME%              hh:mm:ss
3070  *   %STIME%             hh_mm_ss
3071  *   %CTIME%             Www Mmm dd hh:mm:ss yyyy
3072  *   %STATUS%            Status value from the last command executed
3073  *   %TSTATUS%           The text form of the last status value
3074  *   %SIM_VERIFY%        The Verify/Verbose mode of the current Do command file
3075  *   %SIM_VERBOSE%       The Verify/Verbose mode of the current Do command file
3076  *   %SIM_QUIET%         The Quiet mode of the current Do command file
3077  *   %SIM_MESSAGE%       The message display status of the current Do command file
3078  * Environment variable lookups are done first with the precise name between
3079  * the % characters and if that fails, then the name between the % characters
3080  * is upcased and a lookup of that value is attempted.
3081 
3082  * The first Space delimited token on the line is extracted in uppercase and
3083  * then looked up as an environment variable.  If found it the value is
3084  * substituted for the original string before expanding everything else.  If
3085  * it is not found, then the original beginning token on the line is left
3086  * untouched.
3087  */
3088 
3089 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
     /* [previous][next][first][last][top][bottom][index][help] */
3090 {
3091 char gbuf[CBUFSIZE];
3092 char *ip = instr, *op, *oend, *tmpbuf;
3093 const char *ap;
3094 char rbuf[CBUFSIZE];
3095 int i;
3096 time_t now;
3097 struct tm *tmnow;
3098 
3099 time(&now);
3100 tmnow = localtime(&now);
3101 tmpbuf = (char *)malloc(instr_size);
3102 if (!tmpbuf)
3103   {
3104      (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3105                    __func__, __FILE__, __LINE__);
3106 #if defined(USE_BACKTRACE)
3107 # if defined(SIGUSR2)
3108      (void)raise(SIGUSR2);
3109      /*NOTREACHED*/ /* unreachable */
3110 # endif /* if defined(SIGUSR2) */
3111 #endif /* if defined(USE_BACKTRACE) */
3112      abort();
3113   }
3114 op = tmpbuf;
3115 oend = tmpbuf + instr_size - 2;
3116 while (sim_isspace (*ip))                               /* skip leading spaces */
3117     *op++ = *ip++;
3118 for (; *ip && (op < oend); ) {
3119     if ((ip [0] == '\\') &&                             /* literal escape? */
3120         ((ip [1] == '%') || (ip [1] == '\\'))) {        /*   and followed by '%' or '\'? */
3121         ip++;                                           /* skip '\' */
3122         *op++ = *ip++;                                  /* copy escaped char */
3123         }
3124     else
3125         if ((*ip == '%') &&
3126             (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */
3127             if ((ip[1] >= '0') && (ip[1] <= ('9'))) {   /* %n = sub */
3128                 ap = do_arg[ip[1] - '0'];
3129                 for (i=0; i<ip[1] - '0'; ++i)           /* make sure we're not past the list end */
3130                     if (do_arg[i] == NULL) {
3131                         ap = NULL;
3132                         break;
3133                         }
3134                 ip = ip + 2;
3135                 }
3136             else if (ip[1] == '*') {                    /* %1 ... %9 = sub */
3137                 (void)memset (rbuf, '\0', sizeof(rbuf));
3138                 ap = rbuf;
3139                 for (i=1; i<=9; ++i)
3140                     if (do_arg[i] == NULL)
3141                         break;
3142                     else
3143                         if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3144                             if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
3145                                 char quote = '"';
3146                                 if (strchr(do_arg[i], quote))
3147                                     quote = '\'';
3148                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3149                                               (i != 1) ? " " : "", quote,
3150                                               do_arg[i], quote);
3151                                 }
3152                             else
3153                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3154                                               (i != 1) ? " " : "", do_arg[i]);
3155                             }
3156                         else
3157                             break;
3158                 ip = ip + 2;
3159                 }
3160             else {                                      /* environment variable */
3161                 ap = NULL;
3162                 (void)get_glyph_nc (ip+1, gbuf, '%');   /* first try using the literal name */
3163                 ap = getenv(gbuf);
3164                 if (!ap) {
3165                     (void)get_glyph (ip+1, gbuf, '%');  /* now try using the upcased name */
3166                     ap = getenv(gbuf);
3167                     }
3168                 ip += 1 + strlen (gbuf);
3169                 if (*ip == '%') ++ip;
3170                 if (!ap) {
3171                     /* ISO 8601 format date/time info */
3172                     if (!strcmp ("DATE", gbuf)) {
3173                         (void)sprintf (rbuf, "%4d-%02d-%02d",
3174                                        tmnow->tm_year + 1900,
3175                                        tmnow->tm_mon  + 1,
3176                                        tmnow->tm_mday);
3177                         ap = rbuf;
3178                         }
3179                     else if (!strcmp ("TIME", gbuf)) {
3180                         (void)sprintf (rbuf, "%02d:%02d:%02d",
3181                                        tmnow->tm_hour,
3182                                        tmnow->tm_min,
3183                                        tmnow->tm_sec);
3184                         ap = rbuf;
3185                         }
3186                     else if (!strcmp ("DATETIME", gbuf)) {
3187                         (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3188                                        tmnow->tm_year + 1900,
3189                                        tmnow->tm_mon  + 1,
3190                                        tmnow->tm_mday,
3191                                        tmnow->tm_hour,
3192                                        tmnow->tm_min,
3193                                        tmnow->tm_sec);
3194                         ap = rbuf;
3195                         }
3196                     /* Locale oriented formatted date/time info */
3197                     if (!strcmp ("LDATE", gbuf)) {
3198                         strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3199                         ap = rbuf;
3200                         }
3201                     else if (!strcmp ("LTIME", gbuf)) {
3202                         strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3203                         ap = rbuf;
3204                         }
3205                     else if (!strcmp ("CTIME", gbuf)) {
3206                         strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3207                         ap = rbuf;
3208                         }
3209                     /* Separate Date/Time info */
3210                     else if (!strcmp ("DATE_YYYY", gbuf)) {/* Year (0000-9999) */
3211                         strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3212                         ap = rbuf;
3213                         }
3214                     else if (!strcmp ("DATE_YY", gbuf)) {/* Year (00-99) */
3215                         strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3216                         ap = rbuf;
3217                         }
3218                     else if (!strcmp ("DATE_YC", gbuf)) {/* Century (year/100) */
3219                         (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3220                         ap = rbuf;
3221                         }
3222                     else if ((!strcmp ("DATE_19XX_YY", gbuf)) || /* Year with same calendar */
3223                              (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3224                         int year = tmnow->tm_year + 1900;
3225                         int days = year - 2001;
3226                         int leaps = days/4 - days/100 + days/400;
3227                         int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3228                         int selector = ((days + leaps + 7) % 7) + lyear * 7;
3229                         static int years[] = {90, 91, 97, 98, 99, 94, 89,
3230                                               96, 80, 92, 76, 88, 72, 84};
3231                         int cal_year = years[selector];
3232 
3233                         if (!strcmp ("DATE_19XX_YY", gbuf))
3234                             (void)sprintf (rbuf, "%d", cal_year);        /* 2 digit year */
3235                         else
3236                             (void)sprintf (rbuf, "%d", cal_year + 1900); /* 4 digit year */
3237                         ap = rbuf;
3238                         }
3239                     else if (!strcmp ("DATE_MM", gbuf)) {/* Month number (01-12) */
3240                         strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3241                         ap = rbuf;
3242                         }
3243                     else if (!strcmp ("DATE_MMM", gbuf)) {/* Month number (01-12) */
3244                         strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3245                         ap = rbuf;
3246                         }
3247                     else if (!strcmp ("DATE_DD", gbuf)) {/* Day of Month (01-31) */
3248                         strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3249                         ap = rbuf;
3250                         }
3251                     else if (!strcmp ("DATE_D", gbuf)) { /* ISO 8601 weekday number (1-7) */
3252                         (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3253                         ap = rbuf;
3254                         }
3255                     else if ((!strcmp ("DATE_WW", gbuf)) ||   /* ISO 8601 week number (01-53) */
3256                              (!strcmp ("DATE_WYYYY", gbuf))) {/* ISO 8601 week year number (0000-9999) */
3257                         int iso_yr = tmnow->tm_year + 1900;
3258                         int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3259 
3260                         if (iso_wk == 0) {
3261                             iso_yr = iso_yr - 1;
3262                             tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);  /* Adjust for Leap Year (Correct thru 2099) */
3263                             iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3264                             }
3265                         else
3266                             if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3267                                 ++iso_yr;
3268                                 iso_wk = 1;
3269                                 }
3270                         if (!strcmp ("DATE_WW", gbuf))
3271                             (void)sprintf (rbuf, "%02d", iso_wk);
3272                         else
3273                             (void)sprintf (rbuf, "%04d", iso_yr);
3274                         ap = rbuf;
3275                         }
3276                     else if (!strcmp ("DATE_JJJ", gbuf)) {/* day of year (001-366) */
3277                         strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3278                         ap = rbuf;
3279                         }
3280                     else if (!strcmp ("TIME_HH", gbuf)) {/* Hour of day (00-23) */
3281                         strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3282                         ap = rbuf;
3283                         }
3284                     else if (!strcmp ("TIME_MM", gbuf)) {/* Minute of hour (00-59) */
3285                         strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3286                         ap = rbuf;
3287                         }
3288                     else if (!strcmp ("TIME_SS", gbuf)) {/* Second of minute (00-59) */
3289                         strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3290                         ap = rbuf;
3291                         }
3292                     else if (!strcmp ("STATUS", gbuf)) {
3293                         (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3294                         ap = rbuf;
3295                         }
3296                     else if (!strcmp ("TSTATUS", gbuf)) {
3297                         (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3298                         ap = rbuf;
3299                         }
3300                     else if (!strcmp ("SIM_VERIFY", gbuf)) {
3301                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3302                         ap = rbuf;
3303                         }
3304                     else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3305                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3306                         ap = rbuf;
3307                         }
3308                     else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3309                         (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3310                         ap = rbuf;
3311                         }
3312                     else if (!strcmp ("SIM_QUIET", gbuf)) {
3313                         (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3314                         ap = rbuf;
3315                         }
3316                     else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3317                         (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3318                         ap = rbuf;
3319                         }
3320                     else if (!strcmp ("HOSTID", gbuf)) {
3321 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__)
3322                         (void)sprintf (rbuf, "%ld", (long)gethostid());
3323 #else
3324                         (void)sprintf (rbuf, "00000000");
3325 #endif /* if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) */
3326                         ap = rbuf;
3327                         }
3328                     else if (!strcmp ("UID", gbuf)) {
3329 #if defined(HAVE_UNISTD)
3330                         (void)sprintf (rbuf, "%ld", (long)getuid());
3331 #else
3332                         (void)sprintf (rbuf, "0");
3333 #endif /* if defined(HAVE_UNISTD) */
3334                         ap = rbuf;
3335                         }
3336                     else if (!strcmp ("GID", gbuf)) {
3337 #if defined(HAVE_UNISTD)
3338                         (void)sprintf (rbuf, "%ld", (long)getgid());
3339 #else
3340                         (void)sprintf (rbuf, "0");
3341 #endif /* if defined(HAVE_UNISTD) */
3342                         ap = rbuf;
3343                         }
3344                     else if (!strcmp ("EUID", gbuf)) {
3345 #if defined(HAVE_UNISTD)
3346                         (void)sprintf (rbuf, "%ld", (long)geteuid());
3347 #else
3348                         (void)sprintf (rbuf, "0");
3349 #endif /* if defined(HAVE_UNISTD) */
3350                         ap = rbuf;
3351                         }
3352                     else if (!strcmp ("EGID", gbuf)) {
3353 #if defined(HAVE_UNISTD)
3354                         (void)sprintf (rbuf, "%ld", (long)getegid());
3355 #else
3356                         (void)sprintf (rbuf, "0");
3357 #endif /* if defined(HAVE_UNISTD) */
3358                         ap = rbuf;
3359                         }
3360                     else if (!strcmp ("PID", gbuf)) {
3361 #if defined(HAVE_UNISTD)
3362                         (void)sprintf (rbuf, "%ld", (long)getpid());
3363 #else
3364                         (void)sprintf (rbuf, "0");
3365 #endif /* if defined(HAVE_UNISTD) */
3366                         ap = rbuf;
3367                         }
3368                     else if (!strcmp ("PPID", gbuf)) {
3369 #if defined(HAVE_UNISTD)
3370                         (void)sprintf (rbuf, "%ld", (long)getppid());
3371 #else
3372                         (void)sprintf (rbuf, "0");
3373 #endif /* if defined(HAVE_UNISTD) */
3374                         ap = rbuf;
3375                         }
3376                     else if (!strcmp ("PGID", gbuf)) {
3377 #if defined(HAVE_UNISTD)
3378                         (void)sprintf (rbuf, "%ld", (long)getpgid(getpid()));
3379 #else
3380                         (void)sprintf (rbuf, "0");
3381 #endif /* if defined(HAVE_UNISTD) */
3382                         ap = rbuf;
3383                         }
3384                     else if (!strcmp ("SID", gbuf)) {
3385 #if defined(HAVE_UNISTD)
3386                         (void)sprintf (rbuf, "%ld", (long)getsid(getpid()));
3387 #else
3388                         (void)sprintf (rbuf, "0");
3389 #endif /* if defined(HAVE_UNISTD) */
3390                         ap = rbuf;
3391                         }
3392                     else if (!strcmp ("ENDIAN", gbuf)) {
3393 #if ( defined(DECLITEND) && DECLITEND == 1 )
3394                         (void)sprintf (rbuf, "LITTLE");
3395 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3396                         (void)sprintf (rbuf, "BIG");
3397 #else
3398                         (void)sprintf (rbuf, "UNKNOWN");
3399 #endif /* if ( defined(DECLITEND) && DECLITEND == 1 ) */
3400                         ap = rbuf;
3401                         }
3402                     else if (!strcmp("SIM_NAME", gbuf)) {
3403                         (void)sprintf (rbuf, "%s", sim_name);
3404                         ap = rbuf;
3405                         }
3406                     else if (!strcmp("SIM_VERSION", gbuf)) {
3407 #if defined(VER_H_GIT_VERSION)
3408                         (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3409 #else
3410                         (void)sprintf (rbuf, "UNKNOWN");
3411 #endif /* if defined(VER_H_GIT_VERSION) */
3412                         ap = rbuf;
3413                         }
3414                     else if (!strcmp("SIM_HASH", gbuf)) {
3415 #if defined(VER_H_GIT_HASH)
3416                         (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3417 #else
3418                         (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3419 #endif /* if defined(VER_H_GIT_HASH) */
3420                         ap = rbuf;
3421                         }
3422                     else if (!strcmp("SIM_RELT", gbuf)) {
3423 #if defined(VER_H_GIT_RELT)
3424                         (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3425 #else
3426                         (void)sprintf (rbuf, "X");
3427 #endif /* if defined(VER_H_GIT_RELT) */
3428                         ap = rbuf;
3429                         }
3430                     else if (!strcmp("SIM_DATE", gbuf)) {
3431 #if defined(VER_H_GIT_DATE)
3432                         (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3433 #else
3434                         (void)sprintf (rbuf, "UNKNOWN");
3435 #endif /* if defined(VER_H_GIT_DATE) */
3436                         ap = rbuf;
3437                         }
3438                     else if ( (!strcmp("CPUS", gbuf)) \
3439                       || (!strcmp("PROCESSORS", gbuf) ) ) {
3440 #if defined(LINUX_OS) && !defined(__ANDROID__)
3441                         (void)sprintf(rbuf, "%ld", (long)get_nprocs());
3442 #elif defined(__HAIKU__)
3443                         system_info hinfo;
3444                         get_system_info(&hinfo);
3445                         (void)sprintf (rbuf, "%llu",
3446                                        (long long unsigned int)hinfo.cpu_count);
3447 #else
3448                         (void)sprintf(rbuf, "1");
3449 #endif /* if defined(LINUX_OS) && !defined(__ANDROID__) */
3450                         ap = rbuf;
3451                         }
3452                     }
3453                 }
3454             if (ap) {                                   /* non-null arg? */
3455                 while (*ap && (op < oend))              /* copy the argument */
3456                     *op++ = *ap++;
3457                 }
3458             }
3459         else
3460             *op++ = *ip++;
3461     }
3462 *op = 0;                                                /* term buffer */
3463 strcpy (instr, tmpbuf);
3464 FREE (tmpbuf);
3465 return;
3466 }
3467 
3468 static
3469 int sim_cmp_string (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help] */
3470 {
3471 long int v1, v2;
3472 char *ep1, *ep2;
3473 
3474 v1 = strtol(s1+1, &ep1, 0);
3475 v2 = strtol(s2+1, &ep2, 0);
3476 if ((ep1 != s1 + strlen (s1) - 1) ||
3477     (ep2 != s2 + strlen (s2) - 1))
3478     return strcmp (s1, s2);
3479 if (v1 == v2)
3480     return 0;
3481 if (v1 < v2)
3482     return -1;
3483 return 1;
3484 }
3485 
3486 /* Assert command */
3487 
3488 t_stat assert_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3489 {
3490 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3491 CONST char *tptr, *gptr;
3492 REG *rptr;
3493 uint32 idx = 0;
3494 t_value val;
3495 t_stat r;
3496 t_bool Not = FALSE;
3497 t_bool result;
3498 t_addr addr = 0;
3499 t_stat reason;
3500 
3501 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3502                                                         /* get sw, default */
3503 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3504 # pragma diagnostic push
3505 # pragma diag_suppress = integer_sign_change
3506 #endif
3507 sim_stabr.boolop = sim_staba.boolop = -1;               /* no relational op dflt */
3508 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3509 # pragma diagnostic pop
3510 #endif
3511 if (*cptr == 0)                                         /* must be more */
3512     return SCPE_2FARG;
3513 tptr = get_glyph (cptr, gbuf, 0);                       /* get token */
3514 if (!strcmp (gbuf, "NOT")) {                            /* Conditional Inversion? */
3515     Not = TRUE;                                         /* remember that, and */
3516     cptr = (CONST char *)tptr;
3517     }
3518 if (*cptr == '"') {                                     /* quoted string comparison? */
3519     char op[CBUFSIZE];
3520     static struct {
3521         const char *op;
3522         int aval;
3523         int bval;
3524         t_bool invert;
3525         } *optr, compare_ops[] =
3526         {
3527             { "==",   0,  0, FALSE },
3528             { "EQU",  0,  0, FALSE },
3529             { "!=",   0,  0, TRUE  },
3530             { "NEQ",  0,  0, TRUE  },
3531             { "<",   -1, -1, FALSE },
3532             { "LSS", -1, -1, FALSE },
3533             { "<=",   0, -1, FALSE },
3534             { "LEQ",  0, -1, FALSE },
3535             { ">",    1,  1, FALSE },
3536             { "GTR",  1,  1, FALSE },
3537             { ">=",   0,  1, FALSE },
3538             { "GEQ",  0,  1, FALSE },
3539             { NULL }
3540         };
3541 
3542     tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3543                                                     /* get first string */
3544     if (!*tptr)
3545         return SCPE_2FARG;
3546     cptr += strlen (gbuf);
3547     while (sim_isspace (*cptr))                     /* skip spaces */
3548         ++cptr;
3549     (void)get_glyph (cptr, op, '"');
3550     for (optr = compare_ops; optr->op; optr++)
3551         if (0 == strcmp (op, optr->op))
3552             break;
3553     if (!optr->op)
3554         return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op);
3555     cptr += strlen (op);
3556     while (sim_isspace (*cptr))                         /* skip spaces */
3557         ++cptr;
3558     cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3559                                                         /* get second string */
3560     if (*cptr) {                                        /* more? */
3561         if (flag)                                       /* ASSERT has no more args */
3562             return SCPE_2MARG;
3563         }
3564     else {
3565         if (!flag)
3566             return SCPE_2FARG;                          /* IF needs actions! */
3567         }
3568     result = sim_cmp_string (gbuf, gbuf2);
3569     result = ((result == optr->aval) || (result == optr->bval));
3570     if (optr->invert)
3571         result = !result;
3572     }
3573 else {
3574     cptr = get_glyph (cptr, gbuf, 0);                   /* get register */
3575     rptr = find_reg (gbuf, &gptr, sim_dfdev);           /* parse register */
3576     if (rptr) {                                         /* got register? */
3577         if (*gptr == '[') {                             /* subscript? */
3578             if (rptr->depth <= 1)                       /* array register? */
3579                 return SCPE_ARG;
3580             idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */
3581             if ((gptr == tptr) || (*tptr++ != ']'))
3582                 return SCPE_ARG;
3583             gptr = tptr;                                /* update */
3584             }
3585         else idx = 0;                                   /* not array */
3586         if (idx >= rptr->depth)                         /* validate subscript */
3587             return SCPE_SUB;
3588         }
3589     else {                                              /* not reg, check for memory */
3590         if (sim_dfdev && sim_vm_parse_addr)             /* get addr */
3591             addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3592         else
3593             addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
3594         if (gbuf == gptr)                               /* error? */
3595             return SCPE_NXREG;
3596         }
3597     if (*gptr != 0)                                     /* more? must be search */
3598         (void)get_glyph (gptr, gbuf, 0);
3599     else {
3600         if (*cptr == 0)                                 /* must be more */
3601             return SCPE_2FARG;
3602         cptr = get_glyph (cptr, gbuf, 0);               /* get search cond */
3603         }
3604     if (*cptr) {                                        /* more? */
3605         if (flag)                                       /* ASSERT has no more args */
3606             return SCPE_2MARG;
3607         }
3608     else {
3609         if (!flag)
3610             return SCPE_2FARG;                          /* IF needs actions! */
3611         }
3612     if (rptr) {                                         /* Handle register case */
3613 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3614 # pragma diagnostic push
3615 # pragma diag_suppress = integer_sign_change
3616 #endif
3617         if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||  /* parse condition */
3618             (sim_stabr.boolop == -1))                   /* relational op reqd */
3619             return SCPE_MISVAL;
3620 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3621 # pragma diagnostic pop
3622 #endif
3623         val = get_rval (rptr, idx);                     /* get register value */
3624         result = test_search (&val, &sim_stabr);        /* test condition */
3625         }
3626     else {                                              /* Handle memory case */
3627 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3628 # pragma diagnostic push
3629 # pragma diag_suppress = integer_sign_change
3630 #endif
3631         if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||  /* parse condition */
3632             (sim_staba.boolop == -1))                    /* relational op reqd */
3633             return SCPE_MISVAL;
3634 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3635 # pragma diagnostic pop
3636 #endif
3637         reason = get_aval (addr, sim_dfdev, sim_dfunit);/* get data */
3638         if (reason != SCPE_OK)                          /* return if error */
3639             return reason;
3640         result = test_search (sim_eval, &sim_staba);    /* test condition */
3641         }
3642     }
3643 if (Not ^ result) {
3644     if (!flag)
3645         sim_brk_setact (cptr);                          /* set up IF actions */
3646     }
3647 else
3648     if (flag)
3649         return SCPE_AFAIL;                              /* return assert status */
3650 return SCPE_OK;
3651 }
3652 
3653 /* Send command */
3654 
3655 t_stat send_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3656 {
3657 char gbuf[CBUFSIZE];
3658 CONST char *tptr;
3659 uint8 dbuf[CBUFSIZE];
3660 uint32 dsize = 0;
3661 uint32 delay = 0;
3662 uint32 after = 0;
3663 t_stat r;
3664 SEND *snd = NULL;
3665 
3666 GET_SWITCHES (cptr);                                    /* get switches */
3667 tptr = get_glyph (cptr, gbuf, ',');
3668 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3669     r = tmxr_locate_line_send (gbuf, &snd);
3670     if (r != SCPE_OK)
3671       return r;
3672     cptr = tptr;
3673     tptr = get_glyph (tptr, gbuf, ',');
3674     }
3675 else
3676     snd = sim_cons_get_send ();
3677 
3678 while (*cptr) {
3679     if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3680         delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3681         if (r != SCPE_OK)
3682             return sim_messagef (SCPE_ARG, "Invalid Delay Value\n");
3683         cptr = tptr;
3684         tptr = get_glyph (cptr, gbuf, ',');
3685         continue;
3686         }
3687     if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3688         after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3689         if (r != SCPE_OK)
3690             return sim_messagef (SCPE_ARG, "Invalid After Value\n");
3691         cptr = tptr;
3692         tptr = get_glyph (cptr, gbuf, ',');
3693         continue;
3694         }
3695     if ((*cptr == '"') || (*cptr == '\''))
3696         break;
3697     return SCPE_ARG;
3698     }
3699 if (*cptr) {
3700     if ((*cptr != '"') && (*cptr != '\'')) //-V560
3701         return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
3702     cptr = get_glyph_quoted (cptr, gbuf, 0);
3703     if (*cptr != '\0')
3704         return SCPE_2MARG;                  /* No more arguments */
3705 
3706     if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3707         return sim_messagef (SCPE_ARG, "Invalid String\n");
3708     }
3709 if ((dsize == 0) && (delay == 0) && (after == 0))
3710     return SCPE_2FARG;
3711 return sim_send_input (snd, dbuf, dsize, after, delay);
3712 }
3713 
3714 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3715 {
3716 char gbuf[CBUFSIZE];
3717 CONST char *tptr;
3718 t_stat r;
3719 SEND *snd = NULL;
3720 
3721 tptr = get_glyph (cptr, gbuf, ',');
3722 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3723     r = tmxr_locate_line_send (gbuf, &snd);
3724     if (r != SCPE_OK)
3725       return r;
3726     cptr = tptr;
3727     }
3728 else
3729     snd = sim_cons_get_send ();
3730 if (*cptr)
3731     return SCPE_2MARG;
3732 return sim_show_send_input (st, snd);
3733 }
3734 
3735 t_stat expect_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3736 {
3737 char gbuf[CBUFSIZE];
3738 CONST char *tptr;
3739 EXPECT *exp = NULL;
3740 
3741 GET_SWITCHES (cptr);                                    /* get switches */
3742 tptr = get_glyph (cptr, gbuf, ',');
3743 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3744     cptr = tptr;
3745     }
3746 else
3747     exp = sim_cons_get_expect ();
3748 if (flag)
3749     return sim_set_expect (exp, cptr);
3750 else
3751     return sim_set_noexpect (exp, cptr);
3752 }
3753 
3754 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3755 {
3756 char gbuf[CBUFSIZE];
3757 CONST char *tptr;
3758 EXPECT *exp = NULL;
3759 t_stat r;
3760 
3761 tptr = get_glyph (cptr, gbuf, ',');
3762 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3763     r = tmxr_locate_line_expect (gbuf, &exp);
3764     if (r != SCPE_OK)
3765         return r;
3766     cptr = tptr;
3767     }
3768 else
3769     exp = sim_cons_get_expect ();
3770 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3771     return SCPE_ARG;            /* String must be quote delimited */
3772 tptr = get_glyph_quoted (cptr, gbuf, 0);
3773 if (*tptr != '\0')
3774     return SCPE_2MARG;          /* No more arguments */
3775 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3776     return SCPE_ARG;            /* String must be quote delimited */
3777 return sim_exp_show (st, exp, gbuf);
3778 }
3779 
3780 /* Goto command */
3781 
3782 t_stat goto_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3783 {
3784 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3785 const char *cptr;
3786 long fpos;
3787 int32 saved_do_echo = sim_do_echo;
3788 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3789 
3790 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
3791 (void)get_glyph (fcptr, gbuf1, 0);
3792 if ('\0' == gbuf1[0]) return SCPE_ARG;                  /* unspecified goto target */
3793 fpos = ftell(sim_gotofile);                             /* Save start position */
3794 rewind(sim_gotofile);                                   /* start search for label */
3795 sim_goto_line[sim_do_depth] = 0;                        /* reset line number */
3796 sim_do_echo = 0;                                        /* Don't echo while searching for label */
3797 while (1) {
3798     cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);/* get cmd line */
3799     if (cptr == NULL) break;                            /* exit on eof */
3800     sim_goto_line[sim_do_depth] += 1;                   /* record line number */
3801     if (*cptr == 0) continue;                           /* ignore blank */
3802     if (*cptr != ':') continue;                         /* ignore non-labels */
3803     ++cptr;                                             /* skip : */
3804     while (sim_isspace (*cptr)) ++cptr;                 /* skip blanks */
3805     cptr = get_glyph (cptr, gbuf, 0);                   /* get label glyph */
3806     if (0 == strcmp(gbuf, gbuf1)) {
3807         sim_brk_clract ();                              /* goto defangs current actions */
3808         sim_do_echo = saved_do_echo;                    /* restore echo mode */
3809         if (sim_do_echo)                                /* echo if -v */
3810             sim_printf("%s> %s\n", do_position(), cbuf);
3811         return SCPE_OK;
3812         }
3813     }
3814 sim_do_echo = saved_do_echo;                       /* restore echo mode         */
3815 fseek(sim_gotofile, fpos, SEEK_SET);               /* restore start position    */
3816 sim_goto_line[sim_do_depth] = saved_goto_line;     /* restore start line number */
3817 return SCPE_ARG;
3818 }
3819 
3820 /* Return command */
3821 
3822 /* The return command is invalid unless encountered in a do_cmd context,    */
3823 /* and in that context, it is handled as a special case inside of do_cmd()  */
3824 /* and not dispatched here, so if we get here a return has been issued from */
3825 /* interactive input */
3826 
3827 t_stat return_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3828 {
3829 return SCPE_UNK;                                 /* only valid inside of do_cmd */
3830 }
3831 
3832 /* Shift command */
3833 
3834 /* The shift command is invalid unless encountered in a do_cmd context,    */
3835 /* and in that context, it is handled as a special case inside of do_cmd() */
3836 /* and not dispatched here, so if we get here a shift has been issued from */
3837 /* interactive input (it is not valid interactively since it would have to */
3838 /* mess with the program's argv which is owned by the C runtime library    */
3839 
3840 t_stat shift_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3841 {
3842 return SCPE_UNK;                                 /* only valid inside of do_cmd */
3843 }
3844 
3845 /* Call command */
3846 
3847 /* The call command is invalid unless encountered in a do_cmd context,     */
3848 /* and in that context, it is handled as a special case inside of do_cmd() */
3849 /* and not dispatched here, so if we get here a call has been issued from  */
3850 /* interactive input                                                       */
3851 
3852 t_stat call_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3853 {
3854 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
3855 const char *cptr;
3856 
3857 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
3858 cptr = get_glyph (fcptr, gbuf, 0);
3859 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified goto target */
3860 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
3861 sim_switches |= SWMASK ('O');                           /* inherit ON state and actions */
3862 return do_cmd_label (flag, cbuf, gbuf);
3863 }
3864 
3865 /* On command */
3866 
3867 t_stat on_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3868 {
3869 char gbuf[CBUFSIZE];
3870 t_stat cond;
3871 
3872 cptr = get_glyph (cptr, gbuf, 0);
3873 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified condition */
3874 if (0 == strcmp("ERROR", gbuf))
3875     cond = 0;
3876 else
3877     if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
3878         return SCPE_ARG;
3879 if ((NULL == cptr) || ('\0' == *cptr)) {                /* Empty Action */
3880     FREE(sim_on_actions[sim_do_depth][cond]);           /* Clear existing condition */
3881     sim_on_actions[sim_do_depth][cond] = NULL; }
3882 else {
3883     sim_on_actions[sim_do_depth][cond] =
3884         (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
3885     if (!sim_on_actions[sim_do_depth][cond])
3886       {
3887         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3888                        __func__, __FILE__, __LINE__);
3889 #if defined(USE_BACKTRACE)
3890 # if defined(SIGUSR2)
3891         (void)raise(SIGUSR2);
3892         /*NOTREACHED*/ /* unreachable */
3893 # endif /* if defined(SIGUSR2) */
3894 #endif /* if defined(USE_BACKTRACE) */
3895         abort();
3896       }
3897     strcpy(sim_on_actions[sim_do_depth][cond], cptr);
3898     }
3899 return SCPE_OK;
3900 }
3901 
3902 /* noop command */
3903 
3904 t_stat noop_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3905 {
3906 if (cptr && (*cptr != 0))                               /* now eol? */
3907     return SCPE_2MARG;
3908 return SCPE_OK;                                         /* we're happy doing nothing */
3909 }
3910 
3911 /* Set on/noon routine */
3912 
3913 t_stat set_on (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3914 {
3915 if ((flag) && (cptr) && (*cptr)) {                      /* Set ON with arg */
3916     char gbuf[CBUFSIZE];
3917 
3918     cptr = get_glyph (cptr, gbuf, 0);                   /* get command glyph */
3919     if (((MATCH_CMD(gbuf,"INHERIT")) &&
3920          (MATCH_CMD(gbuf,"NOINHERIT"))) || //-V600
3921         (*cptr))
3922         return SCPE_2MARG;
3923     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT"))) //-V560
3924         sim_on_inherit = 1;
3925     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT"))) //-V560
3926         sim_on_inherit = 0;
3927     return SCPE_OK;
3928     }
3929 if (cptr && (*cptr != 0))                               /* now eol? */
3930     return SCPE_2MARG;
3931 sim_on_check[sim_do_depth] = flag;
3932 if ((sim_do_depth != 0) &&
3933     (NULL == sim_on_actions[sim_do_depth][0])) {        /* default handler set? */
3934     sim_on_actions[sim_do_depth][0] =                   /* No, so make "RETURN" */
3935         (char *)malloc(1+strlen("RETURN"));             /* be the default action */
3936     strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
3937     }
3938 if ((sim_do_depth != 0) &&
3939     (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {/* handler set for AFAIL? */
3940     sim_on_actions[sim_do_depth][SCPE_AFAIL] =          /* No, so make "RETURN" */
3941         (char *)malloc(1+strlen("RETURN"));             /* be the action */
3942     strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
3943     }
3944 return SCPE_OK;
3945 }
3946 
3947 /* Set verify/noverify routine */
3948 
3949 t_stat set_verify (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3950 {
3951 if (cptr && (*cptr != 0))                               /* now eol? */
3952     return SCPE_2MARG;
3953 if (flag == sim_do_echo)                                /* already set correctly? */
3954     return SCPE_OK;
3955 sim_do_echo = flag;
3956 return SCPE_OK;
3957 }
3958 
3959 /* Set message/nomessage routine */
3960 
3961 t_stat set_message (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3962 {
3963 if (cptr && (*cptr != 0))                               /* now eol? */
3964     return SCPE_2MARG;
3965 if (flag == sim_show_message)                           /* already set correctly? */
3966     return SCPE_OK;
3967 sim_show_message = flag;
3968 return SCPE_OK;
3969 }
3970 
3971 /* Set localopc/nolocalopc routine */
3972 
3973 t_stat set_localopc (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3974 {
3975 if (cptr && (*cptr != 0))                               /* now eol? */
3976     return SCPE_2MARG;
3977 if (flag == sim_localopc)                               /* already set correctly? */
3978     return SCPE_OK;
3979 sim_localopc = flag;
3980 return SCPE_OK;
3981 }
3982 /* Set quiet/noquiet routine */
3983 
3984 t_stat set_quiet (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3985 {
3986 if (cptr && (*cptr != 0))                               /* now eol? */
3987     return SCPE_2MARG;
3988 if (flag == sim_quiet)                                  /* already set correctly? */
3989     return SCPE_OK;
3990 sim_quiet = flag;
3991 return SCPE_OK;
3992 }
3993 
3994 /* Set environment routine */
3995 
3996 t_stat sim_set_environment (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3997 {
3998 char varname[CBUFSIZE];
3999 
4000 if ((NULL == cptr) || (*cptr == 0))                            /* now eol? */
4001     return SCPE_2FARG;
4002 cptr = get_glyph (cptr, varname, '=');                  /* get environment variable name */
4003 setenv(varname, cptr, 1);
4004 return SCPE_OK;
4005 }
4006 
4007 /* Set command */
4008 
4009 t_stat set_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4010 {
4011 uint32 lvl = 0;
4012 t_stat r;
4013 char gbuf[CBUFSIZE], *cvptr;
4014 CONST char *svptr;
4015 DEVICE *dptr;
4016 UNIT *uptr;
4017 MTAB *mptr;
4018 CTAB *gcmdp;
4019 C1TAB *ctbr = NULL, *glbr;
4020 
4021 GET_SWITCHES (cptr);                                    /* get switches */
4022 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
4023     return SCPE_2FARG;
4024 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get glob/dev/unit */
4025 
4026 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4027     uptr = dptr->units;                                 /* first unit */
4028     ctbr = set_dev_tab;                                 /* global table */
4029     lvl = MTAB_VDV;                                     /* device match */
4030     GET_SWITCHES (cptr);                                /* get more switches */
4031     }
4032 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4033     if (uptr == NULL)                                   /* invalid unit */
4034         return SCPE_NXUN;
4035     ctbr = set_unit_tab;                                /* global table */
4036     lvl = MTAB_VUN;                                     /* unit match */
4037     GET_SWITCHES (cptr);                                /* get more switches */
4038     }
4039 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {    /* global? */
4040     GET_SWITCHES (cptr);                                /* get more switches */
4041     return gcmdp->action (gcmdp->arg, cptr);            /* do the rest */
4042     }
4043 else {
4044     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4045         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4046             *cvptr++ = 0;
4047         for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4048             if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4049                 dptr = sim_dflt_dev;
4050                 cptr = svptr;
4051                 while (sim_isspace(*cptr))
4052                     ++cptr;
4053                 break;
4054                 }
4055             }
4056         }
4057     if (!dptr)
4058         return SCPE_NXDEV;                              /* no match */
4059     lvl = MTAB_VDV;                                     /* device match */
4060     uptr = dptr->units;                                 /* first unit */
4061     }
4062 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4063     return SCPE_2FARG;
4064 GET_SWITCHES (cptr);                                    /* get more switches */
4065 
4066 while (*cptr != 0) {                                    /* do all mods */
4067     cptr = get_glyph (svptr = cptr, gbuf, ',');         /* get modifier */
4068     if (0 == strcmp (gbuf, ";"))
4069         break;
4070     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4071         *cvptr++ = 0;
4072     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4073         if ((mptr->mstring) &&                          /* match string */
4074             (MATCH_CMD (gbuf, mptr->mstring) == 0)) {   /* matches option? */
4075             if (mptr->mask & MTAB_XTD) {                /* extended? */
4076                 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4077                     return SCPE_ARG;
4078                 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4079                     return SCPE_UDIS;                   /* unit disabled? */
4080                 if (mptr->valid) {                      /* validation rtn? */
4081                     if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4082                         svptr = get_glyph_quoted (svptr, gbuf, ',');
4083                         if ((cvptr = strchr (gbuf, '='))) {
4084                             *cvptr++ = 0;
4085                             cptr = svptr;
4086                             }
4087                         }
4088                     else {
4089                         if (cvptr && MODMASK(mptr,MTAB_NC)) {
4090                             (void)get_glyph_nc (svptr, gbuf, ',');
4091                             if ((cvptr = strchr (gbuf, '=')))
4092                                 *cvptr++ = 0;
4093                             }
4094                         }
4095                     r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4096                     if (r != SCPE_OK)
4097                         return r;
4098                     }
4099                 else if (!mptr->desc)                   /* value desc? */
4100                     break;
4101                 else if (cvptr)                         /* = value? */
4102                     return SCPE_ARG;
4103                 else *((int32 *) mptr->desc) = mptr->match;
4104                 }                                       /* end if xtd */
4105             else {                                      /* old style */
4106                 if (cvptr)                              /* = value? */
4107                     return SCPE_ARG;
4108                 if (uptr->flags & UNIT_DIS)             /* disabled? */
4109                      return SCPE_UDIS;
4110                 if ((mptr->valid) &&                    /* invalid? */
4111                     ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4112                     return r;
4113                 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4114                     (mptr->match & mptr->mask);         /* set new value */
4115                 }                                       /* end else xtd */
4116             break;                                      /* terminate for */
4117             }                                           /* end if match */
4118         }                                               /* end for */
4119     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4120         if ((glbr = find_c1tab (ctbr, gbuf))) {         /* global match? */
4121             r = glbr->action (dptr, uptr, glbr->arg, cvptr);    /* do global */
4122             if (r != SCPE_OK)
4123                 return r;
4124             }
4125         else if (!dptr->modifiers)                      /* no modifiers? */
4126             return SCPE_NOPARAM;
4127         else return SCPE_NXPAR;
4128         }                                               /* end if no mat */
4129     }                                                   /* end while */
4130 return SCPE_OK;                                         /* done all */
4131 }
4132 
4133 /* Match CTAB/CTAB1 name */
4134 
4135 CTAB *find_ctab (CTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4136 {
4137 if (!tab)
4138     return NULL;
4139 for (; tab->name != NULL; tab++) {
4140     if (MATCH_CMD (gbuf, tab->name) == 0)
4141         return tab;
4142     }
4143 return NULL;
4144 }
4145 
4146 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4147 {
4148 if (!tab)
4149     return NULL;
4150 for (; tab->name != NULL; tab++) {
4151     if (MATCH_CMD (gbuf, tab->name) == 0)
4152         return tab;
4153     }
4154 return NULL;
4155 }
4156 
4157 /* Set device data radix routine */
4158 
4159 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4160 {
4161 if (cptr)
4162     return SCPE_ARG;
4163 dptr->dradix = flag & 037;
4164 return SCPE_OK;
4165 }
4166 
4167 /* Set device enabled/disabled routine */
4168 
4169 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4170 {
4171 UNIT *up;
4172 uint32 i;
4173 
4174 if (cptr)
4175     return SCPE_ARG;
4176 if ((dptr->flags & DEV_DISABLE) == 0)                   /* allowed? */
4177     return SCPE_NOFNC;
4178 if (flag) {                                             /* enable? */
4179     if ((dptr->flags & DEV_DIS) == 0)                   /* already enb? ok */
4180         return SCPE_OK;
4181     dptr->flags = dptr->flags & ~DEV_DIS;               /* no, enable */
4182     }
4183 else {
4184     if (dptr->flags & DEV_DIS)                          /* already dsb? ok */
4185         return SCPE_OK;
4186     for (i = 0; i < dptr->numunits; i++) {              /* check units */
4187         up = (dptr->units) + i;                         /* att or active? */
4188         if ((up->flags & UNIT_ATT) || sim_is_active (up))
4189             return SCPE_NOFNC;                          /* can't do it */
4190         }
4191     dptr->flags = dptr->flags | DEV_DIS;                /* disable */
4192     }
4193 if (dptr->reset)                                        /* reset device */
4194     return dptr->reset (dptr);
4195 else return SCPE_OK;
4196 }
4197 
4198 /* Set unit enabled/disabled routine */
4199 
4200 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4201 {
4202 if (cptr)
4203     return SCPE_ARG;
4204 if (!(uptr->flags & UNIT_DISABLE))                      /* allowed? */
4205     return SCPE_NOFNC;
4206 if (flag)                                               /* enb? enable */
4207     uptr->flags = uptr->flags & ~UNIT_DIS;
4208 else {
4209     if ((uptr->flags & UNIT_ATT) ||                     /* dsb */
4210         sim_is_active (uptr))                           /* more tests */
4211         return SCPE_NOFNC;
4212     uptr->flags = uptr->flags | UNIT_DIS;               /* disable */
4213     }
4214 return SCPE_OK;
4215 }
4216 
4217 /* Set device debug enabled/disabled routine */
4218 
4219 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4220 {
4221 char gbuf[CBUFSIZE];
4222 DEBTAB *dep;
4223 
4224 if ((dptr->flags & DEV_DEBUG) == 0)
4225     return SCPE_NOFNC;
4226 if (cptr == NULL) {                                     /* no arguments? */
4227     dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;/* disable/enable w/o table */
4228     if (flag && dptr->debflags) {                       /* enable with table? */
4229         for (dep = dptr->debflags; dep->name != NULL; dep++)
4230             dptr->dctrl = dptr->dctrl | dep->mask;      /* set all */
4231         }
4232     return SCPE_OK;
4233     }
4234 if (dptr->debflags == NULL)                             /* must have table */
4235     return SCPE_ARG;
4236 while (*cptr) {
4237     cptr = get_glyph (cptr, gbuf, ';');                 /* get debug flag */
4238     for (dep = dptr->debflags; dep->name != NULL; dep++) {
4239         if (strcmp (dep->name, gbuf) == 0) {            /* match? */
4240             if (flag)
4241                 dptr->dctrl = dptr->dctrl | dep->mask;
4242             else dptr->dctrl = dptr->dctrl & ~dep->mask;
4243             break;
4244             }
4245         }                                               /* end for */
4246     if (dep->mask == 0)                                 /* no match? */
4247         return SCPE_ARG;
4248     }                                                   /* end while */
4249 return SCPE_OK;
4250 }
4251 
4252 /* Show command */
4253 
4254 t_stat show_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4255 {
4256 t_stat r = SCPE_IERR;
4257 
4258 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4259                                                         /* get sw, ofile */
4260 if (NULL == cptr)                                              /* error? */
4261     return r;
4262 if (sim_ofile) {                                        /* output file? */
4263     r = show_cmd_fi (sim_ofile, flag, cptr);            /* do show */
4264     fclose (sim_ofile);
4265     }
4266 else {
4267     r = show_cmd_fi (stdout, flag, cptr);               /* no, stdout, log */
4268     if (sim_log && (sim_log != stdout))
4269         show_cmd_fi (sim_log, flag, cptr);
4270     if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4271         show_cmd_fi (sim_deb, flag, cptr);
4272     }
4273 return r;
4274 }
4275 
4276 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4277 {
4278 uint32 lvl = 0xFFFFFFFF;
4279 char gbuf[CBUFSIZE], *cvptr;
4280 CONST char *svptr;
4281 DEVICE *dptr;
4282 UNIT *uptr;
4283 MTAB *mptr;
4284 SHTAB *shtb = NULL, *shptr;
4285 
4286 GET_SWITCHES (cptr);                                    /* get switches */
4287 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4288     return SCPE_2FARG;
4289 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get next glyph */
4290 
4291 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4292     uptr = dptr->units;                                 /* first unit */
4293     shtb = show_dev_tab;                                /* global table */
4294     lvl = MTAB_VDV;                                     /* device match */
4295     GET_SWITCHES (cptr);                                /* get more switches */
4296     }
4297 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4298     if (uptr == NULL)                                   /* invalid unit */
4299         return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\n", gbuf);
4300     if (uptr->flags & UNIT_DIS)                         /* disabled? */
4301         return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", gbuf);
4302     shtb = show_unit_tab;                               /* global table */
4303     lvl = MTAB_VUN;                                     /* unit match */
4304     GET_SWITCHES (cptr);                                /* get more switches */
4305     }
4306 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {  /* global? */
4307     GET_SWITCHES (cptr);                                /* get more switches */
4308     return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4309     }
4310 else {
4311     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4312         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4313             *cvptr++ = 0;
4314         for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4315             if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4316                  (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) || //-V600
4317                 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4318                 dptr = sim_dflt_dev;
4319                 lvl = MTAB_VDV;                         /* device match */
4320                 cptr = svptr;
4321                 while (sim_isspace(*cptr))
4322                     ++cptr;
4323                 break;
4324                 }
4325             }
4326         }
4327     if (!dptr) {
4328         if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))  /* global match? */
4329             return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4330         else
4331             return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf);/* no match */
4332         }
4333     }
4334 
4335 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) { /* now eol? */
4336     return (lvl == MTAB_VDV)?
4337         show_device (ofile, dptr, 0):
4338         show_unit (ofile, dptr, uptr, -1);
4339     }
4340 GET_SWITCHES (cptr);                                    /* get more switches */
4341 
4342 while (*cptr != 0) {                                    /* do all mods */
4343     cptr = get_glyph (cptr, gbuf, ',');                 /* get modifier */
4344     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4345         *cvptr++ = 0;
4346     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4347         if (((mptr->mask & MTAB_XTD)?                   /* right level? */
4348             ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4349             ((mptr->disp && mptr->pstring &&            /* named disp? */
4350             (MATCH_CMD (gbuf, mptr->pstring) == 0))
4351             )) {
4352             if (cvptr && !MODMASK(mptr,MTAB_SHP))
4353                 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\n", gbuf, cvptr);
4354             show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4355             break;
4356             }                                           /* end if */
4357         }                                               /* end for */
4358     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4359         if (shtb && (shptr = find_shtab (shtb, gbuf))) {/* global match? */
4360             t_stat r;
4361 
4362             r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4363             if (r != SCPE_OK)
4364                 return r;
4365             }
4366         else {
4367             if (!dptr->modifiers)                       /* no modifiers? */
4368                 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\n", dptr->name);
4369             else
4370                 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\n", gbuf);
4371             }
4372         }                                               /* end if */
4373     }                                                   /* end while */
4374 return SCPE_OK;
4375 }
4376 
4377 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4378 {
4379 if (!tab)
4380     return NULL;
4381 for (; tab->name != NULL; tab++) {
4382     if (MATCH_CMD (gbuf, tab->name) == 0)
4383         return tab;
4384     }
4385 return NULL;
4386 }
4387 
4388 /* Show device and unit */
4389 
4390 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4391 {
4392 uint32 j, udbl, ucnt;
4393 UNIT *uptr;
4394 int32 toks = 0;
4395 
4396 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4397 (void)fprintf (st, "%s", sim_dname (dptr));                   /* print dev name */
4398 if ((flag == 2) && dptr->description) {
4399     (void)fprintf (st, "\t%s\n", dptr->description(dptr));
4400     }
4401 else {
4402     if ((sim_switches & SWMASK ('D')) && dptr->description)
4403         (void)fprintf (st, "\t%s\n", dptr->description(dptr));
4404     }
4405 if (qdisable (dptr)) {                                  /* disabled? */
4406     (void)fprintf (st, "\tdisabled\n");
4407     return SCPE_OK;
4408     }
4409 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {    /* count units */
4410     uptr = dptr->units + j;
4411     if (!(uptr->flags & UNIT_DIS))                      /* count enabled units */
4412         ucnt++;
4413     else if (uptr->flags & UNIT_DISABLE)
4414         udbl++;                                         /* count user-disabled */
4415     }
4416 //show_all_mods (st, dptr, dptr->units, MTAB_VDV, &toks); /* show dev mods */
4417 if (dptr->numunits == 0) {
4418     if (toks) //-V547
4419         (void)fprintf (st, "\n");
4420     }
4421 else {
4422     if (ucnt == 0) {
4423         fprint_sep (st, &toks);
4424         (void)fprintf (st, "all units disabled\n");
4425         }
4426     else if ((ucnt + udbl) == 1) {
4427         fprint_sep (st, &toks);
4428         (void)fprintf (st, " 1 unit\n");
4429         }
4430     else if ((ucnt > 1) || (udbl > 0)) {
4431         fprint_sep (st, &toks);
4432         (void)fprintf (st, "%2.d units\n", ucnt + udbl);
4433         }
4434     else
4435         if ((flag != 2) || !dptr->description || toks)
4436             (void)fprintf (st, "\n");
4437     toks = 0;
4438     }
4439 if (flag)                                               /* dev only? */
4440     return SCPE_OK;
4441 for (j = 0; j < dptr->numunits; j++) {                  /* loop thru units */
4442     uptr = dptr->units + j;
4443     if ((uptr->flags & UNIT_DIS) == 0)
4444         show_unit (st, dptr, uptr, ucnt + udbl);
4445     }
4446 }
4447 return SCPE_OK;
4448 }
4449 
4450 void fprint_sep (FILE *st, int32 *tokens)
     /* [previous][next][first][last][top][bottom][index][help] */
4451 {
4452 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4453 *tokens += 1;
4454 }
4455 
4456 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4457 {
4458 int32 u = (int32)(uptr - dptr->units);
4459 int32 toks = 0;
4460 
4461 if (flag > 1)
4462     (void)fprintf (st, "   %s%d \n", sim_dname (dptr), u);
4463 else if (flag < 0)
4464     (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4465 if (uptr->flags & UNIT_ATT) {
4466     fprint_sep (st, &toks);
4467     (void)fprintf (st, "status   : attached to %s", uptr->filename);
4468     if (uptr->flags & UNIT_RO)
4469         (void)fprintf (st, ", read only");
4470     }
4471 else {
4472     if (uptr->flags & UNIT_ATTABLE) {
4473         fprint_sep (st, &toks);
4474         (void)fprintf (st, "status   : not attached");
4475         }
4476     }
4477 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4478     fprint_sep (st, &toks);
4479     fprint_capac (st, dptr, uptr);
4480     }
4481 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);        /* show unit mods */
4482 if (toks || (flag < 0) || (flag > 1))
4483     (void)fprintf (st, "\n");
4484 return SCPE_OK;
4485 }
4486 
4487 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4488 {
4489 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4490 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4491 t_offset mval;
4492 t_offset psize = (t_offset)uptr->capac;
4493 char *scale, *width;
4494 
4495 if (sim_switches & SWMASK ('B'))
4496     kval = 1024;
4497 mval = kval * kval;
4498 if (dptr->flags & DEV_SECTORS) {
4499     kval = kval / 512;
4500     mval = mval / 512;
4501     }
4502 if ((dptr->dwidth / dptr->aincr) > 8)
4503     width = "W";
4504 else
4505     width = "B";
4506 if ((psize < (kval * 10)) &&
4507     (0 != (psize % kval))) {
4508     scale = "";
4509     }
4510 else if ((psize < (mval * 10)) &&
4511          (0 != (psize % mval))){
4512     scale = "K";
4513     psize = psize / kval;
4514     }
4515 else {
4516     scale = "M";
4517     psize = psize / mval;
4518     }
4519 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4520 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4521 return capac_buf;
4522 }
4523 
4524 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4525 {
4526 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4527 }
4528 
4529 /* Show <global name> processors  */
4530 
4531 extern void print_default_base_system_script (void);
4532 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4533 {
4534 #if !defined(PERF_STRIP)
4535   print_default_base_system_script();
4536 #endif /* if !defined(PERF_STRIP) */
4537   return 0;
4538 }
4539 
4540 static void printp (unsigned char * PROM, char * label, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4541   sim_printf (" %s ", label);
4542   sim_printf ("   %2d     %3o(8)     '", length, offset);
4543   for (int l = 0; l < length; l ++)
4544     {
4545       unsigned int byte = PROM[offset + l];
4546       if (byte == 255)
4547         {
4548           byte = ' ';
4549         }
4550       sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4551     }
4552   sim_printf ("'\r\n");
4553 }
4554 
4555 static void strip_spaces(char* str) {
     /* [previous][next][first][last][top][bottom][index][help] */
4556   int i, x;
4557   for (i=x=0; str[i]; ++i)
4558     {
4559       if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)]))) //-V781
4560         {
4561           str[x++] = str[i];
4562         }
4563     }
4564   str[x] = '\0';
4565   i = -1;
4566   x = 0;
4567   while (str[x] != '\0')
4568     {
4569       if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4570         {
4571           i=x;
4572         }
4573       x++;
4574     }
4575   str[i+1] = '\0';
4576 }
4577 
4578 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4579   char sx[1024];
4580   sx[1023] = '\0';
4581   unsigned int lastbyte = 0;
4582   for (int l = 0; l < length; l ++)
4583     {
4584       unsigned int byte = PROM[offset + l];
4585       if (byte == 255)
4586         {
4587           byte = 20;
4588         }
4589       if ((lastbyte != 20) && (byte != 20))
4590         {
4591           (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4592         }
4593       lastbyte = byte;
4594     }
4595   strip_spaces(sx);
4596   (void)fprintf (st, "%s", sx);
4597 }
4598 
4599 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4600 {
4601   unsigned char PROM[1024];
4602   setupPROM (0, PROM);
4603 
4604   sim_printf (" PROM size: %llu bytes\r\n",
4605               (long long unsigned)sizeof(PROM));
4606   sim_printf (" PROM initialization data:\r\n\r\n");
4607 
4608   sim_printf ("     Field Description      Length   Offset              Contents\r\n");
4609   sim_printf (" ========================= ======== ======== ==================================\r\n");
4610   sim_printf ("\r\n");
4611 
4612   //                      Field                 Offset       Length
4613   //             -------------------------    ----------   ----------
4614   printp (PROM, "CPU Model                ",       0,          11);
4615   printp (PROM, "CPU Serial               ",      11,          11);
4616   printp (PROM, "Ship Date                ",      22,           6);
4617   printp (PROM, "PROM Layout Version      ",      60,           1);
4618   printp (PROM, "Release Git Commit Date  ",      70,          10);
4619   printp (PROM, "Release Major            ",      80,           3);
4620   printp (PROM, "Release Minor            ",      83,           3);
4621   printp (PROM, "Release Patch            ",      86,           3);
4622   printp (PROM, "Release Iteration        ",      89,           3);
4623   printp (PROM, "Release Build Number     ",      92,           8);  /* Reserved */
4624   printp (PROM, "Release Type             ",     100,           1);
4625   printp (PROM, "Release Version Text     ",     101,          29);
4626   printp (PROM, "Build Architecture       ",     130,          20);
4627   printp (PROM, "Build Operating System   ",     150,          20);
4628   printp (PROM, "Target Architecture      ",     170,          20);
4629   printp (PROM, "Target Operating System  ",     190,          20);
4630 
4631   sim_printf("\r\n");
4632   return 0;
4633 }
4634 
4635 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4636 {
4637     (void)fprintf (st, "\r Build Information:\n");
4638 #if defined(BUILDINFO_scp) && defined(SYSDEFS_USED)
4639     (void)fprintf (st, "\r\n      Compilation info: %s\n", BUILDINFO_scp );
4640 # if !defined(__OPEN64__)
4641     (void)fprintf (st, "\r\n  Relevant definitions: %s\n", SYSDEFS_USED );
4642 # endif
4643 #elif defined(BUILDINFO_scp)
4644     (void)fprintf (st, "\r\n      Compilation info: %s\n", BUILDINFO_scp );
4645 #else
4646     (void)fprintf (st, "\r\n      Compilation info: Not available\n" );
4647 #endif
4648 #if !defined(__CYGWIN__)
4649 # if !defined(__APPLE__)
4650 #  if !defined(_AIX)
4651 #   if !defined(__MINGW32__)
4652 #    if !defined(__MINGW64__)
4653 #     if !defined(CROSS_MINGW32)
4654 #      if !defined(CROSS_MINGW64)
4655 #       if !defined(_WIN32)
4656 #        if !defined(__HAIKU__)
4657     (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4658     if (dl_iterate_phdr_callback_called)
4659         (void)fprintf (st, "\n");
4660 #        endif
4661 #       endif
4662 #      endif
4663 #     endif
4664 #    endif
4665 #   endif
4666 #  endif
4667 # endif
4668 #endif
4669 #if defined(UV_VERSION_MAJOR) && \
4670     defined(UV_VERSION_MINOR) && \
4671     defined(UV_VERSION_PATCH)
4672 # if defined(UV_VERSION_MAJOR)
4673 #  if !defined(UV_VERSION_MINOR) && \
4674       !defined(UV_VERSION_PATCH) && \
4675       !defined(UV_VERSION_SUFFIX)
4676     (void)fprintf (st, "\r\n    Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4677 #  endif /* if !defined(UV_VERSION_MINOR) && !defined(UV_VERSION_PATCH) && defined(UV_VERSION_SUFFIX) */
4678 #  if defined(UV_VERSION_MINOR)
4679 #   if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4680     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4681                    UV_VERSION_MINOR);
4682 #   endif /* if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX) */
4683 #   if defined(UV_VERSION_PATCH)
4684 #    if !defined(UV_VERSION_SUFFIX)
4685     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4686                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4687 #    endif /* if !defined(UV_VERSION_SUFFIX) */
4688 #    if defined(UV_VERSION_SUFFIX)
4689     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4690                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4691 #     if defined(UV_VERSION_IS_RELEASE)
4692 #      if UV_VERSION_IS_RELEASE == 1
4693 #       define UV_RELEASE_TYPE " (release)"
4694 #      endif /* if UV_VERSION_IS_RELEASE == 1 */
4695 #      if UV_VERSION_IS_RELEASE == 0
4696 #       define UV_RELEASE_TYPE "-dev"
4697 #      endif /* if UV_VERSION_IS_RELEASE == 0 */
4698 #      if !defined(UV_RELEASE_TYPE)
4699 #       define UV_RELEASE_TYPE ""
4700 #      endif /* if !defined(UV_RELEASE_TYPE) */
4701 #      if defined(UV_RELEASE_TYPE)
4702     (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4703 #      endif /* if defined(UV_RELEASE_TYPE) */
4704 #     endif /* if defined(UV_VERSION_IS_RELEASE) */
4705 #    endif /* if defined(UV_VERSION_SUFFIX) */
4706 #   endif /* if defined(UV_VERSION_PATCH) */
4707 #  endif /* if defined(UV_VERSION_MINOR) */
4708     unsigned int CurrentUvVersion = uv_version();
4709     if (CurrentUvVersion > 0)
4710         if (uv_version_string() != NULL)
4711             (void)fprintf (st, "; %s in use", uv_version_string());
4712 # endif /* if defined(UV_VERSION_MAJOR) */
4713 #else
4714     (void)fprintf (st, "\r\n    Event loop library: Using libuv (or compatible) library, unknown version");
4715 #endif /* if defined(UV_VERSION_MAJOR) &&  \
4716         *    defined(UV_VERSION_MINOR) &&  \
4717         *    defined(UV_VERSION_PATCH)     \
4718         */
4719 #if defined(DECNUMBERLOC)
4720 # if defined(DECVERSION)
4721 #  if defined(DECVERSEXT)
4722     (void)fprintf (st, "\r\n          Math library: %s-%s", DECVERSION, DECVERSEXT);
4723 #  else
4724 #   if defined(DECNLAUTHOR)
4725     (void)fprintf (st, "\r\n          Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4726 #   else
4727     (void)fprintf (st, "\r\n          Math library: %s", DECVERSION);
4728 #   endif /* if defined(DECNLAUTHOR) */
4729 #  endif /* if defined(DECVERSEXT) */
4730 # else
4731     (void)fprintf (st, "\r\n          Math library: decNumber, unknown version");
4732 # endif /* if defined(DECVERSION) */
4733 #endif /* if defined(DECNUMBERLOC) */
4734 #if defined(LOCKLESS)
4735     (void)fprintf (st, "\r\n     Atomic operations: ");
4736 # if defined(AIX_ATOMICS)
4737     (void)fprintf (st, "IBM AIX-style");
4738 # elif defined(BSD_ATOMICS)
4739     (void)fprintf (st, "FreeBSD-style");
4740 # elif defined(GNU_ATOMICS)
4741     (void)fprintf (st, "GNU-style");
4742 # elif defined(SYNC_ATOMICS)
4743     (void)fprintf (st, "GNU sync-style");
4744 # elif defined(ISO_ATOMICS)
4745     (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4746 # elif defined(NT_ATOMICS)
4747     (void)fprintf (st, "Windows NT interlocked operations");
4748 # endif
4749 #endif /* if defined(LOCKLESS) */
4750     (void)fprintf (st, "\r\n          File locking: ");
4751 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4752     (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4753 #endif
4754 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4755     (void)fprintf (st, "POSIX-style fcntl() locking");
4756 #endif
4757 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4758     (void)fprintf (st, "BSD-style flock() locking");
4759 #endif
4760 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4761     (void)fprintf (st, "No file locking available");
4762 #endif
4763     (void)fprintf (st, "\r\n     Backtrace support: ");
4764 #if defined(USE_BACKTRACE)
4765     (void)fprintf (st, "Enabled (libbacktrace)");
4766 #else
4767     (void)fprintf (st, "Disabled");
4768 #endif /* if defined(USE_BACKTRACE) */
4769     (void)fprintf (st, "\r\n       Windows support: ");
4770 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4771 # if defined(__MINGW64_VERSION_STR)
4772     (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
4773 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MAJOR_VERSION)
4774     (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
4775 # else
4776     (void)fprintf (st, "Built with MinGW");
4777 # endif
4778 
4779 # if defined(MINGW_CRT)
4780     (void)fprintf (st, "; %s", MINGW_CRT);
4781 #  if !defined(_UCRT)
4782 #   if defined(__MSVCRT_VERSION__)
4783 #    if __MSVCRT_VERSION__ > 0x00
4784     (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
4785 #    endif
4786 #   endif
4787 #  else
4788 
4789     struct UCRTVersion ucrtversion;
4790     int result = GetUCRTVersion (&ucrtversion);
4791 
4792     if (result == 0)
4793       (void)fprintf (st, " %u.%u.%u.%u",
4794                      ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
4795                      ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
4796 #  endif
4797     (void)fprintf (st, " in use");
4798 # endif
4799 #elif defined(__CYGWIN__)
4800     struct utsname utsname;
4801     (void)fprintf (st, "Built with Cygwin %d.%d.%d",
4802                    CYGWIN_VERSION_DLL_MAJOR / 1000,
4803                    CYGWIN_VERSION_DLL_MAJOR % 1000,
4804                    CYGWIN_VERSION_DLL_MINOR);
4805     if (uname(&utsname) == 0)
4806       fprintf (st, "; %s in use", utsname.release);
4807 #else
4808     (void)fprintf (st, "Disabled");
4809 #endif
4810 
4811     (void)fprintf (st, "\r\n");
4812     return 0;
4813 }
4814 
4815 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4816 {
4817 const char *arch = "";
4818 char *whydirty = " ";
4819 int dirty = 0;
4820 
4821 if (cptr && (*cptr != 0))
4822     return SCPE_2MARG;
4823 if (flag) {
4824         (void)fprintf (st, " %s Simulator:", sim_name);
4825 #if defined(USE_DUMA)
4826 # undef NO_SUPPORT_VERSION
4827 # define NO_SUPPORT_VERSION 1
4828         nodist++;
4829 #endif /* if defined(USE_DUMA) */
4830 #if defined(NO_SUPPORT_VERSION) ||  \
4831     defined(WITH_SOCKET_DEV)    ||  \
4832     defined(WITH_ABSI_DEV)      ||  \
4833     defined(WITH_MGP_DEV)       ||  \
4834     defined(TESTING)            ||  \
4835     defined(ISOLTS)             ||  \
4836     defined(USE_DUMA)
4837 # if !defined(NO_SUPPORT_VERSION)
4838 #  define NO_SUPPORT_VERSION 1
4839 # endif /* if !defined(NO_SUPPORT_VERSION) */
4840 #endif
4841 #if defined(NO_SUPPORT_VERSION)
4842         dirty++;
4843 #endif
4844 #if defined(GENERATED_MAKE_VER_H)
4845 # if defined(VER_H_GIT_VERSION)
4846 
4847         /* Dirty if git source is dirty */
4848         if (strstr(VER_H_GIT_VERSION, "*"))
4849           {
4850                 dirty++;
4851           }
4852 
4853         /* Dirty if version contains "X", "D", "A", or "B" */
4854         if ((strstr(VER_H_GIT_VERSION, "X")) ||  \
4855             (strstr(VER_H_GIT_VERSION, "D")) ||  \
4856             (strstr(VER_H_GIT_VERSION, "A")) ||  \
4857             (strstr(VER_H_GIT_VERSION, "B")))
4858           {
4859                 dirty++;
4860           }
4861 
4862         /* Why? */
4863         if (dirty) //-V547
4864           {
4865             if ((strstr(VER_H_GIT_VERSION, "X")))
4866               {
4867                     whydirty = " ";
4868               }
4869             else if ((strstr(VER_H_GIT_VERSION, "D")))
4870               {
4871                     whydirty = " DEV ";
4872               }
4873             else if ((strstr(VER_H_GIT_VERSION, "A")))
4874               {
4875                     whydirty = " ALPHA ";
4876               }
4877             else if ((strstr(VER_H_GIT_VERSION, "B")))
4878               {
4879                     whydirty = " BETA ";
4880               }
4881           }
4882 
4883 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
4884 #   if defined(VER_H_GIT_HASH)
4885 #    if VER_H_GIT_PATCH_INT < 1
4886     (void)fprintf (st, "\n   Version: %s (%ld-bit)\n    Commit: %s",
4887                    VER_H_GIT_VERSION,
4888                    (long)(CHAR_BIT*sizeof(void *)),
4889                    VER_H_GIT_HASH);
4890 #    else
4891 #     define NO_SUPPORT_VERSION 1
4892     (void)fprintf (st, "\n   Version: %s+%s (%ld-bit)\n    Commit: %s",
4893                    VER_H_GIT_VERSION, VER_H_GIT_PATCH,
4894                    (long)(CHAR_BIT*sizeof(void *)),
4895                    VER_H_GIT_HASH);
4896 #    endif
4897 #   else
4898 #    if VER_H_GIT_PATCH_INT < 1
4899         (void)fprintf (st, "\n   Version: %s (%ld-bit)",
4900                        VER_H_GIT_VERSION,
4901                        (long)(CHAR_BIT*sizeof(void *)));
4902 #    else
4903 #     define NO_SUPPORT_VERSION 1
4904         (void)fprintf (st, "\n   Version: %s+%s (%ld-bit)",
4905                        VER_H_GIT_VERSION, VER_H_GIT_PATCH,
4906                        (long)(CHAR_BIT*sizeof(void *)));
4907 #    endif
4908 #   endif
4909 #  else
4910 #   if defined(VER_H_GIT_HASH)
4911         (void)fprintf (st, "\n   Version: %s (%ld-bit)\n    Commit: %s",
4912                        VER_H_GIT_VERSION,
4913                        (long)(CHAR_BIT*sizeof(void *)),
4914                        VER_H_GIT_HASH);
4915 #   else
4916         (void)fprintf (st, "\n   Version: %s (%ld-bit)",
4917                        VER_H_GIT_VERSION,
4918                        (long)(CHAR_BIT*sizeof(void *)));
4919 #   endif
4920 #  endif
4921 # endif
4922 #endif
4923 
4924 /* TESTING */
4925 #if defined(TESTING)
4926     (void)fprintf (st, "\n   Options: ");
4927 # if !defined(HAVE_DPSOPT)
4928 #  define HAVE_DPSOPT 1
4929 # endif
4930     (void)fprintf (st, "TESTING");
4931 #endif /* if defined(TESTING) */
4932 
4933 /* ISOLTS */
4934 #if defined(ISOLTS)
4935 # if defined(HAVE_DPSOPT)
4936     (void)fprintf (st, ", ");
4937 # else
4938     (void)fprintf (st, "\n   Options: ");
4939 # endif
4940 # if !defined(HAVE_DPSOPT)
4941 #  define HAVE_DPSOPT 1
4942 # endif
4943     (void)fprintf (st, "ISOLTS");
4944 #endif /* if defined(ISOLTS) */
4945 
4946 /* NO_UCACHE */
4947 #if defined(NO_UCACHE)
4948 # if defined(HAVE_DPSOPT)
4949     (void)fprintf (st, ", ");
4950 # else
4951     (void)fprintf (st, "\n   Options: ");
4952 # endif
4953 # if !defined(HAVE_DPSOPT)
4954 #  define HAVE_DPSOPT 1
4955 # endif
4956     (void)fprintf (st, "NO_UCACHE");
4957 #endif /* if defined(NO_UCACHE) */
4958 
4959 /* NEED_128 */
4960 #if defined(NEED_128)
4961 # if defined(HAVE_DPSOPT)
4962     (void)fprintf (st, ", ");
4963 # else
4964     (void)fprintf (st, "\n   Options: ");
4965 # endif
4966 # if !defined(HAVE_DPSOPT)
4967 #  define HAVE_DPSOPT 1
4968 # endif
4969     (void)fprintf (st, "NEED_128");
4970 #endif /* if defined(NEED_128) */
4971 
4972 /* WAM */
4973 #if defined(WAM)
4974 # if defined(HAVE_DPSOPT)
4975     (void)fprintf (st, ", ");
4976 # else
4977     (void)fprintf (st, "\n   Options: ");
4978 # endif
4979 # if !defined(HAVE_DPSOPT)
4980 #  define HAVE_DPSOPT 1
4981 # endif
4982     (void)fprintf (st, "WAM");
4983 #endif /* if defined(WAM) */
4984 
4985 /* ROUND_ROBIN */
4986 #if defined(ROUND_ROBIN)
4987 # if defined(HAVE_DPSOPT)
4988     (void)fprintf (st, ", ");
4989 # else
4990     (void)fprintf (st, "\n   Options: ");
4991 # endif
4992 # if !defined(HAVE_DPSOPT)
4993 #  define HAVE_DPSOPT 1
4994 # endif
4995     (void)fprintf (st, "ROUND_ROBIN");
4996 #endif /* if defined(ROUND_ROBIN) */
4997 
4998 /* NO_LOCKLESS */
4999 #if !defined(LOCKLESS)
5000 # if defined(HAVE_DPSOPT)
5001     (void)fprintf (st, ", ");
5002 # else
5003     (void)fprintf (st, "\n   Options: ");
5004 # endif
5005 # if !defined(HAVE_DPSOPT)
5006 #  define HAVE_DPSOPT 1
5007 # endif
5008     (void)fprintf (st, "NO_LOCKLESS");
5009 #endif /* if !defined(LOCKLESS) */
5010 
5011 /* ABSI */  /* XXX: Change to NO_ABSI once code is non-experimental */
5012 #if defined(WITH_ABSI_DEV)
5013 # if defined(HAVE_DPSOPT)
5014     (void)fprintf (st, ", ");
5015 # else
5016     (void)fprintf (st, "\n   Options: ");
5017 # endif
5018 # if !defined(HAVE_DPSOPT)
5019 #  define HAVE_DPSOPT 1
5020 # endif
5021     (void)fprintf (st, "ABSI");
5022 #endif /* if defined(WITH_ABSI_DEV) */
5023 
5024 /* SOCKET */  /* XXX: Change to NO_SOCKET once code is non-experimental */
5025 #if defined(WITH_SOCKET_DEV)
5026 # if defined(HAVE_DPSOPT)
5027     (void)fprintf (st, ", ");
5028 # else
5029     (void)fprintf (st, "\n   Options: ");
5030 # endif
5031 # if !defined(HAVE_DPSOPT)
5032 #  define HAVE_DPSOPT 1
5033 # endif
5034     (void)fprintf (st, "SOCKET");
5035 #endif /* if defined(WITH_SOCKET_DEV) */
5036 
5037 /* CHAOSNET */  /* XXX: Change to NO_CHAOSNET once code is non-experimental */
5038 #if defined(WITH_MGP_DEV)
5039 # if defined(HAVE_DPSOPT)
5040     (void)fprintf (st, ", ");
5041 # else
5042     (void)fprintf (st, "\n   Options: ");
5043 # endif
5044 # if !defined(HAVE_DPSOPT)
5045 #  define HAVE_DPSOPT 1
5046 # endif
5047     (void)fprintf (st, "CHAOSNET");
5048 # if USE_SOCKET_DEV_APPROACH
5049     (void)fprintf (st, "-S");
5050 # endif /* if USE_SOCKET_DEV_APPROACH */
5051 #endif /* if defined(WITH_MGP_DEV) */
5052 
5053 /* DUMA */
5054 #if defined(USE_DUMA)
5055 # if defined(HAVE_DPSOPT)
5056     (void)fprintf (st, ", ");
5057 # else
5058     (void)fprintf (st, "\n   Options: ");
5059 # endif
5060 # if !defined(HAVE_DPSOPT)
5061 #  define HAVE_DPSOPT 1
5062 # endif
5063     (void)fprintf (st, "DUMA");
5064 #endif /* if defined(USE_DUMA) */
5065 
5066 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5067 # if defined(NO_SUPPORT_VERSION)
5068     (void)fprintf (st, "\n  Modified: %s", VER_H_GIT_DATE);
5069 # else
5070     (void)fprintf (st, "\n  Released: %s", VER_H_GIT_DATE);
5071 # endif
5072 #endif
5073 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5074     (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5075 #endif
5076 #if defined(VER_CURRENT_TIME)
5077     (void)fprintf (st, "\n  Compiled: %s", VER_CURRENT_TIME);
5078 #endif
5079     if (dirty) //-V547
5080       {
5081         (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5082       }
5083     (void)fprintf (st, "\r\n\r\n Build Information:");
5084 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5085     char build_os_version_raw[255];
5086     char build_os_arch_raw[255];
5087     (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5088     (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5089     char *build_os_version = strdup(build_os_version_raw);
5090     if (!build_os_version)
5091       {
5092         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5093                        __func__, __FILE__, __LINE__);
5094 # if defined(USE_BACKTRACE)
5095 #  if defined(SIGUSR2)
5096         (void)raise(SIGUSR2);
5097         /*NOTREACHED*/ /* unreachable */
5098 #  endif /* if defined(SIGUSR2) */
5099 # endif /* if defined(USE_BACKTRACE) */
5100         abort();
5101       }
5102     char *build_os_arch = strdup(build_os_arch_raw);
5103     if (!build_os_arch)
5104       {
5105         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5106                        __func__, __FILE__, __LINE__);
5107 # if defined(USE_BACKTRACE)
5108 #  if defined(SIGUSR2)
5109         (void)raise(SIGUSR2);
5110         /*NOTREACHED*/ /* unreachable */
5111 #  endif /* if defined(SIGUSR2) */
5112 # endif /* if defined(USE_BACKTRACE) */
5113         abort();
5114       }
5115     unsigned char SPROM[1024];
5116     setupPROM (0, SPROM);
5117     (void)fprintf (st, "\n    Target: ");
5118     printpq (SPROM, st, 190, 20);
5119     if (SPROM[170] != 20)
5120       {
5121         if (SPROM[170] != 255)
5122           {
5123             (void)fprintf (st, " on ");
5124             printpq (SPROM, st, 170, 20);
5125           }
5126       }
5127     strtrimspace(build_os_version, build_os_version_raw);
5128     strtrimspace(build_os_arch, build_os_arch_raw);
5129     (void)fprintf (st, "\n  Build OS: %s %s", build_os_version, build_os_arch);
5130     FREE(build_os_version);
5131     FREE(build_os_arch);
5132 #endif
5133 #if defined(__VERSION__)
5134     char gnumver[2];
5135     char postver[1024];
5136     (void)sprintf(gnumver, "%.1s", __VERSION__);
5137     (void)sprintf(postver, "%.1023s", __VERSION__);
5138     strremove(postver, "(TM)");
5139     strremove(postver, "(R)");
5140     strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5141     strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5142     strremove(postver, " gcc 4.9 mode");
5143     strremove(postver, "4.2.1 Compatible ");
5144     strremove(postver, "git@github.com:llvm/llvm-project.git ");
5145     strremove(postver, "https://github.com/llvm/llvm-project.git ");
5146     strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5147     strremove(postver, "https://github.com/yrnkrn/zapcc ");
5148     strremove(postver, "(experimental) ");
5149     strremove(postver, ".module+el8.7.0+20823+214a699d");
5150     strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5151     strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5152     strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5153     strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5154     strremove(postver, "llvmorg-16.0.6-0-");
5155     strremove(postver, " Clang 15.0.0 (build 760095e)");
5156     strremove(postver, " Clang 15.0.0 (build 6af5742)");
5157     strremove(postver, " Clang 15.0.0 (build ca7115e)");
5158     strremove(postver, " Clang 15.0.0 (build 232543c)");
5159     strremove(postver, " Clang 17.0.6 (build 19a779f)");
5160     strremove(postver, "CLANG: ");
5161 #endif
5162 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5163 # if !defined(__clang_version__)
5164     if (isdigit((unsigned char)gnumver[0])) {
5165         (void)fprintf (st, "\n  Compiler: GCC %s", postver);
5166     } else {
5167         (void)fprintf (st, "\n  Compiler: %s", postver);
5168     }
5169 # endif
5170 # if defined(__clang_analyzer__ )
5171     (void)fprintf (st, "\n  Compiler: Clang C/C++ Static Analyzer");
5172 # elif defined(__clang_version__) && defined(__VERSION__)
5173     char clangllvmver[1024];
5174     (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5175     strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5176     strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5177     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5178     strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5179     strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5180     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5181     strremove(clangllvmver, " ( )");
5182     strremove(clangllvmver, " ()");
5183     if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5184         (void)fprintf (st, "\n  Compiler: Clang %s", clangllvmver);
5185     } else {
5186         (void)fprintf (st, "\n  Compiler: %s", postver);
5187     }
5188 # elif defined(__clang_version__)
5189     (void)fprintf (st, "\n  Compiler: %s", postver);
5190 # endif
5191 #elif defined(__PGI) && !defined(__NVCOMPILER)
5192     (void)fprintf (st, "\n  Compiler: Portland Group, Inc. (PGI) C Compiler ");
5193 # if defined(__PGIC__)
5194     (void)fprintf (st, "%d", __PGIC__);
5195 #  if defined(__PGIC_MINOR__)
5196     (void)fprintf (st, ".%d", __PGIC_MINOR__);
5197 #   if defined(__PGIC_PATCHLEVEL__)
5198     (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5199 #   endif
5200 #  endif
5201 # endif
5202 #elif defined(__NVCOMPILER)
5203     (void)fprintf (st, "\n  Compiler: NVIDIA HPC SDK C Compiler ");
5204 # if defined(__NVCOMPILER_MAJOR__)
5205     (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5206 #  if defined(__NVCOMPILER_MINOR__)
5207     (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5208 #   if defined(__NVCOMPILER_PATCHLEVEL__)
5209     (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5210 #   endif
5211 #  endif
5212 # endif
5213 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5214     (void)fprintf (st, "\n  Compiler: Microsoft C %d.%02d.%05d.%02d",
5215                    _MSC_FULL_VER/10000000,
5216                    (_MSC_FULL_VER/100000)%100,
5217                    _MSC_FULL_VER%100000,
5218                    _MSC_BUILD);
5219 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5220 # if defined(_AIX) && defined(__PASE__)
5221     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5222 # endif
5223 # if defined(_AIX) && !defined(__PASE__)
5224     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5225 # endif
5226 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5227     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5228 # endif
5229 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5230 #  if defined(__PPC__) && defined(__APPLE__)
5231     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5232 #  else
5233     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ V%s", __xlc__);
5234 #  endif
5235 # endif
5236 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5237 # define VER_ENC(maj, min, rev) \
5238   (((maj) * 1000000) + ((min) * 1000) + (rev))
5239 # define VER_DEC_MAJ(ver) \
5240   ((ver) / 1000000)
5241 # define VER_DEC_MIN(ver) \
5242   (((ver) % 1000000) / 1000)
5243 # define VER_DEC_REV(ver) \
5244   ((ver) % 1000)
5245 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5246 #  define COMP_VER VER_ENC(                                        \
5247    (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5248    (((__SUNPRO_C >>  8) & 0xf) * 10) + ((__SUNPRO_C >>  4) & 0xf), \
5249      (__SUNPRO_C & 0xf) * 10)
5250 # elif defined(__SUNPRO_C)
5251 #  define COMP_VER VER_ENC(    \
5252      (__SUNPRO_C >>  8) & 0xf, \
5253      (__SUNPRO_C >>  4) & 0xf, \
5254      (__SUNPRO_C) & 0xf)
5255 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5256 #  define COMP_VER VER_ENC(                                          \
5257    (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5258    (((__SUNPRO_CC >>  8) & 0xf) * 10) + ((__SUNPRO_CC >>  4) & 0xf), \
5259      (__SUNPRO_CC & 0xf) * 10)
5260 # elif defined(__SUNPRO_CC)
5261 #  define COMP_VER VER_ENC(     \
5262      (__SUNPRO_CC >>  8) & 0xf, \
5263      (__SUNPRO_CC >>  4) & 0xf, \
5264      (__SUNPRO_CC) & 0xf)
5265 # endif
5266 # if !defined(COMP_VER)
5267 #  define COMP_VER 0
5268 # endif
5269     (void)fprintf (st, "\n  Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5270                    VER_DEC_MAJ(COMP_VER),
5271                    VER_DEC_MIN(COMP_VER),
5272                    VER_DEC_REV(COMP_VER));
5273 #elif defined(__DMC__)
5274     (void)fprintf (st, "\n  Compiler: Digital Mars C/C++");
5275 #elif defined(__PCC__)
5276     (void)fprintf (st, "\n  Compiler: Portable C Compiler");
5277 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5278     (void)fprintf (st, "\n  Compiler: Plan 9 Compiler Suite");
5279 #elif defined(__ACK__)
5280     (void)fprintf (st, "\n  Compiler: Amsterdam Compiler Kit");
5281 #elif defined(__COMO__)
5282     (void)fprintf (st, "\n  Compiler: Comeau C++");
5283 #elif defined(__COMPCERT__)
5284     (void)fprintf (st, "\n  Compiler: CompCert C");
5285 #elif defined(__COVERITY__)
5286     (void)fprintf (st, "\n  Compiler: Coverity C/C++ Static Analyzer");
5287 #elif defined(__LCC__)
5288     (void)fprintf (st, "\n  Compiler: Local C Compiler (lcc)");
5289 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5290     (void)fprintf (st, "\n  Compiler: SGI MIPSpro");
5291 #elif defined(__OPEN64__)
5292     (void)fprintf (st, "\n  Compiler: Open64 %s", __OPEN64__);
5293 #elif defined(__PGI) || defined(__PGIC__)
5294     (void)fprintf (st, "\n  Compiler: Portland Group/PGI C/C++");
5295 #elif defined(__VBCC__)
5296     (void)fprintf (st, "\n  Compiler: Volker Barthelmann C Compiler (vbcc)");
5297 #elif defined(__WATCOMC__)
5298     (void)fprintf (st, "\n  Compiler: Watcom C/C++ %d.%d",
5299                    __WATCOMC__ / 100,
5300                    __WATCOMC__ % 100);
5301 #elif defined(__xlC__)
5302     (void)fprintf (st, "\n  Compiler: IBM XL C/C++");
5303 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5304 # if defined(__INTEL_COMPILER_UPDATE)
5305 #  if defined(__INTEL_COMPILER_BUILD_DATE)
5306     (void)fprintf (st, "\n  Compiler: Intel C++ Compiler %d.%d (%d)",
5307                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5308                    __INTEL_COMPILER_BUILD_DATE);
5309 #  else
5310     (void)fprintf (st, "\n  Compiler: Intel C++ Compiler %d.%d",
5311                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5312 #  endif
5313 # else
5314     (void)fprintf (st, "\n  Compiler: Intel C++ Compiler %d",
5315                    __INTEL_COMPILER);
5316 # endif
5317 #elif defined(SIM_COMPILER)
5318 # define S_xstr(a) S_str(a)
5319 # define S_str(a) #a
5320     (void)fprintf (st, "\n  Compiler: %s", S_xstr(SIM_COMPILER));
5321 # undef S_str
5322 # undef S_xstr
5323 #else
5324     (void)fprintf (st, "\n  Compiler: Unknown");
5325 #endif
5326 
5327 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5328     defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5329 # define SC_IS_PPC64 1
5330 #else
5331 # define SC_IS_PPC64 0
5332 #endif
5333 
5334 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5335     defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5336     defined(__PPC32)
5337 # define SC_IS_PPC32 1
5338 #else
5339 # define SC_IS_PPC32 0
5340 #endif
5341 
5342 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5343     arch = " x86_64";
5344 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5345     arch = " x86";
5346 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5347     arch = " arm64";
5348 #elif defined(_M_ARM) || defined(__arm__)
5349     arch = " arm";
5350 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5351     arch = " ia64";
5352 #elif SC_IS_PPC64
5353     arch = " powerpc64";
5354 #elif SC_IS_PPC32
5355     arch = " powerpc";
5356 #elif defined(__s390x__)
5357     arch = " s390x";
5358 #elif defined(__s390__)
5359     arch = " s390";
5360 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5361     arch = " j2";
5362 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5363     arch = " sh4";
5364 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5365     arch = " sh2";
5366 #elif defined(__alpha__)
5367     arch = " alpha";
5368 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5369     arch = " hppa";
5370 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5371     arch = " ice9";
5372 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5373     arch = " mips64";
5374 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5375     arch = " mips";
5376 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5377       defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5378     arch = " openrisc";
5379 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5380     arch = " sparc64";
5381 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5382     arch = " sparc";
5383 #elif defined(__riscv) || defined(__riscv__)
5384     arch = " riscv";
5385 #elif defined(__myriad2__)
5386     arch = " myriad2";
5387 #elif defined(__loongarch64) || defined(__loongarch__)
5388     arch = " loongarch";
5389 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5390     arch = " m68k";
5391 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5392     arch = " m88k";
5393 #elif defined(__VAX__) || defined(__vax__)
5394     arch = " vax";
5395 #elif defined(__NIOS2__) || defined(__nios2__)
5396     arch = " nios2";
5397 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5398     arch = " microblaze";
5399 #else
5400     arch = " ";
5401 #endif
5402     (void)fprintf (st, "%s", arch);
5403 #if defined(BUILD_BY_USER)
5404         (void)fprintf (st, "\n  Built by: %s", BUILD_BY_USER);
5405 #else
5406 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5407         (void)fprintf (st, "\n  Built by: %s", VER_H_PREP_USER);
5408 # endif
5409 #endif
5410                 (void)fprintf (st, "\n\n Host System Information:");
5411 #if defined(_WIN32)
5412     if (1) {
5413         char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5414         char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5415         char osversion[PATH_MAX+1] = "";
5416         FILE *f;
5417 
5418         if ((f = _popen ("ver", "r"))) {
5419             (void)memset (osversion, 0, sizeof(osversion));
5420             do {
5421                 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5422                     break;
5423                 sim_trim_endspc (osversion);
5424                 } while (osversion[0] == '\0');
5425             _pclose (f);
5426             }
5427         (void)fprintf (st, "\n   Host OS: %s", osversion);
5428         (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264  : "");
5429         }
5430 #else
5431     if (1) {
5432         char osversion[2*PATH_MAX+1] = "";
5433         FILE *f;
5434 # if !defined(_AIX)
5435         if ((f = popen \
5436              ("uname -mrs 2> /dev/null", "r"))) {
5437 # else
5438         if ((f = popen \
5439              ("sh -c 'echo \"$(command -p env uname -v \
5440                2> /dev/null).$(command -p env uname -r \
5441                2> /dev/null) $(command -p env uname -p \
5442                2> /dev/null)\"' 2> /dev/null", "r"))) {
5443 # endif /* if !defined(_AIX) */
5444             (void)memset (osversion, 0, sizeof(osversion));
5445             do {
5446               if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5447                     break;
5448               }
5449             sim_trim_endspc (osversion);
5450             } while (osversion[0] == '\0');
5451             pclose (f);
5452             strremove(osversion, "0000000000000000 ");
5453             strremove(osversion, " 0000000000000000");
5454             strremove(osversion, "000000000000 ");
5455             strremove(osversion, " 000000000000");
5456             strremove(osversion, "IBM ");
5457             strremove(osversion, " (emulated by qemu)");
5458             strremove(osversion, " (emulated by QEMU)");
5459         }
5460 # if !defined(_AIX)
5461             (void)fprintf (st, "\n   Host OS: %s", osversion);
5462 # else
5463             strremove(osversion, "AIX ");
5464 #  if !defined(__PASE__)
5465             (void)fprintf (st, "\n   Host OS: IBM AIX %s", osversion);
5466 #  else
5467             (void)fprintf (st, "\n   Host OS: IBM OS/400 (PASE) %s", osversion);
5468 #  endif /* if !defined(__PASE__) */
5469 # endif /* if !defined(_AIX) */
5470     } else {
5471 # if !defined(_AIX)
5472         (void)fprintf (st, "\n   Host OS: Unknown");
5473 # else
5474 #  if !defined(__PASE__)
5475         (void)fprintf (st, "\n   Host OS: IBM AIX");
5476 #  else
5477         (void)fprintf (st, "\n   Host OS: IBM OS/400 (PASE)");
5478 #  endif /* if !defined(__PASE__) */
5479 # endif /* if !defined(_AIX) */
5480     }
5481 #endif
5482 #if defined(__APPLE__)
5483     int isRosetta = processIsTranslated();
5484     if (isRosetta == 1) {
5485         sim_printf ("\n\n  ****** RUNNING UNDER APPLE ROSETTA 2, EXPECT REDUCED PERFORMANCE ******");
5486     }
5487 #endif
5488     if (nodist)
5489       {
5490         sim_printf ("\n\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\n");
5491       }
5492     else
5493       {
5494         (void)fprintf (st, "\n");
5495         (void)fprintf (st, "\n This software is made available under the terms of the ICU License.");
5496         (void)fprintf (st, "\n For complete license details, see the LICENSE file included with the");
5497         (void)fprintf (st, "\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5498       }
5499         (void)fprintf (st, "\n");
5500     }
5501 return SCPE_OK;
5502 }
5503 
5504 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5505 {
5506 size_t i;
5507 DEVICE *dptr;
5508 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5509 
5510 if (cptr && (*cptr != 0))
5511     return SCPE_2MARG;
5512 (void)fprintf (st, "%s simulator configuration%s\n\n", sim_name, only_enabled ? " (enabled devices)" : "");
5513 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5514     if (!only_enabled || !qdisable (dptr))
5515         show_device (st, dptr, flag);
5516 return SCPE_OK;
5517 }
5518 
5519 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5520 {
5521 int32 i;
5522 DEVICE *dptr;
5523 
5524 if (cptr && (*cptr != 0))
5525     return SCPE_2MARG;
5526 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5527     show_dev_logicals (st, dptr, NULL, 1, cptr);
5528 return SCPE_OK;
5529 }
5530 
5531 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5532 {
5533 if (dptr->lname)
5534     (void)fprintf (st, "%s -> %s\n", dptr->lname, dptr->name);
5535 else if (!flag)
5536     fputs ("no logical name assigned\n", st);
5537 return SCPE_OK;
5538 }
5539 
5540 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5541 {
5542 DEVICE *dptr;
5543 UNIT *uptr;
5544 int32 accum;
5545 
5546 if (cptr && (*cptr != 0))
5547     return SCPE_2MARG;
5548 if (sim_clock_queue == QUEUE_LIST_END)
5549     (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\n",
5550                    sim_name, sim_time, sim_timer_inst_per_sec ());
5551 else {
5552     const char *tim;
5553 
5554     (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\n",
5555                    sim_name, sim_time, sim_timer_inst_per_sec ());
5556     accum = 0;
5557     for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5558         if (uptr == &sim_step_unit)
5559             (void)fprintf (st, "  Step timer");
5560         else
5561             if (uptr == &sim_expect_unit)
5562                 (void)fprintf (st, "  Expect fired");
5563             else
5564                 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5565                     (void)fprintf (st, "  %s", sim_dname (dptr));
5566                     if (dptr->numunits > 1)
5567                         (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5568                     }
5569                 else
5570                     (void)fprintf (st, "  Unknown");
5571         tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5572         (void)fprintf (st, " at %d%s%s%s%s\n", accum + uptr->time,
5573                        (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5574                        (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5575         accum = accum + uptr->time;
5576         }
5577     }
5578 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5579 return SCPE_OK;
5580 }
5581 
5582 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5583 {
5584 if (cptr && (*cptr != 0))
5585     return SCPE_2MARG;
5586 (void)fprintf (st, "Time:\t%.0f\n", sim_gtime());
5587 return SCPE_OK;
5588 }
5589 
5590 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5591 {
5592 t_stat r;
5593 
5594 if (cptr && (*cptr != 0))
5595     r = ssh_break (st, cptr, 1);  /* more? */
5596 else
5597     r = sim_brk_showall (st, sim_switches);
5598 return r;
5599 }
5600 
5601 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5602 {
5603 (void)fprintf (st, "Radix=%d\n", dptr->dradix);
5604 return SCPE_OK;
5605 }
5606 
5607 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5608 {
5609 int32 any = 0;
5610 DEBTAB *dep;
5611 
5612 if (dptr->flags & DEV_DEBUG) {
5613     if (dptr->dctrl == 0)
5614         fputs ("Debugging disabled", st);
5615     else if (dptr->debflags == NULL)
5616         fputs ("Debugging enabled", st);
5617     else {
5618         uint32 dctrl = dptr->dctrl;
5619 
5620         fputs ("Debug=", st);
5621         for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5622             if ((dctrl & dep->mask) == dep->mask) {
5623                 dctrl &= ~dep->mask;
5624                 if (any)
5625                     fputc (';', st);
5626                 fputs (dep->name, st);
5627                 any = 1;
5628                 }
5629             }
5630         }
5631     fputc ('\n', st);
5632     return SCPE_OK;
5633     }
5634 else return SCPE_NOFNC;
5635 }
5636 
5637 /* Show On actions */
5638 
5639 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5640 {
5641 int32 lvl, i;
5642 
5643 if (cptr && (*cptr != 0)) return SCPE_2MARG;            /* now eol? */
5644 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5645     if (lvl > 0)
5646         (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5647     else
5648         (void)fprintf(st, "On Processing for input commands");
5649     (void)fprintf(st, " is %s\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5650     for (i=1; i<SCPE_BASE; ++i) {
5651         if (sim_on_actions[lvl][i])
5652             (void)fprintf(st, "    on %5d    %s\n", i, sim_on_actions[lvl][i]); }
5653     for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5654         if (sim_on_actions[lvl][i])
5655             (void)fprintf(st, "    on %-5s    %s\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5656     if (sim_on_actions[lvl][0])
5657         (void)fprintf(st, "    on ERROR    %s\n", sim_on_actions[lvl][0]);
5658     (void)fprintf(st, "\n");
5659     }
5660 if (sim_on_inherit)
5661     (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\n");
5662 return SCPE_OK;
5663 }
5664 
5665 /* Show modifiers */
5666 
5667 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5668 {
5669 int32 i;
5670 DEVICE *dptr;
5671 
5672 if (cptr && (*cptr != 0))                               /* now eol? */
5673     return SCPE_2MARG;
5674 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5675     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5676 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5677     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5678 return SCPE_OK;
5679 }
5680 
5681 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5682 {
5683 fprint_set_help (st, dptr);
5684 return SCPE_OK;
5685 }
5686 
5687 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
     /* [previous][next][first][last][top][bottom][index][help] */
5688 {
5689 MTAB *mptr;
5690 t_stat r = SCPE_OK;
5691 
5692 if (dptr->modifiers == NULL)
5693     return SCPE_OK;
5694 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5695     if (mptr->pstring &&
5696         ((mptr->mask & MTAB_XTD)?
5697             (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5698             ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5699         if (*toks > 0) {
5700             (void)fprintf (st, "\n");
5701             *toks = 0;
5702             }
5703         if (r == SCPE_OK)
5704             fprint_sep (st, toks);
5705         r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5706         }
5707     }
5708 return SCPE_OK;
5709 }
5710 
5711 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
     /* [previous][next][first][last][top][bottom][index][help] */
5712     CONST char *cptr, int32 flag)
5713 {
5714 t_stat r = SCPE_OK;
5715 
5716 if (mptr->disp)
5717     r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5718 else
5719     fputs (mptr->pstring, st);
5720 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5721     fputc ('\n', st);
5722 return r;
5723 }
5724 
5725 /* Show show commands */
5726 
5727 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5728 {
5729 int32 i;
5730 DEVICE *dptr;
5731 
5732 if (cptr && (*cptr != 0))                               /* now eol? */
5733     return SCPE_2MARG;
5734 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5735     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5736 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5737     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5738 return SCPE_OK;
5739 }
5740 
5741 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5742 {
5743 fprint_show_help (st, dptr);
5744 return SCPE_OK;
5745 }
5746 
5747 /* Breakpoint commands */
5748 
5749 t_stat brk_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5750 {
5751 GET_SWITCHES (cptr);                                    /* get switches */
5752 return ssh_break (NULL, cptr, flg);                     /* call common code */
5753 }
5754 
5755 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
     /* [previous][next][first][last][top][bottom][index][help] */
5756 {
5757 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5758 CONST char *tptr, *t1ptr;
5759 DEVICE *dptr = sim_dflt_dev;
5760 UNIT *uptr;
5761 t_stat r;
5762 t_addr lo, hi, max;
5763 int32 cnt;
5764 
5765 if (sim_brk_types == 0)
5766     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5767 if (dptr == NULL)
5768     return SCPE_IERR;
5769 uptr = dptr->units;
5770 if (uptr == NULL)
5771     return SCPE_IERR;
5772 max = uptr->capac - 1;
5773 abuf[sizeof(abuf)-1] = '\0';
5774 strncpy (abuf, cptr, sizeof(abuf)-1);
5775 cptr = abuf;
5776 if ((aptr = strchr (abuf, ';'))) {                      /* ;action? */
5777     if (flg != SSH_ST)                                  /* only on SET */
5778         return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", aptr);
5779     *aptr++ = 0;                                        /* separate strings */
5780     }
5781 if (*cptr == 0) {                                       /* no argument? */
5782     lo = (t_addr) get_rval (sim_PC, 0);                 /* use PC */
5783     return ssh_break_one (st, flg, lo, 0, aptr);
5784     }
5785 while (*cptr) {
5786     cptr = get_glyph (cptr, gbuf, ',');
5787     tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5788     if (tptr == NULL)
5789         return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\n", gbuf);
5790     if (*tptr == '[') {
5791         cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5792         if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5793             return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\n", tptr + 1);
5794         tptr = t1ptr + 1;
5795         }
5796     else cnt = 0;
5797     if (*tptr != 0)
5798         return sim_messagef (SCPE_ARG, "Unexpected argument: %s\n", tptr);
5799     if ((lo == 0) && (hi == max)) {
5800         if (flg == SSH_CL)
5801             sim_brk_clrall (sim_switches);
5802         else
5803             if (flg == SSH_SH)
5804                 sim_brk_showall (st, sim_switches);
5805             else
5806                 return SCPE_ARG;
5807         }
5808     else {
5809         for ( ; lo <= hi; lo = lo + 1) {
5810             r = ssh_break_one (st, flg, lo, cnt, aptr);
5811             if (r != SCPE_OK)
5812                 return r;
5813             }
5814         }
5815     }
5816 return SCPE_OK;
5817 }
5818 
5819 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5820 {
5821 if (!sim_brk_types)
5822     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5823 switch (flg) {
5824     case SSH_ST:
5825         return sim_brk_set (lo, sim_switches, cnt, aptr);
5826         /*NOTREACHED*/ /* unreachable */
5827         break;
5828 
5829     case SSH_CL:
5830         return sim_brk_clr (lo, sim_switches);
5831         /*NOTREACHED*/ /* unreachable */
5832         break;
5833 
5834     case SSH_SH:
5835         return sim_brk_show (st, lo, sim_switches);
5836         /*NOTREACHED*/ /* unreachable */
5837         break;
5838 
5839     default:
5840         return SCPE_ARG;
5841     }
5842 }
5843 
5844 /* Reset command and routines */
5845 
5846 static t_bool run_cmd_did_reset = FALSE;
5847 
5848 t_stat reset_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5849 {
5850 char gbuf[CBUFSIZE];
5851 DEVICE *dptr;
5852 
5853 GET_SWITCHES (cptr);                                    /* get switches */
5854 run_cmd_did_reset = FALSE;
5855 if (*cptr == 0)                                         /* reset(cr) */
5856     return (reset_all (0));
5857 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
5858 if (*cptr != 0)                                         /* now eol? */
5859     return SCPE_2MARG;
5860 if (strcmp (gbuf, "ALL") == 0)
5861     return (reset_all (0));
5862 dptr = find_dev (gbuf);                                 /* locate device */
5863 if (dptr == NULL)                                       /* found it? */
5864     return SCPE_NXDEV;
5865 if (dptr->reset != NULL)
5866     return dptr->reset (dptr);
5867 else return SCPE_OK;
5868 }
5869 
5870 /* Reset devices start..end
5871 
5872    Inputs:
5873         start   =       number of starting device
5874    Outputs:
5875         status  =       error status
5876 */
5877 
5878 t_stat reset_all (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
5879 {
5880 DEVICE *dptr;
5881 uint32 i;
5882 t_stat reason;
5883 
5884 for (i = 0; i < start; i++) {
5885     if (sim_devices[i] == NULL)
5886         return SCPE_IERR;
5887     }
5888 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
5889     if (dptr->reset != NULL) {
5890         reason = dptr->reset (dptr);
5891         if (reason != SCPE_OK)
5892             return reason;
5893         }
5894     }
5895 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
5896     if (dptr->reset != NULL) {
5897         reason = dptr->reset (dptr);
5898         if (reason != SCPE_OK)
5899             return reason;
5900         }
5901     }
5902 return SCPE_OK;
5903 }
5904 
5905 /* Reset to powerup state
5906 
5907    Inputs:
5908         start   =       number of starting device
5909    Outputs:
5910         status  =       error status
5911 */
5912 
5913 t_stat reset_all_p (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
5914 {
5915 t_stat r;
5916 int32 old_sw = sim_switches;
5917 
5918 sim_switches = SWMASK ('P');
5919 r = reset_all (start);
5920 sim_switches = old_sw;
5921 return r;
5922 }
5923 
5924 /* Attach command */
5925 
5926 t_stat attach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5927 {
5928 char gbuf[4*CBUFSIZE];
5929 DEVICE *dptr;
5930 UNIT *uptr;
5931 t_stat r;
5932 
5933 GET_SWITCHES (cptr);                                    /* get switches */
5934 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
5935     return SCPE_2FARG;
5936 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
5937 GET_SWITCHES (cptr);                                    /* get switches */
5938 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* now eol? */
5939     return SCPE_2FARG;
5940 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
5941 if (dptr == NULL)                                       /* found dev? */
5942     return SCPE_NXDEV;
5943 if (uptr == NULL)                                       /* valid unit? */
5944     return SCPE_NXUN;
5945 if (uptr->flags & UNIT_ATT) {                           /* already attached? */
5946     if (!(uptr->dynflags & UNIT_ATTMULT) &&             /* and only single attachable */
5947         !(dptr->flags & DEV_DONTAUTO)) {                /* and auto detachable */
5948         r = scp_detach_unit (dptr, uptr);               /* detach it */
5949         if (r != SCPE_OK)                               /* error? */
5950             return r; }
5951     else {
5952         if (!(uptr->dynflags & UNIT_ATTMULT))
5953             return SCPE_ALATT;                          /* Already attached */
5954         }
5955     }
5956 gbuf[sizeof(gbuf)-1] = '\0';
5957 strncpy (gbuf, cptr, sizeof(gbuf)-1);
5958 sim_trim_endspc (gbuf);                                 /* trim trailing spc */
5959 return scp_attach_unit (dptr, uptr, gbuf);              /* attach */
5960 }
5961 
5962 /* Call device-specific or file-oriented attach unit routine */
5963 
5964 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5965 {
5966 if (dptr->attach != NULL)                               /* device routine? */
5967     return dptr->attach (uptr, (CONST char *)cptr);     /* call it */
5968 return attach_unit (uptr, (CONST char *)cptr);          /* no, std routine */
5969 }
5970 
5971 /* Attach unit to file */
5972 
5973 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5974 {
5975 DEVICE *dptr;
5976 
5977 if (uptr->flags & UNIT_DIS)                             /* disabled? */
5978     return SCPE_UDIS;
5979 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
5980     return SCPE_NOATT;
5981 if ((dptr = find_dev_from_unit (uptr)) == NULL)
5982     return SCPE_NOATT;
5983 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */
5984 if (uptr->filename == NULL)
5985     return SCPE_MEM;
5986 strncpy (uptr->filename, cptr, CBUFSIZE-1);             /* save name */
5987 if ((sim_switches & SWMASK ('R')) ||                    /* read only? */
5988     ((uptr->flags & UNIT_RO) != 0)) {
5989     if (((uptr->flags & UNIT_ROABLE) == 0) &&           /* allowed? */
5990         ((uptr->flags & UNIT_RO) == 0))
5991         return attach_err (uptr, SCPE_NORO);            /* no, error */
5992     uptr->fileref = sim_fopen (cptr, "rb");             /* open rd only */
5993     if (uptr->fileref == NULL)                          /* open fail? */
5994         return attach_err (uptr, SCPE_OPENERR);         /* yes, error */
5995     uptr->flags = uptr->flags | UNIT_RO;                /* set rd only */
5996     if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
5997         sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
5998         }
5999     }
6000 else {
6001     if (sim_switches & SWMASK ('N')) {                  /* new file only? */
6002         uptr->fileref = sim_fopen (cptr, "wb+");        /* open new file */
6003         if (uptr->fileref == NULL)                      /* open fail? */
6004             return attach_err (uptr, SCPE_OPENERR);     /* yes, error */
6005         if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6006             sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
6007             }
6008         }
6009     else {                                              /* normal */
6010         uptr->fileref = sim_fopen (cptr, "rb+");        /* open r/w */
6011         if (uptr->fileref == NULL) {                    /* open fail? */
6012 #if defined(EWOULDBLOCK)
6013             if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6014 #else
6015             if ((errno == EAGAIN))
6016 #endif
6017                 return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6018 
6019 #if defined(EPERM)
6020             if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {/* read only? */
6021 #else
6022             if ((errno == EROFS) || (errno == EACCES)) {/* read only? */
6023 #endif
6024                 if ((uptr->flags & UNIT_ROABLE) == 0)   /* allowed? */
6025                     return attach_err (uptr, SCPE_NORO);/* no error */
6026                 uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */
6027                 if (uptr->fileref == NULL)              /* open fail? */
6028                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6029                 uptr->flags = uptr->flags | UNIT_RO;    /* set rd only */
6030                 if (!sim_quiet) {
6031                     sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
6032                     }
6033                 }
6034             else {                                      /* doesn't exist */
6035                 if (sim_switches & SWMASK ('E'))        /* must exist? */
6036                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6037                 uptr->fileref = sim_fopen (cptr, "wb+");/* open new file */
6038                 if (uptr->fileref == NULL)              /* open fail? */
6039                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6040                 if (!sim_quiet) {
6041                     sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
6042                     }
6043                 }
6044             }                                           /* end if null */
6045         }                                               /* end else */
6046     }
6047 if (uptr->flags & UNIT_BUFABLE) {                       /* buffer? */
6048     uint32 cap = ((uint32) uptr->capac) / dptr->aincr;  /* effective size */
6049     if (uptr->flags & UNIT_MUSTBUF)                     /* dyn alloc? */
6050         uptr->filebuf = calloc (cap, SZ_D (dptr));      /* allocate */
6051     if (uptr->filebuf == NULL)                          /* no buffer? */
6052         return attach_err (uptr, SCPE_MEM);             /* error */
6053     if (!sim_quiet) {
6054         sim_printf ("%s: buffering file in memory\n", sim_dname (dptr));
6055         }
6056     uptr->hwmark = (uint32)sim_fread (uptr->filebuf,    /* read file */
6057         SZ_D (dptr), cap, uptr->fileref);
6058     uptr->flags = uptr->flags | UNIT_BUF;               /* set buffered */
6059     }
6060 uptr->flags = uptr->flags | UNIT_ATT;
6061 uptr->pos = 0;
6062 return SCPE_OK;
6063 }
6064 
6065 t_stat attach_err (UNIT *uptr, t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
6066 {
6067 FREE (uptr->filename);
6068 uptr->filename = NULL;
6069 return stat;
6070 }
6071 
6072 /* Detach command */
6073 
6074 t_stat detach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6075 {
6076 char gbuf[CBUFSIZE];
6077 DEVICE *dptr;
6078 UNIT *uptr;
6079 
6080 GET_SWITCHES (cptr);                                    /* get switches */
6081 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6082     return SCPE_2FARG;
6083 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6084 if (*cptr != 0)                                         /* now eol? */
6085     return SCPE_2MARG;
6086 if (strcmp (gbuf, "ALL") == 0)
6087     return (detach_all (0, FALSE));
6088 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6089 if (dptr == NULL)                                       /* found dev? */
6090     return SCPE_NXDEV;
6091 if (uptr == NULL)                                       /* valid unit? */
6092     return SCPE_NXUN;
6093 return scp_detach_unit (dptr, uptr);                    /* detach */
6094 }
6095 
6096 /* Detach devices start..end
6097 
6098    Inputs:
6099         start   =       number of starting device
6100         shutdown =      TRUE if simulator shutting down
6101    Outputs:
6102         status  =       error status
6103 
6104    Note that during shutdown, detach routines for non-attachable devices
6105    will be called.  These routines can implement simulator shutdown.  Error
6106    returns during shutdown are ignored.
6107 */
6108 
6109 t_stat detach_all (int32 start, t_bool shutdown)
     /* [previous][next][first][last][top][bottom][index][help] */
6110 {
6111 uint32 i, j;
6112 DEVICE *dptr;
6113 UNIT *uptr;
6114 t_stat r;
6115 
6116 if ((start < 0) || (start > 1))
6117     return SCPE_IERR;
6118 if (shutdown)
6119     sim_switches = sim_switches | SIM_SW_SHUT;          /* flag shutdown */
6120 for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
6121     for (j = 0; j < dptr->numunits; j++) {              /* loop thru units */
6122         uptr = (dptr->units) + j;
6123         if ((uptr->flags & UNIT_ATT) ||                 /* attached? */
6124             (shutdown && dptr->detach &&                /* shutdown, spec rtn, */
6125             !(uptr->flags & UNIT_ATTABLE))) {           /* !attachable? */
6126             r = scp_detach_unit (dptr, uptr);           /* detach unit */
6127 
6128             if ((r != SCPE_OK) && !shutdown)            /* error and not shutting down? */
6129                 return r;                               /* bail out now with error status */
6130             }
6131         }
6132     }
6133 return SCPE_OK;
6134 }
6135 
6136 /* Call device-specific or file-oriented detach unit routine */
6137 
6138 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6139 {
6140 if (dptr->detach != NULL)                               /* device routine? */
6141     return dptr->detach (uptr);
6142 return detach_unit (uptr);                              /* no, standard */
6143 }
6144 
6145 /* Detach unit from file */
6146 
6147 t_stat detach_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6148 {
6149 DEVICE *dptr;
6150 
6151 if (uptr == NULL)
6152     return SCPE_IERR;
6153 if (!(uptr->flags & UNIT_ATTABLE))                      /* attachable? */
6154     return SCPE_NOATT;
6155 if (!(uptr->flags & UNIT_ATT)) {                        /* not attached? */
6156     if (sim_switches & SIM_SW_REST)                     /* restoring? */
6157         return SCPE_OK;                                 /* allow detach */
6158     else
6159         return SCPE_NOTATT;                             /* complain */
6160     }
6161 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6162     return SCPE_OK;
6163 if (uptr->flags & UNIT_BUF) {
6164     uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6165     if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6166         if (!sim_quiet) {
6167             sim_printf ("%s: writing buffer to file\n", sim_dname (dptr));
6168             }
6169         rewind (uptr->fileref);
6170         sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6171         if (ferror (uptr->fileref))
6172             sim_printf ("%s: I/O error - %s (Error %d)",
6173                         sim_dname (dptr), xstrerror_l(errno), errno);
6174         }
6175     if (uptr->flags & UNIT_MUSTBUF) {                   /* dyn alloc? */
6176         FREE (uptr->filebuf);                           /* free buf */
6177         uptr->filebuf = NULL;
6178         }
6179     uptr->flags = uptr->flags & ~UNIT_BUF;
6180     }
6181 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6182 FREE (uptr->filename);
6183 uptr->filename = NULL;
6184 if (fclose (uptr->fileref) == EOF)
6185     return SCPE_IOERR;
6186 return SCPE_OK;
6187 }
6188 
6189 /* Get device display name */
6190 
6191 const char *sim_dname (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6192 {
6193 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6194 }
6195 
6196 /* Get unit display name */
6197 
6198 const char *sim_uname (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6199 {
6200 DEVICE *d = find_dev_from_unit(uptr);
6201 static char uname[CBUFSIZE];
6202 
6203 if (!d)
6204     return "";
6205 if (d->numunits == 1)
6206     return sim_dname (d);
6207 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6208 return uname;
6209 }
6210 
6211 /* Run, go, boot, cont, step, next commands */
6212 
6213 t_stat run_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6214 {
6215 char gbuf[CBUFSIZE] = "";
6216 CONST char *tptr;
6217 uint32 i, j;
6218 int32 sim_next = 0;
6219 int32 unitno;
6220 t_value pcv, orig_pcv;
6221 t_stat r;
6222 DEVICE *dptr;
6223 UNIT *uptr;
6224 
6225 GET_SWITCHES (cptr);                                    /* get switches */
6226 sim_step = 0;
6227 if ((flag == RU_RUN) || (flag == RU_GO)) {              /* run or go */
6228     orig_pcv = get_rval (sim_PC, 0);                    /* get current PC value */
6229     if (*cptr != 0) {                                   /* argument? */
6230         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6231         if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6232             if (sim_dflt_dev && sim_vm_parse_addr)      /* address parser? */
6233                 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6234             else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */
6235             if ((tptr == gbuf) || (*tptr != 0) ||       /* error? */
6236                 (pcv > width_mask[sim_PC->width]))
6237                 return SCPE_ARG;
6238             put_rval (sim_PC, 0, pcv);                  /* Save in PC */
6239             }
6240         }
6241     if ((flag == RU_RUN) &&                             /* run? */
6242         ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {  /* reset sim */
6243         put_rval (sim_PC, 0, orig_pcv);                 /* restore original PC */
6244         return r;
6245         }
6246     if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) { //-V600 /* should be end */
6247         int32 saved_switches = sim_switches;
6248 
6249         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6250             cptr = get_glyph (cptr, gbuf, 0);           /* get next glyph */
6251         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6252             return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\n",
6253                                              (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6254         sim_switches = 0;
6255         GET_SWITCHES (cptr);
6256         if ((*cptr == '\'') || (*cptr == '"')) {        /* Expect UNTIL condition */
6257             r = expect_cmd (1, cptr);
6258             if (r != SCPE_OK)
6259                 return r;
6260             }
6261         else {                                          /* BREAK UNTIL condition */
6262             if (sim_switches == 0)
6263                 sim_switches = sim_brk_dflt;
6264             sim_switches |= BRK_TYP_TEMP;               /* make this a one-shot breakpoint */
6265             sim_brk_types |= BRK_TYP_TEMP;
6266             r = ssh_break (NULL, cptr, SSH_ST);
6267             if (r != SCPE_OK)
6268                 return sim_messagef (r, "Unable to establish breakpoint at: %s\n", cptr);
6269             }
6270         sim_switches = saved_switches;
6271         }
6272     }
6273 
6274 else if ((flag == RU_STEP) ||
6275          ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) { /* step */
6276     static t_bool not_implemented_message = FALSE;
6277 
6278     if ((!not_implemented_message) && (flag == RU_NEXT)) {
6279         not_implemented_message = TRUE;
6280         flag = RU_STEP;
6281         }
6282     if (*cptr != 0) {                                   /* argument? */
6283         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6284         if (*cptr != 0)                                 /* should be end */
6285             return SCPE_2MARG;
6286         sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6287         if ((r != SCPE_OK) || (sim_step <= 0))          /* error? */
6288             return SCPE_ARG;
6289         }
6290     else sim_step = 1;
6291     if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6292         sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6293     }
6294 else if (flag == RU_NEXT) {                             /* next */
6295     t_addr *addrs;
6296 
6297     if (*cptr != 0) {                                   /* argument? */
6298         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6299         if (*cptr != 0)                                 /* should be end */
6300             return SCPE_2MARG;
6301         sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6302         if ((r != SCPE_OK) || (sim_next <= 0))          /* error? */
6303             return SCPE_ARG;
6304         }
6305     else sim_next = 1;
6306     if (sim_vm_is_subroutine_call(&addrs)) {
6307         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6308         for (i=0; addrs[i]; i++)
6309             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6310         }
6311     else
6312         sim_step = 1;
6313     }
6314 else if (flag == RU_BOOT) {                             /* boot */
6315     if (*cptr == 0)                                     /* must be more */
6316         return SCPE_2FARG;
6317     cptr = get_glyph (cptr, gbuf, 0);                   /* get next glyph */
6318     if (*cptr != 0)                                     /* should be end */
6319         return SCPE_2MARG;
6320     dptr = find_unit (gbuf, &uptr);                     /* locate unit */
6321     if (dptr == NULL)                                   /* found dev? */
6322         return SCPE_NXDEV;
6323     if (uptr == NULL)                                   /* valid unit? */
6324         return SCPE_NXUN;
6325     if (dptr->boot == NULL)                             /* can it boot? */
6326         return SCPE_NOFNC;
6327     if (uptr->flags & UNIT_DIS)                         /* disabled? */
6328         return SCPE_UDIS;
6329     if ((uptr->flags & UNIT_ATTABLE) &&                 /* if attable, att? */
6330         !(uptr->flags & UNIT_ATT))
6331         return SCPE_UNATT;
6332     unitno = (int32) (uptr - dptr->units);              /* recover unit# */
6333     if ((r = sim_run_boot_prep (flag)) != SCPE_OK)      /* reset sim */
6334         return r;
6335     if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)     /* boot device */
6336         return r;
6337     }
6338 
6339 else
6340     if (flag != RU_CONT)                                /* must be cont */
6341         return SCPE_IERR;
6342     else                                                /* CONTINUE command */
6343         if (*cptr != 0)                                 /* should be end (no arguments allowed) */
6344             return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\n");
6345 
6346 if (sim_switches & SIM_SW_HIDE)                         /* Setup only for Remote Console Mode */
6347     return SCPE_OK;
6348 
6349 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* reposition all */
6350     for (j = 0; j < dptr->numunits; j++) {              /* seq devices */
6351         uptr = dptr->units + j;
6352         if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6353             sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6354         }
6355     }
6356 stop_cpu = 0;
6357 sim_is_running = 1;                                     /* flag running */
6358 if (sim_ttrun () != SCPE_OK) {                          /* set console mode */
6359     sim_is_running = 0;                                 /* flag idle */
6360     sim_ttcmd ();
6361     return SCPE_TTYERR;
6362     }
6363 if ((r = sim_check_console (30)) != SCPE_OK) {          /* check console, error? */
6364     sim_is_running = 0;                                 /* flag idle */
6365     sim_ttcmd ();
6366     return r;
6367     }
6368 #if !defined(IS_WINDOWS)
6369 # if defined(SIGINT)
6370 if (signal (SIGINT, int_handler) == SIG_ERR) {          /* set WRU */
6371     sim_is_running = 0;                                 /* flag idle */
6372     sim_ttcmd ();
6373     return SCPE_SIGERR;
6374     }
6375 # endif
6376 #endif
6377 #if !defined(IS_WINDOWS)
6378 # if defined(SIGHUP)
6379 if (signal (SIGHUP, int_handler) == SIG_ERR) {          /* set WRU */
6380     sim_is_running = 0;                                 /* flag idle */
6381     sim_ttcmd ();
6382     return SCPE_SIGERR;
6383     }
6384 # endif
6385 #endif
6386 #if !defined(IS_WINDOWS)
6387 # if defined(SIGTERM)
6388 if (signal (SIGTERM, int_handler) == SIG_ERR) {         /* set WRU */
6389     sim_is_running = 0;                                 /* flag idle */
6390     sim_ttcmd ();
6391     return SCPE_SIGERR;
6392     }
6393 # endif
6394 #endif
6395 if (sim_step)                                           /* set step timer */
6396     sim_activate (&sim_step_unit, sim_step);
6397 (void)fflush(stdout);                                   /* flush stdout */
6398 if (sim_log)                                            /* flush log if enabled */
6399     (void)fflush (sim_log);
6400 sim_rtcn_init_all ();                                   /* re-init clocks */
6401 sim_start_timer_services ();                            /* enable wall clock timing */
6402 
6403 do {
6404     t_addr *addrs;
6405 
6406     while (1) {
6407         r = sim_instr();
6408         if (r != SCPE_REMOTE)
6409             break;
6410         sim_remote_process_command ();                  /* Process the command and resume processing */
6411         }
6412     if ((flag != RU_NEXT) ||                            /* done if not doing NEXT */
6413         (--sim_next <=0))
6414         break;
6415     if (sim_step == 0) {                                /* doing a NEXT? */
6416         t_addr val;
6417         BRKTAB *bp;
6418 
6419         if (SCPE_BARE_STATUS(r) >= SCPE_BASE)           /* done if an error occurred */
6420             break;
6421         if (sim_vm_pc_value)                            /* done if didn't stop at a dynamic breakpoint */
6422             val = (t_addr)(*sim_vm_pc_value)();
6423         else
6424             val = (t_addr)get_rval (sim_PC, 0);
6425         if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6426             break;
6427         sim_brk_clrall (BRK_TYP_DYN_STEPOVER);          /* cancel any step/over subroutine breakpoints */
6428         }
6429     else {
6430         if (r != SCPE_STEP)                             /* done if step didn't complete with step expired */
6431             break;
6432         }
6433     /* setup another next/step */
6434     sim_step = 0;
6435     if (sim_vm_is_subroutine_call(&addrs)) {
6436         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6437         for (i=0; addrs[i]; i++)
6438             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6439         }
6440     else
6441         sim_step = 1;
6442     if (sim_step)                                       /* set step timer */
6443         sim_activate (&sim_step_unit, sim_step);
6444     } while (1);
6445 
6446 sim_is_running = 0;                                     /* flag idle */
6447 sim_stop_timer_services ();                             /* disable wall clock timing */
6448 sim_ttcmd ();                                           /* restore console */
6449 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);                  /* cancel any step/over subroutine breakpoints */
6450 signal (SIGINT, SIG_DFL);                               /* cancel WRU */
6451 #if defined(SIGHUP)
6452 signal (SIGHUP, SIG_DFL);                               /* cancel WRU */
6453 #endif
6454 signal (SIGTERM, SIG_DFL);                              /* cancel WRU */
6455 if (sim_log)                                            /* flush console log */
6456     (void)fflush (sim_log);
6457 if (sim_deb)                                            /* flush debug log */
6458     sim_debug_flush ();
6459 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* flush attached files */
6460     for (j = 0; j < dptr->numunits; j++) {              /* if not buffered in mem */
6461         uptr = dptr->units + j;
6462         if (uptr->flags & UNIT_ATT) {                   /* attached, */
6463             if (uptr->io_flush)                         /* unit specific flush routine */
6464                 uptr->io_flush (uptr);                  /* call it */
6465             else {
6466                 if (!(uptr->flags & UNIT_BUF) &&        /* not buffered, */
6467                     (uptr->fileref) &&                  /* real file, */
6468                     !(uptr->dynflags & UNIT_NO_FIO) &&  /* is FILE *, */
6469                     !(uptr->flags & UNIT_RO))           /* not read only? */
6470                     (void)fflush (uptr->fileref);
6471                 }
6472             }
6473         }
6474     }
6475 sim_cancel (&sim_step_unit);                            /* cancel step timer */
6476 UPDATE_SIM_TIME;                                        /* update sim time */
6477 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6478 }
6479 
6480 /* run command message handler */
6481 
6482 void
6483 run_cmd_message (const char *unechoed_cmdline, t_stat r)
     /* [previous][next][first][last][top][bottom][index][help] */
6484 {
6485 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6486     sim_printf("%s> %s\n", do_position(), unechoed_cmdline);
6487 #if defined(WIN_STDIO)
6488 (void)fflush(stderr);
6489 (void)fflush(stdout);
6490 #endif /* if defined(WIN_STDIO) */
6491 fprint_stopped (stdout, r);                         /* print msg */
6492 if (sim_log && (sim_log != stdout))                 /* log if enabled */
6493     fprint_stopped (sim_log, r);
6494 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))/* debug if enabled */
6495     fprint_stopped (sim_deb, r);
6496 #if defined(WIN_STDIO)
6497 (void)fflush(stderr);
6498 (void)fflush(stdout);
6499 #endif /* if defined(WIN_STDIO) */
6500 }
6501 
6502 /* Common setup for RUN or BOOT */
6503 
6504 t_stat sim_run_boot_prep (int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
6505 {
6506 UNIT *uptr;
6507 t_stat r;
6508 
6509 sim_interval = 0;                                       /* reset queue */
6510 sim_time = sim_rtime = 0;
6511 noqueue_time = 0;
6512 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6513     sim_clock_queue = uptr->next;
6514     uptr->next = NULL;
6515     }
6516 r = reset_all (0);
6517 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6518     if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6519         sim_printf ("Resetting all devices...  This may not have been your intention.\n");
6520         sim_printf ("The GO and CONTINUE commands do not reset devices.\n");
6521         }
6522     run_cmd_did_reset = TRUE;
6523     }
6524 return r;
6525 }
6526 
6527 /* Print stopped message
6528  * For VM stops, if a VM-specific "sim_vm_fprint_stopped" pointer is defined,
6529  * call the indicated routine to print additional information after the message
6530  * and before the PC value is printed.  If the routine returns FALSE, skip
6531  * printing the PC and its related instruction.
6532  */
6533 
6534 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6535 {
6536 int32 i;
6537 t_stat r = 0;
6538 t_addr k;
6539 t_value pcval;
6540 
6541 fputc ('\n', st);                                       /* start on a new line */
6542 
6543 if (v >= SCPE_BASE)                                     /* SCP error? */
6544     fputs (sim_error_text (v), st);                     /* print it from the SCP list */
6545 else {                                                  /* VM error */
6546     fputs (sim_stop_messages [v], st);                  /* print the VM-specific message */
6547 
6548     if ((sim_vm_fprint_stopped != NULL) &&              /* if a VM-specific stop handler is defined */
6549         (!sim_vm_fprint_stopped (st, v)))               /*   call it; if it returned FALSE, */
6550         return;                                         /*     we're done */
6551     }
6552 
6553 (void)fprintf (st, ", %s: ", pc->name);                       /* print the name of the PC register */
6554 
6555 pcval = get_rval (pc, 0);
6556 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)       /* if reg wants VM-specific printer */
6557     sim_vm_fprint_addr (st, dptr, (t_addr) pcval);      /*   call it to print the PC address */
6558 else fprint_val (st, pcval, pc->radix, pc->width,       /* otherwise, print as a numeric value */
6559     pc->flags & REG_FMT);                               /*   with the radix and formatting specified */
6560 if ((dptr != NULL) && (dptr->examine != NULL)) {
6561     for (i = 0; i < sim_emax; i++)
6562         sim_eval[i] = 0;
6563     for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6564         if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6565             break;
6566         }
6567     if ((r == SCPE_OK) || (i > 0)) {
6568         (void)fprintf (st, " (");
6569         if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6570             fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6571         (void)fprintf (st, ")");
6572         }
6573     }
6574 (void)fprintf (st, "\n");
6575 return;
6576 }
6577 
6578 void fprint_stopped (FILE *st, t_stat v)
     /* [previous][next][first][last][top][bottom][index][help] */
6579 {
6580 #if defined(WIN_STDIO)
6581 (void)fflush(stderr);
6582 (void)fflush(stdout);
6583 #endif /* if defined(WIN_STDIO) */
6584 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6585 return;
6586 }
6587 
6588 /* Unit service for step timeout, originally scheduled by STEP n command
6589    Return step timeout SCP code, will cause simulation to stop */
6590 
6591 t_stat step_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6592 {
6593 return SCPE_STEP;
6594 }
6595 
6596 /* Unit service to facilitate expect matching to stop simulation.
6597    Return expect SCP code, will cause simulation to stop */
6598 
6599 t_stat expect_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6600 {
6601 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6602 }
6603 
6604 /* Signal handler for ^C signal - set stop simulation flag */
6605 
6606 void int_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
6607 {
6608 stop_cpu = 1;
6609 return;
6610 }
6611 
6612 /* Examine/deposit commands */
6613 
6614 t_stat exdep_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6615 {
6616 char gbuf[CBUFSIZE];
6617 CONST char *gptr;
6618 CONST char *tptr = NULL;
6619 int32 opt;
6620 t_addr low, high;
6621 t_stat reason = SCPE_IERR;
6622 DEVICE *tdptr;
6623 REG *lowr, *highr;
6624 FILE *ofile;
6625 
6626 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;               /* options for all */
6627 if (flag == EX_E)                                       /* extra for EX */
6628     opt = opt | CMD_OPT_OF;
6629 cptr = get_sim_opt (opt, cptr, &reason);                /* get cmd options */
6630 if (NULL == cptr)                                       /* error? */
6631     return reason;
6632 if (*cptr == 0)                                         /* must be more */
6633     return SCPE_2FARG;
6634 if (sim_dfunit == NULL)                                 /* got a unit? */
6635     return SCPE_NXUN;
6636 cptr = get_glyph (cptr, gbuf, 0);                       /* get list */
6637 if ((flag == EX_D) && (*cptr == 0))                     /* deposit needs more */
6638 
6639     return SCPE_2FARG;
6640 ofile = sim_ofile? sim_ofile: stdout;                   /* no ofile? use stdout */
6641 
6642 for (gptr = gbuf, reason = SCPE_OK;
6643     (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6644     tdptr = sim_dfdev;                                  /* working dptr */
6645     if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6646         tptr = gptr + strlen ("STATE");
6647         if (*tptr && (*tptr++ != ','))
6648             return SCPE_ARG;
6649         if ((lowr = sim_dfdev->registers) == NULL)
6650             return SCPE_NXREG;
6651         for (highr = lowr; highr->name != NULL; highr++) ;
6652         sim_switches = sim_switches | SIM_SW_HIDE;
6653         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6654             lowr, --highr, 0, 0);
6655         continue;
6656         }
6657 
6658     /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
6659     if ((lowr = find_reg (gptr, &tptr, tdptr)) ||       /* local reg or */
6660         (!(sim_opt_out & CMD_OPT_DFT) &&                /* no dflt, global? */
6661         (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6662         low = high = 0;
6663         if ((*tptr == '-') || (*tptr == ':')) {
6664             highr = find_reg (tptr + 1, &tptr, tdptr);
6665             if (highr == NULL)
6666                 return SCPE_NXREG;
6667             }
6668         else {
6669             highr = lowr;
6670             if (*tptr == '[') {
6671                 if (lowr->depth <= 1)
6672                     return SCPE_ARG;
6673                 tptr = get_range (NULL, tptr + 1, &low, &high,
6674                     10, lowr->depth - 1, ']');
6675                 if (tptr == NULL)
6676                     return SCPE_ARG;
6677                 }
6678             }
6679         if (*tptr && (*tptr++ != ','))
6680             return SCPE_ARG;
6681         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6682             lowr, highr, (uint32) low, (uint32) high);
6683         continue;
6684         }
6685 
6686     tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6687         (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6688         sim_dfunit->capac - sim_dfdev->aincr), 0);
6689     if (tptr == NULL)
6690         return SCPE_ARG;
6691     if (*tptr && (*tptr++ != ','))
6692         return SCPE_ARG;
6693     reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6694         sim_dfdev, sim_dfunit);
6695     }                                                   /* end for */
6696 if (sim_ofile)                                          /* close output file */
6697     fclose (sim_ofile);
6698 return reason;
6699 }
6700 
6701 /* Loop controllers for examine/deposit
6702 
6703    exdep_reg_loop       examine/deposit range of registers
6704    exdep_addr_loop      examine/deposit range of addresses
6705 */
6706 
6707 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6708     REG *lowr, REG *highr, uint32 lows, uint32 highs)
6709 {
6710 t_stat reason;
6711 uint32 idx, val_start=lows;
6712 t_value val, last_val;
6713 REG *rptr;
6714 
6715 if ((lowr == NULL) || (highr == NULL))
6716     return SCPE_IERR;
6717 if (lowr > highr)
6718     return SCPE_ARG;
6719 for (rptr = lowr; rptr <= highr; rptr++) {
6720     if ((sim_switches & SIM_SW_HIDE) &&
6721         (rptr->flags & REG_HIDDEN))
6722         continue;
6723     val = last_val = 0;
6724     for (idx = lows; idx <= highs; idx++) {
6725         if (idx >= rptr->depth)
6726             return SCPE_SUB;
6727         val = get_rval (rptr, idx);
6728         if (schptr && !test_search (&val, schptr))
6729             continue;
6730         if (flag == EX_E) {
6731             if ((idx > lows) && (val == last_val))
6732                 continue;
6733             if (idx > val_start+1) {
6734                 if (idx-1 == val_start+1) {
6735                     reason = ex_reg (ofile, val, flag, rptr, idx-1);
6736                     if (reason != SCPE_OK)
6737                         return reason;
6738                     if (sim_log && (ofile == stdout))
6739                         ex_reg (sim_log, val, flag, rptr, idx-1);
6740                     }
6741                 else {
6742                     if (val_start+1 != idx-1) {
6743                         (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6744                         if (sim_log && (ofile == stdout))
6745                             (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6746                         }
6747                     else {
6748                         (void)Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6749                         if (sim_log && (ofile == stdout))
6750                             (void)Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6751                         }
6752                     }
6753                 }
6754             sim_last_val = last_val = val;
6755             val_start = idx;
6756             reason = ex_reg (ofile, val, flag, rptr, idx);
6757             if (reason != SCPE_OK)
6758                 return reason;
6759             if (sim_log && (ofile == stdout))
6760                 ex_reg (sim_log, val, flag, rptr, idx);
6761             }
6762         if (flag != EX_E) {
6763             reason = dep_reg (flag, cptr, rptr, idx);
6764             if (reason != SCPE_OK)
6765                 return reason;
6766             }
6767         }
6768     if ((flag == EX_E) && (val_start != highs)) {
6769         if (highs == val_start+1) {
6770             reason = ex_reg (ofile, val, flag, rptr, highs);
6771             if (reason != SCPE_OK)
6772                 return reason;
6773             if (sim_log && (ofile == stdout))
6774                 ex_reg (sim_log, val, flag, rptr, highs);
6775             }
6776         else {
6777             if (val_start+1 != highs) {
6778                 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6779                 if (sim_log && (ofile == stdout))
6780                     (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6781                 }
6782             else {
6783                 (void)Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6784                 if (sim_log && (ofile == stdout))
6785                     (void)Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6786                 }
6787             }
6788         }
6789     }
6790 return SCPE_OK;
6791 }
6792 
6793 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6794     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6795 {
6796 t_addr i, mask;
6797 t_stat reason;
6798 
6799 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6800     return SCPE_UDIS;
6801 mask = (t_addr) width_mask[dptr->awidth];
6802 if ((low > mask) || (high > mask) || (low > high))
6803     return SCPE_ARG;
6804 for (i = low; i <= high; ) {                            /* all paths must incr!! */
6805     reason = get_aval (i, dptr, uptr);                  /* get data */
6806     if (reason != SCPE_OK)                              /* return if error */
6807         return reason;
6808     if (schptr && !test_search (sim_eval, schptr))
6809         i = i + dptr->aincr;                            /* sch fails, incr */
6810     else {                                              /* no sch or success */
6811         if (flag != EX_D) {                             /* ex, ie, or id? */
6812             reason = ex_addr (ofile, flag, i, dptr, uptr);
6813             if (reason > SCPE_OK)
6814                 return reason;
6815             if (sim_log && (ofile == stdout))
6816                 ex_addr (sim_log, flag, i, dptr, uptr);
6817             }
6818         else reason = 1 - dptr->aincr;                  /* no, dflt incr */
6819         if (flag != EX_E) {                             /* ie, id, or d? */
6820             reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
6821             if (reason > SCPE_OK)
6822                 return reason;
6823             }
6824         i = i + (1 - reason);                           /* incr */
6825         }
6826     }
6827 return SCPE_OK;
6828 }
6829 
6830 /* Examine register routine
6831 
6832    Inputs:
6833         ofile   =       output stream
6834         val     =       current register value
6835         flag    =       type of ex/mod command (ex, iex, idep)
6836         rptr    =       pointer to register descriptor
6837         idx     =       index
6838    Outputs:
6839         return  =       error status
6840 */
6841 
6842 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
6843 {
6844 int32 rdx;
6845 
6846 if (rptr == NULL)
6847     return SCPE_IERR;
6848 if (rptr->depth > 1)
6849     (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
6850 else
6851     (void)Fprintf (ofile, "%s:\t", rptr->name);
6852 if (!(flag & EX_E))
6853     return SCPE_OK;
6854 GET_RADIX (rdx, rptr->radix);
6855 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
6856     sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
6857 else if (!(rptr->flags & REG_VMFLAGS) ||
6858     (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
6859                  NULL, sim_switches | SIM_SW_REG) > 0)) {
6860         fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
6861         if (rptr->fields) {
6862             (void)Fprintf (ofile, "\t");
6863             fprint_fields (ofile, val, val, rptr->fields);
6864             }
6865         }
6866 if (flag & EX_I)
6867     (void)Fprintf (ofile, "\t");
6868 else
6869     (void)Fprintf (ofile, "\n");
6870 return SCPE_OK;
6871 }
6872 
6873 /* Get register value
6874 
6875    Inputs:
6876         rptr    =       pointer to register descriptor
6877         idx     =       index
6878    Outputs:
6879         return  =       register value
6880 */
6881 
6882 t_value get_rval (REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
6883 {
6884 size_t sz;
6885 t_value val;
6886 uint32 *ptr;
6887 
6888 sz = SZ_R (rptr);
6889 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
6890     idx = idx + rptr->qptr;
6891     if (idx >= rptr->depth) idx = idx - rptr->depth;
6892     }
6893 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
6894     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
6895     if (sz <= sizeof (uint32))
6896         val = *ptr;
6897     else val = *((t_uint64 *) ptr); //-V1032
6898     }
6899 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
6900     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
6901     if (sz <= sizeof (uint32))
6902         val = *ptr;
6903     else val = *((t_uint64 *) ptr);
6904     }
6905 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
6906     (sz == sizeof (uint8)))
6907     val = *(((uint8 *) rptr->loc) + idx);
6908 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
6909     (sz == sizeof (uint16)))
6910     val = *(((uint16 *) rptr->loc) + idx);
6911 else if (sz <= sizeof (uint32))
6912      val = *(((uint32 *) rptr->loc) + idx);
6913 else val = *(((t_uint64 *) rptr->loc) + idx);
6914 val = (val >> rptr->offset) & width_mask[rptr->width];
6915 return val;
6916 }
6917 
6918 /* Deposit register routine
6919 
6920    Inputs:
6921         flag    =       type of deposit (normal/interactive)
6922         cptr    =       pointer to input string
6923         rptr    =       pointer to register descriptor
6924         idx     =       index
6925    Outputs:
6926         return  =       error status
6927 */
6928 
6929 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
6930 {
6931 t_stat r;
6932 t_value val, mask;
6933 int32 rdx;
6934 CONST char *tptr;
6935 char gbuf[CBUFSIZE];
6936 
6937 if ((cptr == NULL) || (rptr == NULL))
6938     return SCPE_IERR;
6939 if (rptr->flags & REG_RO)
6940     return SCPE_RO;
6941 if (flag & EX_I) {
6942     cptr = read_line (gbuf, sizeof(gbuf), stdin);
6943     if (sim_log)
6944         (void)fprintf (sim_log, "%s\n", cptr? cptr: "");
6945     if (cptr == NULL)                                   /* force exit */
6946         return 1;
6947     if (*cptr == 0)                                     /* success */
6948         return SCPE_OK;
6949     }
6950 mask = width_mask[rptr->width];
6951 GET_RADIX (rdx, rptr->radix);
6952 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {    /* address form? */
6953     val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
6954     if ((tptr == cptr) || (*tptr != 0) || (val > mask))
6955         return SCPE_ARG;
6956     }
6957 else
6958     if (!(rptr->flags & REG_VMFLAGS) ||                 /* don't use sym? */
6959         (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
6960                     &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
6961     val = get_uint (cptr, rdx, mask, &r);
6962     if (r != SCPE_OK)
6963         return SCPE_ARG;
6964     }
6965 if ((rptr->flags & REG_NZ) && (val == 0))
6966     return SCPE_ARG;
6967 put_rval (rptr, idx, val);
6968 return SCPE_OK;
6969 }
6970 
6971 /* Put register value
6972 
6973    Inputs:
6974         rptr    =       pointer to register descriptor
6975         idx     =       index
6976         val     =       new value
6977         mask    =       mask
6978    Outputs:
6979         none
6980 */
6981 
6982 void put_rval (REG *rptr, uint32 idx, t_value val)
     /* [previous][next][first][last][top][bottom][index][help] */
6983 {
6984 size_t sz;
6985 t_value mask;
6986 uint32 *ptr;
6987 
6988 #define PUT_RVAL(sz,rp,id,v,m)            \
6989     *(((sz *) rp->loc) + id) =            \
6990         (sz)((*(((sz *) rp->loc) + id) &  \
6991             ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
6992 
6993 if (rptr == sim_PC)
6994     sim_brk_npc (0);
6995 sz = SZ_R (rptr);
6996 mask = width_mask[rptr->width];
6997 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
6998     idx = idx + rptr->qptr;
6999     if (idx >= rptr->depth)
7000         idx = idx - rptr->depth;
7001     }
7002 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7003     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7004     if (sz <= sizeof (uint32))
7005         *ptr = (*ptr &
7006         ~(((uint32) mask) << rptr->offset)) |
7007         (((uint32) val) << rptr->offset);
7008     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr) //-V1032
7009         & ~(mask << rptr->offset)) | (val << rptr->offset);
7010     }
7011 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7012     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7013     if (sz <= sizeof (uint32))
7014         *((uint32 *) ptr) = (*((uint32 *) ptr) &
7015         ~(((uint32) mask) << rptr->offset)) |
7016         (((uint32) val) << rptr->offset);
7017     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7018         & ~(mask << rptr->offset)) | (val << rptr->offset);
7019     }
7020 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7021     (sz == sizeof (uint8)))
7022     PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7023 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7024     (sz == sizeof (uint16)))
7025     PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7026 else if (sz <= sizeof (uint32))
7027     PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7028 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7029 return;
7030 }
7031 
7032 /* Examine address routine
7033 
7034    Inputs: (sim_eval is an implicit argument)
7035         ofile   =       output stream
7036         flag    =       type of ex/mod command (ex, iex, idep)
7037         addr    =       address to examine
7038         dptr    =       pointer to device
7039         uptr    =       pointer to unit
7040    Outputs:
7041         return  =       if > 0, error status
7042                         if <= 0,-number of extra addr units retired
7043 */
7044 
7045 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7046 {
7047 t_stat reason;
7048 int32 rdx;
7049 
7050 if (sim_vm_fprint_addr)
7051     sim_vm_fprint_addr (ofile, dptr, addr);
7052 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7053 (void)Fprintf (ofile, ":\t");
7054 if (!(flag & EX_E))
7055     return (1 - dptr->aincr);
7056 
7057 GET_RADIX (rdx, dptr->dradix);
7058 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7059     fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7060     reason = 1 - dptr->aincr;
7061     }
7062 if (flag & EX_I)
7063     (void)Fprintf (ofile, "\t");
7064 else
7065     (void)Fprintf (ofile, "\n");
7066 return reason;
7067 }
7068 
7069 /* Get address routine
7070 
7071    Inputs:
7072         flag    =       type of ex/mod command (ex, iex, idep)
7073         addr    =       address to examine
7074         dptr    =       pointer to device
7075         uptr    =       pointer to unit
7076    Outputs: (sim_eval is an implicit output)
7077         return  =       error status
7078 */
7079 
7080 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7081 {
7082 int32 i;
7083 t_value mask;
7084 t_addr j, loc;
7085 size_t sz;
7086 t_stat reason = SCPE_OK;
7087 
7088 if ((dptr == NULL) || (uptr == NULL))
7089     return SCPE_IERR;
7090 mask = width_mask[dptr->dwidth];
7091 for (i = 0; i < sim_emax; i++)
7092     sim_eval[i] = 0;
7093 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7094     if (dptr->examine != NULL) {
7095         reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7096         if (reason != SCPE_OK)
7097             break;
7098         }
7099     else {
7100         if (!(uptr->flags & UNIT_ATT))
7101             return SCPE_UNATT;
7102         if (uptr->dynflags & UNIT_NO_FIO)
7103             return SCPE_NOFNC;
7104         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7105             reason = SCPE_NXM;
7106             break;
7107             }
7108         sz = SZ_D (dptr);
7109         loc = j / dptr->aincr;
7110         if (uptr->flags & UNIT_BUF) {
7111             SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7112             }
7113         else {
7114             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7115             sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7116             if ((feof (uptr->fileref)) &&
7117                !(uptr->flags & UNIT_FIX)) {
7118                 reason = SCPE_EOF;
7119                 break;
7120                 }
7121             else if (ferror (uptr->fileref)) {
7122                 clearerr (uptr->fileref);
7123                 reason = SCPE_IOERR;
7124                 break;
7125                 }
7126             }
7127         }
7128     sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7129     }
7130 if ((reason != SCPE_OK) && (i == 0))
7131     return reason;
7132 return SCPE_OK;
7133 }
7134 
7135 /* Deposit address routine
7136 
7137    Inputs:
7138         flag    =       type of deposit (normal/interactive)
7139         cptr    =       pointer to input string
7140         addr    =       address to examine
7141         dptr    =       pointer to device
7142         uptr    =       pointer to unit
7143         dfltinc =       value to return on cr input
7144    Outputs:
7145         return  =       if > 0, error status
7146                         if <= 0, -number of extra address units retired
7147 */
7148 
7149 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
7150     UNIT *uptr, int32 dfltinc)
7151 {
7152 int32 i, count, rdx;
7153 t_addr j, loc;
7154 t_stat r, reason;
7155 t_value mask;
7156 size_t sz;
7157 char gbuf[CBUFSIZE];
7158 
7159 if (dptr == NULL)
7160     return SCPE_IERR;
7161 if (flag & EX_I) {
7162     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7163     if (sim_log)
7164         (void)fprintf (sim_log, "%s\n", cptr? cptr: "");
7165     if (cptr == NULL)                                   /* force exit */
7166         return 1;
7167     if (*cptr == 0)                                     /* success */
7168         return dfltinc;
7169     }
7170 if (uptr->flags & UNIT_RO)                              /* read only? */
7171     return SCPE_RO;
7172 mask = width_mask[dptr->dwidth];
7173 
7174 GET_RADIX (rdx, dptr->dradix);
7175 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7176     sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7177     if (reason != SCPE_OK)
7178         return reason;
7179     reason = dfltinc;
7180     }
7181 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7182 
7183 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7184     sim_eval[i] = sim_eval[i] & mask;
7185     if (dptr->deposit != NULL) {
7186         r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7187         if (r != SCPE_OK)
7188             return r;
7189         }
7190     else {
7191         if (!(uptr->flags & UNIT_ATT))
7192             return SCPE_UNATT;
7193         if (uptr->dynflags & UNIT_NO_FIO)
7194             return SCPE_NOFNC;
7195         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7196             return SCPE_NXM;
7197         sz = SZ_D (dptr);
7198         loc = j / dptr->aincr;
7199         if (uptr->flags & UNIT_BUF) {
7200             SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7201             if (loc >= uptr->hwmark)
7202                 uptr->hwmark = (uint32) loc + 1;
7203             }
7204         else {
7205             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7206             sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7207             if (ferror (uptr->fileref)) {
7208                 clearerr (uptr->fileref);
7209                 return SCPE_IOERR;
7210                 }
7211             }
7212         }
7213     }
7214 return reason;
7215 }
7216 
7217 /* Evaluate command */
7218 
7219 t_stat eval_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7220 {
7221 if (!sim_dflt_dev)
7222   return SCPE_ARG;
7223 DEVICE *dptr = sim_dflt_dev;
7224 int32 i, rdx, a, lim;
7225 t_stat r;
7226 
7227 GET_SWITCHES (cptr);
7228 GET_RADIX (rdx, dptr->dradix);
7229 for (i = 0; i < sim_emax; i++)
7230 sim_eval[i] = 0;
7231 if (*cptr == 0)
7232     return SCPE_2FARG;
7233 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7234     sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7235     if (r != SCPE_OK)
7236         return r;
7237     }
7238 lim = 1 - r;
7239 for (i = a = 0; a < lim; ) {
7240     sim_printf ("%d:\t", a);
7241     if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7242         r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7243     if (sim_log) {
7244         if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7245             r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7246         }
7247     sim_printf ("\n");
7248     if (r < 0)
7249         a = a + 1 - r;
7250     else a = a + dptr->aincr;
7251     i = a / dptr->aincr;
7252     }
7253 return SCPE_OK;
7254 }
7255 
7256 /* String processing routines
7257 
7258    read_line            read line
7259 
7260    Inputs:
7261         cptr    =       pointer to buffer
7262         size    =       maximum size
7263         stream  =       pointer to input stream
7264    Outputs:
7265         optr    =       pointer to first non-blank character
7266                         NULL if EOF
7267 */
7268 
7269 char *read_line (char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7270 {
7271 return read_line_p (NULL, cptr, size, stream);
7272 }
7273 
7274 /* read_line_p          read line with prompt
7275 
7276    Inputs:
7277         prompt  =       pointer to prompt string
7278         cptr    =       pointer to buffer
7279         size    =       maximum size
7280         stream  =       pointer to input stream
7281    Outputs:
7282         optr    =       pointer to first non-blank character
7283                         NULL if EOF
7284 */
7285 
7286 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7287 {
7288 char *tptr;
7289 
7290 if (prompt) {                                           /* interactive? */
7291 #if defined(HAVE_LINEHISTORY)
7292         char *tmpc = linenoise (prompt);                /* get cmd line */
7293         if (tmpc == NULL)                               /* bad result? */
7294             cptr = NULL;
7295         else {
7296             strncpy (cptr, tmpc, size-1);               /* copy result */
7297             linenoiseHistoryAdd (tmpc);                 /* add to history */
7298             FREE (tmpc);                                /* free temp */
7299             }
7300         }
7301 #else
7302         (void)fflush (stdout);                          /* flush output */
7303         (void)printf ("%s", prompt);                    /* display prompt */
7304         (void)fflush (stdout);                          /* flush output */
7305         cptr = fgets (cptr, size, stream);              /* get cmd line */
7306         }
7307 #endif /* if defined(HAVE_LINEHISTORY) */
7308 else cptr = fgets (cptr, size, stream);                 /* get cmd line */
7309 
7310 if (cptr == NULL) {
7311     clearerr (stream);                                  /* clear error */
7312     return NULL;                                        /* ignore EOF */
7313     }
7314 for (tptr = cptr; tptr < (cptr + size); tptr++) {       /* remove cr or nl */
7315     if ((*tptr == '\n') || (*tptr == '\r') ||
7316         (tptr == (cptr + size - 1))) {                  /* str max length? */
7317         *tptr = 0;                                      /* terminate */
7318         break;
7319         }
7320     }
7321 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))              /* Skip/ignore UTF8_BOM */
7322     memmove (cptr, cptr + 3, strlen (cptr + 3));
7323 while (sim_isspace (*cptr))                             /* trim leading spc */
7324     cptr++;
7325 if ((*cptr == ';') || (*cptr == '#')) {                 /* ignore comment */
7326     if (sim_do_echo)                                    /* echo comments if -v */
7327         sim_printf("%s> %s\n", do_position(), cptr);
7328     *cptr = 0;
7329     }
7330 
7331 return cptr;
7332 }
7333 
7334 /* get_glyph            get next glyph (force upper case)
7335    get_glyph_nc         get next glyph (no conversion)
7336    get_glyph_quoted     get next glyph (potentially enclosed in quotes, no conversion)
7337    get_glyph_cmd        get command glyph (force upper case, extract leading !)
7338    get_glyph_gen        get next glyph (general case)
7339 
7340    Inputs:
7341         iptr        =   pointer to input string
7342         optr        =   pointer to output string
7343         mchar       =   optional end of glyph character
7344         uc          =   TRUE for convert to upper case (_gen only)
7345         quote       =   TRUE to allow quote enclosing values (_gen only)
7346         escape_char =   optional escape character within quoted strings (_gen only)
7347 
7348    Outputs
7349         result      =   pointer to next character in input string
7350 */
7351 
7352 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char)
     /* [previous][next][first][last][top][bottom][index][help] */
7353 {
7354 t_bool quoting = FALSE;
7355 t_bool escaping = FALSE;
7356 char quote_char = 0;
7357 
7358 while ((*iptr != 0) &&
7359        ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7360     if (quote) {
7361         if (quoting) {
7362             if (!escaping) {
7363                 if (*iptr == escape_char)
7364                     escaping = TRUE;
7365                 else
7366                     if (*iptr == quote_char)
7367                         quoting = FALSE;
7368                 }
7369             else
7370                 escaping = FALSE;
7371             }
7372         else {
7373             if ((*iptr == '"') || (*iptr == '\'')) {
7374                 quoting = TRUE;
7375                 quote_char = *iptr;
7376                 }
7377             }
7378         }
7379     if (sim_islower (*iptr) && uc)
7380         *optr = (char)toupper (*iptr);
7381     else *optr = *iptr;
7382     iptr++; optr++;
7383     }
7384 if (mchar && (*iptr == mchar))              /* skip input terminator */
7385     iptr++;
7386 *optr = 0;                                  /* terminate result string */
7387 while (sim_isspace (*iptr))                 /* absorb additional input spaces */
7388     iptr++;
7389 return iptr;
7390 }
7391 
7392 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7393 {
7394 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7395 }
7396 
7397 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7398 {
7399 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7400 }
7401 
7402 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7403 {
7404 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7405 }
7406 
7407 CONST char *get_glyph_cmd (const char *iptr, char *optr)
     /* [previous][next][first][last][top][bottom][index][help] */
7408 {
7409 /* Tolerate "!subprocess" vs. requiring "! subprocess" */
7410 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7411     strcpy (optr, "!");                     /* return ! as command glyph */
7412     return (CONST char *)(iptr + 1);        /* and skip over the leading ! */
7413     }
7414 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7415 }
7416 
7417 /* Trim trailing spaces from a string
7418 
7419     Inputs:
7420         cptr    =       pointer to string
7421     Outputs:
7422         cptr    =       pointer to string
7423 */
7424 
7425 char *sim_trim_endspc (char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7426 {
7427 char *tptr;
7428 
7429 tptr = cptr + strlen (cptr);
7430 while ((--tptr >= cptr) && sim_isspace (*tptr))
7431     *tptr = 0;
7432 return cptr;
7433 }
7434 
7435 int sim_isspace (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7436 {
7437 return (c & 0x80) ? 0 : isspace (c);
7438 }
7439 
7440 int sim_islower (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7441 {
7442 return (c & 0x80) ? 0 : islower (c);
7443 }
7444 
7445 int sim_isalpha (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7446 {
7447 return (c & 0x80) ? 0 : isalpha (c);
7448 }
7449 
7450 int sim_isprint (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7451 {
7452 return (c & 0x80) ? 0 : isprint (c);
7453 }
7454 
7455 int sim_isdigit (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7456 {
7457 return (c & 0x80) ? 0 : isdigit (c);
7458 }
7459 
7460 int sim_isgraph (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7461 {
7462 return (c & 0x80) ? 0 : isgraph (c);
7463 }
7464 
7465 int sim_isalnum (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7466 {
7467 return (c & 0x80) ? 0 : isalnum (c);
7468 }
7469 
7470 /* get_uint             unsigned number
7471 
7472    Inputs:
7473         cptr    =       pointer to input string
7474         radix   =       input radix
7475         max     =       maximum acceptable value
7476         *status =       pointer to error status
7477    Outputs:
7478         val     =       value
7479 */
7480 
7481 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
     /* [previous][next][first][last][top][bottom][index][help] */
7482 {
7483 t_value val;
7484 CONST char *tptr;
7485 
7486 *status = SCPE_OK;
7487 val = strtotv ((CONST char *)cptr, &tptr, radix);
7488 if ((cptr == tptr) || (val > max))
7489     *status = SCPE_ARG;
7490 else {
7491     while (sim_isspace (*tptr)) tptr++;
7492     if (*tptr != 0)
7493         *status = SCPE_ARG;
7494     }
7495 return val;
7496 }
7497 
7498 /* get_range            range specification
7499 
7500    Inputs:
7501         dptr    =       pointer to device (NULL if none)
7502         cptr    =       pointer to input string
7503         *lo     =       pointer to low result
7504         *hi     =       pointer to high result
7505         aradix  =       radix
7506         max     =       default high value
7507         term    =       terminating character, 0 if none
7508    Outputs:
7509         tptr    =       input pointer after processing
7510                         NULL if error
7511 */
7512 
7513 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
     /* [previous][next][first][last][top][bottom][index][help] */
7514     uint32 rdx, t_addr max, char term)
7515 {
7516 CONST char *tptr;
7517 
7518 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {    /* ALL? */
7519     tptr = cptr + strlen ("ALL");
7520     *lo = 0;
7521     *hi = max;
7522     }
7523 else {
7524     if ((strncmp (cptr, ".", strlen (".")) == 0) &&             /* .? */
7525         ((cptr[1] == '\0') ||
7526          (cptr[1] == '-')  ||
7527          (cptr[1] == ':')  ||
7528          (cptr[1] == '/'))) {
7529         tptr = cptr + strlen (".");
7530         *lo = *hi = sim_last_addr;
7531         }
7532     else {
7533         if (strncmp (cptr, "$", strlen ("$")) == 0) {           /* $? */
7534             tptr = cptr + strlen ("$");
7535             *hi = *lo = (t_addr)sim_last_val;
7536             }
7537         else {
7538             if (dptr && sim_vm_parse_addr)                      /* get low */
7539                 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7540             else
7541                 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7542             if (cptr == tptr)                                   /* error? */
7543                     return NULL;
7544             }
7545         }
7546     if ((*tptr == '-') || (*tptr == ':')) {             /* range? */
7547         cptr = tptr + 1;
7548         if (dptr && sim_vm_parse_addr)                  /* get high */
7549             *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7550         else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7551         if (cptr == tptr)
7552             return NULL;
7553         if (*lo > *hi)
7554             return NULL;
7555         }
7556     else if (*tptr == '/') {                            /* relative? */
7557         cptr = tptr + 1;
7558         *hi = (t_addr) strtotv (cptr, &tptr, rdx);      /* get high */
7559         if ((cptr == tptr) || (*hi == 0))
7560             return NULL;
7561         *hi = *lo + *hi - 1;
7562         }
7563     else *hi = *lo;
7564     }
7565 sim_last_addr = *hi;
7566 if (term && (*tptr++ != term))
7567     return NULL;
7568 return tptr;
7569 }
7570 
7571 /* sim_decode_quoted_string
7572 
7573    Inputs:
7574         iptr        =   pointer to input string
7575         optr        =   pointer to output buffer
7576                         the output buffer must be allocated by the caller
7577                         and to avoid overrunat it must be at least as big
7578                         as the input string.
7579 
7580    Outputs
7581         result      =   status of decode SCPE_OK when good, SCPE_ARG otherwise
7582         osize       =   size of the data in the optr buffer
7583 
7584    The input string must be quoted.  Quotes may be either single or
7585    double but the opening anc closing quote characters must match.
7586    Within quotes C style character escapes are allowed.
7587 */
7588 
7589 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
     /* [previous][next][first][last][top][bottom][index][help] */
7590 {
7591 char quote_char;
7592 uint8 *ostart = optr;
7593 
7594 *osize = 0;
7595 if ((strlen(iptr) == 1) ||
7596     (iptr[0] != iptr[strlen(iptr)-1]) ||
7597     ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7598     return SCPE_ARG;            /* String must be quote delimited */
7599 quote_char = *iptr++;           /* Save quote character */
7600 while (iptr[1]) {               /* Skip trailing quote */
7601     if (*iptr != '\\') {
7602         if (*iptr == quote_char)
7603             return SCPE_ARG;    /* Embedded quotes must be escaped */
7604         *(optr++) = (uint8)(*(iptr++));
7605         continue;
7606         }
7607     ++iptr; /* Skip backslash */
7608     switch (*iptr) {
7609         case 'r':   /* ASCII Carriage Return character (Decimal value 13) */
7610             *(optr++) = 13; ++iptr;
7611             break;
7612         case 'n':   /* ASCII Linefeed character (Decimal value 10) */
7613             *(optr++) = 10; ++iptr;
7614             break;
7615         case 'f':   /* ASCII Formfeed character (Decimal value 12) */
7616             *(optr++) = 12; ++iptr;
7617             break;
7618         case 't':   /* ASCII Horizontal Tab character (Decimal value 9) */
7619             *(optr++) = 9; ++iptr;
7620             break;
7621         case 'v':   /* ASCII Vertical Tab character (Decimal value 11) */
7622             *(optr++) = 11; ++iptr;
7623             break;
7624         case 'b':   /* ASCII Backspace character (Decimal value 8) */
7625             *(optr++) = 8; ++iptr;
7626             break;
7627         case '\\':   /* ASCII Backslash character (Decimal value 92) */
7628             *(optr++) = 92; ++iptr;
7629             break;
7630         case 'e':   /* ASCII Escape character (Decimal value 27) */
7631             *(optr++) = 27; ++iptr;
7632             break;
7633         case '\'':   /* ASCII Single Quote character (Decimal value 39) */
7634             *(optr++) = 39; ++iptr;
7635             break;
7636         case '"':   /* ASCII Double Quote character (Decimal value 34) */
7637             *(optr++) = 34; ++iptr;
7638             break;
7639         case '?':   /* ASCII Question Mark character (Decimal value 63) */
7640             *(optr++) = 63; ++iptr;
7641             break;
7642         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7643             *optr = *(iptr++) - '0';
7644             if ((*iptr >= '0') && (*iptr <= '7'))
7645                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7646             if ((*iptr >= '0') && (*iptr <= '7'))
7647                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7648             ++optr;
7649             break;
7650         case 'x':
7651             if (1) {
7652                 static const char *hex_digits = "0123456789ABCDEF";
7653                 const char *c;
7654 
7655                 ++iptr;
7656                 *optr = 0;
7657                 c = strchr (hex_digits, toupper(*iptr));
7658                 if (c) {
7659                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7660                     ++iptr;
7661                     }
7662                 c = strchr (hex_digits, toupper(*iptr));
7663                 if (c) {
7664                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7665                     ++iptr;
7666                     }
7667                 ++optr;
7668                 }
7669             break;
7670         default:
7671             return SCPE_ARG;    /* Invalid escape */
7672         }
7673     }
7674 *optr = '\0';
7675 *osize = (uint32)(optr-ostart);
7676 return SCPE_OK;
7677 }
7678 
7679 /* sim_encode_quoted_string
7680 
7681    Inputs:
7682         iptr        =   pointer to input buffer
7683         size        =   number of bytes of data in the buffer
7684 
7685    Outputs
7686         optr        =   pointer to output buffer
7687                         the output buffer must be freed by the caller
7688 
7689    The input data will be encoded into a simply printable form.
7690 */
7691 
7692 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7693 {
7694 size_t i;
7695 t_bool double_quote_found = FALSE;
7696 t_bool single_quote_found = FALSE;
7697 char quote = '"';
7698 char *tptr, *optr;
7699 
7700 optr = (char *)malloc (4*size + 3);
7701 if (optr == NULL)
7702     return NULL;
7703 tptr = optr;
7704 for (i=0; i<size; i++)
7705     switch ((char)iptr[i]) {
7706         case '"':
7707             double_quote_found = TRUE;
7708             break;
7709         case '\'':
7710             single_quote_found = TRUE;
7711             break;
7712         }
7713 if (double_quote_found && (!single_quote_found))
7714     quote = '\'';
7715 *tptr++ = quote;
7716 while (size--) {
7717     switch (*iptr) {
7718         case '\r':
7719             *tptr++ = '\\'; *tptr++ = 'r'; break;
7720         case '\n':
7721             *tptr++ = '\\'; *tptr++ = 'n'; break;
7722         case '\f':
7723             *tptr++ = '\\'; *tptr++ = 'f'; break;
7724         case '\t':
7725             *tptr++ = '\\'; *tptr++ = 't'; break;
7726         case '\v':
7727             *tptr++ = '\\'; *tptr++ = 'v'; break;
7728         case '\b':
7729             *tptr++ = '\\'; *tptr++ = 'b'; break;
7730         case '\\':
7731             *tptr++ = '\\'; *tptr++ = '\\'; break;
7732         case '"':
7733         case '\'':
7734             if (quote == *iptr)
7735                 *tptr++ = '\\';
7736         /*FALLTHRU*/ /* fall through */ /* fallthrough */
7737         default:
7738             if (sim_isprint (*iptr))
7739                 *tptr++ = *iptr;
7740             else {
7741                 (void)sprintf (tptr, "\\%03o", *iptr);
7742                 tptr += 4;
7743                 }
7744             break;
7745         }
7746     ++iptr;
7747     }
7748 *tptr++ = quote;
7749 *tptr++ = '\0';
7750 return optr;
7751 }
7752 
7753 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7754 {
7755 char *string;
7756 
7757 string = sim_encode_quoted_string (buf, size);
7758 (void)fprintf (st, "%s", string);
7759 FREE (string);
7760 }
7761 
7762 /* Find_device          find device matching input string
7763 
7764    Inputs:
7765         cptr    =       pointer to input string
7766    Outputs:
7767         result  =       pointer to device
7768 */
7769 
7770 DEVICE *find_dev (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7771 {
7772 int32 i;
7773 DEVICE *dptr;
7774 
7775 if (cptr == NULL)
7776     return NULL;
7777 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7778     if ((strcmp (cptr, dptr->name) == 0) ||
7779         (dptr->lname &&
7780         (strcmp (cptr, dptr->lname) == 0)))
7781         return dptr;
7782     }
7783 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7784     if ((strcmp (cptr, dptr->name) == 0) ||
7785         (dptr->lname &&
7786         (strcmp (cptr, dptr->lname) == 0)))
7787         return dptr;
7788     }
7789 return NULL;
7790 }
7791 
7792 /* Find_unit            find unit matching input string
7793 
7794    Inputs:
7795         cptr    =       pointer to input string
7796         uptr    =       pointer to unit pointer
7797    Outputs:
7798         result  =       pointer to device (null if no dev)
7799         *iptr   =       pointer to unit (null if nx unit)
7800 
7801 */
7802 
7803 DEVICE *find_unit (const char *cptr, UNIT **uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7804 {
7805 uint32 i, u;
7806 const char *nptr;
7807 const char *tptr;
7808 t_stat r;
7809 DEVICE *dptr;
7810 
7811 if (uptr == NULL)                                       /* arg error? */
7812     return NULL;
7813 *uptr = NULL;
7814 if ((dptr = find_dev (cptr))) {                         /* exact match? */
7815     if (qdisable (dptr))                                /* disabled? */
7816         return NULL;
7817     *uptr = dptr->units;                                /* unit 0 */
7818     return dptr;
7819     }
7820 
7821 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {     /* base + unit#? */
7822     if (qdisable (dptr))                                /* device disabled? */
7823         continue;
7824     if (dptr->numunits && /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/ /* any units? */
7825         (((nptr = dptr->name) &&
7826           (strncmp (cptr, nptr, strlen (nptr)) == 0)) || /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
7827          ((nptr = dptr->lname) &&
7828           (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
7829         tptr = cptr + strlen (nptr);
7830         if (sim_isdigit (*tptr)) {
7831             if (qdisable (dptr))                        /* disabled? */
7832                 return NULL;
7833             u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
7834             if (r != SCPE_OK)                           /* error? */
7835                 *uptr = NULL;
7836             else
7837                 *uptr = dptr->units + u;
7838             return dptr;
7839             }
7840         }
7841     for (u = 0; u < dptr->numunits; u++) {
7842         if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
7843             *uptr = &dptr->units[u];
7844             return dptr;
7845             }
7846         }
7847     }
7848 return NULL;
7849 }
7850 
7851 /* sim_register_internal_device   Add device to internal device list
7852 
7853    Inputs:
7854         dptr    =       pointer to device
7855 */
7856 
7857 t_stat sim_register_internal_device (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7858 {
7859 uint32 i;
7860 
7861 for (i = 0; (sim_devices[i] != NULL); i++)
7862     if (sim_devices[i] == dptr)
7863         return SCPE_OK;
7864 for (i = 0; i < sim_internal_device_count; i++)
7865     if (sim_internal_devices[i] == dptr)
7866         return SCPE_OK;
7867 ++sim_internal_device_count;
7868 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
7869 if (!sim_internal_devices)
7870   {
7871     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
7872                    __func__, __FILE__, __LINE__);
7873 #if defined(USE_BACKTRACE)
7874 # if defined(SIGUSR2)
7875     (void)raise(SIGUSR2);
7876     /*NOTREACHED*/ /* unreachable */
7877 # endif /* if defined(SIGUSR2) */
7878 #endif /* if defined(USE_BACKTRACE) */
7879     abort();
7880   }
7881 sim_internal_devices[sim_internal_device_count-1] = dptr;
7882 sim_internal_devices[sim_internal_device_count] = NULL;
7883 return SCPE_OK;
7884 }
7885 
7886 /* Find_dev_from_unit   find device for unit
7887 
7888    Inputs:
7889         uptr    =       pointer to unit
7890    Outputs:
7891         result  =       pointer to device
7892 */
7893 
7894 DEVICE *find_dev_from_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7895 {
7896 DEVICE *dptr;
7897 uint32 i, j;
7898 
7899 if (uptr == NULL)
7900     return NULL;
7901 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7902     for (j = 0; j < dptr->numunits; j++) {
7903         if (uptr == (dptr->units + j))
7904             return dptr;
7905         }
7906     }
7907 for (i = 0; i<sim_internal_device_count; i++) {
7908     dptr = sim_internal_devices[i];
7909     for (j = 0; j < dptr->numunits; j++) {
7910         if (uptr == (dptr->units + j))
7911             return dptr;
7912         }
7913     }
7914 return NULL;
7915 }
7916 
7917 /* Test for disabled device */
7918 
7919 t_bool qdisable (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7920 {
7921 return (dptr->flags & DEV_DIS? TRUE: FALSE);
7922 }
7923 
7924 /* find_reg_glob        find globally unique register
7925 
7926    Inputs:
7927         cptr    =       pointer to input string
7928         optr    =       pointer to output pointer (can be null)
7929         gdptr   =       pointer to global device
7930    Outputs:
7931         result  =       pointer to register, NULL if error
7932         *optr   =       pointer to next character in input string
7933         *gdptr  =       pointer to device where found
7934 */
7935 
7936 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7937 {
7938 int32 i;
7939 DEVICE *dptr;
7940 REG *rptr, *srptr = NULL;
7941 
7942 *gdptr = NULL;
7943 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {        /* all dev */
7944     if (dptr->flags & DEV_DIS)                          /* skip disabled */
7945         continue;
7946     if ((rptr = find_reg (cptr, optr, dptr))) {         /* found? */
7947         if (srptr)                                      /* ambig? err */
7948             return NULL;
7949         srptr = rptr;                                   /* save reg */
7950         *gdptr = dptr;                                  /* save unit */
7951         }
7952     }
7953 return srptr;
7954 }
7955 
7956 /* find_reg             find register matching input string
7957 
7958    Inputs:
7959         cptr    =       pointer to input string
7960         optr    =       pointer to output pointer (can be null)
7961         dptr    =       pointer to device
7962    Outputs:
7963         result  =       pointer to register, NULL if error
7964         *optr   =       pointer to next character in input string
7965 */
7966 
7967 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7968 {
7969 CONST char *tptr;
7970 REG *rptr;
7971 size_t slnt;
7972 
7973 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
7974     return NULL;
7975 tptr = cptr;
7976 do {
7977     tptr++;
7978     } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
7979 slnt = tptr - cptr;
7980 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
7981     if ((slnt == strlen (rptr->name)) &&
7982         (strncmp (cptr, rptr->name, slnt) == 0)) {
7983         if (optr != NULL)
7984             *optr = tptr;
7985         return rptr;
7986         }
7987     }
7988 return NULL;
7989 }
7990 
7991 /* get_switches         get switches from input string
7992 
7993    Inputs:
7994         cptr    =       pointer to input string
7995    Outputs:
7996         sw      =       switch bit mask
7997                         0 if no switches, -1 if error
7998 */
7999 
8000 int32 get_switches (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8001 {
8002 int32 sw;
8003 
8004 if (*cptr != '-')
8005     return 0;
8006 sw = 0;
8007 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8008     if (sim_isalpha (*cptr) == 0)
8009         return -1;
8010     sw = sw | SWMASK (toupper (*cptr));
8011     }
8012 return sw;
8013 }
8014 
8015 /* get_sim_sw           accumulate sim_switches
8016 
8017    Inputs:
8018         cptr    =       pointer to input string
8019    Outputs:
8020         ptr     =       pointer to first non-string glyph
8021                         NULL if error
8022 */
8023 
8024 CONST char *get_sim_sw (CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8025 {
8026 int32 lsw;
8027 char gbuf[CBUFSIZE];
8028 
8029 while (*cptr == '-') {                                  /* while switches */
8030     cptr = get_glyph (cptr, gbuf, 0);                   /* get switch glyph */
8031     lsw = get_switches (gbuf);                          /* parse */
8032     if (lsw <= 0)                                       /* invalid? */
8033         return NULL;
8034     sim_switches = sim_switches | lsw;                  /* accumulate */
8035     }
8036 return cptr;
8037 }
8038 
8039 /* get_sim_opt          get simulator command options
8040 
8041    Inputs:
8042         opt     =       command options
8043         cptr    =       pointer to input string
8044    Outputs:
8045         ptr     =       pointer to next glyph, NULL if error
8046         *stat   =       error status
8047 */
8048 
8049 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
     /* [previous][next][first][last][top][bottom][index][help] */
8050 {
8051 int32 t;
8052 char gbuf[CBUFSIZE];
8053 CONST char *svptr;
8054 DEVICE *tdptr;
8055 UNIT *tuptr;
8056 
8057 sim_switches = 0;                                       /* no switches */
8058 sim_ofile = NULL;                                       /* no output file */
8059 sim_schrptr = NULL;                                     /* no search */
8060 sim_schaptr = NULL;                                     /* no search */
8061 sim_stabr.logic = sim_staba.logic = SCH_OR;             /* default search params */
8062 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8063 sim_stabr.count = 1;
8064 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8065 if (!sim_stabr.mask)
8066   {
8067     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8068                    __func__, __FILE__, __LINE__);
8069 #if defined(USE_BACKTRACE)
8070 # if defined(SIGUSR2)
8071     (void)raise(SIGUSR2);
8072     /*NOTREACHED*/ /* unreachable */
8073 # endif /* if defined(SIGUSR2) */
8074 #endif /* if defined(USE_BACKTRACE) */
8075     abort();
8076   }
8077 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8078 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8079 if (!sim_stabr.comp)
8080   {
8081     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8082                    __func__, __FILE__, __LINE__);
8083 #if defined(USE_BACKTRACE)
8084 # if defined(SIGUSR2)
8085     (void)raise(SIGUSR2);
8086     /*NOTREACHED*/ /* unreachable */
8087 # endif /* if defined(SIGUSR2) */
8088 #endif /* if defined(USE_BACKTRACE) */
8089     abort();
8090   }
8091 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8092 sim_staba.count = sim_emax;
8093 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8094 if (!sim_staba.mask)
8095   {
8096     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8097                    __func__, __FILE__, __LINE__);
8098 #if defined(USE_BACKTRACE)
8099 # if defined(SIGUSR2)
8100     (void)raise(SIGUSR2);
8101     /*NOTREACHED*/ /* unreachable */
8102 # endif /* if defined(SIGUSR2) */
8103 #endif /* if defined(USE_BACKTRACE) */
8104     abort();
8105   }
8106 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8107 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8108 if (!sim_staba.comp)
8109   {
8110     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8111                    __func__, __FILE__, __LINE__);
8112 #if defined(USE_BACKTRACE)
8113 # if defined(SIGUSR2)
8114     (void)raise(SIGUSR2);
8115     /*NOTREACHED*/ /* unreachable */
8116 # endif /* if defined(SIGUSR2) */
8117 #endif /* if defined(USE_BACKTRACE) */
8118     abort();
8119   }
8120 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8121 if (! sim_dflt_dev)
8122   return NULL;
8123 sim_dfdev = sim_dflt_dev;
8124 sim_dfunit = sim_dfdev->units;
8125 sim_opt_out = 0;                                        /* no options yet */
8126 *st = SCPE_OK;
8127 while (*cptr) {                                         /* loop through modifiers */
8128     svptr = cptr;                                       /* save current position */
8129     if ((opt & CMD_OPT_OF) && (*cptr == '@')) {         /* output file spec? */
8130         if (sim_ofile) {                                /* already got one? */
8131             fclose (sim_ofile);                         /* one per customer */
8132             *st = SCPE_ARG;
8133             return NULL;
8134             }
8135         cptr = get_glyph (cptr + 1, gbuf, 0);
8136         sim_ofile = sim_fopen (gbuf, "a");              /* open for append */
8137         if (sim_ofile == NULL) {                        /* open failed? */
8138             *st = SCPE_OPENERR;
8139             return NULL;
8140             }
8141         sim_opt_out |= CMD_OPT_OF;                      /* got output file */
8142         continue;
8143         }
8144     cptr = get_glyph (cptr, gbuf, 0);
8145     if ((t = get_switches (gbuf)) != 0) {               /* try for switches */
8146         if (t < 0) {                                    /* err if bad switch */
8147             *st = SCPE_INVSW;
8148             return NULL;
8149             }
8150         sim_switches = sim_switches | t;                /* or in new switches */
8151         }
8152     else if ((opt & CMD_OPT_SCH) &&                     /* if allowed, */
8153         get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) { /* try for search */
8154         sim_schrptr = &sim_stabr;                       /* set search */
8155         sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);/* populate memory version of the same expression */
8156         sim_opt_out |= CMD_OPT_SCH;                     /* got search */
8157         }
8158     else if ((opt & CMD_OPT_DFT) &&                     /* default allowed? */
8159         ((sim_opt_out & CMD_OPT_DFT) == 0) &&           /* none yet? */
8160         (tdptr = find_unit (gbuf, &tuptr)) &&           /* try for default */
8161         (tuptr != NULL)) {
8162         sim_dfdev = tdptr;                              /* set as default */
8163         sim_dfunit = tuptr;
8164         sim_opt_out |= CMD_OPT_DFT;                     /* got default */
8165         }
8166     else return svptr;                                  /* not rec, break out */
8167     }
8168 return cptr;
8169 }
8170 
8171 /* put_switches         put switches into string
8172 
8173    Inputs:
8174         buf     =       pointer to string buffer
8175         bufsize =       size of string buffer
8176         sw      =       switch bit mask
8177    Outputs:
8178         buf     =       buffer with switches converted to text
8179 */
8180 
8181 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
8182 {
8183 char *optr = buf;
8184 int32 bit;
8185 
8186 (void)memset (buf, 0, bufsize);
8187 if ((sw == 0) || (bufsize < 3))
8188     return buf;
8189 --bufsize;                          /* leave room for terminating NUL */
8190 *optr++ = '-';
8191 for (bit=0; bit <= ('Z'-'A'); bit++)
8192     if (sw & (1 << bit))
8193         if ((size_t)(optr - buf) < bufsize)
8194             *optr++ = 'A' + bit;
8195 return buf;
8196 }
8197 
8198 /* Get register search specification
8199 
8200    Inputs:
8201         cptr    =       pointer to input string
8202         radix   =       radix for numbers
8203         schptr =        pointer to search table
8204    Outputs:
8205         return =        NULL if error
8206                         schptr if valid search specification
8207 */
8208 
8209 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8210 {
8211 int32 c;
8212 size_t logop, cmpop;
8213 t_value logval, cmpval;
8214 const char *sptr;
8215 CONST char *tptr;
8216 const char logstr[] = "|&^", cmpstr[] = "=!><";
8217 /* Using a const instead of a #define. */
8218 const size_t invalid_op = (size_t) -1;
8219 
8220 logval = cmpval = 0;
8221 if (*cptr == 0)                                         /* check for clause */
8222     return NULL;
8223 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8224 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8225     if ((sptr = strchr (logstr, c))) {                  /* check for mask */
8226         logop = sptr - logstr;
8227         logval = strtotv (cptr, &tptr, radix);
8228         if (cptr == tptr)
8229             return NULL;
8230         cptr = tptr;
8231         }
8232     else if ((sptr = strchr (cmpstr, c))) {             /* check for boolop */
8233         cmpop = sptr - cmpstr;
8234         if (*cptr == '=') {
8235             cmpop = cmpop + strlen (cmpstr);
8236             cptr++;
8237             }
8238         cmpval = strtotv (cptr, &tptr, radix);
8239         if (cptr == tptr)
8240             return NULL;
8241         cptr = tptr;
8242         }
8243     else return NULL;
8244     }                                                   /* end for */
8245 if (schptr->count != 1) {
8246     FREE (schptr->mask);
8247     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8248     FREE (schptr->comp);
8249     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8250     }
8251 if (logop != invalid_op) {
8252     schptr->logic = logop;
8253     schptr->mask[0] = logval;
8254     }
8255 if (cmpop != invalid_op) {
8256     schptr->boolop = cmpop;
8257     schptr->comp[0] = cmpval;
8258     }
8259 schptr->count = 1;
8260 return schptr;
8261 }
8262 
8263 /* Get memory search specification
8264 
8265    Inputs:
8266         cptr    =       pointer to input string
8267         radix   =       radix for numbers
8268         schptr =        pointer to search table
8269    Outputs:
8270         return =        NULL if error
8271                         schptr if valid search specification
8272 */
8273 
8274 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8275 {
8276 int32 c;
8277 size_t logop, cmpop;
8278 t_value *logval, *cmpval;
8279 t_stat reason = SCPE_OK;
8280 CONST char *ocptr = cptr;
8281 const char *sptr;
8282 char gbuf[CBUFSIZE];
8283 const char logstr[] = "|&^", cmpstr[] = "=!><";
8284 /* Using a const instead of a #define. */
8285 const size_t invalid_op = (size_t) -1;
8286 
8287 if (*cptr == 0)                                         /* check for clause */
8288     return NULL;
8289 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8290 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8291 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8292 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8293     if (NULL != (sptr = strchr (logstr, c))) {          /* check for mask */
8294         logop = sptr - logstr;
8295         cptr = get_glyph (cptr, gbuf, 0);
8296         reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8297         if (reason > 0) {
8298             FREE (logval);
8299             FREE (cmpval);
8300             return get_rsearch (ocptr, radix, schptr);
8301             }
8302         }
8303     else if (NULL != (sptr = strchr (cmpstr, c))) {     /* check for boolop */
8304         cmpop = sptr - cmpstr;
8305         if (*cptr == '=') {
8306             cmpop = cmpop + strlen (cmpstr);
8307             cptr++;
8308             }
8309         cptr = get_glyph (cptr, gbuf, 0);
8310         reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8311         if (reason > 0) {
8312             FREE (logval);
8313             FREE (cmpval);
8314             return get_rsearch (ocptr, radix, schptr);
8315             }
8316         }
8317     else {
8318         FREE (logval);
8319         FREE (cmpval);
8320         return NULL;
8321         }
8322     }                                                   /* end for */
8323 if (schptr->count != (uint32)(1 - reason)) {
8324     schptr->count = 1 - reason;
8325     FREE (schptr->mask);
8326     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8327     FREE (schptr->comp);
8328     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8329     }
8330 if (logop != invalid_op) {
8331     schptr->logic = logop;
8332     FREE (schptr->mask);
8333     schptr->mask = logval;
8334     }
8335 else {
8336     FREE (logval);
8337     }
8338 if (cmpop != invalid_op) {
8339     schptr->boolop = cmpop;
8340     FREE (schptr->comp);
8341     schptr->comp = cmpval;
8342     }
8343 else {
8344     FREE (cmpval);
8345     }
8346 return schptr;
8347 }
8348 
8349 /* Test value against search specification
8350 
8351    Inputs:
8352         val    =        value list to test
8353         schptr =        pointer to search table
8354    Outputs:
8355         return =        1 if value passes search criteria, 0 if not
8356 */
8357 
8358 int32 test_search (t_value *values, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8359 {
8360 t_value *val = NULL;
8361 int32 i, updown;
8362 int32 ret = 0;
8363 
8364 if (schptr == NULL)
8365     return ret;
8366 
8367 val = (t_value *)malloc (schptr->count * sizeof (*values));
8368 if (!val)
8369   {
8370     (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8371                   __func__, __FILE__, __LINE__);
8372 #if defined(USE_BACKTRACE)
8373 # if defined(SIGUSR2)
8374     (void)raise(SIGUSR2);
8375     /*NOTREACHED*/ /* unreachable */
8376 # endif /* if defined(SIGUSR2) */
8377 #endif /* if defined(USE_BACKTRACE) */
8378     abort();
8379   }
8380 for (i=0; i<(int32)schptr->count; i++) {
8381     val[i] = values[i];
8382     switch (schptr->logic) {                            /* case on logical */
8383 
8384         case SCH_OR:
8385             val[i] = val[i] | schptr->mask[i];
8386             break;
8387 
8388         case SCH_AND:
8389             val[i] = val[i] & schptr->mask[i];
8390             break;
8391 
8392         case SCH_XOR:
8393             val[i] = val[i] ^ schptr->mask[i];
8394             break;
8395             }
8396     }
8397 
8398 ret = 1;
8399 if (1) {    /* Little Endian VM */
8400     updown = -1;
8401     i=schptr->count-1;
8402     }
8403 else {      /* Big Endian VM */
8404     updown = 1;
8405     i=0;
8406     }
8407 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8408     switch (schptr->boolop) {                           /* case on comparison */
8409 
8410         case SCH_E: case SCH_EE:
8411             if (val[i] != schptr->comp[i])
8412                 ret = 0;
8413             break;
8414 
8415         case SCH_N: case SCH_NE:
8416             if (val[i] == schptr->comp[i])
8417                 ret = 0;
8418             break;
8419 
8420         case SCH_G:
8421             if (val[i] <= schptr->comp[i])
8422                 ret = 0;
8423             break;
8424 
8425         case SCH_GE:
8426             if (val[i] < schptr->comp[i])
8427                 ret = 0;
8428             break;
8429 
8430         case SCH_L:
8431             if (val[i] >= schptr->comp[i])
8432                 ret = 0;
8433             break;
8434 
8435         case SCH_LE:
8436             if (val[i] > schptr->comp[i])
8437                 ret = 0;
8438             break;
8439         }
8440     }
8441 FREE (val);
8442 return ret;
8443 }
8444 
8445 /* Radix independent input/output package
8446 
8447    strtotv - general radix input routine
8448 
8449    Inputs:
8450         inptr   =       string to convert
8451         endptr  =       pointer to first unconverted character
8452         radix   =       radix for input
8453    Outputs:
8454         value   =       converted value
8455 
8456    On an error, the endptr will equal the inptr.
8457 */
8458 
8459 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
     /* [previous][next][first][last][top][bottom][index][help] */
8460 {
8461 int32 nodigit;
8462 t_value val;
8463 uint32 c, digit;
8464 
8465 *endptr = inptr;                                        /* assume fails */
8466 if ((radix < 2) || (radix > 36))
8467     return 0;
8468 while (sim_isspace (*inptr))                            /* bypass white space */
8469     inptr++;
8470 val = 0;
8471 nodigit = 1;
8472 for (c = *inptr; sim_isalnum(c); c = *++inptr) {        /* loop through char */
8473     if (sim_islower (c))
8474         c = toupper (c);
8475     if (sim_isdigit (c))                                /* digit? */
8476         digit = c - (uint32) '0';
8477     else if (radix <= 10)                               /* stop if not expected */
8478         break;
8479     else digit = c + 10 - (uint32) 'A';                 /* convert letter */
8480     if (digit >= radix)                                 /* valid in radix? */
8481         return 0;
8482     val = (val * radix) + digit;                        /* add to value */
8483     nodigit = 0;
8484     }
8485 if (nodigit)                                            /* no digits? */
8486     return 0;
8487 *endptr = inptr;                                        /* result pointer */
8488 return val;
8489 }
8490 
8491 /* fprint_val - general radix printing routine
8492 
8493    Inputs:
8494         stream  =       stream designator
8495         val     =       value to print
8496         radix   =       radix to print
8497         width   =       width to print
8498         format  =       leading zeroes format
8499    Outputs:
8500         status  =       error status
8501         if stream is NULL, returns length of output that would
8502         have been generated.
8503 */
8504 
8505 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8506                    size_t width, uint32 format)
8507 {
8508 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8509 t_value owtest, wtest;
8510 size_t d;
8511 size_t digit;
8512 size_t ndigits;
8513 size_t commas = 0;
8514 char dbuf[MAX_WIDTH + 1];
8515 
8516 for (d = 0; d < MAX_WIDTH; d++)
8517     dbuf[d] = (format == PV_RZRO)? '0': ' ';
8518 dbuf[MAX_WIDTH] = 0;
8519 d = MAX_WIDTH;
8520 do {
8521     d = d - 1;
8522     digit = val % radix;
8523     val = val / radix;
8524     dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8525     } while ((d > 0) && (val != 0));
8526 
8527 switch (format) {
8528     case PV_LEFT:
8529         break;
8530     case PV_RZRO:
8531         wtest = owtest = radix;
8532         ndigits = 1;
8533         while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8534             owtest = wtest;
8535             wtest = wtest * radix;
8536             ndigits = ndigits + 1;
8537             }
8538         if ((MAX_WIDTH - (ndigits + commas)) < d)
8539             d = MAX_WIDTH - (ndigits + commas);
8540         break;
8541     }
8542 if (NULL == buffer)                   /* Potentially unsafe wraparound if */
8543     return ((t_stat) strlen(dbuf+d)); /*  sizeof(t_stat) < sizeof(size_t) */
8544 *buffer = '\0';
8545 if (width < strlen(dbuf+d))
8546     return SCPE_IOERR;
8547 strcpy(buffer, dbuf+d);
8548 return SCPE_OK;
8549 }
8550 
8551 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8552     uint32 width, uint32 format)
8553 {
8554 char dbuf[MAX_WIDTH + 1];
8555 
8556 if (!stream)
8557     return sprint_val (NULL, val, radix, width, format);
8558 if (width > MAX_WIDTH)
8559     width = MAX_WIDTH;
8560 sprint_val (dbuf, val, radix, width, format);
8561 if (Fprintf (stream, "%s", dbuf) < 0)
8562     return SCPE_IOERR;
8563 return SCPE_OK;
8564 }
8565 
8566 const char *sim_fmt_secs (double seconds)
     /* [previous][next][first][last][top][bottom][index][help] */
8567 {
8568 static char buf[60];
8569 char frac[16] = "";
8570 const char *sign = "";
8571 double val = seconds;
8572 double days, hours, mins, secs, msecs, usecs;
8573 
8574 if (val == 0.0)
8575     return "";
8576 if (val < 0.0) {
8577     sign = "-";
8578     val = -val;
8579     }
8580 days = floor (val / (24.0*60.0*60.0));
8581 val -= (days * 24.0*60.0*60.0);
8582 hours = floor (val / (60.0*60.0));
8583 val -= (hours * 60.0 * 60.0);
8584 mins = floor (val / 60.0);
8585 val -= (mins * 60.0);
8586 secs = floor (val);
8587 val -= secs;
8588 val *= 1000.0;
8589 msecs = floor (val);
8590 val -= msecs;
8591 val *= 1000.0;
8592 usecs = floor (val+0.5);
8593 if (usecs == 1000.0) {
8594     usecs = 0.0;
8595     msecs += 1;
8596     }
8597 if ((msecs > 0.0) || (usecs > 0.0)) {
8598     (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8599     while (frac[strlen (frac) - 1] == '0') //-V557
8600         frac[strlen (frac) - 1] = '\0'; //-V557
8601     if (strlen (frac) == 1)
8602         frac[0] = '\0';
8603     }
8604 if (days > 0)
8605     (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8606                    sign, days, (days != 1) ? "s" : "", hours, mins,
8607                    secs, frac, (days == 1) ? "s" : "");
8608 else
8609     if (hours > 0)
8610         (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8611                        sign, hours, mins, secs, frac);
8612     else
8613         if (mins > 0)
8614             (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8615                            sign, mins, secs, frac);
8616         else
8617             if (secs > 0)
8618                 (void)sprintf (buf, "%s%.0f%s second",
8619                                sign, secs, frac);
8620             else
8621                 if (msecs > 0) {
8622                     if (usecs > 0)
8623                         (void)sprintf (buf, "%s%.0f.%s msec",
8624                                        sign, msecs, frac+4);
8625                     else
8626                         (void)sprintf (buf, "%s%.0f msec",
8627                                        sign, msecs);
8628                     }
8629                 else
8630                     (void)sprintf (buf, "%s%.0f usec",
8631                                    sign, usecs);
8632 if (0 != strncmp ("1 ", buf, 2))
8633     strcpy (&buf[strlen (buf)], "s");
8634 return buf;
8635 }
8636 
8637 /*
8638  * Event queue package
8639  *
8640  *      sim_activate            add entry to event queue
8641  *      sim_activate_abs        add entry to event queue even if event already scheduled
8642  *      sim_activate_after      add entry to event queue after a specified amount of wall time
8643  *      sim_cancel              remove entry from event queue
8644  *      sim_process_event       process entries on event queue
8645  *      sim_is_active           see if entry is on event queue
8646  *      sim_activate_time       return time until activation
8647  *      sim_atime               return absolute time for an entry
8648  *      sim_gtime               return global time
8649  *      sim_qcount              return event queue entry count
8650  */
8651 
8652 t_stat sim_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8653 {
8654 UNIT *uptr;
8655 t_stat reason;
8656 #if defined(TESTING)
8657 cpu_state_t * cpup = _cpup;
8658 #endif
8659 
8660 if (stop_cpu)                                           /* stop CPU? */
8661   {
8662 #if defined(WIN_STDIO)
8663     (void)fflush(stdout);
8664     (void)fflush(stderr);
8665 #endif /* if defined(WIN_STDIO) */
8666     return SCPE_STOP;
8667   }
8668 UPDATE_SIM_TIME;                                        /* update sim time */
8669 
8670 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8671     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8672     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8673                "Queue Empty New Interval = %d\n",
8674                sim_interval);
8675     return SCPE_OK;
8676     }
8677 sim_processing_event = TRUE;
8678 do {
8679     uptr = sim_clock_queue;                             /* get first */
8680     sim_clock_queue = uptr->next;                       /* remove first */
8681     uptr->next = NULL;                                  /* hygiene */
8682     sim_interval -= uptr->time;
8683     uptr->time = 0;
8684     if (sim_clock_queue != QUEUE_LIST_END)
8685         sim_interval = sim_clock_queue->time;
8686     else
8687         sim_interval = noqueue_time = NOQUEUE_WAIT;
8688     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8689                "Processing Event for %s\n", sim_uname (uptr));
8690     if (uptr->action != NULL)
8691         reason = uptr->action (uptr);
8692     else
8693         reason = SCPE_OK;
8694     } while ((reason == SCPE_OK) &&
8695              (sim_interval <= 0) &&
8696              (sim_clock_queue != QUEUE_LIST_END) &&
8697              (!stop_cpu));
8698 
8699 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8700     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8701     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8702                "Processing Queue Complete New Interval = %d\n",
8703                sim_interval);
8704     }
8705 else
8706     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8707                "Processing Queue Complete New Interval = %d(%s)\n",
8708                sim_interval, sim_uname(sim_clock_queue));
8709 
8710 if ((reason == SCPE_OK) && stop_cpu)
8711   {
8712 #if defined(WIN_STDIO)
8713     (void)fflush(stdout);
8714     (void)fflush(stderr);
8715 #endif /* if defined(WIN_STDIO) */
8716     reason = SCPE_STOP;
8717   }
8718 sim_processing_event = FALSE;
8719 return reason;
8720 }
8721 
8722 /* sim_activate - activate (queue) event
8723 
8724    Inputs:
8725         uptr    =       pointer to unit
8726         event_time =    relative timeout
8727    Outputs:
8728         reason  =       result (SCPE_OK if ok)
8729 */
8730 
8731 t_stat sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8732 {
8733 if (uptr->dynflags & UNIT_TMR_UNIT)
8734     return sim_timer_activate (uptr, event_time);
8735 return _sim_activate (uptr, event_time);
8736 }
8737 
8738 t_stat _sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8739 {
8740 UNIT *cptr, *prvptr;
8741 int32 accum;
8742 #if defined(TESTING)
8743 cpu_state_t * cpup = _cpup;
8744 #endif
8745 
8746 if (sim_is_active (uptr))                               /* already active? */
8747     return SCPE_OK;
8748 UPDATE_SIM_TIME;                                        /* update sim time */
8749 
8750 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\n", sim_uname (uptr), event_time);
8751 
8752 prvptr = NULL;
8753 accum = 0;
8754 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8755     if (event_time < (accum + cptr->time))
8756         break;
8757     accum = accum + cptr->time;
8758     prvptr = cptr;
8759     }
8760 if (prvptr == NULL) {                                   /* insert at head */
8761     cptr = uptr->next = sim_clock_queue;
8762     sim_clock_queue = uptr;
8763     }
8764 else {
8765     cptr = uptr->next = prvptr->next;                   /* insert at prvptr */
8766     prvptr->next = uptr;
8767     }
8768 uptr->time = event_time - accum;
8769 if (cptr != QUEUE_LIST_END)
8770     cptr->time = cptr->time - uptr->time;
8771 sim_interval = sim_clock_queue->time;
8772 return SCPE_OK;
8773 }
8774 
8775 /* sim_activate_abs - activate (queue) event even if event already scheduled
8776 
8777    Inputs:
8778         uptr    =       pointer to unit
8779         event_time =    relative timeout
8780    Outputs:
8781         reason  =       result (SCPE_OK if ok)
8782 */
8783 
8784 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8785 {
8786 sim_cancel (uptr);
8787 return _sim_activate (uptr, event_time);
8788 }
8789 
8790 /* sim_activate_after - activate (queue) event
8791 
8792    Inputs:
8793         uptr    =       pointer to unit
8794         usec_delay =    relative timeout (in microseconds)
8795    Outputs:
8796         reason  =       result (SCPE_OK if ok)
8797 */
8798 
8799 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
8800 {
8801 return _sim_activate_after (uptr, usec_delay);
8802 }
8803 
8804 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
8805 {
8806 if (sim_is_active (uptr))                               /* already active? */
8807     return SCPE_OK;
8808 return sim_timer_activate_after (uptr, usec_delay);
8809 }
8810 
8811 /* sim_cancel - cancel (dequeue) event
8812 
8813    Inputs:
8814         uptr    =       pointer to unit
8815    Outputs:
8816         reason  =       result (SCPE_OK if ok)
8817 
8818 */
8819 
8820 t_stat sim_cancel (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8821 {
8822 UNIT *cptr, *nptr;
8823 #if defined(TESTING)
8824 cpu_state_t * cpup = _cpup;
8825 #endif
8826 
8827 if (sim_clock_queue == QUEUE_LIST_END)
8828     return SCPE_OK;
8829 if (!sim_is_active (uptr))
8830     return SCPE_OK;
8831 UPDATE_SIM_TIME;                                        /* update sim time */
8832 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\n", sim_uname(uptr));
8833 nptr = QUEUE_LIST_END;
8834 
8835 if (sim_clock_queue == uptr) {
8836     nptr = sim_clock_queue = uptr->next;
8837     uptr->next = NULL;                                  /* hygiene */
8838     }
8839 else {
8840     for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8841         if (cptr->next == uptr) {
8842             nptr = cptr->next = uptr->next;
8843             uptr->next = NULL;                          /* hygiene */
8844             break;                                      /* end queue scan */
8845             }
8846         }
8847     }
8848 if (nptr != QUEUE_LIST_END)
8849     nptr->time += (uptr->next) ? 0 : uptr->time;
8850 if (!uptr->next)
8851     uptr->time = 0;
8852 if (sim_clock_queue != QUEUE_LIST_END)
8853     sim_interval = sim_clock_queue->time;
8854 else sim_interval = noqueue_time = NOQUEUE_WAIT;
8855 if (uptr->next) {
8856     sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
8857     if (sim_deb)
8858         fclose(sim_deb);
8859     (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
8860                    __func__, __FILE__, __LINE__);
8861     abort ();
8862     }
8863 return SCPE_OK;
8864 }
8865 
8866 /* sim_is_active - test for entry in queue
8867 
8868    Inputs:
8869         uptr    =       pointer to unit
8870    Outputs:
8871         result =        TRUE if unit is busy, FALSE inactive
8872 */
8873 
8874 t_bool sim_is_active (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8875 {
8876 if (uptr->next == NULL)
8877   return FALSE;
8878 else
8879 return TRUE;
8880 }
8881 
8882 /* sim_activate_time - return activation time
8883 
8884    Inputs:
8885         uptr    =       pointer to unit
8886    Outputs:
8887         result =        absolute activation time + 1, 0 if inactive
8888 */
8889 
8890 int32 sim_activate_time (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8891 {
8892 UNIT *cptr;
8893 int32 accum = 0;
8894 
8895 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8896     if (cptr == sim_clock_queue) {
8897         if (sim_interval > 0)
8898             accum = accum + sim_interval;
8899         }
8900     else
8901         accum = accum + cptr->time;
8902     if (cptr == uptr)
8903         return accum + 1;
8904     }
8905 return 0;
8906 }
8907 
8908 /* sim_gtime - return global time
8909 
8910    Inputs: none
8911    Outputs:
8912         time    =       global time
8913 */
8914 
8915 double sim_gtime (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8916 {
8917 return sim_time;
8918 }
8919 
8920 /* sim_qcount - return queue entry count
8921 
8922    Inputs: none
8923    Outputs:
8924         count   =       number of entries on the queue
8925 */
8926 
8927 int32 sim_qcount (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8928 {
8929 int32 cnt;
8930 UNIT *uptr;
8931 
8932 cnt = 0;
8933 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
8934     cnt++;
8935 return cnt;
8936 }
8937 
8938 /* Breakpoint package.  This module replaces the VM-implemented one
8939    instruction breakpoint capability.
8940 
8941    Breakpoints are stored in table sim_brk_tab, which is ordered by address for
8942    efficient binary searching.  A breakpoint consists of a six entry structure:
8943 
8944         addr                    address of the breakpoint
8945         type                    types of breakpoints set on the address
8946                                 a bit mask representing letters A-Z
8947         cnt                     number of iterations before breakp is taken
8948         action                  pointer command string to be executed
8949                                 when break is taken
8950         next                    list of other breakpoints with the same addr specifier
8951         time_fired              array of when this breakpoint was fired for each class
8952 
8953    sim_brk_summ is a summary of the types of breakpoints that are currently set (it
8954    is the bitwise OR of all the type fields).  A simulator need only check for
8955    a breakpoint of type X if bit SWMASK('X') is set in sim_brk_summ.
8956 
8957    The package contains the following public routines:
8958 
8959         sim_brk_init            initialize
8960         sim_brk_set             set breakpoint
8961         sim_brk_clr             clear breakpoint
8962         sim_brk_clrall          clear all breakpoints
8963         sim_brk_show            show breakpoint
8964         sim_brk_showall         show all breakpoints
8965         sim_brk_test            test for breakpoint
8966         sim_brk_npc             PC has been changed
8967         sim_brk_getact          get next action
8968         sim_brk_clract          clear pending actions
8969 
8970    Initialize breakpoint system.
8971 */
8972 
8973 t_stat sim_brk_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8974 {
8975 int32 i;
8976 
8977 for (i=0; i<sim_brk_lnt; i++) {
8978     BRKTAB *bp;
8979     if (sim_brk_tab)
8980       {
8981         bp = sim_brk_tab[i];
8982 
8983         while (bp)
8984           {
8985             BRKTAB *bpt = bp->next;
8986 
8987             FREE (bp->act);
8988             FREE (bp);
8989             bp = bpt;
8990           }
8991       }
8992 }
8993 if (sim_brk_tab != NULL)
8994     (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
8995 sim_brk_lnt = SIM_BRK_INILNT;
8996 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
8997 if (sim_brk_tab == NULL)
8998     return SCPE_MEM;
8999 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9000 sim_brk_ent = sim_brk_ins = 0;
9001 sim_brk_clract ();
9002 sim_brk_npc (0);
9003 return SCPE_OK;
9004 }
9005 
9006 /* Search for a breakpoint in the sorted breakpoint table */
9007 
9008 BRKTAB *sim_brk_fnd (t_addr loc)
     /* [previous][next][first][last][top][bottom][index][help] */
9009 {
9010 int32 lo, hi, p;
9011 BRKTAB *bp;
9012 
9013 if (sim_brk_ent == 0) {                                 /* table empty? */
9014     sim_brk_ins = 0;                                    /* insrt at head */
9015     return NULL;                                        /* sch fails */
9016     }
9017 lo = 0;                                                 /* initial bounds */
9018 hi = sim_brk_ent - 1;
9019 do {
9020     p = (lo + hi) >> 1;                                 /* probe */
9021     bp = sim_brk_tab[p];                                /* table addr */
9022     if (loc == bp->addr) {                              /* match? */
9023         sim_brk_ins = p;
9024         return bp;
9025         }
9026     else if (loc < bp->addr)                            /* go down? p is upper */
9027         hi = p - 1;
9028     else lo = p + 1;                                    /* go up? p is lower */
9029     } while (lo <= hi);
9030 if (loc < bp->addr)                                     /* insrt before or */
9031     sim_brk_ins = p;
9032 else sim_brk_ins = p + 1;                               /* after last sch */
9033 return NULL;
9034 }
9035 
9036 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
     /* [previous][next][first][last][top][bottom][index][help] */
9037 {
9038 BRKTAB *bp = sim_brk_fnd (loc);
9039 
9040 while (bp) {
9041     if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9042                   (bp->typ == btyp))
9043         return bp;
9044     bp = bp->next;
9045     }
9046 return bp;
9047 }
9048 
9049 /* Insert a breakpoint */
9050 
9051 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9052 {
9053 int32 i, t;
9054 BRKTAB *bp, **newp;
9055 
9056 if (sim_brk_ins < 0)
9057     return NULL;
9058 if (sim_brk_ent >= sim_brk_lnt) {                       /* out of space? */
9059     t = sim_brk_lnt + SIM_BRK_INILNT;                   /* new size */
9060     newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));    /* new table */
9061     if (newp == NULL)                                   /* can't extend */
9062         return NULL;
9063     memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));/* copy table */
9064     (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));/* zero new entries */
9065     FREE (sim_brk_tab);                                 /* free old table */
9066     sim_brk_tab = newp;                                 /* new base, lnt */
9067     sim_brk_lnt = t;
9068     }
9069 if ((sim_brk_ins == sim_brk_ent) ||
9070     ((sim_brk_ins != sim_brk_ent) && //-V728
9071      (sim_brk_tab[sim_brk_ins]->addr != loc))) {        /* need to open a hole? */
9072     for (i = sim_brk_ent; i > sim_brk_ins; --i)
9073         sim_brk_tab[i] = sim_brk_tab[i - 1];
9074     sim_brk_tab[sim_brk_ins] = NULL;
9075     }
9076 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9077 if (!bp)
9078   {
9079     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9080                    __func__, __FILE__, __LINE__);
9081 #if defined(USE_BACKTRACE)
9082 # if defined(SIGUSR2)
9083     (void)raise(SIGUSR2);
9084     /*NOTREACHED*/ /* unreachable */
9085 # endif /* if defined(SIGUSR2) */
9086 #endif /* if defined(USE_BACKTRACE) */
9087     abort();
9088   }
9089 bp->next = sim_brk_tab[sim_brk_ins];
9090 sim_brk_tab[sim_brk_ins] = bp;
9091 if (bp->next == NULL)
9092     sim_brk_ent += 1;
9093 bp->addr = loc;
9094 bp->typ = btyp;
9095 bp->cnt = 0;
9096 bp->act = NULL;
9097 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9098     bp->time_fired[i] = -1.0;
9099 return bp;
9100 }
9101 
9102 /* Set a breakpoint of type sw */
9103 
9104 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
     /* [previous][next][first][last][top][bottom][index][help] */
9105 {
9106 BRKTAB *bp;
9107 
9108 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9109     sw |= sim_brk_dflt;
9110 if (~sim_brk_types & sw) {
9111     char gbuf[CBUFSIZE];
9112 
9113     return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9114     }
9115 if ((sw & BRK_TYP_DYN_ALL) && act)                      /* can't specify an action with a dynamic breakpoint */
9116     return SCPE_ARG;
9117 bp = sim_brk_fnd (loc);                                 /* loc present? */
9118 if (!bp)                                                /* no, allocate */
9119     bp = sim_brk_new (loc, sw);
9120 else {
9121     while (bp && (bp->typ != (uint32)sw))
9122         bp = bp->next;
9123     if (!bp)
9124         bp = sim_brk_new (loc, sw);
9125     }
9126 if (!bp)                                                /* still no? mem err */
9127     return SCPE_MEM;
9128 bp->cnt = ncnt;                                         /* set count */
9129 if ((!(sw & BRK_TYP_DYN_ALL)) &&                        /* Not Dynamic and */
9130     (bp->act != NULL) && (act != NULL)) {               /* replace old action? */
9131     FREE (bp->act);                                     /* deallocate */
9132     bp->act = NULL;                                     /* now no action */
9133     }
9134 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9135     char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char)); /* alloc buf */
9136     if (newp == NULL)                                   /* mem err? */
9137         return SCPE_MEM;
9138     strncpy (newp, act, CBUFSIZE);                      /* copy action */
9139     bp->act = newp;                                     /* set pointer */
9140     }
9141 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9142 return SCPE_OK;
9143 }
9144 
9145 /* Clear a breakpoint */
9146 
9147 t_stat sim_brk_clr (t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9148 {
9149 BRKTAB *bpl = NULL;
9150 BRKTAB *bp = sim_brk_fnd (loc);
9151 int32 i;
9152 
9153 if (!bp)                                                /* not there? ok */
9154     return SCPE_OK;
9155 if (sw == 0)
9156     sw = SIM_BRK_ALLTYP;
9157 
9158 #if !defined(__clang_analyzer__)
9159 while (bp) {
9160     if (bp->typ == (bp->typ & sw)) {
9161         FREE (bp->act);                                 /* deallocate action */
9162         if (bp == sim_brk_tab[sim_brk_ins])
9163             bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9164         else
9165           {
9166             if (bpl)
9167               bpl->next = bp->next;
9168           }
9169         FREE (bp);
9170         bp = bpl;
9171         }
9172     else {
9173         bpl = bp;
9174         bp = bp->next;
9175         }
9176     }
9177 #endif /* if !defined(__clang_analyzer__) */
9178 if (sim_brk_tab[sim_brk_ins] == NULL) {                 /* erased entry */
9179     sim_brk_ent = sim_brk_ent - 1;                      /* decrement count */
9180     for (i = sim_brk_ins; i < sim_brk_ent; i++)         /* shuffle remaining entries */
9181         sim_brk_tab[i] = sim_brk_tab[i+1];
9182     }
9183 sim_brk_summ = 0;                                       /* recalc summary */
9184 for (i = 0; i < sim_brk_ent; i++) {
9185     bp = sim_brk_tab[i];
9186     while (bp) {
9187         sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9188         bp = bp->next;
9189         }
9190     }
9191 return SCPE_OK;
9192 }
9193 
9194 /* Clear all breakpoints */
9195 
9196 t_stat sim_brk_clrall (int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9197 {
9198 int32 i;
9199 
9200 if (sw == 0)
9201     sw = SIM_BRK_ALLTYP;
9202 for (i = 0; i < sim_brk_ent;) {
9203     t_addr loc = sim_brk_tab[i]->addr;
9204     sim_brk_clr (loc, sw);
9205     if ((i < sim_brk_ent) &&
9206         (loc == sim_brk_tab[i]->addr))
9207         ++i;
9208     }
9209 return SCPE_OK;
9210 }
9211 
9212 /* Show a breakpoint */
9213 
9214 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9215 {
9216 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9217 DEVICE *dptr;
9218 int32 i, any;
9219 
9220 if ((sw == 0) || (sw == SWMASK ('C'))) {
9221     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9222 if (!bp || (!(bp->typ & sw))) {
9223     return SCPE_OK; }
9224 dptr = sim_dflt_dev;
9225 if (dptr == NULL) {
9226     return SCPE_OK; }
9227 if (sw & SWMASK ('C')) {
9228     if (st != NULL) {
9229         (void)fprintf (st, "SET BREAK "); }
9230 } else {
9231     if (sim_vm_fprint_addr) {
9232         sim_vm_fprint_addr
9233             (st, dptr, loc);
9234     } else {
9235         fprint_val
9236             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9237     if (st != NULL) {
9238         (void)fprintf (st, ":\t"); }
9239     }
9240 for (i = any = 0; i < 26; i++) {
9241     if ((bp->typ >> i) & 1) {
9242         if ((sw & SWMASK ('C')) == 0) {
9243             if (any) {
9244                 if (st != NULL) {
9245                     (void)fprintf (st, ", "); } }
9246             if (st != NULL) {
9247                 fputc (i + 'A', st); }
9248             }
9249         } else {
9250             if (st != NULL) {
9251                 (void)fprintf (st, "-%c", i + 'A'); }
9252         any = 1;
9253         }
9254     }
9255 if (sw & SWMASK ('C')) {
9256     if (st != NULL) {
9257         (void)fprintf (st, " "); }
9258     if (sim_vm_fprint_addr) {
9259         if (st != NULL) {
9260             sim_vm_fprint_addr (st, dptr, loc); }
9261     } else {
9262         fprint_val
9263             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9264     }
9265 if (bp->cnt > 0) {
9266     if (st != NULL) {
9267         (void)fprintf (st, "[%d]", bp->cnt); } }
9268 if (bp->act != NULL) {
9269     if (st != NULL) {
9270         (void)fprintf (st, "; %s", bp->act); } }
9271 (void)fprintf (st, "\n");
9272 return SCPE_OK;
9273 }
9274 
9275 /* Show all breakpoints */
9276 
9277 t_stat sim_brk_showall (FILE *st, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9278 {
9279 int32 bit, mask, types;
9280 BRKTAB **bpt;
9281 
9282 if ((sw == 0) || (sw == SWMASK ('C')))
9283     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9284 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9285     if (sim_brk_types & (1 << bit))
9286         ++types;
9287 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9288     (void)fprintf (st, "Supported Breakpoint Types:");
9289     for (bit=0; bit <= ('Z'-'A'); bit++)
9290         if (sim_brk_types & (1 << bit))
9291             (void)fprintf (st, " -%c", 'A' + bit);
9292     (void)fprintf (st, "\n");
9293     }
9294 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9295     mask = (sw & sim_brk_types);
9296     (void)fprintf (st, "Displaying Breakpoint Types:");
9297     for (bit=0; bit <= ('Z'-'A'); bit++)
9298         if (mask & (1 << bit))
9299             (void)fprintf (st, " -%c", 'A' + bit);
9300     (void)fprintf (st, "\n");
9301     }
9302 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9303     BRKTAB *prev = NULL;
9304     BRKTAB *cur = *bpt;
9305     BRKTAB *next;
9306     /* First reverse the list */
9307     while (cur) {
9308         next = cur->next;
9309         cur->next = prev;
9310         prev = cur;
9311         cur = next;
9312         }
9313     /* save reversed list in the head pointer so lookups work */
9314     *bpt = prev;
9315     /* Walk the reversed list and print it in the order it was defined in */
9316     cur = prev;
9317     while (cur) {
9318         if (cur->typ & sw)
9319             sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9320         cur = cur->next;
9321         }
9322     /* reversing the list again */
9323     cur = prev;
9324     prev = NULL;
9325     while (cur) {
9326         next = cur->next;
9327         cur->next = prev;
9328         prev = cur;
9329         cur = next;
9330         }
9331     /* restore original list */
9332     *bpt = prev;
9333     }
9334 return SCPE_OK;
9335 }
9336 
9337 /* Test for breakpoint */
9338 
9339 uint32 sim_brk_test (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9340 {
9341 BRKTAB *bp;
9342 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9343 
9344 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9345     btyp |= BRK_TYP_DYN_ALL;
9346 
9347 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {     /* in table, and type match? */
9348     double s_gtime = sim_gtime ();                      /* get time now */
9349 
9350     if (bp->time_fired[spc] == s_gtime)                 /* already taken?  */
9351         return 0;
9352     bp->time_fired[spc] = s_gtime;                      /* remember match time */
9353     if (--bp->cnt > 0)                                  /* count > 0? */
9354         return 0;
9355     bp->cnt = 0;                                        /* reset count */
9356     sim_brk_setact (bp->act);                           /* set up actions */
9357     sim_brk_match_type = btyp & bp->typ;                /* set return value */
9358     if (bp->typ & BRK_TYP_TEMP)
9359         sim_brk_clr (loc, bp->typ);                     /* delete one-shot breakpoint */
9360     sim_brk_match_addr = loc;
9361     return sim_brk_match_type;
9362     }
9363 return 0;
9364 }
9365 
9366 /* Get next pending action, if any */
9367 
9368 CONST char *sim_brk_getact (char *buf, int32 size)
     /* [previous][next][first][last][top][bottom][index][help] */
9369 {
9370 char *ep;
9371 size_t lnt;
9372 
9373 if (sim_brk_act[sim_do_depth] == NULL)                  /* any action? */
9374     return NULL;
9375 while (sim_isspace (*sim_brk_act[sim_do_depth]))        /* skip spaces */
9376     sim_brk_act[sim_do_depth]++;
9377 if (*sim_brk_act[sim_do_depth] == 0) {                  /* now empty? */
9378     return sim_brk_clract ();
9379     }
9380 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {   /* cmd delimiter? */
9381     lnt = ep - sim_brk_act[sim_do_depth];               /* cmd length */
9382     memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);   /* copy with ; */
9383     buf[lnt] = 0;                                       /* erase ; */
9384     sim_brk_act[sim_do_depth] += lnt + 1;               /* adv ptr */
9385     }
9386 else {
9387     strncpy (buf, sim_brk_act[sim_do_depth], size);     /* copy action */
9388     sim_brk_clract ();                                  /* no more */
9389     }
9390 return buf;
9391 }
9392 
9393 /* Clear pending actions */
9394 
9395 char *sim_brk_clract (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9396 {
9397 FREE (sim_brk_act_buf[sim_do_depth]);
9398 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9399 }
9400 
9401 /* Set up pending actions */
9402 
9403 void sim_brk_setact (const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
9404 {
9405 if (action) {
9406     sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9407     if (!sim_brk_act_buf[sim_do_depth])
9408       {
9409         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9410                        __func__, __FILE__, __LINE__);
9411 #if defined(USE_BACKTRACE)
9412 # if defined(SIGUSR2)
9413         (void)raise(SIGUSR2);
9414         /*NOTREACHED*/ /* unreachable */
9415 # endif /* if defined(SIGUSR2) */
9416 #endif /* if defined(USE_BACKTRACE) */
9417         abort();
9418       }
9419     strcpy (sim_brk_act_buf[sim_do_depth], action);
9420     sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9421     }
9422 else
9423     sim_brk_clract ();
9424 }
9425 
9426 /* New PC */
9427 
9428 void sim_brk_npc (uint32 cnt)
     /* [previous][next][first][last][top][bottom][index][help] */
9429 {
9430 uint32 spc;
9431 BRKTAB **bpt, *bp;
9432 
9433 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9434     cnt = SIM_BKPT_N_SPC;
9435 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9436     for (bp = *bpt; bp; bp = bp->next) {
9437         for (spc = 0; spc < cnt; spc++)
9438             bp->time_fired[spc] = -1.0;
9439         }
9440     }
9441 }
9442 
9443 /* Clear breakpoint space */
9444 
9445 void sim_brk_clrspc (uint32 spc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9446 {
9447 BRKTAB **bpt, *bp;
9448 
9449 if (spc < SIM_BKPT_N_SPC) {
9450     for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9451         for (bp = *bpt; bp; bp = bp->next) {
9452             if (bp->typ & btyp)
9453                 bp->time_fired[spc] = -1.0;
9454             }
9455         }
9456     }
9457 }
9458 
9459 const char *sim_brk_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
9460 {
9461 static char msg[256];
9462 char addr[65];
9463 char buf[32];
9464 
9465 msg[0] = '\0';
9466 if (sim_dflt_dev) {
9467   if (sim_vm_sprint_addr)
9468     sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9469   else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9470 }
9471 if (sim_brk_type_desc) {
9472     BRKTYPTAB *brk = sim_brk_type_desc;
9473 
9474     while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9475         if (brk->btyp == sim_brk_match_type) {
9476             (void)sprintf (msg, "%s: %s", brk->desc, addr);
9477             break;
9478             }
9479         brk++;
9480         }
9481     }
9482 if (!msg[0])
9483     (void)sprintf (msg, "%s Breakpoint at: %s\n",
9484                    put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9485 
9486 return msg;
9487 }
9488 
9489 /* Expect package.  This code provides a mechanism to stop and control simulator
9490    execution based on traffic coming out of simulated ports and as well as a means
9491    to inject data into those ports.  It can conceptually viewed as a string
9492    breakpoint package.
9493 
9494    Expect rules are stored in tables associated with each port which can use this
9495    facility.  An expect rule consists of a five entry structure:
9496 
9497         match                   the expect match string
9498         size                    the number of bytes in the match string
9499         match_pattern           the expect match string in display format
9500         cnt                     number of iterations before match is declared
9501         action                  command string to be executed when match occurs
9502 
9503    All active expect rules are contained in an expect match context structure.
9504 
9505         rules                   the match rules
9506         size                    the count of match rules
9507         buf                     the buffer of output data which has been produced
9508         buf_ins                 the buffer insertion point for the next output data
9509         buf_size                the buffer size
9510 
9511    The package contains the following public routines:
9512 
9513         sim_set_expect          expect command parser and initializer
9514         sim_set_noexpect        noexpect command parser
9515         sim_exp_set             set or add an expect rule
9516         sim_exp_clr             clear or delete an expect rule
9517         sim_exp_clrall          clear all expect rules
9518         sim_exp_show            show an expect rule
9519         sim_exp_showall         show all expect rules
9520         sim_exp_check           test for rule match
9521 */
9522 
9523 /* Set expect */
9524 
9525 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9526 {
9527 char gbuf[CBUFSIZE];
9528 CONST char *tptr;
9529 CONST char *c1ptr;
9530 t_bool after_set = FALSE;
9531 uint32 after;
9532 int32 cnt = 0;
9533 t_stat r;
9534 
9535 if (exp == NULL)
9536     return sim_messagef (SCPE_ARG, "Null exp!\n");
9537 after = exp->after;
9538 
9539 if ((cptr == NULL) || (*cptr == 0))
9540     return SCPE_2FARG;
9541 if (*cptr == '[') {
9542     cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9543     if ((cptr == c1ptr) || (*c1ptr != ']'))
9544         return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n");
9545     cptr = c1ptr + 1;
9546     while (sim_isspace(*cptr))
9547         ++cptr;
9548     }
9549 tptr = get_glyph (cptr, gbuf, ',');
9550 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9551     after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9552     if (r != SCPE_OK)
9553         return sim_messagef (SCPE_ARG, "Invalid Halt After Value\n");
9554     after_set = TRUE;
9555     cptr = tptr;
9556     }
9557 if ((*cptr != '"') && (*cptr != '\''))
9558     return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
9559 cptr = get_glyph_quoted (cptr, gbuf, 0);
9560 
9561 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9562 }
9563 
9564 /* Clear expect */
9565 
9566 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9567 {
9568 char gbuf[CBUFSIZE];
9569 
9570 if (NULL == cptr || !*cptr)
9571     return sim_exp_clrall (exp);                    /* clear all rules */
9572 if ((*cptr != '"') && (*cptr != '\''))
9573     return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
9574 cptr = get_glyph_quoted (cptr, gbuf, 0);
9575 if (*cptr != '\0')
9576     return SCPE_2MARG;                              /* No more arguments */
9577 return sim_exp_clr (exp, gbuf);                     /* clear one rule */
9578 }
9579 
9580 /* Search for an expect rule in an expect context */
9581 
9582 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
     /* [previous][next][first][last][top][bottom][index][help] */
9583 {
9584 size_t i;
9585 
9586 if (NULL == exp->rules)
9587     return NULL;
9588 for (i=start_rule; i<exp->size; i++)
9589     if (!strcmp (exp->rules[i].match_pattern, match))
9590         return &exp->rules[i];
9591 return NULL;
9592 }
9593 
9594 /* Clear (delete) an expect rule */
9595 
9596 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9597 {
9598 size_t i;
9599 
9600 if (NULL == ep)                                         /* not there? ok */
9601     return SCPE_OK;
9602 FREE (ep->match);                                       /* deallocate match string */
9603 FREE (ep->match_pattern);                               /* deallocate the display format match string */
9604 FREE (ep->act);                                         /* deallocate action */
9605 exp->size -= 1;                                         /* decrement count */
9606 #if !defined(__clang_analyzer__)
9607 for (i=ep-exp->rules; i<exp->size; i++)                 /* shuffle up remaining rules */
9608     exp->rules[i] = exp->rules[i+1];
9609 if (exp->size == 0) {                                   /* No rules left? */
9610     FREE (exp->rules);
9611     exp->rules = NULL;
9612     }
9613 #endif /* if !defined(__clang_analyzer__) */
9614 return SCPE_OK;
9615 }
9616 
9617 t_stat sim_exp_clr (EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9618 {
9619 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9620 
9621 while (ep) {
9622     sim_exp_clr_tab (exp, ep);
9623     ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9624     }
9625 return SCPE_OK;
9626 }
9627 
9628 /* Clear all expect rules */
9629 
9630 t_stat sim_exp_clrall (EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
9631 {
9632 int32 i;
9633 
9634 for (i=0; i<exp->size; i++) {
9635     FREE (exp->rules[i].match);                         /* deallocate match string */
9636     FREE (exp->rules[i].match_pattern);                 /* deallocate display format match string */
9637     FREE (exp->rules[i].act);                           /* deallocate action */
9638     }
9639 FREE (exp->rules);
9640 exp->rules = NULL;
9641 exp->size = 0;
9642 FREE (exp->buf);
9643 exp->buf = NULL;
9644 exp->buf_size = 0;
9645 exp->buf_ins = 0;
9646 return SCPE_OK;
9647 }
9648 
9649 /* Set/Add an expect rule */
9650 
9651 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] */
9652 {
9653 EXPTAB *ep;
9654 uint8 *match_buf;
9655 uint32 match_size;
9656 size_t i;
9657 
9658 /* Validate the match string */
9659 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9660 if (!match_buf)
9661     return SCPE_MEM;
9662 if (switches & EXP_TYP_REGEX) {
9663     FREE (match_buf);
9664     return sim_messagef (SCPE_ARG, "RegEx support not available\n");
9665     }
9666 else {
9667     if (switches & EXP_TYP_REGEX_I) {
9668         FREE (match_buf);
9669         return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\n");
9670         }
9671     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9672     if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9673         FREE (match_buf);
9674         return sim_messagef (SCPE_ARG, "Invalid quoted string\n");
9675         }
9676     }
9677 FREE (match_buf);
9678 for (i=0; i<exp->size; i++) {                           /* Make sure this rule won't be occluded */
9679     if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9680         (exp->rules[i].switches & EXP_TYP_PERSIST))
9681         return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\n");
9682     }
9683 if (after && exp->size)
9684     return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n");
9685 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9686 if (!exp->rules)
9687   {
9688     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9689                    __func__, __FILE__, __LINE__);
9690 #if defined(USE_BACKTRACE)
9691 # if defined(SIGUSR2)
9692     (void)raise(SIGUSR2);
9693     /*NOTREACHED*/ /* unreachable */
9694 # endif /* if defined(SIGUSR2) */
9695 #endif /* if defined(USE_BACKTRACE) */
9696     abort();
9697   }
9698 ep = &exp->rules[exp->size];
9699 exp->size += 1;
9700 exp->after = after;                                     /* set halt after value */
9701 (void)memset (ep, 0, sizeof(*ep));
9702 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9703 if (ep->match_pattern)
9704     strcpy (ep->match_pattern, match);
9705 ep->cnt = cnt;                                          /* set proceed count */
9706 ep->switches = switches;                                /* set switches */
9707 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9708 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9709     sim_exp_clr_tab (exp, ep);                          /* clear it */
9710     FREE (match_buf);                                   /* release allocation */
9711     return SCPE_MEM;
9712     }
9713 if (switches & EXP_TYP_REGEX) {
9714     FREE (match_buf);
9715     match_buf = NULL;
9716     }
9717 else {
9718     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9719     sim_decode_quoted_string (match, match_buf, &match_size);
9720     ep->match = match_buf;
9721     ep->size = match_size;
9722     }
9723 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9724 if (!ep->match_pattern)
9725   {
9726     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9727                    __func__, __FILE__, __LINE__);
9728 #if defined(USE_BACKTRACE)
9729 # if defined(SIGUSR2)
9730     (void)raise(SIGUSR2);
9731     /*NOTREACHED*/ /* unreachable */
9732 # endif /* if defined(SIGUSR2) */
9733 #endif /* if defined(USE_BACKTRACE) */
9734     abort();
9735   }
9736 strcpy (ep->match_pattern, match);
9737 if (ep->act) {                                          /* replace old action? */
9738     FREE (ep->act);                                     /* deallocate */
9739     ep->act = NULL;                                     /* now no action */
9740     }
9741 if (act) while (sim_isspace(*act)) ++act;                   /* skip leading spaces in action string */
9742 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9743     char *newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */
9744     if (newp == NULL)                                   /* mem err? */
9745         return SCPE_MEM;
9746     strcpy (newp, act);                                 /* copy action */
9747     ep->act = newp;                                     /* set pointer */
9748     }
9749 /* Make sure that the production buffer is large enough to detect a match for all rules including a NUL termination byte */
9750 for (i=0; i<exp->size; i++) {
9751     size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9752     if (compare_size >= exp->buf_size) {
9753         exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2); /* Extra byte to null terminate regex compares */
9754         exp->buf_size = compare_size + 1;
9755         }
9756     }
9757 return SCPE_OK;
9758 }
9759 
9760 /* Show an expect rule */
9761 
9762 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9763 {
9764 if (!ep)
9765     return SCPE_OK;
9766 (void)fprintf (st, "EXPECT");
9767 if (ep->switches & EXP_TYP_PERSIST)
9768     (void)fprintf (st, " -p");
9769 if (ep->switches & EXP_TYP_CLEARALL)
9770     (void)fprintf (st, " -c");
9771 if (ep->switches & EXP_TYP_REGEX)
9772     (void)fprintf (st, " -r");
9773 if (ep->switches & EXP_TYP_REGEX_I)
9774     (void)fprintf (st, " -i");
9775 (void)fprintf (st, " %s", ep->match_pattern);
9776 if (ep->cnt > 0)
9777     (void)fprintf (st, " [%d]", ep->cnt);
9778 if (ep->act)
9779     (void)fprintf (st, " %s", ep->act);
9780 (void)fprintf (st, "\n");
9781 return SCPE_OK;
9782 }
9783 
9784 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9785 {
9786 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9787 
9788 if (exp->buf_size) {
9789     char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9790 
9791     (void)fprintf (st, "Match Buffer Size: %lld\n",
9792                    (long long)exp->buf_size);
9793     (void)fprintf (st, "Buffer Insert Offset: %lld\n",
9794                    (long long)exp->buf_ins);
9795     (void)fprintf (st, "Buffer Contents: %s\n",
9796                    bstr);
9797     FREE (bstr);
9798     }
9799 if (exp->after)
9800     (void)fprintf (st, "Halt After: %lld instructions\n",
9801                    (long long)exp->after);
9802 if (exp->dptr && exp->dbit)
9803     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\n",
9804                    sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
9805                    exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
9806 (void)fprintf (st, "Match Rules:\n");
9807 if (!*match)
9808     return sim_exp_showall (st, exp);
9809 if (!ep) {
9810     (void)fprintf (st, "No Rules match '%s'\n", match);
9811     return SCPE_ARG;
9812     }
9813 do {
9814     sim_exp_show_tab (st, exp, ep);
9815     ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
9816     } while (ep);
9817 return SCPE_OK;
9818 }
9819 
9820 /* Show all expect rules */
9821 
9822 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
9823 {
9824 size_t i;
9825 
9826 for (i=0; i < exp->size; i++)
9827     sim_exp_show_tab (st, exp, &exp->rules[i]);
9828 return SCPE_OK;
9829 }
9830 
9831 /* Test for expect match */
9832 
9833 t_stat sim_exp_check (EXPECT *exp, uint8 data)
     /* [previous][next][first][last][top][bottom][index][help] */
9834 {
9835 size_t i;
9836 EXPTAB *ep = NULL;
9837 char *tstr = NULL;
9838 #if defined(TESTING)
9839 cpu_state_t * cpup = _cpup;
9840 #endif
9841 
9842 if ((!exp) || (!exp->rules))                            /* Anything to check? */
9843     return SCPE_OK;
9844 
9845 exp->buf[exp->buf_ins++] = data;                        /* Save new data */
9846 exp->buf[exp->buf_ins] = '\0';                          /* Nul terminate for RegEx match */
9847 
9848 for (i=0; i < exp->size; i++) {
9849     ep = &exp->rules[i];
9850     if (ep == NULL)
9851         break;
9852     if (ep->switches & EXP_TYP_REGEX) {
9853         }
9854     else {
9855         if (exp->buf_ins < ep->size) {                          /* Match stradle end of buffer */
9856             /*
9857              * First compare the newly deposited data at the beginning
9858              * of buffer with the end of the match string
9859              */
9860             if (exp->buf_ins > 0) {
9861                 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9862                     char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9863                     char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
9864 
9865                     sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\n",
9866                                (long long)exp->buf_ins, estr);
9867                     sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9868                     FREE (estr);
9869                     FREE (mstr);
9870                     }
9871                 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
9872                     continue;
9873                 }
9874             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9875                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
9876                 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
9877 
9878                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\n",
9879                            (long long)exp->buf_size-(ep->size-exp->buf_ins),
9880                            (long long)ep->size-exp->buf_ins, estr);
9881                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9882                 FREE (estr);
9883                 FREE (mstr);
9884                 }
9885             if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
9886                 continue;
9887             break;
9888             }
9889         else {
9890             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
9891                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
9892                 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
9893 
9894                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\n",
9895                            (long long)exp->buf_ins-ep->size,
9896                            (long long)ep->size, estr);
9897                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
9898                 FREE (estr);
9899                 FREE (mstr);
9900                 }
9901             if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
9902                 continue;
9903             break;
9904             }
9905         }
9906     }
9907 if (exp->buf_ins == exp->buf_size) {                    /* At end of match buffer? */
9908         exp->buf_ins = 0;                               /* wrap around to beginning */
9909         sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\n");
9910     }
9911 if ((ep != NULL) && (i != exp->size)) {                 /* Found? */
9912     sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\n");
9913     if (ep->cnt > 0) {
9914         ep->cnt -= 1;
9915         sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\n",
9916                    (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
9917         }
9918     else {
9919         uint32 after   = exp->after;
9920         int32 switches = ep->switches;
9921         if (ep->act && *ep->act) {
9922             sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\n", ep->act);
9923             }
9924         else {
9925             sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\n");
9926             }
9927         sim_brk_setact (ep->act);                       /* set up actions */
9928         if (ep->switches & EXP_TYP_CLEARALL)            /* Clear-all expect rule? */
9929             sim_exp_clrall (exp);                       /* delete all rules */
9930         else {
9931             if (!(ep->switches & EXP_TYP_PERSIST))      /* One shot expect rule? */
9932                 sim_exp_clr_tab (exp, ep);              /* delete it */
9933             }
9934         sim_activate (&sim_expect_unit,                 /* schedule simulation stop when indicated */
9935                       (switches & EXP_TYP_TIME) ?
9936                             (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
9937                              after);
9938         }
9939     /* Matched data is no longer available for future matching */
9940     exp->buf_ins = 0;
9941     }
9942 if (tstr)  //-V547
9943   FREE (tstr);
9944 return SCPE_OK;
9945 }
9946 
9947 /* Queue input data for sending */
9948 
9949 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
     /* [previous][next][first][last][top][bottom][index][help] */
9950 {
9951 if (snd->extoff != 0) {
9952     if (snd->insoff > snd->extoff)
9953         memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
9954     snd->insoff -= snd->extoff;
9955     snd->extoff  = 0;
9956     }
9957 if (snd->insoff+size > snd->bufsize) {
9958     snd->bufsize = snd->insoff+size;
9959     snd->buffer  = (uint8 *)realloc(snd->buffer, snd->bufsize);
9960     if (!snd->buffer)
9961       {
9962         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9963                        __func__, __FILE__, __LINE__);
9964 #if defined(USE_BACKTRACE)
9965 # if defined(SIGUSR2)
9966         (void)raise(SIGUSR2);
9967         /*NOTREACHED*/ /* unreachable */
9968 # endif /* if defined(SIGUSR2) */
9969 #endif /* if defined(USE_BACKTRACE) */
9970         abort();
9971       }
9972     }
9973 memcpy(snd->buffer+snd->insoff, data, size);
9974 snd->insoff += size;
9975 if (delay)
9976     snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
9977 if (after)
9978     snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
9979 if (snd->after == 0)
9980     snd->after = snd->delay;
9981 snd->next_time = sim_gtime() + snd->after;
9982 return SCPE_OK;
9983 }
9984 
9985 /* Cancel Queued input data */
9986 t_stat sim_send_clear (SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
9987 {
9988 snd->insoff = 0;
9989 snd->extoff = 0;
9990 return SCPE_OK;
9991 }
9992 
9993 /* Display console Queued input data status */
9994 
9995 t_stat sim_show_send_input (FILE *st, const SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
9996 {
9997 if (snd->extoff < snd->insoff) {
9998     (void)fprintf (st, "%lld bytes of pending input Data:\n    ",
9999                    (long long)snd->insoff-snd->extoff);
10000     fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10001     (void)fprintf (st, "\n");
10002     }
10003 else
10004     (void)fprintf (st, "No Pending Input Data\n");
10005 if ((snd->next_time - sim_gtime()) > 0) {
10006     if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10007         (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\n",
10008                        (int)(snd->next_time - sim_gtime()),
10009         (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10010     else
10011         (void)fprintf (st, "Minimum of %d instructions before sending first character\n",
10012                        (int)(snd->next_time - sim_gtime()));
10013     }
10014 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10015     (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\n",
10016                    (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10017 else
10018     (void)fprintf (st, "Minimum of %d instructions between characters\n",
10019                    (int)snd->delay);
10020 if (snd->dptr && snd->dbit)
10021     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\n",
10022                    sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10023                    snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10024 return SCPE_OK;
10025 }
10026 
10027 /* Poll for Queued input data */
10028 
10029 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10030 {
10031 #if defined(TESTING)
10032 cpu_state_t * cpup = _cpup;
10033 #endif
10034 if ((NULL != snd) && (snd->extoff < snd->insoff)) {     /* pending input characters available? */
10035     if (sim_gtime() < snd->next_time) {                 /* too soon? */
10036         *stat = SCPE_OK;
10037         sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\n");
10038         }
10039     else {
10040         char dstr[8] = "";
10041         *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;/* get one */
10042         snd->next_time = sim_gtime() + snd->delay;
10043         if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10044             (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10045         sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\n", *stat & 0xFF, dstr);
10046         }
10047     return TRUE;
10048     }
10049 return FALSE;
10050 }
10051 
10052 /* Message Text */
10053 
10054 const char *sim_error_text (t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10055 {
10056 static char msgbuf[64];
10057 
10058 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);        /* remove any flags */
10059 if (stat == SCPE_OK)
10060     return "No Error";
10061 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10062     return scp_errors[stat-SCPE_BASE].message;
10063 (void)sprintf(msgbuf, "Error %d", stat);
10064 return msgbuf;
10065 }
10066 
10067 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10068 {
10069 char gbuf[CBUFSIZE];
10070 size_t cond;
10071 
10072 *stat = SCPE_ARG;
10073 cptr = get_glyph (cptr, gbuf, 0);
10074 if (0 == memcmp("SCPE_", gbuf, 5))
10075     memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));  /* skip leading SCPE_ */
10076 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10077     if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10078         cond += SCPE_BASE;
10079         break;
10080         }
10081 if (0 == strcmp(gbuf, "OK"))
10082     cond = SCPE_OK;
10083 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {       /* not found? */
10084     unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10085     if (0 == numeric_cond)                    /* try explicit number */
10086         return SCPE_ARG;
10087     cond = (t_stat) numeric_cond;
10088     }
10089 if (cond > SCPE_MAX_ERR)
10090     return SCPE_ARG;
10091 *stat = cond;
10092 return SCPE_OK;
10093 }
10094 
10095 /* Debug printout routines, from Dave Hittner */
10096 
10097 const char* debug_bstates = "01_^";
10098 char debug_line_prefix[256];
10099 int32 debug_unterm  = 0;
10100 
10101 /* Finds debug phrase matching bitmask from from device DEBTAB table */
10102 
10103 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10104 {
10105 static const char *debtab_none    = "DEBTAB_ISNULL";
10106 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10107 const char *some_match = NULL;
10108 int32 offset = 0;
10109 
10110 if (dptr->debflags == 0)
10111     return debtab_none;
10112 
10113 dbits &= dptr->dctrl;                           /* Look for just the bits that matched */
10114 
10115 /* Find matching words for bitmask */
10116 
10117 while ((offset < 32) && dptr->debflags[offset].name) {
10118     if (dptr->debflags[offset].mask == dbits)   /* All Bits Match */
10119         return dptr->debflags[offset].name;
10120     if (dptr->debflags[offset].mask & dbits)
10121         some_match = dptr->debflags[offset].name;
10122     offset++;
10123     }
10124 return some_match ? some_match : debtab_nomatch;
10125 }
10126 
10127 /* Prints standard debug prefix unless previous call unterminated */
10128 
10129 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10130 {
10131 const char* debug_type = get_dbg_verb (dbits, dptr);
10132 char tim_t[32] = "";
10133 char tim_a[32] = "";
10134 char  pc_s[64] = "";
10135 struct timespec time_now;
10136 
10137 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10138     clock_gettime(CLOCK_REALTIME, &time_now);
10139     if (sim_deb_switches & SWMASK ('R'))
10140         sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10141     if (sim_deb_switches & SWMASK ('T')) {
10142         time_t tnow = (time_t)time_now.tv_sec;
10143         struct tm *now = gmtime(&tnow);
10144         (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10145                       (int)now->tm_hour,
10146                       (int)now->tm_min,
10147                       (int)now->tm_sec,
10148                       (long)(time_now.tv_nsec / 1000000));
10149         }
10150     if (sim_deb_switches & SWMASK ('A')) {
10151         (void)sprintf(tim_t, "%d.%03ld ",
10152                       (int)(time_now.tv_sec),
10153                       (long)(time_now.tv_nsec / 1000000));
10154         }
10155     }
10156 if (sim_deb_switches & SWMASK ('P')) {
10157     t_value val;
10158 
10159     if (sim_vm_pc_value)
10160         val = (*sim_vm_pc_value)();
10161     else
10162         val = get_rval (sim_PC, 0);
10163     (void)sprintf(pc_s, "-%s:", sim_PC->name);
10164     sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10165     }
10166 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10167               tim_t, tim_a, sim_gtime(), pc_s,
10168               "", dptr->name, debug_type);
10169 return debug_line_prefix;
10170 }
10171 
10172 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
     /* [previous][next][first][last][top][bottom][index][help] */
10173 {
10174 int32 i, fields, offset;
10175 uint32 value, beforevalue, mask;
10176 
10177 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10178     if (bitdefs[fields].offset == 0xffffffff)       /* fixup uninitialized offsets */
10179         bitdefs[fields].offset = offset;
10180     offset += bitdefs[fields].width;
10181     }
10182 for (i = fields-1; i >= 0; i--) {                   /* print xlation, transition */
10183     if (bitdefs[i].name[0] == '\0')
10184         continue;
10185     if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10186         int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10187         (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10188         }
10189     else {
10190         const char *delta = "";
10191         mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10192         value = (uint32)((after >> bitdefs[i].offset) & mask);
10193         beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10194         if (value < beforevalue)
10195             delta = "_";
10196         if (value > beforevalue)
10197             delta = "^";
10198         if (bitdefs[i].valuenames)
10199             (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10200         else
10201             if (bitdefs[i].format) {
10202                 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10203                 (void)Fprintf(stream, bitdefs[i].format, value);
10204                 (void)Fprintf(stream, " ");
10205                 }
10206             else
10207                 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10208         }
10209     }
10210 }
10211 
10212 /* Prints state of a register: bit translation + state (0,1,_,^)
10213    indicating the state and transition of the bit and bitfields. States:
10214    0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */
10215 
10216 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
     /* [previous][next][first][last][top][bottom][index][help] */
10217     BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10218 {
10219 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10220     if (!debug_unterm)
10221         (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));         /* print prefix if required */
10222     if (header)
10223         (void)fprintf(sim_deb, "%s: ", header);
10224     fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs); /* print xlation, transition */
10225     if (terminate)
10226         (void)fprintf(sim_deb, "\r\n");
10227     debug_unterm = terminate ? 0 : 1;                   /* set unterm for next */
10228     }
10229 }
10230 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
     /* [previous][next][first][last][top][bottom][index][help] */
10231     uint32 before, uint32 after, int terminate)
10232 {
10233 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10234 }
10235 
10236 /* Print message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10237 void sim_printf (const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10238 {
10239 char stackbuf[STACKBUFSIZE];
10240 int32 bufsize = sizeof(stackbuf);
10241 char *buf = stackbuf;
10242 int32 len;
10243 va_list arglist;
10244 
10245 while (1) {                                         /* format passed string, args */
10246     va_start (arglist, fmt);
10247     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10248     va_end (arglist);
10249 
10250 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10251 
10252     if ((len < 0) || (len >= bufsize-1)) {
10253         if (buf != stackbuf)
10254             FREE (buf);
10255         bufsize = bufsize * 2;
10256         if (bufsize < len + 2)
10257             bufsize = len + 2;
10258         buf = (char *) malloc (bufsize);
10259         if (buf == NULL)                            /* out of memory */
10260             return;
10261         buf[bufsize-1] = '\0';
10262         continue;
10263         }
10264     break;
10265     }
10266 
10267 if (sim_is_running) {
10268     char *c, *remnant = buf;
10269     while ((c = strchr(remnant, '\n'))) {
10270         if ((c != buf) && (*(c - 1) != '\r'))
10271             (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10272         else
10273             (void)printf("%.*s\n", (int)(c-remnant), remnant);
10274         remnant = c + 1;
10275         }
10276     (void)printf("%s", remnant);
10277     }
10278 else
10279     (void)printf("%s", buf);
10280 if (sim_log && (sim_log != stdout))
10281     (void)fprintf (sim_log, "%s", buf);
10282 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10283     (void)fprintf (sim_deb, "%s", buf);
10284 
10285 if (buf != stackbuf)
10286     FREE (buf);
10287 }
10288 
10289 /* Print command result message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10290 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10291 {
10292 char stackbuf[STACKBUFSIZE];
10293 size_t bufsize = sizeof(stackbuf);
10294 char *buf = stackbuf;
10295 size_t len;
10296 va_list arglist;
10297 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10298 
10299 while (1) {                                         /* format passed string, args */
10300     va_start (arglist, fmt);
10301     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10302     va_end (arglist);
10303 
10304 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10305 
10306     if (len >= bufsize - 1) {
10307         if (buf != stackbuf)
10308             FREE (buf);
10309         bufsize = bufsize * 2;
10310         if (bufsize < len + 2)
10311             bufsize = len + 2;
10312         buf = (char *) malloc (bufsize);
10313         if (buf == NULL)                            /* out of memory */
10314             return SCPE_MEM;
10315         buf[bufsize-1] = '\0';
10316         continue;
10317         }
10318     break;
10319     }
10320 
10321 if (sim_do_ocptr[sim_do_depth]) {
10322     if (!sim_do_echo && !sim_quiet && !inhibit_message)
10323         sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
10324     else {
10325         if (sim_deb)                        /* Always put context in debug output */
10326             (void)fprintf (sim_deb, "%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
10327         }
10328     }
10329 if (sim_is_running && !inhibit_message) {
10330     char *c, *remnant = buf;
10331     while ((c = strchr(remnant, '\n'))) {
10332         if ((c != buf) && (*(c - 1) != '\r'))
10333             (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10334         else
10335             (void)printf("%.*s\n", (int)(c-remnant), remnant);
10336         remnant = c + 1;
10337         }
10338     (void)printf("%s", remnant);
10339     }
10340 else {
10341     if (!inhibit_message)
10342         (void)printf("%s", buf);
10343     }
10344 if (sim_log && (sim_log != stdout) && !inhibit_message)
10345     (void)fprintf (sim_log, "%s", buf);
10346 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))/* Always display messages in debug output */
10347     (void)fprintf (sim_deb, "%s", buf);
10348 
10349 if (buf != stackbuf)
10350     FREE (buf);
10351 return stat | SCPE_NOMESSAGE;
10352 }
10353 
10354 /* Inline debugging - will print debug message if debug file is
10355    set and the bitmask matches the current device debug options.
10356    Extra returns are added for un*x systems, since the output
10357    device is set into 'raw' mode when the cpu is booted,
10358    and the extra returns don't hurt any other systems.
10359    Callers should be calling sim_debug() which is a macro
10360    defined in scp.h which evaluates the action condition before
10361    incurring call overhead. */
10362 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10363 {
10364 DEVICE *dptr = (DEVICE *)vdptr;
10365 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10366     char stackbuf[STACKBUFSIZE];
10367     int32 bufsize = sizeof(stackbuf);
10368     char *buf = stackbuf;
10369     va_list arglist;
10370     int32 i, j, len;
10371     const char* debug_prefix = sim_debug_prefix(dbits, dptr);   /* prefix to print if required */
10372 
10373     buf[bufsize-1] = '\0';
10374     while (1) {                                         /* format passed string, args */
10375         va_start (arglist, fmt);
10376         len = vsnprintf (buf, bufsize-1, fmt, arglist);
10377         va_end (arglist);
10378 
10379 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10380 
10381         if ((len < 0) || (len >= bufsize-1)) {
10382             if (buf != stackbuf)
10383                 FREE (buf);
10384             bufsize = bufsize * 2;
10385             if (bufsize < len + 2)
10386                 bufsize = len + 2;
10387             buf = (char *) malloc (bufsize);
10388             if (buf == NULL)                            /* out of memory */
10389                 return;
10390             buf[bufsize-1] = '\0';
10391             continue;
10392             }
10393         break;
10394         }
10395 
10396 /* Output the formatted data expanding newlines where they exist */
10397 
10398     for (i = j = 0; i < len; ++i) {
10399         if ('\n' == buf[i]) {
10400             if (i >= j) {
10401                 if ((i != j) || (i == 0)) {
10402                     if (debug_unterm)
10403                         (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10404                     else                                /* print prefix when required */
10405                         (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10406                     }
10407                 debug_unterm = 0;
10408                 }
10409             j = i + 1;
10410             }
10411         }
10412     if (i > j) {
10413         if (debug_unterm)
10414             (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10415         else                                        /* print prefix when required */
10416             (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10417         }
10418 
10419 /* Set unterminated flag for next time */
10420 
10421     debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10422     if (buf != stackbuf)
10423         FREE (buf);
10424     }
10425 return;
10426 }
10427 
10428 void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason)
     /* [previous][next][first][last][top][bottom][index][help] */
10429 {
10430 #if defined(TESTING)
10431 cpu_state_t * cpup = _cpup;
10432 #endif
10433 if (sim_deb && (dptr->dctrl & reason)) {
10434     sim_debug (reason, dptr, "%s %s %slen: %08X\n", sim_uname(uptr), txt, position, (unsigned int)len);
10435     if (data && len) {
10436         size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10437         char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10438         static char hex[] = "0123456789ABCDEF";
10439         static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10440         static unsigned char ebcdic2ascii[] = {
10441             0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10442             0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10443             0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10444             0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10445             0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10446             0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10447             0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10448             0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10449             0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10450             0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10451             0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10452             0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10453             0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10454             0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10455             0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10456             0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10457             0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10458             0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10459             0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10460             0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10461             0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10462             0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10463             0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10464             0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10465             0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10466             0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10467             0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10468             0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10469             0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10470             0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10471             0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10472             0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10473             };
10474 
10475         for (i=same=0; i<len; i += 16) {
10476             if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10477                 ++same;
10478                 continue;
10479                 }
10480             if (same > 0) {
10481                 sim_debug (reason, dptr, "%04lx thru %04lx same as above\n",
10482                            i - (16*same),
10483                            i - 1);
10484                 same = 0;
10485                 }
10486             group = (((len - i) > 16) ? 16 : (len - i));
10487             strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10488             eidx = strlen(ebcdicbuf);
10489             strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10490             ridx = strlen(rad50buf);
10491             strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10492             soff = strlen(strbuf);
10493             for (sidx=oidx=0; sidx<group; ++sidx) {
10494                 outbuf[oidx++] = ' ';
10495                 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10496                 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10497                 if (sim_isprint (data[i+sidx]))
10498                     strbuf[soff+sidx] = data[i+sidx];
10499                 else
10500                     strbuf[soff+sidx] = '.';
10501                 if (ridx && ((sidx&1) == 0)) {
10502                     uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10503 
10504                     if (word >= 64000) {
10505                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10506                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10507                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10508                         }
10509                     else {
10510                         rad50buf[ridx++] = rad50[word/1600];
10511                         rad50buf[ridx++] = rad50[(word/40)%40];
10512                         rad50buf[ridx++] = rad50[word%40];
10513                         }
10514                     }
10515                 if (eidx) {
10516                     if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10517                         ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10518                     else
10519                         ebcdicbuf[eidx++] = '.';
10520                     }
10521                 }
10522             outbuf[oidx] = '\0';
10523             strbuf[soff+sidx] = '\0';
10524             ebcdicbuf[eidx] = '\0';
10525             rad50buf[ridx] = '\0';
10526             sim_debug (reason, dptr, "%04lx%-48s %s%s%s\n", i, outbuf, strbuf, ebcdicbuf, rad50buf);
10527             }
10528         if (same > 0) {
10529             sim_debug (reason, dptr, "%04lx thru %04lx same as above\n", i-(16*same), (long unsigned int)(len-1));
10530             }
10531         }
10532     }
10533 }
10534 
10535 int Fprintf (FILE *f, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10536 {
10537 int ret = 0;
10538 va_list args;
10539 
10540 va_start (args, fmt);
10541     ret = vfprintf (f, fmt, args);
10542 va_end (args);
10543 return ret;
10544 }
10545 
10546 /* Hierarchical help presentation
10547  *
10548  * Device help can be presented hierarchically by calling
10549  *
10550  * t_stat scp_help (FILE *st, DEVICE *dptr,
10551  *                  UNIT *uptr, int flag, const char *help, char *cptr)
10552  *
10553  * or one of its three cousins from the device HELP routine.
10554  *
10555  * *help is the pointer to the structured help text to be displayed.
10556  *
10557  * The format and usage, and some helper macros can be found in scp_help.h
10558  * If you don't use the macros, it is not necessary to #include "scp_help.h".
10559  *
10560  * Actually, if you don't specify a DEVICE pointer and don't include
10561  * other device references, it can be used for non-device help.
10562  */
10563 
10564 #define blankch(x) ((x) == ' ' || (x) == '\t')
10565 
10566 typedef struct topic {
10567     size_t         level;
10568     char          *title;
10569     char          *label;
10570     struct topic  *parent;
10571     struct topic **children;
10572     uint32         kids;
10573     char          *text;
10574     size_t         len;
10575     uint32         flags;
10576     size_t         kidwid;
10577 #define HLP_MAGIC_TOPIC  1
10578     } TOPIC;
10579 
10580 static volatile struct {
10581     const char *error;
10582     const char *prox;
10583     size_t block;
10584     size_t line;
10585     } help_where = { "", NULL, 0, 0 };
10586 jmp_buf help_env;
10587 
10588 #define FAIL(why,text,here)        \
10589   {                                \
10590     help_where.error = #text;      \
10591     help_where.prox = here;        \
10592     longjmp ( help_env, (why) );   \
10593     /*LINTED E_STMT_NOT_REACHED*/  \
10594   }
10595 
10596 /*
10597  * Add to topic text.
10598  * Expands text buffer as necessary.
10599  */
10600 
10601 static void appendText (TOPIC *topic, const char *text, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
10602 {
10603 char *newt;
10604 
10605 if (!len)
10606     return;
10607 
10608 newt = (char *)realloc (topic->text, topic->len + len +1);
10609 if (!newt) {
10610 #if !defined(SUNLINT)
10611     FAIL (SCPE_MEM, No memory, NULL);
10612 #endif /* if !defined(SUNLINT) */
10613     }
10614 topic->text = newt;
10615 memcpy (newt + topic->len, text, len);
10616 topic->len +=len;
10617 newt[topic->len] = '\0';
10618 return;
10619 }
10620 
10621 /* Release memory held by a topic and its children.
10622  */
10623 static void cleanHelp (TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
10624 {
10625 TOPIC *child;
10626 size_t i;
10627 
10628 FREE (topic->title);
10629 FREE (topic->text);
10630 FREE (topic->label);
10631 for (i = 0; i < topic->kids; i++) {
10632     child = topic->children[i];
10633     cleanHelp (child);
10634     FREE (child);
10635     }
10636 FREE (topic->children);
10637 return;
10638 }
10639 
10640 /* Build a help tree from a string.
10641  * Handles substitutions, formatting.
10642  */
10643 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
10644                          UNIT *uptr, const char *htext, va_list ap)
10645 {
10646 char *end;
10647 size_t n, ilvl;
10648 #define VSMAX 100
10649 char *vstrings[VSMAX];
10650 size_t vsnum = 0;
10651 char * astrings[VSMAX+1];
10652 size_t asnum = 0;
10653 char *const *hblock;
10654 const char *ep;
10655 t_bool excluded = FALSE;
10656 
10657 /* variable arguments consumed table.
10658  * The scheme used allows arguments to be accessed in random
10659  * order, but for portability, all arguments must be char *.
10660  * If you try to violate this, there ARE machines that WILL break.
10661  */
10662 
10663 (void)memset (vstrings, 0, sizeof (vstrings));
10664 (void)memset (astrings, 0, sizeof (astrings));
10665 astrings[asnum++] = (char *) htext;
10666 
10667 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10668     help_where.block = hblock - astrings;
10669     help_where.line = 0;
10670     while (*htext) {
10671         const char *start;
10672 
10673         help_where.line++;
10674         if (sim_isspace (*htext) || *htext == '+') {/* Topic text, indented topic text */
10675             if (excluded) {                     /* Excluded topic text */
10676                 while (*htext && *htext != '\n')
10677                     htext++;
10678                 if (*htext)
10679                     ++htext;
10680                 continue;
10681                 }
10682             ilvl = 1;
10683             appendText (topic, "    ", 4);      /* Basic indentation */
10684             if (*htext == '+') {                /* More for each + */
10685                 while (*htext == '+') {
10686                     ilvl++;
10687                     appendText (topic, "    ", 4);
10688                     htext++;
10689                     }
10690                 }
10691             while (*htext && *htext != '\n' && sim_isspace (*htext))
10692                 htext++;
10693             if (!*htext)                        /* Empty after removing leading spaces */
10694                 break;
10695             start = htext;
10696             while (*htext) {                    /* Process line for substitutions */
10697                 if (*htext == '%') {
10698                     appendText (topic, start, htext - start); /* Flush up to escape */
10699                     switch (*++htext) {         /* Evaluate escape */
10700                         case 'U':
10701                             if (dptr) {
10702                                 char buf[129];
10703                                 n = uptr? uptr - dptr->units: 0;
10704                                 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10705                                 appendText (topic, buf, strlen (buf));
10706                                 }
10707                             break;
10708                         case 'D':
10709                             if (dptr != NULL)
10710                                 appendText (topic, dptr->name, strlen (dptr->name));
10711                             break;
10712                         case 'S':
10713                             appendText (topic, sim_name, strlen (sim_name));
10714                             break;
10715                         case '%':
10716                             appendText (topic, "%", 1);
10717                             break;
10718                         case '+':
10719                             appendText (topic, "+", 1);
10720                             break;
10721                         default:                    /* Check for vararg # */
10722                             if (sim_isdigit (*htext)) {
10723                                 n = 0;
10724                                 while (sim_isdigit (*htext))
10725                                     n += (n * 10) + (*htext++ - '0');
10726                                 if (( *htext != 'H' && *htext != 's') ||
10727                                     n == 0 || n >= VSMAX) {
10728 #if !defined(SUNLINT)
10729                                     FAIL (SCPE_ARG, Invalid escape, htext);
10730 #endif /* if !defined(SUNLINT) */
10731                                     }
10732                                 while (n > vsnum)   /* Get arg pointer if not cached */
10733                                     vstrings[vsnum++] = va_arg (ap, char *);
10734                                 start = vstrings[n-1]; /* Insert selected string */
10735                                 if (*htext == 'H') {   /* Append as more input */
10736                                     if (asnum >= VSMAX) {
10737 #if !defined(SUNLINT)
10738                                         FAIL (SCPE_ARG, Too many blocks, htext);
10739 #endif /* if !defined(SUNLINT) */
10740                                         }
10741                                     astrings[asnum++] = (char *)start;
10742                                     break;
10743                                     }
10744                                 ep = start;
10745                                 while (*ep) {
10746                                     if (*ep == '\n') {
10747                                         ep++;       /* Segment to \n */
10748                                         appendText (topic, start, ep - start);
10749                                         if (*ep) {  /* More past \n, indent */
10750                                             size_t i;
10751                                             for (i = 0; i < ilvl; i++)
10752                                                 appendText (topic, "    ", 4);
10753                                             }
10754                                         start = ep;
10755                                         }
10756                                     else
10757                                         ep++;
10758                                     }
10759                                 appendText (topic, start, ep-start);
10760                                 break;
10761                                 }
10762 #if !defined(SUNLINT)
10763                             FAIL (SCPE_ARG, Invalid escape, htext);
10764 #endif /* if !defined(SUNLINT) */
10765                         } /* switch (escape) */
10766                     start = ++htext;
10767                     continue;                   /* Current line */
10768                     } /* if (escape) */
10769                 if (*htext == '\n') {           /* End of line, append last segment */
10770                     htext++;
10771                     appendText (topic, start, htext - start);
10772                     break;                      /* To next line */
10773                     }
10774                 htext++;                        /* Regular character */
10775                 }
10776             continue;
10777             } /* topic text line */
10778         if (sim_isdigit (*htext)) {             /* Topic heading */
10779             TOPIC **children;
10780             TOPIC *newt;
10781             char nbuf[100];
10782 
10783             n = 0;
10784             start = htext;
10785             while (sim_isdigit (*htext))
10786                 n += (n * 10) + (*htext++ - '0');
10787             if ((htext == start) || !n) {
10788 #if !defined(SUNLINT)
10789                 FAIL (SCPE_ARG, Invalid topic heading, htext);
10790 #endif /* if !defined(SUNLINT) */
10791                 }
10792             if (n <= topic->level) {            /* Find level for new topic */
10793                 while (n <= topic->level)
10794                     topic = topic->parent;
10795                 }
10796             else {
10797                 if (n > topic->level + 1) {     /* Skipping down more than 1 */
10798 #if !defined(SUNLINT)
10799                     FAIL (SCPE_ARG, Level not contiguous, htext); /* E.g. 1 3, not reasonable */
10800 #endif /* if !defined(SUNLINT) */
10801                     }
10802                 }
10803             while (*htext && (*htext != '\n') && sim_isspace (*htext))
10804                 htext++;
10805             if (!*htext || (*htext == '\n')) {  /* Name missing */
10806 #if !defined(SUNLINT)
10807                 FAIL (SCPE_ARG, Missing topic name, htext);
10808 #endif /* if !defined(SUNLINT) */
10809                 }
10810             start = htext;
10811             while (*htext && (*htext != '\n'))
10812                 htext++;
10813             if (start == htext) {               /* Name NULL */
10814 #if !defined(SUNLINT)
10815                 FAIL (SCPE_ARG, Null topic name, htext);
10816 #endif /* if !defined(SUNLINT) */
10817                 }
10818             excluded = FALSE;
10819             if (*start == '?') {                /* Conditional topic? */
10820                 size_t n = 0;
10821                 start++;
10822                 while (sim_isdigit (*start))    /* Get param # */
10823                     n += (n * 10) + (*start++ - '0');
10824                 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
10825 #if !defined(SUNLINT)
10826                     FAIL (SCPE_ARG, Invalid parameter number, start);
10827 #endif /* if !defined(SUNLINT) */
10828                     }
10829                 while (n > vsnum)               /* Get arg pointer if not cached */
10830                     vstrings[vsnum++] = va_arg (ap, char *);
10831                 end = vstrings[n-1];            /* Check for True */
10832                 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
10833                     excluded = TRUE;            /* False, skip topic this time */
10834                     if (*htext)
10835                         htext++;
10836                     continue;
10837                     }
10838                 }
10839             newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
10840             if (!newt) {
10841 #if !defined(SUNLINT)
10842                 FAIL (SCPE_MEM, No memory, NULL);
10843 #endif /* if !defined(SUNLINT) */
10844                 }
10845             newt->title = (char *) malloc ((htext - start)+1);
10846             if (!newt->title) {
10847                 FREE (newt);
10848 #if !defined(SUNLINT)
10849                 FAIL (SCPE_MEM, No memory, NULL);
10850 #endif /* if !defined(SUNLINT) */
10851                 }
10852             memcpy (newt->title, start, htext - start);
10853             newt->title[htext - start] = '\0';
10854             if (*htext)
10855                 htext++;
10856 
10857             if (newt->title[0] == '$')
10858                 newt->flags |= HLP_MAGIC_TOPIC;
10859 
10860             children = (TOPIC **) realloc (topic->children,
10861                                            (topic->kids +1) * sizeof (TOPIC *));
10862             if (NULL == children) {
10863                 FREE (newt->title);
10864                 FREE (newt);
10865 #if !defined(SUNLINT)
10866                 FAIL (SCPE_MEM, No memory, NULL);
10867 #endif /* if !defined(SUNLINT) */
10868                 }
10869             topic->children = children;
10870             topic->children[topic->kids++] = newt;
10871             newt->level = n;
10872             newt->parent = topic;
10873             n = strlen (newt->title);
10874             if (n > topic->kidwid)
10875                 topic->kidwid = n;
10876             (void)sprintf (nbuf, ".%u", topic->kids);
10877             n = strlen (topic->label) + strlen (nbuf) + 1;
10878             newt->label = (char *) malloc (n);
10879             if (NULL == newt->label) {
10880                 FREE (newt->title);
10881                 topic->children[topic->kids -1] = NULL;
10882                 FREE (newt);
10883 #if !defined(SUNLINT)
10884                 FAIL (SCPE_MEM, No memory, NULL);
10885 #endif /* if !defined(SUNLINT) */
10886                 }
10887             (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
10888             topic = newt;
10889             continue;
10890             } /* digits introducing a topic */
10891         if (*htext == ';') {                    /* Comment */
10892             while (*htext && *htext != '\n')
10893                 htext++;
10894             continue;
10895             }
10896 #if !defined(SUNLINT)
10897         FAIL (SCPE_ARG, Unknown line type, htext);     /* Unknown line */
10898 #endif /* if !defined(SUNLINT) */
10899         } /* htext not at end */
10900     (void)memset (vstrings, 0, VSMAX * sizeof (char *));
10901     vsnum = 0;
10902     } /* all strings */
10903 
10904 return topic;
10905 }
10906 
10907 /*
10908  * Create prompt string - top thru current topic
10909  * Add prompt at end.
10910  */
10911 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
     /* [previous][next][first][last][top][bottom][index][help] */
10912 {
10913 char *prefix;
10914 char *newp, *newt;
10915 
10916 if (topic->level == 0) {
10917     prefix = (char *) calloc (2,1);
10918     if (!prefix) {
10919 #if !defined(SUNLINT)
10920         FAIL (SCPE_MEM, No memory, NULL);
10921 #endif /* if !defined(SUNLINT) */
10922         }
10923     prefix[0] = '\n';
10924     }
10925 else
10926     prefix = helpPrompt (topic->parent, "", oneword);
10927 
10928 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
10929                         strlen (pstring) +1);
10930 if (!newp) {
10931     FREE (prefix);
10932 #if !defined(SUNLINT)
10933     FAIL (SCPE_MEM, No memory, NULL);
10934 #endif /* if !defined(SUNLINT) */
10935     }
10936 strcpy (newp, prefix);
10937 if (topic->children) {
10938     if (topic->level != 0)
10939         strcat (newp, " ");
10940     newt = (topic->flags & HLP_MAGIC_TOPIC)?
10941             topic->title+1: topic->title;
10942     if (oneword) {
10943         char *np = newp + strlen (newp);
10944         while (*newt) {
10945             *np++ = blankch (*newt)? '_' : *newt;
10946             newt++;
10947             }
10948         *np = '\0';
10949         }
10950     else
10951         strcat (newp, newt);
10952     if (*pstring && *pstring != '?')
10953         strcat (newp, " ");
10954     }
10955 strcat (newp, pstring);
10956 FREE (prefix);
10957 return newp;
10958 }
10959 
10960 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
10961 {
10962 char tbuf[CBUFSIZE];
10963 size_t i, skiplines;
10964 #if defined(_WIN32)
10965 FILE *tmp;
10966 char *tmpnam;
10967 
10968 do {
10969     int fd;
10970     tmpnam = _tempnam (NULL, "simh");
10971     fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
10972     if (fd != -1) {
10973         tmp = _fdopen (fd, "w+");
10974         break;
10975         }
10976     } while (1);
10977 #else
10978 FILE *tmp = tmpfile();
10979 #endif /* if defined(_WIN32) */
10980 
10981 if (!tmp) {
10982     (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\n",
10983                    xstrerror_l(errno), errno);
10984     return;
10985     }
10986 
10987 if (topic->title)
10988     (void)fprintf (st, "%s\n", topic->title+1);
10989 
10990 skiplines = 0;
10991 if (topic->title) {
10992   if (!strcmp (topic->title+1, "Registers")) {
10993       fprint_reg_help (tmp, dptr) ;
10994       skiplines = 1;
10995       }
10996   else
10997       if (!strcmp (topic->title+1, "Set commands")) {
10998           fprint_set_help (tmp, dptr);
10999           skiplines = 3;
11000           }
11001       else
11002           if (!strcmp (topic->title+1, "Show commands")) {
11003               fprint_show_help (tmp, dptr);
11004               skiplines = 3;
11005               }
11006   }
11007 rewind (tmp);
11008 
11009 /* Discard leading blank lines/redundant titles */
11010 
11011 for (i =0; i < skiplines; i++)
11012     if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11013 
11014 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11015     if (tbuf[0] != '\n')
11016         fputs ("    ", st);
11017     fputs (tbuf, st);
11018     }
11019 fclose (tmp);
11020 #if defined(_WIN32)
11021 remove (tmpnam);
11022 FREE (tmpnam);
11023 #endif /* if defined(_WIN32) */
11024 return;
11025 }
11026 /* Flatten and display help for those who say they prefer it. */
11027 
11028 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11029                                UNIT *uptr, int32 flag,
11030                                TOPIC *topic, va_list ap )
11031 {
11032 size_t i;
11033 
11034 if (topic->flags & HLP_MAGIC_TOPIC) {
11035     (void)fprintf (st, "\n%s ", topic->label);
11036     displayMagicTopic (st, dptr, topic);
11037     }
11038 else
11039     (void)fprintf (st, "\n%s %s\n", topic->label, topic->title);
11040 
11041 /*
11042  * Topic text (for magic topics, follows for explanations)
11043  * It's possible/reasonable for a magic topic to have no text.
11044  */
11045 
11046 if (topic->text)
11047     fputs (topic->text, st);
11048 
11049 for (i = 0; i < topic->kids; i++)
11050     displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11051 
11052 return SCPE_OK;
11053 }
11054 
11055 #define HLP_MATCH_AMBIGUOUS (~0u)
11056 #define HLP_MATCH_WILDCARD  (~1U)
11057 #define HLP_MATCH_NONE      0
11058 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
     /* [previous][next][first][last][top][bottom][index][help] */
11059 {
11060 size_t i, match;
11061 char cbuf[CBUFSIZE], *cptr;
11062 
11063 if (!strcmp (token, "*"))
11064     return HLP_MATCH_WILDCARD;
11065 
11066 match = 0;
11067 for (i = 0; i < topic->kids; i++) {
11068     strcpy (cbuf,topic->children[i]->title +
11069             ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11070     cptr = cbuf;
11071     while (*cptr) {
11072         if (blankch (*cptr)) {
11073             *cptr++ = '_';
11074             }
11075         else {
11076             *cptr = (char)toupper (*cptr);
11077             cptr++;
11078             }
11079         }
11080     if (!strcmp (cbuf, token))      /* Exact Match */
11081         return i+1;
11082     if (!strncmp (cbuf, token, strlen (token))) {
11083         if (match)
11084             return HLP_MATCH_AMBIGUOUS;
11085         match = i+1;
11086         }
11087     }
11088 return match;
11089 }
11090 
11091 /* Main help routine */
11092 
11093 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11094                   UNIT *uptr, int32 flag,
11095                   const char *help, const char *cptr, va_list ap)
11096 {
11097 TOPIC top;
11098 TOPIC *topic = &top;
11099 int failed;
11100 size_t match;
11101 size_t i;
11102 const char *p;
11103 t_bool flat_help = FALSE;
11104 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11105 
11106 static const char attach_help[] = { " ATTACH" };
11107 static const char  brief_help[] = { "%s help.  Type <CR> to exit, HELP for navigation help.\n" };
11108 static const char onecmd_help[] = { "%s help.\n" };
11109 static const char   help_help[] = {
11110     /****|***********************80 column width guide********************************/
11111     "    To see more HELP information, type the listed subtopic name.  To move\n"
11112     "    up a level, just type <CR>.  To review the current subtopic, type \"?\".\n"
11113     "    To view all subtopics, type \"*\".  To exit type \"EXIT\", \"^C\", or \"^D\".\n\n"
11114     };
11115 
11116 (void)memset (&top, 0, sizeof(top));
11117 top.parent = &top;
11118 if ((failed = setjmp (help_env)) != 0) {
11119     (void)fprintf (stderr, "\nHELP was unable to process HELP for this device.\n"
11120                            "Error in block %u line %u: %s\n"
11121                            "%s%*.*s%s\n",
11122                    (int)help_where.block, (int)help_where.line, help_where.error,
11123                    help_where.prox ? "Near '" : "",
11124                    help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11125                    help_where.prox ? help_where.prox : "",
11126                    help_where.prox ? "'" : "");
11127     cleanHelp (&top);
11128     return failed;
11129     }
11130 
11131 /* Compile string into navigation tree */
11132 
11133 /* Root */
11134 
11135 if (dptr) {
11136     p = dptr->name;
11137     flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11138     }
11139 else
11140     p = sim_name;
11141 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11142 if (!top.title)
11143   {
11144     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11145                    __func__, __FILE__, __LINE__);
11146 #if defined(USE_BACKTRACE)
11147 # if defined(SIGUSR2)
11148     (void)raise(SIGUSR2);
11149     /*NOTREACHED*/ /* unreachable */
11150 # endif /* if defined(SIGUSR2) */
11151 #endif /* if defined(USE_BACKTRACE) */
11152     abort();
11153   }
11154 for (i = 0; p[i]; i++ )
11155     top.title[i] = (char)toupper (p[i]);
11156 top.title[i] = '\0';
11157 if (flag & SCP_HELP_ATTACH)
11158     strcpy (top.title+i, attach_help);
11159 
11160 top.label = (char *) malloc (sizeof ("1"));
11161 if (!top.label)
11162   {
11163     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11164                    __func__, __FILE__, __LINE__);
11165 #if defined(USE_BACKTRACE)
11166 # if defined(SIGUSR2)
11167     (void)raise(SIGUSR2);
11168     /*NOTREACHED*/ /* unreachable */
11169 # endif /* if defined(SIGUSR2) */
11170 #endif /* if defined(USE_BACKTRACE) */
11171     abort();
11172   }
11173 strcpy (top.label, "1");
11174 
11175 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11176 
11177 if (flat_help) {
11178     flag |= SCP_HELP_FLAT;
11179     if (sim_ttisatty())
11180         (void)fprintf (st, "%s help.\nThis help is also available in hierarchical form.\n", top.title);
11181     else
11182         (void)fprintf (st, "%s help.\n", top.title);
11183     }
11184 else
11185     (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11186 
11187 /* Add text and subtopics */
11188 
11189 (void) buildHelp (&top, dptr, uptr, help, ap);
11190 
11191 /* Go to initial topic if provided */
11192 
11193 while (cptr && *cptr) {
11194     cptr = get_glyph (cptr, gbuf, 0);
11195     if (!gbuf[0])
11196         break;
11197     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11198         (void)fprintf (st, "\n");
11199         fputs (help_help, st);
11200         break;
11201         }
11202     match =  matchHelpTopicName (topic, gbuf);
11203     if (match == HLP_MATCH_WILDCARD) {
11204         displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11205         cleanHelp (&top);
11206         return SCPE_OK;
11207         }
11208     if (match == HLP_MATCH_AMBIGUOUS) {
11209         (void)fprintf (st, "\n%s is ambiguous in %s\n", gbuf, topic->title);
11210         break;
11211         }
11212     if (match == HLP_MATCH_NONE) {
11213         (void)fprintf (st, "\n%s is not available in %s\n", gbuf, topic->title);
11214         break;
11215         }
11216     topic = topic->children[match-1];
11217     }
11218 cptr = NULL;
11219 
11220 if (flat_help) {
11221     displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11222     cleanHelp (&top);
11223     return SCPE_OK;
11224     }
11225 
11226 /* Interactive loop displaying help */
11227 
11228 while (TRUE) {
11229     char *pstring;
11230     const char *prompt[2] = {"? ", "Subtopic? "};
11231 
11232     /* Some magic topic names for help from data structures */
11233 
11234     if (topic->flags & HLP_MAGIC_TOPIC) {
11235         fputc ('\n', st);
11236         displayMagicTopic (st, dptr, topic);
11237         }
11238     else
11239         (void)fprintf (st, "\n%s\n", topic->title);
11240 
11241     /* Topic text (for magic topics, follows for explanations)
11242      * It's possible/reasonable for a magic topic to have no text.
11243      */
11244 
11245     if (topic->text)
11246         fputs (topic->text, st);
11247 
11248     if (topic->kids) {
11249         size_t w = 0;
11250         char *p;
11251         char tbuf[CBUFSIZE];
11252 
11253         (void)fprintf (st, "\n    Additional information available:\n\n");
11254         for (i = 0; i < topic->kids; i++) {
11255             strcpy (tbuf, topic->children[i]->title +
11256                     ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11257             for (p = tbuf; *p; p++) {
11258                 if (blankch (*p))
11259                     *p = '_';
11260                 }
11261             w += 4 + topic->kidwid;
11262             if (w > 80) {
11263                 w = 4 + topic->kidwid;
11264                 fputc ('\n', st);
11265                 }
11266             (void)fprintf (st, "    %-*s", (int32_t)topic->kidwid, tbuf);
11267             }
11268         (void)fprintf (st, "\n\n");
11269         if (flag & SCP_HELP_ONECMD) {
11270             pstring = helpPrompt (topic, "", TRUE);
11271             (void)fprintf (st, "To view additional topics, type HELP %s topicname\n", pstring+1);
11272             FREE (pstring);
11273             break;
11274             }
11275         }
11276 
11277     if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11278         break;
11279 
11280   reprompt:
11281     if (NULL == cptr || !*cptr) {
11282         if (topic->kids == 0)
11283             topic = topic->parent;
11284         pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11285 
11286         cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11287         FREE (pstring);
11288         if ((cptr != NULL) &&                   /* Got something? */
11289             ((0 == strcmp (cptr, "\x04")) ||    /* was it a bare ^D? */
11290              (0 == strcmp (cptr, "\x1A"))))     /* was it a bare ^Z? */
11291             cptr = NULL;                        /* These are EOF synonyms */
11292         }
11293 
11294     if (NULL == cptr)                           /* EOF, exit help */
11295         break;
11296 
11297     cptr = get_glyph (cptr, gbuf, 0);
11298     if (!strcmp (gbuf, "*")) {              /* Wildcard */
11299         displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11300         gbuf[0] = '\0';                     /* Displayed all subtopics, go up */
11301         }
11302     if (!gbuf[0]) {                         /* Blank, up a level */
11303         if (topic->level == 0)
11304             break;
11305         topic = topic->parent;
11306         continue;
11307         }
11308     if (!strcmp (gbuf, "?"))                /* ?, repaint current topic */
11309         continue;
11310     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11311         fputs (help_help, st);
11312         goto reprompt;
11313         }
11314     if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))   /* EXIT (help) */
11315         break;
11316 
11317     /* String - look for that topic */
11318 
11319     if (!topic->kids) {
11320         (void)fprintf (st, "No additional help at this level.\n");
11321         cptr = NULL;
11322         goto reprompt;
11323         }
11324     match = matchHelpTopicName (topic, gbuf);
11325     if (match == HLP_MATCH_AMBIGUOUS) {
11326         (void)fprintf (st, "%s is ambiguous, please type more of the topic name\n", gbuf);
11327         cptr = NULL;
11328         goto reprompt;
11329         }
11330 
11331     if (match == HLP_MATCH_NONE) {
11332         (void)fprintf (st, "Help for %s is not available\n", gbuf);
11333         cptr = NULL;
11334         goto reprompt;
11335         }
11336     /* Found, display subtopic */
11337 
11338     topic = topic->children[match-1];
11339     }
11340 
11341 /* Free structures and return */
11342 
11343 cleanHelp (&top);
11344 
11345 return SCPE_OK;
11346 }
11347 
11348 /* variable argument list shell - most commonly used */
11349 
11350 t_stat scp_help (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11351                  UNIT *uptr, int32 flag,
11352                  const char *help, const char *cptr, ...)
11353 {
11354 t_stat r;
11355 va_list ap;
11356 
11357 va_start (ap, cptr);
11358 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11359 va_end (ap);
11360 
11361 return r;
11362 }
11363 
11364 #if defined(_MSC_VER)
11365 # pragma warning(pop)
11366 #endif

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