root/src/simh/scp.c

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

DEFINITIONS

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

   1 /*
   2  * scp.c: simulator control program
   3  *
   4  * vim: filetype=c:tabstop=4:ai:colorcolumn=84:expandtab
   5  * SPDX-License-Identifier: MIT
   6  * scspell-id: 7cde852c-f62a-11ec-8444-80ee73e9b8e7
   7  *
   8  * ---------------------------------------------------------------------------
   9  *
  10  * Copyright (c) 1993-2022 Robert M. Supnik
  11  * Copyright (c) 2021-2023 Jeffrey H. Johnson
  12  * Copyright (c) 2006-2025 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_hints.h"
  59 #include "sim_tape.h"
  60 #include "sim_sock.h"
  61 #include "sim_os_mem.h"
  62 
  63 #include <signal.h>
  64 #include <ctype.h>
  65 #include <time.h>
  66 #include <math.h>
  67 #include <stddef.h>
  68 #if defined(_WIN32)
  69 # if !defined(WIN32_LEAN_AND_MEAN)
  70 #  define WIN32_LEAN_AND_MEAN
  71 # endif /* if !defined(WIN32_LEAN_AND_MEAN) */
  72 # if defined(_MSC_VER)
  73 #  pragma warning(push, 3)
  74 # endif
  75 # include <direct.h>
  76 # include <io.h>
  77 # include <fcntl.h>
  78 #else
  79 # include <unistd.h>
  80 # define HAVE_UNISTD 1
  81 #endif
  82 #include <sys/stat.h>
  83 #include <sys/types.h>
  84 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
  85 # include <sys/resource.h>
  86 #endif
  87 #include <setjmp.h>
  88 #include <stdint.h>
  89 #include <limits.h>
  90 #if defined(__APPLE__)
  91 # include <xlocale.h>
  92 #endif
  93 #include <locale.h>
  94 
  95 #include "linehistory.h"
  96 
  97 #if defined(__APPLE__)
  98 # include <sys/sysctl.h>
  99 #endif /* if defined(_APPLE_) */
 100 
 101 #if ( defined(__linux__) || defined(__linux) || defined(_linux) || defined(linux) ) //-V1040
 102 # include <sys/sysinfo.h>
 103 # define LINUX_OS
 104 #endif
 105 
 106 #include <uv.h>
 107 
 108 #if !defined(HAVE_UNISTD)
 109 # undef USE_BACKTRACE
 110 #endif /* if !defined(HAVE_UNISTD) */
 111 
 112 #if defined(USE_BACKTRACE)
 113 # include <string.h>
 114 # include <signal.h>
 115 #endif /* if defined(USE_BACKTRACE) */
 116 
 117 #if defined(__HAIKU__)
 118 # include <OS.h>
 119 #endif /* if defined(__HAIKU__) */
 120 
 121 #if !defined(__CYGWIN__)
 122 # if !defined(__APPLE__)
 123 #  if !defined(_AIX)
 124 #   if !defined(__MINGW32__)
 125 #    if !defined(__MINGW64__)
 126 #     if !defined(CROSS_MINGW32)
 127 #      if !defined(CROSS_MINGW64)
 128 #       if !defined(_WIN32)
 129 #        if !defined(__HAIKU__)
 130 #         if !defined(__QNX__)
 131 #          include <link.h>
 132 #         endif
 133 #        endif
 134 #       endif
 135 #      endif
 136 #     endif
 137 #    endif
 138 #   endif
 139 #  endif
 140 # endif
 141 #endif
 142 
 143 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
 144 # include <windows.h>
 145 #endif
 146 
 147 #if defined(__CYGWIN__)
 148 # include <windows.h>
 149 # include <sys/utsname.h>
 150 # include <sys/cygwin.h>
 151 # include <cygwin/version.h>
 152 #endif
 153 
 154 #define DBG_CTR 0
 155 
 156 #include "../dps8/dps8.h"
 157 #include "../dps8/dps8_cpu.h"
 158 #include "../dps8/dps8_rt.h"
 159 #include "../dps8/dps8_priv.h"
 160 #include "../dps8/dps8_topo.h"
 161 #include "../dps8/ver.h"
 162 
 163 #include "../dps8/dps8_iom.h"
 164 #include "../dps8/dps8_fnp2.h"
 165 
 166 #include "../decNumber/decContext.h"
 167 #include "../decNumber/decNumberLocal.h"
 168 
 169 #include "../dps8/dps8_math128.h"
 170 
 171 #include "../dps8/dps8_sir.h"
 172 
 173 #if !defined(__CYGWIN__)
 174 # if !defined(__APPLE__)
 175 #  if !defined(_AIX)
 176 #   if !defined(__MINGW32__)
 177 #    if !defined(__MINGW64__)
 178 #     if !defined(CROSS_MINGW32)
 179 #      if !defined(CROSS_MINGW64)
 180 #       if !defined(_WIN32)
 181 #        if !defined(__HAIKU__)
 182 #         if !defined(__QNX__)
 183 #          if !defined(__FILC__)
 184 static unsigned int dl_iterate_phdr_callback_called = 0;
 185 #          endif
 186 #         endif
 187 #        endif
 188 #       endif
 189 #      endif
 190 #     endif
 191 #    endif
 192 #   endif
 193 #  endif
 194 # endif
 195 #endif
 196 
 197 #if defined(MAX)
 198 # undef MAX
 199 #endif /* if defined(MAX) */
 200 #define MAX(a,b)  (((a) >= (b)) ? (a) : (b))
 201 
 202 #if defined(FREE)
 203 # undef FREE
 204 #endif /* if defined(FREE) */
 205 #define FREE(p) do  \
 206   {                 \
 207     free((p));      \
 208     (p) = NULL;     \
 209   } while(0)
 210 
 211 /* search logical and boolean ops */
 212 
 213 #define SCH_OR          0                               /* search logicals */
 214 #define SCH_AND         1
 215 #define SCH_XOR         2
 216 #define SCH_E           0                               /* search booleans */
 217 #define SCH_N           1
 218 #define SCH_G           2
 219 #define SCH_L           3
 220 #define SCH_EE          4
 221 #define SCH_NE          5
 222 #define SCH_GE          6
 223 #define SCH_LE          7
 224 
 225 #define MAX_DO_NEST_LVL 20                              /* DO cmd nesting level */
 226 #define SRBSIZ          1024                            /* save/restore buffer */
 227 #define SIM_BRK_INILNT  4096                            /* bpt tbl length */
 228 #define SIM_BRK_ALLTYP  0xFFFFFFFB
 229 
 230 #define UPDATE_SIM_TIME                                         \
 231     if (1) {                                                    \
 232         int32 _x;                                               \
 233         if (sim_clock_queue == QUEUE_LIST_END)                  \
 234             _x = noqueue_time;                                  \
 235         else                                                    \
 236             _x = sim_clock_queue->time;                         \
 237         sim_time = sim_time + (_x - sim_interval);              \
 238         sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
 239         if (sim_clock_queue == QUEUE_LIST_END)                  \
 240             noqueue_time = sim_interval;                        \
 241         else                                                    \
 242             sim_clock_queue->time = sim_interval;               \
 243         }                                                       \
 244     else                                                        \
 245         (void)0
 246 
 247 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
 248 
 249 #define SZ_R(rp) \
 250     (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
 251 
 252 #define SZ_LOAD(sz,v,mb,j)                                                 \
 253     if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j));        \
 254     else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
 255     else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
 256     else v = *(((t_uint64 *) mb) + ((uint32) j));
 257 
 258 #define SZ_STORE(sz,v,mb,j)                                                         \
 259     if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v;                    \
 260     else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
 261     else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
 262     else *(((t_uint64 *) mb) + ((uint32) j)) = v;
 263 
 264 #define GET_SWITCHES(cp) \
 265     if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
 266 
 267 #define GET_RADIX(val,dft)                          \
 268     if (sim_switches & SWMASK ('O')) val = 8;       \
 269     else if (sim_switches & SWMASK ('D')) val = 10; \
 270     else if (sim_switches & SWMASK ('H')) val = 16; \
 271     else val = dft;
 272 
 273 /*
 274  * The per-simulator init routine is a weak global that defaults to NULL
 275  * The other per-simulator pointers can be overridden by the init routine
 276  */
 277 
 278 t_bool sim_asynch_enabled = FALSE;
 279 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
 280 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
 281 extern void (*sim_vm_init) (void);
 282 extern void (*sim_vm_exit) (void);
 283 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
 284 void (*sim_vm_post) (t_bool from_scp) = NULL;
 285 CTAB *sim_vm_cmd = NULL;
 286 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
 287 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
 288 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
 289 t_value (*sim_vm_pc_value) (void) = NULL;
 290 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
 291 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
 292 unsigned int nprocs;
 293 unsigned int ncores;
 294 bool mlock_failure = false;
 295 char* sim_appfilename;
 296 
 297 /* Prototypes */
 298 
 299 /* Set and show command processors */
 300 
 301 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 302 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 303 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 304 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 305 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
 306 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
 307 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 308 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 309 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 310 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 311 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 312 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 313 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 314 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 315 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 316 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 317 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 318 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 319 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
 320 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 321 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 322 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 323 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 324 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 325 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 326 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 327 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
 328 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
 329 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
 330 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
 331 t_stat sim_save (FILE *sfile);
 332 t_stat sim_rest (FILE *rfile);
 333 
 334 /* Breakpoint package */
 335 
 336 t_stat sim_brk_init (void);
 337 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
 338 t_stat sim_brk_clr (t_addr loc, int32 sw);
 339 t_stat sim_brk_clrall (int32 sw);
 340 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
 341 t_stat sim_brk_showall (FILE *st, uint32 sw);
 342 CONST char *sim_brk_getact (char *buf, int32 size);
 343 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
 344 char *sim_brk_clract (void);
 345 
 346 FILE *stdnul;
 347 
 348 /* Command support routines */
 349 
 350 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 351 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 352 int32 test_search (t_value *val, SCHTAB *schptr);
 353 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
 354 int32 get_switches (const char *cptr);
 355 CONST char *get_sim_sw (CONST char *cptr);
 356 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
 357 t_value get_rval (REG *rptr, uint32 idx);
 358 void put_rval (REG *rptr, uint32 idx, t_value val);
 359 void fprint_help (FILE *st);
 360 void fprint_stopped (FILE *st, t_stat r);
 361 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
 362 void fprint_sep (FILE *st, int32 *tokens);
 363 char *read_line (char *ptr, int32 size, FILE *stream);
 364 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
 365 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
 366 char *sim_trim_endspc (char *cptr);
 367 
 368 /* Forward references */
 369 
 370 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
 371 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
 372 t_bool qdisable (DEVICE *dptr);
 373 t_stat attach_err (UNIT *uptr, t_stat stat);
 374 t_stat detach_all (int32 start_device, t_bool shutdown);
 375 t_stat assign_device (DEVICE *dptr, const char *cptr);
 376 t_stat deassign_device (DEVICE *dptr);
 377 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
 378 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
 379     REG *lowr, REG *highr, uint32 lows, uint32 highs);
 380 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
 381 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
 382 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
 383     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
 384 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
 385 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
 386     UNIT *uptr, int32 dfltinc);
 387 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
 388 t_stat step_svc (UNIT *ptr);
 389 t_stat expect_svc (UNIT *ptr);
 390 t_stat set_on (int32 flag, CONST char *cptr);
 391 t_stat set_verify (int32 flag, CONST char *cptr);
 392 t_stat set_message (int32 flag, CONST char *cptr);
 393 t_stat set_quiet (int32 flag, CONST char *cptr);
 394 t_stat set_localopc (int32 flag, CONST char *cptr);
 395 t_stat set_asynch (int32 flag, CONST char *cptr);
 396 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 397 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
 398 void int_handler (int signal);
 399 t_stat set_prompt (int32 flag, CONST char *cptr);
 400 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
 401 t_stat sim_set_environment (int32 flag, CONST char *cptr);
 402 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
 403 
 404 /* Global data */
 405 
 406 DEVICE *sim_dflt_dev             = NULL;
 407 UNIT *sim_clock_queue            = QUEUE_LIST_END;
 408 int32 sim_interval               = 0;
 409 int32 sim_switches               = 0;
 410 FILE *sim_ofile                  = NULL;
 411 SCHTAB *sim_schrptr              = NULL;
 412 SCHTAB *sim_schaptr              = NULL;
 413 DEVICE *sim_dfdev                = NULL;
 414 UNIT *sim_dfunit                 = NULL;
 415 DEVICE **sim_internal_devices    = NULL;
 416 uint32 sim_internal_device_count = 0;
 417 int32 sim_opt_out                = 0;
 418 int32 sim_is_running             = 0;
 419 t_bool sim_processing_event      = FALSE;
 420 uint32 sim_brk_summ              = 0;
 421 uint32 sim_brk_types             = 0;
 422 BRKTYPTAB *sim_brk_type_desc     = NULL;         /* type descriptions */
 423 uint32 sim_brk_dflt              = 0;
 424 uint32 sim_brk_match_type;
 425 t_addr sim_brk_match_addr;
 426 char *sim_brk_act[MAX_DO_NEST_LVL];
 427 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
 428 BRKTAB **sim_brk_tab             = NULL;
 429 int32 sim_brk_ent                = 0;
 430 int32 sim_brk_lnt                = 0;
 431 int32 sim_brk_ins                = 0;
 432 int32 sim_iglock                 = 0;
 433 int32 sim_nolock                 = 0;
 434 int32 sim_quiet                  = 0;
 435 int32 sim_localopc               = 1;
 436 int32 sim_randompst              = 0;
 437 int32 sim_randstate              = 0;
 438 int32 sim_step                   = 0;
 439 int nodist                       = 0;
 440 #if defined(PERF_STRIP)
 441 int32 sim_nostate                = 1;
 442 #else
 443 int32 sim_nostate                = 0;
 444 #endif /* if defined(PERF_STRIP) */
 445 static double sim_time;
 446 static uint32 sim_rtime;
 447 static int32 noqueue_time;
 448 volatile int32 stop_cpu          = 0;
 449 t_value *sim_eval                = NULL;
 450 static t_value sim_last_val;
 451 static t_addr sim_last_addr;
 452 FILE *sim_log                    = NULL;         /* log file */
 453 FILEREF *sim_log_ref             = NULL;         /* log file file reference */
 454 FILE *sim_deb                    = NULL;         /* debug file */
 455 FILEREF *sim_deb_ref             = NULL;         /* debug file file reference */
 456 int32 sim_deb_switches           = 0;            /* debug switches */
 457 struct timespec sim_deb_basetime;                /* debug timestamp relative base time */
 458 char *sim_prompt                 = NULL;         /* prompt string */
 459 static FILE *sim_gotofile;                       /* the currently open do file */
 460 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];   /* the current line number in the currently open do file */
 461 static int32 sim_do_echo         = 0;            /* the echo status of the currently open do file */
 462 static int32 sim_show_message    = 1;            /* the message display status of the currently open do file */
 463 static int32 sim_on_inherit      = 0;            /* the inherit status of on state and conditions when executing do files */
 464 #if !defined(PERF_STRIP)
 465 static int32 sim_realtime        = 0;            /* user requested real-time mode */
 466 #endif
 467 static int32 sim_do_depth        = 0;
 468 uint64_t sim_free_memory         = 0;
 469 
 470 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
 471 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
 472 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
 473 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
 474 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
 475 
 476 t_stat sim_last_cmd_stat;                        /* Command Status */
 477 
 478 static SCHTAB sim_stabr;                         /* Register search specifier */
 479 static SCHTAB sim_staba;                         /* Memory search specifier */
 480 
 481 static UNIT sim_step_unit   = { UDATA (&step_svc, 0, 0)  };
 482 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0)  };
 483 
 484 pthread_t main_thread_id;
 485 
 486 /* Tables and strings */
 487 
 488 const char save_vercur[] = "V4.1";
 489 const char save_ver40[]  = "V4.0";
 490 const char save_ver35[]  = "V3.5";
 491 const char save_ver32[]  = "V3.2";
 492 const char save_ver30[]  = "V3.0";
 493 const struct scp_error {
 494     const char *code;
 495     const char *message;
 496     } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
 497         {{"NXM",     "Address space exceeded"},
 498          {"UNATT",   "Unit not attached"},
 499          {"IOERR",   "I/O error"},
 500          {"CSUM",    "Checksum error"},
 501          {"FMT",     "Format error"},
 502          {"NOATT",   "Unit not attachable"},
 503          {"OPENERR", "File open error"},
 504          {"MEM",     "Memory exhausted"},
 505          {"ARG",     "Invalid argument"},
 506          {"STEP",    "Step expired"},
 507          {"UNK",     "Unknown command"},
 508          {"RO",      "Read only argument"},
 509          {"INCOMP",  "Command not completed"},
 510          {"STOP",    "Simulation stopped"},
 511          {"EXIT",    "Goodbye"},
 512          {"TTIERR",  "Console input I/O error"},
 513          {"TTOERR",  "Console output I/O error"},
 514          {"EOF",     "End of file"},
 515          {"REL",     "Relocation error"},
 516          {"NOPARAM", "No settable parameters"},
 517          {"ALATT",   "Unit already attached"},
 518          {"TIMER",   "Hardware timer error"},
 519          {"SIGERR",  "Signal handler setup error"},
 520          {"TTYERR",  "Console terminal setup error"},
 521          {"SUB",     "Subscript out of range"},
 522          {"NOFNC",   "Command not allowed"},
 523          {"UDIS",    "Unit disabled"},
 524          {"NORO",    "Read only operation not allowed"},
 525          {"INVSW",   "Invalid switch"},
 526          {"MISVAL",  "Missing value"},
 527          {"2FARG",   "Too few arguments"},
 528          {"2MARG",   "Too many arguments"},
 529          {"NXDEV",   "Non-existent device"},
 530          {"NXUN",    "Non-existent unit"},
 531          {"NXREG",   "Non-existent register"},
 532          {"NXPAR",   "Non-existent parameter"},
 533          {"NEST",    "Nested DO command limit exceeded"},
 534          {"IERR",    "Internal error"},
 535          {"MTRLNT",  "Invalid magtape record length"},
 536          {"LOST",    "Console Telnet connection lost"},
 537          {"TTMO",    "Console Telnet connection timed out"},
 538          {"STALL",   "Console Telnet output stall"},
 539          {"AFAIL",   "Assertion failed"},
 540          {"INVREM",  "Invalid remote console command"},
 541          {"NOTATT",  "Not attached"},
 542          {"EXPECT",  "Expect matched"},
 543          {"REMOTE",  "Remote console command"},
 544     };
 545 
 546 const size_t size_map[] = { sizeof (int8),
 547     sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
 548     , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
 549 };
 550 
 551 const t_value width_mask[] = { 0,
 552     0x1, 0x3, 0x7, 0xF,
 553     0x1F, 0x3F, 0x7F, 0xFF,
 554     0x1FF, 0x3FF, 0x7FF, 0xFFF,
 555     0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
 556     0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
 557     0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
 558     0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
 559     0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
 560     0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
 561     0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
 562     0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
 563     0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
 564     0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
 565     0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
 566     0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
 567     0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
 568     };
 569 
 570 static const char simh_help[] =
 571        /***************** 80 character line width template *************************/
 572       "1Commands\n" //-NLOK
 573 #define HLP_RESET       "*Commands Resetting Devices"
 574        /***************** 80 character line width template *************************/
 575       "2Resetting Devices\n" //-NLOK
 576       " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\r\n"
 577       " simulator to a predefined condition.  If the switch \"`-p`\" is specified,\r\n"
 578       " the device is reset to its initial power-on state:\r\n\r\n"
 579       "++RESET                  resets all devices\r\n"
 580       "++RESET -p               power-cycle all devices\r\n"
 581       "++RESET ALL              resets all devices\r\n"
 582       "++RESET <device>         resets the specified <device>\r\n\r\n"
 583       " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\r\n"
 584       " interrupt requests, and returns the device to a quiescent state.\r\n\r\n"
 585       " * It does **NOT** clear the main memory or affect associated I/O\r\n"
 586       " connections.\r\n"
 587 #define HLP_EXAMINE     "*Commands Examining_and_Changing_State"
 588 #define HLP_IEXAMINE    "*Commands Examining_and_Changing_State"
 589 #define HLP_DEPOSIT     "*Commands Examining_and_Changing_State"
 590 #define HLP_IDEPOSIT    "*Commands Examining_and_Changing_State"
 591        /***************** 80 character line width template *************************/
 592       "2Examining and Changing State\n" //-NLOK
 593       " There are four commands to examine and change state:\r\n\r\n"
 594       " * `EXAMINE` (*abbreviated* `E`) examines state\r\n"
 595       " * `DEPOSIT` (*abbreviated* `D`) changes state\r\n"
 596       " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\r\n"
 597       "    and allows the user to interactively change it\r\n"
 598       " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\r\n"
 599       "    interactively change state\r\n\r\n"
 600       " All four commands take the form:\r\n\r\n"
 601       "++command {modifiers} <object list>\r\n\r\n"
 602       " The `DEPOSIT` command requires the deposit value at the end of the command.\r\n\r\n"
 603       " There are four kinds of modifiers: **switches**, **device/unit name**,\r\n"
 604       " **search specifier**, and for `EXAMINE`, **output file**.\r\n\r\n"
 605       " * **Switches** have been described previously.\r\n"
 606       " * A **device/unit name** identifies the device and unit whose address\r\n"
 607       " space is to be examined or modified. If no device is specified, the CPU\r\n"
 608       " main memory is selected. If a device but no unit is specified, unit `0`\r\n"
 609       " of the specified device is selected automatically.\r\n"
 610       " * The **search specifier** provides criteria for testing addresses or\r\n"
 611       " registers to see if they should be processed.  The search specifier\r\n"
 612       " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\r\n"
 613       " both, optionally separated by spaces:\r\n\r\n"
 614       "++{ < logical op >  < value > }  < relational op >  < value >\r\n\r\n"
 615        /***************** 80 character line width template *************************/
 616       " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\r\n"
 617       " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\r\n"
 618       " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\r\n"
 619       " equal*), \">=\" (*greater than or equal*), \">\" (*greater\r\n"
 620       " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\r\n"
 621       " * * If any \"<`logical operator`>\" is specified without\r\n"
 622       " a \"<`relational operator`>\", it is ignored.\r\n"
 623       " * * If any \"<`relational operator`>\" is specified without\r\n"
 624       " a \"<`logical operator`>\", no logical operation is performed.\r\n"
 625       " * * All comparisons are unsigned.\r\n\r\n"
 626       " * The **output file** modifier redirects the command output to a file\r\n"
 627       " instead of the console.  The **output file** modifier is specified with\r\n"
 628       " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\r\n\r\n"
 629       " **NOTE**: Modifiers may be specified in any order.  If multiple\r\n"
 630       " modifiers of the same type are specified, later modifiers override earlier\r\n"
 631       " modifiers. If the **device/unit name** comes *after* the search specifier,\r\n"
 632       " the search values will interpreted in the *radix of the CPU*, rather than\r\n"
 633       " of the device/unit.\r\n\r\n"
 634       " The \"<`object list`>\" argument consists of one or more of the following,\r\n"
 635       " separated by commas:\r\n\r\n"
 636        /***************** 80 character line width template *************************/
 637       "++register                the specified register\r\n"
 638       "++register[sub1-sub2]     the specified register array locations,\r\n"
 639       "++++++++                  starting at location sub1 up to and\r\n"
 640       "++++++++                  including location sub2\r\n"
 641       "++register[sub1/length]   the specified register array locations,\r\n"
 642       "++++++++                  starting at location sub1 up to but\r\n"
 643       "++++++++                  not including sub1+length\r\n"
 644       "++register[ALL]           all locations in the specified register\r\n"
 645       "++++++++                  array\r\n"
 646       "++register1-register2     all the registers starting at register1\r\n"
 647       "++++++++                  up to and including register2\r\n"
 648       "++address                 the specified location\r\n"
 649       "++address1-address2       all locations starting at address1 up to\r\n"
 650       "++++++++                  and including address2\r\n"
 651       "++address/length          all location starting at address up to\r\n"
 652       "++++++++                  but not including address+length\r\n"
 653       "++STATE                   all registers in the device\r\n"
 654       "++ALL                     all locations in the unit\r\n"
 655       "++$                       the last value displayed by an EXAMINE\r\n"
 656       "++++++++                  command interpreted as an address\r\n"
 657       "3Switches\n" //-NLOK
 658       "4Formatting Control\n" //-NLOK
 659       " Switches can be used to control the format of the displayed information:\r\n\r\n"
 660        /***************** 80 character line width template *************************/
 661       "5`-a`\n" //-NLOK
 662       " display as ASCII\r\n"
 663       "5`-c`\n" //-NLOK
 664       " display as character string\r\n"
 665       "5`-m`\n" //-NLOK
 666       " display as instruction mnemonics\r\n"
 667       "5`-o`\n" //-NLOK
 668       " display as octal\r\n"
 669       "5`-d`\n" //-NLOK
 670       " display as decimal\r\n"
 671       "5`-h`\n" //-NLOK
 672       " display as hexadecimal\r\n\r\n"
 673       "3Examples\n" //-NLOK
 674       "++ex 1000-1100                examine 1000 to 1100\r\n"
 675       "++de PC 1040                  set PC to 1040\r\n"
 676       "++ie 40-50                    interactively examine 40:50\r\n"
 677       "++ie >1000 40-50              interactively examine the subset\r\n"
 678       "+++++++++                     of locations 40:50 that are >1000\r\n"
 679       "++ex rx0 50060                examine 50060, RX unit 0\r\n"
 680       "++ex rx sbuf[3-6]             examine SBUF[3] to SBUF[6] in RX\r\n"
 681       "++de all 0                    set main memory to 0\r\n"
 682       "++de &77>0 0                  set all addresses whose low order\r\n"
 683       "+++++++++                     bits are non-zero to 0\r\n"
 684       "++ex -m @memdump.txt 0-7777   dump memory to file\r\n\r\n"
 685       " * **NOTE**: To terminate an interactive command, simply type any bad value\r\n"
 686       "           (*e.g.* `XYZ`) when input is requested.\r\n"
 687 #define HLP_EVALUATE    "*Commands Evaluating_Instructions"
 688        /***************** 80 character line width template *************************/
 689       "2Evaluating Instructions\n" //-NLOK
 690       " The `EVAL` command evaluates a symbolic expression and returns the\r\n"
 691       " equivalent numeric value.\r\n\r\n"
 692        /***************** 80 character line width template *************************/
 693       "2Running A Simulated Program\n" //-NLOK
 694 #define HLP_RUN         "*Commands Running_A_Simulated_Program RUN"
 695       "3RUN\n" //-NLOK
 696       " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\r\n"
 697       " argument, if given, in the PC (program counter), and starts execution.\r\n"
 698       " If no argument is given execution starts at the current PC.\r\n"
 699 #define HLP_GO          "*Commands Running_A_Simulated_Program GO"
 700       "3GO\n" //-NLOK
 701       " The `GO` command does *not* reset devices, deposits its argument (if\r\n"
 702       " given) in the PC, and starts execution.  If no argument is given,\r\n"
 703       " execution starts at the current PC (program counter).\r\n"
 704 #define HLP_CONTINUE    "*Commands Running_A_Simulated_Program Continuing_Execution"
 705       "3Continuing Execution\n" //-NLOK
 706       " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\r\n"
 707       " (if execution was stopped, possibly due to hitting a breakpoint) at the\r\n"
 708       " current program counter without resetting any devices.\r\n"
 709 #define HLP_STEP        "*Commands Running_A_Simulated_Program Step_Execution"
 710       "3Step Execution\n" //-NLOK
 711       " The `STEP` command (*abbreviated* `S`) resumes execution at the current\r\n"
 712       " PC for the number of instructions given by its argument.  If no argument\r\n"
 713       " is supplied, one instruction is executed.\r\n"
 714       "4Switches\n" //-NLOK
 715       "5`-T`\n" //-NLOK
 716       " If the `STEP` command is invoked with the \"`-T`\" switch, the step\r\n"
 717       " command will cause execution to run for *microseconds* rather than\r\n"
 718       " instructions.\r\n"
 719 #define HLP_NEXT        "*Commands Running_A_Simulated_Program NEXT"
 720       "3NEXT\n" //-NLOK
 721       " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\r\n"
 722       " for one instruction, attempting to execute *through* subroutine calls.\r\n"
 723       " If the next instruction to be executed is *not* a subroutine call, then\r\n"
 724       " one instruction is executed.\r\n"
 725 #define HLP_BOOT        "*Commands Running_A_Simulated_Program Booting_the_system"
 726       "3Booting the system\n" //-NLOK
 727       " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\r\n"
 728       " the device and unit given by its argument. If no unit is supplied,\r\n"
 729       " unit `0` is bootstrapped.  The specified unit must be `ATTACH`'ed.\r\n\r\n"
 730       " When booting Multics, the boot device should always be `iom0`.\r\n"
 731       " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\r\n"
 732       " into memory and the system will transfer control to the boot record.\r\n\r\n"
 733       " **Example**\r\n\r\n"
 734       "++; Boot Multics using iom0\r\n"
 735       "++boot iom0\r\n\r\n"
 736        /***************** 80 character line width template *************************/
 737       "2Stopping The Simulator\n" //-NLOK
 738       " The simulator runs until the simulated hardware encounters an error, or\r\n"
 739       " until the user forces a stop condition.\r\n"
 740       "3Simulator Detected Stop Conditions\n" //-NLOK
 741       " These simulator-detected conditions stop simulation:\r\n\r\n"
 742       "++-  HALT instruction.  If a HALT instruction is decoded, simulation stops.\r\n\r\n"
 743       "++-  I/O error.  If an I/O error occurs during simulation of an I/O\r\n"
 744       "+++operation, and the device stop-on-I/O-error flag is set, simulation\r\n"
 745       "+++usually stops.\r\n\r\n"
 746       "++-  Processor condition.  Certain processor conditions can stop\r\n"
 747       "+++the simulation.\r\n"
 748       "3User Specified Stop Conditions\n" //-NLOK
 749       " Typing the interrupt character stops simulation.  The interrupt character\r\n"
 750       " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\r\n"
 751       " set to `005` (`^E`).\r\n\r\n"
 752        /***************** 80 character line width template *************************/
 753 #define HLP_BREAK       "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 754 #define HLP_NOBREAK     "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 755       "4Breakpoints\n" //-NLOK
 756       " The simulator offers breakpoint capability for debugging. Users may define\r\n"
 757       " breakpoints of different types, identified by letter (for example, `E`\r\n"
 758       " for *execution*, `R` for *read*, `W` for *write*, etc).\r\n\r\n"
 759       " Associated with each breakpoint is a count and, optionally, one or more\r\n"
 760       " actions.  Each time a breakpoint occurs, the associated count\r\n"
 761       " is *decremented*.  If the count is less than or equal to `0`, the breakpoint\r\n"
 762       " occurs; otherwise, it is deferred.  When the breakpoint occurs, any\r\n"
 763       " optional actions are automatically executed.\r\n\r\n"
 764       " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\r\n\r\n"
 765       "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\r\n\r\n"
 766       " If no type is specified, the default breakpoint type (`E`, *execution*) is\r\n"
 767       " used.  If no address range is specified, the current PC is used.  As\r\n"
 768       " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\r\n"
 769       " range of addresses low-high, or a relative range of address/length.\r\n"
 770        /***************** 80 character line width template *************************/
 771       "5Displaying Breakpoints\n" //-NLOK
 772       " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\r\n\r\n"
 773       "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\r\n\r\n"
 774       " Locations with breakpoints of the specified type are displayed.\r\n\r\n"
 775       " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\r\n"
 776       " commands which may be subsequently used to establish the same\r\n"
 777       " breakpoint(s).\r\n\r\n"
 778       "5Removing Breakpoints\n" //-NLOK
 779       " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\r\n"
 780       "5Examples\n" //-NLOK
 781       " The following examples illustrate breakpoint usage:\r\n\r\n"
 782       "++BREAK                      set E break at current PC\r\n"
 783       "++BREAK -e 200               set E break at 200\r\n"
 784       "++BREAK 2000/2[2]            set E breaks at 2000,2001 with count = 2\r\n"
 785       "++BREAK 100;EX AC;D MQ 0     set E break at 100 with actions EX AC and\r\n"
 786       "+++++++++D MQ 0\r\n"
 787       "++BREAK 100;                 delete action on break at 100\r\n\r\n"
 788        /***************** 80 character line width template *************************/
 789       "2Connecting and Disconnecting Devices\n" //-NLOK
 790       " Units are simulated as files on the host file system.  Before using any\r\n"
 791       " simulated unit, the user must specify the file to be accessed by that unit.\r\n"
 792 #define HLP_ATTACH      "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
 793       "3Attaching devices\n" //-NLOK
 794       " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\r\n\r\n"
 795       "++ATTACH <unit> <filename>\r\n\r\n"
 796       " Some devices have more detailed or specific help available with:\r\n\r\n"
 797       "++HELP <device> ATTACH\r\n\r\n"
 798       "4Switches\n" //-NLOK
 799       "5`-n`\n" //-NLOK
 800       " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\r\n"
 801       " file will be created when the filename specified does not exist, or an\r\n"
 802       " existing file will have it's size truncated to zero, and an appropriate\r\n"
 803       " message is printed.\r\n"
 804       "5`-e`\n" //-NLOK
 805       " If the file does not exist, and the \"`-e`\" switch *was not* specified,\r\n"
 806       " a new file is created, and an appropriate message is printed.  If\r\n"
 807       " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\r\n"
 808       " error message is printed.\r\n"
 809       "5`-r`\n" //-NLOK
 810       " If the \"`-r`\" switch is specified, or the file is write protected by\r\n"
 811       " host operating system, `ATTACH` tries to open the file in read only mode.\r\n"
 812       " If the file does not exist, or the unit does not support read only\r\n"
 813       " operation, an error occurs.  Input-only devices, such as card readers, or\r\n"
 814       " storage devices with write locking switches, such as disks or tapes,\r\n"
 815       " support read only operation - other devices do not.  If a file is\r\n"
 816       " attached read only, its contents can be examined but not modified.\r\n"
 817       "5`-q`\n" //-NLOK
 818       " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\r\n"
 819       " or opening one read only (\"`-r`\"), the message announcing this fact\r\n"
 820       " is suppressed.\r\n"
 821       "5`-f`\n" //-NLOK
 822       " For simulated magnetic tapes, the `ATTACH` command can specify the format\r\n"
 823       " of the attached tape image file:\r\n\r\n"
 824       "++ATTACH -f <tape_unit> <format> <filename>\r\n\r\n"
 825       " * The currently supported magnetic tape image file formats are:\r\n\r\n"
 826       " |                  |                                                      |\r\n"
 827       " | ----------------:|:---------------------------------------------------- |\r\n"
 828       " | \"**`SIMH`**\"   | The **SIMH** / **DPS8M** native portable tape format |\r\n"
 829       " | \"**`E11`**\"    | The *D Bit* **Ersatz-11** simulator format           |\r\n"
 830       " | \"**`TPC`**\"    | The **TPC** format (*used by _SIMH_ prior to V2.3*)  |\r\n"
 831       " | \"**`P7B`**\"    | The **Paul Pierce** `7`-track tape archive format    |\r\n\r\n"
 832        /***************** 80 character line width template *************************/
 833       " * The default tape format can also be specified with the `SET` command\r\n"
 834       " prior to using the `ATTACH` command:\r\n\r\n"
 835       "++SET <tape_unit> FORMAT=<format>\r\n"
 836       "++ATTACH <tape_unit> <filename>\r\n\r\n"
 837       " * The format of a currently attached tape image can be displayed with\r\n"
 838       "   the `SHOW FORMAT` command:\r\n\r\n"
 839       "++SHOW <unit> FORMAT\r\n\r\n"
 840       " **Examples**\r\n\r\n"
 841       " The following example illustrates common `ATTACH` usage:\r\n"
 842       "++; Associate the tape image file \"12.8MULTICS.tap\" with the tape0 unit\r\n"
 843       "++; in read-only mode, where tape0 corresponds to the first tape device.\r\n"
 844       "++ATTACH -r tape0 12.8MULTICS.tap\r\n\r\n"
 845       "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\r\n"
 846       "++; The disk0 unit corresponds to the first disk device.\r\n"
 847       "++ATTACH disk0 root.dsk\r\n\r\n"
 848        /***************** 80 character line width template *************************/
 849 #define HLP_DETACH      "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
 850       "3Detaching devices\n" //-NLOK
 851       " The `DETACH` (*abbreviation* `DET`) command breaks the association between\r\n"
 852       " a unit and its backing file or device:\r\n\r\n"
 853       "++DETACH ALL             Detach all units\r\n"
 854       "++DETACH <unit>          Detach specified unit\r\n\r\n"
 855       " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\r\n"
 856 #define HLP_SET         "*Commands SET"
 857       "2SET\n" //-NLOK
 858        /***************** 80 character line width template *************************/
 859 #define HLP_SET_LOG    "*Commands SET Logging"
 860       "3Logging\n" //-NLOK
 861       " Interactions with the simulator session can be recorded to a log file.\r\n\r\n"
 862       "+SET LOG log_file            Specify the log destination\r\n"
 863       "++++++++                     (STDOUT, DEBUG, or filename)\r\n"
 864       "+SET NOLOG                   Disables any currently active logging\r\n"
 865       "4Switches\n" //-NLOK
 866       "5`-N`\n" //-NLOK
 867       " By default, log output is written at the *end* of the specified log file.\r\n"
 868       " A new log file can created if the \"`-N`\" switch is used on the command\r\n"
 869       " line.\r\n\r\n"
 870       "5`-B`\n" //-NLOK
 871       " By default, log output is written in *text* mode.  The log file can be\r\n"
 872       " opened for *binary* mode writing if the \"`-B`\" switch is used on the\r\n"
 873       " command line.\r\n"
 874 #define HLP_SET_DEBUG  "*Commands SET Debug_Messages"
 875        /***************** 80 character line width template *************************/
 876       "3Debug Messages\n" //-NLOK
 877       "+SET DEBUG debug_file        Specify the debug destination\r\n"
 878       "++++++++                     (STDOUT, STDERR, LOG, or filename)\r\n"
 879       "+SET NODEBUG                 Disables any currently active debug output\r\n"
 880       "4Switches\n" //-NLOK
 881       " Debug message output contains a timestamp which indicates the number of\r\n"
 882       " simulated instructions which have been executed prior to the debug event.\r\n\r\n"
 883       " Debug message output can be enhanced to contain additional, potentially\r\n"
 884       " useful information.\r\n\r\n\r\n"
 885       " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\r\n"
 886       "5`-T`\n" //-NLOK
 887       " The \"`-T`\" switch causes debug output to contain a time of day displayed\r\n"
 888       " as `hh:mm:ss.msec`.\r\n"
 889       "5`-A`\n" //-NLOK
 890       " The \"`-A`\" switch causes debug output to contain a time of day displayed\r\n"
 891       " as `seconds.msec`.\r\n"
 892       "5`-R`\n" //-NLOK
 893       " The \"`-R`\" switch causes timing to be relative to the start of debugging.\r\n"
 894       "5`-P`\n" //-NLOK
 895       " The \"`-P`\" switch adds the output of the PC (program counter) to each\r\n"
 896       " debug message.\r\n"
 897       "5`-N`\n" //-NLOK
 898       " The \"`-N`\" switch causes a new (empty) file to be written to.\r\n"
 899       " (The default is to append to an existing debug log file).\r\n"
 900       "5`-D`\n" //-NLOK
 901       " The \"`-D`\" switch causes data blob output to also display the data\r\n"
 902       " as **`RADIX-50`** characters.\r\n"
 903       "5`-E`\n" //-NLOK
 904       " The \"`-E`\" switch causes data blob output to also display the data\r\n"
 905       " as \"**EBCDIC**\" characters.\r\n"
 906        /***************** 80 character line width template *************************/
 907 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
 908       "3Environment Variables\n" //-NLOK
 909       "+SET ENVIRONMENT NAME=val    Set environment variable\r\n"
 910       "+SET ENVIRONMENT NAME        Clear environment variable\r\n"
 911 #define HLP_SET_ON      "*Commands SET Command_Status_Trap_Dispatching"
 912       "3Command Status Trap Dispatching\n" //-NLOK
 913       "+SET ON                      Enables error checking command execution\r\n"
 914       "+SET NOON                    Disables error checking command execution\r\n"
 915       "+SET ON INHERIT              Enables inheritance of ON state and actions\r\n"
 916       "+SET ON NOINHERIT            Disables inheritance of ON state and actions\r\n"
 917 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
 918       "3Command Execution Display\n" //-NLOK
 919       "+SET VERIFY                  Enables display of processed script commands\r\n"
 920       "+SET VERBOSE                 Enables display of processed script commands\r\n"
 921       "+SET NOVERIFY                Disables display of processed script commands\r\n"
 922       "+SET NOVERBOSE               Disables display of processed script commands\r\n"
 923 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
 924       "3Command Error Status Display\n" //-NLOK
 925       "+SET MESSAGE                 Re-enables display of script error messages\r\n"
 926       "+SET NOMESSAGE               Disables display of script error messages\r\n"
 927 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
 928       "3Command Output Display\n" //-NLOK
 929       "+SET QUIET                   Disables suppression of some messages\r\n"
 930       "+SET NOQUIET                 Re-enables suppression of some messages\r\n"
 931 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
 932       "3Local Operator Console\n" //-NLOK
 933       "+SET LOCALOPC                Enables local operator console\r\n"
 934       "+SET NOLOCALOPC              Disables local operator console\r\n"
 935 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
 936       "3Command Prompt\n" //-NLOK
 937       "+SET PROMPT \"string\"         Sets an alternate simulator prompt string\r\n"
 938       "3Device and Unit Settings\n" //-NLOK
 939       "+SET <dev> OCT|DEC|HEX       Set device display radix\r\n"
 940       "+SET <dev> ENABLED           Enable device\r\n"
 941       "+SET <dev> DISABLED          Disable device\r\n"
 942       "+SET <dev> DEBUG{=arg}       Set device debug flags\r\n"
 943       "+SET <dev> NODEBUG={arg}     Clear device debug flags\r\n"
 944       "+SET <dev> arg{,arg...}      Set device parameters\r\n"
 945       "+SET <unit> ENABLED          Enable unit\r\n"
 946       "+SET <unit> DISABLED         Disable unit\r\n"
 947       "+SET <unit> arg{,arg...}     Set unit parameters\r\n"
 948       "+HELP <dev> SET              Displays any device specific SET commands\r\n"
 949       " \r\n\r\n"
 950       " See the Omnibus documentation for a complete SET command reference.\r\n"
 951        /***************** 80 character line width template *************************/
 952 #define HLP_SHOW        "*Commands SHOW"
 953       "2SHOW\n" //-NLOK
 954       "+SH{OW} B{UILDINFO}               Show build-time compilation information\r\n"
 955       "+SH{OW} CL{OCKS}                  Show wall clock and timer information\r\n"
 956       "+SH{OW} C{ONFIGURATION}           Show simulator configuration\r\n"
 957       "+SH{OW} D{EFAULT_BASE_SYSTEM}     Show default base system script\r\n"
 958       "+SH{OW} DEV{ICES}                 Show devices\r\n"
 959       "+SH{OW} H{INTS}                   Show configuration hints\r\n"
 960       "+SH{OW} M{ODIFIERS}               Show SET commands for all devices\r\n"
 961       "+SH{OW} O{N}                      Show ON condition actions\r\n"
 962       "+SH{OW} P{ROM}                    Show CPU ID PROM initialization data\r\n"
 963       "+SH{OW} Q{UEUE}                   Show event queue\r\n"
 964       "+SH{OW} S{HOW}                    Show SHOW commands for all devices\r\n"
 965       "+SH{OW} T{IME}                    Show simulated timer\r\n"
 966       "+SH{OW} VE{RSION}                 Show simulator version\r\n"
 967       "+H{ELP} <dev> SHOW                Show device-specific SHOW commands\r\n"
 968       "+SH{OW} <dev> {arg,...}           Show device parameters\r\n"
 969       "+SH{OW} <dev> DEBUG               Show device debug flags\r\n"
 970       "+SH{OW} <dev> MODIFIERS           Show device modifiers\r\n"
 971       "+SH{OW} <dev> RADIX               Show device display radix\r\n"
 972       "+SH{OW} <dev> SHOW                Show device SHOW commands\r\n"
 973       "+SH{OW} <unit> {arg,...}          Show unit parameters\r\n\r\n"
 974       " See the Omnibus documentation for a complete SHOW command reference.\r\n\r\n"
 975 #define HLP_SHOW_CONFIG         "*Commands SHOW"
 976 #define HLP_SHOW_DEVICES        "*Commands SHOW"
 977 #define HLP_SHOW_FEATURES       "*Commands SHOW"
 978 #define HLP_SHOW_QUEUE          "*Commands SHOW"
 979 #define HLP_SHOW_TIME           "*Commands SHOW"
 980 #define HLP_SHOW_MODIFIERS      "*Commands SHOW"
 981 #define HLP_SHOW_NAMES          "*Commands SHOW"
 982 #define HLP_SHOW_SHOW           "*Commands SHOW"
 983 #define HLP_SHOW_VERSION        "*Commands SHOW"
 984 #define HLP_SHOW_BUILDINFO      "*Commands SHOW"
 985 #define HLP_SHOW_PROM           "*Commands SHOW"
 986 #define HLP_SHOW_HINTS          "*Commands SHOW"
 987 #define HLP_SHOW_DBS            "*Commands SHOW"
 988 #define HLP_SHOW_DEFAULT        "*Commands SHOW"
 989 #define HLP_SHOW_CONSOLE        "*Commands SHOW"
 990 #define HLP_SHOW_REMOTE         "*Commands SHOW"
 991 #define HLP_SHOW_BREAK          "*Commands SHOW"
 992 #define HLP_SHOW_LOG            "*Commands SHOW"
 993 #define HLP_SHOW_DEBUG          "*Commands SHOW"
 994 #define HLP_SHOW_CLOCKS         "*Commands SHOW"
 995 #define HLP_SHOW_ON             "*Commands SHOW"
 996 #define HLP_SHOW_SEND           "*Commands SHOW"
 997 #define HLP_SHOW_EXPECT         "*Commands SHOW"
 998 #define HLP_HELP                "*Commands HELP"
 999        /***************** 80 character line width template *************************/
1000       "2HELP\n" //-NLOK
1001       "+H{ELP}                      Show this message\r\n"
1002       "+H{ELP} <command>            Show help for command\r\n"
1003       "+H{ELP} <dev>                Show help for device\r\n"
1004       "+H{ELP} <dev> REGISTERS      Show help for device register variables\r\n"
1005       "+H{ELP} <dev> ATTACH         Show help for device specific ATTACH command\r\n"
1006       "+H{ELP} <dev> SET            Show help for device specific SET commands\r\n"
1007       "+H{ELP} <dev> SHOW           Show help for device specific SHOW commands\r\n"
1008       "+H{ELP} <dev> <command>      Show help for device specific <command> command\r\n"
1009        /***************** 80 character line width template *************************/
1010       "2Altering The Simulated Configuration\n" //-NLOK
1011       " The \"SET <device> DISABLED\" command removes a device from the configuration.\r\n"
1012       " A `DISABLED` device is invisible to running programs.  The device can still\r\n"
1013       " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\r\n\r\n"
1014       " The \"SET <device> ENABLED\" command restores a disabled device to a\r\n"
1015       " configuration.\r\n\r\n"
1016       " Most multi-unit devices allow units to be enabled or disabled:\r\n\r\n"
1017       "++SET <unit> ENABLED\r\n"
1018       "++SET <unit> DISABLED\r\n\r\n"
1019       " When a unit is disabled, it will not be displayed by SHOW DEVICE.\r\n\r\n"
1020        /***************** 80 character line width template *************************/
1021 #define HLP_DO          "*Commands Executing_Command_Files Processing_Command_Files"
1022       "2Executing Command Files\n" //-NLOK
1023       "3Processing Command Files\n" //-NLOK
1024       " The simulator can invoke another script file with the \"`DO`\" command:\r\n\r\n"
1025       "++DO <filename> {arguments...}       execute commands in specified file\r\n\r\n"
1026       " The \"`DO`\" command allows command files to contain substitutable\r\n"
1027       " arguments. The string \"`%%n`\", where \"`n`\" is a number\r\n"
1028       " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\r\n"
1029       " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\r\n"
1030       " The string \"`%%0`\" is replaced with \"<`filename`>\"\r\n"
1031       " The sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\r\n"
1032       " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\r\n"
1033       " be enclosed in matching single or double quotation marks.\r\n\r\n"
1034       " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\r\n"
1035       " deep.\r\n\r\n"
1036       "4Switches\n" //-NLOK
1037       "5`-v`\n\n" //-NLOK
1038       " If the switch \"`-v`\" is specified, commands in the command file are\r\n"
1039       " echoed *before* they are executed.\r\n\r\n"
1040       "5`-e`\n\n" //-NLOK
1041       " If the switch \"`-e`\" is specified, command processing (including nested\r\n"
1042       " command invocations) will be aborted if any command error is encountered.\r\n"
1043       " (A simulation stop **never** aborts processing; use `ASSERT` to catch\r\n"
1044       " unexpected stops.) Without this switch, all errors except `ASSERT` failures\r\n"
1045       " will be ignored, and command processing will continue.\r\n\r\n"
1046       "5`-o`\n\n" //-NLOK
1047       " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\r\n"
1048       " the calling command file will be inherited by the command file being\r\n"
1049       " invoked.\r\n"
1050       "5`-q`\n\n" //-NLOK
1051       " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\r\n"
1052       " enabled for the called command file, otherwise the *quiet mode* setting\r\n"
1053       " is inherited from the calling context.\r\n"
1054        /***************** 80 character line width template *************************/
1055 #define HLP_GOTO        "*Commands Executing_Command_Files GOTO"
1056       "3GOTO\n" //-NLOK
1057       " Commands in a command file execute in sequence until either an error\r\n"
1058       " trap occurs (when a command completes with an error status), or when an\r\n"
1059       " explicit request is made to start command execution elsewhere with\r\n"
1060       " the `GOTO` command:\r\n\r\n"
1061       "++GOTO <label>\r\n\r\n"
1062       " * Labels are lines in a command file which the first non-whitespace\r\n"
1063       " character is a \"`:`\".\r\n"
1064       " * The target of a `GOTO` is the first matching label in the current `DO`\r\n"
1065       " command file which is encountered.\r\n\r\n"
1066       " **Example**\r\n\r\n"
1067       " The following example illustrates usage of the `GOTO` command (by\r\n"
1068       " creating an infinite loop):\r\n\r\n"
1069       "++:Label\r\n"
1070       "++:: This is a loop.\r\n"
1071       "++GOTO Label\r\n\r\n"
1072 #define HLP_RETURN      "*Commands Executing_Command_Files RETURN"
1073        /***************** 80 character line width template *************************/
1074       "3RETURN\n" //-NLOK
1075       " The `RETURN` command causes the current procedure call to be restored to\r\n"
1076       " the calling context, possibly returning a specific return status.\r\n"
1077       " If no return status is specified, the return status from the last command\r\n"
1078       " executed will be returned.  The calling context may have `ON` traps defined\r\n"
1079       " which may redirect command flow in that context.\r\n\r\n"
1080       "++RETURN                 return from command file with last command status\r\n"
1081       "++RETURN {-Q} <status>   return from command file with specific status\r\n\r\n"
1082       " * The status return can be any numeric value or one of the standard SCPE_\r\n"
1083       " condition names.\r\n\r\n"
1084       " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\r\n"
1085       " status to be returned, but normal error status message printing to be\r\n"
1086       " suppressed.\r\n\r\n"
1087       " **Condition Names**\r\n\r\n"
1088       " The available standard SCPE_ condition names and their meanings are:\r\n\r\n"
1089       " | Name    | Meaning                         | Name    | Meaning                             |\r\n"
1090       " | ------- | --------------------------------| ------- | ----------------------------------- |\r\n"
1091       " | NXM     | Address space exceeded          | UNATT   | Unit not attached                   |\r\n"
1092       " | IOERR   | I/O error                       | CSUM    | Checksum error                      |\r\n"
1093       " | FMT     | Format error                    | NOATT   | Unit not attachable                 |\r\n"
1094       " | OPENERR | File open error                 | MEM     | Memory exhausted                    |\r\n"
1095       " | ARG     | Invalid argument                | STEP    | Step expired                        |\r\n"
1096       " | UNK     | Unknown command                 | RO      | Read only argument                  |\r\n"
1097       " | INCOMP  | Command not completed           | STOP    | Simulation stopped                  |\r\n"
1098       " | EXIT    | Goodbye                         | TTIERR  | Console input I/O error             |\r\n"
1099       " | TTOERR  | Console output I/O error        | EOF     | End of file                         |\r\n"
1100       " | REL     | Relocation error                | NOPARAM | No settable parameters              |\r\n"
1101       " | ALATT   | Unit already attached           | TIMER   | Hardware timer error                |\r\n"
1102       " | SIGERR  | Signal handler setup error      | TTYERR  | Console terminal setup error        |\r\n"
1103       " | NOFNC   | Command not allowed             | UDIS    | Unit disabled                       |\r\n"
1104       " | NORO    | Read only operation not allowed | INVSW   | Invalid switch                      |\r\n"
1105       " | MISVAL  | Missing value                   | 2FARG   | Too few arguments                   |\r\n"
1106       " | 2MARG   | Too many arguments              | NXDEV   | Non-existent device                 |\r\n"
1107       " | NXUN    | Non-existent unit               | NXREG   | Non-existent register               |\r\n"
1108       " | NXPAR   | Non-existent parameter          | NEST    | Nested DO command limit exceeded    |\r\n"
1109       " | IERR    | Internal error                  | MTRLNT  | Invalid magtape record length       |\r\n"
1110       " | LOST    | Console Telnet connection lost  | TTMO    | Console Telnet connection timed out |\r\n"
1111       " | STALL   | Console Telnet output stall     | AFAIL   | Assertion failed                    |\r\n"
1112       " | INVREM  | Invalid remote console command  |         |                                     |\r\n"
1113       "\r\n\r\n"
1114 #define HLP_SHIFT       "*Commands Executing_Command_Files Shift_Parameters"
1115       "3Shift Parameters\n" //-NLOK
1116       " Shift the command files positional parameters\r\n"
1117 #define HLP_CALL        "*Commands Executing_Command_Files Call_a_subroutine"
1118       "3Call a subroutine\n" //-NLOK
1119       " Control can be transferred to a labeled subroutine using `CALL`.\r\n\r\n"
1120       " **Example**\r\n\r\n"
1121       "++CALL routine\r\n"
1122       "++BYE\r\n"
1123       "++\r\n"
1124       "++:routine\r\n"
1125       "++ECHO routine called\r\n"
1126       "++RETURN\r\n\r\n"
1127 #define HLP_ON          "*Commands Executing_Command_Files ON"
1128       "3ON\n" //-NLOK
1129       " The `ON` command performs actions after a condition, or clears a condition.\r\n"
1130       "++ON <condition> <action>  Perform action after condition\r\n"
1131       "++ON <condition>           Clears action of specified condition\r\n"
1132 #define HLP_PROCEED     "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1133 #define HLP_IGNORE      "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1134        /***************** 80 character line width template *************************/
1135       "3PROCEED or IGNORE\n" //-NLOK
1136       " The `PROCEED` (or `IGNORE`) command does nothing.  It is potentially\r\n"
1137       " useful as a placeholder for any `ON` action condition that should be\r\n"
1138       " explicitly ignored, allowing command file execution to continue without\r\n"
1139       " taking any specific action.\r\n"
1140 #define HLP_ECHO        "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1141        /***************** 80 character line width template *************************/
1142       "3Displaying Arbitrary Text\n" //-NLOK
1143       " The `ECHO` command is a useful way of annotating command files.  `ECHO`\r\n"
1144       " prints out its arguments to the console (and to any applicable log file):\r\n\r\n"
1145       "++ECHO <string>      Output string to console\r\n\r\n"
1146       " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\r\n"
1147       " This may be used to provide spacing for console messages or log file\r\n"
1148       " output.\r\n"
1149        /***************** 80 character line width template *************************/
1150 #define HLP_ASSERT      "*Commands Executing_Command_Files Testing_Assertions"
1151       "3Testing Assertions\n" //-NLOK
1152       " The `ASSERT` command tests a simulator state condition and halts command\r\n"
1153       " file execution if the condition is false:\r\n\r\n"
1154       "++ASSERT <Simulator State Expressions>\r\n\r\n"
1155       " * If the indicated expression evaluates to false, the command completes\r\n"
1156       " with an `AFAIL` condition.  By default, when a command file encounters a\r\n"
1157       " command which returns the `AFAIL` condition, it will exit the running\r\n"
1158       " command file with the `AFAIL` status to the calling command file.  This\r\n"
1159       " behavior can be changed with the `ON` command as well as switches to the\r\n"
1160       " invoking `DO` command.\r\n\r\n"
1161       " **Examples**\r\n\r\n"
1162       " The command file below might be used to bootstrap a hypothetical system\r\n"
1163       " that halts after the initial load from disk. The `ASSERT` command can then\r\n"
1164       " be used to confirm that the load completed successfully by examining the\r\n"
1165       " CPU's \"`A`\" register for the expected value:`\r\n\r\n"
1166       "++; Example INI file\r\n"
1167       "++BOOT\r\n"
1168       "++; A register contains error code; 0 = good boot\r\n"
1169       "++ASSERT A=0\r\n"
1170       "++RUN\r\n\r\n"
1171        /***************** 80 character line width template *************************/
1172       " * In the above example, if the \"`A`\" register is *not* `0`,\r\n"
1173       " the \"`ASSERT A=0`\" command will be displayed to the user, and the\r\n"
1174       " command file will be aborted with an \"`Assertion failed`\" message.\r\n"
1175       " Otherwise, the command file will continue to bring up the system.\r\n\r\n"
1176       " * See the **`IF`** command documentation for more information and details\r\n"
1177       " regarding simulator state expressions.\r\n\r\n"
1178 #define HLP_IF          "*Commands Executing_Command_Files Testing_Conditions"
1179       "3Testing Conditions\n" //-NLOK
1180       " The `IF` command tests a simulator state condition and executes additional\r\n"
1181       " commands if the condition is true:\r\n\r\n"
1182       "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\r\n\r\n"
1183       " **Examples**\r\n\r\n"
1184       " The command file below might be used to bootstrap a hypothetical system\r\n"
1185       " that halts after the initial load from disk. The `IF` command can then\r\n"
1186       " be used to confirm that the load completed successfully by examining the\r\n"
1187       " CPU's \"`A`\" register for an expected value:\r\n\r\n"
1188       "++; Example INI file\r\n"
1189       "++BOOT\r\n"
1190       "++; A register contains error code; 0 = good boot\r\n"
1191       "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\r\n"
1192       "++RUN\r\n\r\n"
1193        /***************** 80 character line width template *************************/
1194       " * In the above example, if the \"`A`\" register is *not* `0`, the\r\n"
1195       " message \"`Boot failed - Failure Code `\" will be displayed, the contents\r\n"
1196       " of the \"`A`\" register will be displayed, and the command file will be\r\n"
1197       " aborted with an \"`Assertion failed`\" message.  Otherwise, the command\r\n"
1198       " file will continue to bring up the system.\r\n"
1199       "4Conditional Expressions\n" //-NLOK
1200       " The `IF` and `ASSERT` commands evaluate the following two different forms\r\n"
1201       " of conditional expressions.\r\n\r\n"
1202       "5Simulator State Expressions\n" //-NLOK
1203       "  &nbsp;\r\n \r\n"
1204       " The values of simulator registers can be evaluated with:\r\n\r\n"
1205       "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\r\n\r\n"
1206       " * If \"<`dev`>\" is not specified, `CPU` is assumed.  \"<`reg`>\" is a\r\n"
1207       " register belonging to the indicated device.\r\n"
1208       " * The \"<`addr`>\" is an address in the address space of the indicated\r\n"
1209       " device.\r\n"
1210       " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\r\n"
1211       " the same as those used for \"search specifiers\" by the `EXAMINE` and\r\n"
1212       " `DEPOSIT` commands.\r\n"
1213       " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\r\n"
1214       " not in the radix for the device when referencing a register; when an\r\n"
1215       " address is referenced the device radix is used as the default.\r\n\r\n"
1216       " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\r\n"
1217       " register value is first altered as indicated.  The result is then compared\r\n"
1218       " to the \"<`value`>\" via the \"<`conditional-op`>\".\r\n"
1219       " * * If the result is *true*, the command(s) are executed before proceeding\r\n"
1220       " to the next line in the command file.\r\n"
1221       " * * If the result is *false*, the next command in the command file is\r\n"
1222       " processed.\r\n\r\n"
1223       "5String Comparison Expressions\n" //-NLOK
1224       "  &nbsp;\r\n \r\n"
1225       " String Values can be compared with:\r\n\r\n"
1226       "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\r\n\r\n"
1227       " * The \"`-i`\" switch, if present, causes a comparison to be case\r\n"
1228       "   insensitive.\r\n"
1229       " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\r\n"
1230       "   values which may have environment variables substituted as desired.\r\n"
1231       " * The \"<`compare-op`>\" may be one of:\r\n\r\n"
1232       " |                |                        |\r\n"
1233       " | --------------:|:---------------------- |\r\n"
1234       " | \"**`==`**\"     |  equal                 |\r\n"
1235       " | \"**`EQU`**\"    |  equal                 |\r\n"
1236       " | \"**`!=`**\"     |  not equal             |\r\n"
1237       " | \"**`NEQ`**\"    |  not equal             |\r\n"
1238       " | \"**<**\"        |  less than             |\r\n"
1239       " | \"**`LSS`**\"    |  less than             |\r\n"
1240       " | \"**<=**\"       |  less than or equal    |\r\n"
1241       " | \"**`LEQ`**\"    |  less than or equal    |\r\n"
1242       " | \"**>**\"        |  greater than          |\r\n"
1243       " | \"**`GTR`**\"    |  greater than          |\r\n"
1244       " | \"**>=**\"       |  greater than or equal |\r\n"
1245       " | \"**`GEQ`**\"    |  greater than or equal |\r\n"
1246       " * **NOTE**: Comparisons are *generic*.  This means that if\r\n"
1247       " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\r\n"
1248       " digits, then the strings are converted to numbers and a numeric\r\n"
1249       " comparison is performed.  For example, the comparison\r\n"
1250       " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\r\n"
1251        /***************** 80 character line width template *************************/
1252 #define HLP_EXIT        "*Commands Exiting_the_Simulator"
1253       "2Exiting the Simulator\n" //-NLOK
1254       " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\r\n"
1255       " returning control to the host operating system.\r\n"
1256        /***************** 80 character line width template *************************/
1257 #define HLP_SPAWN       "*Commands Executing_System_Commands"
1258       "2Executing System Commands\n" //-NLOK
1259       " * The simulator can execute host operating system commands with\r\n"
1260       " the \"`!`\" (*spawn*) command.\r\n\r\n"
1261       " |                         |                                             |\r\n"
1262       " |:----------------------- |:------------------------------------------- |\r\n"
1263       " | \"**`!`**\"             | Spawn the hosts default command interpreter |\r\n"
1264       " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\r\n\r\n"
1265       " * **NOTE**: The *exit status* from the command which was executed is set\r\n"
1266       " as the *command completion status* for the \"`!`\" command.  This may\r\n"
1267       " influence any enabled `ON` condition traps.\r\n" ;
1268        /***************** 80 character line width template *************************/
1269 
1270 static CTAB cmd_table[] = {
1271     { "RESET",    &reset_cmd,  0,         HLP_RESET     },
1272     { "EXAMINE",  &exdep_cmd,  EX_E,      HLP_EXAMINE   },
1273     { "IEXAMINE", &exdep_cmd,  EX_E+EX_I, HLP_IEXAMINE  },
1274     { "DEPOSIT",  &exdep_cmd,  EX_D,      HLP_DEPOSIT   },
1275     { "IDEPOSIT", &exdep_cmd,  EX_D+EX_I, HLP_IDEPOSIT  },
1276     { "EVALUATE", &eval_cmd,   0,         HLP_EVALUATE  },
1277     { "RUN",      &run_cmd,    RU_RUN,    HLP_RUN,      NULL, &run_cmd_message },
1278     { "GO",       &run_cmd,    RU_GO,     HLP_GO,       NULL, &run_cmd_message },
1279     { "STEP",     &run_cmd,    RU_STEP,   HLP_STEP,     NULL, &run_cmd_message },
1280     { "NEXT",     &run_cmd,    RU_NEXT,   HLP_NEXT,     NULL, &run_cmd_message },
1281     { "CONTINUE", &run_cmd,    RU_CONT,   HLP_CONTINUE, NULL, &run_cmd_message },
1282     { "BOOT",     &run_cmd,    RU_BOOT,   HLP_BOOT,     NULL, &run_cmd_message },
1283     { "BREAK",    &brk_cmd,    SSH_ST,    HLP_BREAK     },
1284     { "NOBREAK",  &brk_cmd,    SSH_CL,    HLP_NOBREAK   },
1285     { "ATTACH",   &attach_cmd, 0,         HLP_ATTACH    },
1286     { "DETACH",   &detach_cmd, 0,         HLP_DETACH    },
1287     { "EXIT",     &exit_cmd,   0,         HLP_EXIT      },
1288     { "QUIT",     &exit_cmd,   0,         NULL          },
1289     { "BYE",      &exit_cmd,   0,         NULL          },
1290     { "SET",      &set_cmd,    0,         HLP_SET       },
1291     { "SHOW",     &show_cmd,   0,         HLP_SHOW      },
1292     { "DO",       &do_cmd,     1,         HLP_DO        },
1293     { "GOTO",     &goto_cmd,   1,         HLP_GOTO      },
1294     { "RETURN",   &return_cmd, 0,         HLP_RETURN    },
1295     { "SHIFT",    &shift_cmd,  0,         HLP_SHIFT     },
1296     { "CALL",     &call_cmd,   0,         HLP_CALL      },
1297     { "ON",       &on_cmd,     0,         HLP_ON        },
1298     { "IF",       &assert_cmd, 0,         HLP_IF        },
1299     { "PROCEED",  &noop_cmd,   0,         HLP_PROCEED   },
1300     { "IGNORE",   &noop_cmd,   0,         HLP_IGNORE    },
1301     { "ECHO",     &echo_cmd,   0,         HLP_ECHO      },
1302     { "ASSERT",   &assert_cmd, 1,         HLP_ASSERT    },
1303     { "SEND",     &send_cmd,   0          },            /* deprecated */
1304     { "EXPECT",   &expect_cmd, 1          },            /* deprecated */
1305     { "NOEXPECT", &expect_cmd, 0          },            /* deprecated */
1306     { "!",        &spawn_cmd,  0,         HLP_SPAWN     },
1307     { "HELP",     &help_cmd,   0,         HLP_HELP      },
1308     { NULL,       NULL,        0          }
1309     };
1310 
1311 static CTAB set_glob_tab[] = {
1312     { "CONSOLE",     &sim_set_console,        0      }, /* deprecated */
1313     { "REMOTE",      &sim_set_remote_console, 0      }, /* deprecated */
1314     { "BREAK",       &brk_cmd,                SSH_ST }, /* deprecated */
1315     { "NOBREAK",     &brk_cmd,                SSH_CL }, /* deprecated */
1316     { "TELNET",      &sim_set_telnet,         0      }, /* deprecated */
1317     { "NOTELNET",    &sim_set_notelnet,       0      }, /* deprecated */
1318     { "LOG",         &sim_set_logon,          0,     HLP_SET_LOG      },
1319     { "NOLOG",       &sim_set_logoff,         0,     HLP_SET_LOG      },
1320     { "DEBUG",       &sim_set_debon,          0,     HLP_SET_DEBUG    },
1321     { "NODEBUG",     &sim_set_deboff,         0,     HLP_SET_DEBUG    },
1322     { "ENVIRONMENT", &sim_set_environment,    1,     HLP_SET_ENVIRON  },
1323     { "ON",          &set_on,                 1,     HLP_SET_ON       },
1324     { "NOON",        &set_on,                 0,     HLP_SET_ON       },
1325     { "VERIFY",      &set_verify,             1,     HLP_SET_VERIFY   },
1326     { "VERBOSE",     &set_verify,             1,     HLP_SET_VERIFY   },
1327     { "NOVERIFY",    &set_verify,             0,     HLP_SET_VERIFY   },
1328     { "NOVERBOSE",   &set_verify,             0,     HLP_SET_VERIFY   },
1329     { "MESSAGE",     &set_message,            1,     HLP_SET_MESSAGE  },
1330     { "NOMESSAGE",   &set_message,            0,     HLP_SET_MESSAGE  },
1331     { "QUIET",       &set_quiet,              1,     HLP_SET_QUIET    },
1332     { "NOQUIET",     &set_quiet,              0,     HLP_SET_QUIET    },
1333     { "LOCALOPC",    &set_localopc,           1,     HLP_SET_LOCALOPC },
1334     { "NOLOCALOPC",  &set_localopc,           0,     HLP_SET_LOCALOPC },
1335     { "PROMPT",      &set_prompt,             0,     HLP_SET_PROMPT   },
1336     { NULL,          NULL,                    0      }
1337     };
1338 
1339 static C1TAB set_dev_tab[] = {
1340     { "OCTAL",    &set_dev_radix,   8  },
1341     { "DECIMAL",  &set_dev_radix,  10  },
1342     { "HEX",      &set_dev_radix,  16  },
1343     { "ENABLED",  &set_dev_enbdis,  1  },
1344     { "DISABLED", &set_dev_enbdis,  0  },
1345     { "DEBUG",    &set_dev_debug,   1  },
1346     { "NODEBUG",  &set_dev_debug,   0  },
1347     { NULL,       NULL,             0  }
1348     };
1349 
1350 static C1TAB set_unit_tab[] = {
1351     { "ENABLED",  &set_unit_enbdis, 1 },
1352     { "DISABLED", &set_unit_enbdis, 0 },
1353     { NULL,       NULL,             0 }
1354     };
1355 
1356 static SHTAB show_glob_tab[] = {
1357     { "CONFIGURATION",  &show_config,        0, HLP_SHOW_CONFIG    },
1358     { "DEFAULT_BASE_SYSTEM_SCRIPT",
1359            &show_default_base_system_script, 0, HLP_SHOW_DBS       },
1360     { "DEVICES",   &show_config,             1, HLP_SHOW_DEVICES   },
1361     { "FEATURES",  &show_config,             2, HLP_SHOW_FEATURES  },
1362     { "QUEUE",     &show_queue,              0, HLP_SHOW_QUEUE     },
1363     { "TIME",      &show_time,               0, HLP_SHOW_TIME      },
1364     { "MODIFIERS", &show_mod_names,          0, HLP_SHOW_MODIFIERS },
1365     { "NAMES",     &show_log_names,          0, HLP_SHOW_NAMES     },
1366     { "SHOW",      &show_show_commands,      0, HLP_SHOW_SHOW      },
1367     { "VERSION",   &show_version,            1, HLP_SHOW_VERSION   },
1368     { "BUILDINFO", &show_buildinfo,          1, HLP_SHOW_BUILDINFO },
1369     { "PROM",      &show_prom,               0, HLP_SHOW_PROM      },
1370     { "HINTS",     &show_hints,              0, HLP_SHOW_HINTS     },
1371     { "CONSOLE",   &sim_show_console,        0, HLP_SHOW_CONSOLE   },
1372     { "REMOTE",    &sim_show_remote_console, 0, HLP_SHOW_REMOTE    },
1373     { "BREAK",     &show_break,              0, HLP_SHOW_BREAK     },
1374     { "LOG",       &sim_show_log,            0, HLP_SHOW_LOG       },
1375     { "TELNET",    &sim_show_telnet,         0  },  /* deprecated */
1376     { "DEBUG",     &sim_show_debug,          0, HLP_SHOW_DEBUG     },
1377     { "CLOCKS",    &sim_show_timers,         0, HLP_SHOW_CLOCKS    },
1378     { "SEND",      &sim_show_send,           0, HLP_SHOW_SEND      },
1379     { "EXPECT",    &sim_show_expect,         0, HLP_SHOW_EXPECT    },
1380     { "ON",        &show_on,                 0, HLP_SHOW_ON        },
1381     { NULL,        NULL,                     0  }
1382     };
1383 
1384 static SHTAB show_dev_tab[] = {
1385     { "RADIX",     &show_dev_radix,         0 },
1386     { "DEBUG",     &show_dev_debug,         0 },
1387     { "MODIFIERS", &show_dev_modifiers,     0 },
1388     { "NAMES",     &show_dev_logicals,      0 },
1389     { "SHOW",      &show_dev_show_commands, 0 },
1390     { NULL,        NULL,                    0 }
1391     };
1392 
1393 static SHTAB show_unit_tab[] = {
1394     { NULL, NULL, 0 }
1395     };
1396 
1397 #if defined(_WIN32)
1398 static
1399 int setenv(const char *envname, const char *envval, int overwrite)
     /* [previous][next][first][last][top][bottom][index][help] */
1400 {
1401 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1402 int r;
1403 
1404 (void)sprintf(envstr, "%s=%s", envname, envval);
1405 r = _putenv(envstr);
1406 FREE(envstr);
1407 return r;
1408 }
1409 
1410 static
1411 int unsetenv(const char *envname)
     /* [previous][next][first][last][top][bottom][index][help] */
1412 {
1413 setenv(envname, "", 1);
1414 return 0;
1415 }
1416 #endif /* if defined(_WIN32) */
1417 
1418 #if !defined(NO_LOCALE)
1419 # define XSTR_EMAXLEN 32767
1420 
1421 const char
1422 *xstrerror_l(int errnum)
     /* [previous][next][first][last][top][bottom][index][help] */
1423 {
1424   int saved = errno;
1425   const char *ret = NULL;
1426   static __thread char buf[XSTR_EMAXLEN];
1427 
1428 # if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1429      defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1430 #  if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1431   if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1432 #  else
1433   if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1434 #  endif
1435 # else
1436 #  if defined(__NetBSD__)
1437   locale_t loc = LC_GLOBAL_LOCALE;
1438 #  else
1439   locale_t loc = uselocale((locale_t)0);
1440 #  endif
1441   locale_t copy = loc;
1442   if (copy == LC_GLOBAL_LOCALE)
1443     copy = duplocale(copy);
1444 
1445   if (copy != (locale_t)0)
1446     {
1447       ret = strerror_l(errnum, copy); /*LINTOK: xstrerror_l*/
1448       if (loc == LC_GLOBAL_LOCALE)
1449         {
1450           freelocale(copy);
1451         }
1452     }
1453 # endif
1454 
1455   if (!ret)
1456     {
1457       (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1458       ret = buf;
1459     }
1460 
1461   errno = saved;
1462   return ret;
1463 }
1464 #else
1465 # define xstrerror_l strerror
1466 #endif
1467 
1468 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1469 
1470 /* Substring removal hack */
1471 
1472 char *strremove(char *str, const char *sub)
     /* [previous][next][first][last][top][bottom][index][help] */
1473 {
1474     char *p, *q, *r;
1475     if (*sub && (q = r = strstr(str, sub)) != NULL) {
1476         size_t len = strlen(sub);
1477         while ((r = strstr(p = r + len, sub)) != NULL) {
1478             while (p < r)
1479                 *q++ = *p++;
1480         }
1481         while ((*q++ = *p++) != '\0')
1482             continue;
1483     }
1484     return str;
1485 }
1486 
1487 /* Trim whitespace */
1488 
1489 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
     /* [previous][next][first][last][top][bottom][index][help] */
1490 {
1491     while (*str_untrimmed != '\0') {
1492       if(!isspace((unsigned char)*str_untrimmed)) {
1493         *str_trimmed = (char)*str_untrimmed;
1494         str_trimmed++;
1495       }
1496       str_untrimmed++;
1497     }
1498     *str_trimmed = '\0';
1499 }
1500 
1501 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1502 void allowCores(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1503 {
1504   int ret;
1505   struct rlimit limit;
1506 # if defined(RLIMIT_CORE)
1507   ret = getrlimit(RLIMIT_CORE, &limit);
1508   (void)ret;
1509 #  if defined(TESTING)
1510   if (ret != 0)
1511     {
1512       sim_warn ("Failed to query core dump configuration.");
1513       return;
1514     }
1515 #  endif /* if defined(TESTING) */
1516   limit.rlim_cur = limit.rlim_max;
1517   ret = setrlimit(RLIMIT_CORE, &limit);
1518 #  if defined(TESTING)
1519   if (ret != 0)
1520     {
1521       sim_warn ("Failed to enable unlimited core dumps.");
1522       return;
1523     }
1524 #  endif /* if defined(TESTING) */
1525 # else
1526 #  if defined(TESTING)
1527   sim_warn ("Unable to query core dump configuration.");
1528 #  endif /* if defined(TESTING) */
1529 # endif /* if defined(RLIMIT_CORE) */
1530   return;
1531 }
1532 #endif
1533 
1534 #if defined(USE_DUMA)
1535 void CleanDUMA(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1536 {
1537   (void)fflush(stdout);
1538   DUMA_CHECKALL();
1539   (void)fflush(stderr);
1540 }
1541 # undef USE_DUMA
1542 # define USE_DUMA 1
1543 #endif /* if defined(USE_DUMA) */
1544 
1545 #if !defined(SIG_SETMASK)
1546 # undef USE_BACKTRACE
1547 #endif /* if !defined(SIG_SETMASK) */
1548 
1549 #if defined(PERF_STRIP)
1550 # undef USE_BACKTRACE
1551 #endif /* if defined(PERF_STRIP) */
1552 
1553 #if defined(USE_BACKTRACE)
1554 # include <backtrace.h>
1555 # include <backtrace-supported.h>
1556 # define BACKTRACE_SKIP 1
1557 # define BACKTRACE_MAIN "main"
1558 # undef USE_BACKTRACE
1559 # define USE_BACKTRACE 1
1560 #endif /* if defined(USE_BACKTRACE) */
1561 
1562 #if defined(BACKTRACE_SUPPORTED)
1563 # if defined(BACKTRACE_SUPPORTS_THREADS)
1564 #  if !(BACKTRACE_SUPPORTED)
1565 #   undef USE_BACKTRACE
1566 #  endif /* if !(BACKTRACE_SUPPORTED) */
1567 # else  /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1568 #  undef USE_BACKTRACE
1569 # endif /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1570 #else  /* if defined(BACKTRACE_SUPPORTED) */
1571 # undef USE_BACKTRACE
1572 #endif /* if defined(BACKTRACE_SUPPORTED) */
1573 
1574 #if defined(USE_BACKTRACE)
1575 # if defined(BACKTRACE_SUPPORTED)
1576 #  include "backtrace_func.c"
1577 # endif /* if defined(BACKTRACE_SUPPORTED) */
1578 #endif /* if defined(USE_BACKTRACE) */
1579 
1580 #if !defined(__CYGWIN__)
1581 # if !defined(__APPLE__)
1582 #  if !defined(_AIX)
1583 #   if !defined(__MINGW32__)
1584 #    if !defined(__MINGW64__)
1585 #     if !defined(CROSS_MINGW32)
1586 #      if !defined(CROSS_MINGW64)
1587 #       if !defined(_WIN32)
1588 #        if !defined(__HAIKU__)
1589 #         if !defined(__QNX__)
1590 #          if !defined(__FILC__)
1591 static int
1592 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1593 {
1594   (void)size;
1595   (void)data;
1596 
1597   if (strlen(info->dlpi_name) >= 2) {
1598       if (!dl_iterate_phdr_callback_called)
1599           (void)printf ("\r\n Loaded shared objects: ");
1600 
1601       dl_iterate_phdr_callback_called++;
1602       (void)printf ("%s ", info->dlpi_name);
1603   }
1604 
1605   return 0;
1606 }
1607 #          endif
1608 #         endif
1609 #        endif
1610 #       endif
1611 #      endif
1612 #     endif
1613 #    endif
1614 #   endif
1615 #  endif
1616 # endif
1617 #endif
1618 
1619 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1620 # if defined(_UCRT)
1621 #  define MINGW_CRT "UCRT"
1622 # else
1623 #  define MINGW_CRT "MSVCRT"
1624 # endif
1625 #endif
1626 
1627 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1628 struct UCRTVersion
1629 {
1630   uint16_t ProductVersion[4];
1631 };
1632 
1633 int
1634 GetUCRTVersion (struct UCRTVersion *ucrtversion)
     /* [previous][next][first][last][top][bottom][index][help] */
1635 {
1636 # ifdef _DEBUG
1637   static const wchar_t *DllName = L"ucrtbased.dll";
1638 # else
1639   static const wchar_t *DllName = L"ucrtbase.dll";
1640 # endif
1641 
1642   HMODULE ucrt = GetModuleHandleW (DllName);
1643   if (!ucrt)
1644     return GetLastError ();
1645 
1646   wchar_t path[SIR_MAXPATH];
1647   if (!GetModuleFileNameW (ucrt, path, SIR_MAXPATH))
1648     return GetLastError ();
1649 
1650   DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1651   if (!versionInfoSize)
1652     return GetLastError ();
1653 
1654   uint8_t versionInfo[versionInfoSize];
1655 
1656   if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1657     return GetLastError ();
1658 
1659   VS_FIXEDFILEINFO *fixedFileInfo;
1660   UINT fixedFileInfoSize;
1661   if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1662     return GetLastError ();
1663 
1664   memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1665 
1666   return 0;
1667 }
1668 #endif
1669 
1670 /* libsir support */
1671 
1672 #if !defined(PERF_STRIP)
1673 static int dps8_sir_report_error(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1674 {
1675   char message[SIR_MAXERROR] = {0};
1676   (void)sir_geterror(message);
1677   (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1678   return EXIT_FAILURE;
1679 }
1680 
1681 /* Main command loop */
1682 
1683 int main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
1684 {
1685 char *cptr, *cptr2;
1686 char nbuf[PATH_MAX + 7];
1687 char cbuf[4*CBUFSIZE];
1688 char **targv = NULL;
1689 int32 i, sw;
1690 t_bool lookswitch;
1691 t_stat stat;
1692 
1693 /* Check for improper setuid root */
1694 # if !defined(__sun) && !defined(__illumos__) && !defined(_WIN32)
1695 uid_t real_uid = getuid();
1696 uid_t eff_uid = geteuid();
1697 if (0 == eff_uid && 0 != real_uid) {
1698   (void)fprintf(stderr, "FATAL: Running with improper setuid root privileges!\r\n");
1699   exit(EXIT_FAILURE);
1700 }
1701 # endif
1702 
1703 sunos_obtain_realtime_privileges(); /* Keep as early as possible */
1704 
1705 sim_free_memory = sim_memory_available(); /* stash free memory */
1706 
1707 sim_appfilename = _sir_getappfilename(); /* stash app filename */
1708 if (sim_appfilename == NULL) {
1709   sim_appfilename = "dps8";
1710 }
1711 
1712 /* libsir init */
1713 
1714 sirinit si;
1715 if (!sir_makeinit(&si))
1716     return dps8_sir_report_error();
1717 
1718 /* Levels for stdout: send debug, information, warning, and notice there. */
1719 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1720 
1721 /* Options for stdout: don't show the name, level, timestamp, hostname, or PID. */
1722 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1723 
1724 /* Levels for stderr: send error and above there. */
1725 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1726 
1727 /* Options for stderr: don't show the hostname. */
1728 si.d_stderr.opts = SIRO_NOHOST;
1729 
1730 /* Levels for the system logger: don't send any output there. */
1731 si.d_syslog.levels = SIRL_NONE;
1732 
1733 /* Options for the system logger: use the default value. */
1734 si.d_syslog.opts = SIRO_DEFAULT;
1735 
1736 /* Configure a name to associate with our output. */
1737 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1738 
1739 /* Initialize libsir. */
1740 if (!sir_init(&si))
1741     return dps8_sir_report_error();
1742 
1743 # if defined(_AIX)
1744 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1745   if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1746     (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1747                   __func__, __FILE__, __LINE__);
1748     abort();
1749   }
1750 
1751   if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1752     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1753   }
1754 
1755   if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1756     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1757   }
1758 
1759   if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1760     (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1761   }
1762 
1763 #  if !defined(__PASE__)
1764   if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1765     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1766   }
1767 #  else
1768 #   if !defined(TESTING)
1769   if (setenv("PASE_SYSCALL_NOSIGILL", "ALL", 1)) {
1770     (void)fprintf(stderr, "\rWARN: Failed to set \"PASE_SYSCALL_NOSIGILL=ALL\".\r\n");
1771   }
1772 #   endif
1773 #  endif
1774 
1775   if (execvp(argv[0], argv) == -1) {
1776     (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1777                   __func__, __FILE__, __LINE__);
1778     abort();
1779   }
1780 }
1781 # endif
1782 
1783 # if defined(USE_BACKTRACE)
1784 #  if defined(BACKTRACE_SUPPORTED)
1785 #   if defined(_INC_BACKTRACE_FUNC)
1786 bt_pid = (long)_sir_getpid();
1787 (void)bt_pid;
1788 #   endif /* if defined(_INC_BACKTRACE_FUNC) */
1789 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1790 # endif /* if defined(USE_BACKTRACE) */
1791 
1792 # if defined(__MINGW32__)
1793 #  undef IS_WINDOWS
1794 #  define IS_WINDOWS 1
1795 #  if !defined(NEED_CONSOLE_SETUP)
1796 #   define NEED_CONSOLE_SETUP
1797 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1798 # endif /* if defined(__MINGW32__)*/
1799 
1800 # if defined(CROSS_MINGW32)
1801 #  undef IS_WINDOWS
1802 #  define IS_WINDOWS 1
1803 #  if !defined(NEED_CONSOLE_SETUP)
1804 #   define NEED_CONSOLE_SETUP
1805 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1806 # endif /* if defined(CROSS_MINGW32) */
1807 
1808 # if defined(__MINGW64__)
1809 #  undef IS_WINDOWS
1810 #  define IS_WINDOWS 1
1811 #  if !defined(NEED_CONSOLE_SETUP)
1812 #   define NEED_CONSOLE_SETUP
1813 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1814 # endif /* if defined(__MINGW64__) */
1815 
1816 # if defined(CROSS_MINGW64)
1817 #  undef IS_WINDOWS
1818 #  define IS_WINDOWS 1
1819 #  if !defined(NEED_CONSOLE_SETUP)
1820 #   define NEED_CONSOLE_SETUP
1821 #  endif /* if !defined(NEED_CONSOLE_SETUP */
1822 # endif /* if defined(CROSS_MINGW64) */
1823 
1824 # if defined(__CYGWIN__)
1825 #  if defined(IS_WINDOWS)
1826 #   undef IS_WINDOWS
1827 #  endif /* if defined(IS_WINDOWS) */
1828 # endif /* if defined(__CYGWIN__) */
1829 
1830 # if defined(USE_DUMA)
1831 #  if defined(DUMA_EXPLICIT_INIT)
1832 duma_init();
1833 (void)fflush(stderr);
1834 #  endif /* if defined(DUMA_EXPLICIT_INIT) */
1835 #  if defined(DUMA_MIN_ALIGNMENT)
1836 #   if DUMA_MIN_ALIGNMENT > 0
1837 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1838 #   endif /* if DUMA_MIN_ALIGNMENT > 0 */
1839 #  endif /* if defined(DUMA_MIN_ALIGNMENT) */
1840 DUMA_SET_FILL(0x2E);
1841 (void)fflush(stderr);
1842 (void)atexit(CleanDUMA);
1843 # endif /* if defined(USE_DUMA) */
1844 
1845 # if defined(USE_BACKTRACE)
1846 #  if defined(BACKTRACE_SUPPORTED)
1847 #   include "backtrace_main.c"
1848 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1849 # endif /* if defined(USE_BACKTRACE) */
1850 
1851 # if !defined(NO_LOCALE)
1852 (void)setlocale(LC_ALL, "");
1853 # endif
1854 
1855 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1856 #  if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1857 #   define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1858 #  endif /* if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) */
1859 # endif /* if defined(NEED_CONSOLE_SETUP) && defined(_WIN32) */
1860 
1861 # if defined(NEED_CONSOLE_SETUP)
1862 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1863 if (handle != INVALID_HANDLE_VALUE)
1864   {
1865     DWORD mode = 0;
1866     if (GetConsoleMode(handle, &mode))
1867       {
1868         mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1869         SetConsoleMode(handle, mode);
1870       }
1871   }
1872 puts ("\e[0m");
1873 # endif /* if defined(NEED_CONSOLE_SETUP) */
1874 
1875 # if defined(__HAIKU__)
1876 (void)disable_debugger(1);
1877 # endif /* if defined(__HAIKU__) */
1878 
1879 running_perf_test = false;
1880 
1881 /* Set a friendly name for the current thread. */
1882 char thread_name[SIR_MAXPID] = {0};
1883 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1884 (void)_sir_setthreadname(thread_name);
1885 
1886 /* sanity checks */
1887 
1888 # if defined(__clang_analyzer__)
1889 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\r\n");
1890 return 1;
1891 # endif /* if defined(__clang_analyzer__) */
1892 
1893 if (argc == 0) {
1894     (void)fprintf (stderr, "Error: main() called directly!\r\n");
1895     return 1;
1896 }
1897 
1898 /* Enable unlimited core dumps */
1899 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1900 allowCores();
1901 # endif
1902 
1903 int testEndian = decContextTestEndian();
1904 if (testEndian != 0) {
1905   if (testEndian == 1) {
1906     (void)fprintf (stderr,
1907                    "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\r\n");
1908     return 1;
1909   }
1910   if (testEndian == -1) {
1911     (void)fprintf (stderr,
1912                    "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\r\n");
1913     return 1;
1914   }
1915   (void)fprintf (stderr,
1916                  "Error: Unable to determine system byte order; aborting.\r\n");
1917   return 1;
1918 }
1919 # if defined(NEED_128)
1920 test_math128();
1921 # endif /* if defined(NEED_128) */
1922 
1923 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1924 
1925 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1926 // Only use uv_available_parallelism on Linux and only on libuv 1.44.0 or higher.
1927 // This will return a value less than the actual number of CPUs if, for example,
1928 // the CPU affinity mask has been pinned to specific CPUs.  On all other systems,
1929 // prefer the _sir_nprocs routine to query the number of actual CPUs available.
1930 nprocs = (unsigned int)uv_available_parallelism();
1931 # else
1932 nprocs = (unsigned int)_sir_nprocs();
1933 # endif
1934 ncores = (unsigned int)get_core_count();
1935 
1936 /* Make sure that argv has at least 10 elements and that it ends in a NULL pointer */
1937 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1938 if (!targv)
1939   {
1940     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1941                    __func__, __FILE__, __LINE__);
1942 # if defined(USE_BACKTRACE)
1943 #  if defined(SIGUSR2)
1944     (void)raise(SIGUSR2);
1945     /*NOTREACHED*/ /* unreachable */
1946 #  endif /* if defined(SIGUSR2) */
1947 # endif /* if defined(USE_BACKTRACE) */
1948     abort();
1949   }
1950 for (i=0; i<argc; i++)
1951     targv[i] = argv[i];
1952 argv = targv;
1953 
1954 /* setup defaults */
1955 set_prompt (0, "sim>");                                 /* start with set standard prompt */
1956 *cbuf = 0;                                              /* init arg buffer */
1957 sim_switches = 0;                                       /* init switches */
1958 lookswitch = TRUE;
1959 stdnul = fopen(NULL_DEVICE,"wb");
1960 
1961 /* process arguments */
1962 for (i = 1; i < argc; i++) {                            /* loop thru args */
1963     if (argv[i] == NULL)                                /* paranoia */
1964         continue;
1965 
1966 # if defined(THREADZ) || defined(LOCKLESS)
1967 /* performance test */
1968     int perftestflag  = strcmp(argv[i], "--perftest");
1969     if (perftestflag == 0) {
1970       char * testName = NULL;
1971       if (i + 1 < argc)
1972         testName = argv[i + 1];
1973       perfTest (testName);
1974       return 0;
1975     }
1976 # endif
1977 
1978 /* requested only version? */
1979     int onlyvers  = strcmp(argv[i], "--version");
1980     if (onlyvers == 0) {
1981 # if defined(VER_H_GIT_VERSION)
1982 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1983 #   if VER_H_GIT_PATCH_INT < 1
1984         (void)fprintf (stdout, "%s simulator %s\r\n",
1985                        sim_name, VER_H_GIT_VERSION);
1986 #   else
1987         (void)fprintf (stdout, "%s simulator %s+%s\r\n",
1988                        sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1989 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
1990 #  else
1991         (void)fprintf (stdout, "%s simulator %s\r\n",
1992                        sim_name, VER_H_GIT_VERSION);
1993 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
1994 # else
1995         (void)fprintf (stdout, "%s simulator\r\n", sim_name);
1996 # endif /* if defined(VER_H_GIT_VERSION) */
1997         FREE (targv);
1998         return 0;
1999     }
2000 
2001 /* requested short or long help? */
2002     int longhelp  = strcmp(argv[i], "--help");
2003     int shorthelp = strcmp(argv[i], "-h");
2004     if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
2005     if (longhelp == 0 || shorthelp == 0) {
2006 # if defined(VER_H_GIT_VERSION)
2007 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
2008 #   if VER_H_GIT_PATCH_INT < 1
2009         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2010 #   else
2011         (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
2012 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
2013 #  else
2014         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2015 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
2016 # else
2017         (void)fprintf (stdout, "%s simulator", sim_name);
2018 # endif /* if defined(VER_H_GIT_VERSION) */
2019         (void)fprintf (stdout, "\r\n");
2020         (void)fprintf (stdout, "\r\n USAGE: %s [ [ SWITCH ] ... ] [ SCRIPT ]", argv[0]);
2021         (void)fprintf (stdout, "\r\n");
2022         (void)fprintf (stdout, "\r\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
2023         (void)fprintf (stdout, "\r\n");
2024         (void)fprintf (stdout, "\r\n Switches:");
2025         (void)fprintf (stdout, "\r\n  -e, -E            Aborts script processing immediately upon any error");
2026         (void)fprintf (stdout, "\r\n  -h, -H, --help    Prints only this informational help text and exits");
2027         (void)fprintf (stdout, "\r\n  -k, -K            Disables all support for exclusive file locking");
2028         (void)fprintf (stdout, "\r\n  -l, -L            Reports but ignores all exclusive file locking errors");
2029         (void)fprintf (stdout, "\r\n  -o, -O            Makes scripting ON conditions and actions inheritable");
2030 # if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2031         (void)fprintf (stdout, "\r\n  -p, -P            Enables real-time scheduling (may require privileges)");
2032 # endif
2033         (void)fprintf (stdout, "\r\n  -q, -Q            Disables printing of non-fatal informational messages");
2034         (void)fprintf (stdout, "\r\n  -r, -R            Enables an unlinked ephemeral system state file");
2035         (void)fprintf (stdout, "\r\n  -s, -S            Enables a randomized persistent system state file");
2036         (void)fprintf (stdout, "\r\n  -t, -T            Disables fsync and creation/usage of system state file");
2037         (void)fprintf (stdout, "\r\n  -v, -V            Prints commands read from script file before execution");
2038         (void)fprintf (stdout, "\r\n  --version         Prints only the simulator identification text and exits");
2039         (void)fprintf (stdout, "\r\n");
2040 # if defined(USE_DUMA)
2041         nodist++;
2042 # endif /* if defined(USE_DUMA) */
2043 if (!nodist) {
2044         (void)fprintf (stdout, "\r\n This software is made available under the terms of the ICU License.");
2045         (void)fprintf (stdout, "\r\n For complete license details, see the LICENSE file included with the");
2046         (void)fprintf (stdout, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\r\n");
2047 }
2048 else
2049 {
2050         (void)fprintf (stdout, "\r\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2051 }
2052         (void)fprintf (stdout, "\r\n");
2053         FREE(argv); //-V726
2054         return 0;
2055     }
2056     /* invalid arguments? */
2057     if ((*argv[i] == '-') && lookswitch) {              /* switch? */
2058         if ((sw = get_switches (argv[i])) < 0) {
2059             (void)fprintf (stderr, "Invalid switch \"%s\".\r\nTry \"%s -h\" for help.\r\n", argv[i], argv[0]);
2060             FREE(argv); //-V726
2061             return 1;
2062             }
2063         sim_switches = sim_switches | sw;
2064         }
2065     /* parse arguments */
2066     else {
2067         if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2068             (void)fprintf (stderr, "Argument string too long\r\n");
2069             FREE(argv); //-V726
2070             return 1;
2071             }
2072         if (*cbuf)                                  /* concat args */
2073             strcat (cbuf, " ");
2074         (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s", //-V755
2075                       strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : ""); //-V755
2076         lookswitch = FALSE;                         /* no more switches */
2077         }
2078     }                                               /* end for */
2079 sim_nolock = sim_switches & SWMASK ('K');           /* -k means skip locking     */
2080 sim_iglock = sim_switches & SWMASK ('L');           /* -l means ignore locking   */
2081 sim_randompst = sim_switches & SWMASK ('S');        /* -s means persist random   */
2082 sim_quiet = sim_switches & SWMASK ('Q');            /* -q means quiet            */
2083 sim_randstate = sim_switches & SWMASK ('R');        /* -r means random sys_state */
2084 if (sim_randompst) sim_randstate = 1;               /*    and is implied with -s */
2085 sim_nostate = sim_switches & SWMASK ('T');          /* -t means no sys_state     */
2086 if (sim_nostate)                                    /*    and disables -s and -r */
2087   {
2088     sim_randompst = 0;
2089     sim_randstate = 0;
2090   }
2091 sim_on_inherit = sim_switches & SWMASK ('O');       /* -o means inherit on state */
2092 
2093 # if !defined(__MVS__) && !defined(__MINGW32__) && !defined(__MINGW64__) && \
2094      !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2095 sim_realtime = sim_switches & SWMASK ('P');         /* -p means real-time priority */
2096 # endif
2097 
2098 sim_init_sock ();                                   /* init socket capabilities */
2099 if (sim_dflt_dev == NULL)                           /* if no default */
2100     sim_dflt_dev = sim_devices[0];
2101 if (sim_vm_init != NULL)                            /* call once only */
2102     (*sim_vm_init)();
2103 sim_finit ();                                       /* init fio package */
2104 for (i = 0; cmd_table[i].name; i++) {
2105     size_t alias_len = strlen (cmd_table[i].name);
2106     char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2107     if (!cmd_name)
2108       {
2109         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2110                        __func__, __FILE__, __LINE__);
2111 # if defined(USE_BACKTRACE)
2112 #  if defined(SIGUSR2)
2113         (void)raise(SIGUSR2);
2114         /*NOTREACHED*/ /* unreachable */
2115 #  endif /* if defined(SIGUSR2) */
2116 # endif /* if defined(USE_BACKTRACE) */
2117         abort();
2118       }
2119 
2120     strcpy (cmd_name, cmd_table[i].name);
2121     while (alias_len > 1) {
2122         cmd_name[alias_len] = '\0';                 /* Possible short form command name */
2123         --alias_len;
2124         if (getenv (cmd_name))                      /* Externally defined command alias? */
2125             unsetenv (cmd_name);                    /* Remove it to protect against possibly malicious aliases */
2126         }
2127     FREE (cmd_name);
2128     }
2129 stop_cpu = 0;
2130 sim_interval = 0;
2131 sim_time = sim_rtime = 0;
2132 noqueue_time = 0;
2133 sim_clock_queue = QUEUE_LIST_END;
2134 sim_is_running = 0;
2135 sim_log = NULL;
2136 if (sim_emax <= 0)
2137     sim_emax = 1;
2138 
2139 /* stash our pthread_id */
2140 main_thread_id = pthread_self();
2141 
2142 /* stash current (default) thread scheduler and priority */
2143 save_thread_sched(pthread_self());
2144 
2145 /* real-time priority (always call before sim_timer_init) */
2146 if (sim_realtime) {
2147     if (nprocs < 2) {
2148         sir_emerg("FATAL: Real-time requires >1 CPU but only %u detected!", nprocs);
2149         exit(EXIT_FAILURE);
2150     } else {
2151         watchdog_startup();
2152     }
2153 }
2154 
2155 /* do setup for realtime or normal operation */
2156 if (realtime_ok) {
2157     set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2158     check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2159 } else {
2160 # if !defined(__QNX__)
2161     (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2162 # endif
2163 }
2164 
2165 sim_timer_init ();
2166 
2167 if ((stat = sim_ttinit ()) != SCPE_OK) {
2168     (void)fprintf (stderr, "Fatal terminal initialization error\r\n%s\r\n",
2169                    sim_error_text (stat));
2170     FREE(argv); //-V726
2171     return 1;
2172     }
2173 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2174     (void)fprintf (stderr, "Unable to allocate examine buffer\r\n");
2175     FREE(argv); //-V726
2176     return 1;
2177     };
2178 if ((stat = reset_all_p (0)) != SCPE_OK) {
2179     (void)fprintf (stderr, "Fatal simulator initialization error\r\n%s\r\n",
2180                    sim_error_text (stat));
2181     FREE(argv); //-V726
2182     return 1;
2183     }
2184 if ((stat = sim_brk_init ()) != SCPE_OK) {
2185     (void)fprintf (stderr, "Fatal breakpoint table initialization error\r\n%s\r\n",
2186                    sim_error_text (stat));
2187     FREE(argv); //-V726
2188     return 1;
2189     }
2190 if (!sim_quiet) {
2191     (void)printf ("\r\n");
2192     show_version (stdout, NULL, NULL, 0, NULL);
2193     }
2194 
2195 cptr = getenv("HOME");
2196 if (cptr == NULL) {
2197     cptr = getenv("HOMEPATH");
2198     cptr2 = getenv("HOMEDRIVE");
2199     }
2200 else
2201     cptr2 = NULL;
2202 (void)cptr2;
2203 if ( (*cbuf) && (strcmp(cbuf, "")) )                    /* cmd file arg? */
2204     stat = do_cmd (0, cbuf);                            /* proc cmd file */
2205 else if (*argv[0]) {                                    /* sim name arg? */
2206     char *np;                                           /* "path.ini" */
2207     nbuf[0] = '"';                                      /* starting " */
2208     stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;         /* proc default cmd file */
2209     if (stat == SCPE_OPENERR) {                         /* didn't exist/can't open? */
2210         np = strrchr (nbuf, '/');                       /* strip path and try again in cwd */
2211         if (np == NULL)
2212             np = strrchr (nbuf, '\\');                  /* windows path separator */
2213         if (np != NULL) {
2214             *np = '"';
2215             stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;   /* proc default cmd file */
2216             }
2217         }
2218     }
2219 
2220 argv = uv_setup_args(argc, argv);
2221 
2222 /* show if hints are not disabled and empty cbuf and not quiet mode */
2223 if (getenv("DPS8M_NO_HINTS") == NULL)
2224   if (!sim_quiet && 0 == strcmp(cbuf, ""))
2225     (void)show_hints(0, 0, 0, 1, 0);
2226 
2227 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2228 
2229 if (sim_vm_exit != NULL)                                /* call once only */
2230     (*sim_vm_exit)();
2231 
2232 detach_all (0, TRUE);                                   /* close files */
2233 sim_set_deboff (0, NULL);                               /* close debug */
2234 sim_set_logoff (0, NULL);                               /* close log */
2235 sim_set_notelnet (0, NULL);                             /* close Telnet */
2236 sim_ttclose ();                                         /* close console */
2237 sim_cleanup_sock ();                                    /* cleanup sockets */
2238 fclose (stdnul);                                        /* close bit bucket file handle */
2239 FREE (targv);                                           /* release any argv copy that was made */
2240 FREE (sim_prompt);
2241 FREE (sim_eval);
2242 FREE (sim_internal_devices);
2243 FREE (sim_brk_tab);
2244 FREE (sim_staba.comp);
2245 FREE (sim_staba.mask);
2246 FREE (sim_stabr.comp);
2247 FREE (sim_stabr.mask);
2248 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2249 }
2250 #endif
2251 
2252 t_stat process_stdin_commands (t_stat stat, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
2253 {
2254 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2255 CONST char *cptr;
2256 t_stat stat_nomessage;
2257 CTAB *cmdp = NULL;
2258 
2259 stat = SCPE_BARE_STATUS(stat);                          /* remove possible flag */
2260 while (stat != SCPE_EXIT) {                             /* in case exit */
2261     if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))   /* pending action? */
2262         (void)printf ("%s%s\r\n", sim_prompt, cptr);    /* echo */
2263     else if (sim_vm_read != NULL) {                     /* sim routine? */
2264         (void)printf ("%s", sim_prompt);                /* prompt */
2265         cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2266         }
2267     else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prompt*/
2268     if (cptr == NULL) {                                 /* EOF? */
2269         if (sim_ttisatty()) continue;                   /* ignore tty EOF */
2270         else break;                                     /* otherwise exit */
2271         }
2272     if (*cptr == 0)                                     /* ignore blank */
2273         continue;
2274     sim_sub_args (cbuf, sizeof(cbuf), argv);
2275     if (sim_log)                                        /* log cmd */
2276         (void)fprintf (sim_log, "%s%s\r\n", sim_prompt, cptr);
2277     if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2278         (void)fprintf (sim_deb, "%s%s\r\n", sim_prompt, cptr);
2279     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
2280     sim_switches = 0;                                   /* init switches */
2281     if ((cmdp = find_cmd (gbuf)))                       /* lookup command */
2282         stat = cmdp->action (cmdp->arg, cptr);          /* if found, exec */
2283     else
2284         stat = SCPE_UNK;
2285     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
2286     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
2287     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
2288     sim_last_cmd_stat = stat;                           /* save command error status */
2289     if (!stat_nomessage) {                              /* displaying message status? */
2290         if (cmdp && (cmdp->message))                    /* special message handler? */
2291             cmdp->message (NULL, stat);                 /* let it deal with display */
2292         else
2293             if (stat >= SCPE_BASE)                      /* error? */
2294                 sim_printf ("%s\r\n", sim_error_text (stat));
2295         }
2296     if (sim_vm_post != NULL)
2297         (*sim_vm_post) (TRUE);
2298     }                                                   /* end while */
2299 return stat;
2300 }
2301 
2302 /* Set prompt routine */
2303 
2304 t_stat set_prompt (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2305 {
2306 char gbuf[CBUFSIZE], *gptr;
2307 
2308 if ((NULL == cptr) || (*cptr == '\0'))
2309     return SCPE_ARG;
2310 
2311 cptr = get_glyph_nc (cptr, gbuf, '"');                  /* get quote delimited token */
2312 if (gbuf[0] == '\0') {                                  /* Token started with quote */
2313     gbuf[sizeof (gbuf)-1] = '\0';
2314     strncpy (gbuf, cptr, sizeof (gbuf)-1);
2315     gptr = strchr (gbuf, '"');
2316     if (NULL != gptr)
2317         *gptr = '\0';
2318     }
2319 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);   /* nul terminator and trailing blank */
2320 if (!sim_prompt)
2321   {
2322     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2323                    __func__, __FILE__, __LINE__);
2324 #if defined(USE_BACKTRACE)
2325 # if defined(SIGUSR2)
2326     (void)raise(SIGUSR2);
2327     /*NOTREACHED*/ /* unreachable */
2328 # endif /* if defined(SIGUSR2) */
2329 #endif /* if defined(USE_BACKTRACE) */
2330     abort();
2331   }
2332 (void)sprintf (sim_prompt, "%s ", gbuf);
2333 return SCPE_OK;
2334 }
2335 
2336 /* Find command routine */
2337 
2338 CTAB *find_cmd (const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
2339 {
2340 CTAB *cmdp = NULL;
2341 
2342 if (sim_vm_cmd)                                         /* try ext commands */
2343     cmdp = find_ctab (sim_vm_cmd, gbuf);
2344 if (cmdp == NULL)                                       /* try regular cmds */
2345     cmdp = find_ctab (cmd_table, gbuf);
2346 return cmdp;
2347 }
2348 
2349 /* Exit command */
2350 
2351 t_stat exit_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2352 {
2353 return SCPE_EXIT;
2354 }
2355 
2356 /* Help command */
2357 
2358 /* Used when sorting a list of command names */
2359 static int _cmd_name_compare (const void *pa, const void *pb)
     /* [previous][next][first][last][top][bottom][index][help] */
2360 {
2361 CTAB * const *a = (CTAB * const *)pa;
2362 CTAB * const *b = (CTAB * const *)pb;
2363 
2364 return strcmp((*a)->name, (*b)->name);
2365 }
2366 
2367 void fprint_help (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
2368 {
2369 CTAB *cmdp;
2370 CTAB **hlp_cmdp = NULL;
2371 size_t cmd_cnt = 0;
2372 size_t cmd_size = 0;
2373 size_t max_cmdname_size = 0;
2374 size_t i, line_offset;
2375 
2376 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2377     if (cmdp->help) {
2378         if (cmd_cnt >= cmd_size) {
2379             cmd_size += 20;
2380             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2381             if (!hlp_cmdp)
2382               {
2383                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2384                                __func__, __FILE__, __LINE__);
2385 #if defined(USE_BACKTRACE)
2386 # if defined(SIGUSR2)
2387                 (void)raise(SIGUSR2);
2388                 /*NOTREACHED*/ /* unreachable */
2389 # endif /* if defined(SIGUSR2) */
2390 #endif /* if defined(USE_BACKTRACE) */
2391                 abort();
2392               }
2393             }
2394         hlp_cmdp[cmd_cnt] = cmdp;
2395         ++cmd_cnt;
2396         if (strlen(cmdp->name) > max_cmdname_size)
2397             max_cmdname_size = strlen(cmdp->name);
2398         }
2399     }
2400 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2401     if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2402         if (cmd_cnt >= cmd_size) {
2403             cmd_size += 20;
2404             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2405             if (!hlp_cmdp)
2406               {
2407                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2408                                __func__, __FILE__, __LINE__);
2409 #if defined(USE_BACKTRACE)
2410 # if defined(SIGUSR2)
2411                 (void)raise(SIGUSR2);
2412                 /*NOTREACHED*/ /* unreachable */
2413 # endif /* if defined(SIGUSR2) */
2414 #endif /* if defined(USE_BACKTRACE) */
2415                 abort();
2416               }
2417             }
2418         hlp_cmdp[cmd_cnt] = cmdp;
2419         ++cmd_cnt;
2420         if (strlen (cmdp->name) > max_cmdname_size)
2421             max_cmdname_size = strlen(cmdp->name);
2422         }
2423     }
2424 (void)fprintf (st, "HELP is available for the following commands:\r\n\r\n    ");
2425 if (hlp_cmdp)
2426   qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2427 line_offset = 4;
2428 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2429     fputs (hlp_cmdp[i]->name, st);
2430     line_offset += 5 + max_cmdname_size;
2431     if (line_offset + max_cmdname_size > 79) {
2432         line_offset = 4;
2433         (void)fprintf (st, "\r\n    ");
2434         }
2435     else
2436         (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2437     }
2438 FREE (hlp_cmdp);
2439 (void)fprintf (st, "\r\n");
2440 return;
2441 }
2442 
2443 static void fprint_header (FILE *st, t_bool *pdone, char *context)
     /* [previous][next][first][last][top][bottom][index][help] */
2444 {
2445 if (!*pdone)
2446     (void)fprintf (st, "%s", context);
2447 *pdone = TRUE;
2448 }
2449 
2450 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2451 {
2452 REG *rptr, *trptr;
2453 t_bool found = FALSE;
2454 t_bool all_unique = TRUE;
2455 size_t max_namelen = 0;
2456 DEVICE *tdptr;
2457 CONST char *tptr;
2458 char *namebuf;
2459 char rangebuf[32];
2460 
2461 if (dptr->registers)
2462     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2463         if (rptr->flags & REG_HIDDEN)
2464             continue;
2465         if (rptr->depth > 1)
2466             (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2467         else
2468             strcpy (rangebuf, "");
2469         if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2470             max_namelen = strlen(rptr->name) + strlen (rangebuf);
2471         found = TRUE;
2472         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2473         if ((trptr == NULL) || (tdptr != dptr))
2474             all_unique = FALSE;
2475         }
2476 if (!found) {
2477     if (!silent)
2478         (void)fprintf (st, "No register HELP available for the %s device\r\n",
2479                        dptr->name);
2480     }
2481 else {
2482     namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2483     if (!namebuf)
2484       {
2485         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2486                        __func__, __FILE__, __LINE__);
2487 #if defined(USE_BACKTRACE)
2488 # if defined(SIGUSR2)
2489         (void)raise(SIGUSR2);
2490         /*NOTREACHED*/ /* unreachable */
2491 # endif /* if defined(SIGUSR2) */
2492 #endif /* if defined(USE_BACKTRACE) */
2493         abort();
2494       }
2495     (void)fprintf (st, "\r\nThe %s device implements these registers:\r\n\r\n",
2496                    dptr->name);
2497     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2498         if (rptr->flags & REG_HIDDEN)
2499             continue;
2500         if (rptr->depth <= 1)
2501             (void)sprintf (namebuf, "%*s",
2502                            -((int)max_namelen),
2503                            rptr->name);
2504         else {
2505             (void)sprintf (rangebuf, "[%d:%d]",
2506                            0,
2507                            rptr->depth-1);
2508             (void)sprintf (namebuf, "%s%*s",
2509                            rptr->name,
2510                            (int)(strlen(rptr->name))-((int)max_namelen),
2511                            rangebuf);
2512             }
2513         if (all_unique) {
2514             (void)fprintf (st, "  %s %4d  %s\r\n",
2515                            namebuf,
2516                            rptr->width,
2517                            rptr->desc ? rptr->desc : "");
2518             continue;
2519             }
2520         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2521         if ((trptr == NULL) || (tdptr != dptr))
2522             (void)fprintf (st, "  %s %s %4d  %s\r\n",
2523                            dptr->name,
2524                            namebuf,
2525                            rptr->width,
2526                            rptr->desc ? rptr->desc : "");
2527         else
2528             (void)fprintf (st, "  %*s %s %4d  %s\r\n",
2529                            (int)strlen(dptr->name), "",
2530                            namebuf,
2531                            rptr->width,
2532                            rptr->desc ? rptr->desc : "");
2533         }
2534     FREE (namebuf);
2535     }
2536 }
2537 
2538 void fprint_reg_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2539 {
2540 fprint_reg_help_ex (st, dptr, TRUE);
2541 }
2542 
2543 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2544 {
2545 if (dptr->attach_help) {
2546     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2547     dptr->attach_help (st, dptr, NULL, 0, NULL);
2548     return;
2549     }
2550 if (DEV_TYPE(dptr) == DEV_DISK) {
2551     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2552     sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2553     return;
2554     }
2555 if (DEV_TYPE(dptr) == DEV_TAPE) {
2556     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2557     sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2558     return;
2559     }
2560 if (!silent) {
2561     (void)fprintf (st, "No ATTACH help is available for the %s device\r\n", dptr->name);
2562     if (dptr->help)
2563         dptr->help (st, dptr, NULL, 0, NULL);
2564     }
2565 }
2566 
2567 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2568 {
2569 MTAB *mptr;
2570 DEBTAB *dep;
2571 t_bool found = FALSE;
2572 char buf[CBUFSIZE], header[CBUFSIZE];
2573 uint32 enabled_units = dptr->numunits;
2574 uint32 unit;
2575 
2576 (void)sprintf (header, "\r\n%s device SET commands:\r\n\r\n", dptr->name);
2577 for (unit=0; unit < dptr->numunits; unit++)
2578     if (dptr->units[unit].flags & UNIT_DIS)
2579         --enabled_units;
2580 if (dptr->modifiers) {
2581     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2582         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2583             continue;                                       /* skip unit only extended modifiers */
2584         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2585             continue;                                       /* skip unit only simple modifiers */
2586         if (mptr->mstring) {
2587             fprint_header (st, &found, header);
2588             (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2589                            mptr->mstring,
2590                            (strchr(mptr->mstring, '=')) \
2591                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2592                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2593                                ? "{=val}" : "")));
2594             if ((strlen (buf) < 30) || (NULL == mptr->help))
2595                 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2596             else
2597                 (void)fprintf (st, "%s\r\n%-30s\t%s\r\n", buf, "", mptr->help);
2598             }
2599         }
2600     }
2601 if (dptr->flags & DEV_DISABLE) {
2602     fprint_header (st, &found, header);
2603     (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2604     (void)fprintf (st,  "%-30s\tEnables device %s\r\n", buf, sim_dname (dptr));
2605     (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2606     (void)fprintf (st,  "%-30s\tDisables device %s\r\n", buf, sim_dname (dptr));
2607     }
2608 if (dptr->flags & DEV_DEBUG) {
2609     fprint_header (st, &found, header);
2610     (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2611     (void)fprintf (st,  "%-30s\tEnables debugging for device %s\r\n", buf, sim_dname (dptr));
2612     (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2613     (void)fprintf (st,  "%-30s\tDisables debugging for device %s\r\n", buf, sim_dname (dptr));
2614     if (dptr->debflags) {
2615         t_bool desc_available = FALSE;
2616         strcpy (buf, "");
2617         (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2618         for (dep = dptr->debflags; dep->name != NULL; dep++) {
2619             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2620             desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2621             }
2622         (void)fprintf (st, "\r\n");
2623         (void)fprintf (st,  "%-30s\tEnables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2624         (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2625         for (dep = dptr->debflags; dep->name != NULL; dep++)
2626             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2627         (void)fprintf (st, "\r\n");
2628         (void)fprintf (st,  "%-30s\tDisables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2629         if (desc_available) {
2630             (void)fprintf (st, "\r\n*%s device DEBUG settings:\r\n", sim_dname (dptr));
2631             for (dep = dptr->debflags; dep->name != NULL; dep++)
2632                 (void)fprintf (st, "%4s%-12s%s\r\n", "", dep->name, dep->desc ? dep->desc : "");
2633             }
2634         }
2635     }
2636 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2637     if (dptr->units->flags & UNIT_DISABLE) {
2638         fprint_header (st, &found, header);
2639         (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2640         (void)fprintf (st,  "%-30s\tEnables unit %sn\r\n", buf, sim_dname (dptr));
2641         (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2642         (void)fprintf (st,  "%-30s\tDisables unit %sn\r\n", buf, sim_dname (dptr));
2643         }
2644     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2645         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2646             continue;                                           /* skip device only modifiers */
2647         if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2648             continue;                                           /* skip show only modifiers */
2649         if (mptr->mstring) {
2650             fprint_header (st, &found, header);
2651             (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2652                            (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2653                            (strchr(mptr->mstring, '=')) \
2654                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2655                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2656                                ? "{=val}" : "")));
2657             (void)fprintf (st, "%-30s\t%s\r\n", buf,
2658                            (strchr(mptr->mstring, '=')) \
2659                                ? "" : (mptr->help ? mptr->help : ""));
2660             }
2661         }
2662     }
2663 if (!found && !silent)
2664     (void)fprintf (st, "No SET help is available for the %s device\r\n", dptr->name);
2665 }
2666 
2667 void fprint_set_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2668 {
2669   fprint_set_help_ex (st, dptr, TRUE);
2670 }
2671 
2672 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2673 {
2674 MTAB *mptr;
2675 t_bool found = FALSE;
2676 char buf[CBUFSIZE], header[CBUFSIZE];
2677 uint32 enabled_units = dptr->numunits;
2678 uint32 unit;
2679 
2680 (void)sprintf (header, "\r\n%s device SHOW commands:\r\n\r\n", dptr->name);
2681 for (unit=0; unit < dptr->numunits; unit++)
2682     if (dptr->units[unit].flags & UNIT_DIS)
2683         --enabled_units;
2684 if (dptr->modifiers) {
2685     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2686         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2687             continue;                                       /* skip unit only extended modifiers */
2688         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2689             continue;                                       /* skip unit only simple modifiers */
2690         if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2691             continue;
2692         fprint_header (st, &found, header);
2693         (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2694                        mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2695         (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2696         }
2697     }
2698 if (dptr->flags & DEV_DEBUG) {
2699     fprint_header (st, &found, header);
2700     (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2701     (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\r\n", buf, sim_dname (dptr));
2702     }
2703 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2704     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2705         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2706             continue;                                           /* skip device only modifiers */
2707         if ((!mptr->disp) || (!mptr->pstring))
2708             continue;
2709         fprint_header (st, &found, header);
2710         (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2711                        (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2712                        MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2713         (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2714         }
2715     }
2716 if (!found && !silent)
2717     (void)fprintf (st, "No SHOW help is available for the %s device\r\n", dptr->name);
2718 }
2719 
2720 void fprint_show_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2721     {
2722     fprint_show_help_ex (st, dptr, TRUE);
2723     }
2724 
2725 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2726 {
2727 BRKTYPTAB *brkt = dptr->brk_types;
2728 char gbuf[CBUFSIZE];
2729 
2730 if (sim_brk_types == 0) {
2731     if ((dptr != sim_dflt_dev) && (!silent)) {
2732         (void)fprintf (st, "Breakpoints are not supported in the %s simulator\r\n", sim_name);
2733         if (dptr->help)
2734             dptr->help (st, dptr, NULL, 0, NULL);
2735         }
2736     return;
2737     }
2738 if (brkt == NULL) {
2739     int i;
2740 
2741     if (dptr == sim_dflt_dev) {
2742         if (sim_brk_types & ~sim_brk_dflt) {
2743             (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2744             for (i=0; i<26; i++) {
2745                 if (sim_brk_types & (1<<i))
2746                     (void)fprintf (st, "  -%c\r\n", 'A'+i);
2747                 }
2748             }
2749         (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2750         }
2751     return;
2752     }
2753 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2754 while (brkt->btyp) {
2755     (void)fprintf (st, "  %s     %s\r\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2756     ++brkt;
2757     }
2758 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2759 }
2760 
2761 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2762 {
2763 char gbuf[CBUFSIZE];
2764 CTAB *cmdp;
2765 
2766 if (*cptr) {
2767     (void)get_glyph (cptr, gbuf, 0);
2768     if ((cmdp = find_cmd (gbuf))) {
2769         if (cmdp->action == &exdep_cmd) {
2770             if (dptr->help) /* Shouldn't this pass cptr so the device knows which command invoked? */
2771                 return dptr->help (st, dptr, uptr, flag, cptr);
2772             else
2773                 (void)fprintf (st, "No HELP available for the %s %s command\r\n", cmdp->name, sim_dname(dptr));
2774             return SCPE_OK;
2775             }
2776         if (cmdp->action == &set_cmd) {
2777             fprint_set_help_ex (st, dptr, FALSE);
2778             return SCPE_OK;
2779             }
2780         if (cmdp->action == &show_cmd) {
2781             fprint_show_help_ex (st, dptr, FALSE);
2782             return SCPE_OK;
2783             }
2784         if (cmdp->action == &attach_cmd) {
2785             fprint_attach_help_ex (st, dptr, FALSE);
2786             return SCPE_OK;
2787             }
2788         if (cmdp->action == &brk_cmd) {
2789             fprint_brk_help_ex (st, dptr, FALSE);
2790             return SCPE_OK;
2791             }
2792         if (dptr->help)
2793             return dptr->help (st, dptr, uptr, flag, cptr);
2794         (void)fprintf (st, "No %s HELP is available for the %s device\r\n", cmdp->name, dptr->name);
2795         return SCPE_OK;
2796         }
2797     if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2798         fprint_reg_help_ex (st, dptr, FALSE);
2799         return SCPE_OK;
2800         }
2801     if (dptr->help)
2802         return dptr->help (st, dptr, uptr, flag, cptr);
2803     (void)fprintf (st, "No %s HELP is available for the %s device\r\n", gbuf, dptr->name);
2804     return SCPE_OK;
2805     }
2806 if (dptr->help) {
2807     return dptr->help (st, dptr, uptr, flag, cptr);
2808     }
2809 if (dptr->description)
2810     (void)fprintf (st, "%s %s HELP\r\n", dptr->description (dptr), dptr->name);
2811 else
2812     (void)fprintf (st, "%s HELP\r\n", dptr->name);
2813 fprint_set_help_ex    (st, dptr, TRUE);
2814 fprint_show_help_ex   (st, dptr, TRUE);
2815 fprint_attach_help_ex (st, dptr, TRUE);
2816 fprint_reg_help_ex    (st, dptr, TRUE);
2817 fprint_brk_help_ex    (st, dptr, TRUE);
2818 return SCPE_OK;
2819 }
2820 
2821 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
     /* [previous][next][first][last][top][bottom][index][help] */
2822 {
2823 switch (help[0]) {
2824     case '*':
2825         scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2826         if (sim_log)
2827             scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2828         break;
2829     default:
2830         fputs (help, stdout);
2831         if (sim_log)
2832             fputs (help, sim_log);
2833         break;
2834     }
2835 return SCPE_OK;
2836 }
2837 
2838 t_stat help_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2839 {
2840 char gbuf[CBUFSIZE];
2841 CTAB *cmdp;
2842 
2843 GET_SWITCHES (cptr);
2844 if (sim_switches & SWMASK ('F'))
2845     flag = flag | SCP_HELP_FLAT;
2846 if (*cptr) {
2847     cptr = get_glyph (cptr, gbuf, 0);
2848     if ((cmdp = find_cmd (gbuf))) {
2849         if (*cptr) {
2850             if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2851                 DEVICE *dptr;
2852                 UNIT *uptr;
2853                 t_stat r;
2854                 cptr = get_glyph (cptr, gbuf, 0);
2855                 dptr = find_unit (gbuf, &uptr);
2856                 if (dptr == NULL)
2857                     dptr = find_dev (gbuf);
2858                 if (dptr != NULL) {
2859                     r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2860                     if (sim_log)
2861                         help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2862                     return r;
2863                     }
2864                 if (cmdp->action == &set_cmd) { /* HELP SET xxx (not device or unit) */
2865                     /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
2866                     if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2867                          (cmdp->help))
2868                         return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2869                     }
2870                 else { /* HELP SHOW xxx (not device or unit) */
2871                     SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2872                     if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2873                         return SCPE_ARG;
2874                     return help_cmd_output (flag, shptr->help, NULL);
2875                     }
2876                 return SCPE_ARG;
2877                 }
2878             else
2879                 return SCPE_2MARG;
2880             }
2881         if (cmdp->help) {
2882             if (strcmp (cmdp->name, "HELP") == 0) {
2883 
2884 
2885 
2886 
2887 
2888 
2889 
2890 
2891 
2892 
2893 
2894 
2895 
2896 
2897 
2898 
2899 
2900 
2901 
2902 
2903 
2904 
2905 
2906 
2907 
2908 
2909 
2910 
2911 
2912 
2913 
2914 
2915 
2916 
2917                 }
2918             else {
2919                 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2920                     sim_dflt_dev && sim_dflt_dev->help) {
2921                         sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2922                         if (sim_log)
2923                             sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2924                     }
2925                 }
2926             help_cmd_output (flag, cmdp->help, cmdp->help_base);
2927             }
2928         else { /* no help so it is likely a command alias */
2929             CTAB *cmdpa;
2930             for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2931                 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2932                     sim_printf ("%s is an alias for the %s command:\r\n%s",
2933                                 cmdp->name, cmdpa->name, cmdpa->help);
2934                     break;
2935                     }
2936             if (cmdpa->name == NULL)                /* not found? */
2937                 sim_printf ("No help available for the %s command\r\n", cmdp->name);
2938             }
2939         }
2940     else {
2941         DEVICE *dptr;
2942         UNIT *uptr;
2943         t_stat r;
2944         dptr = find_unit (gbuf, &uptr);
2945         if (dptr == NULL) {
2946             dptr = find_dev (gbuf);
2947             if (dptr == NULL)
2948                 return SCPE_ARG;
2949             if (dptr->flags & DEV_DIS)
2950                 sim_printf ("Device %s is currently disabled\r\n", dptr->name);
2951             }
2952         r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2953         if (sim_log)
2954             help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2955         return r;
2956         }
2957     }
2958 else {
2959     fprint_help (stdout);
2960     if (sim_log)
2961         fprint_help (sim_log);
2962     }
2963 return SCPE_OK;
2964 }
2965 
2966 /* Spawn command */
2967 
2968 t_stat spawn_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2969 {
2970 t_stat status;
2971 if ((cptr == NULL) || (strlen (cptr) == 0))
2972     cptr = getenv("SHELL");
2973 if ((cptr == NULL) || (strlen (cptr) == 0))
2974     cptr = getenv("ComSpec");
2975 (void)fflush(stdout);                                   /* flush stdout */
2976 if (sim_log)                                            /* flush log if enabled */
2977     (void)fflush (sim_log);
2978 if (sim_deb)                                            /* flush debug if enabled */
2979     (void)fflush (sim_deb);
2980 status = system (cptr);
2981 
2982 return status;
2983 }
2984 
2985 /* Echo command */
2986 
2987 t_stat echo_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2988 {
2989 sim_printf ("%s\r\n", cptr);
2990 return SCPE_OK;
2991 }
2992 
2993 /*
2994  * DO command
2995  *
2996  * Note that SCPE_STEP ("Step expired") is considered a note and
2997  * not an error; it does not abort command execution when using -E.
2998  *
2999  * Inputs:
3000  *      flag    =   caller and nesting level indicator
3001  *      fcptr   =   filename and optional arguments, space-separated
3002  * Outputs:
3003  *      status  =   error status
3004  *
3005  * The "flag" input value indicates the source of the call, as follows:
3006  *
3007  *      -1      =   initialization file (no error if not found)
3008  *       0      =   command line file
3009  *       1      =   "DO" command
3010  *      >1      =   nested "DO" command
3011  */
3012 
3013 t_stat do_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3014 {
3015 return do_cmd_label (flag, fcptr, NULL);
3016 }
3017 
3018 static char *do_position(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3019 {
3020 static char cbuf[4*CBUFSIZE];
3021 
3022 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
3023                 sim_do_label[sim_do_depth] ? "::" : "",
3024                 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
3025                 sim_goto_line[sim_do_depth]);
3026 return cbuf;
3027 }
3028 
3029 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
     /* [previous][next][first][last][top][bottom][index][help] */
3030 {
3031 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
3032 CONST char *cptr;
3033 FILE *fpin;
3034 CTAB *cmdp = NULL;
3035 int32 echo, nargs, errabort, i;
3036 int32 saved_sim_do_echo = sim_do_echo,
3037       saved_sim_show_message = sim_show_message,
3038       saved_sim_on_inherit = sim_on_inherit,
3039       saved_sim_quiet = sim_quiet;
3040 t_bool staying;
3041 t_stat stat, stat_nomessage;
3042 
3043 stat = SCPE_OK;
3044 staying = TRUE;
3045 if (flag > 0)                                           /* need switches? */
3046     GET_SWITCHES (fcptr);                               /* get switches */
3047 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;    /* -v means echo */
3048 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet; /* -q means quiet */
3049 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit; /* -o means inherit ON condition actions */
3050 errabort = sim_switches & SWMASK ('E');                 /* -e means abort on error */
3051 
3052 abuf[sizeof(abuf)-1] = '\0';
3053 strncpy (abuf, fcptr, sizeof(abuf)-1);
3054 c = abuf;
3055 do_arg[10] = NULL;                                      /* make sure the argument list always ends with a NULL */
3056 for (nargs = 0; nargs < 10; ) {                         /* extract arguments */
3057     while (sim_isspace (*c))                            /* skip blanks */
3058         c++;
3059     if (*c == 0)                                        /* all done? */
3060         do_arg [nargs++] = NULL;                        /* null argument */
3061     else {
3062         if (*c == '\'' || *c == '"')                    /* quoted string? */
3063             quote = *c++;
3064         else quote = 0;
3065         do_arg[nargs++] = c;                            /* save start */
3066         while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
3067             c++;
3068         if (*c)                                         /* term at quote/spc */
3069             *c++ = 0;
3070         }
3071     }                                                   /* end for */
3072 
3073 if (do_arg [0] == NULL)                                 /* need at least 1 */
3074     return SCPE_2FARG;
3075 if ((fpin = fopen (do_arg[0], "r")) == NULL) {          /* file failed to open? */
3076     strcat (strcpy (cbuf, do_arg[0]), ".ini");          /* try again with .ini extension */
3077     if ((fpin = fopen (cbuf, "r")) == NULL) {           /* failed a second time? */
3078         if (flag == 0)                                  /* cmd line file? */
3079              (void)fprintf (stderr, "Can't open file %s\r\n", do_arg[0]);
3080         return SCPE_OPENERR;                            /* return failure */
3081         }
3082     }
3083 if (flag >= 0) {                                        /* Only bump nesting from command or nested */
3084     ++sim_do_depth;
3085     if (sim_on_inherit) {                               /* inherit ON condition actions? */
3086         sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1]; /* inherit On mode */
3087         for (i=0; i<SCPE_MAX_ERR; i++) {                /* replicate any on commands */
3088             if (sim_on_actions[sim_do_depth-1][i]) {
3089                 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3090                 if (NULL == sim_on_actions[sim_do_depth][i]) {
3091                     while (--i >= 0) {
3092                         FREE(sim_on_actions[sim_do_depth][i]);
3093                         sim_on_actions[sim_do_depth][i] = NULL;
3094                         }
3095                     sim_on_check[sim_do_depth] = 0;
3096                     sim_brk_clract ();                  /* defang breakpoint actions */
3097                     --sim_do_depth;                     /* unwind nesting */
3098                     fclose(fpin);
3099                     return SCPE_MEM;
3100                     }
3101                 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3102                 }
3103             }
3104         }
3105     }
3106 
3107 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);      /* stash away do file name for possible use by 'call' command */
3108 sim_do_label[sim_do_depth] = label;                     /* stash away do label for possible use in messages */
3109 sim_goto_line[sim_do_depth] = 0;
3110 if (label) {
3111     sim_gotofile = fpin;
3112     sim_do_echo = echo;
3113     stat = goto_cmd (0, label);
3114     if (stat != SCPE_OK) {
3115         strcpy(cbuf, "RETURN SCPE_ARG");
3116         cptr = get_glyph (cbuf, gbuf, 0);               /* get command glyph */
3117         cmdp = find_cmd (gbuf);                         /* return the errorStage things to the stat will be returned */
3118         goto Cleanup_Return;
3119         }
3120     }
3121 if (errabort)                                           /* -e flag? */
3122     set_on (1, NULL);                                   /* equivalent to ON ERROR RETURN */
3123 
3124 do {
3125     sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */
3126     if (!sim_do_ocptr[sim_do_depth]) {                  /* no pending action? */
3127         sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */
3128         sim_goto_line[sim_do_depth] += 1;
3129         }
3130     if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {  /* validate */
3131         sim_sub_args(cbuf, sizeof(cbuf), do_arg);       /* substitute args */
3132         }
3133     sim_sub_args (cbuf, sizeof(cbuf), do_arg);          /* substitute args */
3134     if (cptr == NULL) {                                 /* EOF? */
3135         stat = SCPE_OK;                                 /* set good return */
3136         break;
3137         }
3138     if (*cptr == 0)                                     /* ignore blank */
3139         continue;
3140     if (echo)                                           /* echo if -v */
3141         sim_printf("%s> %s\r\n", do_position(), cptr);
3142     if (*cptr == ':')                                   /* ignore label */
3143         continue;
3144     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
3145     sim_switches = 0;                                   /* init switches */
3146     sim_gotofile = fpin;
3147     sim_do_echo = echo;
3148     if ((cmdp = find_cmd (gbuf))) {                     /* lookup command */
3149         if (cmdp->action == &return_cmd)                /* RETURN command? */
3150             break;                                      /*    done! */
3151         if (cmdp->action == &do_cmd) {                  /* DO command? */
3152             if (sim_do_depth >= MAX_DO_NEST_LVL)        /* nest too deep? */
3153                 stat = SCPE_NEST;
3154             else
3155                 stat = do_cmd (sim_do_depth+1, cptr);   /* exec DO cmd */
3156             }
3157         else
3158             stat = cmdp->action (cmdp->arg, cptr);      /* exec other cmd */
3159         }
3160     else stat = SCPE_UNK;                               /* bad cmd given */
3161     echo = sim_do_echo;                                 /* Allow for SET VERIFY */
3162     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
3163     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
3164     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
3165     if (cmdp)
3166       if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3167           ((cmdp->action != &return_cmd) &&
3168            (cmdp->action != &goto_cmd) &&
3169            (cmdp->action != &on_cmd) &&
3170            (cmdp->action != &echo_cmd)))
3171         sim_last_cmd_stat = stat;                       /* save command error status */
3172     switch (stat) {
3173         case SCPE_AFAIL:
3174             staying = (sim_on_check[sim_do_depth] &&        /* if trap action defined */
3175                        sim_on_actions[sim_do_depth][stat]); /* use it, otherwise exit */
3176             break;
3177         case SCPE_EXIT:
3178             staying = FALSE;
3179             break;
3180         case SCPE_OK:
3181         case SCPE_STEP:
3182             break;
3183         default:
3184             break;
3185         }
3186     if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&   /* error from cmd? */
3187         (stat != SCPE_STEP)) {
3188         if (!echo && !sim_quiet &&                      /* report if not echoing */
3189             !stat_nomessage &&                          /* and not suppressing messages */
3190             !(cmdp && cmdp->message)) {                 /* and not handling them specially */
3191             sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
3192             }
3193         }
3194     if (!stat_nomessage) {                              /* report error if not suppressed */
3195         if (cmdp && cmdp->message)                      /* special message handler */
3196             cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3197         else
3198             if (stat >= SCPE_BASE)                      /* report error if not suppressed */
3199                 sim_printf ("%s\r\n", sim_error_text (stat));
3200         }
3201     if (stat == SCPE_EXPECT)                            /* EXPECT status is non actionable */
3202         stat = SCPE_OK;                                 /* so adjust it to SCPE_OK */
3203     if (staying &&
3204         (sim_on_check[sim_do_depth]) &&
3205         (stat != SCPE_OK) &&
3206         (stat != SCPE_STEP)) {
3207         if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3208             sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3209         else
3210             sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3211         }
3212     if (sim_vm_post != NULL)
3213         (*sim_vm_post) (TRUE);
3214     } while (staying);
3215 Cleanup_Return:
3216 if (fpin) //-V547
3217     fclose (fpin);                                      /* close file */
3218 sim_gotofile = NULL;
3219 if (flag >= 0) {
3220     sim_do_echo = saved_sim_do_echo;                    /* restore echo state we entered with */
3221     sim_show_message = saved_sim_show_message;          /* restore message display state we entered with */
3222     sim_on_inherit = saved_sim_on_inherit;              /* restore ON inheritance state we entered with */
3223     }
3224 sim_quiet = saved_sim_quiet;                            /* restore quiet mode we entered with */
3225 if ((flag >= 0) || (!sim_on_inherit)) {
3226     for (i=0; i<SCPE_MAX_ERR; i++) {                    /* release any on commands */
3227         FREE (sim_on_actions[sim_do_depth][i]);
3228         sim_on_actions[sim_do_depth][i] = NULL;
3229         }
3230     sim_on_check[sim_do_depth] = 0;                     /* clear on mode */
3231     }
3232 if (flag >= 0)
3233     --sim_do_depth;                                     /* unwind nesting */
3234 sim_brk_clract ();                                      /* defang breakpoint actions */
3235 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) { /* return command with argument? */
3236     sim_string_to_stat (cptr, &stat);
3237     sim_last_cmd_stat = stat;                           /* save explicit status as command error status */
3238     if (sim_switches & SWMASK ('Q'))
3239         stat |= SCPE_NOMESSAGE;                         /* suppress error message display (in caller) if requested */
3240     return stat;                                        /* return with explicit return status */
3241     }
3242 return stat | SCPE_NOMESSAGE;                           /* suppress message since we've already done that here */
3243 }
3244 
3245 /*
3246  * Substitute_args - replace %n tokens in 'instr' with the do command's arguments
3247  *                   and other environment variables
3248  *
3249  * Calling sequence
3250  * instr        =       input string
3251  * instr_size   =       sizeof input string buffer
3252  * do_arg[10]   =       arguments
3253  *
3254  * Token "%0" expands to the command file name.
3255  * Token %n (n being a single digit) expands to the n'th argument
3256  * Tonen %* expands to the whole set of arguments (%1 ... %9)
3257  *
3258  * The input sequence "\%" represents a literal "%", and "\\" represents a
3259  * literal "\".  All other character combinations are rendered literally.
3260  *
3261  * Omitted parameters result in null-string substitutions.
3262  *
3263  * A Tokens preceded and followed by % characters are expanded as environment
3264  * variables, and if one isn't found then can be one of several special
3265  * variables:
3266  *   %DATE%              yyyy-mm-dd
3267  *   %TIME%              hh:mm:ss
3268  *   %STIME%             hh_mm_ss
3269  *   %CTIME%             Www Mmm dd hh:mm:ss yyyy
3270  *   %STATUS%            Status value from the last command executed
3271  *   %TSTATUS%           The text form of the last status value
3272  *   %SIM_VERIFY%        The Verify/Verbose mode of the current Do command file
3273  *   %SIM_VERBOSE%       The Verify/Verbose mode of the current Do command file
3274  *   %SIM_QUIET%         The Quiet mode of the current Do command file
3275  *   %SIM_MESSAGE%       The message display status of the current Do command file
3276  * Environment variable lookups are done first with the precise name between
3277  * the % characters and if that fails, then the name between the % characters
3278  * is upcased and a lookup of that value is attempted.
3279 
3280  * The first Space delimited token on the line is extracted in uppercase and
3281  * then looked up as an environment variable.  If found it the value is
3282  * substituted for the original string before expanding everything else.  If
3283  * it is not found, then the original beginning token on the line is left
3284  * untouched.
3285  */
3286 
3287 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
     /* [previous][next][first][last][top][bottom][index][help] */
3288 {
3289 char gbuf[CBUFSIZE];
3290 char *ip = instr, *op, *oend, *tmpbuf;
3291 const char *ap;
3292 char rbuf[CBUFSIZE];
3293 int i;
3294 time_t now;
3295 struct tm *tmnow;
3296 
3297 time(&now);
3298 tmnow = localtime(&now);
3299 tmpbuf = (char *)malloc(instr_size);
3300 if (!tmpbuf)
3301   {
3302      (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3303                    __func__, __FILE__, __LINE__);
3304 #if defined(USE_BACKTRACE)
3305 # if defined(SIGUSR2)
3306      (void)raise(SIGUSR2);
3307      /*NOTREACHED*/ /* unreachable */
3308 # endif /* if defined(SIGUSR2) */
3309 #endif /* if defined(USE_BACKTRACE) */
3310      abort();
3311   }
3312 op = tmpbuf;
3313 oend = tmpbuf + instr_size - 2;
3314 while (sim_isspace (*ip))                               /* skip leading spaces */
3315     *op++ = *ip++;
3316 for (; *ip && (op < oend); ) {
3317     if ((ip [0] == '\\') &&                             /* literal escape? */
3318         ((ip [1] == '%') || (ip [1] == '\\'))) {        /*   and followed by '%' or '\'? */
3319         ip++;                                           /* skip '\' */
3320         *op++ = *ip++;                                  /* copy escaped char */
3321         }
3322     else
3323         if ((*ip == '%') &&
3324             (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */
3325             if ((ip[1] >= '0') && (ip[1] <= ('9'))) {   /* %n = sub */
3326                 ap = do_arg[ip[1] - '0'];
3327                 for (i=0; i<ip[1] - '0'; ++i)           /* make sure we're not past the list end */
3328                     if (do_arg[i] == NULL) {
3329                         ap = NULL;
3330                         break;
3331                         }
3332                 ip = ip + 2;
3333                 }
3334             else if (ip[1] == '*') {                    /* %1 ... %9 = sub */
3335                 (void)memset (rbuf, '\0', sizeof(rbuf));
3336                 ap = rbuf;
3337                 for (i=1; i<=9; ++i)
3338                     if (do_arg[i] == NULL)
3339                         break;
3340                     else
3341                         if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3342                             if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
3343                                 char quote = '"';
3344                                 if (strchr(do_arg[i], quote))
3345                                     quote = '\'';
3346                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3347                                               (i != 1) ? " " : "", quote,
3348                                               do_arg[i], quote);
3349                                 }
3350                             else
3351                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3352                                               (i != 1) ? " " : "", do_arg[i]);
3353                             }
3354                         else
3355                             break;
3356                 ip = ip + 2;
3357                 }
3358             else {                                      /* environment variable */
3359                 ap = NULL;
3360                 (void)get_glyph_nc (ip+1, gbuf, '%');   /* first try using the literal name */
3361                 ap = getenv(gbuf);
3362                 if (!ap) {
3363                     (void)get_glyph (ip+1, gbuf, '%');  /* now try using the upcased name */
3364                     ap = getenv(gbuf);
3365                     }
3366                 ip += 1 + strlen (gbuf);
3367                 if (*ip == '%') ++ip;
3368                 if (!ap) {
3369                     /* ISO 8601 format date/time info */
3370                     if (!strcmp ("DATE", gbuf)) {
3371                         (void)sprintf (rbuf, "%4d-%02d-%02d",
3372                                        tmnow->tm_year + 1900,
3373                                        tmnow->tm_mon  + 1,
3374                                        tmnow->tm_mday);
3375                         ap = rbuf;
3376                         }
3377                     else if (!strcmp ("TIME", gbuf)) {
3378                         (void)sprintf (rbuf, "%02d:%02d:%02d",
3379                                        tmnow->tm_hour,
3380                                        tmnow->tm_min,
3381                                        tmnow->tm_sec);
3382                         ap = rbuf;
3383                         }
3384                     else if (!strcmp ("DATETIME", gbuf)) {
3385                         (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3386                                        tmnow->tm_year + 1900,
3387                                        tmnow->tm_mon  + 1,
3388                                        tmnow->tm_mday,
3389                                        tmnow->tm_hour,
3390                                        tmnow->tm_min,
3391                                        tmnow->tm_sec);
3392                         ap = rbuf;
3393                         }
3394                     /* Locale oriented formatted date/time info */
3395                     if (!strcmp ("LDATE", gbuf)) {
3396                         strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3397                         ap = rbuf;
3398                         }
3399                     else if (!strcmp ("LTIME", gbuf)) {
3400                         strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3401                         ap = rbuf;
3402                         }
3403                     else if (!strcmp ("CTIME", gbuf)) {
3404                         strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3405                         ap = rbuf;
3406                         }
3407                     /* Separate Date/Time info */
3408                     else if (!strcmp ("DATE_YYYY", gbuf)) {/* Year (0000-9999) */
3409                         strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3410                         ap = rbuf;
3411                         }
3412                     else if (!strcmp ("DATE_YY", gbuf)) {/* Year (00-99) */
3413                         strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3414                         ap = rbuf;
3415                         }
3416                     else if (!strcmp ("DATE_YC", gbuf)) {/* Century (year/100) */
3417                         (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3418                         ap = rbuf;
3419                         }
3420                     else if ((!strcmp ("DATE_19XX_YY", gbuf)) || /* Year with same calendar */
3421                              (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3422                         int year = tmnow->tm_year + 1900;
3423                         int days = year - 2001;
3424                         int leaps = days/4 - days/100 + days/400;
3425                         int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3426                         int selector = ((days + leaps + 7) % 7) + lyear * 7;
3427                         static int years[] = {90, 91, 97, 98, 99, 94, 89,
3428                                               96, 80, 92, 76, 88, 72, 84};
3429                         int cal_year = years[selector];
3430 
3431                         if (!strcmp ("DATE_19XX_YY", gbuf))
3432                             (void)sprintf (rbuf, "%d", cal_year);        /* 2 digit year */
3433                         else
3434                             (void)sprintf (rbuf, "%d", cal_year + 1900); /* 4 digit year */
3435                         ap = rbuf;
3436                         }
3437                     else if (!strcmp ("DATE_MM", gbuf)) {/* Month number (01-12) */
3438                         strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3439                         ap = rbuf;
3440                         }
3441                     else if (!strcmp ("DATE_MMM", gbuf)) {/* Month number (01-12) */
3442                         strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3443                         ap = rbuf;
3444                         }
3445                     else if (!strcmp ("DATE_DD", gbuf)) {/* Day of Month (01-31) */
3446                         strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3447                         ap = rbuf;
3448                         }
3449                     else if (!strcmp ("DATE_D", gbuf)) { /* ISO 8601 weekday number (1-7) */
3450                         (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3451                         ap = rbuf;
3452                         }
3453                     else if ((!strcmp ("DATE_WW", gbuf)) ||   /* ISO 8601 week number (01-53) */
3454                              (!strcmp ("DATE_WYYYY", gbuf))) {/* ISO 8601 week year number (0000-9999) */
3455                         int iso_yr = tmnow->tm_year + 1900;
3456                         int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3457 
3458                         if (iso_wk == 0) {
3459                             iso_yr = iso_yr - 1;
3460                             tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);  /* Adjust for Leap Year (Correct thru 2099) */
3461                             iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3462                             }
3463                         else
3464                             if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3465                                 ++iso_yr;
3466                                 iso_wk = 1;
3467                                 }
3468                         if (!strcmp ("DATE_WW", gbuf))
3469                             (void)sprintf (rbuf, "%02d", iso_wk);
3470                         else
3471                             (void)sprintf (rbuf, "%04d", iso_yr);
3472                         ap = rbuf;
3473                         }
3474                     else if (!strcmp ("DATE_JJJ", gbuf)) {/* day of year (001-366) */
3475                         strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3476                         ap = rbuf;
3477                         }
3478                     else if (!strcmp ("TIME_HH", gbuf)) {/* Hour of day (00-23) */
3479                         strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3480                         ap = rbuf;
3481                         }
3482                     else if (!strcmp ("TIME_MM", gbuf)) {/* Minute of hour (00-59) */
3483                         strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3484                         ap = rbuf;
3485                         }
3486                     else if (!strcmp ("TIME_SS", gbuf)) {/* Second of minute (00-59) */
3487                         strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3488                         ap = rbuf;
3489                         }
3490                     else if (!strcmp ("STATUS", gbuf)) {
3491                         (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3492                         ap = rbuf;
3493                         }
3494                     else if (!strcmp ("TSTATUS", gbuf)) {
3495                         (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3496                         ap = rbuf;
3497                         }
3498                     else if (!strcmp ("SIM_VERIFY", gbuf)) {
3499                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3500                         ap = rbuf;
3501                         }
3502                     else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3503                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3504                         ap = rbuf;
3505                         }
3506                     else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3507                         (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3508                         ap = rbuf;
3509                         }
3510                     else if (!strcmp ("SIM_QUIET", gbuf)) {
3511                         (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3512                         ap = rbuf;
3513                         }
3514                     else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3515                         (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3516                         ap = rbuf;
3517                         }
3518                     else if (!strcmp ("HOSTID", gbuf)) {
3519 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3520                         (void)sprintf (rbuf, "%ld", (long)gethostid());
3521 #else
3522                         (void)sprintf (rbuf, "00000000");
3523 #endif /* if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) */
3524                         ap = rbuf;
3525                         }
3526                     else if (!strcmp ("UID", gbuf)) {
3527 #if defined(HAVE_UNISTD)
3528                         (void)sprintf (rbuf, "%ld", (long)getuid());
3529 #else
3530                         (void)sprintf (rbuf, "0");
3531 #endif /* if defined(HAVE_UNISTD) */
3532                         ap = rbuf;
3533                         }
3534                     else if (!strcmp ("GID", gbuf)) {
3535 #if defined(HAVE_UNISTD)
3536                         (void)sprintf (rbuf, "%ld", (long)getgid());
3537 #else
3538                         (void)sprintf (rbuf, "0");
3539 #endif /* if defined(HAVE_UNISTD) */
3540                         ap = rbuf;
3541                         }
3542                     else if (!strcmp ("EUID", gbuf)) {
3543 #if defined(HAVE_UNISTD)
3544                         (void)sprintf (rbuf, "%ld", (long)geteuid());
3545 #else
3546                         (void)sprintf (rbuf, "0");
3547 #endif /* if defined(HAVE_UNISTD) */
3548                         ap = rbuf;
3549                         }
3550                     else if (!strcmp ("EGID", gbuf)) {
3551 #if defined(HAVE_UNISTD)
3552                         (void)sprintf (rbuf, "%ld", (long)getegid());
3553 #else
3554                         (void)sprintf (rbuf, "0");
3555 #endif /* if defined(HAVE_UNISTD) */
3556                         ap = rbuf;
3557                         }
3558                     else if (!strcmp ("PID", gbuf)) {
3559 #if defined(HAVE_UNISTD)
3560                         (void)sprintf (rbuf, "%ld", (long)_sir_getpid());
3561 #else
3562                         (void)sprintf (rbuf, "0");
3563 #endif /* if defined(HAVE_UNISTD) */
3564                         ap = rbuf;
3565                         }
3566                     else if (!strcmp ("PPID", gbuf)) {
3567 #if defined(HAVE_UNISTD)
3568                         (void)sprintf (rbuf, "%ld", (long)getppid());
3569 #else
3570                         (void)sprintf (rbuf, "0");
3571 #endif /* if defined(HAVE_UNISTD) */
3572                         ap = rbuf;
3573                         }
3574                     else if (!strcmp ("PGID", gbuf)) {
3575 #if defined(HAVE_UNISTD)
3576                         (void)sprintf (rbuf, "%ld", (long)getpgid(_sir_getpid()));
3577 #else
3578                         (void)sprintf (rbuf, "0");
3579 #endif /* if defined(HAVE_UNISTD) */
3580                         ap = rbuf;
3581                         }
3582                     else if (!strcmp ("SID", gbuf)) {
3583 #if defined(HAVE_UNISTD)
3584                         (void)sprintf (rbuf, "%ld", (long)getsid(_sir_getpid()));
3585 #else
3586                         (void)sprintf (rbuf, "0");
3587 #endif /* if defined(HAVE_UNISTD) */
3588                         ap = rbuf;
3589                         }
3590                     else if (!strcmp ("ENDIAN", gbuf)) {
3591 #if ( defined(DECLITEND) && DECLITEND == 1 )
3592                         (void)sprintf (rbuf, "LITTLE");
3593 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3594                         (void)sprintf (rbuf, "BIG");
3595 #else
3596                         (void)sprintf (rbuf, "UNKNOWN");
3597 #endif /* if ( defined(DECLITEND) && DECLITEND == 1 ) */
3598                         ap = rbuf;
3599                         }
3600                     else if (!strcmp("SIM_NAME", gbuf)) {
3601                         (void)sprintf (rbuf, "%s", sim_name);
3602                         ap = rbuf;
3603                         }
3604                     else if (!strcmp("SIM_VERSION", gbuf)) {
3605 #if defined(VER_H_GIT_VERSION)
3606                         (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3607 #else
3608                         (void)sprintf (rbuf, "UNKNOWN");
3609 #endif /* if defined(VER_H_GIT_VERSION) */
3610                         ap = rbuf;
3611                         }
3612                     else if (!strcmp("SIM_HASH", gbuf)) {
3613 #if defined(VER_H_GIT_HASH)
3614                         (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3615 #else
3616                         (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3617 #endif /* if defined(VER_H_GIT_HASH) */
3618                         ap = rbuf;
3619                         }
3620                     else if (!strcmp("SIM_RELT", gbuf)) {
3621 #if defined(VER_H_GIT_RELT)
3622                         (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3623 #else
3624                         (void)sprintf (rbuf, "X");
3625 #endif /* if defined(VER_H_GIT_RELT) */
3626                         ap = rbuf;
3627                         }
3628                     else if (!strcmp("SIM_DATE", gbuf)) {
3629 #if defined(VER_H_GIT_DATE)
3630                         (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3631 #else
3632                         (void)sprintf (rbuf, "UNKNOWN");
3633 #endif /* if defined(VER_H_GIT_DATE) */
3634                         ap = rbuf;
3635                         }
3636                     else if ((!strcmp("CORES", gbuf)) ||
3637                              (!strcmp("SIM_CORES", gbuf))) {
3638                         (void)sprintf(rbuf, "%u", (ncores >= 1 && nprocs >= 1) ? ((ncores > nprocs) ? nprocs : ncores) : 1);
3639                         ap = rbuf;
3640                         }
3641                     else if ((!strcmp("CPUS", gbuf)) ||
3642                              (!strcmp("SIM_PROCESSORS", gbuf))) {
3643                         (void)sprintf(rbuf, "%u", (nprocs < 2) ? 1U : nprocs);
3644                         ap = rbuf;
3645                         }
3646                     }
3647                 }
3648             if (ap) {                                   /* non-null arg? */
3649                 while (*ap && (op < oend))              /* copy the argument */
3650                     *op++ = *ap++;
3651                 }
3652             }
3653         else
3654             *op++ = *ip++;
3655     }
3656 *op = 0;                                                /* term buffer */
3657 strcpy (instr, tmpbuf);
3658 FREE (tmpbuf);
3659 return;
3660 }
3661 
3662 static
3663 int sim_cmp_string (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help] */
3664 {
3665 long int v1, v2;
3666 char *ep1, *ep2;
3667 
3668 v1 = strtol(s1+1, &ep1, 0);
3669 v2 = strtol(s2+1, &ep2, 0);
3670 if ((ep1 != s1 + strlen (s1) - 1) ||
3671     (ep2 != s2 + strlen (s2) - 1))
3672     return strcmp (s1, s2);
3673 if (v1 == v2)
3674     return 0;
3675 if (v1 < v2)
3676     return -1;
3677 return 1;
3678 }
3679 
3680 /* Assert command */
3681 
3682 t_stat assert_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3683 {
3684 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3685 CONST char *tptr, *gptr;
3686 REG *rptr;
3687 uint32 idx = 0;
3688 t_value val;
3689 t_stat r;
3690 t_bool Not = FALSE;
3691 t_bool result;
3692 t_addr addr = 0;
3693 t_stat reason = SCPE_AFAIL; /* default fail reason */
3694 
3695 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3696                                                         /* get sw, default */
3697 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3698 # pragma diagnostic push
3699 # pragma diag_suppress = integer_sign_change
3700 #endif
3701 sim_stabr.boolop = sim_staba.boolop = -1;               /* no relational op dflt */
3702 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3703 # pragma diagnostic pop
3704 #endif
3705 if (*cptr == 0)                                         /* must be more */
3706     return SCPE_2FARG;
3707 tptr = get_glyph (cptr, gbuf, 0);                       /* get token */
3708 if (!strcmp (gbuf, "NOT")) {                            /* Conditional Inversion? */
3709     Not = TRUE;                                         /* remember that, and */
3710     cptr = (CONST char *)tptr;
3711     }
3712 if (*cptr == '"') {                                     /* quoted string comparison? */
3713     char op[CBUFSIZE];
3714     static struct {
3715         const char *op;
3716         int aval;
3717         int bval;
3718         t_bool invert;
3719         } *optr, compare_ops[] =
3720         {
3721             { "==",   0,  0, FALSE },
3722             { "EQU",  0,  0, FALSE },
3723             { "!=",   0,  0, TRUE  },
3724             { "NEQ",  0,  0, TRUE  },
3725             { "<",   -1, -1, FALSE },
3726             { "LSS", -1, -1, FALSE },
3727             { "<=",   0, -1, FALSE },
3728             { "LEQ",  0, -1, FALSE },
3729             { ">",    1,  1, FALSE },
3730             { "GTR",  1,  1, FALSE },
3731             { ">=",   0,  1, FALSE },
3732             { "GEQ",  0,  1, FALSE },
3733             { NULL }
3734         };
3735 
3736     tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3737                                                     /* get first string */
3738     if (!*tptr)
3739         return SCPE_2FARG;
3740     cptr += strlen (gbuf);
3741     while (sim_isspace (*cptr))                     /* skip spaces */
3742         ++cptr;
3743     (void)get_glyph (cptr, op, '"');
3744     for (optr = compare_ops; optr->op; optr++)
3745         if (0 == strcmp (op, optr->op))
3746             break;
3747     if (!optr->op)
3748         return sim_messagef (SCPE_ARG, "Invalid operator: %s\r\n", op);
3749     cptr += strlen (op);
3750     while (sim_isspace (*cptr))                         /* skip spaces */
3751         ++cptr;
3752     cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3753                                                         /* get second string */
3754     if (*cptr) {                                        /* more? */
3755         if (flag)                                       /* ASSERT has no more args */
3756             return SCPE_2MARG;
3757         }
3758     else {
3759         if (!flag)
3760             return SCPE_2FARG;                          /* IF needs actions! */
3761         }
3762     result = sim_cmp_string (gbuf, gbuf2);
3763     result = ((result == optr->aval) || (result == optr->bval));
3764     if (optr->invert)
3765         result = !result;
3766     }
3767 else {
3768     cptr = get_glyph (cptr, gbuf, 0);                   /* get register */
3769     rptr = find_reg (gbuf, &gptr, sim_dfdev);           /* parse register */
3770     if (rptr) {                                         /* got register? */
3771         if (*gptr == '[') {                             /* subscript? */
3772             if (rptr->depth <= 1)                       /* array register? */
3773                 return SCPE_ARG;
3774             idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */
3775             if ((gptr == tptr) || (*tptr++ != ']'))
3776                 return SCPE_ARG;
3777             gptr = tptr;                                /* update */
3778             }
3779         else idx = 0;                                   /* not array */
3780         if (idx >= rptr->depth)                         /* validate subscript */
3781             return SCPE_SUB;
3782         }
3783     else {                                              /* not reg, check for memory */
3784         if (sim_dfdev && sim_vm_parse_addr)             /* get addr */
3785             addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3786         else if (sim_dfdev) //-V547
3787             addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix); //-V547
3788         if (gbuf == gptr)                               /* error? */
3789             return SCPE_NXREG;
3790         }
3791     if (*gptr != 0)                                     /* more? must be search */
3792         (void)get_glyph (gptr, gbuf, 0);
3793     else {
3794         if (*cptr == 0)                                 /* must be more */
3795             return SCPE_2FARG;
3796         cptr = get_glyph (cptr, gbuf, 0);               /* get search cond */
3797         }
3798     if (*cptr) {                                        /* more? */
3799         if (flag)                                       /* ASSERT has no more args */
3800             return SCPE_2MARG;
3801         }
3802     else {
3803         if (!flag)
3804             return SCPE_2FARG;                          /* IF needs actions! */
3805         }
3806     if (rptr) {                                         /* Handle register case */
3807 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3808 # pragma diagnostic push
3809 # pragma diag_suppress = integer_sign_change
3810 #endif
3811         if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||  /* parse condition */
3812             (sim_stabr.boolop == -1))                   /* relational op reqd */
3813             return SCPE_MISVAL;
3814 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3815 # pragma diagnostic pop
3816 #endif
3817         val = get_rval (rptr, idx);                     /* get register value */
3818         result = test_search (&val, &sim_stabr);        /* test condition */
3819         }
3820     else {                                              /* Handle memory case */
3821 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3822 # pragma diagnostic push
3823 # pragma diag_suppress = integer_sign_change
3824 #endif
3825         if (sim_dfdev)
3826             if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||  /* parse condition */
3827                 (sim_staba.boolop == -1))                    /* relational op reqd */
3828                 return SCPE_MISVAL;
3829 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3830 # pragma diagnostic pop
3831 #endif
3832         if (sim_dfdev)
3833             reason = get_aval (addr, sim_dfdev, sim_dfunit); /* get data */
3834         if (reason != SCPE_OK)                          /* return if error */
3835             return reason;
3836         result = test_search (sim_eval, &sim_staba);    /* test condition */
3837         }
3838     }
3839 if (Not ^ result) {
3840     if (!flag)
3841         sim_brk_setact (cptr);                          /* set up IF actions */
3842     }
3843 else
3844     if (flag)
3845         return SCPE_AFAIL;                              /* return assert status */
3846 return SCPE_OK;
3847 }
3848 
3849 /* Send command */
3850 
3851 t_stat send_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3852 {
3853 char gbuf[CBUFSIZE];
3854 CONST char *tptr;
3855 uint8 dbuf[CBUFSIZE];
3856 uint32 dsize = 0;
3857 uint32 delay = 0;
3858 uint32 after = 0;
3859 t_stat r;
3860 SEND *snd = NULL;
3861 
3862 GET_SWITCHES (cptr);                                    /* get switches */
3863 tptr = get_glyph (cptr, gbuf, ',');
3864 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3865     r = tmxr_locate_line_send (gbuf, &snd);
3866     if (r != SCPE_OK)
3867       return r;
3868     cptr = tptr;
3869     tptr = get_glyph (tptr, gbuf, ',');
3870     }
3871 else
3872     snd = sim_cons_get_send ();
3873 
3874 while (*cptr) {
3875     if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3876         delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3877         if (r != SCPE_OK)
3878             return sim_messagef (SCPE_ARG, "Invalid Delay Value\r\n");
3879         cptr = tptr;
3880         tptr = get_glyph (cptr, gbuf, ',');
3881         continue;
3882         }
3883     if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3884         after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3885         if (r != SCPE_OK)
3886             return sim_messagef (SCPE_ARG, "Invalid After Value\r\n");
3887         cptr = tptr;
3888         tptr = get_glyph (cptr, gbuf, ',');
3889         continue;
3890         }
3891     if ((*cptr == '"') || (*cptr == '\''))
3892         break;
3893     return SCPE_ARG;
3894     }
3895 if (*cptr) {
3896     if ((*cptr != '"') && (*cptr != '\'')) //-V560
3897         return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
3898     cptr = get_glyph_quoted (cptr, gbuf, 0);
3899     if (*cptr != '\0')
3900         return SCPE_2MARG;                  /* No more arguments */
3901 
3902     if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3903         return sim_messagef (SCPE_ARG, "Invalid String\r\n");
3904     }
3905 if ((dsize == 0) && (delay == 0) && (after == 0))
3906     return SCPE_2FARG;
3907 return sim_send_input (snd, dbuf, dsize, after, delay);
3908 }
3909 
3910 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3911 {
3912 char gbuf[CBUFSIZE];
3913 CONST char *tptr;
3914 t_stat r;
3915 SEND *snd = NULL;
3916 
3917 tptr = get_glyph (cptr, gbuf, ',');
3918 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3919     r = tmxr_locate_line_send (gbuf, &snd);
3920     if (r != SCPE_OK)
3921       return r;
3922     cptr = tptr;
3923     }
3924 else
3925     snd = sim_cons_get_send ();
3926 if (*cptr)
3927     return SCPE_2MARG;
3928 return sim_show_send_input (st, snd);
3929 }
3930 
3931 t_stat expect_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3932 {
3933 char gbuf[CBUFSIZE];
3934 CONST char *tptr;
3935 EXPECT *exp = NULL;
3936 
3937 GET_SWITCHES (cptr);                                    /* get switches */
3938 tptr = get_glyph (cptr, gbuf, ',');
3939 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3940     cptr = tptr;
3941 } else {
3942     exp = sim_cons_get_expect ();
3943 }
3944 
3945 if (flag) {
3946     return sim_set_expect (exp, cptr);
3947 } else {
3948     if (exp == NULL) {
3949         exp = sim_cons_get_expect();
3950     }
3951     return sim_set_noexpect (exp, cptr);
3952 }
3953 }
3954 
3955 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3956 {
3957 char gbuf[CBUFSIZE];
3958 CONST char *tptr;
3959 EXPECT *exp = NULL;
3960 t_stat r;
3961 
3962 tptr = get_glyph (cptr, gbuf, ',');
3963 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3964     r = tmxr_locate_line_expect (gbuf, &exp);
3965     if (r != SCPE_OK)
3966         return r;
3967     cptr = tptr;
3968     }
3969 else
3970     exp = sim_cons_get_expect ();
3971 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3972     return SCPE_ARG;            /* String must be quote delimited */
3973 tptr = get_glyph_quoted (cptr, gbuf, 0);
3974 if (*tptr != '\0')
3975     return SCPE_2MARG;          /* No more arguments */
3976 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3977     return SCPE_ARG;            /* String must be quote delimited */
3978 return sim_exp_show (st, exp, gbuf);
3979 }
3980 
3981 /* Goto command */
3982 
3983 t_stat goto_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3984 {
3985 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3986 const char *cptr;
3987 long fpos;
3988 int32 saved_do_echo = sim_do_echo;
3989 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3990 
3991 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
3992 (void)get_glyph (fcptr, gbuf1, 0);
3993 if ('\0' == gbuf1[0]) return SCPE_ARG;                  /* unspecified goto target */
3994 fpos = ftell(sim_gotofile);                             /* Save start position */
3995 rewind(sim_gotofile);                                   /* start search for label */
3996 sim_goto_line[sim_do_depth] = 0;                        /* reset line number */
3997 sim_do_echo = 0;                                        /* Don't echo while searching for label */
3998 while (1) {
3999     cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);/* get cmd line */
4000     if (cptr == NULL) break;                            /* exit on eof */
4001     sim_goto_line[sim_do_depth] += 1;                   /* record line number */
4002     if (*cptr == 0) continue;                           /* ignore blank */
4003     if (*cptr != ':') continue;                         /* ignore non-labels */
4004     ++cptr;                                             /* skip : */
4005     while (sim_isspace (*cptr)) ++cptr;                 /* skip blanks */
4006     cptr = get_glyph (cptr, gbuf, 0);                   /* get label glyph */
4007     if (0 == strcmp(gbuf, gbuf1)) {
4008         sim_brk_clract ();                              /* goto defangs current actions */
4009         sim_do_echo = saved_do_echo;                    /* restore echo mode */
4010         if (sim_do_echo)                                /* echo if -v */
4011             sim_printf("%s> %s\r\n", do_position(), cbuf);
4012         return SCPE_OK;
4013         }
4014     }
4015 sim_do_echo = saved_do_echo;                       /* restore echo mode         */
4016 fseek(sim_gotofile, fpos, SEEK_SET);               /* restore start position    */
4017 sim_goto_line[sim_do_depth] = saved_goto_line;     /* restore start line number */
4018 return SCPE_ARG;
4019 }
4020 
4021 /* Return command */
4022 
4023 /* The return command is invalid unless encountered in a do_cmd context,    */
4024 /* and in that context, it is handled as a special case inside of do_cmd()  */
4025 /* and not dispatched here, so if we get here a return has been issued from */
4026 /* interactive input */
4027 
4028 t_stat return_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4029 {
4030 return SCPE_UNK;                                 /* only valid inside of do_cmd */
4031 }
4032 
4033 /* Shift command */
4034 
4035 /* The shift command is invalid unless encountered in a do_cmd context,    */
4036 /* and in that context, it is handled as a special case inside of do_cmd() */
4037 /* and not dispatched here, so if we get here a shift has been issued from */
4038 /* interactive input (it is not valid interactively since it would have to */
4039 /* mess with the program's argv which is owned by the C runtime library    */
4040 
4041 t_stat shift_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4042 {
4043 return SCPE_UNK;                                 /* only valid inside of do_cmd */
4044 }
4045 
4046 /* Call command */
4047 
4048 /* The call command is invalid unless encountered in a do_cmd context,     */
4049 /* and in that context, it is handled as a special case inside of do_cmd() */
4050 /* and not dispatched here, so if we get here a call has been issued from  */
4051 /* interactive input                                                       */
4052 
4053 t_stat call_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4054 {
4055 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
4056 const char *cptr;
4057 
4058 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
4059 cptr = get_glyph (fcptr, gbuf, 0);
4060 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified goto target */
4061 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
4062 sim_switches |= SWMASK ('O');                           /* inherit ON state and actions */
4063 return do_cmd_label (flag, cbuf, gbuf);
4064 }
4065 
4066 /* On command */
4067 
4068 t_stat on_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4069 {
4070 char gbuf[CBUFSIZE];
4071 t_stat cond;
4072 
4073 cptr = get_glyph (cptr, gbuf, 0);
4074 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified condition */
4075 if (0 == strcmp("ERROR", gbuf))
4076     cond = 0;
4077 else
4078     if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4079         return SCPE_ARG;
4080 if ((NULL == cptr) || ('\0' == *cptr)) {                /* Empty Action */
4081     FREE(sim_on_actions[sim_do_depth][cond]);           /* Clear existing condition */
4082     sim_on_actions[sim_do_depth][cond] = NULL; }
4083 else {
4084     sim_on_actions[sim_do_depth][cond] =
4085         (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4086     if (!sim_on_actions[sim_do_depth][cond])
4087       {
4088         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4089                        __func__, __FILE__, __LINE__);
4090 #if defined(USE_BACKTRACE)
4091 # if defined(SIGUSR2)
4092         (void)raise(SIGUSR2);
4093         /*NOTREACHED*/ /* unreachable */
4094 # endif /* if defined(SIGUSR2) */
4095 #endif /* if defined(USE_BACKTRACE) */
4096         abort();
4097       }
4098     strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4099     }
4100 return SCPE_OK;
4101 }
4102 
4103 /* noop command */
4104 
4105 t_stat noop_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4106 {
4107 if (cptr && (*cptr != 0))                               /* now eol? */
4108     return SCPE_2MARG;
4109 return SCPE_OK;                                         /* we're happy doing nothing */
4110 }
4111 
4112 /* Set on/noon routine */
4113 
4114 t_stat set_on (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4115 {
4116 if ((flag) && (cptr) && (*cptr)) {                      /* Set ON with arg */
4117     char gbuf[CBUFSIZE];
4118 
4119     cptr = get_glyph (cptr, gbuf, 0);                   /* get command glyph */
4120     if (((MATCH_CMD(gbuf,"INHERIT")) &&
4121          (MATCH_CMD(gbuf,"NOINHERIT"))) || //-V600
4122         (*cptr))
4123         return SCPE_2MARG;
4124     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT"))) //-V560
4125         sim_on_inherit = 1;
4126     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT"))) //-V560
4127         sim_on_inherit = 0;
4128     return SCPE_OK;
4129     }
4130 if (cptr && (*cptr != 0))                               /* now eol? */
4131     return SCPE_2MARG;
4132 sim_on_check[sim_do_depth] = flag;
4133 if ((sim_do_depth != 0) &&
4134     (NULL == sim_on_actions[sim_do_depth][0])) {        /* default handler set? */
4135     sim_on_actions[sim_do_depth][0] =                   /* No, so make "RETURN" */
4136         (char *)malloc(1+strlen("RETURN"));             /* be the default action */
4137     strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4138     }
4139 if ((sim_do_depth != 0) &&
4140     (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {/* handler set for AFAIL? */
4141     sim_on_actions[sim_do_depth][SCPE_AFAIL] =           /* No, so make "RETURN" */
4142         (char *)malloc(1+strlen("RETURN"));              /* be the action */
4143     strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4144     }
4145 return SCPE_OK;
4146 }
4147 
4148 /* Set verify/noverify routine */
4149 
4150 t_stat set_verify (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4151 {
4152 if (cptr && (*cptr != 0))                               /* now eol? */
4153     return SCPE_2MARG;
4154 if (flag == sim_do_echo)                                /* already set correctly? */
4155     return SCPE_OK;
4156 sim_do_echo = flag;
4157 return SCPE_OK;
4158 }
4159 
4160 /* Set message/nomessage routine */
4161 
4162 t_stat set_message (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4163 {
4164 if (cptr && (*cptr != 0))                               /* now eol? */
4165     return SCPE_2MARG;
4166 if (flag == sim_show_message)                           /* already set correctly? */
4167     return SCPE_OK;
4168 sim_show_message = flag;
4169 return SCPE_OK;
4170 }
4171 
4172 /* Set localopc/nolocalopc routine */
4173 
4174 t_stat set_localopc (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4175 {
4176 if (cptr && (*cptr != 0))                               /* now eol? */
4177     return SCPE_2MARG;
4178 if (flag == sim_localopc)                               /* already set correctly? */
4179     return SCPE_OK;
4180 sim_localopc = flag;
4181 return SCPE_OK;
4182 }
4183 /* Set quiet/noquiet routine */
4184 
4185 t_stat set_quiet (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4186 {
4187 if (cptr && (*cptr != 0))                               /* now eol? */
4188     return SCPE_2MARG;
4189 if (flag == sim_quiet)                                  /* already set correctly? */
4190     return SCPE_OK;
4191 sim_quiet = flag;
4192 return SCPE_OK;
4193 }
4194 
4195 /* Set environment routine */
4196 
4197 t_stat sim_set_environment (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4198 {
4199 char varname[CBUFSIZE];
4200 
4201 if ((NULL == cptr) || (*cptr == 0))                            /* now eol? */
4202     return SCPE_2FARG;
4203 cptr = get_glyph (cptr, varname, '=');                  /* get environment variable name */
4204 setenv(varname, cptr, 1);
4205 return SCPE_OK;
4206 }
4207 
4208 /* Set command */
4209 
4210 t_stat set_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4211 {
4212 uint32 lvl = 0;
4213 t_stat r;
4214 char gbuf[CBUFSIZE], *cvptr;
4215 CONST char *svptr;
4216 DEVICE *dptr;
4217 UNIT *uptr;
4218 MTAB *mptr;
4219 CTAB *gcmdp;
4220 C1TAB *ctbr = NULL, *glbr;
4221 
4222 GET_SWITCHES (cptr);                                    /* get switches */
4223 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
4224     return SCPE_2FARG;
4225 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get glob/dev/unit */
4226 
4227 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4228     uptr = dptr->units;                                 /* first unit */
4229     ctbr = set_dev_tab;                                 /* global table */
4230     lvl = MTAB_VDV;                                     /* device match */
4231     GET_SWITCHES (cptr);                                /* get more switches */
4232     }
4233 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4234     if (uptr == NULL)                                   /* invalid unit */
4235         return SCPE_NXUN;
4236     ctbr = set_unit_tab;                                /* global table */
4237     lvl = MTAB_VUN;                                     /* unit match */
4238     GET_SWITCHES (cptr);                                /* get more switches */
4239     }
4240 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {    /* global? */
4241     GET_SWITCHES (cptr);                                /* get more switches */
4242     return gcmdp->action (gcmdp->arg, cptr);            /* do the rest */
4243     }
4244 else {
4245     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4246         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4247             *cvptr++ = 0;
4248         for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4249             if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4250                 dptr = sim_dflt_dev;
4251                 cptr = svptr;
4252                 while (sim_isspace(*cptr))
4253                     ++cptr;
4254                 break;
4255                 }
4256             }
4257         }
4258     if (!dptr)
4259         return SCPE_NXDEV;                              /* no match */
4260     lvl = MTAB_VDV;                                     /* device match */
4261     uptr = dptr->units;                                 /* first unit */
4262     }
4263 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4264     return SCPE_2FARG;
4265 GET_SWITCHES (cptr);                                    /* get more switches */
4266 
4267 while (*cptr != 0) {                                    /* do all mods */
4268     cptr = get_glyph (svptr = cptr, gbuf, ',');         /* get modifier */
4269     if (0 == strcmp (gbuf, ";"))
4270         break;
4271     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4272         *cvptr++ = 0;
4273     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4274         if ((mptr->mstring) &&                          /* match string */
4275             (MATCH_CMD (gbuf, mptr->mstring) == 0)) {   /* matches option? */
4276             if (mptr->mask & MTAB_XTD) {                /* extended? */
4277                 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4278                     return SCPE_ARG;
4279                 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4280                     return SCPE_UDIS;                   /* unit disabled? */
4281                 if (mptr->valid) {                      /* validation rtn? */
4282                     if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4283                         svptr = get_glyph_quoted (svptr, gbuf, ',');
4284                         if ((cvptr = strchr (gbuf, '='))) {
4285                             *cvptr++ = 0;
4286                             cptr = svptr;
4287                             }
4288                         }
4289                     else {
4290                         if (cvptr && MODMASK(mptr,MTAB_NC)) {
4291                             (void)get_glyph_nc (svptr, gbuf, ',');
4292                             if ((cvptr = strchr (gbuf, '=')))
4293                                 *cvptr++ = 0;
4294                             }
4295                         }
4296                     r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4297                     if (r != SCPE_OK)
4298                         return r;
4299                     }
4300                 else if (!mptr->desc)                   /* value desc? */
4301                     break;
4302                 else if (cvptr)                         /* = value? */
4303                     return SCPE_ARG;
4304                 else *((int32 *) mptr->desc) = mptr->match;
4305                 }                                       /* end if xtd */
4306             else {                                      /* old style */
4307                 if (cvptr)                              /* = value? */
4308                     return SCPE_ARG;
4309                 if (uptr->flags & UNIT_DIS)             /* disabled? */
4310                      return SCPE_UDIS;
4311                 if ((mptr->valid) &&                    /* invalid? */
4312                     ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4313                     return r;
4314                 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4315                     (mptr->match & mptr->mask);         /* set new value */
4316                 }                                       /* end else xtd */
4317             break;                                      /* terminate for */
4318             }                                           /* end if match */
4319         }                                               /* end for */
4320     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4321         if ((glbr = find_c1tab (ctbr, gbuf))) {         /* global match? */
4322             r = glbr->action (dptr, uptr, glbr->arg, cvptr);    /* do global */
4323             if (r != SCPE_OK)
4324                 return r;
4325             }
4326         else if (!dptr->modifiers)                      /* no modifiers? */
4327             return SCPE_NOPARAM;
4328         else return SCPE_NXPAR;
4329         }                                               /* end if no mat */
4330     }                                                   /* end while */
4331 return SCPE_OK;                                         /* done all */
4332 }
4333 
4334 /* Match CTAB/CTAB1 name */
4335 
4336 CTAB *find_ctab (CTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4337 {
4338 if (!tab)
4339     return NULL;
4340 for (; tab->name != NULL; tab++) {
4341     if (MATCH_CMD (gbuf, tab->name) == 0)
4342         return tab;
4343     }
4344 return NULL;
4345 }
4346 
4347 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4348 {
4349 if (!tab)
4350     return NULL;
4351 for (; tab->name != NULL; tab++) {
4352     if (MATCH_CMD (gbuf, tab->name) == 0)
4353         return tab;
4354     }
4355 return NULL;
4356 }
4357 
4358 /* Set device data radix routine */
4359 
4360 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4361 {
4362 if (cptr)
4363     return SCPE_ARG;
4364 dptr->dradix = flag & 037;
4365 return SCPE_OK;
4366 }
4367 
4368 /* Set device enabled/disabled routine */
4369 
4370 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4371 {
4372 UNIT *up;
4373 uint32 i;
4374 
4375 if (cptr)
4376     return SCPE_ARG;
4377 if ((dptr->flags & DEV_DISABLE) == 0)                   /* allowed? */
4378     return SCPE_NOFNC;
4379 if (flag) {                                             /* enable? */
4380     if ((dptr->flags & DEV_DIS) == 0)                   /* already enb? ok */
4381         return SCPE_OK;
4382     dptr->flags = dptr->flags & ~DEV_DIS;               /* no, enable */
4383     }
4384 else {
4385     if (dptr->flags & DEV_DIS)                          /* already dsb? ok */
4386         return SCPE_OK;
4387     for (i = 0; i < dptr->numunits; i++) {              /* check units */
4388         up = (dptr->units) + i;                         /* att or active? */
4389         if ((up->flags & UNIT_ATT) || sim_is_active (up))
4390             return SCPE_NOFNC;                          /* can't do it */
4391         }
4392     dptr->flags = dptr->flags | DEV_DIS;                /* disable */
4393     }
4394 if (dptr->reset)                                        /* reset device */
4395     return dptr->reset (dptr);
4396 else return SCPE_OK;
4397 }
4398 
4399 /* Set unit enabled/disabled routine */
4400 
4401 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4402 {
4403 if (cptr)
4404     return SCPE_ARG;
4405 if (!(uptr->flags & UNIT_DISABLE))                      /* allowed? */
4406     return SCPE_NOFNC;
4407 if (flag)                                               /* enb? enable */
4408     uptr->flags = uptr->flags & ~UNIT_DIS;
4409 else {
4410     if ((uptr->flags & UNIT_ATT) ||                     /* dsb */
4411         sim_is_active (uptr))                           /* more tests */
4412         return SCPE_NOFNC;
4413     uptr->flags = uptr->flags | UNIT_DIS;               /* disable */
4414     }
4415 return SCPE_OK;
4416 }
4417 
4418 /* Set device debug enabled/disabled routine */
4419 
4420 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4421 {
4422 char gbuf[CBUFSIZE];
4423 DEBTAB *dep;
4424 
4425 if ((dptr->flags & DEV_DEBUG) == 0)
4426     return SCPE_NOFNC;
4427 if (cptr == NULL) {                                     /* no arguments? */
4428     dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;/* disable/enable w/o table */
4429     if (flag && dptr->debflags) {                       /* enable with table? */
4430         for (dep = dptr->debflags; dep->name != NULL; dep++)
4431             dptr->dctrl = dptr->dctrl | dep->mask;      /* set all */
4432         }
4433     return SCPE_OK;
4434     }
4435 if (dptr->debflags == NULL)                             /* must have table */
4436     return SCPE_ARG;
4437 while (*cptr) {
4438     cptr = get_glyph (cptr, gbuf, ';');                 /* get debug flag */
4439     for (dep = dptr->debflags; dep->name != NULL; dep++) {
4440         if (strcmp (dep->name, gbuf) == 0) {            /* match? */
4441             if (flag)
4442                 dptr->dctrl = dptr->dctrl | dep->mask;
4443             else dptr->dctrl = dptr->dctrl & ~dep->mask;
4444             break;
4445             }
4446         }                                               /* end for */
4447     if (dep->mask == 0)                                 /* no match? */
4448         return SCPE_ARG;
4449     }                                                   /* end while */
4450 return SCPE_OK;
4451 }
4452 
4453 /* Show command */
4454 
4455 t_stat show_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4456 {
4457 t_stat r = SCPE_IERR;
4458 
4459 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4460                                                         /* get sw, ofile */
4461 if (NULL == cptr)                                              /* error? */
4462     return r;
4463 if (sim_ofile) {                                        /* output file? */
4464     r = show_cmd_fi (sim_ofile, flag, cptr);            /* do show */
4465     fclose (sim_ofile);
4466     }
4467 else {
4468     r = show_cmd_fi (stdout, flag, cptr);               /* no, stdout, log */
4469     if (sim_log && (sim_log != stdout))
4470         show_cmd_fi (sim_log, flag, cptr);
4471     if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4472         show_cmd_fi (sim_deb, flag, cptr);
4473     }
4474 return r;
4475 }
4476 
4477 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4478 {
4479 uint32 lvl = 0xFFFFFFFF;
4480 char gbuf[CBUFSIZE], *cvptr;
4481 CONST char *svptr;
4482 DEVICE *dptr;
4483 UNIT *uptr;
4484 MTAB *mptr;
4485 SHTAB *shtb = NULL, *shptr;
4486 
4487 GET_SWITCHES (cptr);                                    /* get switches */
4488 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4489     return SCPE_2FARG;
4490 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get next glyph */
4491 
4492 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4493     uptr = dptr->units;                                 /* first unit */
4494     shtb = show_dev_tab;                                /* global table */
4495     lvl = MTAB_VDV;                                     /* device match */
4496     GET_SWITCHES (cptr);                                /* get more switches */
4497     }
4498 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4499     if (uptr == NULL)                                   /* invalid unit */
4500         return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\r\n", gbuf);
4501     if (uptr->flags & UNIT_DIS)                         /* disabled? */
4502         return sim_messagef (SCPE_UDIS, "Unit disabled: %s\r\n", gbuf);
4503     shtb = show_unit_tab;                               /* global table */
4504     lvl = MTAB_VUN;                                     /* unit match */
4505     GET_SWITCHES (cptr);                                /* get more switches */
4506     }
4507 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {  /* global? */
4508     GET_SWITCHES (cptr);                                /* get more switches */
4509     return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4510     }
4511 else {
4512     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4513         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4514             *cvptr++ = 0;
4515         for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4516             if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4517                  (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) || //-V600
4518                 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4519                 dptr = sim_dflt_dev;
4520                 lvl = MTAB_VDV;                         /* device match */
4521                 cptr = svptr;
4522                 while (sim_isspace(*cptr))
4523                     ++cptr;
4524                 break;
4525                 }
4526             }
4527         }
4528     if (!dptr) {
4529         if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))  /* global match? */
4530             return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4531         else
4532             return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\r\n", gbuf);/* no match */
4533         }
4534     }
4535 
4536 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) { /* now eol? */
4537     return (lvl == MTAB_VDV)?
4538         show_device (ofile, dptr, 0):
4539         show_unit (ofile, dptr, uptr, -1);
4540     }
4541 GET_SWITCHES (cptr);                                    /* get more switches */
4542 
4543 while (*cptr != 0) {                                    /* do all mods */
4544     cptr = get_glyph (cptr, gbuf, ',');                 /* get modifier */
4545     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4546         *cvptr++ = 0;
4547     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4548         if (((mptr->mask & MTAB_XTD)?                   /* right level? */
4549             ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4550             ((mptr->disp && mptr->pstring &&            /* named disp? */
4551             (MATCH_CMD (gbuf, mptr->pstring) == 0))
4552             )) {
4553             if (cvptr && !MODMASK(mptr,MTAB_SHP))
4554                 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\r\n", gbuf, cvptr);
4555             show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4556             break;
4557             }                                           /* end if */
4558         }                                               /* end for */
4559     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4560         if (shtb && (shptr = find_shtab (shtb, gbuf))) {/* global match? */
4561             t_stat r;
4562 
4563             r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4564             if (r != SCPE_OK)
4565                 return r;
4566             }
4567         else {
4568             if (!dptr->modifiers)                       /* no modifiers? */
4569                 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\r\n", dptr->name);
4570             else
4571                 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\r\n", gbuf);
4572             }
4573         }                                               /* end if */
4574     }                                                   /* end while */
4575 return SCPE_OK;
4576 }
4577 
4578 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4579 {
4580 if (!tab)
4581     return NULL;
4582 for (; tab->name != NULL; tab++) {
4583     if (MATCH_CMD (gbuf, tab->name) == 0)
4584         return tab;
4585     }
4586 return NULL;
4587 }
4588 
4589 /* Show device and unit */
4590 
4591 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4592 {
4593 uint32 j, udbl, ucnt;
4594 UNIT *uptr;
4595 int32 toks = 0;
4596 
4597 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4598 (void)fprintf (st, "%s", sim_dname (dptr));                   /* print dev name */
4599 if ((flag == 2) && dptr->description) {
4600     (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4601     }
4602 else {
4603     if ((sim_switches & SWMASK ('D')) && dptr->description)
4604         (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4605     }
4606 if (qdisable (dptr)) {                                  /* disabled? */
4607     (void)fprintf (st, "\tdisabled\r\n");
4608     return SCPE_OK;
4609     }
4610 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {    /* count units */
4611     uptr = dptr->units + j;
4612     if (!(uptr->flags & UNIT_DIS))                      /* count enabled units */
4613         ucnt++;
4614     else if (uptr->flags & UNIT_DISABLE)
4615         udbl++;                                         /* count user-disabled */
4616     }
4617 //show_all_mods (st, dptr, dptr->units, MTAB_VDV, &toks); /* show dev mods */
4618 if (dptr->numunits == 0) {
4619     // if (toks) //-V547
4620     //     (void)fprintf (st, "\r\n");
4621 }
4622  else
4623 {
4624     if (ucnt == 0) {
4625         fprint_sep (st, &toks);
4626         (void)fprintf (st, "all units disabled\r\n");
4627         }
4628     else if ((ucnt + udbl) == 1) {
4629         fprint_sep (st, &toks);
4630         (void)fprintf (st, " 1 unit\r\n");
4631         }
4632     else if ((ucnt > 1) || (udbl > 0)) {
4633         fprint_sep (st, &toks);
4634         (void)fprintf (st, "%2.d units\r\n", ucnt + udbl);
4635         }
4636     else
4637         if ((flag != 2) || !dptr->description || toks)
4638             (void)fprintf (st, "\r\n");
4639     toks = 0;
4640 }
4641 if (flag)                                               /* dev only? */
4642     return SCPE_OK;
4643 for (j = 0; j < dptr->numunits; j++) {                  /* loop thru units */
4644     uptr = dptr->units + j;
4645     if ((uptr->flags & UNIT_DIS) == 0)
4646         show_unit (st, dptr, uptr, ucnt + udbl);
4647     }
4648 }
4649 return SCPE_OK;
4650 }
4651 
4652 void fprint_sep (FILE *st, int32 *tokens)
     /* [previous][next][first][last][top][bottom][index][help] */
4653 {
4654 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4655 *tokens += 1;
4656 }
4657 
4658 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4659 {
4660 int32 u = (int32)(uptr - dptr->units);
4661 int32 toks = 0;
4662 
4663 if (flag > 1)
4664     (void)fprintf (st, "   %s%d\r\n", sim_dname (dptr), u);
4665 else if (flag < 0)
4666     (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4667 if (uptr->flags & UNIT_ATT) {
4668     fprint_sep (st, &toks);
4669     (void)fprintf (st, "status   : attached to %s", uptr->filename);
4670     if (uptr->flags & UNIT_RO)
4671         (void)fprintf (st, ", read only");
4672     }
4673 else {
4674     if (uptr->flags & UNIT_ATTABLE) {
4675         fprint_sep (st, &toks);
4676         (void)fprintf (st, "status   : not attached");
4677         }
4678     }
4679 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4680     fprint_sep (st, &toks);
4681     fprint_capac (st, dptr, uptr);
4682     }
4683 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);        /* show unit mods */
4684 if (toks || (flag < 0) || (flag > 1))
4685     (void)fprintf (st, "\r\n");
4686 return SCPE_OK;
4687 }
4688 
4689 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4690 {
4691 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4692 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4693 t_offset mval;
4694 t_offset psize = (t_offset)uptr->capac;
4695 char *scale, *width;
4696 
4697 if (sim_switches & SWMASK ('B'))
4698     kval = 1024;
4699 mval = kval * kval;
4700 if (dptr->flags & DEV_SECTORS) {
4701     kval = kval / 512;
4702     mval = mval / 512;
4703     }
4704 if ((dptr->dwidth / dptr->aincr) > 8)
4705     width = "W";
4706 else
4707     width = "B";
4708 if ((psize < (kval * 10)) &&
4709     (0 != (psize % kval))) {
4710     scale = "";
4711     }
4712 else if ((psize < (mval * 10)) &&
4713          (0 != (psize % mval))){
4714     scale = "K";
4715     psize = psize / kval;
4716     }
4717 else {
4718     scale = "M";
4719     psize = psize / mval;
4720     }
4721 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4722 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4723 return capac_buf;
4724 }
4725 
4726 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4727 {
4728 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4729 }
4730 
4731 /* Show <global name> processors  */
4732 
4733 extern void print_default_base_system_script (void);
4734 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] */
4735 {
4736 #if !defined(PERF_STRIP)
4737   print_default_base_system_script();
4738 #endif /* if !defined(PERF_STRIP) */
4739   return 0;
4740 }
4741 
4742 static void printp (unsigned char * PROM, char * label, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4743   sim_printf (" %s ", label);
4744   sim_printf ("   %2d     %3o(8)     '", length, offset);
4745   for (int l = 0; l < length; l ++)
4746     {
4747       unsigned int byte = PROM[offset + l];
4748       if (byte == 255)
4749         {
4750           byte = ' ';
4751         }
4752       sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4753     }
4754   sim_printf ("'\r\n");
4755 }
4756 
4757 static void strip_spaces(char* str) {
     /* [previous][next][first][last][top][bottom][index][help] */
4758   int i, x;
4759   for (i=x=0; str[i]; ++i)
4760     {
4761       if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)]))) //-V781
4762         {
4763           str[x++] = str[i];
4764         }
4765     }
4766   str[x] = '\0';
4767   i = -1;
4768   x = 0;
4769   while (str[x] != '\0')
4770     {
4771       if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4772         {
4773           i=x;
4774         }
4775       x++;
4776     }
4777   str[i+1] = '\0';
4778 }
4779 
4780 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4781   char sx[1024];
4782   sx[1023] = '\0';
4783   unsigned int lastbyte = 0;
4784   for (int l = 0; l < length; l ++)
4785     {
4786       unsigned int byte = PROM[offset + l];
4787       if (byte == 255)
4788         {
4789           byte = 20;
4790         }
4791       if ((lastbyte != 20) && (byte != 20))
4792         {
4793           (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4794         }
4795       lastbyte = byte;
4796     }
4797   strip_spaces(sx);
4798   (void)fprintf (st, "%s", sx);
4799 }
4800 
4801 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4802 {
4803   unsigned char PROM[1024];
4804   setupPROM (0, PROM);
4805 
4806   sim_printf (" PROM size: %llu bytes\r\n",
4807               (long long unsigned)sizeof(PROM));
4808   sim_printf (" PROM initialization data:\r\n\r\n");
4809 
4810   sim_printf ("     Field Description      Length   Offset              Contents\r\n");
4811   sim_printf (" ========================= ======== ======== ==================================\r\n");
4812   sim_printf ("\r\n");
4813 
4814   //                      Field                 Offset       Length
4815   //             -------------------------    ----------   ----------
4816   printp (PROM, "CPU Model                ",       0,          11);
4817   printp (PROM, "CPU Serial               ",      11,          11);
4818   printp (PROM, "Ship Date                ",      22,           6);
4819   printp (PROM, "PROM Layout Version      ",      60,           1);
4820   printp (PROM, "Release Git Commit Date  ",      70,          10);
4821   printp (PROM, "Release Major            ",      80,           3);
4822   printp (PROM, "Release Minor            ",      83,           3);
4823   printp (PROM, "Release Patch            ",      86,           3);
4824   printp (PROM, "Release Iteration        ",      89,           3);
4825   printp (PROM, "Release Build Number     ",      92,           8);  /* Reserved */
4826   printp (PROM, "Release Type             ",     100,           1);
4827   printp (PROM, "Release Version Text     ",     101,          29);
4828   printp (PROM, "Build Architecture       ",     130,          20);
4829   printp (PROM, "Build Operating System   ",     150,          20);
4830   printp (PROM, "Target Architecture      ",     170,          20);
4831   printp (PROM, "Target Operating System  ",     190,          20);
4832 
4833   sim_printf("\r\n");
4834   return 0;
4835 }
4836 
4837 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4838 {
4839     (void)fprintf (st, "\r Build Information:\r\n");
4840 #if defined(BUILDINFO_scp)
4841     (void)fprintf (st, "\r\n      Compilation info: %s\r\n", BUILDINFO_scp );
4842 #else
4843     (void)fprintf (st, "\r\n      Compilation info: Not available\r\n" );
4844 #endif
4845 #if !defined(__CYGWIN__)
4846 # if !defined(__APPLE__)
4847 #  if !defined(_AIX)
4848 #   if !defined(__MINGW32__)
4849 #    if !defined(__MINGW64__)
4850 #     if !defined(CROSS_MINGW32)
4851 #      if !defined(CROSS_MINGW64)
4852 #       if !defined(_WIN32)
4853 #        if !defined(__HAIKU__)
4854 #         if !defined(__QNX__)
4855 #          if !defined(__FILC__)
4856     (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4857     if (dl_iterate_phdr_callback_called)
4858         (void)fprintf (st, "\r\n");
4859     dl_iterate_phdr_callback_called = 0;
4860 #          endif
4861 #         endif
4862 #        endif
4863 #       endif
4864 #      endif
4865 #     endif
4866 #    endif
4867 #   endif
4868 #  endif
4869 # endif
4870 #endif
4871 #if defined(UV_VERSION_MAJOR) && \
4872     defined(UV_VERSION_MINOR) && \
4873     defined(UV_VERSION_PATCH)
4874 # if defined(UV_VERSION_MAJOR)
4875 #  if !defined(UV_VERSION_MINOR) && \
4876       !defined(UV_VERSION_PATCH) && \
4877       !defined(UV_VERSION_SUFFIX)
4878     (void)fprintf (st, "\r\n    Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4879 #  endif /* if !defined(UV_VERSION_MINOR) && !defined(UV_VERSION_PATCH) && defined(UV_VERSION_SUFFIX) */
4880 #  if defined(UV_VERSION_MINOR)
4881 #   if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4882     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4883                    UV_VERSION_MINOR);
4884 #   endif /* if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX) */
4885 #   if defined(UV_VERSION_PATCH)
4886 #    if !defined(UV_VERSION_SUFFIX)
4887     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4888                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4889 #    endif /* if !defined(UV_VERSION_SUFFIX) */
4890 #    if defined(UV_VERSION_SUFFIX)
4891     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4892                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4893 #     if defined(UV_VERSION_IS_RELEASE)
4894 #      if UV_VERSION_IS_RELEASE == 1
4895 #       define UV_RELEASE_TYPE " (release)"
4896 #      endif /* if UV_VERSION_IS_RELEASE == 1 */
4897 #      if UV_VERSION_IS_RELEASE == 0
4898 #       define UV_RELEASE_TYPE "-dev"
4899 #      endif /* if UV_VERSION_IS_RELEASE == 0 */
4900 #      if !defined(UV_RELEASE_TYPE)
4901 #       define UV_RELEASE_TYPE ""
4902 #      endif /* if !defined(UV_RELEASE_TYPE) */
4903 #      if defined(UV_RELEASE_TYPE)
4904     (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4905 #      endif /* if defined(UV_RELEASE_TYPE) */
4906 #     endif /* if defined(UV_VERSION_IS_RELEASE) */
4907 #    endif /* if defined(UV_VERSION_SUFFIX) */
4908 #   endif /* if defined(UV_VERSION_PATCH) */
4909 #  endif /* if defined(UV_VERSION_MINOR) */
4910     unsigned int CurrentUvVersion = uv_version();
4911     if (CurrentUvVersion > 0)
4912         if (uv_version_string() != NULL)
4913             (void)fprintf (st, "; %s in use", uv_version_string());
4914 # endif /* if defined(UV_VERSION_MAJOR) */
4915 #else
4916     (void)fprintf (st, "\r\n    Event loop library: Using libuv (or compatible) library, unknown version");
4917 #endif /* if defined(UV_VERSION_MAJOR) &&  \
4918         *    defined(UV_VERSION_MINOR) &&  \
4919         *    defined(UV_VERSION_PATCH)     \
4920         */
4921     (void)fprintf (st, "\r\n   Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4922                    SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4923                    SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4924                    sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4925 #if defined(DECNUMBERLOC)
4926 # if defined(DECVERSION)
4927 #  if defined(DECVERSEXT)
4928     (void)fprintf (st, "\r\n          Math library: %s-%s", DECVERSION, DECVERSEXT);
4929 #  else
4930 #   if defined(DECNLAUTHOR)
4931     (void)fprintf (st, "\r\n          Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4932 #   else
4933     (void)fprintf (st, "\r\n          Math library: %s", DECVERSION);
4934 #   endif /* if defined(DECNLAUTHOR) */
4935 #  endif /* if defined(DECVERSEXT) */
4936 # else
4937     (void)fprintf (st, "\r\n          Math library: decNumber, unknown version");
4938 # endif /* if defined(DECVERSION) */
4939 #endif /* if defined(DECNUMBERLOC) */
4940 #if defined(LOCKLESS)
4941     (void)fprintf (st, "\r\n     Atomic operations: ");
4942 # if defined(AIX_ATOMICS)
4943     (void)fprintf (st, "C11 and IBM AIX-style");
4944 # elif defined(BSD_ATOMICS)
4945     (void)fprintf (st, "C11 and FreeBSD-style");
4946 # elif defined(GNU_ATOMICS)
4947     (void)fprintf (st, "C11 and GNU-style");
4948 # elif defined(SYNC_ATOMICS)
4949     (void)fprintf (st, "C11 and GNU sync-style");
4950 # elif defined(ISO_ATOMICS)
4951     (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4952 # elif defined(NT_ATOMICS)
4953     (void)fprintf (st, "C11 and Windows NT interlocked operations");
4954 # endif
4955 #endif /* if defined(LOCKLESS) */
4956     (void)fprintf (st, "\r\n          File locking: ");
4957 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4958     (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4959 #endif
4960 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4961     (void)fprintf (st, "POSIX-style fcntl() locking");
4962 #endif
4963 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4964     (void)fprintf (st, "BSD-style flock() locking");
4965 #endif
4966 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4967     (void)fprintf (st, "No file locking available");
4968 #endif
4969 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64) || defined(__CYGWIN__)
4970     (void)fprintf (st, "\r\n       Windows support: ");
4971 #endif
4972 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4973 # if defined(__MINGW64_VERSION_STR)
4974     (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
4975 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
4976     (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
4977 # else
4978     (void)fprintf (st, "Built with MinGW");
4979 # endif
4980 
4981 # if defined(MINGW_CRT)
4982     (void)fprintf (st, "; %s", MINGW_CRT);
4983 #  if !defined(_UCRT)
4984 #   if defined(__MSVCRT_VERSION__)
4985 #    if __MSVCRT_VERSION__ > 0x00
4986     (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
4987 #    endif
4988 #   endif
4989 #  else
4990 
4991     struct UCRTVersion ucrtversion;
4992     int result = GetUCRTVersion (&ucrtversion);
4993 
4994     if (result == 0)
4995       (void)fprintf (st, " %u.%u.%u.%u",
4996                      ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
4997                      ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
4998 #  endif
4999     (void)fprintf (st, " in use");
5000 # endif
5001 #elif defined(__CYGWIN__)
5002     struct utsname utsname;
5003     (void)fprintf (st, "Built with Cygwin %d.%d.%d",
5004                    CYGWIN_VERSION_DLL_MAJOR / 1000,
5005                    CYGWIN_VERSION_DLL_MAJOR % 1000,
5006                    CYGWIN_VERSION_DLL_MINOR);
5007     if (uname(&utsname) == 0)
5008       fprintf (st, "; %s in use", utsname.release);
5009 #endif
5010 
5011     (void)fprintf (st, "\r\n");
5012     return 0;
5013 }
5014 
5015 static void
5016 removehex(char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
5017 {
5018   if (!s) return;
5019 
5020   size_t len = strlen(s);
5021   for (size_t i = 0; i < len; i++) {
5022     if (s[i] != ' ')
5023      continue;
5024 
5025     if ((len - i) < 41)
5026       continue;
5027 
5028     size_t j;
5029     for (j = 1; j <= 40; j++) {
5030       unsigned char uc = (unsigned char)s[i + j];
5031       if (!isxdigit(uc))
5032         break;
5033     }
5034 
5035     if (j == 41) {
5036       memmove(&s[i], &s[i + 41], strlen(&s[i + 41]) + 1);
5037       return;
5038     }
5039   }
5040 }
5041 
5042 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5043 {
5044 const char *arch = "";
5045 char *whydirty = " ";
5046 int dirty = 0;
5047 
5048 if (cptr && (*cptr != 0))
5049     return SCPE_2MARG;
5050 if (flag) {
5051         (void)fprintf (st, " %s Simulator:", sim_name);
5052 #if defined(USE_DUMA)
5053 # undef NO_SUPPORT_VERSION
5054 # define NO_SUPPORT_VERSION 1
5055         nodist++;
5056 #endif /* if defined(USE_DUMA) */
5057 #if defined(NO_SUPPORT_VERSION) ||  \
5058     defined(WITH_SOCKET_DEV)    ||  \
5059     defined(WITH_ABSI_DEV)      ||  \
5060     defined(WITH_MGP_DEV)       ||  \
5061     defined(TESTING)            ||  \
5062     defined(ISOLTS)             ||  \
5063     defined(USE_DUMA)
5064 # if !defined(NO_SUPPORT_VERSION)
5065 #  define NO_SUPPORT_VERSION 1
5066 # endif /* if !defined(NO_SUPPORT_VERSION) */
5067 #endif
5068 #if defined(NO_SUPPORT_VERSION)
5069         dirty++;
5070 #endif
5071 #if defined(GENERATED_MAKE_VER_H)
5072 # if defined(VER_H_GIT_VERSION)
5073 
5074         /* Dirty if git source is dirty */
5075         if (strstr(VER_H_GIT_VERSION, "*"))
5076           {
5077                 dirty++;
5078           }
5079 
5080         /* Dirty if version contains "X", "D", "A", or "B" */
5081         if ((strstr(VER_H_GIT_VERSION, "X")) ||  \
5082             (strstr(VER_H_GIT_VERSION, "D")) ||  \
5083             (strstr(VER_H_GIT_VERSION, "A")) ||  \
5084             (strstr(VER_H_GIT_VERSION, "B")))
5085           {
5086                 dirty++;
5087           }
5088 
5089         /* Why? */
5090         if (dirty) //-V547
5091           {
5092             if ((strstr(VER_H_GIT_VERSION, "X")))
5093               {
5094                     whydirty = " ";
5095               }
5096             else if ((strstr(VER_H_GIT_VERSION, "D")))
5097               {
5098                     whydirty = " DEV ";
5099               }
5100             else if ((strstr(VER_H_GIT_VERSION, "A")))
5101               {
5102                     whydirty = " ALPHA ";
5103               }
5104             else if ((strstr(VER_H_GIT_VERSION, "B")))
5105               {
5106                     whydirty = " BETA ";
5107               }
5108           }
5109 
5110 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5111 #   if defined(VER_H_GIT_HASH)
5112 #    if VER_H_GIT_PATCH_INT < 1
5113     (void)fprintf (st, "\r\n   Version: %s (%ld-bit)\r\n    Commit: %s",
5114                    VER_H_GIT_VERSION,
5115                    (long)(CHAR_BIT*sizeof(void *)),
5116                    VER_H_GIT_HASH);
5117 #    else
5118 #     define NO_SUPPORT_VERSION 1
5119     (void)fprintf (st, "\r\n   Version: %s+%s (%ld-bit)\r\n    Commit: %s",
5120                    VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5121                    (long)(CHAR_BIT*sizeof(void *)),
5122                    VER_H_GIT_HASH);
5123 #    endif
5124 #   else
5125 #    if VER_H_GIT_PATCH_INT < 1
5126         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)",
5127                        VER_H_GIT_VERSION,
5128                        (long)(CHAR_BIT*sizeof(void *)));
5129 #    else
5130 #     define NO_SUPPORT_VERSION 1
5131         (void)fprintf (st, "\r\n   Version: %s+%s (%ld-bit)",
5132                        VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5133                        (long)(CHAR_BIT*sizeof(void *)));
5134 #    endif
5135 #   endif
5136 #  else
5137 #   if defined(VER_H_GIT_HASH)
5138         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)\r\n    Commit: %s",
5139                        VER_H_GIT_VERSION,
5140                        (long)(CHAR_BIT*sizeof(void *)),
5141                        VER_H_GIT_HASH);
5142 #   else
5143         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)",
5144                        VER_H_GIT_VERSION,
5145                        (long)(CHAR_BIT*sizeof(void *)));
5146 #   endif
5147 #  endif
5148 # endif
5149 #endif
5150 
5151 /* TESTING */
5152 #if defined(TESTING)
5153     (void)fprintf (st, "\r\n   Options: ");
5154 # if !defined(HAVE_DPSOPT)
5155 #  define HAVE_DPSOPT 1
5156 # endif
5157     (void)fprintf (st, "TESTING");
5158 #endif /* if defined(TESTING) */
5159 
5160 /* ISOLTS */
5161 #if defined(ISOLTS)
5162 # if defined(HAVE_DPSOPT)
5163     (void)fprintf (st, ", ");
5164 # else
5165     (void)fprintf (st, "\r\n   Options: ");
5166 # endif
5167 # if !defined(HAVE_DPSOPT)
5168 #  define HAVE_DPSOPT 1
5169 # endif
5170     (void)fprintf (st, "ISOLTS");
5171 #endif /* if defined(ISOLTS) */
5172 
5173 /* NEED_128 */
5174 #if defined(NEED_128)
5175 # if defined(HAVE_DPSOPT)
5176     (void)fprintf (st, ", ");
5177 # else
5178     (void)fprintf (st, "\r\n   Options: ");
5179 # endif
5180 # if !defined(HAVE_DPSOPT)
5181 #  define HAVE_DPSOPT 1
5182 # endif
5183     (void)fprintf (st, "NEED_128");
5184 #endif /* if defined(NEED_128) */
5185 
5186 /* NO_LOCKLESS */
5187 #if !defined(LOCKLESS)
5188 # if defined(HAVE_DPSOPT)
5189     (void)fprintf (st, ", ");
5190 # else
5191     (void)fprintf (st, "\r\n   Options: ");
5192 # endif
5193 # if !defined(HAVE_DPSOPT)
5194 #  define HAVE_DPSOPT 1
5195 # endif
5196     (void)fprintf (st, "NO_LOCKLESS");
5197 #endif /* if !defined(LOCKLESS) */
5198 
5199 /* PANEL68 */
5200 #if defined(PANEL68)
5201 # if defined(HAVE_DPSOPT)
5202     (void)fprintf (st, ", ");
5203 # else
5204     (void)fprintf (st, "\r\n Options: ");
5205 # endif
5206 # if !defined(HAVE_DPSOPT)
5207 #  define HAVE_DPSOPT 1
5208 # endif
5209     (void)fprintf (st, "PANEL68");
5210 #endif /* if defined(PANEL68) */
5211 
5212 /* ABSI */  /* XXX: Change to NO_ABSI once code is non-experimental */
5213 #if defined(WITH_ABSI_DEV)
5214 # if defined(HAVE_DPSOPT)
5215     (void)fprintf (st, ", ");
5216 # else
5217     (void)fprintf (st, "\r\n   Options: ");
5218 # endif
5219 # if !defined(HAVE_DPSOPT)
5220 #  define HAVE_DPSOPT 1
5221 # endif
5222     (void)fprintf (st, "ABSI");
5223 #endif /* if defined(WITH_ABSI_DEV) */
5224 
5225 /* SOCKET */  /* XXX: Change to NO_SOCKET once code is non-experimental */
5226 #if defined(WITH_SOCKET_DEV)
5227 # if defined(HAVE_DPSOPT)
5228     (void)fprintf (st, ", ");
5229 # else
5230     (void)fprintf (st, "\r\n   Options: ");
5231 # endif
5232 # if !defined(HAVE_DPSOPT)
5233 #  define HAVE_DPSOPT 1
5234 # endif
5235     (void)fprintf (st, "SOCKET");
5236 #endif /* if defined(WITH_SOCKET_DEV) */
5237 
5238 /* CHAOSNET */  /* XXX: Change to NO_CHAOSNET once code is non-experimental */
5239 #if defined(WITH_MGP_DEV)
5240 # if defined(HAVE_DPSOPT)
5241     (void)fprintf (st, ", ");
5242 # else
5243     (void)fprintf (st, "\r\n   Options: ");
5244 # endif
5245 # if !defined(HAVE_DPSOPT)
5246 #  define HAVE_DPSOPT 1
5247 # endif
5248     (void)fprintf (st, "CHAOSNET");
5249 # if USE_SOCKET_DEV_APPROACH
5250     (void)fprintf (st, "-S");
5251 # endif /* if USE_SOCKET_DEV_APPROACH */
5252 #endif /* if defined(WITH_MGP_DEV) */
5253 
5254 /* DUMA */
5255 #if defined(USE_DUMA)
5256 # if defined(HAVE_DPSOPT)
5257     (void)fprintf (st, ", ");
5258 # else
5259     (void)fprintf (st, "\r\n   Options: ");
5260 # endif
5261 # if !defined(HAVE_DPSOPT)
5262 #  define HAVE_DPSOPT 1
5263 # endif
5264     (void)fprintf (st, "DUMA");
5265 #endif /* if defined(USE_DUMA) */
5266 
5267 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5268 # if defined(NO_SUPPORT_VERSION)
5269     (void)fprintf (st, "\r\n  Modified: %s", VER_H_GIT_DATE);
5270 # else
5271     (void)fprintf (st, "\r\n  Released: %s", VER_H_GIT_DATE);
5272 # endif
5273 #endif
5274 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5275     (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5276 #endif
5277 #if defined(VER_CURRENT_TIME)
5278     (void)fprintf (st, "\r\n  Compiled: %s", VER_CURRENT_TIME);
5279 #endif
5280     if (dirty) //-V547
5281       {
5282         (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5283       }
5284     (void)fprintf (st, "\r\n\r\n Build Information:");
5285 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5286     char build_os_version_raw[255];
5287     char build_os_arch_raw[255];
5288     (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5289     (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5290     char *build_os_version = strdup(build_os_version_raw);
5291     if (!build_os_version)
5292       {
5293         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5294                        __func__, __FILE__, __LINE__);
5295 # if defined(USE_BACKTRACE)
5296 #  if defined(SIGUSR2)
5297         (void)raise(SIGUSR2);
5298         /*NOTREACHED*/ /* unreachable */
5299 #  endif /* if defined(SIGUSR2) */
5300 # endif /* if defined(USE_BACKTRACE) */
5301         abort();
5302       }
5303     char *build_os_arch = strdup(build_os_arch_raw);
5304     if (!build_os_arch)
5305       {
5306         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5307                        __func__, __FILE__, __LINE__);
5308 # if defined(USE_BACKTRACE)
5309 #  if defined(SIGUSR2)
5310         (void)raise(SIGUSR2);
5311         /*NOTREACHED*/ /* unreachable */
5312 #  endif /* if defined(SIGUSR2) */
5313 # endif /* if defined(USE_BACKTRACE) */
5314         abort();
5315       }
5316     unsigned char SPROM[1024];
5317     setupPROM (0, SPROM);
5318     (void)fprintf (st, "\r\n    Target: ");
5319     printpq (SPROM, st, 190, 20);
5320     if (SPROM[170] != 20)
5321       {
5322         if (SPROM[170] != 255)
5323           {
5324             (void)fprintf (st, " on ");
5325             printpq (SPROM, st, 170, 20);
5326           }
5327       }
5328     strtrimspace(build_os_version, build_os_version_raw);
5329     strtrimspace(build_os_arch, build_os_arch_raw);
5330     (void)fprintf (st, "\r\n  Build OS: %s %s", build_os_version, build_os_arch);
5331     FREE(build_os_version);
5332     FREE(build_os_arch);
5333 #endif
5334 #if defined(__VERSION__)
5335     char gnumver[2];
5336     char postver[1024];
5337     (void)sprintf(gnumver, "%.1s", __VERSION__);
5338     (void)sprintf(postver, "%.1023s", __VERSION__);
5339     strremove(postver, "(TM)");
5340     strremove(postver, "(R)");
5341     strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5342     strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5343     strremove(postver, " gcc 4.9 mode");
5344     strremove(postver, "4.2.1 Compatible ");
5345     strremove(postver, "git@github.com:llvm/llvm-project.git ");
5346     strremove(postver, "https://github.com/llvm/llvm-project.git ");
5347     strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5348     strremove(postver, "https://github.com/yrnkrn/zapcc ");
5349     strremove(postver, "(experimental) ");
5350     strremove(postver, ".module+el8.7.0+20823+214a699d");
5351     strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5352     strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5353     strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5354     strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5355     strremove(postver, "llvmorg-16.0.6-0-");
5356     strremove(postver, " Clang 15.0.0 (build 760095e)");
5357     strremove(postver, " Clang 15.0.0 (build 6af5742)");
5358     strremove(postver, " Clang 15.0.0 (build ca7115e)");
5359     strremove(postver, " Clang 15.0.0 (build 232543c)");
5360     strremove(postver, " Clang 17.0.6 (build 19a779f)");
5361     strremove(postver, "CLANG: ");
5362     removehex(postver);
5363     strremove(postver, " (git@github.com:pizlonator/llvm-project-deluge.git)");
5364 #endif
5365 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5366 # if !defined(__clang_version__)
5367     if (isdigit((unsigned char)gnumver[0])) {
5368         (void)fprintf (st, "\r\n  Compiler: GCC %s", postver);
5369     } else {
5370         (void)fprintf (st, "\r\n  Compiler: %s", postver);
5371     }
5372 # endif
5373 # if defined(__clang_analyzer__ )
5374     (void)fprintf (st, "\r\n  Compiler: Clang C/C++ Static Analyzer");
5375 # elif defined(__clang_version__) && defined(__VERSION__)
5376     char clangllvmver[1024];
5377     (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5378     strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5379     strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5380     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5381     strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5382     strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5383     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5384     strremove(clangllvmver, " ( )");
5385     strremove(clangllvmver, " ()");
5386     if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5387         (void)fprintf (st, "\r\n  Compiler: Clang %s", clangllvmver);
5388     } else {
5389         (void)fprintf (st, "\r\n  Compiler: %s", postver);
5390     }
5391 # elif defined(__clang_version__)
5392     (void)fprintf (st, "\r\n  Compiler: %s", postver);
5393 # endif
5394 #elif defined(__PGI) && !defined(__NVCOMPILER)
5395     (void)fprintf (st, "\r\n  Compiler: Portland Group, Inc. (PGI) C Compiler ");
5396 # if defined(__PGIC__)
5397     (void)fprintf (st, "%d", __PGIC__);
5398 #  if defined(__PGIC_MINOR__)
5399     (void)fprintf (st, ".%d", __PGIC_MINOR__);
5400 #   if defined(__PGIC_PATCHLEVEL__)
5401     (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5402 #   endif
5403 #  endif
5404 # endif
5405 #elif defined(__NVCOMPILER)
5406     (void)fprintf (st, "\r\n  Compiler: NVIDIA HPC SDK C Compiler ");
5407 # if defined(__NVCOMPILER_MAJOR__)
5408     (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5409 #  if defined(__NVCOMPILER_MINOR__)
5410     (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5411 #   if defined(__NVCOMPILER_PATCHLEVEL__)
5412     (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5413 #   endif
5414 #  endif
5415 # endif
5416 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5417     (void)fprintf (st, "\r\n  Compiler: Microsoft C %d.%02d.%05d.%02d",
5418                    _MSC_FULL_VER/10000000,
5419                    (_MSC_FULL_VER/100000)%100,
5420                    _MSC_FULL_VER%100000,
5421                    _MSC_BUILD);
5422 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5423 # if defined(_AIX) && defined(__PASE__)
5424     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5425 # endif
5426 # if defined(_AIX) && !defined(__PASE__)
5427     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5428 # endif
5429 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5430     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5431 # endif
5432 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5433 #  if defined(__PPC__) && defined(__APPLE__)
5434     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5435 #  else
5436     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s", __xlc__);
5437 #  endif
5438 # endif
5439 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5440 # define VER_ENC(maj, min, rev) \
5441   (((maj) * 1000000) + ((min) * 1000) + (rev))
5442 # define VER_DEC_MAJ(ver) \
5443   ((ver) / 1000000)
5444 # define VER_DEC_MIN(ver) \
5445   (((ver) % 1000000) / 1000)
5446 # define VER_DEC_REV(ver) \
5447   ((ver) % 1000)
5448 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5449 #  define COMP_VER VER_ENC(                                        \
5450    (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5451    (((__SUNPRO_C >>  8) & 0xf) * 10) + ((__SUNPRO_C >>  4) & 0xf), \
5452      (__SUNPRO_C & 0xf) * 10)
5453 # elif defined(__SUNPRO_C)
5454 #  define COMP_VER VER_ENC(    \
5455      (__SUNPRO_C >>  8) & 0xf, \
5456      (__SUNPRO_C >>  4) & 0xf, \
5457      (__SUNPRO_C) & 0xf)
5458 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5459 #  define COMP_VER VER_ENC(                                          \
5460    (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5461    (((__SUNPRO_CC >>  8) & 0xf) * 10) + ((__SUNPRO_CC >>  4) & 0xf), \
5462      (__SUNPRO_CC & 0xf) * 10)
5463 # elif defined(__SUNPRO_CC)
5464 #  define COMP_VER VER_ENC(     \
5465      (__SUNPRO_CC >>  8) & 0xf, \
5466      (__SUNPRO_CC >>  4) & 0xf, \
5467      (__SUNPRO_CC) & 0xf)
5468 # endif
5469 # if !defined(COMP_VER)
5470 #  define COMP_VER 0
5471 # endif
5472     (void)fprintf (st, "\r\n  Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5473                    VER_DEC_MAJ(COMP_VER),
5474                    VER_DEC_MIN(COMP_VER),
5475                    VER_DEC_REV(COMP_VER));
5476 #elif defined(__DMC__)
5477     (void)fprintf (st, "\r\n  Compiler: Digital Mars C/C++");
5478 #elif defined(__PCC__)
5479     (void)fprintf (st, "\r\n  Compiler: Portable C Compiler");
5480 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5481     (void)fprintf (st, "\r\n  Compiler: Plan 9 Compiler Suite");
5482 #elif defined(__ACK__)
5483     (void)fprintf (st, "\r\n  Compiler: Amsterdam Compiler Kit");
5484 #elif defined(__COMO__)
5485     (void)fprintf (st, "\r\n  Compiler: Comeau C++");
5486 #elif defined(__COMPCERT__)
5487     (void)fprintf (st, "\r\n  Compiler: CompCert C");
5488 #elif defined(__COVERITY__)
5489     (void)fprintf (st, "\r\n  Compiler: Coverity C/C++ Static Analyzer");
5490 #elif defined(__LCC__)
5491 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5492     (void)fprintf (st, "\r\n  Compiler: MCST Elbrus C Compiler");
5493 #  if __LCC__ > 99
5494     (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5495 #   if defined(__LCC_MINOR__)
5496 #    if __LCC_MINOR__ > 0
5497     (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5498 #    endif
5499 #   endif
5500 #  endif
5501 #  if defined(__EDG__) && defined(__EDG_VERSION__)
5502 #   if __EDG_VERSION__ > 99
5503     (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5504                   (int)(((__EDG_VERSION__) % 100) % 10));
5505 #   endif
5506 #  endif
5507 # else
5508     (void)fprintf (st, "\r\n  Compiler: Local/Little C Compiler (lcc)");
5509 # endif
5510 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5511     (void)fprintf (st, "\r\n  Compiler: SGI MIPSpro");
5512 #elif defined(__OPEN64__)
5513     (void)fprintf (st, "\r\n  Compiler: Open64 %s", __OPEN64__);
5514 #elif defined(__PGI) || defined(__PGIC__)
5515     (void)fprintf (st, "\r\n  Compiler: Portland Group/PGI C/C++");
5516 #elif defined(__VBCC__)
5517     (void)fprintf (st, "\r\n  Compiler: Volker Barthelmann C Compiler (vbcc)");
5518 #elif defined(__WATCOMC__)
5519     (void)fprintf (st, "\r\n  Compiler: Watcom C/C++ %d.%d",
5520                    __WATCOMC__ / 100,
5521                    __WATCOMC__ % 100);
5522 #elif defined(__xlC__)
5523     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++");
5524 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5525 # if defined(__INTEL_COMPILER_UPDATE)
5526 #  if defined(__INTEL_COMPILER_BUILD_DATE)
5527     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d.%d (%d)",
5528                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5529                    __INTEL_COMPILER_BUILD_DATE);
5530 #  else
5531     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d.%d",
5532                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5533 #  endif
5534 # else
5535     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d",
5536                    __INTEL_COMPILER);
5537 # endif
5538 #elif defined(SIM_COMPILER)
5539 # define S_xstr(a) S_str(a)
5540 # define S_str(a) #a
5541     (void)fprintf (st, "\r\n  Compiler: %s", S_xstr(SIM_COMPILER));
5542 # undef S_str
5543 # undef S_xstr
5544 #else
5545     (void)fprintf (st, "\r\n  Compiler: Unknown");
5546 #endif
5547 
5548 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5549     defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5550 # define SC_IS_PPC64 1
5551 #else
5552 # define SC_IS_PPC64 0
5553 #endif
5554 
5555 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5556     defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5557     defined(__PPC32)
5558 # define SC_IS_PPC32 1
5559 #else
5560 # define SC_IS_PPC32 0
5561 #endif
5562 
5563 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5564     arch = " x86_64";
5565 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5566     arch = " x86";
5567 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5568     arch = " arm64";
5569 #elif defined(_M_ARM) || defined(__arm__)
5570     arch = " arm";
5571 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5572     arch = " ia64";
5573 #elif SC_IS_PPC64
5574     arch = " powerpc64";
5575 #elif SC_IS_PPC32
5576     arch = " powerpc";
5577 #elif defined(__s390x__)
5578     arch = " s390x";
5579 #elif defined(__s390__)
5580     arch = " s390";
5581 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5582     arch = " j2";
5583 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5584     arch = " sh4";
5585 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5586     arch = " sh2";
5587 #elif defined(__alpha__)
5588     arch = " alpha";
5589 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5590     arch = " hppa";
5591 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5592     arch = " ice9";
5593 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5594     arch = " mips64";
5595 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5596     arch = " mips";
5597 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5598       defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5599     arch = " openrisc";
5600 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5601     arch = " sparc64";
5602 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5603     arch = " sparc";
5604 #elif defined(__riscv) || defined(__riscv__)
5605     arch = " riscv";
5606 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5607     arch = " e2k";
5608 #elif defined(__myriad2__)
5609     arch = " myriad2";
5610 #elif defined(__loongarch64) || defined(__loongarch__)
5611     arch = " loongarch";
5612 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5613     arch = " m68k";
5614 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5615     arch = " m88k";
5616 #elif defined(__VAX__) || defined(__vax__)
5617     arch = " vax";
5618 #elif defined(__NIOS2__) || defined(__nios2__)
5619     arch = " nios2";
5620 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5621     arch = " microblaze";
5622 #else
5623     arch = " ";
5624 #endif
5625     (void)fprintf (st, "%s", arch);
5626 #if defined(BUILD_BY_USER)
5627         (void)fprintf (st, "\r\n  Built by: %s", BUILD_BY_USER);
5628 #else
5629 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5630         (void)fprintf (st, "\r\n  Built by: %s", VER_H_PREP_USER);
5631 # endif
5632 #endif
5633                 (void)fprintf (st, "\r\n\r\n Host System Information:");
5634 #if defined(_WIN32)
5635     if (1) {
5636         char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5637         char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5638         char osversion[PATH_MAX+1] = "";
5639         FILE *f;
5640 
5641         if ((f = _popen ("ver", "r"))) {
5642             (void)memset (osversion, 0, sizeof(osversion));
5643             do {
5644                 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5645                     break;
5646                 sim_trim_endspc (osversion);
5647                 } while (osversion[0] == '\0');
5648             _pclose (f);
5649             }
5650         (void)fprintf (st, "\r\n   Host OS: %s", osversion);
5651         (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264  : "");
5652         }
5653 #else
5654     if (1) {
5655         char osversion[2*PATH_MAX+1] = "";
5656         FILE *f;
5657 # if !defined(_AIX)
5658         if ((f = popen \
5659              ("uname -mrs 2> /dev/null", "r"))) {
5660 # else
5661         if ((f = popen \
5662              ("sh -c 'echo \"$(command -p env uname -v \
5663                2> /dev/null).$(command -p env uname -r \
5664                2> /dev/null) $(command -p env uname -p \
5665                2> /dev/null)\"' 2> /dev/null", "r"))) {
5666 # endif /* if !defined(_AIX) */
5667             (void)memset (osversion, 0, sizeof(osversion));
5668             do {
5669               if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5670                     break;
5671               }
5672             sim_trim_endspc (osversion);
5673             } while (osversion[0] == '\0');
5674             pclose (f);
5675             strremove(osversion, "0000000000000000 ");
5676             strremove(osversion, " 0000000000000000");
5677             strremove(osversion, "000000000000 ");
5678             strremove(osversion, " 000000000000");
5679             strremove(osversion, "IBM ");
5680             strremove(osversion, " (emulated by qemu)");
5681             strremove(osversion, " (emulated by QEMU)");
5682         }
5683 # if !defined(_AIX)
5684             (void)fprintf (st, "\r\n   Host OS: %s", osversion);
5685 # else
5686             strremove(osversion, "AIX ");
5687 #  if !defined(__PASE__)
5688             (void)fprintf (st, "\r\n   Host OS: IBM AIX %s", osversion);
5689 #  else
5690             (void)fprintf (st, "\r\n   Host OS: IBM OS/400 (PASE) %s", osversion);
5691 #  endif /* if !defined(__PASE__) */
5692 # endif /* if !defined(_AIX) */
5693     } else {
5694 # if !defined(_AIX)
5695         (void)fprintf (st, "\r\n   Host OS: Unknown");
5696 # else
5697 #  if !defined(__PASE__)
5698         (void)fprintf (st, "\r\n   Host OS: IBM AIX");
5699 #  else
5700         (void)fprintf (st, "\r\n   Host OS: IBM OS/400 (PASE)");
5701 #  endif /* if !defined(__PASE__) */
5702 # endif /* if !defined(_AIX) */
5703     }
5704 #endif
5705     if (nodist)
5706       {
5707         sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5708       }
5709     else
5710       {
5711         (void)fprintf (st, "\r\n");
5712         (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5713         (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5714         (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5715       }
5716         (void)fprintf (st, "\r\n");
5717     }
5718 return SCPE_OK;
5719 }
5720 
5721 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5722 {
5723 size_t i;
5724 DEVICE *dptr;
5725 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5726 
5727 if (cptr && (*cptr != 0))
5728     return SCPE_2MARG;
5729 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5730 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5731     if (!only_enabled || !qdisable (dptr))
5732         show_device (st, dptr, flag);
5733 return SCPE_OK;
5734 }
5735 
5736 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5737 {
5738 int32 i;
5739 DEVICE *dptr;
5740 
5741 if (cptr && (*cptr != 0))
5742     return SCPE_2MARG;
5743 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5744     show_dev_logicals (st, dptr, NULL, 1, cptr);
5745 return SCPE_OK;
5746 }
5747 
5748 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5749 {
5750 if (dptr->lname)
5751     (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5752 else if (!flag)
5753     fputs ("no logical name assigned\r\n", st);
5754 return SCPE_OK;
5755 }
5756 
5757 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5758 {
5759 DEVICE *dptr;
5760 UNIT *uptr;
5761 int32 accum;
5762 
5763 if (cptr && (*cptr != 0))
5764     return SCPE_2MARG;
5765 if (sim_clock_queue == QUEUE_LIST_END)
5766     (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5767                    sim_name, sim_time, sim_timer_inst_per_sec ());
5768 else {
5769     const char *tim;
5770 
5771     (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5772                    sim_name, sim_time, sim_timer_inst_per_sec ());
5773     accum = 0;
5774     for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5775         if (uptr == &sim_step_unit)
5776             (void)fprintf (st, "  Step timer");
5777         else
5778             if (uptr == &sim_expect_unit)
5779                 (void)fprintf (st, "  Expect fired");
5780             else
5781                 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5782                     (void)fprintf (st, "  %s", sim_dname (dptr));
5783                     if (dptr->numunits > 1)
5784                         (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5785                     }
5786                 else
5787                     (void)fprintf (st, "  Unknown");
5788         tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5789         (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5790                        (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5791                        (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5792         accum = accum + uptr->time;
5793         }
5794     }
5795 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5796 return SCPE_OK;
5797 }
5798 
5799 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5800 {
5801 if (cptr && (*cptr != 0))
5802     return SCPE_2MARG;
5803 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5804 return SCPE_OK;
5805 }
5806 
5807 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5808 {
5809 t_stat r;
5810 
5811 if (cptr && (*cptr != 0))
5812     r = ssh_break (st, cptr, 1);  /* more? */
5813 else
5814     r = sim_brk_showall (st, (uint32)sim_switches);
5815 return r;
5816 }
5817 
5818 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5819 {
5820 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5821 return SCPE_OK;
5822 }
5823 
5824 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5825 {
5826 int32 any = 0;
5827 DEBTAB *dep;
5828 
5829 if (dptr->flags & DEV_DEBUG) {
5830     if (dptr->dctrl == 0)
5831         fputs ("Debugging disabled", st);
5832     else if (dptr->debflags == NULL)
5833         fputs ("Debugging enabled", st);
5834     else {
5835         uint32 dctrl = dptr->dctrl;
5836 
5837         fputs ("Debug=", st);
5838         for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5839             if ((dctrl & dep->mask) == dep->mask) {
5840                 dctrl &= ~dep->mask;
5841                 if (any)
5842                     fputc (';', st);
5843                 fputs (dep->name, st);
5844                 any = 1;
5845                 }
5846             }
5847         }
5848     fputc ('\n', st);
5849     return SCPE_OK;
5850     }
5851 else return SCPE_NOFNC;
5852 }
5853 
5854 /* Show On actions */
5855 
5856 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5857 {
5858 int32 lvl, i;
5859 
5860 if (cptr && (*cptr != 0)) return SCPE_2MARG;            /* now eol? */
5861 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5862     if (lvl > 0)
5863         (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5864     else
5865         (void)fprintf(st, "On Processing for input commands");
5866     (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5867     for (i=1; i<SCPE_BASE; ++i) {
5868         if (sim_on_actions[lvl][i])
5869             (void)fprintf(st, "    on %5d    %s\r\n", i, sim_on_actions[lvl][i]); }
5870     for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5871         if (sim_on_actions[lvl][i])
5872             (void)fprintf(st, "    on %-5s    %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5873     if (sim_on_actions[lvl][0])
5874         (void)fprintf(st, "    on ERROR    %s\r\n", sim_on_actions[lvl][0]);
5875     (void)fprintf(st, "\r\n");
5876     }
5877 if (sim_on_inherit)
5878     (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5879 return SCPE_OK;
5880 }
5881 
5882 /* Show modifiers */
5883 
5884 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5885 {
5886 int32 i;
5887 DEVICE *dptr;
5888 
5889 if (cptr && (*cptr != 0))                               /* now eol? */
5890     return SCPE_2MARG;
5891 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5892     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5893 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5894     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5895 return SCPE_OK;
5896 }
5897 
5898 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5899 {
5900 fprint_set_help (st, dptr);
5901 return SCPE_OK;
5902 }
5903 
5904 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
     /* [previous][next][first][last][top][bottom][index][help] */
5905 {
5906 MTAB *mptr;
5907 t_stat r = SCPE_OK;
5908 
5909 if (dptr->modifiers == NULL)
5910     return SCPE_OK;
5911 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5912     if (mptr->pstring &&
5913         ((mptr->mask & MTAB_XTD)?
5914             (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5915             ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5916         if (*toks > 0) {
5917             (void)fprintf (st, "\r\n");
5918             *toks = 0;
5919             }
5920         if (r == SCPE_OK)
5921             fprint_sep (st, toks);
5922         r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5923         }
5924     }
5925 return SCPE_OK;
5926 }
5927 
5928 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
     /* [previous][next][first][last][top][bottom][index][help] */
5929     CONST char *cptr, int32 flag)
5930 {
5931 t_stat r = SCPE_OK;
5932 
5933 if (mptr->disp)
5934     r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5935 else
5936     fputs (mptr->pstring, st);
5937 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5938     fputc ('\n', st);
5939 return r;
5940 }
5941 
5942 /* Show show commands */
5943 
5944 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5945 {
5946 int32 i;
5947 DEVICE *dptr;
5948 
5949 if (cptr && (*cptr != 0))                               /* now eol? */
5950     return SCPE_2MARG;
5951 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5952     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5953 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5954     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5955 return SCPE_OK;
5956 }
5957 
5958 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] */
5959 {
5960 fprint_show_help (st, dptr);
5961 return SCPE_OK;
5962 }
5963 
5964 /* Breakpoint commands */
5965 
5966 t_stat brk_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5967 {
5968 GET_SWITCHES (cptr);                                    /* get switches */
5969 return ssh_break (NULL, cptr, flg);                     /* call common code */
5970 }
5971 
5972 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
     /* [previous][next][first][last][top][bottom][index][help] */
5973 {
5974 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5975 CONST char *tptr, *t1ptr;
5976 DEVICE *dptr = sim_dflt_dev;
5977 UNIT *uptr;
5978 t_stat r;
5979 t_addr lo, hi, max;
5980 int32 cnt;
5981 
5982 if (sim_brk_types == 0)
5983     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
5984 if (dptr == NULL)
5985     return SCPE_IERR;
5986 uptr = dptr->units;
5987 if (uptr == NULL)
5988     return SCPE_IERR;
5989 max = uptr->capac - 1;
5990 abuf[sizeof(abuf)-1] = '\0';
5991 strncpy (abuf, cptr, sizeof(abuf)-1);
5992 cptr = abuf;
5993 if ((aptr = strchr (abuf, ';'))) {                      /* ;action? */
5994     if (flg != SSH_ST)                                  /* only on SET */
5995         return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
5996     *aptr++ = 0;                                        /* separate strings */
5997     }
5998 if (*cptr == 0) {                                       /* no argument? */
5999     lo = (t_addr) get_rval (sim_PC, 0);                 /* use PC */
6000     return ssh_break_one (st, flg, lo, 0, aptr);
6001     }
6002 while (*cptr) {
6003     cptr = get_glyph (cptr, gbuf, ',');
6004     tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
6005     if (tptr == NULL)
6006         return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
6007     if (*tptr == '[') {
6008         cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
6009         if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
6010             return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
6011         tptr = t1ptr + 1;
6012         }
6013     else cnt = 0;
6014     if (*tptr != 0)
6015         return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
6016     if ((lo == 0) && (hi == max)) {
6017         if (flg == SSH_CL)
6018             sim_brk_clrall (sim_switches);
6019         else
6020             if (flg == SSH_SH)
6021                 sim_brk_showall (st, (uint32)sim_switches);
6022             else
6023                 return SCPE_ARG;
6024         }
6025     else {
6026         for ( ; lo <= hi; lo = lo + 1) {
6027             r = ssh_break_one (st, flg, lo, cnt, aptr);
6028             if (r != SCPE_OK)
6029                 return r;
6030             }
6031         }
6032     }
6033 return SCPE_OK;
6034 }
6035 
6036 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] */
6037 {
6038 if (!sim_brk_types)
6039     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6040 switch (flg) {
6041     case SSH_ST:
6042         return sim_brk_set (lo, sim_switches, cnt, aptr);
6043         /*NOTREACHED*/ /* unreachable */
6044         break;
6045 
6046     case SSH_CL:
6047         return sim_brk_clr (lo, sim_switches);
6048         /*NOTREACHED*/ /* unreachable */
6049         break;
6050 
6051     case SSH_SH:
6052         return sim_brk_show (st, lo, sim_switches);
6053         /*NOTREACHED*/ /* unreachable */
6054         break;
6055 
6056     default:
6057         return SCPE_ARG;
6058     }
6059 }
6060 
6061 /* Reset command and routines */
6062 
6063 static t_bool run_cmd_did_reset = FALSE;
6064 
6065 t_stat reset_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6066 {
6067 char gbuf[CBUFSIZE];
6068 DEVICE *dptr;
6069 
6070 GET_SWITCHES (cptr);                                    /* get switches */
6071 run_cmd_did_reset = FALSE;
6072 if (*cptr == 0)                                         /* reset(cr) */
6073     return (reset_all (0));
6074 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6075 if (*cptr != 0)                                         /* now eol? */
6076     return SCPE_2MARG;
6077 if (strcmp (gbuf, "ALL") == 0)
6078     return (reset_all (0));
6079 dptr = find_dev (gbuf);                                 /* locate device */
6080 if (dptr == NULL)                                       /* found it? */
6081     return SCPE_NXDEV;
6082 if (dptr->reset != NULL)
6083     return dptr->reset (dptr);
6084 else return SCPE_OK;
6085 }
6086 
6087 /* Reset devices start..end
6088 
6089    Inputs:
6090         start   =       number of starting device
6091    Outputs:
6092         status  =       error status
6093 */
6094 
6095 t_stat reset_all (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6096 {
6097 DEVICE *dptr;
6098 uint32 i;
6099 t_stat reason;
6100 
6101 for (i = 0; i < start; i++) {
6102     if (sim_devices[i] == NULL)
6103         return SCPE_IERR;
6104     }
6105 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6106     if (dptr->reset != NULL) {
6107         reason = dptr->reset (dptr);
6108         if (reason != SCPE_OK)
6109             return reason;
6110         }
6111     }
6112 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6113     if (dptr->reset != NULL) {
6114         reason = dptr->reset (dptr);
6115         if (reason != SCPE_OK)
6116             return reason;
6117         }
6118     }
6119 return SCPE_OK;
6120 }
6121 
6122 /* Reset to powerup state
6123 
6124    Inputs:
6125         start   =       number of starting device
6126    Outputs:
6127         status  =       error status
6128 */
6129 
6130 t_stat reset_all_p (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6131 {
6132 t_stat r;
6133 int32 old_sw = sim_switches;
6134 
6135 sim_switches = SWMASK ('P');
6136 r = reset_all (start);
6137 sim_switches = old_sw;
6138 return r;
6139 }
6140 
6141 /* Attach command */
6142 
6143 t_stat attach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6144 {
6145 char gbuf[4*CBUFSIZE];
6146 DEVICE *dptr;
6147 UNIT *uptr;
6148 t_stat r;
6149 
6150 GET_SWITCHES (cptr);                                    /* get switches */
6151 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6152     return SCPE_2FARG;
6153 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6154 GET_SWITCHES (cptr);                                    /* get switches */
6155 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* now eol? */
6156     return SCPE_2FARG;
6157 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6158 if (dptr == NULL)                                       /* found dev? */
6159     return SCPE_NXDEV;
6160 if (uptr == NULL)                                       /* valid unit? */
6161     return SCPE_NXUN;
6162 if (uptr->flags & UNIT_ATT) {                           /* already attached? */
6163     if (!(uptr->dynflags & UNIT_ATTMULT) &&             /* and only single attachable */
6164         !(dptr->flags & DEV_DONTAUTO)) {                /* and auto detachable */
6165         r = scp_detach_unit (dptr, uptr);               /* detach it */
6166         if (r != SCPE_OK)                               /* error? */
6167             return r; }
6168     else {
6169         if (!(uptr->dynflags & UNIT_ATTMULT))
6170             return SCPE_ALATT;                          /* Already attached */
6171         }
6172     }
6173 gbuf[sizeof(gbuf)-1] = '\0';
6174 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6175 sim_trim_endspc (gbuf);                                 /* trim trailing spc */
6176 return scp_attach_unit (dptr, uptr, gbuf);              /* attach */
6177 }
6178 
6179 /* Call device-specific or file-oriented attach unit routine */
6180 
6181 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6182 {
6183 if (dptr->attach != NULL)                               /* device routine? */
6184     return dptr->attach (uptr, (CONST char *)cptr);     /* call it */
6185 return attach_unit (uptr, (CONST char *)cptr);          /* no, std routine */
6186 }
6187 
6188 /* Attach unit to file */
6189 
6190 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6191 {
6192 DEVICE *dptr;
6193 
6194 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6195     return SCPE_UDIS;
6196 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
6197     return SCPE_NOATT;
6198 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6199     return SCPE_NOATT;
6200 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */
6201 if (uptr->filename == NULL)
6202     return SCPE_MEM;
6203 strncpy (uptr->filename, cptr, CBUFSIZE-1);             /* save name */
6204 if ((sim_switches & SWMASK ('R')) ||                    /* read only? */
6205     ((uptr->flags & UNIT_RO) != 0)) {
6206     if (((uptr->flags & UNIT_ROABLE) == 0) &&           /* allowed? */
6207         ((uptr->flags & UNIT_RO) == 0))
6208         return attach_err (uptr, SCPE_NORO);            /* no, error */
6209     uptr->fileref = sim_fopen (cptr, "rb");             /* open rd only */
6210     if (uptr->fileref == NULL)                          /* open fail? */
6211         return attach_err (uptr, SCPE_OPENERR);         /* yes, error */
6212     uptr->flags = uptr->flags | UNIT_RO;                /* set rd only */
6213     if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6214         sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6215         }
6216     }
6217 else {
6218     if (sim_switches & SWMASK ('N')) {                  /* new file only? */
6219         uptr->fileref = sim_fopen (cptr, "wb+");        /* open new file */
6220         if (uptr->fileref == NULL)                      /* open fail? */
6221             return attach_err (uptr, SCPE_OPENERR);     /* yes, error */
6222         if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6223             sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6224             }
6225         }
6226     else {                                              /* normal */
6227         uptr->fileref = sim_fopen (cptr, "rb+");        /* open r/w */
6228         if (uptr->fileref == NULL) {                    /* open fail? */
6229 #if defined(EWOULDBLOCK)
6230             if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6231 #else
6232             if ((errno == EAGAIN))
6233 #endif
6234                 return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6235 
6236 #if defined(EPERM)
6237             if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {/* read only? */
6238 #else
6239             if ((errno == EROFS) || (errno == EACCES)) {/* read only? */
6240 #endif
6241                 if ((uptr->flags & UNIT_ROABLE) == 0)   /* allowed? */
6242                     return attach_err (uptr, SCPE_NORO);/* no error */
6243                 uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */
6244                 if (uptr->fileref == NULL)              /* open fail? */
6245                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6246                 uptr->flags = uptr->flags | UNIT_RO;    /* set rd only */
6247                 if (!sim_quiet) {
6248                     sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6249                     }
6250                 }
6251             else {                                      /* doesn't exist */
6252                 if (sim_switches & SWMASK ('E'))        /* must exist? */
6253                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6254                 uptr->fileref = sim_fopen (cptr, "wb+");/* open new file */
6255                 if (uptr->fileref == NULL)              /* open fail? */
6256                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6257                 if (!sim_quiet) {
6258                     sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6259                     }
6260                 }
6261             }                                           /* end if null */
6262         }                                               /* end else */
6263     }
6264 if (uptr->flags & UNIT_BUFABLE) {                       /* buffer? */
6265     uint32 cap = ((uint32) uptr->capac) / dptr->aincr;  /* effective size */
6266     if (uptr->flags & UNIT_MUSTBUF)                     /* dyn alloc? */
6267         uptr->filebuf = calloc (cap, SZ_D (dptr));      /* allocate */
6268     if (uptr->filebuf == NULL)                          /* no buffer? */
6269         return attach_err (uptr, SCPE_MEM);             /* error */
6270     if (!sim_quiet) {
6271         sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6272         }
6273     uptr->hwmark = (uint32)sim_fread (uptr->filebuf,    /* read file */
6274         SZ_D (dptr), cap, uptr->fileref);
6275     uptr->flags = uptr->flags | UNIT_BUF;               /* set buffered */
6276     }
6277 uptr->flags = uptr->flags | UNIT_ATT;
6278 uptr->pos = 0;
6279 return SCPE_OK;
6280 }
6281 
6282 t_stat attach_err (UNIT *uptr, t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
6283 {
6284 FREE (uptr->filename);
6285 uptr->filename = NULL;
6286 return stat;
6287 }
6288 
6289 /* Detach command */
6290 
6291 t_stat detach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6292 {
6293 char gbuf[CBUFSIZE];
6294 DEVICE *dptr;
6295 UNIT *uptr;
6296 
6297 GET_SWITCHES (cptr);                                    /* get switches */
6298 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6299     return SCPE_2FARG;
6300 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6301 if (*cptr != 0)                                         /* now eol? */
6302     return SCPE_2MARG;
6303 if (strcmp (gbuf, "ALL") == 0)
6304     return (detach_all (0, FALSE));
6305 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6306 if (dptr == NULL)                                       /* found dev? */
6307     return SCPE_NXDEV;
6308 if (uptr == NULL)                                       /* valid unit? */
6309     return SCPE_NXUN;
6310 return scp_detach_unit (dptr, uptr);                    /* detach */
6311 }
6312 
6313 /* Detach devices start..end
6314 
6315    Inputs:
6316         start   =       number of starting device
6317         shutdown =      TRUE if simulator shutting down
6318    Outputs:
6319         status  =       error status
6320 
6321    Note that during shutdown, detach routines for non-attachable devices
6322    will be called.  These routines can implement simulator shutdown.  Error
6323    returns during shutdown are ignored.
6324 */
6325 
6326 t_stat detach_all (int32 start, t_bool shutdown)
     /* [previous][next][first][last][top][bottom][index][help] */
6327 {
6328 uint32 i, j;
6329 DEVICE *dptr;
6330 UNIT *uptr;
6331 t_stat r;
6332 
6333 if ((start < 0) || (start > 1))
6334     return SCPE_IERR;
6335 if (shutdown)
6336     sim_switches = sim_switches | SIM_SW_SHUT;          /* flag shutdown */
6337 for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
6338     for (j = 0; j < dptr->numunits; j++) {              /* loop thru units */
6339         uptr = (dptr->units) + j;
6340         if ((uptr->flags & UNIT_ATT) ||                 /* attached? */
6341             (shutdown && dptr->detach &&                /* shutdown, spec rtn, */
6342             !(uptr->flags & UNIT_ATTABLE))) {           /* !attachable? */
6343             r = scp_detach_unit (dptr, uptr);           /* detach unit */
6344 
6345             if ((r != SCPE_OK) && !shutdown)            /* error and not shutting down? */
6346                 return r;                               /* bail out now with error status */
6347             }
6348         }
6349     }
6350 return SCPE_OK;
6351 }
6352 
6353 /* Call device-specific or file-oriented detach unit routine */
6354 
6355 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6356 {
6357 if (dptr->detach != NULL)                               /* device routine? */
6358     return dptr->detach (uptr);
6359 return detach_unit (uptr);                              /* no, standard */
6360 }
6361 
6362 /* Detach unit from file */
6363 
6364 t_stat detach_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6365 {
6366 DEVICE *dptr;
6367 
6368 if (uptr == NULL)
6369     return SCPE_IERR;
6370 if (!(uptr->flags & UNIT_ATTABLE))                      /* attachable? */
6371     return SCPE_NOATT;
6372 if (!(uptr->flags & UNIT_ATT)) {                        /* not attached? */
6373     if (sim_switches & SIM_SW_REST)                     /* restoring? */
6374         return SCPE_OK;                                 /* allow detach */
6375     else
6376         return SCPE_NOTATT;                             /* complain */
6377     }
6378 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6379     return SCPE_OK;
6380 if (uptr->flags & UNIT_BUF) {
6381     uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6382     if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6383         if (!sim_quiet) {
6384             sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6385             }
6386         rewind (uptr->fileref);
6387         sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6388         if (ferror (uptr->fileref))
6389             sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6390                         sim_dname (dptr), xstrerror_l(errno), errno);
6391         }
6392     if (uptr->flags & UNIT_MUSTBUF) {                   /* dyn alloc? */
6393         FREE (uptr->filebuf);                           /* free buf */
6394         uptr->filebuf = NULL;
6395         }
6396     uptr->flags = uptr->flags & ~UNIT_BUF;
6397     }
6398 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6399 FREE (uptr->filename);
6400 uptr->filename = NULL;
6401 if (fclose (uptr->fileref) == EOF)
6402     return SCPE_IOERR;
6403 return SCPE_OK;
6404 }
6405 
6406 /* Get device display name */
6407 
6408 const char *sim_dname (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6409 {
6410 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6411 }
6412 
6413 /* Get unit display name */
6414 
6415 const char *sim_uname (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6416 {
6417 DEVICE *d = find_dev_from_unit(uptr);
6418 static char uname[CBUFSIZE];
6419 
6420 if (!d)
6421     return "";
6422 if (d->numunits == 1)
6423     return sim_dname (d);
6424 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6425 return uname;
6426 }
6427 
6428 /* Run, go, boot, cont, step, next commands */
6429 
6430 t_stat run_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6431 {
6432 char gbuf[CBUFSIZE] = "";
6433 CONST char *tptr;
6434 uint32 i, j;
6435 int32 sim_next = 0;
6436 int32 unitno;
6437 t_value pcv, orig_pcv;
6438 t_stat r;
6439 DEVICE *dptr;
6440 UNIT *uptr;
6441 
6442 GET_SWITCHES (cptr);                                    /* get switches */
6443 sim_step = 0;
6444 if ((flag == RU_RUN) || (flag == RU_GO)) {              /* run or go */
6445     orig_pcv = get_rval (sim_PC, 0);                    /* get current PC value */
6446     if (*cptr != 0) {                                   /* argument? */
6447         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6448         if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6449             if (sim_dflt_dev && sim_vm_parse_addr)      /* address parser? */
6450                 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6451             else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */
6452             if ((tptr == gbuf) || (*tptr != 0) ||       /* error? */
6453                 (pcv > width_mask[sim_PC->width]))
6454                 return SCPE_ARG;
6455             put_rval (sim_PC, 0, pcv);                  /* Save in PC */
6456             }
6457         }
6458     if ((flag == RU_RUN) &&                             /* run? */
6459         ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {  /* reset sim */
6460         put_rval (sim_PC, 0, orig_pcv);                 /* restore original PC */
6461         return r;
6462         }
6463     if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) { //-V600 /* should be end */
6464         int32 saved_switches = sim_switches;
6465 
6466         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6467             cptr = get_glyph (cptr, gbuf, 0);           /* get next glyph */
6468         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6469             return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6470                                              (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6471         sim_switches = 0;
6472         GET_SWITCHES (cptr);
6473         if ((*cptr == '\'') || (*cptr == '"')) {        /* Expect UNTIL condition */
6474             r = expect_cmd (1, cptr);
6475             if (r != SCPE_OK)
6476                 return r;
6477             }
6478         else {                                          /* BREAK UNTIL condition */
6479             if (sim_switches == 0)
6480                 sim_switches = sim_brk_dflt;
6481             sim_switches |= BRK_TYP_TEMP;               /* make this a one-shot breakpoint */
6482             sim_brk_types |= BRK_TYP_TEMP;
6483             r = ssh_break (NULL, cptr, SSH_ST);
6484             if (r != SCPE_OK)
6485                 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6486             }
6487         sim_switches = saved_switches;
6488         }
6489     }
6490 
6491 else if ((flag == RU_STEP) ||
6492          ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) { /* step */
6493     static t_bool not_implemented_message = FALSE;
6494 
6495     if ((!not_implemented_message) && (flag == RU_NEXT)) {
6496         not_implemented_message = TRUE;
6497         flag = RU_STEP;
6498         }
6499     if (*cptr != 0) {                                   /* argument? */
6500         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6501         if (*cptr != 0)                                 /* should be end */
6502             return SCPE_2MARG;
6503         sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6504         if ((r != SCPE_OK) || (sim_step <= 0))          /* error? */
6505             return SCPE_ARG;
6506         }
6507     else sim_step = 1;
6508     if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6509         sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6510     }
6511 else if (flag == RU_NEXT) {                             /* next */
6512     t_addr *addrs;
6513 
6514     if (*cptr != 0) {                                   /* argument? */
6515         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6516         if (*cptr != 0)                                 /* should be end */
6517             return SCPE_2MARG;
6518         sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6519         if ((r != SCPE_OK) || (sim_next <= 0))          /* error? */
6520             return SCPE_ARG;
6521         }
6522     else sim_next = 1;
6523     if (sim_vm_is_subroutine_call(&addrs)) {
6524         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6525         for (i=0; addrs[i]; i++)
6526             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6527         }
6528     else
6529         sim_step = 1;
6530     }
6531 else if (flag == RU_BOOT) {                             /* boot */
6532     if (*cptr == 0)                                     /* must be more */
6533         return SCPE_2FARG;
6534     cptr = get_glyph (cptr, gbuf, 0);                   /* get next glyph */
6535     if (*cptr != 0)                                     /* should be end */
6536         return SCPE_2MARG;
6537     dptr = find_unit (gbuf, &uptr);                     /* locate unit */
6538     if (dptr == NULL)                                   /* found dev? */
6539         return SCPE_NXDEV;
6540     if (uptr == NULL)                                   /* valid unit? */
6541         return SCPE_NXUN;
6542     if (dptr->boot == NULL)                             /* can it boot? */
6543         return SCPE_NOFNC;
6544     if (uptr->flags & UNIT_DIS)                         /* disabled? */
6545         return SCPE_UDIS;
6546     if ((uptr->flags & UNIT_ATTABLE) &&                 /* if attable, att? */
6547         !(uptr->flags & UNIT_ATT))
6548         return SCPE_UNATT;
6549     unitno = (int32) (uptr - dptr->units);              /* recover unit# */
6550     if ((r = sim_run_boot_prep (flag)) != SCPE_OK)      /* reset sim */
6551         return r;
6552     if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)     /* boot device */
6553         return r;
6554     }
6555 
6556 else
6557     if (flag != RU_CONT)                                /* must be cont */
6558         return SCPE_IERR;
6559     else                                                /* CONTINUE command */
6560         if (*cptr != 0)                                 /* should be end (no arguments allowed) */
6561             return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6562 
6563 if (sim_switches & SIM_SW_HIDE)                         /* Setup only for Remote Console Mode */
6564     return SCPE_OK;
6565 
6566 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* reposition all */
6567     for (j = 0; j < dptr->numunits; j++) {              /* seq devices */
6568         uptr = dptr->units + j;
6569         if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6570             sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6571         }
6572     }
6573 stop_cpu = 0;
6574 sim_is_running = 1;                                     /* flag running */
6575 if (sim_ttrun () != SCPE_OK) {                          /* set console mode */
6576     sim_is_running = 0;                                 /* flag idle */
6577     sim_ttcmd ();
6578     return SCPE_TTYERR;
6579     }
6580 if ((r = sim_check_console (30)) != SCPE_OK) {          /* check console, error? */
6581     sim_is_running = 0;                                 /* flag idle */
6582     sim_ttcmd ();
6583     return r;
6584     }
6585 #if !defined(IS_WINDOWS)
6586 # if defined(SIGINT)
6587 if (signal (SIGINT, int_handler) == SIG_ERR) {          /* set WRU */
6588     sim_is_running = 0;                                 /* flag idle */
6589     sim_ttcmd ();
6590     return SCPE_SIGERR;
6591     }
6592 # endif
6593 #endif
6594 #if !defined(IS_WINDOWS)
6595 # if defined(SIGHUP)
6596 if (signal (SIGHUP, int_handler) == SIG_ERR) {          /* set WRU */
6597     sim_is_running = 0;                                 /* flag idle */
6598     sim_ttcmd ();
6599     return SCPE_SIGERR;
6600     }
6601 # endif
6602 #endif
6603 #if !defined(IS_WINDOWS)
6604 # if defined(SIGTERM)
6605 if (signal (SIGTERM, int_handler) == SIG_ERR) {         /* set WRU */
6606     sim_is_running = 0;                                 /* flag idle */
6607     sim_ttcmd ();
6608     return SCPE_SIGERR;
6609     }
6610 # endif
6611 #endif
6612 if (sim_step)                                           /* set step timer */
6613     sim_activate (&sim_step_unit, sim_step);
6614 (void)fflush(stdout);                                   /* flush stdout */
6615 if (sim_log)                                            /* flush log if enabled */
6616     (void)fflush (sim_log);
6617 sim_rtcn_init_all ();                                   /* re-init clocks */
6618 sim_start_timer_services ();                            /* enable wall clock timing */
6619 
6620 do {
6621     t_addr *addrs;
6622 
6623     while (1) {
6624         r = sim_instr();
6625         if (r != SCPE_REMOTE)
6626             break;
6627         sim_remote_process_command ();                  /* Process the command and resume processing */
6628         }
6629     if ((flag != RU_NEXT) ||                            /* done if not doing NEXT */
6630         (--sim_next <=0))
6631         break;
6632     if (sim_step == 0) {                                /* doing a NEXT? */
6633         t_addr val;
6634         BRKTAB *bp;
6635 
6636         if (SCPE_BARE_STATUS(r) >= SCPE_BASE)           /* done if an error occurred */
6637             break;
6638         if (sim_vm_pc_value)                            /* done if didn't stop at a dynamic breakpoint */
6639             val = (t_addr)(*sim_vm_pc_value)();
6640         else
6641             val = (t_addr)get_rval (sim_PC, 0);
6642         if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6643             break;
6644         sim_brk_clrall (BRK_TYP_DYN_STEPOVER);          /* cancel any step/over subroutine breakpoints */
6645         }
6646     else {
6647         if (r != SCPE_STEP)                             /* done if step didn't complete with step expired */
6648             break;
6649         }
6650     /* setup another next/step */
6651     sim_step = 0;
6652     if (sim_vm_is_subroutine_call(&addrs)) {
6653         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6654         for (i=0; addrs[i]; i++)
6655             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6656         }
6657     else
6658         sim_step = 1;
6659     if (sim_step)                                       /* set step timer */
6660         sim_activate (&sim_step_unit, sim_step);
6661     } while (1);
6662 
6663 sim_is_running = 0;                                     /* flag idle */
6664 sim_stop_timer_services ();                             /* disable wall clock timing */
6665 sim_ttcmd ();                                           /* restore console */
6666 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);                  /* cancel any step/over subroutine breakpoints */
6667 signal (SIGINT, SIG_DFL);                               /* cancel WRU */
6668 #if defined(SIGHUP)
6669 signal (SIGHUP, SIG_DFL);                               /* cancel WRU */
6670 #endif
6671 signal (SIGTERM, SIG_DFL);                              /* cancel WRU */
6672 if (sim_log)                                            /* flush console log */
6673     (void)fflush (sim_log);
6674 if (sim_deb)                                            /* flush debug log */
6675     sim_debug_flush ();
6676 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* flush attached files */
6677     for (j = 0; j < dptr->numunits; j++) {              /* if not buffered in mem */
6678         uptr = dptr->units + j;
6679         if (uptr->flags & UNIT_ATT) {                   /* attached, */
6680             if (uptr->io_flush)                         /* unit specific flush routine */
6681                 uptr->io_flush (uptr);                  /* call it */
6682             else {
6683                 if (!(uptr->flags & UNIT_BUF) &&        /* not buffered, */
6684                     (uptr->fileref) &&                  /* real file, */
6685                     !(uptr->dynflags & UNIT_NO_FIO) &&  /* is FILE *, */
6686                     !(uptr->flags & UNIT_RO))           /* not read only? */
6687                     (void)fflush (uptr->fileref);
6688                 }
6689             }
6690         }
6691     }
6692 sim_cancel (&sim_step_unit);                            /* cancel step timer */
6693 UPDATE_SIM_TIME;                                        /* update sim time */
6694 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6695 }
6696 
6697 /* run command message handler */
6698 
6699 void
6700 run_cmd_message (const char *unechoed_cmdline, t_stat r)
     /* [previous][next][first][last][top][bottom][index][help] */
6701 {
6702 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6703     sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6704 #if defined(WIN_STDIO)
6705 (void)fflush(stderr);
6706 (void)fflush(stdout);
6707 #endif /* if defined(WIN_STDIO) */
6708 fprint_stopped (stdout, r);                         /* print msg */
6709 if (sim_log && (sim_log != stdout))                 /* log if enabled */
6710     fprint_stopped (sim_log, r);
6711 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))/* debug if enabled */
6712     fprint_stopped (sim_deb, r);
6713 #if defined(WIN_STDIO)
6714 (void)fflush(stderr);
6715 (void)fflush(stdout);
6716 #endif /* if defined(WIN_STDIO) */
6717 }
6718 
6719 /* Common setup for RUN or BOOT */
6720 
6721 t_stat sim_run_boot_prep (int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
6722 {
6723 UNIT *uptr;
6724 t_stat r;
6725 
6726 sim_interval = 0;                                       /* reset queue */
6727 sim_time = sim_rtime = 0;
6728 noqueue_time = 0;
6729 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6730     sim_clock_queue = uptr->next;
6731     uptr->next = NULL;
6732     }
6733 r = reset_all (0);
6734 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6735     if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6736         sim_printf ("Resetting all devices...  This may not have been your intention.\r\n");
6737         sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6738         }
6739     run_cmd_did_reset = TRUE;
6740     }
6741 return r;
6742 }
6743 
6744 /* Print stopped message
6745  * For VM stops, if a VM-specific "sim_vm_fprint_stopped" pointer is defined,
6746  * call the indicated routine to print additional information after the message
6747  * and before the PC value is printed.  If the routine returns FALSE, skip
6748  * printing the PC and its related instruction.
6749  */
6750 
6751 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6752 {
6753 int32 i;
6754 t_stat r = 0;
6755 t_addr k;
6756 t_value pcval;
6757 
6758 fputc ('\n', st);                                       /* start on a new line */
6759 
6760 if (v >= SCPE_BASE)                                     /* SCP error? */
6761     fputs (sim_error_text (v), st);                     /* print it from the SCP list */
6762 else {                                                  /* VM error */
6763     fputs (sim_stop_messages [v], st);                  /* print the VM-specific message */
6764 
6765     if ((sim_vm_fprint_stopped != NULL) &&              /* if a VM-specific stop handler is defined */
6766         (!sim_vm_fprint_stopped (st, v)))               /*   call it; if it returned FALSE, */
6767         return;                                         /*     we're done */
6768     }
6769 
6770 (void)fprintf (st, ", %s: ", pc->name);                       /* print the name of the PC register */
6771 
6772 pcval = get_rval (pc, 0);
6773 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)       /* if reg wants VM-specific printer */
6774     sim_vm_fprint_addr (st, dptr, (t_addr) pcval);      /*   call it to print the PC address */
6775 else fprint_val (st, pcval, pc->radix, pc->width,       /* otherwise, print as a numeric value */
6776     pc->flags & REG_FMT);                               /*   with the radix and formatting specified */
6777 if ((dptr != NULL) && (dptr->examine != NULL)) {
6778     for (i = 0; i < sim_emax; i++)
6779         sim_eval[i] = 0;
6780     for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6781         if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6782             break;
6783         }
6784     if ((r == SCPE_OK) || (i > 0)) {
6785         (void)fprintf (st, " (");
6786         if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6787             fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6788         (void)fprintf (st, ")");
6789         }
6790     }
6791 (void)fprintf (st, "\r\n");
6792 return;
6793 }
6794 
6795 void fprint_stopped (FILE *st, t_stat v)
     /* [previous][next][first][last][top][bottom][index][help] */
6796 {
6797 #if defined(WIN_STDIO)
6798 (void)fflush(stderr);
6799 (void)fflush(stdout);
6800 #endif /* if defined(WIN_STDIO) */
6801 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6802 return;
6803 }
6804 
6805 /* Unit service for step timeout, originally scheduled by STEP n command
6806    Return step timeout SCP code, will cause simulation to stop */
6807 
6808 t_stat step_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6809 {
6810 return SCPE_STEP;
6811 }
6812 
6813 /* Unit service to facilitate expect matching to stop simulation.
6814    Return expect SCP code, will cause simulation to stop */
6815 
6816 t_stat expect_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6817 {
6818 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6819 }
6820 
6821 /* Signal handler for ^C signal - set stop simulation flag */
6822 
6823 void int_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
6824 {
6825 stop_cpu = 1;
6826 return;
6827 }
6828 
6829 /* Examine/deposit commands */
6830 
6831 t_stat exdep_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6832 {
6833 char gbuf[CBUFSIZE];
6834 CONST char *gptr;
6835 CONST char *tptr = NULL;
6836 int32 opt;
6837 t_addr low, high;
6838 t_stat reason = SCPE_IERR;
6839 DEVICE *tdptr;
6840 REG *lowr, *highr;
6841 FILE *ofile;
6842 
6843 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;               /* options for all */
6844 if (flag == EX_E)                                       /* extra for EX */
6845     opt = opt | CMD_OPT_OF;
6846 cptr = get_sim_opt (opt, cptr, &reason);                /* get cmd options */
6847 if (NULL == cptr)                                       /* error? */
6848     return reason;
6849 if (*cptr == 0)                                         /* must be more */
6850     return SCPE_2FARG;
6851 if (sim_dfunit == NULL)                                 /* got a unit? */
6852     return SCPE_NXUN;
6853 cptr = get_glyph (cptr, gbuf, 0);                       /* get list */
6854 if ((flag == EX_D) && (*cptr == 0))                     /* deposit needs more */
6855 
6856     return SCPE_2FARG;
6857 ofile = sim_ofile? sim_ofile: stdout;                   /* no ofile? use stdout */
6858 
6859 for (gptr = gbuf, reason = SCPE_OK;
6860     (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6861     tdptr = sim_dfdev;                                  /* working dptr */
6862     if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6863         tptr = gptr + strlen ("STATE");
6864         if (*tptr && (*tptr++ != ','))
6865             return SCPE_ARG;
6866         if ((lowr = sim_dfdev->registers) == NULL)
6867             return SCPE_NXREG;
6868         for (highr = lowr; highr->name != NULL; highr++) ;
6869         sim_switches = sim_switches | SIM_SW_HIDE;
6870         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6871             lowr, --highr, 0, 0);
6872         continue;
6873         }
6874 
6875     /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
6876     if ((lowr = find_reg (gptr, &tptr, tdptr)) ||       /* local reg or */
6877         (!(sim_opt_out & CMD_OPT_DFT) &&                /* no dflt, global? */
6878         (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6879         low = high = 0;
6880         if ((*tptr == '-') || (*tptr == ':')) {
6881             highr = find_reg (tptr + 1, &tptr, tdptr);
6882             if (highr == NULL)
6883                 return SCPE_NXREG;
6884             }
6885         else {
6886             highr = lowr;
6887             if (*tptr == '[') {
6888                 if (lowr->depth <= 1)
6889                     return SCPE_ARG;
6890                 tptr = get_range (NULL, tptr + 1, &low, &high,
6891                     10, lowr->depth - 1, ']');
6892                 if (tptr == NULL)
6893                     return SCPE_ARG;
6894                 }
6895             }
6896         if (*tptr && (*tptr++ != ','))
6897             return SCPE_ARG;
6898         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6899             lowr, highr, (uint32) low, (uint32) high);
6900         continue;
6901         }
6902 
6903     tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6904         (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6905         sim_dfunit->capac - sim_dfdev->aincr), 0);
6906     if (tptr == NULL)
6907         return SCPE_ARG;
6908     if (*tptr && (*tptr++ != ','))
6909         return SCPE_ARG;
6910     reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6911         sim_dfdev, sim_dfunit);
6912     }                                                   /* end for */
6913 if (sim_ofile)                                          /* close output file */
6914     fclose (sim_ofile);
6915 return reason;
6916 }
6917 
6918 /* Loop controllers for examine/deposit
6919 
6920    exdep_reg_loop       examine/deposit range of registers
6921    exdep_addr_loop      examine/deposit range of addresses
6922 */
6923 
6924 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6925     REG *lowr, REG *highr, uint32 lows, uint32 highs)
6926 {
6927 t_stat reason;
6928 uint32 idx, val_start=lows;
6929 t_value val, last_val;
6930 REG *rptr;
6931 
6932 if ((lowr == NULL) || (highr == NULL))
6933     return SCPE_IERR;
6934 if (lowr > highr)
6935     return SCPE_ARG;
6936 for (rptr = lowr; rptr <= highr; rptr++) {
6937     if ((sim_switches & SIM_SW_HIDE) &&
6938         (rptr->flags & REG_HIDDEN))
6939         continue;
6940     val = last_val = 0;
6941     for (idx = lows; idx <= highs; idx++) {
6942         if (idx >= rptr->depth)
6943             return SCPE_SUB;
6944         val = get_rval (rptr, idx);
6945         if (schptr && !test_search (&val, schptr))
6946             continue;
6947         if (flag == EX_E) {
6948             if ((idx > lows) && (val == last_val))
6949                 continue;
6950             if (idx > val_start+1) {
6951                 if (idx-1 == val_start+1) {
6952                     reason = ex_reg (ofile, val, flag, rptr, idx-1);
6953                     if (reason != SCPE_OK)
6954                         return reason;
6955                     if (sim_log && (ofile == stdout))
6956                         ex_reg (sim_log, val, flag, rptr, idx-1);
6957                     }
6958                 else {
6959                     if (val_start+1 != idx-1) {
6960                         (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6961                         if (sim_log && (ofile == stdout))
6962                             (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6963                         }
6964                     else {
6965                         (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6966                         if (sim_log && (ofile == stdout))
6967                             (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6968                         }
6969                     }
6970                 }
6971             sim_last_val = last_val = val;
6972             val_start = idx;
6973             reason = ex_reg (ofile, val, flag, rptr, idx);
6974             if (reason != SCPE_OK)
6975                 return reason;
6976             if (sim_log && (ofile == stdout))
6977                 ex_reg (sim_log, val, flag, rptr, idx);
6978             }
6979         if (flag != EX_E) {
6980             reason = dep_reg (flag, cptr, rptr, idx);
6981             if (reason != SCPE_OK)
6982                 return reason;
6983             }
6984         }
6985     if ((flag == EX_E) && (val_start != highs)) {
6986         if (highs == val_start+1) {
6987             reason = ex_reg (ofile, val, flag, rptr, highs);
6988             if (reason != SCPE_OK)
6989                 return reason;
6990             if (sim_log && (ofile == stdout))
6991                 ex_reg (sim_log, val, flag, rptr, highs);
6992             }
6993         else {
6994             if (val_start+1 != highs) {
6995                 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6996                 if (sim_log && (ofile == stdout))
6997                     (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6998                 }
6999             else {
7000                 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7001                 if (sim_log && (ofile == stdout))
7002                     (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
7003                 }
7004             }
7005         }
7006     }
7007 return SCPE_OK;
7008 }
7009 
7010 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
7011     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
7012 {
7013 t_addr i, mask;
7014 t_stat reason;
7015 
7016 if (uptr->flags & UNIT_DIS)                             /* disabled? */
7017     return SCPE_UDIS;
7018 mask = (t_addr) width_mask[dptr->awidth];
7019 if ((low > mask) || (high > mask) || (low > high))
7020     return SCPE_ARG;
7021 for (i = low; i <= high; ) {                            /* all paths must incr!! */
7022     reason = get_aval (i, dptr, uptr);                  /* get data */
7023     if (reason != SCPE_OK)                              /* return if error */
7024         return reason;
7025     if (schptr && !test_search (sim_eval, schptr))
7026         i = i + dptr->aincr;                            /* sch fails, incr */
7027     else {                                              /* no sch or success */
7028         if (flag != EX_D) {                             /* ex, ie, or id? */
7029             reason = ex_addr (ofile, flag, i, dptr, uptr);
7030             if (reason > SCPE_OK)
7031                 return reason;
7032             if (sim_log && (ofile == stdout))
7033                 ex_addr (sim_log, flag, i, dptr, uptr);
7034             }
7035         else reason = 1 - dptr->aincr;                  /* no, dflt incr */
7036         if (flag != EX_E) {                             /* ie, id, or d? */
7037             reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7038             if (reason > SCPE_OK)
7039                 return reason;
7040             }
7041         i = i + (1 - reason);                           /* incr */
7042         }
7043     }
7044 return SCPE_OK;
7045 }
7046 
7047 /* Examine register routine
7048 
7049    Inputs:
7050         ofile   =       output stream
7051         val     =       current register value
7052         flag    =       type of ex/mod command (ex, iex, idep)
7053         rptr    =       pointer to register descriptor
7054         idx     =       index
7055    Outputs:
7056         return  =       error status
7057 */
7058 
7059 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7060 {
7061 int32 rdx;
7062 
7063 if (rptr == NULL)
7064     return SCPE_IERR;
7065 if (rptr->depth > 1)
7066     (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7067 else
7068     (void)Fprintf (ofile, "%s:\t", rptr->name);
7069 if (!(flag & EX_E))
7070     return SCPE_OK;
7071 GET_RADIX (rdx, rptr->radix);
7072 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7073     sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7074 else if (!(rptr->flags & REG_VMFLAGS) ||
7075     (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7076                  NULL, sim_switches | SIM_SW_REG) > 0)) {
7077         fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7078         if (rptr->fields) {
7079             (void)Fprintf (ofile, "\t");
7080             fprint_fields (ofile, val, val, rptr->fields);
7081             }
7082         }
7083 if (flag & EX_I)
7084     (void)Fprintf (ofile, "\t");
7085 else
7086     (void)Fprintf (ofile, "\r\n");
7087 return SCPE_OK;
7088 }
7089 
7090 /* Get register value
7091 
7092    Inputs:
7093         rptr    =       pointer to register descriptor
7094         idx     =       index
7095    Outputs:
7096         return  =       register value
7097 */
7098 
7099 t_value get_rval (REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7100 {
7101 size_t sz;
7102 t_value val;
7103 uint32 *ptr;
7104 
7105 sz = SZ_R (rptr);
7106 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7107     idx = idx + rptr->qptr;
7108     if (idx >= rptr->depth) idx = idx - rptr->depth;
7109     }
7110 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7111     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7112     if (sz <= sizeof (uint32))
7113         val = *ptr;
7114     else val = *((t_uint64 *) ptr); //-V1032
7115     }
7116 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7117     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7118     if (sz <= sizeof (uint32))
7119         val = *ptr;
7120     else val = *((t_uint64 *) ptr);
7121     }
7122 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7123     (sz == sizeof (uint8)))
7124     val = *(((uint8 *) rptr->loc) + idx);
7125 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7126     (sz == sizeof (uint16)))
7127     val = *(((uint16 *) rptr->loc) + idx);
7128 else if (sz <= sizeof (uint32))
7129      val = *(((uint32 *) rptr->loc) + idx);
7130 else val = *(((t_uint64 *) rptr->loc) + idx);
7131 val = (val >> rptr->offset) & width_mask[rptr->width];
7132 return val;
7133 }
7134 
7135 /* Deposit register routine
7136 
7137    Inputs:
7138         flag    =       type of deposit (normal/interactive)
7139         cptr    =       pointer to input string
7140         rptr    =       pointer to register descriptor
7141         idx     =       index
7142    Outputs:
7143         return  =       error status
7144 */
7145 
7146 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7147 {
7148 t_stat r;
7149 t_value val, mask;
7150 int32 rdx;
7151 CONST char *tptr;
7152 char gbuf[CBUFSIZE];
7153 
7154 if ((cptr == NULL) || (rptr == NULL))
7155     return SCPE_IERR;
7156 if (rptr->flags & REG_RO)
7157     return SCPE_RO;
7158 if (flag & EX_I) {
7159     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7160     if (sim_log)
7161         (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7162     if (cptr == NULL)                                   /* force exit */
7163         return 1;
7164     if (*cptr == 0)                                     /* success */
7165         return SCPE_OK;
7166     }
7167 mask = width_mask[rptr->width];
7168 GET_RADIX (rdx, rptr->radix);
7169 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {    /* address form? */
7170     val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7171     if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7172         return SCPE_ARG;
7173     }
7174 else
7175     if (!(rptr->flags & REG_VMFLAGS) ||                 /* don't use sym? */
7176         (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7177                     &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7178     val = get_uint (cptr, rdx, mask, &r);
7179     if (r != SCPE_OK)
7180         return SCPE_ARG;
7181     }
7182 if ((rptr->flags & REG_NZ) && (val == 0))
7183     return SCPE_ARG;
7184 put_rval (rptr, idx, val);
7185 return SCPE_OK;
7186 }
7187 
7188 /* Put register value
7189 
7190    Inputs:
7191         rptr    =       pointer to register descriptor
7192         idx     =       index
7193         val     =       new value
7194         mask    =       mask
7195    Outputs:
7196         none
7197 */
7198 
7199 void put_rval (REG *rptr, uint32 idx, t_value val)
     /* [previous][next][first][last][top][bottom][index][help] */
7200 {
7201 size_t sz;
7202 t_value mask;
7203 uint32 *ptr;
7204 
7205 #define PUT_RVAL(sz,rp,id,v,m)            \
7206     *(((sz *) rp->loc) + id) =            \
7207         (sz)((*(((sz *) rp->loc) + id) &  \
7208             ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7209 
7210 if (rptr == sim_PC)
7211     sim_brk_npc (0);
7212 sz = SZ_R (rptr);
7213 mask = width_mask[rptr->width];
7214 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7215     idx = idx + rptr->qptr;
7216     if (idx >= rptr->depth)
7217         idx = idx - rptr->depth;
7218     }
7219 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7220     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7221     if (sz <= sizeof (uint32))
7222         *ptr = (*ptr &
7223         ~(((uint32) mask) << rptr->offset)) |
7224         (((uint32) val) << rptr->offset);
7225     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr) //-V1032
7226         & ~(mask << rptr->offset)) | (val << rptr->offset);
7227     }
7228 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7229     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7230     if (sz <= sizeof (uint32))
7231         *((uint32 *) ptr) = (*((uint32 *) ptr) &
7232         ~(((uint32) mask) << rptr->offset)) |
7233         (((uint32) val) << rptr->offset);
7234     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7235         & ~(mask << rptr->offset)) | (val << rptr->offset);
7236     }
7237 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7238     (sz == sizeof (uint8)))
7239     PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7240 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7241     (sz == sizeof (uint16)))
7242     PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7243 else if (sz <= sizeof (uint32))
7244     PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7245 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7246 return;
7247 }
7248 
7249 /* Examine address routine
7250 
7251    Inputs: (sim_eval is an implicit argument)
7252         ofile   =       output stream
7253         flag    =       type of ex/mod command (ex, iex, idep)
7254         addr    =       address to examine
7255         dptr    =       pointer to device
7256         uptr    =       pointer to unit
7257    Outputs:
7258         return  =       if > 0, error status
7259                         if <= 0,-number of extra addr units retired
7260 */
7261 
7262 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7263 {
7264 t_stat reason;
7265 int32 rdx;
7266 
7267 if (sim_vm_fprint_addr)
7268     sim_vm_fprint_addr (ofile, dptr, addr);
7269 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7270 (void)Fprintf (ofile, ":\t");
7271 if (!(flag & EX_E))
7272     return (1 - dptr->aincr);
7273 
7274 GET_RADIX (rdx, dptr->dradix);
7275 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7276     fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7277     reason = 1 - dptr->aincr;
7278     }
7279 if (flag & EX_I)
7280     (void)Fprintf (ofile, "\t");
7281 else
7282     (void)Fprintf (ofile, "\r\n");
7283 return reason;
7284 }
7285 
7286 /* Get address routine
7287 
7288    Inputs:
7289         flag    =       type of ex/mod command (ex, iex, idep)
7290         addr    =       address to examine
7291         dptr    =       pointer to device
7292         uptr    =       pointer to unit
7293    Outputs: (sim_eval is an implicit output)
7294         return  =       error status
7295 */
7296 
7297 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7298 {
7299 int32 i;
7300 t_value mask;
7301 t_addr j, loc;
7302 size_t sz;
7303 t_stat reason = SCPE_OK;
7304 
7305 if ((dptr == NULL) || (uptr == NULL))
7306     return SCPE_IERR;
7307 mask = width_mask[dptr->dwidth];
7308 for (i = 0; i < sim_emax; i++)
7309     sim_eval[i] = 0;
7310 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7311     if (dptr->examine != NULL) {
7312         reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7313         if (reason != SCPE_OK)
7314             break;
7315         }
7316     else {
7317         if (!(uptr->flags & UNIT_ATT))
7318             return SCPE_UNATT;
7319         if (uptr->dynflags & UNIT_NO_FIO)
7320             return SCPE_NOFNC;
7321         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7322             reason = SCPE_NXM;
7323             break;
7324             }
7325         sz = SZ_D (dptr);
7326         loc = j / dptr->aincr;
7327         if (uptr->flags & UNIT_BUF) {
7328             SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7329             }
7330         else {
7331             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7332             sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7333             if ((feof (uptr->fileref)) &&
7334                !(uptr->flags & UNIT_FIX)) {
7335                 reason = SCPE_EOF;
7336                 break;
7337                 }
7338             else if (ferror (uptr->fileref)) {
7339                 clearerr (uptr->fileref);
7340                 reason = SCPE_IOERR;
7341                 break;
7342                 }
7343             }
7344         }
7345     sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7346     }
7347 if ((reason != SCPE_OK) && (i == 0))
7348     return reason;
7349 return SCPE_OK;
7350 }
7351 
7352 /* Deposit address routine
7353 
7354    Inputs:
7355         flag    =       type of deposit (normal/interactive)
7356         cptr    =       pointer to input string
7357         addr    =       address to examine
7358         dptr    =       pointer to device
7359         uptr    =       pointer to unit
7360         dfltinc =       value to return on cr input
7361    Outputs:
7362         return  =       if > 0, error status
7363                         if <= 0, -number of extra address units retired
7364 */
7365 
7366 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
7367     UNIT *uptr, int32 dfltinc)
7368 {
7369 int32 i, count, rdx;
7370 t_addr j, loc;
7371 t_stat r, reason;
7372 t_value mask;
7373 size_t sz;
7374 char gbuf[CBUFSIZE];
7375 
7376 if (dptr == NULL)
7377     return SCPE_IERR;
7378 if (flag & EX_I) {
7379     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7380     if (sim_log)
7381         (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7382     if (cptr == NULL)                                   /* force exit */
7383         return 1;
7384     if (*cptr == 0)                                     /* success */
7385         return dfltinc;
7386     }
7387 if (uptr->flags & UNIT_RO)                              /* read only? */
7388     return SCPE_RO;
7389 mask = width_mask[dptr->dwidth];
7390 
7391 GET_RADIX (rdx, dptr->dradix);
7392 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7393     sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7394     if (reason != SCPE_OK)
7395         return reason;
7396     reason = dfltinc;
7397     }
7398 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7399 
7400 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7401     sim_eval[i] = sim_eval[i] & mask;
7402     if (dptr->deposit != NULL) {
7403         r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7404         if (r != SCPE_OK)
7405             return r;
7406         }
7407     else {
7408         if (!(uptr->flags & UNIT_ATT))
7409             return SCPE_UNATT;
7410         if (uptr->dynflags & UNIT_NO_FIO)
7411             return SCPE_NOFNC;
7412         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7413             return SCPE_NXM;
7414         sz = SZ_D (dptr);
7415         loc = j / dptr->aincr;
7416         if (uptr->flags & UNIT_BUF) {
7417             SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7418             if (loc >= uptr->hwmark)
7419                 uptr->hwmark = (uint32) loc + 1;
7420             }
7421         else {
7422             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7423             sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7424             if (ferror (uptr->fileref)) {
7425                 clearerr (uptr->fileref);
7426                 return SCPE_IOERR;
7427                 }
7428             }
7429         }
7430     }
7431 return reason;
7432 }
7433 
7434 /* Evaluate command */
7435 
7436 t_stat eval_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7437 {
7438 if (!sim_dflt_dev)
7439   return SCPE_ARG;
7440 DEVICE *dptr = sim_dflt_dev;
7441 int32 i, rdx, a, lim;
7442 t_stat r;
7443 
7444 GET_SWITCHES (cptr);
7445 GET_RADIX (rdx, dptr->dradix);
7446 for (i = 0; i < sim_emax; i++)
7447 sim_eval[i] = 0;
7448 if (*cptr == 0)
7449     return SCPE_2FARG;
7450 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7451     sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7452     if (r != SCPE_OK)
7453         return r;
7454     }
7455 lim = 1 - r;
7456 for (i = a = 0; a < lim; ) {
7457     sim_printf ("%d:\t", a);
7458     if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7459         r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7460     if (sim_log) {
7461         if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7462             r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7463         }
7464     sim_printf ("\r\n");
7465     if (r < 0)
7466         a = a + 1 - r;
7467     else a = a + dptr->aincr;
7468     i = a / dptr->aincr;
7469     }
7470 return SCPE_OK;
7471 }
7472 
7473 /* String processing routines
7474 
7475    read_line            read line
7476 
7477    Inputs:
7478         cptr    =       pointer to buffer
7479         size    =       maximum size
7480         stream  =       pointer to input stream
7481    Outputs:
7482         optr    =       pointer to first non-blank character
7483                         NULL if EOF
7484 */
7485 
7486 char *read_line (char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7487 {
7488 return read_line_p (NULL, cptr, size, stream);
7489 }
7490 
7491 /* read_line_p          read line with prompt
7492 
7493    Inputs:
7494         prompt  =       pointer to prompt string
7495         cptr    =       pointer to buffer
7496         size    =       maximum size
7497         stream  =       pointer to input stream
7498    Outputs:
7499         optr    =       pointer to first non-blank character
7500                         NULL if EOF
7501 */
7502 
7503 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7504 {
7505 char *tptr;
7506 
7507 if (prompt) {                                           /* interactive? */
7508 #if defined(HAVE_LINEHISTORY)
7509         char *tmpc = linenoise (prompt);                /* get cmd line */
7510         if (tmpc == NULL)                               /* bad result? */
7511             cptr = NULL;
7512         else {
7513             strncpy (cptr, tmpc, size-1);               /* copy result */
7514             linenoiseHistoryAdd (tmpc);                 /* add to history */
7515             FREE (tmpc);                                /* free temp */
7516             }
7517         }
7518 #else
7519         (void)fflush (stdout);                          /* flush output */
7520         (void)printf ("%s", prompt);                    /* display prompt */
7521         (void)fflush (stdout);                          /* flush output */
7522         cptr = fgets (cptr, size, stream);              /* get cmd line */
7523         }
7524 #endif /* if defined(HAVE_LINEHISTORY) */
7525 else cptr = fgets (cptr, size, stream);                 /* get cmd line */
7526 
7527 if (cptr == NULL) {
7528     clearerr (stream);                                  /* clear error */
7529     return NULL;                                        /* ignore EOF */
7530     }
7531 for (tptr = cptr; tptr < (cptr + size); tptr++) {       /* remove cr or nl */
7532     if ((*tptr == '\n') || (*tptr == '\r') ||
7533         (tptr == (cptr + size - 1))) {                  /* str max length? */
7534         *tptr = 0;                                      /* terminate */
7535         break;
7536         }
7537     }
7538 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))              /* Skip/ignore UTF8_BOM */
7539     memmove (cptr, cptr + 3, strlen (cptr + 3));
7540 while (sim_isspace (*cptr))                             /* trim leading spc */
7541     cptr++;
7542 if ((*cptr == ';') || (*cptr == '#')) {                 /* ignore comment */
7543     if (sim_do_echo)                                    /* echo comments if -v */
7544         sim_printf("%s> %s\r\n", do_position(), cptr);
7545     *cptr = 0;
7546     }
7547 
7548 return cptr;
7549 }
7550 
7551 /* get_glyph            get next glyph (force upper case)
7552    get_glyph_nc         get next glyph (no conversion)
7553    get_glyph_quoted     get next glyph (potentially enclosed in quotes, no conversion)
7554    get_glyph_cmd        get command glyph (force upper case, extract leading !)
7555    get_glyph_gen        get next glyph (general case)
7556 
7557    Inputs:
7558         iptr        =   pointer to input string
7559         optr        =   pointer to output string
7560         mchar       =   optional end of glyph character
7561         uc          =   TRUE for convert to upper case (_gen only)
7562         quote       =   TRUE to allow quote enclosing values (_gen only)
7563         escape_char =   optional escape character within quoted strings (_gen only)
7564 
7565    Outputs
7566         result      =   pointer to next character in input string
7567 */
7568 
7569 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] */
7570 {
7571 t_bool quoting = FALSE;
7572 t_bool escaping = FALSE;
7573 char quote_char = 0;
7574 
7575 while ((*iptr != 0) &&
7576        ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7577     if (quote) {
7578         if (quoting) {
7579             if (!escaping) {
7580                 if (*iptr == escape_char)
7581                     escaping = TRUE;
7582                 else
7583                     if (*iptr == quote_char)
7584                         quoting = FALSE;
7585                 }
7586             else
7587                 escaping = FALSE;
7588             }
7589         else {
7590             if ((*iptr == '"') || (*iptr == '\'')) {
7591                 quoting = TRUE;
7592                 quote_char = *iptr;
7593                 }
7594             }
7595         }
7596     if (sim_islower (*iptr) && uc)
7597         *optr = (char)toupper (*iptr);
7598     else *optr = *iptr;
7599     iptr++; optr++;
7600     }
7601 if (mchar && (*iptr == mchar))              /* skip input terminator */
7602     iptr++;
7603 *optr = 0;                                  /* terminate result string */
7604 while (sim_isspace (*iptr))                 /* absorb additional input spaces */
7605     iptr++;
7606 return iptr;
7607 }
7608 
7609 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7610 {
7611 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7612 }
7613 
7614 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7615 {
7616 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7617 }
7618 
7619 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7620 {
7621 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7622 }
7623 
7624 CONST char *get_glyph_cmd (const char *iptr, char *optr)
     /* [previous][next][first][last][top][bottom][index][help] */
7625 {
7626 /* Tolerate "!subprocess" vs. requiring "! subprocess" */
7627 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7628     strcpy (optr, "!");                     /* return ! as command glyph */
7629     return (CONST char *)(iptr + 1);        /* and skip over the leading ! */
7630     }
7631 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7632 }
7633 
7634 /* Trim trailing spaces from a string
7635 
7636     Inputs:
7637         cptr    =       pointer to string
7638     Outputs:
7639         cptr    =       pointer to string
7640 */
7641 
7642 char *sim_trim_endspc (char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7643 {
7644 char *tptr;
7645 
7646 tptr = cptr + strlen (cptr);
7647 while ((--tptr >= cptr) && sim_isspace (*tptr))
7648     *tptr = 0;
7649 return cptr;
7650 }
7651 
7652 int sim_isspace (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7653 {
7654 return (c & 0x80) ? 0 : isspace (c);
7655 }
7656 
7657 int sim_islower (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7658 {
7659 return (c & 0x80) ? 0 : islower (c);
7660 }
7661 
7662 int sim_isalpha (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7663 {
7664 return (c & 0x80) ? 0 : isalpha (c);
7665 }
7666 
7667 int sim_isprint (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7668 {
7669 return (c & 0x80) ? 0 : isprint (c);
7670 }
7671 
7672 int sim_isdigit (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7673 {
7674 return (c & 0x80) ? 0 : isdigit (c);
7675 }
7676 
7677 int sim_isgraph (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7678 {
7679 return (c & 0x80) ? 0 : isgraph (c);
7680 }
7681 
7682 int sim_isalnum (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7683 {
7684 return (c & 0x80) ? 0 : isalnum (c);
7685 }
7686 
7687 /* get_uint             unsigned number
7688 
7689    Inputs:
7690         cptr    =       pointer to input string
7691         radix   =       input radix
7692         max     =       maximum acceptable value
7693         *status =       pointer to error status
7694    Outputs:
7695         val     =       value
7696 */
7697 
7698 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
     /* [previous][next][first][last][top][bottom][index][help] */
7699 {
7700 t_value val;
7701 CONST char *tptr;
7702 
7703 *status = SCPE_OK;
7704 val = strtotv ((CONST char *)cptr, &tptr, radix);
7705 if ((cptr == tptr) || (val > max))
7706     *status = SCPE_ARG;
7707 else {
7708     while (sim_isspace (*tptr)) tptr++;
7709     if (*tptr != 0)
7710         *status = SCPE_ARG;
7711     }
7712 return val;
7713 }
7714 
7715 /* get_range            range specification
7716 
7717    Inputs:
7718         dptr    =       pointer to device (NULL if none)
7719         cptr    =       pointer to input string
7720         *lo     =       pointer to low result
7721         *hi     =       pointer to high result
7722         aradix  =       radix
7723         max     =       default high value
7724         term    =       terminating character, 0 if none
7725    Outputs:
7726         tptr    =       input pointer after processing
7727                         NULL if error
7728 */
7729 
7730 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
     /* [previous][next][first][last][top][bottom][index][help] */
7731     uint32 rdx, t_addr max, char term)
7732 {
7733 CONST char *tptr;
7734 
7735 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {    /* ALL? */
7736     tptr = cptr + strlen ("ALL");
7737     *lo = 0;
7738     *hi = max;
7739     }
7740 else {
7741     if ((strncmp (cptr, ".", strlen (".")) == 0) &&             /* .? */
7742         ((cptr[1] == '\0') ||
7743          (cptr[1] == '-')  ||
7744          (cptr[1] == ':')  ||
7745          (cptr[1] == '/'))) {
7746         tptr = cptr + strlen (".");
7747         *lo = *hi = sim_last_addr;
7748         }
7749     else {
7750         if (strncmp (cptr, "$", strlen ("$")) == 0) {           /* $? */
7751             tptr = cptr + strlen ("$");
7752             *hi = *lo = (t_addr)sim_last_val;
7753             }
7754         else {
7755             if (dptr && sim_vm_parse_addr)                      /* get low */
7756                 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7757             else
7758                 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7759             if (cptr == tptr)                                   /* error? */
7760                     return NULL;
7761             }
7762         }
7763     if ((*tptr == '-') || (*tptr == ':')) {             /* range? */
7764         cptr = tptr + 1;
7765         if (dptr && sim_vm_parse_addr)                  /* get high */
7766             *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7767         else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7768         if (cptr == tptr)
7769             return NULL;
7770         if (*lo > *hi)
7771             return NULL;
7772         }
7773     else if (*tptr == '/') {                            /* relative? */
7774         cptr = tptr + 1;
7775         *hi = (t_addr) strtotv (cptr, &tptr, rdx);      /* get high */
7776         if ((cptr == tptr) || (*hi == 0))
7777             return NULL;
7778         *hi = *lo + *hi - 1;
7779         }
7780     else *hi = *lo;
7781     }
7782 sim_last_addr = *hi;
7783 if (term && (*tptr++ != term))
7784     return NULL;
7785 return tptr;
7786 }
7787 
7788 /* sim_decode_quoted_string
7789 
7790    Inputs:
7791         iptr        =   pointer to input string
7792         optr        =   pointer to output buffer
7793                         the output buffer must be allocated by the caller
7794                         and to avoid overrunat it must be at least as big
7795                         as the input string.
7796 
7797    Outputs
7798         result      =   status of decode SCPE_OK when good, SCPE_ARG otherwise
7799         osize       =   size of the data in the optr buffer
7800 
7801    The input string must be quoted.  Quotes may be either single or
7802    double but the opening anc closing quote characters must match.
7803    Within quotes C style character escapes are allowed.
7804 */
7805 
7806 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
     /* [previous][next][first][last][top][bottom][index][help] */
7807 {
7808 char quote_char;
7809 uint8 *ostart = optr;
7810 
7811 *osize = 0;
7812 if ((strlen(iptr) == 1) ||
7813     (iptr[0] != iptr[strlen(iptr)-1]) ||
7814     ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7815     return SCPE_ARG;            /* String must be quote delimited */
7816 quote_char = *iptr++;           /* Save quote character */
7817 while (iptr[1]) {               /* Skip trailing quote */
7818     if (*iptr != '\\') {
7819         if (*iptr == quote_char)
7820             return SCPE_ARG;    /* Embedded quotes must be escaped */
7821         *(optr++) = (uint8)(*(iptr++));
7822         continue;
7823         }
7824     ++iptr; /* Skip backslash */
7825     switch (*iptr) {
7826         case 'r':   /* ASCII Carriage Return character (Decimal value 13) */
7827             *(optr++) = 13; ++iptr;
7828             break;
7829         case 'n':   /* ASCII Linefeed character (Decimal value 10) */
7830             *(optr++) = 10; ++iptr;
7831             break;
7832         case 'f':   /* ASCII Formfeed character (Decimal value 12) */
7833             *(optr++) = 12; ++iptr;
7834             break;
7835         case 't':   /* ASCII Horizontal Tab character (Decimal value 9) */
7836             *(optr++) = 9; ++iptr;
7837             break;
7838         case 'v':   /* ASCII Vertical Tab character (Decimal value 11) */
7839             *(optr++) = 11; ++iptr;
7840             break;
7841         case 'b':   /* ASCII Backspace character (Decimal value 8) */
7842             *(optr++) = 8; ++iptr;
7843             break;
7844         case '\\':   /* ASCII Backslash character (Decimal value 92) */
7845             *(optr++) = 92; ++iptr;
7846             break;
7847         case 'e':   /* ASCII Escape character (Decimal value 27) */
7848             *(optr++) = 27; ++iptr;
7849             break;
7850         case '\'':   /* ASCII Single Quote character (Decimal value 39) */
7851             *(optr++) = 39; ++iptr;
7852             break;
7853         case '"':   /* ASCII Double Quote character (Decimal value 34) */
7854             *(optr++) = 34; ++iptr;
7855             break;
7856         case '?':   /* ASCII Question Mark character (Decimal value 63) */
7857             *(optr++) = 63; ++iptr;
7858             break;
7859         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7860             *optr = *(iptr++) - '0';
7861             if ((*iptr >= '0') && (*iptr <= '7'))
7862                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7863             if ((*iptr >= '0') && (*iptr <= '7'))
7864                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7865             ++optr;
7866             break;
7867         case 'x':
7868             if (1) {
7869                 static const char *hex_digits = "0123456789ABCDEF";
7870                 const char *c;
7871 
7872                 ++iptr;
7873                 *optr = 0;
7874                 c = strchr (hex_digits, toupper(*iptr));
7875                 if (c) {
7876                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7877                     ++iptr;
7878                     }
7879                 c = strchr (hex_digits, toupper(*iptr));
7880                 if (c) {
7881                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7882                     ++iptr;
7883                     }
7884                 ++optr;
7885                 }
7886             break;
7887         default:
7888             return SCPE_ARG;    /* Invalid escape */
7889         }
7890     }
7891 *optr = '\0';
7892 *osize = (uint32)(optr-ostart);
7893 return SCPE_OK;
7894 }
7895 
7896 /* sim_encode_quoted_string
7897 
7898    Inputs:
7899         iptr        =   pointer to input buffer
7900         size        =   number of bytes of data in the buffer
7901 
7902    Outputs
7903         optr        =   pointer to output buffer
7904                         the output buffer must be freed by the caller
7905 
7906    The input data will be encoded into a simply printable form.
7907 */
7908 
7909 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7910 {
7911 size_t i;
7912 t_bool double_quote_found = FALSE;
7913 t_bool single_quote_found = FALSE;
7914 char quote = '"';
7915 char *tptr, *optr;
7916 
7917 optr = (char *)malloc (4*size + 3);
7918 if (optr == NULL)
7919     return NULL;
7920 tptr = optr;
7921 for (i=0; i<size; i++)
7922     switch ((char)iptr[i]) {
7923         case '"':
7924             double_quote_found = TRUE;
7925             break;
7926         case '\'':
7927             single_quote_found = TRUE;
7928             break;
7929         }
7930 if (double_quote_found && (!single_quote_found))
7931     quote = '\'';
7932 *tptr++ = quote;
7933 while (size--) {
7934     switch (*iptr) {
7935         case '\r':
7936             *tptr++ = '\\'; *tptr++ = 'r'; break;
7937         case '\n':
7938             *tptr++ = '\\'; *tptr++ = 'n'; break;
7939         case '\f':
7940             *tptr++ = '\\'; *tptr++ = 'f'; break;
7941         case '\t':
7942             *tptr++ = '\\'; *tptr++ = 't'; break;
7943         case '\v':
7944             *tptr++ = '\\'; *tptr++ = 'v'; break;
7945         case '\b':
7946             *tptr++ = '\\'; *tptr++ = 'b'; break;
7947         case '\\':
7948             *tptr++ = '\\'; *tptr++ = '\\'; break;
7949         case '"':
7950         case '\'':
7951             if (quote == *iptr)
7952                 *tptr++ = '\\';
7953         /*FALLTHRU*/ /* fall through */ /* fallthrough */
7954         default:
7955             if (sim_isprint (*iptr))
7956                 *tptr++ = *iptr;
7957             else {
7958                 (void)sprintf (tptr, "\\%03o", *iptr);
7959                 tptr += 4;
7960                 }
7961             break;
7962         }
7963     ++iptr;
7964     }
7965 *tptr++ = quote;
7966 *tptr++ = '\0';
7967 return optr;
7968 }
7969 
7970 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7971 {
7972 char *string;
7973 
7974 string = sim_encode_quoted_string (buf, size);
7975 (void)fprintf (st, "%s", string);
7976 FREE (string);
7977 }
7978 
7979 /* Find_device          find device matching input string
7980 
7981    Inputs:
7982         cptr    =       pointer to input string
7983    Outputs:
7984         result  =       pointer to device
7985 */
7986 
7987 DEVICE *find_dev (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7988 {
7989 int32 i;
7990 DEVICE *dptr;
7991 
7992 if (cptr == NULL)
7993     return NULL;
7994 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7995     if ((strcmp (cptr, dptr->name) == 0) ||
7996         (dptr->lname &&
7997         (strcmp (cptr, dptr->lname) == 0)))
7998         return dptr;
7999     }
8000 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
8001     if ((strcmp (cptr, dptr->name) == 0) ||
8002         (dptr->lname &&
8003         (strcmp (cptr, dptr->lname) == 0)))
8004         return dptr;
8005     }
8006 return NULL;
8007 }
8008 
8009 /* Find_unit            find unit matching input string
8010 
8011    Inputs:
8012         cptr    =       pointer to input string
8013         uptr    =       pointer to unit pointer
8014    Outputs:
8015         result  =       pointer to device (null if no dev)
8016         *iptr   =       pointer to unit (null if nx unit)
8017 
8018 */
8019 
8020 DEVICE *find_unit (const char *cptr, UNIT **uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8021 {
8022 uint32 i, u;
8023 const char *nptr;
8024 const char *tptr;
8025 t_stat r;
8026 DEVICE *dptr;
8027 
8028 if (uptr == NULL)                                       /* arg error? */
8029     return NULL;
8030 *uptr = NULL;
8031 if ((dptr = find_dev (cptr))) {                         /* exact match? */
8032     if (qdisable (dptr))                                /* disabled? */
8033         return NULL;
8034     *uptr = dptr->units;                                /* unit 0 */
8035     return dptr;
8036     }
8037 
8038 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {     /* base + unit#? */
8039     if (qdisable (dptr))                                /* device disabled? */
8040         continue;
8041     if (dptr->numunits && /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/ /* any units? */
8042         (((nptr = dptr->name) &&
8043           (strncmp (cptr, nptr, strlen (nptr)) == 0)) || /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8044          ((nptr = dptr->lname) &&
8045           (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8046         tptr = cptr + strlen (nptr);
8047         if (sim_isdigit (*tptr)) {
8048             if (qdisable (dptr))                        /* disabled? */
8049                 return NULL;
8050             u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8051             if (r != SCPE_OK)                           /* error? */
8052                 *uptr = NULL;
8053             else
8054                 *uptr = dptr->units + u;
8055             return dptr;
8056             }
8057         }
8058     for (u = 0; u < dptr->numunits; u++) {
8059         if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8060             *uptr = &dptr->units[u];
8061             return dptr;
8062             }
8063         }
8064     }
8065 return NULL;
8066 }
8067 
8068 /* sim_register_internal_device   Add device to internal device list
8069 
8070    Inputs:
8071         dptr    =       pointer to device
8072 */
8073 
8074 t_stat sim_register_internal_device (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8075 {
8076 uint32 i;
8077 
8078 for (i = 0; (sim_devices[i] != NULL); i++)
8079     if (sim_devices[i] == dptr)
8080         return SCPE_OK;
8081 for (i = 0; i < sim_internal_device_count; i++)
8082     if (sim_internal_devices[i] == dptr)
8083         return SCPE_OK;
8084 ++sim_internal_device_count;
8085 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8086 if (!sim_internal_devices)
8087   {
8088     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8089                    __func__, __FILE__, __LINE__);
8090 #if defined(USE_BACKTRACE)
8091 # if defined(SIGUSR2)
8092     (void)raise(SIGUSR2);
8093     /*NOTREACHED*/ /* unreachable */
8094 # endif /* if defined(SIGUSR2) */
8095 #endif /* if defined(USE_BACKTRACE) */
8096     abort();
8097   }
8098 sim_internal_devices[sim_internal_device_count-1] = dptr;
8099 sim_internal_devices[sim_internal_device_count] = NULL;
8100 return SCPE_OK;
8101 }
8102 
8103 /* Find_dev_from_unit   find device for unit
8104 
8105    Inputs:
8106         uptr    =       pointer to unit
8107    Outputs:
8108         result  =       pointer to device
8109 */
8110 
8111 DEVICE *find_dev_from_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8112 {
8113 DEVICE *dptr;
8114 uint32 i, j;
8115 
8116 if (uptr == NULL)
8117     return NULL;
8118 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8119     for (j = 0; j < dptr->numunits; j++) {
8120         if (uptr == (dptr->units + j))
8121             return dptr;
8122         }
8123     }
8124 for (i = 0; i<sim_internal_device_count; i++) {
8125     dptr = sim_internal_devices[i];
8126     for (j = 0; j < dptr->numunits; j++) {
8127         if (uptr == (dptr->units + j))
8128             return dptr;
8129         }
8130     }
8131 return NULL;
8132 }
8133 
8134 /* Test for disabled device */
8135 
8136 t_bool qdisable (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8137 {
8138 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8139 }
8140 
8141 /* find_reg_glob        find globally unique register
8142 
8143    Inputs:
8144         cptr    =       pointer to input string
8145         optr    =       pointer to output pointer (can be null)
8146         gdptr   =       pointer to global device
8147    Outputs:
8148         result  =       pointer to register, NULL if error
8149         *optr   =       pointer to next character in input string
8150         *gdptr  =       pointer to device where found
8151 */
8152 
8153 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8154 {
8155 int32 i;
8156 DEVICE *dptr;
8157 REG *rptr, *srptr = NULL;
8158 
8159 *gdptr = NULL;
8160 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {        /* all dev */
8161     if (dptr->flags & DEV_DIS)                          /* skip disabled */
8162         continue;
8163     if ((rptr = find_reg (cptr, optr, dptr))) {         /* found? */
8164         if (srptr)                                      /* ambig? err */
8165             return NULL;
8166         srptr = rptr;                                   /* save reg */
8167         *gdptr = dptr;                                  /* save unit */
8168         }
8169     }
8170 return srptr;
8171 }
8172 
8173 /* find_reg             find register matching input string
8174 
8175    Inputs:
8176         cptr    =       pointer to input string
8177         optr    =       pointer to output pointer (can be null)
8178         dptr    =       pointer to device
8179    Outputs:
8180         result  =       pointer to register, NULL if error
8181         *optr   =       pointer to next character in input string
8182 */
8183 
8184 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8185 {
8186 CONST char *tptr;
8187 REG *rptr;
8188 size_t slnt;
8189 
8190 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8191     return NULL;
8192 tptr = cptr;
8193 do {
8194     tptr++;
8195     } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8196 slnt = tptr - cptr;
8197 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8198     if ((slnt == strlen (rptr->name)) &&
8199         (strncmp (cptr, rptr->name, slnt) == 0)) {
8200         if (optr != NULL)
8201             *optr = tptr;
8202         return rptr;
8203         }
8204     }
8205 return NULL;
8206 }
8207 
8208 /* get_switches         get switches from input string
8209 
8210    Inputs:
8211         cptr    =       pointer to input string
8212    Outputs:
8213         sw      =       switch bit mask
8214                         0 if no switches, -1 if error
8215 */
8216 
8217 int32 get_switches (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8218 {
8219 int32 sw;
8220 
8221 if (*cptr != '-')
8222     return 0;
8223 sw = 0;
8224 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8225     if (sim_isalpha (*cptr) == 0)
8226         return -1;
8227     sw = sw | SWMASK (toupper (*cptr));
8228     }
8229 return sw;
8230 }
8231 
8232 /* get_sim_sw           accumulate sim_switches
8233 
8234    Inputs:
8235         cptr    =       pointer to input string
8236    Outputs:
8237         ptr     =       pointer to first non-string glyph
8238                         NULL if error
8239 */
8240 
8241 CONST char *get_sim_sw (CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8242 {
8243 int32 lsw;
8244 char gbuf[CBUFSIZE];
8245 
8246 while (*cptr == '-') {                                  /* while switches */
8247     cptr = get_glyph (cptr, gbuf, 0);                   /* get switch glyph */
8248     lsw = get_switches (gbuf);                          /* parse */
8249     if (lsw <= 0)                                       /* invalid? */
8250         return NULL;
8251     sim_switches = sim_switches | lsw;                  /* accumulate */
8252     }
8253 return cptr;
8254 }
8255 
8256 /* get_sim_opt          get simulator command options
8257 
8258    Inputs:
8259         opt     =       command options
8260         cptr    =       pointer to input string
8261    Outputs:
8262         ptr     =       pointer to next glyph, NULL if error
8263         *stat   =       error status
8264 */
8265 
8266 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
     /* [previous][next][first][last][top][bottom][index][help] */
8267 {
8268 int32 t;
8269 char gbuf[CBUFSIZE];
8270 CONST char *svptr;
8271 DEVICE *tdptr;
8272 UNIT *tuptr;
8273 
8274 sim_switches = 0;                                       /* no switches */
8275 sim_ofile = NULL;                                       /* no output file */
8276 sim_schrptr = NULL;                                     /* no search */
8277 sim_schaptr = NULL;                                     /* no search */
8278 sim_stabr.logic = sim_staba.logic = SCH_OR;             /* default search params */
8279 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8280 sim_stabr.count = 1;
8281 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8282 if (!sim_stabr.mask)
8283   {
8284     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8285                    __func__, __FILE__, __LINE__);
8286 #if defined(USE_BACKTRACE)
8287 # if defined(SIGUSR2)
8288     (void)raise(SIGUSR2);
8289     /*NOTREACHED*/ /* unreachable */
8290 # endif /* if defined(SIGUSR2) */
8291 #endif /* if defined(USE_BACKTRACE) */
8292     abort();
8293   }
8294 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8295 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8296 if (!sim_stabr.comp)
8297   {
8298     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8299                    __func__, __FILE__, __LINE__);
8300 #if defined(USE_BACKTRACE)
8301 # if defined(SIGUSR2)
8302     (void)raise(SIGUSR2);
8303     /*NOTREACHED*/ /* unreachable */
8304 # endif /* if defined(SIGUSR2) */
8305 #endif /* if defined(USE_BACKTRACE) */
8306     abort();
8307   }
8308 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8309 sim_staba.count = sim_emax;
8310 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8311 if (!sim_staba.mask)
8312   {
8313     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8314                    __func__, __FILE__, __LINE__);
8315 #if defined(USE_BACKTRACE)
8316 # if defined(SIGUSR2)
8317     (void)raise(SIGUSR2);
8318     /*NOTREACHED*/ /* unreachable */
8319 # endif /* if defined(SIGUSR2) */
8320 #endif /* if defined(USE_BACKTRACE) */
8321     abort();
8322   }
8323 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8324 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8325 if (!sim_staba.comp)
8326   {
8327     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8328                    __func__, __FILE__, __LINE__);
8329 #if defined(USE_BACKTRACE)
8330 # if defined(SIGUSR2)
8331     (void)raise(SIGUSR2);
8332     /*NOTREACHED*/ /* unreachable */
8333 # endif /* if defined(SIGUSR2) */
8334 #endif /* if defined(USE_BACKTRACE) */
8335     abort();
8336   }
8337 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8338 if (! sim_dflt_dev)
8339   return NULL;
8340 sim_dfdev = sim_dflt_dev;
8341 sim_dfunit = sim_dfdev->units;
8342 sim_opt_out = 0;                                        /* no options yet */
8343 *st = SCPE_OK;
8344 while (*cptr) {                                         /* loop through modifiers */
8345     svptr = cptr;                                       /* save current position */
8346     if ((opt & CMD_OPT_OF) && (*cptr == '@')) {         /* output file spec? */
8347         if (sim_ofile) {                                /* already got one? */
8348             fclose (sim_ofile);                         /* one per customer */
8349             *st = SCPE_ARG;
8350             return NULL;
8351             }
8352         cptr = get_glyph (cptr + 1, gbuf, 0);
8353         sim_ofile = sim_fopen (gbuf, "a");              /* open for append */
8354         if (sim_ofile == NULL) {                        /* open failed? */
8355             *st = SCPE_OPENERR;
8356             return NULL;
8357             }
8358         sim_opt_out |= CMD_OPT_OF;                      /* got output file */
8359         continue;
8360         }
8361     cptr = get_glyph (cptr, gbuf, 0);
8362     if ((t = get_switches (gbuf)) != 0) {               /* try for switches */
8363         if (t < 0) {                                    /* err if bad switch */
8364             *st = SCPE_INVSW;
8365             return NULL;
8366             }
8367         sim_switches = sim_switches | t;                /* or in new switches */
8368         }
8369     else if ((opt & CMD_OPT_SCH) &&                     /* if allowed, */
8370         get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) { /* try for search */
8371         sim_schrptr = &sim_stabr;                       /* set search */
8372         sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);/* populate memory version of the same expression */
8373         sim_opt_out |= CMD_OPT_SCH;                     /* got search */
8374         }
8375     else if ((opt & CMD_OPT_DFT) &&                     /* default allowed? */
8376         ((sim_opt_out & CMD_OPT_DFT) == 0) &&           /* none yet? */
8377         (tdptr = find_unit (gbuf, &tuptr)) &&           /* try for default */
8378         (tuptr != NULL)) {
8379         sim_dfdev = tdptr;                              /* set as default */
8380         sim_dfunit = tuptr;
8381         sim_opt_out |= CMD_OPT_DFT;                     /* got default */
8382         }
8383     else return svptr;                                  /* not rec, break out */
8384     }
8385 return cptr;
8386 }
8387 
8388 /* put_switches         put switches into string
8389 
8390    Inputs:
8391         buf     =       pointer to string buffer
8392         bufsize =       size of string buffer
8393         sw      =       switch bit mask
8394    Outputs:
8395         buf     =       buffer with switches converted to text
8396 */
8397 
8398 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
8399 {
8400 char *optr = buf;
8401 int32 bit;
8402 
8403 (void)memset (buf, 0, bufsize);
8404 if ((sw == 0) || (bufsize < 3))
8405     return buf;
8406 --bufsize;                          /* leave room for terminating NUL */
8407 *optr++ = '-';
8408 for (bit=0; bit <= ('Z'-'A'); bit++)
8409     if (sw & (1 << bit))
8410         if ((size_t)(optr - buf) < bufsize)
8411             *optr++ = 'A' + bit;
8412 return buf;
8413 }
8414 
8415 /* Get register search specification
8416 
8417    Inputs:
8418         cptr    =       pointer to input string
8419         radix   =       radix for numbers
8420         schptr =        pointer to search table
8421    Outputs:
8422         return =        NULL if error
8423                         schptr if valid search specification
8424 */
8425 
8426 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8427 {
8428 int32 c;
8429 size_t logop, cmpop;
8430 t_value logval, cmpval;
8431 const char *sptr;
8432 CONST char *tptr;
8433 const char logstr[] = "|&^", cmpstr[] = "=!><";
8434 /* Using a const instead of a #define. */
8435 const size_t invalid_op = (size_t) -1;
8436 
8437 logval = cmpval = 0;
8438 if (*cptr == 0)                                         /* check for clause */
8439     return NULL;
8440 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8441 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8442     if ((sptr = strchr (logstr, c))) {                  /* check for mask */
8443         logop = sptr - logstr;
8444         logval = strtotv (cptr, &tptr, radix);
8445         if (cptr == tptr)
8446             return NULL;
8447         cptr = tptr;
8448         }
8449     else if ((sptr = strchr (cmpstr, c))) {             /* check for boolop */
8450         cmpop = sptr - cmpstr;
8451         if (*cptr == '=') {
8452             cmpop = cmpop + strlen (cmpstr);
8453             cptr++;
8454             }
8455         cmpval = strtotv (cptr, &tptr, radix);
8456         if (cptr == tptr)
8457             return NULL;
8458         cptr = tptr;
8459         }
8460     else return NULL;
8461     }                                                   /* end for */
8462 if (schptr->count != 1) {
8463     FREE (schptr->mask);
8464     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8465     FREE (schptr->comp);
8466     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8467     }
8468 if (logop != invalid_op) {
8469     schptr->logic = logop;
8470     schptr->mask[0] = logval;
8471     }
8472 if (cmpop != invalid_op) {
8473     schptr->boolop = cmpop;
8474     schptr->comp[0] = cmpval;
8475     }
8476 schptr->count = 1;
8477 return schptr;
8478 }
8479 
8480 /* Get memory search specification
8481 
8482    Inputs:
8483         cptr    =       pointer to input string
8484         radix   =       radix for numbers
8485         schptr =        pointer to search table
8486    Outputs:
8487         return =        NULL if error
8488                         schptr if valid search specification
8489 */
8490 
8491 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8492 {
8493 int32 c;
8494 size_t logop, cmpop;
8495 t_value *logval, *cmpval;
8496 t_stat reason = SCPE_OK;
8497 CONST char *ocptr = cptr;
8498 const char *sptr;
8499 char gbuf[CBUFSIZE];
8500 const char logstr[] = "|&^", cmpstr[] = "=!><";
8501 /* Using a const instead of a #define. */
8502 const size_t invalid_op = (size_t) -1;
8503 
8504 if (*cptr == 0)                                         /* check for clause */
8505     return NULL;
8506 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8507 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8508 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8509 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8510     if (NULL != (sptr = strchr (logstr, c))) {          /* check for mask */
8511         logop = sptr - logstr;
8512         cptr = get_glyph (cptr, gbuf, 0);
8513         reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8514         if (reason > 0) {
8515             FREE (logval);
8516             FREE (cmpval);
8517             return get_rsearch (ocptr, radix, schptr);
8518             }
8519         }
8520     else if (NULL != (sptr = strchr (cmpstr, c))) {     /* check for boolop */
8521         cmpop = sptr - cmpstr;
8522         if (*cptr == '=') {
8523             cmpop = cmpop + strlen (cmpstr);
8524             cptr++;
8525             }
8526         cptr = get_glyph (cptr, gbuf, 0);
8527         reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8528         if (reason > 0) {
8529             FREE (logval);
8530             FREE (cmpval);
8531             return get_rsearch (ocptr, radix, schptr);
8532             }
8533         }
8534     else {
8535         FREE (logval);
8536         FREE (cmpval);
8537         return NULL;
8538         }
8539     }                                                   /* end for */
8540 if (schptr->count != (uint32)(1 - reason)) {
8541     schptr->count = 1 - reason;
8542     FREE (schptr->mask);
8543     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8544     FREE (schptr->comp);
8545     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8546     }
8547 if (logop != invalid_op) {
8548     schptr->logic = logop;
8549     FREE (schptr->mask);
8550     schptr->mask = logval;
8551     }
8552 else {
8553     FREE (logval);
8554     }
8555 if (cmpop != invalid_op) {
8556     schptr->boolop = cmpop;
8557     FREE (schptr->comp);
8558     schptr->comp = cmpval;
8559     }
8560 else {
8561     FREE (cmpval);
8562     }
8563 return schptr;
8564 }
8565 
8566 /* Test value against search specification
8567 
8568    Inputs:
8569         val    =        value list to test
8570         schptr =        pointer to search table
8571    Outputs:
8572         return =        1 if value passes search criteria, 0 if not
8573 */
8574 
8575 int32 test_search (t_value *values, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8576 {
8577 t_value *val = NULL;
8578 int32 i, updown;
8579 int32 ret = 0;
8580 
8581 if (schptr == NULL)
8582     return ret;
8583 
8584 val = (t_value *)malloc (schptr->count * sizeof (*values));
8585 if (!val)
8586   {
8587     (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8588                   __func__, __FILE__, __LINE__);
8589 #if defined(USE_BACKTRACE)
8590 # if defined(SIGUSR2)
8591     (void)raise(SIGUSR2);
8592     /*NOTREACHED*/ /* unreachable */
8593 # endif /* if defined(SIGUSR2) */
8594 #endif /* if defined(USE_BACKTRACE) */
8595     abort();
8596   }
8597 for (i=0; i<(int32)schptr->count; i++) {
8598     val[i] = values[i];
8599     switch (schptr->logic) {                            /* case on logical */
8600 
8601         case SCH_OR:
8602             val[i] = val[i] | schptr->mask[i];
8603             break;
8604 
8605         case SCH_AND:
8606             val[i] = val[i] & schptr->mask[i];
8607             break;
8608 
8609         case SCH_XOR:
8610             val[i] = val[i] ^ schptr->mask[i];
8611             break;
8612             }
8613     }
8614 
8615 ret = 1;
8616 if (1) {    /* Little Endian VM */
8617     updown = -1;
8618     i=schptr->count-1;
8619     }
8620 else {      /* Big Endian VM */
8621     updown = 1;
8622     i=0;
8623     }
8624 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8625     switch (schptr->boolop) {                           /* case on comparison */
8626 
8627         case SCH_E: case SCH_EE:
8628             if (val[i] != schptr->comp[i])
8629                 ret = 0;
8630             break;
8631 
8632         case SCH_N: case SCH_NE:
8633             if (val[i] == schptr->comp[i])
8634                 ret = 0;
8635             break;
8636 
8637         case SCH_G:
8638             if (val[i] <= schptr->comp[i])
8639                 ret = 0;
8640             break;
8641 
8642         case SCH_GE:
8643             if (val[i] < schptr->comp[i])
8644                 ret = 0;
8645             break;
8646 
8647         case SCH_L:
8648             if (val[i] >= schptr->comp[i])
8649                 ret = 0;
8650             break;
8651 
8652         case SCH_LE:
8653             if (val[i] > schptr->comp[i])
8654                 ret = 0;
8655             break;
8656         }
8657     }
8658 FREE (val);
8659 return ret;
8660 }
8661 
8662 /* Radix independent input/output package
8663 
8664    strtotv - general radix input routine
8665 
8666    Inputs:
8667         inptr   =       string to convert
8668         endptr  =       pointer to first unconverted character
8669         radix   =       radix for input
8670    Outputs:
8671         value   =       converted value
8672 
8673    On an error, the endptr will equal the inptr.
8674 */
8675 
8676 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
     /* [previous][next][first][last][top][bottom][index][help] */
8677 {
8678 int32 nodigit;
8679 t_value val;
8680 uint32 c, digit;
8681 
8682 *endptr = inptr;                                        /* assume fails */
8683 if ((radix < 2) || (radix > 36))
8684     return 0;
8685 while (sim_isspace (*inptr))                            /* bypass white space */
8686     inptr++;
8687 val = 0;
8688 nodigit = 1;
8689 for (c = *inptr; sim_isalnum(c); c = *++inptr) {        /* loop through char */
8690     if (sim_islower (c))
8691         c = toupper (c);
8692     if (sim_isdigit (c))                                /* digit? */
8693         digit = c - (uint32) '0';
8694     else if (radix <= 10)                               /* stop if not expected */
8695         break;
8696     else digit = c + 10 - (uint32) 'A';                 /* convert letter */
8697     if (digit >= radix)                                 /* valid in radix? */
8698         return 0;
8699     val = (val * radix) + digit;                        /* add to value */
8700     nodigit = 0;
8701     }
8702 if (nodigit)                                            /* no digits? */
8703     return 0;
8704 *endptr = inptr;                                        /* result pointer */
8705 return val;
8706 }
8707 
8708 /* fprint_val - general radix printing routine
8709 
8710    Inputs:
8711         stream  =       stream designator
8712         val     =       value to print
8713         radix   =       radix to print
8714         width   =       width to print
8715         format  =       leading zeroes format
8716    Outputs:
8717         status  =       error status
8718         if stream is NULL, returns length of output that would
8719         have been generated.
8720 */
8721 
8722 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8723                    size_t width, uint32 format)
8724 {
8725 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8726 t_value owtest, wtest;
8727 size_t d;
8728 size_t digit;
8729 size_t ndigits;
8730 size_t commas = 0;
8731 char dbuf[MAX_WIDTH + 1];
8732 
8733 for (d = 0; d < MAX_WIDTH; d++)
8734     dbuf[d] = (format == PV_RZRO)? '0': ' ';
8735 dbuf[MAX_WIDTH] = 0;
8736 d = MAX_WIDTH;
8737 do {
8738     d = d - 1;
8739     digit = val % radix;
8740     val = val / radix;
8741     dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8742     } while ((d > 0) && (val != 0));
8743 
8744 switch (format) {
8745     case PV_LEFT:
8746         break;
8747     case PV_RZRO:
8748         wtest = owtest = radix;
8749         ndigits = 1;
8750         while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8751             owtest = wtest;
8752             wtest = wtest * radix;
8753             ndigits = ndigits + 1;
8754             }
8755         if ((MAX_WIDTH - (ndigits + commas)) < d)
8756             d = MAX_WIDTH - (ndigits + commas);
8757         break;
8758     }
8759 if (NULL == buffer)                   /* Potentially unsafe wraparound if */
8760     return ((t_stat) strlen(dbuf+d)); /*  sizeof(t_stat) < sizeof(size_t) */
8761 *buffer = '\0';
8762 if (width < strlen(dbuf+d))
8763     return SCPE_IOERR;
8764 strcpy(buffer, dbuf+d);
8765 return SCPE_OK;
8766 }
8767 
8768 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8769     uint32 width, uint32 format)
8770 {
8771 char dbuf[MAX_WIDTH + 1];
8772 
8773 if (!stream)
8774     return sprint_val (NULL, val, radix, width, format);
8775 if (width > MAX_WIDTH)
8776     width = MAX_WIDTH;
8777 sprint_val (dbuf, val, radix, width, format);
8778 if (Fprintf (stream, "%s", dbuf) < 0)
8779     return SCPE_IOERR;
8780 return SCPE_OK;
8781 }
8782 
8783 const char *sim_fmt_secs (double seconds)
     /* [previous][next][first][last][top][bottom][index][help] */
8784 {
8785 static char buf[60];
8786 char frac[16] = "";
8787 const char *sign = "";
8788 double val = seconds;
8789 double days, hours, mins, secs, msecs, usecs;
8790 
8791 if (val == 0.0)
8792     return "";
8793 if (val < 0.0) {
8794     sign = "-";
8795     val = -val;
8796     }
8797 days = floor (val / (24.0*60.0*60.0));
8798 val -= (days * 24.0*60.0*60.0);
8799 hours = floor (val / (60.0*60.0));
8800 val -= (hours * 60.0 * 60.0);
8801 mins = floor (val / 60.0);
8802 val -= (mins * 60.0);
8803 secs = floor (val);
8804 val -= secs;
8805 val *= 1000.0;
8806 msecs = floor (val);
8807 val -= msecs;
8808 val *= 1000.0;
8809 usecs = floor (val+0.5);
8810 if (usecs == 1000.0) {
8811     usecs = 0.0;
8812     msecs += 1;
8813     }
8814 if ((msecs > 0.0) || (usecs > 0.0)) {
8815     (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8816     while (frac[strlen (frac) - 1] == '0') //-V557
8817         frac[strlen (frac) - 1] = '\0'; //-V557
8818     if (strlen (frac) == 1)
8819         frac[0] = '\0';
8820     }
8821 if (days > 0)
8822     (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8823                    sign, days, (days != 1) ? "s" : "", hours, mins,
8824                    secs, frac, (days == 1) ? "s" : "");
8825 else
8826     if (hours > 0)
8827         (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8828                        sign, hours, mins, secs, frac);
8829     else
8830         if (mins > 0)
8831             (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8832                            sign, mins, secs, frac);
8833         else
8834             if (secs > 0)
8835                 (void)sprintf (buf, "%s%.0f%s second",
8836                                sign, secs, frac);
8837             else
8838                 if (msecs > 0) {
8839                     if (usecs > 0)
8840                         (void)sprintf (buf, "%s%.0f.%s msec",
8841                                        sign, msecs, frac+4);
8842                     else
8843                         (void)sprintf (buf, "%s%.0f msec",
8844                                        sign, msecs);
8845                     }
8846                 else
8847                     (void)sprintf (buf, "%s%.0f usec",
8848                                    sign, usecs);
8849 if (0 != strncmp ("1 ", buf, 2))
8850     strcpy (&buf[strlen (buf)], "s");
8851 return buf;
8852 }
8853 
8854 /*
8855  * Event queue package
8856  *
8857  *      sim_activate            add entry to event queue
8858  *      sim_activate_abs        add entry to event queue even if event already scheduled
8859  *      sim_activate_after      add entry to event queue after a specified amount of wall time
8860  *      sim_cancel              remove entry from event queue
8861  *      sim_process_event       process entries on event queue
8862  *      sim_is_active           see if entry is on event queue
8863  *      sim_activate_time       return time until activation
8864  *      sim_atime               return absolute time for an entry
8865  *      sim_gtime               return global time
8866  *      sim_qcount              return event queue entry count
8867  */
8868 
8869 t_stat sim_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8870 {
8871 UNIT *uptr;
8872 t_stat reason;
8873 #if defined(TESTING)
8874 cpu_state_t * cpup = _cpup;
8875 #endif
8876 
8877 if (stop_cpu)                                           /* stop CPU? */
8878   {
8879 #if defined(WIN_STDIO)
8880     (void)fflush(stdout);
8881     (void)fflush(stderr);
8882 #endif /* if defined(WIN_STDIO) */
8883     return SCPE_STOP;
8884   }
8885 UPDATE_SIM_TIME;                                        /* update sim time */
8886 
8887 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8888     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8889     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8890                "Queue Empty New Interval = %d\r\n",
8891                sim_interval);
8892     return SCPE_OK;
8893     }
8894 sim_processing_event = TRUE;
8895 do {
8896     uptr = sim_clock_queue;                             /* get first */
8897     sim_clock_queue = uptr->next;                       /* remove first */
8898     uptr->next = NULL;                                  /* hygiene */
8899     sim_interval -= uptr->time;
8900     uptr->time = 0;
8901     if (sim_clock_queue != QUEUE_LIST_END)
8902         sim_interval = sim_clock_queue->time;
8903     else
8904         sim_interval = noqueue_time = NOQUEUE_WAIT;
8905     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8906                "Processing Event for %s\r\n", sim_uname (uptr));
8907     if (uptr->action != NULL)
8908         reason = uptr->action (uptr);
8909     else
8910         reason = SCPE_OK;
8911     } while ((reason == SCPE_OK) &&
8912              (sim_interval <= 0) &&
8913              (sim_clock_queue != QUEUE_LIST_END) &&
8914              (!stop_cpu));
8915 
8916 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8917     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8918     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8919                "Processing Queue Complete New Interval = %d\r\n",
8920                sim_interval);
8921     }
8922 else
8923     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8924                "Processing Queue Complete New Interval = %d(%s)\r\n",
8925                sim_interval, sim_uname(sim_clock_queue));
8926 
8927 if ((reason == SCPE_OK) && stop_cpu)
8928   {
8929 #if defined(WIN_STDIO)
8930     (void)fflush(stdout);
8931     (void)fflush(stderr);
8932 #endif /* if defined(WIN_STDIO) */
8933     reason = SCPE_STOP;
8934   }
8935 sim_processing_event = FALSE;
8936 return reason;
8937 }
8938 
8939 /* sim_activate - activate (queue) event
8940 
8941    Inputs:
8942         uptr    =       pointer to unit
8943         event_time =    relative timeout
8944    Outputs:
8945         reason  =       result (SCPE_OK if ok)
8946 */
8947 
8948 t_stat sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8949 {
8950 if (uptr->dynflags & UNIT_TMR_UNIT)
8951     return sim_timer_activate (uptr, event_time);
8952 return _sim_activate (uptr, event_time);
8953 }
8954 
8955 t_stat _sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8956 {
8957 UNIT *cptr, *prvptr;
8958 int32 accum;
8959 #if defined(TESTING)
8960 cpu_state_t * cpup = _cpup;
8961 #endif
8962 
8963 if (sim_is_active (uptr))                               /* already active? */
8964     return SCPE_OK;
8965 UPDATE_SIM_TIME;                                        /* update sim time */
8966 
8967 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
8968 
8969 prvptr = NULL;
8970 accum = 0;
8971 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8972     if (event_time < (accum + cptr->time))
8973         break;
8974     accum = accum + cptr->time;
8975     prvptr = cptr;
8976     }
8977 if (prvptr == NULL) {                                   /* insert at head */
8978     cptr = uptr->next = sim_clock_queue;
8979     sim_clock_queue = uptr;
8980     }
8981 else {
8982     cptr = uptr->next = prvptr->next;                   /* insert at prvptr */
8983     prvptr->next = uptr;
8984     }
8985 uptr->time = event_time - accum;
8986 if (cptr != QUEUE_LIST_END)
8987     cptr->time = cptr->time - uptr->time;
8988 sim_interval = sim_clock_queue->time;
8989 return SCPE_OK;
8990 }
8991 
8992 /* sim_activate_abs - activate (queue) event even if event already scheduled
8993 
8994    Inputs:
8995         uptr    =       pointer to unit
8996         event_time =    relative timeout
8997    Outputs:
8998         reason  =       result (SCPE_OK if ok)
8999 */
9000 
9001 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
9002 {
9003 sim_cancel (uptr);
9004 return _sim_activate (uptr, event_time);
9005 }
9006 
9007 /* sim_activate_after - activate (queue) event
9008 
9009    Inputs:
9010         uptr    =       pointer to unit
9011         usec_delay =    relative timeout (in microseconds)
9012    Outputs:
9013         reason  =       result (SCPE_OK if ok)
9014 */
9015 
9016 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
9017 {
9018 return _sim_activate_after (uptr, usec_delay);
9019 }
9020 
9021 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
9022 {
9023 if (sim_is_active (uptr))                               /* already active? */
9024     return SCPE_OK;
9025 return sim_timer_activate_after (uptr, usec_delay);
9026 }
9027 
9028 /* sim_cancel - cancel (dequeue) event
9029 
9030    Inputs:
9031         uptr    =       pointer to unit
9032    Outputs:
9033         reason  =       result (SCPE_OK if ok)
9034 
9035 */
9036 
9037 t_stat sim_cancel (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9038 {
9039 UNIT *cptr, *nptr;
9040 #if defined(TESTING)
9041 cpu_state_t * cpup = _cpup;
9042 #endif
9043 
9044 if (sim_clock_queue == QUEUE_LIST_END)
9045     return SCPE_OK;
9046 if (!sim_is_active (uptr))
9047     return SCPE_OK;
9048 UPDATE_SIM_TIME;                                        /* update sim time */
9049 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9050 nptr = QUEUE_LIST_END;
9051 
9052 if (sim_clock_queue == uptr) {
9053     nptr = sim_clock_queue = uptr->next;
9054     uptr->next = NULL;                                  /* hygiene */
9055     }
9056 else {
9057     for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9058         if (cptr->next == uptr) {
9059             nptr = cptr->next = uptr->next;
9060             uptr->next = NULL;                          /* hygiene */
9061             break;                                      /* end queue scan */
9062             }
9063         }
9064     }
9065 if (nptr != QUEUE_LIST_END)
9066     nptr->time += (uptr->next) ? 0 : uptr->time;
9067 if (!uptr->next)
9068     uptr->time = 0;
9069 if (sim_clock_queue != QUEUE_LIST_END)
9070     sim_interval = sim_clock_queue->time;
9071 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9072 if (uptr->next) {
9073     sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9074     if (sim_deb)
9075         fclose(sim_deb);
9076     (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9077                    __func__, __FILE__, __LINE__);
9078     abort ();
9079     }
9080 return SCPE_OK;
9081 }
9082 
9083 /* sim_is_active - test for entry in queue
9084 
9085    Inputs:
9086         uptr    =       pointer to unit
9087    Outputs:
9088         result =        TRUE if unit is busy, FALSE inactive
9089 */
9090 
9091 t_bool sim_is_active (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9092 {
9093 if (uptr->next == NULL)
9094   return FALSE;
9095 else
9096 return TRUE;
9097 }
9098 
9099 /* sim_activate_time - return activation time
9100 
9101    Inputs:
9102         uptr    =       pointer to unit
9103    Outputs:
9104         result =        absolute activation time + 1, 0 if inactive
9105 */
9106 
9107 int32 sim_activate_time (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9108 {
9109 UNIT *cptr;
9110 int32 accum = 0;
9111 
9112 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9113     if (cptr == sim_clock_queue) {
9114         if (sim_interval > 0)
9115             accum = accum + sim_interval;
9116         }
9117     else
9118         accum = accum + cptr->time;
9119     if (cptr == uptr)
9120         return accum + 1;
9121     }
9122 return 0;
9123 }
9124 
9125 /* sim_gtime - return global time
9126 
9127    Inputs: none
9128    Outputs:
9129         time    =       global time
9130 */
9131 
9132 double sim_gtime (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9133 {
9134 return sim_time;
9135 }
9136 
9137 /* sim_qcount - return queue entry count
9138 
9139    Inputs: none
9140    Outputs:
9141         count   =       number of entries on the queue
9142 */
9143 
9144 int32 sim_qcount (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9145 {
9146 int32 cnt;
9147 UNIT *uptr;
9148 
9149 cnt = 0;
9150 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9151     cnt++;
9152 return cnt;
9153 }
9154 
9155 /* Breakpoint package.  This module replaces the VM-implemented one
9156    instruction breakpoint capability.
9157 
9158    Breakpoints are stored in table sim_brk_tab, which is ordered by address for
9159    efficient binary searching.  A breakpoint consists of a six entry structure:
9160 
9161         addr                    address of the breakpoint
9162         type                    types of breakpoints set on the address
9163                                 a bit mask representing letters A-Z
9164         cnt                     number of iterations before breakp is taken
9165         action                  pointer command string to be executed
9166                                 when break is taken
9167         next                    list of other breakpoints with the same addr specifier
9168         time_fired              array of when this breakpoint was fired for each class
9169 
9170    sim_brk_summ is a summary of the types of breakpoints that are currently set (it
9171    is the bitwise OR of all the type fields).  A simulator need only check for
9172    a breakpoint of type X if bit SWMASK('X') is set in sim_brk_summ.
9173 
9174    The package contains the following public routines:
9175 
9176         sim_brk_init            initialize
9177         sim_brk_set             set breakpoint
9178         sim_brk_clr             clear breakpoint
9179         sim_brk_clrall          clear all breakpoints
9180         sim_brk_show            show breakpoint
9181         sim_brk_showall         show all breakpoints
9182         sim_brk_test            test for breakpoint
9183         sim_brk_npc             PC has been changed
9184         sim_brk_getact          get next action
9185         sim_brk_clract          clear pending actions
9186 
9187    Initialize breakpoint system.
9188 */
9189 
9190 t_stat sim_brk_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9191 {
9192 int32 i;
9193 
9194 for (i=0; i<sim_brk_lnt; i++) {
9195     BRKTAB *bp;
9196     if (sim_brk_tab)
9197       {
9198         bp = sim_brk_tab[i];
9199 
9200         while (bp)
9201           {
9202             BRKTAB *bpt = bp->next;
9203 
9204             FREE (bp->act);
9205             FREE (bp);
9206             bp = bpt;
9207           }
9208       }
9209 }
9210 if (sim_brk_tab != NULL)
9211     (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9212 sim_brk_lnt = SIM_BRK_INILNT;
9213 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9214 if (sim_brk_tab == NULL)
9215     return SCPE_MEM;
9216 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9217 sim_brk_ent = sim_brk_ins = 0;
9218 sim_brk_clract ();
9219 sim_brk_npc (0);
9220 return SCPE_OK;
9221 }
9222 
9223 /* Search for a breakpoint in the sorted breakpoint table */
9224 
9225 BRKTAB *sim_brk_fnd (t_addr loc)
     /* [previous][next][first][last][top][bottom][index][help] */
9226 {
9227 int32 lo, hi, p;
9228 BRKTAB *bp;
9229 
9230 if (sim_brk_ent == 0) {                                 /* table empty? */
9231     sim_brk_ins = 0;                                    /* insrt at head */
9232     return NULL;                                        /* sch fails */
9233     }
9234 lo = 0;                                                 /* initial bounds */
9235 hi = sim_brk_ent - 1;
9236 do {
9237     p = (lo + hi) >> 1;                                 /* probe */
9238     bp = sim_brk_tab[p];                                /* table addr */
9239     if (loc == bp->addr) {                              /* match? */
9240         sim_brk_ins = p;
9241         return bp;
9242         }
9243     else if (loc < bp->addr)                            /* go down? p is upper */
9244         hi = p - 1;
9245     else lo = p + 1;                                    /* go up? p is lower */
9246     } while (lo <= hi);
9247 if (loc < bp->addr)                                     /* insrt before or */
9248     sim_brk_ins = p;
9249 else sim_brk_ins = p + 1;                               /* after last sch */
9250 return NULL;
9251 }
9252 
9253 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
     /* [previous][next][first][last][top][bottom][index][help] */
9254 {
9255 BRKTAB *bp = sim_brk_fnd (loc);
9256 
9257 while (bp) {
9258     if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9259                   (bp->typ == btyp))
9260         return bp;
9261     bp = bp->next;
9262     }
9263 return bp;
9264 }
9265 
9266 /* Insert a breakpoint */
9267 
9268 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9269 {
9270 int32 i, t;
9271 BRKTAB *bp, **newp;
9272 
9273 if (sim_brk_ins < 0)
9274     return NULL;
9275 if (sim_brk_ent >= sim_brk_lnt) {                       /* out of space? */
9276     t = sim_brk_lnt + SIM_BRK_INILNT;                   /* new size */
9277     newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));    /* new table */
9278     if (newp == NULL)                                   /* can't extend */
9279         return NULL;
9280     memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));/* copy table */
9281     (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));/* zero new entries */
9282     FREE (sim_brk_tab);                                 /* free old table */
9283     sim_brk_tab = newp;                                 /* new base, lnt */
9284     sim_brk_lnt = t;
9285     }
9286 if ((sim_brk_ins == sim_brk_ent) ||
9287     ((sim_brk_ins != sim_brk_ent) && //-V728
9288      (sim_brk_tab[sim_brk_ins]->addr != loc))) {        /* need to open a hole? */
9289     for (i = sim_brk_ent; i > sim_brk_ins; --i)
9290         sim_brk_tab[i] = sim_brk_tab[i - 1];
9291     sim_brk_tab[sim_brk_ins] = NULL;
9292     }
9293 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9294 if (!bp)
9295   {
9296     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9297                    __func__, __FILE__, __LINE__);
9298 #if defined(USE_BACKTRACE)
9299 # if defined(SIGUSR2)
9300     (void)raise(SIGUSR2);
9301     /*NOTREACHED*/ /* unreachable */
9302 # endif /* if defined(SIGUSR2) */
9303 #endif /* if defined(USE_BACKTRACE) */
9304     abort();
9305   }
9306 bp->next = sim_brk_tab[sim_brk_ins];
9307 sim_brk_tab[sim_brk_ins] = bp;
9308 if (bp->next == NULL)
9309     sim_brk_ent += 1;
9310 bp->addr = loc;
9311 bp->typ = btyp;
9312 bp->cnt = 0;
9313 bp->act = NULL;
9314 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9315     bp->time_fired[i] = -1.0;
9316 return bp;
9317 }
9318 
9319 /* Set a breakpoint of type sw */
9320 
9321 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
     /* [previous][next][first][last][top][bottom][index][help] */
9322 {
9323 BRKTAB *bp;
9324 
9325 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9326     sw |= sim_brk_dflt;
9327 if (~sim_brk_types & sw) {
9328     char gbuf[CBUFSIZE];
9329 
9330     return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9331     }
9332 if ((sw & BRK_TYP_DYN_ALL) && act)                      /* can't specify an action with a dynamic breakpoint */
9333     return SCPE_ARG;
9334 bp = sim_brk_fnd (loc);                                 /* loc present? */
9335 if (!bp)                                                /* no, allocate */
9336     bp = sim_brk_new (loc, sw);
9337 else {
9338     while (bp && (bp->typ != (uint32)sw))
9339         bp = bp->next;
9340     if (!bp)
9341         bp = sim_brk_new (loc, sw);
9342     }
9343 if (!bp)                                                /* still no? mem err */
9344     return SCPE_MEM;
9345 bp->cnt = ncnt;                                         /* set count */
9346 if ((!(sw & BRK_TYP_DYN_ALL)) &&                        /* Not Dynamic and */
9347     (bp->act != NULL) && (act != NULL)) {               /* replace old action? */
9348     FREE (bp->act);                                     /* deallocate */
9349     bp->act = NULL;                                     /* now no action */
9350     }
9351 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9352     char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char)); /* alloc buf */
9353     if (newp == NULL)                                   /* mem err? */
9354         return SCPE_MEM;
9355     strncpy (newp, act, CBUFSIZE);                      /* copy action */
9356     bp->act = newp;                                     /* set pointer */
9357     }
9358 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9359 return SCPE_OK;
9360 }
9361 
9362 /* Clear a breakpoint */
9363 
9364 t_stat sim_brk_clr (t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9365 {
9366 BRKTAB *bpl = NULL;
9367 BRKTAB *bp = sim_brk_fnd (loc);
9368 int32 i;
9369 
9370 if (!bp)                                                /* not there? ok */
9371     return SCPE_OK;
9372 if (sw == 0)
9373     sw = SIM_BRK_ALLTYP;
9374 
9375 #if !defined(__clang_analyzer__)
9376 while (bp) {
9377     if (bp->typ == (bp->typ & sw)) {
9378         FREE (bp->act);                                 /* deallocate action */
9379         if (bp == sim_brk_tab[sim_brk_ins])
9380             bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9381         else
9382           {
9383             if (bpl)
9384               bpl->next = bp->next;
9385           }
9386         FREE (bp);
9387         bp = bpl;
9388         }
9389     else {
9390         bpl = bp;
9391         bp = bp->next;
9392         }
9393     }
9394 #endif /* if !defined(__clang_analyzer__) */
9395 if (sim_brk_tab[sim_brk_ins] == NULL) {                 /* erased entry */
9396     sim_brk_ent = sim_brk_ent - 1;                      /* decrement count */
9397     for (i = sim_brk_ins; i < sim_brk_ent; i++)         /* shuffle remaining entries */
9398         sim_brk_tab[i] = sim_brk_tab[i+1];
9399     }
9400 sim_brk_summ = 0;                                       /* recalc summary */
9401 for (i = 0; i < sim_brk_ent; i++) {
9402     bp = sim_brk_tab[i];
9403     while (bp) {
9404         sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9405         bp = bp->next;
9406         }
9407     }
9408 return SCPE_OK;
9409 }
9410 
9411 /* Clear all breakpoints */
9412 
9413 t_stat sim_brk_clrall (int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9414 {
9415 int32 i;
9416 
9417 if (sw == 0)
9418     sw = SIM_BRK_ALLTYP;
9419 for (i = 0; i < sim_brk_ent;) {
9420     t_addr loc = sim_brk_tab[i]->addr;
9421     sim_brk_clr (loc, sw);
9422     if ((i < sim_brk_ent) &&
9423         (loc == sim_brk_tab[i]->addr))
9424         ++i;
9425     }
9426 return SCPE_OK;
9427 }
9428 
9429 /* Show a breakpoint */
9430 
9431 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9432 {
9433 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9434 DEVICE *dptr;
9435 uint32 i, any;
9436 
9437 if ((sw == 0) || (sw == SWMASK ('C'))) {
9438     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9439 if (!bp || (!(bp->typ & sw))) {
9440     return SCPE_OK; }
9441 dptr = sim_dflt_dev;
9442 if (dptr == NULL) {
9443     return SCPE_OK; }
9444 if (sw & SWMASK ('C')) {
9445     if (st != NULL) {
9446         (void)fprintf (st, "SET BREAK "); }
9447 } else {
9448     if (sim_vm_fprint_addr) {
9449         sim_vm_fprint_addr
9450             (st, dptr, loc);
9451     } else {
9452         fprint_val
9453             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9454     if (st != NULL) {
9455         (void)fprintf (st, ":\t"); }
9456     }
9457 for (i = any = 0; i < 26; i++) {
9458     if ((bp->typ >> i) & 1) {
9459         if ((sw & SWMASK ('C')) == 0) {
9460             if (any) {
9461                 if (st != NULL) {
9462                     (void)fprintf (st, ", "); } }
9463             if (st != NULL) {
9464                 fputc (i + 'A', st); }
9465             }
9466         } else {
9467             if (st != NULL) {
9468                 (void)fprintf (st, "-%c", i + 'A'); }
9469         any = 1;
9470         }
9471     }
9472 if (sw & SWMASK ('C')) {
9473     if (st != NULL) {
9474         (void)fprintf (st, " "); }
9475     if (sim_vm_fprint_addr) {
9476         if (st != NULL) {
9477             sim_vm_fprint_addr (st, dptr, loc); }
9478     } else {
9479         fprint_val
9480             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9481     }
9482 if (bp->cnt > 0) {
9483     if (st != NULL) {
9484         (void)fprintf (st, "[%d]", bp->cnt); } }
9485 if (bp->act != NULL) {
9486     if (st != NULL) {
9487         (void)fprintf (st, "; %s", bp->act); } }
9488 (void)fprintf (st, "\r\n");
9489 return SCPE_OK;
9490 }
9491 
9492 /* Show all breakpoints */
9493 
9494 t_stat sim_brk_showall (FILE *st, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9495 {
9496 int32 bit, mask, types;
9497 BRKTAB **bpt;
9498 
9499 if ((sw == 0) || (sw == SWMASK ('C')))
9500     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9501 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9502     if (sim_brk_types & (1 << bit))
9503         ++types;
9504 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9505     (void)fprintf (st, "Supported Breakpoint Types:"); //-V522
9506     for (bit=0; bit <= ('Z'-'A'); bit++)
9507         if (sim_brk_types & (1 << bit))
9508             (void)fprintf (st, " -%c", 'A' + bit);
9509     (void)fprintf (st, "\r\n");
9510     }
9511 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9512     mask = (sw & sim_brk_types);
9513     (void)fprintf (st, "Displaying Breakpoint Types:");
9514     for (bit=0; bit <= ('Z'-'A'); bit++)
9515         if (mask & (1 << bit))
9516             (void)fprintf (st, " -%c", 'A' + bit);
9517     (void)fprintf (st, "\r\n");
9518     }
9519 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9520     BRKTAB *prev = NULL;
9521     BRKTAB *cur = *bpt;
9522     BRKTAB *next;
9523     /* First reverse the list */
9524     while (cur) {
9525         next = cur->next;
9526         cur->next = prev;
9527         prev = cur;
9528         cur = next;
9529         }
9530     /* save reversed list in the head pointer so lookups work */
9531     *bpt = prev;
9532     /* Walk the reversed list and print it in the order it was defined in */
9533     cur = prev;
9534     while (cur) {
9535         if (cur->typ & sw)
9536             sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9537         cur = cur->next;
9538         }
9539     /* reversing the list again */
9540     cur = prev;
9541     prev = NULL;
9542     while (cur) {
9543         next = cur->next;
9544         cur->next = prev;
9545         prev = cur;
9546         cur = next;
9547         }
9548     /* restore original list */
9549     *bpt = prev;
9550     }
9551 return SCPE_OK;
9552 }
9553 
9554 /* Test for breakpoint */
9555 
9556 uint32 sim_brk_test (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9557 {
9558 BRKTAB *bp;
9559 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9560 
9561 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9562     btyp |= BRK_TYP_DYN_ALL;
9563 
9564 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {     /* in table, and type match? */
9565     double s_gtime = sim_gtime ();                      /* get time now */
9566 
9567     if (bp->time_fired[spc] == s_gtime)                 /* already taken?  */
9568         return 0;
9569     bp->time_fired[spc] = s_gtime;                      /* remember match time */
9570     if (--bp->cnt > 0)                                  /* count > 0? */
9571         return 0;
9572     bp->cnt = 0;                                        /* reset count */
9573     sim_brk_setact (bp->act);                           /* set up actions */
9574     sim_brk_match_type = btyp & bp->typ;                /* set return value */
9575     if (bp->typ & BRK_TYP_TEMP)
9576         sim_brk_clr (loc, bp->typ);                     /* delete one-shot breakpoint */
9577     sim_brk_match_addr = loc;
9578     return sim_brk_match_type;
9579     }
9580 return 0;
9581 }
9582 
9583 /* Get next pending action, if any */
9584 
9585 CONST char *sim_brk_getact (char *buf, int32 size)
     /* [previous][next][first][last][top][bottom][index][help] */
9586 {
9587 char *ep;
9588 size_t lnt;
9589 
9590 if (sim_brk_act[sim_do_depth] == NULL)                  /* any action? */
9591     return NULL;
9592 while (sim_isspace (*sim_brk_act[sim_do_depth]))        /* skip spaces */
9593     sim_brk_act[sim_do_depth]++;
9594 if (*sim_brk_act[sim_do_depth] == 0) {                  /* now empty? */
9595     return sim_brk_clract ();
9596     }
9597 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {   /* cmd delimiter? */
9598     lnt = ep - sim_brk_act[sim_do_depth];               /* cmd length */
9599     memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);   /* copy with ; */
9600     buf[lnt] = 0;                                       /* erase ; */
9601     sim_brk_act[sim_do_depth] += lnt + 1;               /* adv ptr */
9602     }
9603 else {
9604     strncpy (buf, sim_brk_act[sim_do_depth], size);     /* copy action */
9605     sim_brk_clract ();                                  /* no more */
9606     }
9607 return buf;
9608 }
9609 
9610 /* Clear pending actions */
9611 
9612 char *sim_brk_clract (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9613 {
9614 FREE (sim_brk_act_buf[sim_do_depth]);
9615 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9616 }
9617 
9618 /* Set up pending actions */
9619 
9620 void sim_brk_setact (const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
9621 {
9622 if (action) {
9623     sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9624     if (!sim_brk_act_buf[sim_do_depth])
9625       {
9626         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9627                        __func__, __FILE__, __LINE__);
9628 #if defined(USE_BACKTRACE)
9629 # if defined(SIGUSR2)
9630         (void)raise(SIGUSR2);
9631         /*NOTREACHED*/ /* unreachable */
9632 # endif /* if defined(SIGUSR2) */
9633 #endif /* if defined(USE_BACKTRACE) */
9634         abort();
9635       }
9636     strcpy (sim_brk_act_buf[sim_do_depth], action);
9637     sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9638     }
9639 else
9640     sim_brk_clract ();
9641 }
9642 
9643 /* New PC */
9644 
9645 void sim_brk_npc (uint32 cnt)
     /* [previous][next][first][last][top][bottom][index][help] */
9646 {
9647 uint32 spc;
9648 BRKTAB **bpt, *bp;
9649 
9650 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9651     cnt = SIM_BKPT_N_SPC;
9652 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9653     for (bp = *bpt; bp; bp = bp->next) {
9654         for (spc = 0; spc < cnt; spc++)
9655             bp->time_fired[spc] = -1.0;
9656         }
9657     }
9658 }
9659 
9660 /* Clear breakpoint space */
9661 
9662 void sim_brk_clrspc (uint32 spc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9663 {
9664 BRKTAB **bpt, *bp;
9665 
9666 if (spc < SIM_BKPT_N_SPC) {
9667     for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9668         for (bp = *bpt; bp; bp = bp->next) {
9669             if (bp->typ & btyp)
9670                 bp->time_fired[spc] = -1.0;
9671             }
9672         }
9673     }
9674 }
9675 
9676 const char *sim_brk_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
9677 {
9678 static char msg[256];
9679 char addr[65] = "";
9680 char buf[32];
9681 
9682 msg[0] = '\0';
9683 if (sim_dflt_dev) {
9684   if (sim_vm_sprint_addr)
9685     sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9686   else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9687 }
9688 if (sim_brk_type_desc) {
9689     BRKTYPTAB *brk = sim_brk_type_desc;
9690 
9691     while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9692         if (brk->btyp == sim_brk_match_type) {
9693             (void)sprintf (msg, "%s: %s", brk->desc, addr);
9694             break;
9695             }
9696         brk++;
9697         }
9698     }
9699 if (!msg[0])
9700     (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9701                    put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9702 
9703 return msg;
9704 }
9705 
9706 /* Expect package.  This code provides a mechanism to stop and control simulator
9707    execution based on traffic coming out of simulated ports and as well as a means
9708    to inject data into those ports.  It can conceptually viewed as a string
9709    breakpoint package.
9710 
9711    Expect rules are stored in tables associated with each port which can use this
9712    facility.  An expect rule consists of a five entry structure:
9713 
9714         match                   the expect match string
9715         size                    the number of bytes in the match string
9716         match_pattern           the expect match string in display format
9717         cnt                     number of iterations before match is declared
9718         action                  command string to be executed when match occurs
9719 
9720    All active expect rules are contained in an expect match context structure.
9721 
9722         rules                   the match rules
9723         size                    the count of match rules
9724         buf                     the buffer of output data which has been produced
9725         buf_ins                 the buffer insertion point for the next output data
9726         buf_size                the buffer size
9727 
9728    The package contains the following public routines:
9729 
9730         sim_set_expect          expect command parser and initializer
9731         sim_set_noexpect        noexpect command parser
9732         sim_exp_set             set or add an expect rule
9733         sim_exp_clr             clear or delete an expect rule
9734         sim_exp_clrall          clear all expect rules
9735         sim_exp_show            show an expect rule
9736         sim_exp_showall         show all expect rules
9737         sim_exp_check           test for rule match
9738 */
9739 
9740 /* Set expect */
9741 
9742 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9743 {
9744 char gbuf[CBUFSIZE];
9745 CONST char *tptr;
9746 CONST char *c1ptr;
9747 t_bool after_set = FALSE;
9748 uint32 after;
9749 int32 cnt = 0;
9750 t_stat r;
9751 
9752 if (exp == NULL)
9753     return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9754 after = exp->after;
9755 
9756 if ((cptr == NULL) || (*cptr == 0))
9757     return SCPE_2FARG;
9758 if (*cptr == '[') {
9759     cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9760     if ((cptr == c1ptr) || (*c1ptr != ']'))
9761         return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9762     cptr = c1ptr + 1;
9763     while (sim_isspace(*cptr))
9764         ++cptr;
9765     }
9766 tptr = get_glyph (cptr, gbuf, ',');
9767 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9768     after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9769     if (r != SCPE_OK)
9770         return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9771     after_set = TRUE;
9772     cptr = tptr;
9773     }
9774 if ((*cptr != '"') && (*cptr != '\''))
9775     return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9776 cptr = get_glyph_quoted (cptr, gbuf, 0);
9777 
9778 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9779 }
9780 
9781 /* Clear expect */
9782 
9783 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9784 {
9785 char gbuf[CBUFSIZE];
9786 
9787 if (NULL == cptr || !*cptr)
9788     return sim_exp_clrall (exp);                    /* clear all rules */
9789 if ((*cptr != '"') && (*cptr != '\''))
9790     return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9791 cptr = get_glyph_quoted (cptr, gbuf, 0);
9792 if (*cptr != '\0')
9793     return SCPE_2MARG;                              /* No more arguments */
9794 return sim_exp_clr (exp, gbuf);                     /* clear one rule */
9795 }
9796 
9797 /* Search for an expect rule in an expect context */
9798 
9799 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
     /* [previous][next][first][last][top][bottom][index][help] */
9800 {
9801 size_t i;
9802 
9803 if (NULL == exp->rules)
9804     return NULL;
9805 for (i=start_rule; i<exp->size; i++)
9806     if (!strcmp (exp->rules[i].match_pattern, match))
9807         return &exp->rules[i];
9808 return NULL;
9809 }
9810 
9811 /* Clear (delete) an expect rule */
9812 
9813 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9814 {
9815 size_t i;
9816 
9817 if (NULL == ep)                                         /* not there? ok */
9818     return SCPE_OK;
9819 FREE (ep->match);                                       /* deallocate match string */
9820 FREE (ep->match_pattern);                               /* deallocate the display format match string */
9821 FREE (ep->act);                                         /* deallocate action */
9822 exp->size -= 1;                                         /* decrement count */
9823 #if !defined(__clang_analyzer__)
9824 for (i=ep-exp->rules; i<exp->size; i++)                 /* shuffle up remaining rules */
9825     exp->rules[i] = exp->rules[i+1];
9826 if (exp->size == 0) {                                   /* No rules left? */
9827     FREE (exp->rules);
9828     exp->rules = NULL;
9829     }
9830 #endif /* if !defined(__clang_analyzer__) */
9831 return SCPE_OK;
9832 }
9833 
9834 t_stat sim_exp_clr (EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9835 {
9836 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9837 
9838 while (ep) {
9839     sim_exp_clr_tab (exp, ep);
9840     ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9841     }
9842 return SCPE_OK;
9843 }
9844 
9845 /* Clear all expect rules */
9846 
9847 t_stat sim_exp_clrall (EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
9848 {
9849 int32 i;
9850 
9851 for (i=0; i<exp->size; i++) {
9852     FREE (exp->rules[i].match);                         /* deallocate match string */
9853     FREE (exp->rules[i].match_pattern);                 /* deallocate display format match string */
9854     FREE (exp->rules[i].act);                           /* deallocate action */
9855     }
9856 FREE (exp->rules);
9857 exp->rules = NULL;
9858 exp->size = 0;
9859 FREE (exp->buf);
9860 exp->buf = NULL;
9861 exp->buf_size = 0;
9862 exp->buf_ins = 0;
9863 return SCPE_OK;
9864 }
9865 
9866 /* Set/Add an expect rule */
9867 
9868 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] */
9869 {
9870 EXPTAB *ep;
9871 uint8 *match_buf;
9872 uint32 match_size;
9873 size_t i;
9874 
9875 /* Validate the match string */
9876 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9877 if (!match_buf)
9878     return SCPE_MEM;
9879 if (switches & EXP_TYP_REGEX) {
9880     FREE (match_buf);
9881     return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9882     }
9883 else {
9884     if (switches & EXP_TYP_REGEX_I) {
9885         FREE (match_buf);
9886         return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9887         }
9888     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9889     if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9890         FREE (match_buf);
9891         return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9892         }
9893     }
9894 FREE (match_buf);
9895 for (i=0; i<exp->size; i++) {                           /* Make sure this rule won't be occluded */
9896     if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9897         (exp->rules[i].switches & EXP_TYP_PERSIST))
9898         return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9899     }
9900 if (after && exp->size)
9901     return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9902 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9903 if (!exp->rules)
9904   {
9905     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9906                    __func__, __FILE__, __LINE__);
9907 #if defined(USE_BACKTRACE)
9908 # if defined(SIGUSR2)
9909     (void)raise(SIGUSR2);
9910     /*NOTREACHED*/ /* unreachable */
9911 # endif /* if defined(SIGUSR2) */
9912 #endif /* if defined(USE_BACKTRACE) */
9913     abort();
9914   }
9915 ep = &exp->rules[exp->size];
9916 exp->size += 1;
9917 exp->after = after;                                     /* set halt after value */
9918 (void)memset (ep, 0, sizeof(*ep));
9919 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9920 if (ep->match_pattern)
9921     strcpy (ep->match_pattern, match);
9922 ep->cnt = cnt;                                          /* set proceed count */
9923 ep->switches = switches;                                /* set switches */
9924 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9925 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9926     sim_exp_clr_tab (exp, ep);                          /* clear it */
9927     FREE (match_buf);                                   /* release allocation */
9928     return SCPE_MEM;
9929     }
9930 if (switches & EXP_TYP_REGEX) {
9931     FREE (match_buf);
9932     match_buf = NULL;
9933     }
9934 else {
9935     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9936     sim_decode_quoted_string (match, match_buf, &match_size);
9937     ep->match = match_buf;
9938     ep->size = match_size;
9939     }
9940 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9941 if (!ep->match_pattern)
9942   {
9943     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9944                    __func__, __FILE__, __LINE__);
9945 #if defined(USE_BACKTRACE)
9946 # if defined(SIGUSR2)
9947     (void)raise(SIGUSR2);
9948     /*NOTREACHED*/ /* unreachable */
9949 # endif /* if defined(SIGUSR2) */
9950 #endif /* if defined(USE_BACKTRACE) */
9951     abort();
9952   }
9953 strcpy (ep->match_pattern, match);
9954 if (ep->act) {                                          /* replace old action? */
9955     FREE (ep->act);                                     /* deallocate */
9956     ep->act = NULL;                                     /* now no action */
9957     }
9958 if (act) while (sim_isspace(*act)) ++act;                   /* skip leading spaces in action string */
9959 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9960     char *newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */
9961     if (newp == NULL)                                   /* mem err? */
9962         return SCPE_MEM;
9963     strcpy (newp, act);                                 /* copy action */
9964     ep->act = newp;                                     /* set pointer */
9965     }
9966 /* Make sure that the production buffer is large enough to detect a match for all rules including a NUL termination byte */
9967 for (i=0; i<exp->size; i++) {
9968     size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9969     if (compare_size >= exp->buf_size) {
9970         exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2); /* Extra byte to null terminate regex compares */
9971         exp->buf_size = compare_size + 1;
9972         }
9973     }
9974 return SCPE_OK;
9975 }
9976 
9977 /* Show an expect rule */
9978 
9979 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9980 {
9981 if (!ep)
9982     return SCPE_OK;
9983 (void)fprintf (st, "EXPECT");
9984 if (ep->switches & EXP_TYP_PERSIST)
9985     (void)fprintf (st, " -p");
9986 if (ep->switches & EXP_TYP_CLEARALL)
9987     (void)fprintf (st, " -c");
9988 if (ep->switches & EXP_TYP_REGEX)
9989     (void)fprintf (st, " -r");
9990 if (ep->switches & EXP_TYP_REGEX_I)
9991     (void)fprintf (st, " -i");
9992 (void)fprintf (st, " %s", ep->match_pattern);
9993 if (ep->cnt > 0)
9994     (void)fprintf (st, " [%d]", ep->cnt);
9995 if (ep->act)
9996     (void)fprintf (st, " %s", ep->act);
9997 (void)fprintf (st, "\r\n");
9998 return SCPE_OK;
9999 }
10000 
10001 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
10002 {
10003 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
10004 
10005 if (exp->buf_size) {
10006     char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10007 
10008     (void)fprintf (st, "Match Buffer Size: %lld\r\n",
10009                    (long long)exp->buf_size);
10010     (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
10011                    (long long)exp->buf_ins);
10012     (void)fprintf (st, "Buffer Contents: %s\r\n",
10013                    bstr);
10014     FREE (bstr);
10015     }
10016 if (exp->after)
10017     (void)fprintf (st, "Halt After: %lld instructions\r\n",
10018                    (long long)exp->after);
10019 if (exp->dptr && exp->dbit)
10020     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10021                    sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
10022                    exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
10023 (void)fprintf (st, "Match Rules:\r\n");
10024 if (!*match)
10025     return sim_exp_showall (st, exp);
10026 if (!ep) {
10027     (void)fprintf (st, "No Rules match '%s'\r\n", match);
10028     return SCPE_ARG;
10029     }
10030 do {
10031     sim_exp_show_tab (st, exp, ep);
10032     ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
10033     } while (ep);
10034 return SCPE_OK;
10035 }
10036 
10037 /* Show all expect rules */
10038 
10039 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
10040 {
10041 size_t i;
10042 
10043 for (i=0; i < exp->size; i++)
10044     sim_exp_show_tab (st, exp, &exp->rules[i]);
10045 return SCPE_OK;
10046 }
10047 
10048 /* Test for expect match */
10049 
10050 t_stat sim_exp_check (EXPECT *exp, uint8 data)
     /* [previous][next][first][last][top][bottom][index][help] */
10051 {
10052 size_t i;
10053 EXPTAB *ep = NULL;
10054 char *tstr = NULL;
10055 #if defined(TESTING)
10056 cpu_state_t * cpup = _cpup;
10057 #endif
10058 
10059 if ((!exp) || (!exp->rules))                            /* Anything to check? */
10060     return SCPE_OK;
10061 
10062 exp->buf[exp->buf_ins++] = data;                        /* Save new data */
10063 exp->buf[exp->buf_ins] = '\0';                          /* Nul terminate for RegEx match */
10064 
10065 for (i=0; i < exp->size; i++) {
10066     ep = &exp->rules[i];
10067     if (ep == NULL) //-V547
10068         break;
10069     if (ep->switches & EXP_TYP_REGEX) {
10070         }
10071     else {
10072         if (exp->buf_ins < ep->size) {                          /* Match stradle end of buffer */
10073             /*
10074              * First compare the newly deposited data at the beginning
10075              * of buffer with the end of the match string
10076              */
10077             if (exp->buf_ins > 0) {
10078                 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10079                     char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10080                     char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10081 
10082                     sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10083                                (long long)exp->buf_ins, estr);
10084                     sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10085                     FREE (estr);
10086                     FREE (mstr);
10087                     }
10088                 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10089                     continue;
10090                 }
10091             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10092                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10093                 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10094 
10095                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10096                            (long long)exp->buf_size-(ep->size-exp->buf_ins),
10097                            (long long)ep->size-exp->buf_ins, estr);
10098                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10099                 FREE (estr);
10100                 FREE (mstr);
10101                 }
10102             if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10103                 continue;
10104             break;
10105             }
10106         else {
10107             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10108                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10109                 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10110 
10111                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10112                            (long long)exp->buf_ins-ep->size,
10113                            (long long)ep->size, estr);
10114                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10115                 FREE (estr);
10116                 FREE (mstr);
10117                 }
10118             if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10119                 continue;
10120             break;
10121             }
10122         }
10123     }
10124 if (exp->buf_ins == exp->buf_size) {                    /* At end of match buffer? */
10125         exp->buf_ins = 0;                               /* wrap around to beginning */
10126         sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10127     }
10128 if ((ep != NULL) && (i != exp->size)) {                 /* Found? */
10129     sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10130     if (ep->cnt > 0) {
10131         ep->cnt -= 1;
10132         sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10133                    (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10134         }
10135     else {
10136         uint32 after   = exp->after;
10137         int32 switches = ep->switches;
10138         if (ep->act && *ep->act) {
10139             sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10140             }
10141         else {
10142             sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10143             }
10144         sim_brk_setact (ep->act);                       /* set up actions */
10145         if (ep->switches & EXP_TYP_CLEARALL)            /* Clear-all expect rule? */
10146             sim_exp_clrall (exp);                       /* delete all rules */
10147         else {
10148             if (!(ep->switches & EXP_TYP_PERSIST))      /* One shot expect rule? */
10149                 sim_exp_clr_tab (exp, ep);              /* delete it */
10150             }
10151         sim_activate (&sim_expect_unit,                 /* schedule simulation stop when indicated */
10152                       (switches & EXP_TYP_TIME) ?
10153                             (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10154                              after);
10155         }
10156     /* Matched data is no longer available for future matching */
10157     exp->buf_ins = 0;
10158     }
10159 if (tstr)  //-V547
10160   FREE (tstr);
10161 return SCPE_OK;
10162 }
10163 
10164 /* Queue input data for sending */
10165 
10166 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
     /* [previous][next][first][last][top][bottom][index][help] */
10167 {
10168 if (snd->extoff != 0) {
10169     if (snd->insoff > snd->extoff)
10170         memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10171     snd->insoff -= snd->extoff;
10172     snd->extoff  = 0;
10173     }
10174 if (snd->insoff+size > snd->bufsize) {
10175     snd->bufsize = snd->insoff+size;
10176     snd->buffer  = (uint8 *)realloc(snd->buffer, snd->bufsize);
10177     if (!snd->buffer)
10178       {
10179         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10180                        __func__, __FILE__, __LINE__);
10181 #if defined(USE_BACKTRACE)
10182 # if defined(SIGUSR2)
10183         (void)raise(SIGUSR2);
10184         /*NOTREACHED*/ /* unreachable */
10185 # endif /* if defined(SIGUSR2) */
10186 #endif /* if defined(USE_BACKTRACE) */
10187         abort();
10188       }
10189     }
10190 memcpy(snd->buffer+snd->insoff, data, size);
10191 snd->insoff += size;
10192 if (delay)
10193     snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10194 if (after)
10195     snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10196 if (snd->after == 0)
10197     snd->after = snd->delay;
10198 snd->next_time = sim_gtime() + snd->after;
10199 return SCPE_OK;
10200 }
10201 
10202 /* Cancel Queued input data */
10203 t_stat sim_send_clear (SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10204 {
10205 snd->insoff = 0;
10206 snd->extoff = 0;
10207 return SCPE_OK;
10208 }
10209 
10210 /* Display console Queued input data status */
10211 
10212 t_stat sim_show_send_input (FILE *st, const SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10213 {
10214 if (snd->extoff < snd->insoff) {
10215     (void)fprintf (st, "%lld bytes of pending input Data:\r\n    ",
10216                    (long long)snd->insoff-snd->extoff);
10217     fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10218     (void)fprintf (st, "\r\n");
10219     }
10220 else
10221     (void)fprintf (st, "No Pending Input Data\r\n");
10222 if ((snd->next_time - sim_gtime()) > 0) {
10223     if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10224         (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10225                        (int)(snd->next_time - sim_gtime()),
10226         (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10227     else
10228         (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10229                        (int)(snd->next_time - sim_gtime()));
10230     }
10231 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10232     (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10233                    (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10234 else
10235     (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10236                    (int)snd->delay);
10237 if (snd->dptr && snd->dbit)
10238     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10239                    sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10240                    snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10241 return SCPE_OK;
10242 }
10243 
10244 /* Poll for Queued input data */
10245 
10246 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10247 {
10248 #if defined(TESTING)
10249 cpu_state_t * cpup = _cpup;
10250 #endif
10251 if ((NULL != snd) && (snd->extoff < snd->insoff)) {     /* pending input characters available? */
10252     if (sim_gtime() < snd->next_time) {                 /* too soon? */
10253         *stat = SCPE_OK;
10254         sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10255         }
10256     else {
10257         char dstr[8] = "";
10258         *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;/* get one */
10259         snd->next_time = sim_gtime() + snd->delay;
10260         if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10261             (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10262         sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10263         }
10264     return TRUE;
10265     }
10266 return FALSE;
10267 }
10268 
10269 /* Message Text */
10270 
10271 const char *sim_error_text (t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10272 {
10273 static char msgbuf[64];
10274 
10275 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);        /* remove any flags */
10276 if (stat == SCPE_OK)
10277     return "No Error";
10278 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10279     return scp_errors[stat-SCPE_BASE].message;
10280 (void)sprintf(msgbuf, "Error %d", stat);
10281 return msgbuf;
10282 }
10283 
10284 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10285 {
10286 char gbuf[CBUFSIZE];
10287 size_t cond;
10288 
10289 *stat = SCPE_ARG;
10290 cptr = get_glyph (cptr, gbuf, 0);
10291 if (0 == memcmp("SCPE_", gbuf, 5))
10292     memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));  /* skip leading SCPE_ */
10293 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10294     if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10295         cond += SCPE_BASE;
10296         break;
10297         }
10298 if (0 == strcmp(gbuf, "OK"))
10299     cond = SCPE_OK;
10300 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {       /* not found? */
10301     unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10302     if (0 == numeric_cond)                    /* try explicit number */
10303         return SCPE_ARG;
10304     cond = (t_stat) numeric_cond;
10305     }
10306 if (cond > SCPE_MAX_ERR)
10307     return SCPE_ARG;
10308 *stat = cond;
10309 return SCPE_OK;
10310 }
10311 
10312 /* Debug printout routines, from Dave Hittner */
10313 
10314 const char* debug_bstates = "01_^";
10315 char debug_line_prefix[256];
10316 int32 debug_unterm  = 0;
10317 
10318 /* Finds debug phrase matching bitmask from from device DEBTAB table */
10319 
10320 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10321 {
10322 static const char *debtab_none    = "DEBTAB_ISNULL";
10323 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10324 const char *some_match = NULL;
10325 int32 offset = 0;
10326 
10327 if (dptr->debflags == 0)
10328     return debtab_none;
10329 
10330 dbits &= dptr->dctrl;                           /* Look for just the bits that matched */
10331 
10332 /* Find matching words for bitmask */
10333 
10334 while ((offset < 32) && dptr->debflags[offset].name) {
10335     if (dptr->debflags[offset].mask == dbits)   /* All Bits Match */
10336         return dptr->debflags[offset].name;
10337     if (dptr->debflags[offset].mask & dbits)
10338         some_match = dptr->debflags[offset].name;
10339     offset++;
10340     }
10341 return some_match ? some_match : debtab_nomatch;
10342 }
10343 
10344 /* Prints standard debug prefix unless previous call unterminated */
10345 
10346 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10347 {
10348 const char* debug_type = get_dbg_verb (dbits, dptr);
10349 char tim_t[32] = "";
10350 char tim_a[32] = "";
10351 char  pc_s[64] = "";
10352 struct timespec time_now;
10353 
10354 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10355     clock_gettime(CLOCK_REALTIME, &time_now);
10356     if (sim_deb_switches & SWMASK ('R'))
10357         sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10358     if (sim_deb_switches & SWMASK ('T')) {
10359         time_t tnow = (time_t)time_now.tv_sec;
10360         struct tm *now = gmtime(&tnow);
10361         (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10362                       (int)now->tm_hour,
10363                       (int)now->tm_min,
10364                       (int)now->tm_sec,
10365                       (long)(time_now.tv_nsec / 1000000));
10366         }
10367     if (sim_deb_switches & SWMASK ('A')) {
10368         (void)sprintf(tim_t, "%d.%03ld ",
10369                       (int)(time_now.tv_sec),
10370                       (long)(time_now.tv_nsec / 1000000));
10371         }
10372     }
10373 if (sim_deb_switches & SWMASK ('P')) {
10374     t_value val;
10375 
10376     if (sim_vm_pc_value)
10377         val = (*sim_vm_pc_value)();
10378     else
10379         val = get_rval (sim_PC, 0);
10380     (void)sprintf(pc_s, "-%s:", sim_PC->name);
10381     sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10382     }
10383 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10384               tim_t, tim_a, sim_gtime(), pc_s,
10385               "", dptr->name, debug_type);
10386 return debug_line_prefix;
10387 }
10388 
10389 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
     /* [previous][next][first][last][top][bottom][index][help] */
10390 {
10391 int32 i, fields, offset;
10392 uint32 value, beforevalue, mask;
10393 
10394 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10395     if (bitdefs[fields].offset == 0xffffffff)       /* fixup uninitialized offsets */
10396         bitdefs[fields].offset = offset;
10397     offset += bitdefs[fields].width;
10398     }
10399 for (i = fields-1; i >= 0; i--) {                   /* print xlation, transition */
10400     if (bitdefs[i].name[0] == '\0')
10401         continue;
10402     if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10403         int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10404         (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10405         }
10406     else {
10407         const char *delta = "";
10408         mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10409         value = (uint32)((after >> bitdefs[i].offset) & mask);
10410         beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10411         if (value < beforevalue)
10412             delta = "_";
10413         if (value > beforevalue)
10414             delta = "^";
10415         if (bitdefs[i].valuenames)
10416             (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10417         else
10418             if (bitdefs[i].format) {
10419                 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10420                 (void)Fprintf(stream, bitdefs[i].format, value);
10421                 (void)Fprintf(stream, " ");
10422                 }
10423             else
10424                 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10425         }
10426     }
10427 }
10428 
10429 /* Prints state of a register: bit translation + state (0,1,_,^)
10430    indicating the state and transition of the bit and bitfields. States:
10431    0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */
10432 
10433 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
     /* [previous][next][first][last][top][bottom][index][help] */
10434     BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10435 {
10436 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10437     if (!debug_unterm)
10438         (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));         /* print prefix if required */
10439     if (header)
10440         (void)fprintf(sim_deb, "%s: ", header);
10441     fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs); /* print xlation, transition */
10442     if (terminate)
10443         (void)fprintf(sim_deb, "\r\n");
10444     debug_unterm = terminate ? 0 : 1;                   /* set unterm for next */
10445     }
10446 }
10447 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
     /* [previous][next][first][last][top][bottom][index][help] */
10448     uint32 before, uint32 after, int terminate)
10449 {
10450 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10451 }
10452 
10453 /* Print message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10454 void sim_printf (const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10455 {
10456 char stackbuf[STACKBUFSIZE];
10457 int32 bufsize = sizeof(stackbuf);
10458 char *buf = stackbuf;
10459 int32 len;
10460 va_list arglist;
10461 
10462 while (1) {                                         /* format passed string, args */
10463     va_start (arglist, fmt);
10464     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10465     va_end (arglist);
10466 
10467 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10468 
10469     if ((len < 0) || (len >= bufsize-1)) {
10470         if (buf != stackbuf)
10471             FREE (buf);
10472         if (bufsize >= (INT_MAX / 2))
10473             return;                                 /* too big */
10474         bufsize = bufsize * 2;
10475         if (bufsize < len + 2)
10476             bufsize = len + 2;
10477         buf = (char *) malloc (bufsize);
10478         if (buf == NULL)                            /* out of memory */
10479             return;
10480         buf[bufsize-1] = '\0';
10481         continue;
10482         }
10483     break;
10484     }
10485 
10486 if (sim_is_running) {
10487     char *c, *remnant = buf;
10488     while ((c = strchr(remnant, '\n'))) { //-NLOK
10489         if ((c != buf) && (*(c - 1) != '\r')) //-NLOK
10490             (void)printf("%.*s\r\n", (int)(c-remnant), remnant); //-NLOK
10491         else
10492             (void)printf("%.*s\n", (int)(c-remnant), remnant); //-NLOK
10493         remnant = c + 1;
10494         }
10495     (void)printf("%s", remnant);
10496     }
10497 else
10498     (void)printf("%s", buf);
10499 if (sim_log && (sim_log != stdout))
10500     (void)fprintf (sim_log, "%s", buf);
10501 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10502     (void)fprintf (sim_deb, "%s", buf);
10503 
10504 if (buf != stackbuf)
10505     FREE (buf);
10506 }
10507 
10508 /* Print command result message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10509 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10510 {
10511 char stackbuf[STACKBUFSIZE];
10512 size_t bufsize = sizeof(stackbuf);
10513 char *buf = stackbuf;
10514 size_t len;
10515 va_list arglist;
10516 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10517 
10518 while (1) {                                         /* format passed string, args */
10519     va_start (arglist, fmt);
10520     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10521     va_end (arglist);
10522 
10523 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10524 
10525     if (len >= bufsize - 1) {
10526         if (buf != stackbuf)
10527             FREE (buf);
10528         bufsize = bufsize * 2;
10529         if (bufsize < len + 2)
10530             bufsize = len + 2;
10531         buf = (char *) malloc (bufsize);
10532         if (buf == NULL)                            /* out of memory */
10533             return SCPE_MEM;
10534         buf[bufsize-1] = '\0';
10535         continue;
10536         }
10537     break;
10538     }
10539 
10540 if (sim_do_ocptr[sim_do_depth]) {
10541     if (!sim_do_echo && !sim_quiet && !inhibit_message)
10542         sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10543     else {
10544         if (sim_deb)                        /* Always put context in debug output */
10545             (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10546         }
10547     }
10548 if (sim_is_running && !inhibit_message) {
10549     char *c, *remnant = buf;
10550     while ((c = strchr(remnant, '\n'))) { //-NLOK
10551         if ((c != buf) && (*(c - 1) != '\r')) //-NLOK
10552             (void)printf("%.*s\r\n", (int)(c-remnant), remnant); //-NLOK
10553         else
10554             (void)printf("%.*s\n", (int)(c-remnant), remnant); //-NLOK
10555         remnant = c + 1;
10556         }
10557     (void)printf("%s", remnant);
10558     }
10559 else {
10560     if (!inhibit_message)
10561         (void)printf("%s", buf);
10562     }
10563 if (sim_log && (sim_log != stdout) && !inhibit_message)
10564     (void)fprintf (sim_log, "%s", buf);
10565 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))/* Always display messages in debug output */
10566     (void)fprintf (sim_deb, "%s", buf);
10567 
10568 if (buf != stackbuf)
10569     FREE (buf);
10570 return stat | SCPE_NOMESSAGE;
10571 }
10572 
10573 /* Inline debugging - will print debug message if debug file is
10574    set and the bitmask matches the current device debug options.
10575    Extra returns are added for un*x systems, since the output
10576    device is set into 'raw' mode when the cpu is booted,
10577    and the extra returns don't hurt any other systems.
10578    Callers should be calling sim_debug() which is a macro
10579    defined in scp.h which evaluates the action condition before
10580    incurring call overhead. */
10581 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10582 {
10583 DEVICE *dptr = (DEVICE *)vdptr;
10584 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10585     char stackbuf[STACKBUFSIZE];
10586     int32 bufsize = sizeof(stackbuf);
10587     char *buf = stackbuf;
10588     va_list arglist;
10589     int32 i, j, len;
10590     const char* debug_prefix = sim_debug_prefix(dbits, dptr);   /* prefix to print if required */
10591 
10592     buf[bufsize-1] = '\0';
10593     while (1) {                                         /* format passed string, args */
10594         va_start (arglist, fmt);
10595         len = vsnprintf (buf, bufsize-1, fmt, arglist);
10596         va_end (arglist);
10597 
10598 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10599 
10600         if ((len < 0) || (len >= bufsize-1)) {
10601             if (buf != stackbuf)
10602                 FREE (buf);
10603             if (bufsize >= (INT_MAX / 2))
10604                 return;                                 /* too big */
10605             bufsize = bufsize * 2;
10606             if (bufsize < len + 2)
10607                 bufsize = len + 2;
10608             buf = (char *) malloc (bufsize);
10609             if (buf == NULL)                            /* out of memory */
10610                 return;
10611             buf[bufsize-1] = '\0';
10612             continue;
10613             }
10614         break;
10615         }
10616 
10617 /* Output the formatted data expanding newlines where they exist */
10618 
10619     for (i = j = 0; i < len; ++i) {
10620         if ('\n' == buf[i]) {
10621             if (i >= j) {
10622                 if ((i != j) || (i == 0)) {
10623                     if (debug_unterm)
10624                         (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10625                     else                                /* print prefix when required */
10626                         (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10627                     }
10628                 debug_unterm = 0;
10629                 }
10630             j = i + 1;
10631             }
10632         }
10633     if (i > j) {
10634         if (debug_unterm)
10635             (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10636         else                                        /* print prefix when required */
10637             (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10638         }
10639 
10640 /* Set unterminated flag for next time */
10641 
10642     debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10643     if (buf != stackbuf)
10644         FREE (buf);
10645     }
10646 return;
10647 }
10648 
10649 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] */
10650 {
10651 #if defined(TESTING)
10652 cpu_state_t * cpup = _cpup;
10653 #endif
10654 if (sim_deb && (dptr->dctrl & reason)) {
10655     sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10656     if (data && len) {
10657         size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10658         char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10659         static char hex[] = "0123456789ABCDEF";
10660         static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10661         static unsigned char ebcdic2ascii[] = {
10662             0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10663             0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10664             0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10665             0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10666             0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10667             0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10668             0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10669             0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10670             0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10671             0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10672             0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10673             0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10674             0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10675             0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10676             0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10677             0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10678             0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10679             0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10680             0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10681             0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10682             0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10683             0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10684             0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10685             0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10686             0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10687             0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10688             0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10689             0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10690             0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10691             0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10692             0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10693             0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10694             };
10695 
10696         for (i=same=0; i<len; i += 16) {
10697             if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10698                 ++same;
10699                 continue;
10700                 }
10701             if (same > 0) {
10702                 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10703                            (unsigned long int)(i - (16*same)),
10704                            (unsigned long int)(i - 1));
10705                 same = 0;
10706                 }
10707             group = (((len - i) > 16) ? 16 : (len - i));
10708             strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10709             eidx = strlen(ebcdicbuf);
10710             strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10711             ridx = strlen(rad50buf);
10712             strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10713             soff = strlen(strbuf);
10714             for (sidx=oidx=0; sidx<group; ++sidx) {
10715                 outbuf[oidx++] = ' ';
10716                 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10717                 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10718                 if (sim_isprint (data[i+sidx]))
10719                     strbuf[soff+sidx] = data[i+sidx];
10720                 else
10721                     strbuf[soff+sidx] = '.';
10722                 if (ridx && ((sidx&1) == 0)) {
10723                     uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10724 
10725                     if (word >= 64000) {
10726                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10727                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10728                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10729                         }
10730                     else {
10731                         rad50buf[ridx++] = rad50[word/1600];
10732                         rad50buf[ridx++] = rad50[(word/40)%40];
10733                         rad50buf[ridx++] = rad50[word%40];
10734                         }
10735                     }
10736                 if (eidx) {
10737                     if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10738                         ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10739                     else
10740                         ebcdicbuf[eidx++] = '.';
10741                     }
10742                 }
10743             outbuf[oidx] = '\0';
10744             strbuf[soff+sidx] = '\0';
10745             ebcdicbuf[eidx] = '\0';
10746             rad50buf[ridx] = '\0';
10747             sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10748                     (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10749             }
10750         if (same > 0) {
10751             sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10752                     (unsigned long int)(i-(16*same)),
10753                     (unsigned long int)(len-1));
10754             }
10755         }
10756     }
10757 }
10758 
10759 int Fprintf (FILE *f, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10760 {
10761 int ret = 0;
10762 va_list args;
10763 
10764 va_start (args, fmt);
10765     ret = vfprintf (f, fmt, args);
10766 va_end (args);
10767 return ret;
10768 }
10769 
10770 /* Hierarchical help presentation
10771  *
10772  * Device help can be presented hierarchically by calling
10773  *
10774  * t_stat scp_help (FILE *st, DEVICE *dptr,
10775  *                  UNIT *uptr, int flag, const char *help, char *cptr)
10776  *
10777  * or one of its three cousins from the device HELP routine.
10778  *
10779  * *help is the pointer to the structured help text to be displayed.
10780  *
10781  * The format and usage, and some helper macros can be found in scp_help.h
10782  * If you don't use the macros, it is not necessary to #include "scp_help.h".
10783  *
10784  * Actually, if you don't specify a DEVICE pointer and don't include
10785  * other device references, it can be used for non-device help.
10786  */
10787 
10788 #define blankch(x) ((x) == ' ' || (x) == '\t')
10789 
10790 typedef struct topic {
10791     size_t         level;
10792     char          *title;
10793     char          *label;
10794     struct topic  *parent;
10795     struct topic **children;
10796     uint32         kids;
10797     char          *text;
10798     size_t         len;
10799     uint32         flags;
10800     size_t         kidwid;
10801 #define HLP_MAGIC_TOPIC  1
10802     } TOPIC;
10803 
10804 static volatile struct {
10805     const char *error;
10806     const char *prox;
10807     size_t block;
10808     size_t line;
10809     } help_where = { "", NULL, 0, 0 };
10810 jmp_buf help_env;
10811 
10812 #define FAIL(why,text,here)        \
10813   {                                \
10814     help_where.error = #text;      \
10815     help_where.prox = here;        \
10816     longjmp ( help_env, (why) );   \
10817     /*LINTED E_STMT_NOT_REACHED*/  \
10818   }
10819 
10820 /*
10821  * Add to topic text.
10822  * Expands text buffer as necessary.
10823  */
10824 
10825 static void appendText (TOPIC *topic, const char *text, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
10826 {
10827 char *newt;
10828 
10829 if (!len)
10830     return;
10831 
10832 newt = (char *)realloc (topic->text, topic->len + len +1);
10833 if (!newt) {
10834 #if !defined(SUNLINT)
10835     FAIL (SCPE_MEM, No memory, NULL);
10836 #endif /* if !defined(SUNLINT) */
10837     }
10838 topic->text = newt;
10839 memcpy (newt + topic->len, text, len);
10840 topic->len +=len;
10841 newt[topic->len] = '\0';
10842 return;
10843 }
10844 
10845 /* Release memory held by a topic and its children.
10846  */
10847 static void cleanHelp (TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
10848 {
10849 TOPIC *child;
10850 size_t i;
10851 
10852 FREE (topic->title);
10853 FREE (topic->text);
10854 FREE (topic->label);
10855 for (i = 0; i < topic->kids; i++) {
10856     child = topic->children[i];
10857     cleanHelp (child);
10858     FREE (child);
10859     }
10860 FREE (topic->children);
10861 return;
10862 }
10863 
10864 /* Build a help tree from a string.
10865  * Handles substitutions, formatting.
10866  */
10867 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
10868                          UNIT *uptr, const char *htext, va_list ap)
10869 {
10870 char *end;
10871 size_t n, ilvl;
10872 #define VSMAX 100
10873 char *vstrings[VSMAX];
10874 size_t vsnum = 0;
10875 char * astrings[VSMAX+1];
10876 size_t asnum = 0;
10877 char *const *hblock;
10878 const char *ep;
10879 t_bool excluded = FALSE;
10880 
10881 /* variable arguments consumed table.
10882  * The scheme used allows arguments to be accessed in random
10883  * order, but for portability, all arguments must be char *.
10884  * If you try to violate this, there ARE machines that WILL break.
10885  */
10886 
10887 (void)memset (vstrings, 0, sizeof (vstrings));
10888 (void)memset (astrings, 0, sizeof (astrings));
10889 astrings[asnum++] = (char *) htext;
10890 
10891 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10892     help_where.block = hblock - astrings;
10893     help_where.line = 0;
10894     while (*htext) {
10895         const char *start;
10896 
10897         help_where.line++;
10898         if (sim_isspace (*htext) || *htext == '+') {/* Topic text, indented topic text */
10899             if (excluded) {                     /* Excluded topic text */
10900                 while (*htext && *htext != '\n')
10901                     htext++;
10902                 if (*htext)
10903                     ++htext;
10904                 continue;
10905                 }
10906             ilvl = 1;
10907             appendText (topic, "    ", 4);      /* Basic indentation */
10908             if (*htext == '+') {                /* More for each + */
10909                 while (*htext == '+') {
10910                     ilvl++;
10911                     appendText (topic, "    ", 4);
10912                     htext++;
10913                     }
10914                 }
10915             while (*htext && *htext != '\n' && sim_isspace (*htext))
10916                 htext++;
10917             if (!*htext)                        /* Empty after removing leading spaces */
10918                 break;
10919             start = htext;
10920             while (*htext) {                    /* Process line for substitutions */
10921                 if (*htext == '%') {
10922                     appendText (topic, start, htext - start); /* Flush up to escape */
10923                     switch (*++htext) {         /* Evaluate escape */
10924                         case 'U':
10925                             if (dptr) {
10926                                 char buf[129];
10927                                 n = uptr? uptr - dptr->units: 0;
10928                                 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10929                                 appendText (topic, buf, strlen (buf));
10930                                 }
10931                             break;
10932                         case 'D':
10933                             if (dptr != NULL)
10934                                 appendText (topic, dptr->name, strlen (dptr->name));
10935                             break;
10936                         case 'S':
10937                             appendText (topic, sim_name, strlen (sim_name));
10938                             break;
10939                         case '%':
10940                             appendText (topic, "%", 1);
10941                             break;
10942                         case '+':
10943                             appendText (topic, "+", 1);
10944                             break;
10945                         default:                    /* Check for vararg # */
10946                             if (sim_isdigit (*htext)) {
10947                                 n = 0;
10948                                 while (sim_isdigit (*htext))
10949                                     n += (n * 10) + (*htext++ - '0');
10950                                 if (( *htext != 'H' && *htext != 's') ||
10951                                     n == 0 || n >= VSMAX) {
10952 #if !defined(SUNLINT)
10953                                     FAIL (SCPE_ARG, Invalid escape, htext);
10954 #endif /* if !defined(SUNLINT) */
10955                                     }
10956                                 while (n > vsnum)   /* Get arg pointer if not cached */
10957                                     vstrings[vsnum++] = va_arg (ap, char *);
10958                                 start = vstrings[n-1]; /* Insert selected string */
10959                                 if (*htext == 'H') {   /* Append as more input */
10960                                     if (asnum >= VSMAX) {
10961 #if !defined(SUNLINT)
10962                                         FAIL (SCPE_ARG, Too many blocks, htext);
10963 #endif /* if !defined(SUNLINT) */
10964                                         }
10965                                     astrings[asnum++] = (char *)start;
10966                                     break;
10967                                     }
10968                                 ep = start;
10969                                 while (*ep) {
10970                                     if (*ep == '\n') {
10971                                         ep++;       /* Segment to \n */
10972                                         appendText (topic, start, ep - start);
10973                                         if (*ep) {  /* More past \n, indent */
10974                                             size_t i;
10975                                             for (i = 0; i < ilvl; i++)
10976                                                 appendText (topic, "    ", 4);
10977                                             }
10978                                         start = ep;
10979                                         }
10980                                     else
10981                                         ep++;
10982                                     }
10983                                 appendText (topic, start, ep-start);
10984                                 break;
10985                                 }
10986 #if !defined(SUNLINT)
10987                             FAIL (SCPE_ARG, Invalid escape, htext);
10988 #endif /* if !defined(SUNLINT) */
10989                         } /* switch (escape) */
10990                     start = ++htext;
10991                     continue;                   /* Current line */
10992                     } /* if (escape) */
10993                 if (*htext == '\n') {           /* End of line, append last segment */
10994                     htext++;
10995                     appendText (topic, start, htext - start);
10996                     break;                      /* To next line */
10997                     }
10998                 htext++;                        /* Regular character */
10999                 }
11000             continue;
11001             } /* topic text line */
11002         if (sim_isdigit (*htext)) {             /* Topic heading */
11003             TOPIC **children;
11004             TOPIC *newt;
11005             char nbuf[100];
11006 
11007             n = 0;
11008             start = htext;
11009             while (sim_isdigit (*htext))
11010                 n += (n * 10) + (*htext++ - '0');
11011             if ((htext == start) || !n) {
11012 #if !defined(SUNLINT)
11013                 FAIL (SCPE_ARG, Invalid topic heading, htext);
11014 #endif /* if !defined(SUNLINT) */
11015                 }
11016             if (n <= topic->level) {            /* Find level for new topic */
11017                 while (n <= topic->level)
11018                     topic = topic->parent;
11019                 }
11020             else {
11021                 if (n > topic->level + 1) {     /* Skipping down more than 1 */
11022 #if !defined(SUNLINT)
11023                     FAIL (SCPE_ARG, Level not contiguous, htext); /* E.g. 1 3, not reasonable */
11024 #endif /* if !defined(SUNLINT) */
11025                     }
11026                 }
11027             while (*htext && (*htext != '\n') && sim_isspace (*htext))
11028                 htext++;
11029             if (!*htext || (*htext == '\n')) {  /* Name missing */
11030 #if !defined(SUNLINT)
11031                 FAIL (SCPE_ARG, Missing topic name, htext);
11032 #endif /* if !defined(SUNLINT) */
11033                 }
11034             start = htext;
11035             while (*htext && (*htext != '\n'))
11036                 htext++;
11037             if (start == htext) {               /* Name NULL */
11038 #if !defined(SUNLINT)
11039                 FAIL (SCPE_ARG, Null topic name, htext);
11040 #endif /* if !defined(SUNLINT) */
11041                 }
11042             excluded = FALSE;
11043             if (*start == '?') {                /* Conditional topic? */
11044                 size_t n = 0;
11045                 start++;
11046                 while (sim_isdigit (*start))    /* Get param # */
11047                     n += (n * 10) + (*start++ - '0');
11048                 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11049 #if !defined(SUNLINT)
11050                     FAIL (SCPE_ARG, Invalid parameter number, start);
11051 #endif /* if !defined(SUNLINT) */
11052                     }
11053                 while (n > vsnum)               /* Get arg pointer if not cached */
11054                     vstrings[vsnum++] = va_arg (ap, char *);
11055                 end = vstrings[n-1];            /* Check for True */
11056                 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11057                     excluded = TRUE;            /* False, skip topic this time */
11058                     if (*htext)
11059                         htext++;
11060                     continue;
11061                     }
11062                 }
11063             newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11064             if (!newt) {
11065 #if !defined(SUNLINT)
11066                 FAIL (SCPE_MEM, No memory, NULL);
11067 #endif /* if !defined(SUNLINT) */
11068                 }
11069             size_t len = (htext > start) ? (htext - start) : 0;
11070             newt->title = (char *) malloc(len + 1);
11071             if (!newt->title) {
11072                 FREE (newt);
11073 #if !defined(SUNLINT)
11074                 FAIL (SCPE_MEM, No memory, NULL);
11075 #endif /* if !defined(SUNLINT) */
11076                 }
11077             memcpy (newt->title, start, htext - start);
11078             newt->title[htext - start] = '\0';
11079             if (*htext)
11080                 htext++;
11081 
11082             if (newt->title[0] == '$')
11083                 newt->flags |= HLP_MAGIC_TOPIC;
11084 
11085             children = (TOPIC **) realloc (topic->children,
11086                                            (topic->kids +1) * sizeof (TOPIC *));
11087             if (NULL == children) {
11088                 FREE (newt->title);
11089                 FREE (newt);
11090 #if !defined(SUNLINT)
11091                 FAIL (SCPE_MEM, No memory, NULL);
11092 #endif /* if !defined(SUNLINT) */
11093                 }
11094             topic->children = children;
11095             topic->children[topic->kids++] = newt;
11096             newt->level = n;
11097             newt->parent = topic;
11098             n = strlen (newt->title);
11099             if (n > topic->kidwid)
11100                 topic->kidwid = n;
11101             (void)sprintf (nbuf, ".%u", topic->kids);
11102             n = strlen (topic->label) + strlen (nbuf) + 1;
11103             newt->label = (char *) malloc (n);
11104             if (NULL == newt->label) {
11105                 FREE (newt->title);
11106                 topic->children[topic->kids -1] = NULL;
11107                 FREE (newt);
11108 #if !defined(SUNLINT)
11109                 FAIL (SCPE_MEM, No memory, NULL);
11110 #endif /* if !defined(SUNLINT) */
11111                 }
11112             (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11113             topic = newt;
11114             continue;
11115             } /* digits introducing a topic */
11116         if (*htext == ';') {                    /* Comment */
11117             while (*htext && *htext != '\n')
11118                 htext++;
11119             continue;
11120             }
11121 #if !defined(SUNLINT)
11122         FAIL (SCPE_ARG, Unknown line type, htext);     /* Unknown line */
11123 #endif /* if !defined(SUNLINT) */
11124         } /* htext not at end */
11125     (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11126     vsnum = 0;
11127     } /* all strings */
11128 
11129 return topic;
11130 }
11131 
11132 /*
11133  * Create prompt string - top thru current topic
11134  * Add prompt at end.
11135  */
11136 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
     /* [previous][next][first][last][top][bottom][index][help] */
11137 {
11138 char *prefix;
11139 char *newp, *newt;
11140 
11141 if (topic->level == 0) {
11142     prefix = (char *) calloc (2,1);
11143     if (!prefix) {
11144 #if !defined(SUNLINT)
11145         FAIL (SCPE_MEM, No memory, NULL);
11146 #endif /* if !defined(SUNLINT) */
11147         }
11148     prefix[0] = '\n';
11149     }
11150 else
11151     prefix = helpPrompt (topic->parent, "", oneword);
11152 
11153 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11154                         strlen (pstring) +1);
11155 if (!newp) {
11156     FREE (prefix);
11157 #if !defined(SUNLINT)
11158     FAIL (SCPE_MEM, No memory, NULL);
11159 #endif /* if !defined(SUNLINT) */
11160     }
11161 strcpy (newp, prefix);
11162 if (topic->children) {
11163     if (topic->level != 0)
11164         strcat (newp, " ");
11165     newt = (topic->flags & HLP_MAGIC_TOPIC)?
11166             topic->title+1: topic->title;
11167     if (oneword) {
11168         char *np = newp + strlen (newp);
11169         while (*newt) {
11170             *np++ = blankch (*newt)? '_' : *newt;
11171             newt++;
11172             }
11173         *np = '\0';
11174         }
11175     else
11176         strcat (newp, newt);
11177     if (*pstring && *pstring != '?')
11178         strcat (newp, " ");
11179     }
11180 strcat (newp, pstring);
11181 FREE (prefix);
11182 return newp;
11183 }
11184 
11185 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
11186 {
11187 char tbuf[CBUFSIZE];
11188 size_t i, skiplines;
11189 #if defined(_WIN32)
11190 FILE *tmp;
11191 char *tmpnam;
11192 
11193 do {
11194     int fd;
11195     tmpnam = _tempnam (NULL, "simh");
11196     fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11197     if (fd != -1) {
11198         tmp = _fdopen (fd, "w+");
11199         break;
11200         }
11201     } while (1);
11202 #else
11203 FILE *tmp = tmpfile();
11204 #endif /* if defined(_WIN32) */
11205 
11206 if (!tmp) {
11207     (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11208                    xstrerror_l(errno), errno);
11209     return;
11210     }
11211 
11212 if (topic->title)
11213     (void)fprintf (st, "%s\r\n", topic->title+1);
11214 
11215 skiplines = 0;
11216 if (topic->title) {
11217   if (!strcmp (topic->title+1, "Registers")) {
11218       fprint_reg_help (tmp, dptr) ;
11219       skiplines = 1;
11220       }
11221   else
11222       if (!strcmp (topic->title+1, "Set commands")) {
11223           fprint_set_help (tmp, dptr);
11224           skiplines = 3;
11225           }
11226       else
11227           if (!strcmp (topic->title+1, "Show commands")) {
11228               fprint_show_help (tmp, dptr);
11229               skiplines = 3;
11230               }
11231   }
11232 rewind (tmp);
11233 if (errno) {
11234     (void)fprintf (st, "rewind: error %d\r\n", errno);
11235 }
11236 
11237 /* Discard leading blank lines/redundant titles */
11238 
11239 for (i =0; i < skiplines; i++)
11240     if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11241 
11242 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11243     if (tbuf[0] != '\n')
11244         fputs ("    ", st);
11245     fputs (tbuf, st);
11246     }
11247 fclose (tmp);
11248 #if defined(_WIN32)
11249 remove (tmpnam);
11250 FREE (tmpnam);
11251 #endif /* if defined(_WIN32) */
11252 return;
11253 }
11254 /* Flatten and display help for those who say they prefer it. */
11255 
11256 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11257                                UNIT *uptr, int32 flag,
11258                                TOPIC *topic, va_list ap )
11259 {
11260 size_t i;
11261 
11262 if (topic->flags & HLP_MAGIC_TOPIC) {
11263     (void)fprintf (st, "\r\n%s ", topic->label);
11264     displayMagicTopic (st, dptr, topic);
11265     }
11266 else
11267     (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11268 
11269 /*
11270  * Topic text (for magic topics, follows for explanations)
11271  * It's possible/reasonable for a magic topic to have no text.
11272  */
11273 
11274 if (topic->text)
11275     fputs (topic->text, st);
11276 
11277 for (i = 0; i < topic->kids; i++)
11278     displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11279 
11280 return SCPE_OK;
11281 }
11282 
11283 #define HLP_MATCH_AMBIGUOUS (~0u)
11284 #define HLP_MATCH_WILDCARD  (~1U)
11285 #define HLP_MATCH_NONE      0
11286 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
     /* [previous][next][first][last][top][bottom][index][help] */
11287 {
11288 size_t i, match;
11289 char cbuf[CBUFSIZE], *cptr;
11290 
11291 if (!strcmp (token, "*"))
11292     return HLP_MATCH_WILDCARD;
11293 
11294 match = 0;
11295 for (i = 0; i < topic->kids; i++) {
11296     strcpy (cbuf,topic->children[i]->title +
11297             ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11298     cptr = cbuf;
11299     while (*cptr) {
11300         if (blankch (*cptr)) {
11301             *cptr++ = '_';
11302             }
11303         else {
11304             *cptr = (char)toupper (*cptr);
11305             cptr++;
11306             }
11307         }
11308     if (!strcmp (cbuf, token))      /* Exact Match */
11309         return i+1;
11310     if (!strncmp (cbuf, token, strlen (token))) {
11311         if (match)
11312             return HLP_MATCH_AMBIGUOUS;
11313         match = i+1;
11314         }
11315     }
11316 return match;
11317 }
11318 
11319 /* Main help routine */
11320 
11321 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11322                   UNIT *uptr, int32 flag,
11323                   const char *help, const char *cptr, va_list ap)
11324 {
11325 TOPIC top;
11326 TOPIC *topic = &top;
11327 int failed;
11328 size_t match;
11329 size_t i;
11330 const char *p;
11331 t_bool flat_help = FALSE;
11332 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11333 
11334 static const char attach_help[] = { " ATTACH" };
11335 static const char  brief_help[] = { "%s help.  Type <CR> to exit, HELP for navigation help.\r\n" };
11336 static const char onecmd_help[] = { "%s help.\r\n" };
11337 static const char   help_help[] = {
11338     /****|***********************80 column width guide********************************/
11339     "    To see more HELP information, type the listed subtopic name.  To move\r\n"
11340     "    up a level, just type <CR>.  To review the current subtopic, type \"?\".\r\n"
11341     "    To view all subtopics, type \"*\".  To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11342     };
11343 
11344 (void)memset (&top, 0, sizeof(top));
11345 top.parent = &top;
11346 if ((failed = setjmp (help_env)) != 0) {
11347     (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11348                            "Error in block %u line %u: %s\r\n"
11349                            "%s%*.*s%s\r\n",
11350                    (int)help_where.block, (int)help_where.line, help_where.error,
11351                    help_where.prox ? "Near '" : "",
11352                    help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11353                    help_where.prox ? help_where.prox : "",
11354                    help_where.prox ? "'" : "");
11355     cleanHelp (&top);
11356     return failed;
11357     }
11358 
11359 /* Compile string into navigation tree */
11360 
11361 /* Root */
11362 
11363 if (dptr) {
11364     p = dptr->name;
11365     flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11366     }
11367 else
11368     p = sim_name;
11369 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11370 if (!top.title)
11371   {
11372     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11373                    __func__, __FILE__, __LINE__);
11374 #if defined(USE_BACKTRACE)
11375 # if defined(SIGUSR2)
11376     (void)raise(SIGUSR2);
11377     /*NOTREACHED*/ /* unreachable */
11378 # endif /* if defined(SIGUSR2) */
11379 #endif /* if defined(USE_BACKTRACE) */
11380     abort();
11381   }
11382 for (i = 0; p[i]; i++ )
11383     top.title[i] = (char)toupper (p[i]);
11384 top.title[i] = '\0';
11385 if (flag & SCP_HELP_ATTACH)
11386     strcpy (top.title+i, attach_help);
11387 
11388 top.label = (char *) malloc (sizeof ("1"));
11389 if (!top.label)
11390   {
11391     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11392                    __func__, __FILE__, __LINE__);
11393 #if defined(USE_BACKTRACE)
11394 # if defined(SIGUSR2)
11395     (void)raise(SIGUSR2);
11396     /*NOTREACHED*/ /* unreachable */
11397 # endif /* if defined(SIGUSR2) */
11398 #endif /* if defined(USE_BACKTRACE) */
11399     abort();
11400   }
11401 strcpy (top.label, "1");
11402 
11403 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11404 
11405 if (flat_help) {
11406     flag |= SCP_HELP_FLAT;
11407     if (sim_ttisatty())
11408         (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11409     else
11410         (void)fprintf (st, "%s help.\r\n", top.title);
11411     }
11412 else
11413     (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11414 
11415 /* Add text and subtopics */
11416 
11417 (void) buildHelp (&top, dptr, uptr, help, ap);
11418 
11419 /* Go to initial topic if provided */
11420 
11421 while (cptr && *cptr) {
11422     cptr = get_glyph (cptr, gbuf, 0);
11423     if (!gbuf[0])
11424         break;
11425     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11426         (void)fprintf (st, "\r\n");
11427         fputs (help_help, st);
11428         break;
11429         }
11430     match =  matchHelpTopicName (topic, gbuf);
11431     if (match == HLP_MATCH_WILDCARD) {
11432         if (dptr)
11433             displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11434         cleanHelp (&top);
11435         return SCPE_OK;
11436         }
11437     if (match == HLP_MATCH_AMBIGUOUS) {
11438         (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11439         break;
11440         }
11441     if (match == HLP_MATCH_NONE) {
11442         (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11443         break;
11444         }
11445     topic = topic->children[match-1];
11446     }
11447 cptr = NULL;
11448 
11449 if (flat_help) {
11450     displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11451     cleanHelp (&top);
11452     return SCPE_OK;
11453     }
11454 
11455 /* Interactive loop displaying help */
11456 
11457 while (TRUE) {
11458     char *pstring;
11459     const char *prompt[2] = {"? ", "Subtopic? "};
11460 
11461     /* Some magic topic names for help from data structures */
11462 
11463     if (topic->flags & HLP_MAGIC_TOPIC) {
11464         fputc ('\n', st);
11465         displayMagicTopic (st, dptr, topic);
11466         }
11467     else
11468         (void)fprintf (st, "\r\n%s\r\n", topic->title);
11469 
11470     /* Topic text (for magic topics, follows for explanations)
11471      * It's possible/reasonable for a magic topic to have no text.
11472      */
11473 
11474     if (topic->text)
11475         fputs (topic->text, st);
11476 
11477     if (topic->kids) {
11478         size_t w = 0;
11479         char *p;
11480         char tbuf[CBUFSIZE];
11481 
11482         (void)fprintf (st, "\r\n    Additional information available:\r\n\r\n");
11483         for (i = 0; i < topic->kids; i++) {
11484             strcpy (tbuf, topic->children[i]->title +
11485                     ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11486             for (p = tbuf; *p; p++) {
11487                 if (blankch (*p))
11488                     *p = '_';
11489                 }
11490             w += 4 + topic->kidwid;
11491             if (w > 80) {
11492                 w = 4 + topic->kidwid;
11493                 fputc ('\r', st);
11494                 fputc ('\n', st);
11495                 }
11496             (void)fprintf (st, "    %-*s", (int32_t)topic->kidwid, tbuf);
11497             }
11498         (void)fprintf (st, "\r\n\r\n");
11499         if (flag & SCP_HELP_ONECMD) {
11500             pstring = helpPrompt (topic, "", TRUE);
11501             (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11502             FREE (pstring);
11503             break;
11504             }
11505         }
11506 
11507     if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11508         break;
11509 
11510   reprompt:
11511     if (NULL == cptr || !*cptr) {
11512         if (topic->kids == 0)
11513             topic = topic->parent;
11514         pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11515 
11516         cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11517         FREE (pstring);
11518         if ((cptr != NULL) &&                   /* Got something? */
11519             ((0 == strcmp (cptr, "\x04")) ||    /* was it a bare ^D? */
11520              (0 == strcmp (cptr, "\x1A"))))     /* was it a bare ^Z? */
11521             cptr = NULL;                        /* These are EOF synonyms */
11522         }
11523 
11524     if (NULL == cptr)                           /* EOF, exit help */
11525         break;
11526 
11527     cptr = get_glyph (cptr, gbuf, 0);
11528     if (!strcmp (gbuf, "*")) {              /* Wildcard */
11529         displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11530         gbuf[0] = '\0';                     /* Displayed all subtopics, go up */
11531         }
11532     if (!gbuf[0]) {                         /* Blank, up a level */
11533         if (topic->level == 0)
11534             break;
11535         topic = topic->parent;
11536         continue;
11537         }
11538     if (!strcmp (gbuf, "?"))                /* ?, repaint current topic */
11539         continue;
11540     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11541         fputs (help_help, st);
11542         goto reprompt;
11543         }
11544     if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))   /* EXIT (help) */
11545         break;
11546 
11547     /* String - look for that topic */
11548 
11549     if (!topic->kids) {
11550         (void)fprintf (st, "No additional help at this level.\r\n");
11551         cptr = NULL;
11552         goto reprompt;
11553         }
11554     match = matchHelpTopicName (topic, gbuf);
11555     if (match == HLP_MATCH_AMBIGUOUS) {
11556         (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11557         cptr = NULL;
11558         goto reprompt;
11559         }
11560 
11561     if (match == HLP_MATCH_NONE) {
11562         (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11563         cptr = NULL;
11564         goto reprompt;
11565         }
11566     /* Found, display subtopic */
11567 
11568     topic = topic->children[match-1];
11569     }
11570 
11571 /* Free structures and return */
11572 
11573 cleanHelp (&top);
11574 
11575 return SCPE_OK;
11576 }
11577 
11578 /* variable argument list shell - most commonly used */
11579 
11580 t_stat scp_help (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11581                  UNIT *uptr, int32 flag,
11582                  const char *help, const char *cptr, ...)
11583 {
11584 t_stat r;
11585 va_list ap;
11586 
11587 va_start (ap, cptr);
11588 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11589 va_end (ap);
11590 
11591 return r;
11592 }
11593 
11594 #if defined(_MSC_VER)
11595 # pragma warning(pop)
11596 #endif

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