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. show_version
  76. show_config
  77. show_log_names
  78. show_dev_logicals
  79. show_queue
  80. show_time
  81. show_break
  82. show_dev_radix
  83. show_dev_debug
  84. show_on
  85. show_mod_names
  86. show_dev_modifiers
  87. show_all_mods
  88. show_one_mod
  89. show_show_commands
  90. show_dev_show_commands
  91. brk_cmd
  92. ssh_break
  93. ssh_break_one
  94. reset_cmd
  95. reset_all
  96. reset_all_p
  97. attach_cmd
  98. scp_attach_unit
  99. attach_unit
  100. attach_err
  101. detach_cmd
  102. detach_all
  103. scp_detach_unit
  104. detach_unit
  105. sim_dname
  106. sim_uname
  107. run_cmd
  108. run_cmd_message
  109. sim_run_boot_prep
  110. fprint_stopped_gen
  111. fprint_stopped
  112. step_svc
  113. expect_svc
  114. int_handler
  115. exdep_cmd
  116. exdep_reg_loop
  117. exdep_addr_loop
  118. ex_reg
  119. get_rval
  120. dep_reg
  121. put_rval
  122. ex_addr
  123. get_aval
  124. dep_addr
  125. eval_cmd
  126. read_line
  127. read_line_p
  128. get_glyph_gen
  129. get_glyph
  130. get_glyph_nc
  131. get_glyph_quoted
  132. get_glyph_cmd
  133. sim_trim_endspc
  134. sim_isspace
  135. sim_islower
  136. sim_isalpha
  137. sim_isprint
  138. sim_isdigit
  139. sim_isgraph
  140. sim_isalnum
  141. get_uint
  142. get_range
  143. sim_decode_quoted_string
  144. sim_encode_quoted_string
  145. fprint_buffer_string
  146. find_dev
  147. find_unit
  148. sim_register_internal_device
  149. find_dev_from_unit
  150. qdisable
  151. find_reg_glob
  152. find_reg
  153. get_switches
  154. get_sim_sw
  155. get_sim_opt
  156. put_switches
  157. get_rsearch
  158. get_asearch
  159. test_search
  160. strtotv
  161. sprint_val
  162. fprint_val
  163. sim_fmt_secs
  164. sim_process_event
  165. sim_activate
  166. _sim_activate
  167. sim_activate_abs
  168. sim_activate_after
  169. _sim_activate_after
  170. sim_cancel
  171. sim_is_active
  172. sim_activate_time
  173. sim_gtime
  174. sim_qcount
  175. sim_brk_init
  176. sim_brk_fnd
  177. sim_brk_fnd_ex
  178. sim_brk_new
  179. sim_brk_set
  180. sim_brk_clr
  181. sim_brk_clrall
  182. sim_brk_show
  183. sim_brk_showall
  184. sim_brk_test
  185. sim_brk_getact
  186. sim_brk_clract
  187. sim_brk_setact
  188. sim_brk_npc
  189. sim_brk_clrspc
  190. sim_brk_message
  191. sim_set_expect
  192. sim_set_noexpect
  193. sim_exp_fnd
  194. sim_exp_clr_tab
  195. sim_exp_clr
  196. sim_exp_clrall
  197. sim_exp_set
  198. sim_exp_show_tab
  199. sim_exp_show
  200. sim_exp_showall
  201. sim_exp_check
  202. sim_send_input
  203. sim_send_clear
  204. sim_show_send_input
  205. sim_send_poll_data
  206. sim_error_text
  207. sim_string_to_stat
  208. get_dbg_verb
  209. sim_debug_prefix
  210. fprint_fields
  211. sim_debug_bits_hdr
  212. sim_debug_bits
  213. sim_printf
  214. sim_messagef
  215. _sim_debug
  216. sim_data_trace
  217. Fprintf
  218. appendText
  219. cleanHelp
  220. buildHelp
  221. helpPrompt
  222. displayMagicTopic
  223. displayFlatHelp
  224. matchHelpTopicName
  225. scp_vhelp
  226. scp_help

   1 /*
   2  * scp.c: simulator control program
   3  *
   4  * vim: filetype=c:tabstop=4:ai:colorcolumn=84:expandtab
   5  * SPDX-License-Identifier: MIT
   6  * scspell-id: 7cde852c-f62a-11ec-8444-80ee73e9b8e7
   7  *
   8  * ---------------------------------------------------------------------------
   9  *
  10  * Copyright (c) 1993-2022 Robert M. Supnik
  11  * Copyright (c) 2021-2023 Jeffrey H. Johnson
  12  * Copyright (c) 2006-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 static unsigned int dl_iterate_phdr_callback_called = 0;
 184 #         endif
 185 #        endif
 186 #       endif
 187 #      endif
 188 #     endif
 189 #    endif
 190 #   endif
 191 #  endif
 192 # endif
 193 #endif
 194 
 195 #if defined(MAX)
 196 # undef MAX
 197 #endif /* if defined(MAX) */
 198 #define MAX(a,b)  (((a) >= (b)) ? (a) : (b))
 199 
 200 #if defined(FREE)
 201 # undef FREE
 202 #endif /* if defined(FREE) */
 203 #define FREE(p) do  \
 204   {                 \
 205     free((p));      \
 206     (p) = NULL;     \
 207   } while(0)
 208 
 209 /* search logical and boolean ops */
 210 
 211 #define SCH_OR          0                               /* search logicals */
 212 #define SCH_AND         1
 213 #define SCH_XOR         2
 214 #define SCH_E           0                               /* search booleans */
 215 #define SCH_N           1
 216 #define SCH_G           2
 217 #define SCH_L           3
 218 #define SCH_EE          4
 219 #define SCH_NE          5
 220 #define SCH_GE          6
 221 #define SCH_LE          7
 222 
 223 #define MAX_DO_NEST_LVL 20                              /* DO cmd nesting level */
 224 #define SRBSIZ          1024                            /* save/restore buffer */
 225 #define SIM_BRK_INILNT  4096                            /* bpt tbl length */
 226 #define SIM_BRK_ALLTYP  0xFFFFFFFB
 227 
 228 #define UPDATE_SIM_TIME                                         \
 229     if (1) {                                                    \
 230         int32 _x;                                               \
 231         if (sim_clock_queue == QUEUE_LIST_END)                  \
 232             _x = noqueue_time;                                  \
 233         else                                                    \
 234             _x = sim_clock_queue->time;                         \
 235         sim_time = sim_time + (_x - sim_interval);              \
 236         sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
 237         if (sim_clock_queue == QUEUE_LIST_END)                  \
 238             noqueue_time = sim_interval;                        \
 239         else                                                    \
 240             sim_clock_queue->time = sim_interval;               \
 241         }                                                       \
 242     else                                                        \
 243         (void)0
 244 
 245 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
 246 
 247 #define SZ_R(rp) \
 248     (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
 249 
 250 #define SZ_LOAD(sz,v,mb,j)                                                 \
 251     if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j));        \
 252     else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
 253     else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
 254     else v = *(((t_uint64 *) mb) + ((uint32) j));
 255 
 256 #define SZ_STORE(sz,v,mb,j)                                                         \
 257     if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v;                    \
 258     else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
 259     else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
 260     else *(((t_uint64 *) mb) + ((uint32) j)) = v;
 261 
 262 #define GET_SWITCHES(cp) \
 263     if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
 264 
 265 #define GET_RADIX(val,dft)                          \
 266     if (sim_switches & SWMASK ('O')) val = 8;       \
 267     else if (sim_switches & SWMASK ('D')) val = 10; \
 268     else if (sim_switches & SWMASK ('H')) val = 16; \
 269     else val = dft;
 270 
 271 /*
 272  * The per-simulator init routine is a weak global that defaults to NULL
 273  * The other per-simulator pointers can be overridden by the init routine
 274  */
 275 
 276 t_bool sim_asynch_enabled = FALSE;
 277 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
 278 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
 279 extern void (*sim_vm_init) (void);
 280 extern void (*sim_vm_exit) (void);
 281 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
 282 void (*sim_vm_post) (t_bool from_scp) = NULL;
 283 CTAB *sim_vm_cmd = NULL;
 284 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
 285 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
 286 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
 287 t_value (*sim_vm_pc_value) (void) = NULL;
 288 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
 289 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
 290 unsigned int nprocs;
 291 unsigned int ncores;
 292 bool mlock_failure = false;
 293 char* sim_appfilename;
 294 
 295 /* Prototypes */
 296 
 297 /* Set and show command processors */
 298 
 299 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 300 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 301 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 302 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 303 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
 304 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
 305 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 306 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 307 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 308 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 309 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 310 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 311 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 312 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 313 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 314 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 315 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 316 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 317 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
 318 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 319 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 320 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 321 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 322 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 323 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 324 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 325 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
 326 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
 327 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
 328 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
 329 t_stat sim_save (FILE *sfile);
 330 t_stat sim_rest (FILE *rfile);
 331 
 332 /* Breakpoint package */
 333 
 334 t_stat sim_brk_init (void);
 335 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
 336 t_stat sim_brk_clr (t_addr loc, int32 sw);
 337 t_stat sim_brk_clrall (int32 sw);
 338 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
 339 t_stat sim_brk_showall (FILE *st, uint32 sw);
 340 CONST char *sim_brk_getact (char *buf, int32 size);
 341 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
 342 char *sim_brk_clract (void);
 343 
 344 FILE *stdnul;
 345 
 346 /* Command support routines */
 347 
 348 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 349 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 350 int32 test_search (t_value *val, SCHTAB *schptr);
 351 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
 352 int32 get_switches (const char *cptr);
 353 CONST char *get_sim_sw (CONST char *cptr);
 354 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
 355 t_value get_rval (REG *rptr, uint32 idx);
 356 void put_rval (REG *rptr, uint32 idx, t_value val);
 357 void fprint_help (FILE *st);
 358 void fprint_stopped (FILE *st, t_stat r);
 359 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
 360 void fprint_sep (FILE *st, int32 *tokens);
 361 char *read_line (char *ptr, int32 size, FILE *stream);
 362 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
 363 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
 364 char *sim_trim_endspc (char *cptr);
 365 
 366 /* Forward references */
 367 
 368 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
 369 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
 370 t_bool qdisable (DEVICE *dptr);
 371 t_stat attach_err (UNIT *uptr, t_stat stat);
 372 t_stat detach_all (int32 start_device, t_bool shutdown);
 373 t_stat assign_device (DEVICE *dptr, const char *cptr);
 374 t_stat deassign_device (DEVICE *dptr);
 375 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
 376 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
 377     REG *lowr, REG *highr, uint32 lows, uint32 highs);
 378 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
 379 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
 380 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
 381     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
 382 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
 383 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
 384     UNIT *uptr, int32 dfltinc);
 385 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
 386 t_stat step_svc (UNIT *ptr);
 387 t_stat expect_svc (UNIT *ptr);
 388 t_stat set_on (int32 flag, CONST char *cptr);
 389 t_stat set_verify (int32 flag, CONST char *cptr);
 390 t_stat set_message (int32 flag, CONST char *cptr);
 391 t_stat set_quiet (int32 flag, CONST char *cptr);
 392 t_stat set_localopc (int32 flag, CONST char *cptr);
 393 t_stat set_asynch (int32 flag, CONST char *cptr);
 394 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 395 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
 396 void int_handler (int signal);
 397 t_stat set_prompt (int32 flag, CONST char *cptr);
 398 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
 399 t_stat sim_set_environment (int32 flag, CONST char *cptr);
 400 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
 401 
 402 /* Global data */
 403 
 404 DEVICE *sim_dflt_dev             = NULL;
 405 UNIT *sim_clock_queue            = QUEUE_LIST_END;
 406 int32 sim_interval               = 0;
 407 int32 sim_switches               = 0;
 408 FILE *sim_ofile                  = NULL;
 409 SCHTAB *sim_schrptr              = NULL;
 410 SCHTAB *sim_schaptr              = NULL;
 411 DEVICE *sim_dfdev                = NULL;
 412 UNIT *sim_dfunit                 = NULL;
 413 DEVICE **sim_internal_devices    = NULL;
 414 uint32 sim_internal_device_count = 0;
 415 int32 sim_opt_out                = 0;
 416 int32 sim_is_running             = 0;
 417 t_bool sim_processing_event      = FALSE;
 418 uint32 sim_brk_summ              = 0;
 419 uint32 sim_brk_types             = 0;
 420 BRKTYPTAB *sim_brk_type_desc     = NULL;         /* type descriptions */
 421 uint32 sim_brk_dflt              = 0;
 422 uint32 sim_brk_match_type;
 423 t_addr sim_brk_match_addr;
 424 char *sim_brk_act[MAX_DO_NEST_LVL];
 425 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
 426 BRKTAB **sim_brk_tab             = NULL;
 427 int32 sim_brk_ent                = 0;
 428 int32 sim_brk_lnt                = 0;
 429 int32 sim_brk_ins                = 0;
 430 int32 sim_iglock                 = 0;
 431 int32 sim_nolock                 = 0;
 432 int32 sim_quiet                  = 0;
 433 int32 sim_localopc               = 1;
 434 int32 sim_randompst              = 0;
 435 int32 sim_randstate              = 0;
 436 int32 sim_step                   = 0;
 437 int nodist                       = 0;
 438 #if defined(PERF_STRIP)
 439 int32 sim_nostate                = 1;
 440 #else
 441 int32 sim_nostate                = 0;
 442 #endif /* if defined(PERF_STRIP) */
 443 static double sim_time;
 444 static uint32 sim_rtime;
 445 static int32 noqueue_time;
 446 volatile int32 stop_cpu          = 0;
 447 t_value *sim_eval                = NULL;
 448 static t_value sim_last_val;
 449 static t_addr sim_last_addr;
 450 FILE *sim_log                    = NULL;         /* log file */
 451 FILEREF *sim_log_ref             = NULL;         /* log file file reference */
 452 FILE *sim_deb                    = NULL;         /* debug file */
 453 FILEREF *sim_deb_ref             = NULL;         /* debug file file reference */
 454 int32 sim_deb_switches           = 0;            /* debug switches */
 455 struct timespec sim_deb_basetime;                /* debug timestamp relative base time */
 456 char *sim_prompt                 = NULL;         /* prompt string */
 457 static FILE *sim_gotofile;                       /* the currently open do file */
 458 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];   /* the current line number in the currently open do file */
 459 static int32 sim_do_echo         = 0;            /* the echo status of the currently open do file */
 460 static int32 sim_show_message    = 1;            /* the message display status of the currently open do file */
 461 static int32 sim_on_inherit      = 0;            /* the inherit status of on state and conditions when executing do files */
 462 #if !defined(PERF_STRIP)
 463 static int32 sim_realtime        = 0;            /* user requested real-time mode */
 464 #endif
 465 static int32 sim_do_depth        = 0;
 466 uint64_t sim_free_memory         = 0;
 467 
 468 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
 469 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
 470 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
 471 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
 472 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
 473 
 474 t_stat sim_last_cmd_stat;                        /* Command Status */
 475 
 476 static SCHTAB sim_stabr;                         /* Register search specifier */
 477 static SCHTAB sim_staba;                         /* Memory search specifier */
 478 
 479 static UNIT sim_step_unit   = { UDATA (&step_svc, 0, 0)  };
 480 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0)  };
 481 
 482 pthread_t main_thread_id;
 483 
 484 /* Tables and strings */
 485 
 486 const char save_vercur[] = "V4.1";
 487 const char save_ver40[]  = "V4.0";
 488 const char save_ver35[]  = "V3.5";
 489 const char save_ver32[]  = "V3.2";
 490 const char save_ver30[]  = "V3.0";
 491 const struct scp_error {
 492     const char *code;
 493     const char *message;
 494     } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
 495         {{"NXM",     "Address space exceeded"},
 496          {"UNATT",   "Unit not attached"},
 497          {"IOERR",   "I/O error"},
 498          {"CSUM",    "Checksum error"},
 499          {"FMT",     "Format error"},
 500          {"NOATT",   "Unit not attachable"},
 501          {"OPENERR", "File open error"},
 502          {"MEM",     "Memory exhausted"},
 503          {"ARG",     "Invalid argument"},
 504          {"STEP",    "Step expired"},
 505          {"UNK",     "Unknown command"},
 506          {"RO",      "Read only argument"},
 507          {"INCOMP",  "Command not completed"},
 508          {"STOP",    "Simulation stopped"},
 509          {"EXIT",    "Goodbye"},
 510          {"TTIERR",  "Console input I/O error"},
 511          {"TTOERR",  "Console output I/O error"},
 512          {"EOF",     "End of file"},
 513          {"REL",     "Relocation error"},
 514          {"NOPARAM", "No settable parameters"},
 515          {"ALATT",   "Unit already attached"},
 516          {"TIMER",   "Hardware timer error"},
 517          {"SIGERR",  "Signal handler setup error"},
 518          {"TTYERR",  "Console terminal setup error"},
 519          {"SUB",     "Subscript out of range"},
 520          {"NOFNC",   "Command not allowed"},
 521          {"UDIS",    "Unit disabled"},
 522          {"NORO",    "Read only operation not allowed"},
 523          {"INVSW",   "Invalid switch"},
 524          {"MISVAL",  "Missing value"},
 525          {"2FARG",   "Too few arguments"},
 526          {"2MARG",   "Too many arguments"},
 527          {"NXDEV",   "Non-existent device"},
 528          {"NXUN",    "Non-existent unit"},
 529          {"NXREG",   "Non-existent register"},
 530          {"NXPAR",   "Non-existent parameter"},
 531          {"NEST",    "Nested DO command limit exceeded"},
 532          {"IERR",    "Internal error"},
 533          {"MTRLNT",  "Invalid magtape record length"},
 534          {"LOST",    "Console Telnet connection lost"},
 535          {"TTMO",    "Console Telnet connection timed out"},
 536          {"STALL",   "Console Telnet output stall"},
 537          {"AFAIL",   "Assertion failed"},
 538          {"INVREM",  "Invalid remote console command"},
 539          {"NOTATT",  "Not attached"},
 540          {"EXPECT",  "Expect matched"},
 541          {"REMOTE",  "Remote console command"},
 542     };
 543 
 544 const size_t size_map[] = { sizeof (int8),
 545     sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
 546     , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
 547 };
 548 
 549 const t_value width_mask[] = { 0,
 550     0x1, 0x3, 0x7, 0xF,
 551     0x1F, 0x3F, 0x7F, 0xFF,
 552     0x1FF, 0x3FF, 0x7FF, 0xFFF,
 553     0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
 554     0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
 555     0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
 556     0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
 557     0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
 558     0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
 559     0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
 560     0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
 561     0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
 562     0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
 563     0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
 564     0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
 565     0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
 566     };
 567 
 568 static const char simh_help[] =
 569        /***************** 80 character line width template *************************/
 570       "1Commands\n" //-NLOK
 571 #define HLP_RESET       "*Commands Resetting Devices"
 572        /***************** 80 character line width template *************************/
 573       "2Resetting Devices\n" //-NLOK
 574       " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\r\n"
 575       " simulator to a predefined condition.  If the switch \"`-p`\" is specified,\r\n"
 576       " the device is reset to its initial power-on state:\r\n\r\n"
 577       "++RESET                  resets all devices\r\n"
 578       "++RESET -p               power-cycle all devices\r\n"
 579       "++RESET ALL              resets all devices\r\n"
 580       "++RESET <device>         resets the specified <device>\r\n\r\n"
 581       " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\r\n"
 582       " interrupt requests, and returns the device to a quiescent state.\r\n\r\n"
 583       " * It does **NOT** clear the main memory or affect associated I/O\r\n"
 584       " connections.\r\n"
 585 #define HLP_EXAMINE     "*Commands Examining_and_Changing_State"
 586 #define HLP_IEXAMINE    "*Commands Examining_and_Changing_State"
 587 #define HLP_DEPOSIT     "*Commands Examining_and_Changing_State"
 588 #define HLP_IDEPOSIT    "*Commands Examining_and_Changing_State"
 589        /***************** 80 character line width template *************************/
 590       "2Examining and Changing State\n" //-NLOK
 591       " There are four commands to examine and change state:\r\n\r\n"
 592       " * `EXAMINE` (*abbreviated* `E`) examines state\r\n"
 593       " * `DEPOSIT` (*abbreviated* `D`) changes state\r\n"
 594       " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\r\n"
 595       "    and allows the user to interactively change it\r\n"
 596       " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\r\n"
 597       "    interactively change state\r\n\r\n"
 598       " All four commands take the form:\r\n\r\n"
 599       "++command {modifiers} <object list>\r\n\r\n"
 600       " The `DEPOSIT` command requires the deposit value at the end of the command.\r\n\r\n"
 601       " There are four kinds of modifiers: **switches**, **device/unit name**,\r\n"
 602       " **search specifier**, and for `EXAMINE`, **output file**.\r\n\r\n"
 603       " * **Switches** have been described previously.\r\n"
 604       " * A **device/unit name** identifies the device and unit whose address\r\n"
 605       " space is to be examined or modified. If no device is specified, the CPU\r\n"
 606       " main memory is selected. If a device but no unit is specified, unit `0`\r\n"
 607       " of the specified device is selected automatically.\r\n"
 608       " * The **search specifier** provides criteria for testing addresses or\r\n"
 609       " registers to see if they should be processed.  The search specifier\r\n"
 610       " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\r\n"
 611       " both, optionally separated by spaces:\r\n\r\n"
 612       "++{ < logical op >  < value > }  < relational op >  < value >\r\n\r\n"
 613        /***************** 80 character line width template *************************/
 614       " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\r\n"
 615       " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\r\n"
 616       " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\r\n"
 617       " equal*), \">=\" (*greater than or equal*), \">\" (*greater\r\n"
 618       " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\r\n"
 619       " * * If any \"<`logical operator`>\" is specified without\r\n"
 620       " a \"<`relational operator`>\", it is ignored.\r\n"
 621       " * * If any \"<`relational operator`>\" is specified without\r\n"
 622       " a \"<`logical operator`>\", no logical operation is performed.\r\n"
 623       " * * All comparisons are unsigned.\r\n\r\n"
 624       " * The **output file** modifier redirects the command output to a file\r\n"
 625       " instead of the console.  The **output file** modifier is specified with\r\n"
 626       " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\r\n\r\n"
 627       " **NOTE**: Modifiers may be specified in any order.  If multiple\r\n"
 628       " modifiers of the same type are specified, later modifiers override earlier\r\n"
 629       " modifiers. If the **device/unit name** comes *after* the search specifier,\r\n"
 630       " the search values will interpreted in the *radix of the CPU*, rather than\r\n"
 631       " of the device/unit.\r\n\r\n"
 632       " The \"<`object list`>\" argument consists of one or more of the following,\r\n"
 633       " separated by commas:\r\n\r\n"
 634        /***************** 80 character line width template *************************/
 635       "++register                the specified register\r\n"
 636       "++register[sub1-sub2]     the specified register array locations,\r\n"
 637       "++++++++                  starting at location sub1 up to and\r\n"
 638       "++++++++                  including location sub2\r\n"
 639       "++register[sub1/length]   the specified register array locations,\r\n"
 640       "++++++++                  starting at location sub1 up to but\r\n"
 641       "++++++++                  not including sub1+length\r\n"
 642       "++register[ALL]           all locations in the specified register\r\n"
 643       "++++++++                  array\r\n"
 644       "++register1-register2     all the registers starting at register1\r\n"
 645       "++++++++                  up to and including register2\r\n"
 646       "++address                 the specified location\r\n"
 647       "++address1-address2       all locations starting at address1 up to\r\n"
 648       "++++++++                  and including address2\r\n"
 649       "++address/length          all location starting at address up to\r\n"
 650       "++++++++                  but not including address+length\r\n"
 651       "++STATE                   all registers in the device\r\n"
 652       "++ALL                     all locations in the unit\r\n"
 653       "++$                       the last value displayed by an EXAMINE\r\n"
 654       "++++++++                  command interpreted as an address\r\n"
 655       "3Switches\n" //-NLOK
 656       "4Formatting Control\n" //-NLOK
 657       " Switches can be used to control the format of the displayed information:\r\n\r\n"
 658        /***************** 80 character line width template *************************/
 659       "5`-a`\n" //-NLOK
 660       " display as ASCII\r\n"
 661       "5`-c`\n" //-NLOK
 662       " display as character string\r\n"
 663       "5`-m`\n" //-NLOK
 664       " display as instruction mnemonics\r\n"
 665       "5`-o`\n" //-NLOK
 666       " display as octal\r\n"
 667       "5`-d`\n" //-NLOK
 668       " display as decimal\r\n"
 669       "5`-h`\n" //-NLOK
 670       " display as hexadecimal\r\n\r\n"
 671       "3Examples\n" //-NLOK
 672       "++ex 1000-1100                examine 1000 to 1100\r\n"
 673       "++de PC 1040                  set PC to 1040\r\n"
 674       "++ie 40-50                    interactively examine 40:50\r\n"
 675       "++ie >1000 40-50              interactively examine the subset\r\n"
 676       "+++++++++                     of locations 40:50 that are >1000\r\n"
 677       "++ex rx0 50060                examine 50060, RX unit 0\r\n"
 678       "++ex rx sbuf[3-6]             examine SBUF[3] to SBUF[6] in RX\r\n"
 679       "++de all 0                    set main memory to 0\r\n"
 680       "++de &77>0 0                  set all addresses whose low order\r\n"
 681       "+++++++++                     bits are non-zero to 0\r\n"
 682       "++ex -m @memdump.txt 0-7777   dump memory to file\r\n\r\n"
 683       " * **NOTE**: To terminate an interactive command, simply type any bad value\r\n"
 684       "           (*e.g.* `XYZ`) when input is requested.\r\n"
 685 #define HLP_EVALUATE    "*Commands Evaluating_Instructions"
 686        /***************** 80 character line width template *************************/
 687       "2Evaluating Instructions\n" //-NLOK
 688       " The `EVAL` command evaluates a symbolic expression and returns the\r\n"
 689       " equivalent numeric value.\r\n\r\n"
 690        /***************** 80 character line width template *************************/
 691       "2Running A Simulated Program\n" //-NLOK
 692 #define HLP_RUN         "*Commands Running_A_Simulated_Program RUN"
 693       "3RUN\n" //-NLOK
 694       " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\r\n"
 695       " argument, if given, in the PC (program counter), and starts execution.\r\n"
 696       " If no argument is given execution starts at the current PC.\r\n"
 697 #define HLP_GO          "*Commands Running_A_Simulated_Program GO"
 698       "3GO\n" //-NLOK
 699       " The `GO` command does *not* reset devices, deposits its argument (if\r\n"
 700       " given) in the PC, and starts execution.  If no argument is given,\r\n"
 701       " execution starts at the current PC (program counter).\r\n"
 702 #define HLP_CONTINUE    "*Commands Running_A_Simulated_Program Continuing_Execution"
 703       "3Continuing Execution\n" //-NLOK
 704       " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\r\n"
 705       " (if execution was stopped, possibly due to hitting a breakpoint) at the\r\n"
 706       " current program counter without resetting any devices.\r\n"
 707 #define HLP_STEP        "*Commands Running_A_Simulated_Program Step_Execution"
 708       "3Step Execution\n" //-NLOK
 709       " The `STEP` command (*abbreviated* `S`) resumes execution at the current\r\n"
 710       " PC for the number of instructions given by its argument.  If no argument\r\n"
 711       " is supplied, one instruction is executed.\r\n"
 712       "4Switches\n" //-NLOK
 713       "5`-T`\n" //-NLOK
 714       " If the `STEP` command is invoked with the \"`-T`\" switch, the step\r\n"
 715       " command will cause execution to run for *microseconds* rather than\r\n"
 716       " instructions.\r\n"
 717 #define HLP_NEXT        "*Commands Running_A_Simulated_Program NEXT"
 718       "3NEXT\n" //-NLOK
 719       " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\r\n"
 720       " for one instruction, attempting to execute *through* subroutine calls.\r\n"
 721       " If the next instruction to be executed is *not* a subroutine call, then\r\n"
 722       " one instruction is executed.\r\n"
 723 #define HLP_BOOT        "*Commands Running_A_Simulated_Program Booting_the_system"
 724       "3Booting the system\n" //-NLOK
 725       " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\r\n"
 726       " the device and unit given by its argument. If no unit is supplied,\r\n"
 727       " unit `0` is bootstrapped.  The specified unit must be `ATTACH`'ed.\r\n\r\n"
 728       " When booting Multics, the boot device should always be `iom0`.\r\n"
 729       " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\r\n"
 730       " into memory and the system will transfer control to the boot record.\r\n\r\n"
 731       " **Example**\r\n\r\n"
 732       "++; Boot Multics using iom0\r\n"
 733       "++boot iom0\r\n\r\n"
 734        /***************** 80 character line width template *************************/
 735       "2Stopping The Simulator\n" //-NLOK
 736       " The simulator runs until the simulated hardware encounters an error, or\r\n"
 737       " until the user forces a stop condition.\r\n"
 738       "3Simulator Detected Stop Conditions\n" //-NLOK
 739       " These simulator-detected conditions stop simulation:\r\n\r\n"
 740       "++-  HALT instruction.  If a HALT instruction is decoded, simulation stops.\r\n\r\n"
 741       "++-  I/O error.  If an I/O error occurs during simulation of an I/O\r\n"
 742       "+++operation, and the device stop-on-I/O-error flag is set, simulation\r\n"
 743       "+++usually stops.\r\n\r\n"
 744       "++-  Processor condition.  Certain processor conditions can stop\r\n"
 745       "+++the simulation.\r\n"
 746       "3User Specified Stop Conditions\n" //-NLOK
 747       " Typing the interrupt character stops simulation.  The interrupt character\r\n"
 748       " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\r\n"
 749       " set to `005` (`^E`).\r\n\r\n"
 750        /***************** 80 character line width template *************************/
 751 #define HLP_BREAK       "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 752 #define HLP_NOBREAK     "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 753       "4Breakpoints\n" //-NLOK
 754       " The simulator offers breakpoint capability for debugging. Users may define\r\n"
 755       " breakpoints of different types, identified by letter (for example, `E`\r\n"
 756       " for *execution*, `R` for *read*, `W` for *write*, etc).\r\n\r\n"
 757       " Associated with each breakpoint is a count and, optionally, one or more\r\n"
 758       " actions.  Each time a breakpoint occurs, the associated count\r\n"
 759       " is *decremented*.  If the count is less than or equal to `0`, the breakpoint\r\n"
 760       " occurs; otherwise, it is deferred.  When the breakpoint occurs, any\r\n"
 761       " optional actions are automatically executed.\r\n\r\n"
 762       " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\r\n\r\n"
 763       "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\r\n\r\n"
 764       " If no type is specified, the default breakpoint type (`E`, *execution*) is\r\n"
 765       " used.  If no address range is specified, the current PC is used.  As\r\n"
 766       " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\r\n"
 767       " range of addresses low-high, or a relative range of address/length.\r\n"
 768        /***************** 80 character line width template *************************/
 769       "5Displaying Breakpoints\n" //-NLOK
 770       " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\r\n\r\n"
 771       "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\r\n\r\n"
 772       " Locations with breakpoints of the specified type are displayed.\r\n\r\n"
 773       " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\r\n"
 774       " commands which may be subsequently used to establish the same\r\n"
 775       " breakpoint(s).\r\n\r\n"
 776       "5Removing Breakpoints\n" //-NLOK
 777       " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\r\n"
 778       "5Examples\n" //-NLOK
 779       " The following examples illustrate breakpoint usage:\r\n\r\n"
 780       "++BREAK                      set E break at current PC\r\n"
 781       "++BREAK -e 200               set E break at 200\r\n"
 782       "++BREAK 2000/2[2]            set E breaks at 2000,2001 with count = 2\r\n"
 783       "++BREAK 100;EX AC;D MQ 0     set E break at 100 with actions EX AC and\r\n"
 784       "+++++++++D MQ 0\r\n"
 785       "++BREAK 100;                 delete action on break at 100\r\n\r\n"
 786        /***************** 80 character line width template *************************/
 787       "2Connecting and Disconnecting Devices\n" //-NLOK
 788       " Units are simulated as files on the host file system.  Before using any\r\n"
 789       " simulated unit, the user must specify the file to be accessed by that unit.\r\n"
 790 #define HLP_ATTACH      "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
 791       "3Attaching devices\n" //-NLOK
 792       " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\r\n\r\n"
 793       "++ATTACH <unit> <filename>\r\n\r\n"
 794       " Some devices have more detailed or specific help available with:\r\n\r\n"
 795       "++HELP <device> ATTACH\r\n\r\n"
 796       "4Switches\n" //-NLOK
 797       "5`-n`\n" //-NLOK
 798       " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\r\n"
 799       " file will be created when the filename specified does not exist, or an\r\n"
 800       " existing file will have it's size truncated to zero, and an appropriate\r\n"
 801       " message is printed.\r\n"
 802       "5`-e`\n" //-NLOK
 803       " If the file does not exist, and the \"`-e`\" switch *was not* specified,\r\n"
 804       " a new file is created, and an appropriate message is printed.  If\r\n"
 805       " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\r\n"
 806       " error message is printed.\r\n"
 807       "5`-r`\n" //-NLOK
 808       " If the \"`-r`\" switch is specified, or the file is write protected by\r\n"
 809       " host operating system, `ATTACH` tries to open the file in read only mode.\r\n"
 810       " If the file does not exist, or the unit does not support read only\r\n"
 811       " operation, an error occurs.  Input-only devices, such as card readers, or\r\n"
 812       " storage devices with write locking switches, such as disks or tapes,\r\n"
 813       " support read only operation - other devices do not.  If a file is\r\n"
 814       " attached read only, its contents can be examined but not modified.\r\n"
 815       "5`-q`\n" //-NLOK
 816       " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\r\n"
 817       " or opening one read only (\"`-r`\"), the message announcing this fact\r\n"
 818       " is suppressed.\r\n"
 819       "5`-f`\n" //-NLOK
 820       " For simulated magnetic tapes, the `ATTACH` command can specify the format\r\n"
 821       " of the attached tape image file:\r\n\r\n"
 822       "++ATTACH -f <tape_unit> <format> <filename>\r\n\r\n"
 823       " * The currently supported magnetic tape image file formats are:\r\n\r\n"
 824       " |                  |                                                      |\r\n"
 825       " | ----------------:|:---------------------------------------------------- |\r\n"
 826       " | \"**`SIMH`**\"   | The **SIMH** / **DPS8M** native portable tape format |\r\n"
 827       " | \"**`E11`**\"    | The *D Bit* **Ersatz-11** simulator format           |\r\n"
 828       " | \"**`TPC`**\"    | The **TPC** format (*used by _SIMH_ prior to V2.3*)  |\r\n"
 829       " | \"**`P7B`**\"    | The **Paul Pierce** `7`-track tape archive format    |\r\n\r\n"
 830        /***************** 80 character line width template *************************/
 831       " * The default tape format can also be specified with the `SET` command\r\n"
 832       " prior to using the `ATTACH` command:\r\n\r\n"
 833       "++SET <tape_unit> FORMAT=<format>\r\n"
 834       "++ATTACH <tape_unit> <filename>\r\n\r\n"
 835       " * The format of a currently attached tape image can be displayed with\r\n"
 836       "   the `SHOW FORMAT` command:\r\n\r\n"
 837       "++SHOW <unit> FORMAT\r\n\r\n"
 838       " **Examples**\r\n\r\n"
 839       " The following example illustrates common `ATTACH` usage:\r\n"
 840       "++; Associate the tape image file \"12.8MULTICS.tap\" with the tape0 unit\r\n"
 841       "++; in read-only mode, where tape0 corresponds to the first tape device.\r\n"
 842       "++ATTACH -r tape0 12.8MULTICS.tap\r\n\r\n"
 843       "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\r\n"
 844       "++; The disk0 unit corresponds to the first disk device.\r\n"
 845       "++ATTACH disk0 root.dsk\r\n\r\n"
 846        /***************** 80 character line width template *************************/
 847 #define HLP_DETACH      "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
 848       "3Detaching devices\n" //-NLOK
 849       " The `DETACH` (*abbreviation* `DET`) command breaks the association between\r\n"
 850       " a unit and its backing file or device:\r\n\r\n"
 851       "++DETACH ALL             Detach all units\r\n"
 852       "++DETACH <unit>          Detach specified unit\r\n\r\n"
 853       " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\r\n"
 854 #define HLP_SET         "*Commands SET"
 855       "2SET\n" //-NLOK
 856        /***************** 80 character line width template *************************/
 857 #define HLP_SET_LOG    "*Commands SET Logging"
 858       "3Logging\n" //-NLOK
 859       " Interactions with the simulator session can be recorded to a log file.\r\n\r\n"
 860       "+SET LOG log_file            Specify the log destination\r\n"
 861       "++++++++                     (STDOUT, DEBUG, or filename)\r\n"
 862       "+SET NOLOG                   Disables any currently active logging\r\n"
 863       "4Switches\n" //-NLOK
 864       "5`-N`\n" //-NLOK
 865       " By default, log output is written at the *end* of the specified log file.\r\n"
 866       " A new log file can created if the \"`-N`\" switch is used on the command\r\n"
 867       " line.\r\n\r\n"
 868       "5`-B`\n" //-NLOK
 869       " By default, log output is written in *text* mode.  The log file can be\r\n"
 870       " opened for *binary* mode writing if the \"`-B`\" switch is used on the\r\n"
 871       " command line.\r\n"
 872 #define HLP_SET_DEBUG  "*Commands SET Debug_Messages"
 873        /***************** 80 character line width template *************************/
 874       "3Debug Messages\n" //-NLOK
 875       "+SET DEBUG debug_file        Specify the debug destination\r\n"
 876       "++++++++                     (STDOUT, STDERR, LOG, or filename)\r\n"
 877       "+SET NODEBUG                 Disables any currently active debug output\r\n"
 878       "4Switches\n" //-NLOK
 879       " Debug message output contains a timestamp which indicates the number of\r\n"
 880       " simulated instructions which have been executed prior to the debug event.\r\n\r\n"
 881       " Debug message output can be enhanced to contain additional, potentially\r\n"
 882       " useful information.\r\n\r\n\r\n"
 883       " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\r\n"
 884       "5`-T`\n" //-NLOK
 885       " The \"`-T`\" switch causes debug output to contain a time of day displayed\r\n"
 886       " as `hh:mm:ss.msec`.\r\n"
 887       "5`-A`\n" //-NLOK
 888       " The \"`-A`\" switch causes debug output to contain a time of day displayed\r\n"
 889       " as `seconds.msec`.\r\n"
 890       "5`-R`\n" //-NLOK
 891       " The \"`-R`\" switch causes timing to be relative to the start of debugging.\r\n"
 892       "5`-P`\n" //-NLOK
 893       " The \"`-P`\" switch adds the output of the PC (program counter) to each\r\n"
 894       " debug message.\r\n"
 895       "5`-N`\n" //-NLOK
 896       " The \"`-N`\" switch causes a new (empty) file to be written to.\r\n"
 897       " (The default is to append to an existing debug log file).\r\n"
 898       "5`-D`\n" //-NLOK
 899       " The \"`-D`\" switch causes data blob output to also display the data\r\n"
 900       " as **`RADIX-50`** characters.\r\n"
 901       "5`-E`\n" //-NLOK
 902       " The \"`-E`\" switch causes data blob output to also display the data\r\n"
 903       " as \"**EBCDIC**\" characters.\r\n"
 904        /***************** 80 character line width template *************************/
 905 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
 906       "3Environment Variables\n" //-NLOK
 907       "+SET ENVIRONMENT NAME=val    Set environment variable\r\n"
 908       "+SET ENVIRONMENT NAME        Clear environment variable\r\n"
 909 #define HLP_SET_ON      "*Commands SET Command_Status_Trap_Dispatching"
 910       "3Command Status Trap Dispatching\n" //-NLOK
 911       "+SET ON                      Enables error checking command execution\r\n"
 912       "+SET NOON                    Disables error checking command execution\r\n"
 913       "+SET ON INHERIT              Enables inheritance of ON state and actions\r\n"
 914       "+SET ON NOINHERIT            Disables inheritance of ON state and actions\r\n"
 915 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
 916       "3Command Execution Display\n" //-NLOK
 917       "+SET VERIFY                  Enables display of processed script commands\r\n"
 918       "+SET VERBOSE                 Enables display of processed script commands\r\n"
 919       "+SET NOVERIFY                Disables display of processed script commands\r\n"
 920       "+SET NOVERBOSE               Disables display of processed script commands\r\n"
 921 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
 922       "3Command Error Status Display\n" //-NLOK
 923       "+SET MESSAGE                 Re-enables display of script error messages\r\n"
 924       "+SET NOMESSAGE               Disables display of script error messages\r\n"
 925 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
 926       "3Command Output Display\n" //-NLOK
 927       "+SET QUIET                   Disables suppression of some messages\r\n"
 928       "+SET NOQUIET                 Re-enables suppression of some messages\r\n"
 929 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
 930       "3Local Operator Console\n" //-NLOK
 931       "+SET LOCALOPC                Enables local operator console\r\n"
 932       "+SET NOLOCALOPC              Disables local operator console\r\n"
 933 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
 934       "3Command Prompt\n" //-NLOK
 935       "+SET PROMPT \"string\"         Sets an alternate simulator prompt string\r\n"
 936       "3Device and Unit Settings\n" //-NLOK
 937       "+SET <dev> OCT|DEC|HEX       Set device display radix\r\n"
 938       "+SET <dev> ENABLED           Enable device\r\n"
 939       "+SET <dev> DISABLED          Disable device\r\n"
 940       "+SET <dev> DEBUG{=arg}       Set device debug flags\r\n"
 941       "+SET <dev> NODEBUG={arg}     Clear device debug flags\r\n"
 942       "+SET <dev> arg{,arg...}      Set device parameters\r\n"
 943       "+SET <unit> ENABLED          Enable unit\r\n"
 944       "+SET <unit> DISABLED         Disable unit\r\n"
 945       "+SET <unit> arg{,arg...}     Set unit parameters\r\n"
 946       "+HELP <dev> SET              Displays any device specific SET commands\r\n"
 947       " \r\n\r\n"
 948       " See the Omnibus documentation for a complete SET command reference.\r\n"
 949        /***************** 80 character line width template *************************/
 950 #define HLP_SHOW        "*Commands SHOW"
 951       "2SHOW\n" //-NLOK
 952       "+SH{OW} B{UILDINFO}               Show build-time compilation information\r\n"
 953       "+SH{OW} CL{OCKS}                  Show wall clock and timer information\r\n"
 954       "+SH{OW} C{ONFIGURATION}           Show simulator configuration\r\n"
 955       "+SH{OW} D{EFAULT_BASE_SYSTEM}     Show default base system script\r\n"
 956       "+SH{OW} DEV{ICES}                 Show devices\r\n"
 957       "+SH{OW} H{INTS}                   Show configuration hints\r\n"
 958       "+SH{OW} M{ODIFIERS}               Show SET commands for all devices\r\n"
 959       "+SH{OW} O{N}                      Show ON condition actions\r\n"
 960       "+SH{OW} P{ROM}                    Show CPU ID PROM initialization data\r\n"
 961       "+SH{OW} Q{UEUE}                   Show event queue\r\n"
 962       "+SH{OW} S{HOW}                    Show SHOW commands for all devices\r\n"
 963       "+SH{OW} T{IME}                    Show simulated timer\r\n"
 964       "+SH{OW} VE{RSION}                 Show simulator version\r\n"
 965       "+H{ELP} <dev> SHOW                Show device-specific SHOW commands\r\n"
 966       "+SH{OW} <dev> {arg,...}           Show device parameters\r\n"
 967       "+SH{OW} <dev> DEBUG               Show device debug flags\r\n"
 968       "+SH{OW} <dev> MODIFIERS           Show device modifiers\r\n"
 969       "+SH{OW} <dev> RADIX               Show device display radix\r\n"
 970       "+SH{OW} <dev> SHOW                Show device SHOW commands\r\n"
 971       "+SH{OW} <unit> {arg,...}          Show unit parameters\r\n\r\n"
 972       " See the Omnibus documentation for a complete SHOW command reference.\r\n\r\n"
 973 #define HLP_SHOW_CONFIG         "*Commands SHOW"
 974 #define HLP_SHOW_DEVICES        "*Commands SHOW"
 975 #define HLP_SHOW_FEATURES       "*Commands SHOW"
 976 #define HLP_SHOW_QUEUE          "*Commands SHOW"
 977 #define HLP_SHOW_TIME           "*Commands SHOW"
 978 #define HLP_SHOW_MODIFIERS      "*Commands SHOW"
 979 #define HLP_SHOW_NAMES          "*Commands SHOW"
 980 #define HLP_SHOW_SHOW           "*Commands SHOW"
 981 #define HLP_SHOW_VERSION        "*Commands SHOW"
 982 #define HLP_SHOW_BUILDINFO      "*Commands SHOW"
 983 #define HLP_SHOW_PROM           "*Commands SHOW"
 984 #define HLP_SHOW_HINTS          "*Commands SHOW"
 985 #define HLP_SHOW_DBS            "*Commands SHOW"
 986 #define HLP_SHOW_DEFAULT        "*Commands SHOW"
 987 #define HLP_SHOW_CONSOLE        "*Commands SHOW"
 988 #define HLP_SHOW_REMOTE         "*Commands SHOW"
 989 #define HLP_SHOW_BREAK          "*Commands SHOW"
 990 #define HLP_SHOW_LOG            "*Commands SHOW"
 991 #define HLP_SHOW_DEBUG          "*Commands SHOW"
 992 #define HLP_SHOW_CLOCKS         "*Commands SHOW"
 993 #define HLP_SHOW_ON             "*Commands SHOW"
 994 #define HLP_SHOW_SEND           "*Commands SHOW"
 995 #define HLP_SHOW_EXPECT         "*Commands SHOW"
 996 #define HLP_HELP                "*Commands HELP"
 997        /***************** 80 character line width template *************************/
 998       "2HELP\n" //-NLOK
 999       "+H{ELP}                      Show this message\r\n"
1000       "+H{ELP} <command>            Show help for command\r\n"
1001       "+H{ELP} <dev>                Show help for device\r\n"
1002       "+H{ELP} <dev> REGISTERS      Show help for device register variables\r\n"
1003       "+H{ELP} <dev> ATTACH         Show help for device specific ATTACH command\r\n"
1004       "+H{ELP} <dev> SET            Show help for device specific SET commands\r\n"
1005       "+H{ELP} <dev> SHOW           Show help for device specific SHOW commands\r\n"
1006       "+H{ELP} <dev> <command>      Show help for device specific <command> command\r\n"
1007        /***************** 80 character line width template *************************/
1008       "2Altering The Simulated Configuration\n" //-NLOK
1009       " The \"SET <device> DISABLED\" command removes a device from the configuration.\r\n"
1010       " A `DISABLED` device is invisible to running programs.  The device can still\r\n"
1011       " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\r\n\r\n"
1012       " The \"SET <device> ENABLED\" command restores a disabled device to a\r\n"
1013       " configuration.\r\n\r\n"
1014       " Most multi-unit devices allow units to be enabled or disabled:\r\n\r\n"
1015       "++SET <unit> ENABLED\r\n"
1016       "++SET <unit> DISABLED\r\n\r\n"
1017       " When a unit is disabled, it will not be displayed by SHOW DEVICE.\r\n\r\n"
1018        /***************** 80 character line width template *************************/
1019 #define HLP_DO          "*Commands Executing_Command_Files Processing_Command_Files"
1020       "2Executing Command Files\n" //-NLOK
1021       "3Processing Command Files\n" //-NLOK
1022       " The simulator can invoke another script file with the \"`DO`\" command:\r\n\r\n"
1023       "++DO <filename> {arguments...}       execute commands in specified file\r\n\r\n"
1024       " The \"`DO`\" command allows command files to contain substitutable\r\n"
1025       " arguments. The string \"`%%n`\", where \"`n`\" is a number\r\n"
1026       " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\r\n"
1027       " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\r\n"
1028       " The string \"`%%0`\" is replaced with \"<`filename`>\"\r\n"
1029       " The sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\r\n"
1030       " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\r\n"
1031       " be enclosed in matching single or double quotation marks.\r\n\r\n"
1032       " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\r\n"
1033       " deep.\r\n\r\n"
1034       "4Switches\n" //-NLOK
1035       "5`-v`\n\n" //-NLOK
1036       " If the switch \"`-v`\" is specified, commands in the command file are\r\n"
1037       " echoed *before* they are executed.\r\n\r\n"
1038       "5`-e`\n\n" //-NLOK
1039       " If the switch \"`-e`\" is specified, command processing (including nested\r\n"
1040       " command invocations) will be aborted if any command error is encountered.\r\n"
1041       " (A simulation stop **never** aborts processing; use `ASSERT` to catch\r\n"
1042       " unexpected stops.) Without this switch, all errors except `ASSERT` failures\r\n"
1043       " will be ignored, and command processing will continue.\r\n\r\n"
1044       "5`-o`\n\n" //-NLOK
1045       " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\r\n"
1046       " the calling command file will be inherited by the command file being\r\n"
1047       " invoked.\r\n"
1048       "5`-q`\n\n" //-NLOK
1049       " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\r\n"
1050       " enabled for the called command file, otherwise the *quiet mode* setting\r\n"
1051       " is inherited from the calling context.\r\n"
1052        /***************** 80 character line width template *************************/
1053 #define HLP_GOTO        "*Commands Executing_Command_Files GOTO"
1054       "3GOTO\n" //-NLOK
1055       " Commands in a command file execute in sequence until either an error\r\n"
1056       " trap occurs (when a command completes with an error status), or when an\r\n"
1057       " explicit request is made to start command execution elsewhere with\r\n"
1058       " the `GOTO` command:\r\n\r\n"
1059       "++GOTO <label>\r\n\r\n"
1060       " * Labels are lines in a command file which the first non-whitespace\r\n"
1061       " character is a \"`:`\".\r\n"
1062       " * The target of a `GOTO` is the first matching label in the current `DO`\r\n"
1063       " command file which is encountered.\r\n\r\n"
1064       " **Example**\r\n\r\n"
1065       " The following example illustrates usage of the `GOTO` command (by\r\n"
1066       " creating an infinite loop):\r\n\r\n"
1067       "++:Label\r\n"
1068       "++:: This is a loop.\r\n"
1069       "++GOTO Label\r\n\r\n"
1070 #define HLP_RETURN      "*Commands Executing_Command_Files RETURN"
1071        /***************** 80 character line width template *************************/
1072       "3RETURN\n" //-NLOK
1073       " The `RETURN` command causes the current procedure call to be restored to\r\n"
1074       " the calling context, possibly returning a specific return status.\r\n"
1075       " If no return status is specified, the return status from the last command\r\n"
1076       " executed will be returned.  The calling context may have `ON` traps defined\r\n"
1077       " which may redirect command flow in that context.\r\n\r\n"
1078       "++RETURN                 return from command file with last command status\r\n"
1079       "++RETURN {-Q} <status>   return from command file with specific status\r\n\r\n"
1080       " * The status return can be any numeric value or one of the standard SCPE_\r\n"
1081       " condition names.\r\n\r\n"
1082       " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\r\n"
1083       " status to be returned, but normal error status message printing to be\r\n"
1084       " suppressed.\r\n\r\n"
1085       " **Condition Names**\r\n\r\n"
1086       " The available standard SCPE_ condition names and their meanings are:\r\n\r\n"
1087       " | Name    | Meaning                         | Name    | Meaning                             |\r\n"
1088       " | ------- | --------------------------------| ------- | ----------------------------------- |\r\n"
1089       " | NXM     | Address space exceeded          | UNATT   | Unit not attached                   |\r\n"
1090       " | IOERR   | I/O error                       | CSUM    | Checksum error                      |\r\n"
1091       " | FMT     | Format error                    | NOATT   | Unit not attachable                 |\r\n"
1092       " | OPENERR | File open error                 | MEM     | Memory exhausted                    |\r\n"
1093       " | ARG     | Invalid argument                | STEP    | Step expired                        |\r\n"
1094       " | UNK     | Unknown command                 | RO      | Read only argument                  |\r\n"
1095       " | INCOMP  | Command not completed           | STOP    | Simulation stopped                  |\r\n"
1096       " | EXIT    | Goodbye                         | TTIERR  | Console input I/O error             |\r\n"
1097       " | TTOERR  | Console output I/O error        | EOF     | End of file                         |\r\n"
1098       " | REL     | Relocation error                | NOPARAM | No settable parameters              |\r\n"
1099       " | ALATT   | Unit already attached           | TIMER   | Hardware timer error                |\r\n"
1100       " | SIGERR  | Signal handler setup error      | TTYERR  | Console terminal setup error        |\r\n"
1101       " | NOFNC   | Command not allowed             | UDIS    | Unit disabled                       |\r\n"
1102       " | NORO    | Read only operation not allowed | INVSW   | Invalid switch                      |\r\n"
1103       " | MISVAL  | Missing value                   | 2FARG   | Too few arguments                   |\r\n"
1104       " | 2MARG   | Too many arguments              | NXDEV   | Non-existent device                 |\r\n"
1105       " | NXUN    | Non-existent unit               | NXREG   | Non-existent register               |\r\n"
1106       " | NXPAR   | Non-existent parameter          | NEST    | Nested DO command limit exceeded    |\r\n"
1107       " | IERR    | Internal error                  | MTRLNT  | Invalid magtape record length       |\r\n"
1108       " | LOST    | Console Telnet connection lost  | TTMO    | Console Telnet connection timed out |\r\n"
1109       " | STALL   | Console Telnet output stall     | AFAIL   | Assertion failed                    |\r\n"
1110       " | INVREM  | Invalid remote console command  |         |                                     |\r\n"
1111       "\r\n\r\n"
1112 #define HLP_SHIFT       "*Commands Executing_Command_Files Shift_Parameters"
1113       "3Shift Parameters\n" //-NLOK
1114       " Shift the command files positional parameters\r\n"
1115 #define HLP_CALL        "*Commands Executing_Command_Files Call_a_subroutine"
1116       "3Call a subroutine\n" //-NLOK
1117       " Control can be transferred to a labeled subroutine using `CALL`.\r\n\r\n"
1118       " **Example**\r\n\r\n"
1119       "++CALL routine\r\n"
1120       "++BYE\r\n"
1121       "++\r\n"
1122       "++:routine\r\n"
1123       "++ECHO routine called\r\n"
1124       "++RETURN\r\n\r\n"
1125 #define HLP_ON          "*Commands Executing_Command_Files ON"
1126       "3ON\n" //-NLOK
1127       " The `ON` command performs actions after a condition, or clears a condition.\r\n"
1128       "++ON <condition> <action>  Perform action after condition\r\n"
1129       "++ON <condition>           Clears action of specified condition\r\n"
1130 #define HLP_PROCEED     "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1131 #define HLP_IGNORE      "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1132        /***************** 80 character line width template *************************/
1133       "3PROCEED or IGNORE\n" //-NLOK
1134       " The `PROCEED` (or `IGNORE`) command does nothing.  It is potentially\r\n"
1135       " useful as a placeholder for any `ON` action condition that should be\r\n"
1136       " explicitly ignored, allowing command file execution to continue without\r\n"
1137       " taking any specific action.\r\n"
1138 #define HLP_ECHO        "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1139        /***************** 80 character line width template *************************/
1140       "3Displaying Arbitrary Text\n" //-NLOK
1141       " The `ECHO` command is a useful way of annotating command files.  `ECHO`\r\n"
1142       " prints out its arguments to the console (and to any applicable log file):\r\n\r\n"
1143       "++ECHO <string>      Output string to console\r\n\r\n"
1144       " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\r\n"
1145       " This may be used to provide spacing for console messages or log file\r\n"
1146       " output.\r\n"
1147        /***************** 80 character line width template *************************/
1148 #define HLP_ASSERT      "*Commands Executing_Command_Files Testing_Assertions"
1149       "3Testing Assertions\n" //-NLOK
1150       " The `ASSERT` command tests a simulator state condition and halts command\r\n"
1151       " file execution if the condition is false:\r\n\r\n"
1152       "++ASSERT <Simulator State Expressions>\r\n\r\n"
1153       " * If the indicated expression evaluates to false, the command completes\r\n"
1154       " with an `AFAIL` condition.  By default, when a command file encounters a\r\n"
1155       " command which returns the `AFAIL` condition, it will exit the running\r\n"
1156       " command file with the `AFAIL` status to the calling command file.  This\r\n"
1157       " behavior can be changed with the `ON` command as well as switches to the\r\n"
1158       " invoking `DO` command.\r\n\r\n"
1159       " **Examples**\r\n\r\n"
1160       " The command file below might be used to bootstrap a hypothetical system\r\n"
1161       " that halts after the initial load from disk. The `ASSERT` command can then\r\n"
1162       " be used to confirm that the load completed successfully by examining the\r\n"
1163       " CPU's \"`A`\" register for the expected value:`\r\n\r\n"
1164       "++; Example INI file\r\n"
1165       "++BOOT\r\n"
1166       "++; A register contains error code; 0 = good boot\r\n"
1167       "++ASSERT A=0\r\n"
1168       "++RUN\r\n\r\n"
1169        /***************** 80 character line width template *************************/
1170       " * In the above example, if the \"`A`\" register is *not* `0`,\r\n"
1171       " the \"`ASSERT A=0`\" command will be displayed to the user, and the\r\n"
1172       " command file will be aborted with an \"`Assertion failed`\" message.\r\n"
1173       " Otherwise, the command file will continue to bring up the system.\r\n\r\n"
1174       " * See the **`IF`** command documentation for more information and details\r\n"
1175       " regarding simulator state expressions.\r\n\r\n"
1176 #define HLP_IF          "*Commands Executing_Command_Files Testing_Conditions"
1177       "3Testing Conditions\n" //-NLOK
1178       " The `IF` command tests a simulator state condition and executes additional\r\n"
1179       " commands if the condition is true:\r\n\r\n"
1180       "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\r\n\r\n"
1181       " **Examples**\r\n\r\n"
1182       " The command file below might be used to bootstrap a hypothetical system\r\n"
1183       " that halts after the initial load from disk. The `IF` command can then\r\n"
1184       " be used to confirm that the load completed successfully by examining the\r\n"
1185       " CPU's \"`A`\" register for an expected value:\r\n\r\n"
1186       "++; Example INI file\r\n"
1187       "++BOOT\r\n"
1188       "++; A register contains error code; 0 = good boot\r\n"
1189       "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\r\n"
1190       "++RUN\r\n\r\n"
1191        /***************** 80 character line width template *************************/
1192       " * In the above example, if the \"`A`\" register is *not* `0`, the\r\n"
1193       " message \"`Boot failed - Failure Code `\" will be displayed, the contents\r\n"
1194       " of the \"`A`\" register will be displayed, and the command file will be\r\n"
1195       " aborted with an \"`Assertion failed`\" message.  Otherwise, the command\r\n"
1196       " file will continue to bring up the system.\r\n"
1197       "4Conditional Expressions\n" //-NLOK
1198       " The `IF` and `ASSERT` commands evaluate the following two different forms\r\n"
1199       " of conditional expressions.\r\n\r\n"
1200       "5Simulator State Expressions\n" //-NLOK
1201       "  &nbsp;\r\n \r\n"
1202       " The values of simulator registers can be evaluated with:\r\n\r\n"
1203       "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\r\n\r\n"
1204       " * If \"<`dev`>\" is not specified, `CPU` is assumed.  \"<`reg`>\" is a\r\n"
1205       " register belonging to the indicated device.\r\n"
1206       " * The \"<`addr`>\" is an address in the address space of the indicated\r\n"
1207       " device.\r\n"
1208       " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\r\n"
1209       " the same as those used for \"search specifiers\" by the `EXAMINE` and\r\n"
1210       " `DEPOSIT` commands.\r\n"
1211       " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\r\n"
1212       " not in the radix for the device when referencing a register; when an\r\n"
1213       " address is referenced the device radix is used as the default.\r\n\r\n"
1214       " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\r\n"
1215       " register value is first altered as indicated.  The result is then compared\r\n"
1216       " to the \"<`value`>\" via the \"<`conditional-op`>\".\r\n"
1217       " * * If the result is *true*, the command(s) are executed before proceeding\r\n"
1218       " to the next line in the command file.\r\n"
1219       " * * If the result is *false*, the next command in the command file is\r\n"
1220       " processed.\r\n\r\n"
1221       "5String Comparison Expressions\n" //-NLOK
1222       "  &nbsp;\r\n \r\n"
1223       " String Values can be compared with:\r\n\r\n"
1224       "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\r\n\r\n"
1225       " * The \"`-i`\" switch, if present, causes a comparison to be case\r\n"
1226       "   insensitive.\r\n"
1227       " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\r\n"
1228       "   values which may have environment variables substituted as desired.\r\n"
1229       " * The \"<`compare-op`>\" may be one of:\r\n\r\n"
1230       " |                |                        |\r\n"
1231       " | --------------:|:---------------------- |\r\n"
1232       " | \"**`==`**\"     |  equal                 |\r\n"
1233       " | \"**`EQU`**\"    |  equal                 |\r\n"
1234       " | \"**`!=`**\"     |  not equal             |\r\n"
1235       " | \"**`NEQ`**\"    |  not equal             |\r\n"
1236       " | \"**<**\"        |  less than             |\r\n"
1237       " | \"**`LSS`**\"    |  less than             |\r\n"
1238       " | \"**<=**\"       |  less than or equal    |\r\n"
1239       " | \"**`LEQ`**\"    |  less than or equal    |\r\n"
1240       " | \"**>**\"        |  greater than          |\r\n"
1241       " | \"**`GTR`**\"    |  greater than          |\r\n"
1242       " | \"**>=**\"       |  greater than or equal |\r\n"
1243       " | \"**`GEQ`**\"    |  greater than or equal |\r\n"
1244       " * **NOTE**: Comparisons are *generic*.  This means that if\r\n"
1245       " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\r\n"
1246       " digits, then the strings are converted to numbers and a numeric\r\n"
1247       " comparison is performed.  For example, the comparison\r\n"
1248       " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\r\n"
1249        /***************** 80 character line width template *************************/
1250 #define HLP_EXIT        "*Commands Exiting_the_Simulator"
1251       "2Exiting the Simulator\n" //-NLOK
1252       " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\r\n"
1253       " returning control to the host operating system.\r\n"
1254        /***************** 80 character line width template *************************/
1255 #define HLP_SPAWN       "*Commands Executing_System_Commands"
1256       "2Executing System Commands\n" //-NLOK
1257       " * The simulator can execute host operating system commands with\r\n"
1258       " the \"`!`\" (*spawn*) command.\r\n\r\n"
1259       " |                         |                                             |\r\n"
1260       " |:----------------------- |:------------------------------------------- |\r\n"
1261       " | \"**`!`**\"             | Spawn the hosts default command interpreter |\r\n"
1262       " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\r\n\r\n"
1263       " * **NOTE**: The *exit status* from the command which was executed is set\r\n"
1264       " as the *command completion status* for the \"`!`\" command.  This may\r\n"
1265       " influence any enabled `ON` condition traps.\r\n" ;
1266        /***************** 80 character line width template *************************/
1267 
1268 static CTAB cmd_table[] = {
1269     { "RESET",    &reset_cmd,  0,         HLP_RESET     },
1270     { "EXAMINE",  &exdep_cmd,  EX_E,      HLP_EXAMINE   },
1271     { "IEXAMINE", &exdep_cmd,  EX_E+EX_I, HLP_IEXAMINE  },
1272     { "DEPOSIT",  &exdep_cmd,  EX_D,      HLP_DEPOSIT   },
1273     { "IDEPOSIT", &exdep_cmd,  EX_D+EX_I, HLP_IDEPOSIT  },
1274     { "EVALUATE", &eval_cmd,   0,         HLP_EVALUATE  },
1275     { "RUN",      &run_cmd,    RU_RUN,    HLP_RUN,      NULL, &run_cmd_message },
1276     { "GO",       &run_cmd,    RU_GO,     HLP_GO,       NULL, &run_cmd_message },
1277     { "STEP",     &run_cmd,    RU_STEP,   HLP_STEP,     NULL, &run_cmd_message },
1278     { "NEXT",     &run_cmd,    RU_NEXT,   HLP_NEXT,     NULL, &run_cmd_message },
1279     { "CONTINUE", &run_cmd,    RU_CONT,   HLP_CONTINUE, NULL, &run_cmd_message },
1280     { "BOOT",     &run_cmd,    RU_BOOT,   HLP_BOOT,     NULL, &run_cmd_message },
1281     { "BREAK",    &brk_cmd,    SSH_ST,    HLP_BREAK     },
1282     { "NOBREAK",  &brk_cmd,    SSH_CL,    HLP_NOBREAK   },
1283     { "ATTACH",   &attach_cmd, 0,         HLP_ATTACH    },
1284     { "DETACH",   &detach_cmd, 0,         HLP_DETACH    },
1285     { "EXIT",     &exit_cmd,   0,         HLP_EXIT      },
1286     { "QUIT",     &exit_cmd,   0,         NULL          },
1287     { "BYE",      &exit_cmd,   0,         NULL          },
1288     { "SET",      &set_cmd,    0,         HLP_SET       },
1289     { "SHOW",     &show_cmd,   0,         HLP_SHOW      },
1290     { "DO",       &do_cmd,     1,         HLP_DO        },
1291     { "GOTO",     &goto_cmd,   1,         HLP_GOTO      },
1292     { "RETURN",   &return_cmd, 0,         HLP_RETURN    },
1293     { "SHIFT",    &shift_cmd,  0,         HLP_SHIFT     },
1294     { "CALL",     &call_cmd,   0,         HLP_CALL      },
1295     { "ON",       &on_cmd,     0,         HLP_ON        },
1296     { "IF",       &assert_cmd, 0,         HLP_IF        },
1297     { "PROCEED",  &noop_cmd,   0,         HLP_PROCEED   },
1298     { "IGNORE",   &noop_cmd,   0,         HLP_IGNORE    },
1299     { "ECHO",     &echo_cmd,   0,         HLP_ECHO      },
1300     { "ASSERT",   &assert_cmd, 1,         HLP_ASSERT    },
1301     { "SEND",     &send_cmd,   0          },            /* deprecated */
1302     { "EXPECT",   &expect_cmd, 1          },            /* deprecated */
1303     { "NOEXPECT", &expect_cmd, 0          },            /* deprecated */
1304     { "!",        &spawn_cmd,  0,         HLP_SPAWN     },
1305     { "HELP",     &help_cmd,   0,         HLP_HELP      },
1306     { NULL,       NULL,        0          }
1307     };
1308 
1309 static CTAB set_glob_tab[] = {
1310     { "CONSOLE",     &sim_set_console,        0      }, /* deprecated */
1311     { "REMOTE",      &sim_set_remote_console, 0      }, /* deprecated */
1312     { "BREAK",       &brk_cmd,                SSH_ST }, /* deprecated */
1313     { "NOBREAK",     &brk_cmd,                SSH_CL }, /* deprecated */
1314     { "TELNET",      &sim_set_telnet,         0      }, /* deprecated */
1315     { "NOTELNET",    &sim_set_notelnet,       0      }, /* deprecated */
1316     { "LOG",         &sim_set_logon,          0,     HLP_SET_LOG      },
1317     { "NOLOG",       &sim_set_logoff,         0,     HLP_SET_LOG      },
1318     { "DEBUG",       &sim_set_debon,          0,     HLP_SET_DEBUG    },
1319     { "NODEBUG",     &sim_set_deboff,         0,     HLP_SET_DEBUG    },
1320     { "ENVIRONMENT", &sim_set_environment,    1,     HLP_SET_ENVIRON  },
1321     { "ON",          &set_on,                 1,     HLP_SET_ON       },
1322     { "NOON",        &set_on,                 0,     HLP_SET_ON       },
1323     { "VERIFY",      &set_verify,             1,     HLP_SET_VERIFY   },
1324     { "VERBOSE",     &set_verify,             1,     HLP_SET_VERIFY   },
1325     { "NOVERIFY",    &set_verify,             0,     HLP_SET_VERIFY   },
1326     { "NOVERBOSE",   &set_verify,             0,     HLP_SET_VERIFY   },
1327     { "MESSAGE",     &set_message,            1,     HLP_SET_MESSAGE  },
1328     { "NOMESSAGE",   &set_message,            0,     HLP_SET_MESSAGE  },
1329     { "QUIET",       &set_quiet,              1,     HLP_SET_QUIET    },
1330     { "NOQUIET",     &set_quiet,              0,     HLP_SET_QUIET    },
1331     { "LOCALOPC",    &set_localopc,           1,     HLP_SET_LOCALOPC },
1332     { "NOLOCALOPC",  &set_localopc,           0,     HLP_SET_LOCALOPC },
1333     { "PROMPT",      &set_prompt,             0,     HLP_SET_PROMPT   },
1334     { NULL,          NULL,                    0      }
1335     };
1336 
1337 static C1TAB set_dev_tab[] = {
1338     { "OCTAL",    &set_dev_radix,   8  },
1339     { "DECIMAL",  &set_dev_radix,  10  },
1340     { "HEX",      &set_dev_radix,  16  },
1341     { "ENABLED",  &set_dev_enbdis,  1  },
1342     { "DISABLED", &set_dev_enbdis,  0  },
1343     { "DEBUG",    &set_dev_debug,   1  },
1344     { "NODEBUG",  &set_dev_debug,   0  },
1345     { NULL,       NULL,             0  }
1346     };
1347 
1348 static C1TAB set_unit_tab[] = {
1349     { "ENABLED",  &set_unit_enbdis, 1 },
1350     { "DISABLED", &set_unit_enbdis, 0 },
1351     { NULL,       NULL,             0 }
1352     };
1353 
1354 static SHTAB show_glob_tab[] = {
1355     { "CONFIGURATION",  &show_config,        0, HLP_SHOW_CONFIG    },
1356     { "DEFAULT_BASE_SYSTEM_SCRIPT",
1357            &show_default_base_system_script, 0, HLP_SHOW_DBS       },
1358     { "DEVICES",   &show_config,             1, HLP_SHOW_DEVICES   },
1359     { "FEATURES",  &show_config,             2, HLP_SHOW_FEATURES  },
1360     { "QUEUE",     &show_queue,              0, HLP_SHOW_QUEUE     },
1361     { "TIME",      &show_time,               0, HLP_SHOW_TIME      },
1362     { "MODIFIERS", &show_mod_names,          0, HLP_SHOW_MODIFIERS },
1363     { "NAMES",     &show_log_names,          0, HLP_SHOW_NAMES     },
1364     { "SHOW",      &show_show_commands,      0, HLP_SHOW_SHOW      },
1365     { "VERSION",   &show_version,            1, HLP_SHOW_VERSION   },
1366     { "BUILDINFO", &show_buildinfo,          1, HLP_SHOW_BUILDINFO },
1367     { "PROM",      &show_prom,               0, HLP_SHOW_PROM      },
1368     { "HINTS",     &show_hints,              0, HLP_SHOW_HINTS     },
1369     { "CONSOLE",   &sim_show_console,        0, HLP_SHOW_CONSOLE   },
1370     { "REMOTE",    &sim_show_remote_console, 0, HLP_SHOW_REMOTE    },
1371     { "BREAK",     &show_break,              0, HLP_SHOW_BREAK     },
1372     { "LOG",       &sim_show_log,            0, HLP_SHOW_LOG       },
1373     { "TELNET",    &sim_show_telnet,         0  },  /* deprecated */
1374     { "DEBUG",     &sim_show_debug,          0, HLP_SHOW_DEBUG     },
1375     { "CLOCKS",    &sim_show_timers,         0, HLP_SHOW_CLOCKS    },
1376     { "SEND",      &sim_show_send,           0, HLP_SHOW_SEND      },
1377     { "EXPECT",    &sim_show_expect,         0, HLP_SHOW_EXPECT    },
1378     { "ON",        &show_on,                 0, HLP_SHOW_ON        },
1379     { NULL,        NULL,                     0  }
1380     };
1381 
1382 static SHTAB show_dev_tab[] = {
1383     { "RADIX",     &show_dev_radix,         0 },
1384     { "DEBUG",     &show_dev_debug,         0 },
1385     { "MODIFIERS", &show_dev_modifiers,     0 },
1386     { "NAMES",     &show_dev_logicals,      0 },
1387     { "SHOW",      &show_dev_show_commands, 0 },
1388     { NULL,        NULL,                    0 }
1389     };
1390 
1391 static SHTAB show_unit_tab[] = {
1392     { NULL, NULL, 0 }
1393     };
1394 
1395 #if defined(_WIN32)
1396 static
1397 int setenv(const char *envname, const char *envval, int overwrite)
     /* [previous][next][first][last][top][bottom][index][help] */
1398 {
1399 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1400 int r;
1401 
1402 (void)sprintf(envstr, "%s=%s", envname, envval);
1403 r = _putenv(envstr);
1404 FREE(envstr);
1405 return r;
1406 }
1407 
1408 static
1409 int unsetenv(const char *envname)
     /* [previous][next][first][last][top][bottom][index][help] */
1410 {
1411 setenv(envname, "", 1);
1412 return 0;
1413 }
1414 #endif /* if defined(_WIN32) */
1415 
1416 #if !defined(NO_LOCALE)
1417 # define XSTR_EMAXLEN 32767
1418 
1419 const char
1420 *xstrerror_l(int errnum)
     /* [previous][next][first][last][top][bottom][index][help] */
1421 {
1422   int saved = errno;
1423   const char *ret = NULL;
1424   static __thread char buf[XSTR_EMAXLEN];
1425 
1426 # if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1427      defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1428 #  if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1429   if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1430 #  else
1431   if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1432 #  endif
1433 # else
1434 #  if defined(__NetBSD__)
1435   locale_t loc = LC_GLOBAL_LOCALE;
1436 #  else
1437   locale_t loc = uselocale((locale_t)0);
1438 #  endif
1439   locale_t copy = loc;
1440   if (copy == LC_GLOBAL_LOCALE)
1441     copy = duplocale(copy);
1442 
1443   if (copy != (locale_t)0)
1444     {
1445       ret = strerror_l(errnum, copy); /*LINTOK: xstrerror_l*/
1446       if (loc == LC_GLOBAL_LOCALE)
1447         {
1448           freelocale(copy);
1449         }
1450     }
1451 # endif
1452 
1453   if (!ret)
1454     {
1455       (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1456       ret = buf;
1457     }
1458 
1459   errno = saved;
1460   return ret;
1461 }
1462 #else
1463 # define xstrerror_l strerror
1464 #endif
1465 
1466 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1467 
1468 /* Substring removal hack */
1469 
1470 char *strremove(char *str, const char *sub)
     /* [previous][next][first][last][top][bottom][index][help] */
1471 {
1472     char *p, *q, *r;
1473     if (*sub && (q = r = strstr(str, sub)) != NULL) {
1474         size_t len = strlen(sub);
1475         while ((r = strstr(p = r + len, sub)) != NULL) {
1476             while (p < r)
1477                 *q++ = *p++;
1478         }
1479         while ((*q++ = *p++) != '\0')
1480             continue;
1481     }
1482     return str;
1483 }
1484 
1485 /* Trim whitespace */
1486 
1487 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
     /* [previous][next][first][last][top][bottom][index][help] */
1488 {
1489     while (*str_untrimmed != '\0') {
1490       if(!isspace((unsigned char)*str_untrimmed)) {
1491         *str_trimmed = (char)*str_untrimmed;
1492         str_trimmed++;
1493       }
1494       str_untrimmed++;
1495     }
1496     *str_trimmed = '\0';
1497 }
1498 
1499 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1500 void allowCores(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1501 {
1502   int ret;
1503   struct rlimit limit;
1504 # if defined(RLIMIT_CORE)
1505   ret = getrlimit(RLIMIT_CORE, &limit);
1506   (void)ret;
1507 #  if defined(TESTING)
1508   if (ret != 0)
1509     {
1510       sim_warn ("Failed to query core dump configuration.");
1511       return;
1512     }
1513 #  endif /* if defined(TESTING) */
1514   limit.rlim_cur = limit.rlim_max;
1515   ret = setrlimit(RLIMIT_CORE, &limit);
1516 #  if defined(TESTING)
1517   if (ret != 0)
1518     {
1519       sim_warn ("Failed to enable unlimited core dumps.");
1520       return;
1521     }
1522 #  endif /* if defined(TESTING) */
1523 # else
1524 #  if defined(TESTING)
1525   sim_warn ("Unable to query core dump configuration.");
1526 #  endif /* if defined(TESTING) */
1527 # endif /* if defined(RLIMIT_CORE) */
1528   return;
1529 }
1530 #endif
1531 
1532 #if defined(USE_DUMA)
1533 void CleanDUMA(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1534 {
1535   (void)fflush(stdout);
1536   DUMA_CHECKALL();
1537   (void)fflush(stderr);
1538 }
1539 # undef USE_DUMA
1540 # define USE_DUMA 1
1541 #endif /* if defined(USE_DUMA) */
1542 
1543 #if !defined(SIG_SETMASK)
1544 # undef USE_BACKTRACE
1545 #endif /* if !defined(SIG_SETMASK) */
1546 
1547 #if defined(PERF_STRIP)
1548 # undef USE_BACKTRACE
1549 #endif /* if defined(PERF_STRIP) */
1550 
1551 #if defined(USE_BACKTRACE)
1552 # include <backtrace.h>
1553 # include <backtrace-supported.h>
1554 # define BACKTRACE_SKIP 1
1555 # define BACKTRACE_MAIN "main"
1556 # undef USE_BACKTRACE
1557 # define USE_BACKTRACE 1
1558 #endif /* if defined(USE_BACKTRACE) */
1559 
1560 #if defined(BACKTRACE_SUPPORTED)
1561 # if defined(BACKTRACE_SUPPORTS_THREADS)
1562 #  if !(BACKTRACE_SUPPORTED)
1563 #   undef USE_BACKTRACE
1564 #  endif /* if !(BACKTRACE_SUPPORTED) */
1565 # else  /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1566 #  undef USE_BACKTRACE
1567 # endif /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1568 #else  /* if defined(BACKTRACE_SUPPORTED) */
1569 # undef USE_BACKTRACE
1570 #endif /* if defined(BACKTRACE_SUPPORTED) */
1571 
1572 #if defined(USE_BACKTRACE)
1573 # if defined(BACKTRACE_SUPPORTED)
1574 #  include "backtrace_func.c"
1575 # endif /* if defined(BACKTRACE_SUPPORTED) */
1576 #endif /* if defined(USE_BACKTRACE) */
1577 
1578 #if !defined(__CYGWIN__)
1579 # if !defined(__APPLE__)
1580 #  if !defined(_AIX)
1581 #   if !defined(__MINGW32__)
1582 #    if !defined(__MINGW64__)
1583 #     if !defined(CROSS_MINGW32)
1584 #      if !defined(CROSS_MINGW64)
1585 #       if !defined(_WIN32)
1586 #        if !defined(__HAIKU__)
1587 #         if !defined(__QNX__)
1588 static int
1589 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1590 {
1591   (void)size;
1592   (void)data;
1593 
1594   if (strlen(info->dlpi_name) >= 2) {
1595       if (!dl_iterate_phdr_callback_called)
1596           (void)printf ("\r\n Loaded shared objects: ");
1597 
1598       dl_iterate_phdr_callback_called++;
1599       (void)printf ("%s ", info->dlpi_name);
1600   }
1601 
1602   return 0;
1603 }
1604 #         endif
1605 #        endif
1606 #       endif
1607 #      endif
1608 #     endif
1609 #    endif
1610 #   endif
1611 #  endif
1612 # endif
1613 #endif
1614 
1615 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1616 # if defined(_UCRT)
1617 #  define MINGW_CRT "UCRT"
1618 # else
1619 #  define MINGW_CRT "MSVCRT"
1620 # endif
1621 #endif
1622 
1623 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1624 struct UCRTVersion
1625 {
1626   uint16_t ProductVersion[4];
1627 };
1628 
1629 int
1630 GetUCRTVersion (struct UCRTVersion *ucrtversion)
     /* [previous][next][first][last][top][bottom][index][help] */
1631 {
1632 # ifdef _DEBUG
1633   static const wchar_t *DllName = L"ucrtbased.dll";
1634 # else
1635   static const wchar_t *DllName = L"ucrtbase.dll";
1636 # endif
1637 
1638   HMODULE ucrt = GetModuleHandleW (DllName);
1639   if (!ucrt)
1640     return GetLastError ();
1641 
1642   wchar_t path[SIR_MAXPATH];
1643   if (!GetModuleFileNameW (ucrt, path, SIR_MAXPATH))
1644     return GetLastError ();
1645 
1646   DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1647   if (!versionInfoSize)
1648     return GetLastError ();
1649 
1650   uint8_t versionInfo[versionInfoSize];
1651 
1652   if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1653     return GetLastError ();
1654 
1655   VS_FIXEDFILEINFO *fixedFileInfo;
1656   UINT fixedFileInfoSize;
1657   if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1658     return GetLastError ();
1659 
1660   memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1661 
1662   return 0;
1663 }
1664 #endif
1665 
1666 /* libsir support */
1667 
1668 #if !defined(PERF_STRIP)
1669 static int dps8_sir_report_error(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1670 {
1671   char message[SIR_MAXERROR] = {0};
1672   (void)sir_geterror(message);
1673   (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1674   return EXIT_FAILURE;
1675 }
1676 
1677 /* Main command loop */
1678 
1679 int main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
1680 {
1681 char *cptr, *cptr2;
1682 char nbuf[PATH_MAX + 7];
1683 char cbuf[4*CBUFSIZE];
1684 char **targv = NULL;
1685 int32 i, sw;
1686 t_bool lookswitch;
1687 t_stat stat;
1688 
1689 /* Check for improper setuid root */
1690 # if !defined(__sun) && !defined(__illumos__) && !defined(_WIN32)
1691 uid_t real_uid = getuid();
1692 uid_t eff_uid = geteuid();
1693 if (0 == eff_uid && 0 != real_uid) {
1694   (void)fprintf(stderr, "FATAL: Running with improper setuid root privileges!\r\n");
1695   exit(EXIT_FAILURE);
1696 }
1697 # endif
1698 
1699 sunos_obtain_realtime_privileges(); /* Keep as early as possible */
1700 
1701 sim_free_memory = sim_memory_available(); /* stash free memory */
1702 
1703 sim_appfilename = _sir_getappfilename(); /* stash app filename */
1704 if (sim_appfilename == NULL) {
1705   sim_appfilename = "dps8";
1706 }
1707 
1708 /* libsir init */
1709 
1710 sirinit si;
1711 if (!sir_makeinit(&si))
1712     return dps8_sir_report_error();
1713 
1714 /* Levels for stdout: send debug, information, warning, and notice there. */
1715 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1716 
1717 /* Options for stdout: don't show the name, level, timestamp, hostname, or PID. */
1718 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1719 
1720 /* Levels for stderr: send error and above there. */
1721 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1722 
1723 /* Options for stderr: don't show the hostname. */
1724 si.d_stderr.opts = SIRO_NOHOST;
1725 
1726 /* Levels for the system logger: don't send any output there. */
1727 si.d_syslog.levels = SIRL_NONE;
1728 
1729 /* Options for the system logger: use the default value. */
1730 si.d_syslog.opts = SIRO_DEFAULT;
1731 
1732 /* Configure a name to associate with our output. */
1733 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1734 
1735 /* Initialize libsir. */
1736 if (!sir_init(&si))
1737     return dps8_sir_report_error();
1738 
1739 # if defined(_AIX)
1740 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1741   if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1742     (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1743                   __func__, __FILE__, __LINE__);
1744     abort();
1745   }
1746 
1747   if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1748     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1749   }
1750 
1751   if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1752     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1753   }
1754 
1755   if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1756     (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1757   }
1758 
1759 #  if !defined(__PASE__)
1760   if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1761     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1762   }
1763 #  else
1764 #   if !defined(TESTING)
1765   if (setenv("PASE_SYSCALL_NOSIGILL", "ALL", 1)) {
1766     (void)fprintf(stderr, "\rWARN: Failed to set \"PASE_SYSCALL_NOSIGILL=ALL\".\r\n");
1767   }
1768 #   endif
1769 #  endif
1770 
1771   if (execvp(argv[0], argv) == -1) {
1772     (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1773                   __func__, __FILE__, __LINE__);
1774     abort();
1775   }
1776 }
1777 # endif
1778 
1779 # if defined(USE_BACKTRACE)
1780 #  if defined(BACKTRACE_SUPPORTED)
1781 #   if defined(_INC_BACKTRACE_FUNC)
1782 bt_pid = (long)_sir_getpid();
1783 (void)bt_pid;
1784 #   endif /* if defined(_INC_BACKTRACE_FUNC) */
1785 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1786 # endif /* if defined(USE_BACKTRACE) */
1787 
1788 # if defined(__MINGW32__)
1789 #  undef IS_WINDOWS
1790 #  define IS_WINDOWS 1
1791 #  if !defined(NEED_CONSOLE_SETUP)
1792 #   define NEED_CONSOLE_SETUP
1793 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1794 # endif /* if defined(__MINGW32__)*/
1795 
1796 # if defined(CROSS_MINGW32)
1797 #  undef IS_WINDOWS
1798 #  define IS_WINDOWS 1
1799 #  if !defined(NEED_CONSOLE_SETUP)
1800 #   define NEED_CONSOLE_SETUP
1801 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1802 # endif /* if defined(CROSS_MINGW32) */
1803 
1804 # if defined(__MINGW64__)
1805 #  undef IS_WINDOWS
1806 #  define IS_WINDOWS 1
1807 #  if !defined(NEED_CONSOLE_SETUP)
1808 #   define NEED_CONSOLE_SETUP
1809 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1810 # endif /* if defined(__MINGW64__) */
1811 
1812 # if defined(CROSS_MINGW64)
1813 #  undef IS_WINDOWS
1814 #  define IS_WINDOWS 1
1815 #  if !defined(NEED_CONSOLE_SETUP)
1816 #   define NEED_CONSOLE_SETUP
1817 #  endif /* if !defined(NEED_CONSOLE_SETUP */
1818 # endif /* if defined(CROSS_MINGW64) */
1819 
1820 # if defined(__CYGWIN__)
1821 #  if defined(IS_WINDOWS)
1822 #   undef IS_WINDOWS
1823 #  endif /* if defined(IS_WINDOWS) */
1824 # endif /* if defined(__CYGWIN__) */
1825 
1826 # if defined(USE_DUMA)
1827 #  if defined(DUMA_EXPLICIT_INIT)
1828 duma_init();
1829 (void)fflush(stderr);
1830 #  endif /* if defined(DUMA_EXPLICIT_INIT) */
1831 #  if defined(DUMA_MIN_ALIGNMENT)
1832 #   if DUMA_MIN_ALIGNMENT > 0
1833 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1834 #   endif /* if DUMA_MIN_ALIGNMENT > 0 */
1835 #  endif /* if defined(DUMA_MIN_ALIGNMENT) */
1836 DUMA_SET_FILL(0x2E);
1837 (void)fflush(stderr);
1838 (void)atexit(CleanDUMA);
1839 # endif /* if defined(USE_DUMA) */
1840 
1841 # if defined(USE_BACKTRACE)
1842 #  if defined(BACKTRACE_SUPPORTED)
1843 #   include "backtrace_main.c"
1844 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1845 # endif /* if defined(USE_BACKTRACE) */
1846 
1847 # if !defined(NO_LOCALE)
1848 (void)setlocale(LC_ALL, "");
1849 # endif
1850 
1851 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1852 #  if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1853 #   define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1854 #  endif /* if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) */
1855 # endif /* if defined(NEED_CONSOLE_SETUP) && defined(_WIN32) */
1856 
1857 # if defined(NEED_CONSOLE_SETUP)
1858 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1859 if (handle != INVALID_HANDLE_VALUE)
1860   {
1861     DWORD mode = 0;
1862     if (GetConsoleMode(handle, &mode))
1863       {
1864         mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1865         SetConsoleMode(handle, mode);
1866       }
1867   }
1868 puts ("\e[0m");
1869 # endif /* if defined(NEED_CONSOLE_SETUP) */
1870 
1871 # if defined(__HAIKU__)
1872 (void)disable_debugger(1);
1873 # endif /* if defined(__HAIKU__) */
1874 
1875 running_perf_test = false;
1876 
1877 /* Set a friendly name for the current thread. */
1878 char thread_name[SIR_MAXPID] = {0};
1879 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1880 (void)_sir_setthreadname(thread_name);
1881 
1882 /* sanity checks */
1883 
1884 # if defined(__clang_analyzer__)
1885 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\r\n");
1886 return 1;
1887 # endif /* if defined(__clang_analyzer__) */
1888 
1889 if (argc == 0) {
1890     (void)fprintf (stderr, "Error: main() called directly!\r\n");
1891     return 1;
1892 }
1893 
1894 /* Enable unlimited core dumps */
1895 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1896 allowCores();
1897 # endif
1898 
1899 int testEndian = decContextTestEndian();
1900 if (testEndian != 0) {
1901   if (testEndian == 1) {
1902     (void)fprintf (stderr,
1903                    "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\r\n");
1904     return 1;
1905   }
1906   if (testEndian == -1) {
1907     (void)fprintf (stderr,
1908                    "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\r\n");
1909     return 1;
1910   }
1911   (void)fprintf (stderr,
1912                  "Error: Unable to determine system byte order; aborting.\r\n");
1913   return 1;
1914 }
1915 # if defined(NEED_128)
1916 test_math128();
1917 # endif /* if defined(NEED_128) */
1918 
1919 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1920 
1921 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1922 // Only use uv_available_parallelism on Linux and only on libuv 1.44.0 or higher.
1923 // This will return a value less than the actual number of CPUs if, for example,
1924 // the CPU affinity mask has been pinned to specific CPUs.  On all other systems,
1925 // prefer the _sir_nprocs routine to query the number of actual CPUs available.
1926 nprocs = (unsigned int)uv_available_parallelism();
1927 # else
1928 nprocs = (unsigned int)_sir_nprocs();
1929 # endif
1930 ncores = (unsigned int)get_core_count();
1931 
1932 /* Make sure that argv has at least 10 elements and that it ends in a NULL pointer */
1933 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1934 if (!targv)
1935   {
1936     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1937                    __func__, __FILE__, __LINE__);
1938 # if defined(USE_BACKTRACE)
1939 #  if defined(SIGUSR2)
1940     (void)raise(SIGUSR2);
1941     /*NOTREACHED*/ /* unreachable */
1942 #  endif /* if defined(SIGUSR2) */
1943 # endif /* if defined(USE_BACKTRACE) */
1944     abort();
1945   }
1946 for (i=0; i<argc; i++)
1947     targv[i] = argv[i];
1948 argv = targv;
1949 
1950 /* setup defaults */
1951 set_prompt (0, "sim>");                                 /* start with set standard prompt */
1952 *cbuf = 0;                                              /* init arg buffer */
1953 sim_switches = 0;                                       /* init switches */
1954 lookswitch = TRUE;
1955 stdnul = fopen(NULL_DEVICE,"wb");
1956 
1957 /* process arguments */
1958 for (i = 1; i < argc; i++) {                            /* loop thru args */
1959     if (argv[i] == NULL)                                /* paranoia */
1960         continue;
1961 
1962 # if defined(THREADZ) || defined(LOCKLESS)
1963 /* performance test */
1964     int perftestflag  = strcmp(argv[i], "--perftest");
1965     if (perftestflag == 0) {
1966       char * testName = NULL;
1967       if (i + 1 < argc)
1968         testName = argv[i + 1];
1969       perfTest (testName);
1970       return 0;
1971     }
1972 # endif
1973 
1974 /* requested only version? */
1975     int onlyvers  = strcmp(argv[i], "--version");
1976     if (onlyvers == 0) {
1977 # if defined(VER_H_GIT_VERSION)
1978 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1979 #   if VER_H_GIT_PATCH_INT < 1
1980         (void)fprintf (stdout, "%s simulator %s\r\n",
1981                        sim_name, VER_H_GIT_VERSION);
1982 #   else
1983         (void)fprintf (stdout, "%s simulator %s+%s\r\n",
1984                        sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1985 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
1986 #  else
1987         (void)fprintf (stdout, "%s simulator %s\r\n",
1988                        sim_name, VER_H_GIT_VERSION);
1989 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
1990 # else
1991         (void)fprintf (stdout, "%s simulator\r\n", sim_name);
1992 # endif /* if defined(VER_H_GIT_VERSION) */
1993         FREE (targv);
1994         return 0;
1995     }
1996 
1997 /* requested short or long help? */
1998     int longhelp  = strcmp(argv[i], "--help");
1999     int shorthelp = strcmp(argv[i], "-h");
2000     if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
2001     if (longhelp == 0 || shorthelp == 0) {
2002 # if defined(VER_H_GIT_VERSION)
2003 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
2004 #   if VER_H_GIT_PATCH_INT < 1
2005         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2006 #   else
2007         (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
2008 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
2009 #  else
2010         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
2011 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
2012 # else
2013         (void)fprintf (stdout, "%s simulator", sim_name);
2014 # endif /* if defined(VER_H_GIT_VERSION) */
2015         (void)fprintf (stdout, "\r\n");
2016         (void)fprintf (stdout, "\r\n USAGE: %s [ [ SWITCH ] ... ] [ SCRIPT ]", argv[0]);
2017         (void)fprintf (stdout, "\r\n");
2018         (void)fprintf (stdout, "\r\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
2019         (void)fprintf (stdout, "\r\n");
2020         (void)fprintf (stdout, "\r\n Switches:");
2021         (void)fprintf (stdout, "\r\n  -e, -E            Aborts script processing immediately upon any error");
2022         (void)fprintf (stdout, "\r\n  -h, -H, --help    Prints only this informational help text and exits");
2023         (void)fprintf (stdout, "\r\n  -k, -K            Disables all support for exclusive file locking");
2024         (void)fprintf (stdout, "\r\n  -l, -L            Reports but ignores all exclusive file locking errors");
2025         (void)fprintf (stdout, "\r\n  -o, -O            Makes scripting ON conditions and actions inheritable");
2026 # if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2027         (void)fprintf (stdout, "\r\n  -p, -P            Enables real-time scheduling (may require privileges)");
2028 # endif
2029         (void)fprintf (stdout, "\r\n  -q, -Q            Disables printing of non-fatal informational messages");
2030         (void)fprintf (stdout, "\r\n  -r, -R            Enables an unlinked ephemeral system state file");
2031         (void)fprintf (stdout, "\r\n  -s, -S            Enables a randomized persistent system state file");
2032         (void)fprintf (stdout, "\r\n  -t, -T            Disables fsync and creation/usage of system state file");
2033         (void)fprintf (stdout, "\r\n  -v, -V            Prints commands read from script file before execution");
2034         (void)fprintf (stdout, "\r\n  --version         Prints only the simulator identification text and exits");
2035         (void)fprintf (stdout, "\r\n");
2036 # if defined(USE_DUMA)
2037         nodist++;
2038 # endif /* if defined(USE_DUMA) */
2039 if (!nodist) {
2040         (void)fprintf (stdout, "\r\n This software is made available under the terms of the ICU License.");
2041         (void)fprintf (stdout, "\r\n For complete license details, see the LICENSE file included with the");
2042         (void)fprintf (stdout, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\r\n");
2043 }
2044 else
2045 {
2046         (void)fprintf (stdout, "\r\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2047 }
2048         (void)fprintf (stdout, "\r\n");
2049         FREE(argv); //-V726
2050         return 0;
2051     }
2052     /* invalid arguments? */
2053     if ((*argv[i] == '-') && lookswitch) {              /* switch? */
2054         if ((sw = get_switches (argv[i])) < 0) {
2055             (void)fprintf (stderr, "Invalid switch \"%s\".\r\nTry \"%s -h\" for help.\r\n", argv[i], argv[0]);
2056             FREE(argv); //-V726
2057             return 1;
2058             }
2059         sim_switches = sim_switches | sw;
2060         }
2061     /* parse arguments */
2062     else {
2063         if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2064             (void)fprintf (stderr, "Argument string too long\r\n");
2065             FREE(argv); //-V726
2066             return 1;
2067             }
2068         if (*cbuf)                                  /* concat args */
2069             strcat (cbuf, " ");
2070         (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s", //-V755
2071                       strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : ""); //-V755
2072         lookswitch = FALSE;                         /* no more switches */
2073         }
2074     }                                               /* end for */
2075 sim_nolock = sim_switches & SWMASK ('K');           /* -k means skip locking     */
2076 sim_iglock = sim_switches & SWMASK ('L');           /* -l means ignore locking   */
2077 sim_randompst = sim_switches & SWMASK ('S');        /* -s means persist random   */
2078 sim_quiet = sim_switches & SWMASK ('Q');            /* -q means quiet            */
2079 sim_randstate = sim_switches & SWMASK ('R');        /* -r means random sys_state */
2080 if (sim_randompst) sim_randstate = 1;               /*    and is implied with -s */
2081 sim_nostate = sim_switches & SWMASK ('T');          /* -t means no sys_state     */
2082 if (sim_nostate)                                    /*    and disables -s and -r */
2083   {
2084     sim_randompst = 0;
2085     sim_randstate = 0;
2086   }
2087 sim_on_inherit = sim_switches & SWMASK ('O');       /* -o means inherit on state */
2088 
2089 # if !defined(__MVS__) && !defined(__MINGW32__) && !defined(__MINGW64__) && \
2090      !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) && !defined(__CYGWIN__)
2091 sim_realtime = sim_switches & SWMASK ('P');         /* -p means real-time priority */
2092 # endif
2093 
2094 sim_init_sock ();                                   /* init socket capabilities */
2095 if (sim_dflt_dev == NULL)                           /* if no default */
2096     sim_dflt_dev = sim_devices[0];
2097 if (sim_vm_init != NULL)                            /* call once only */
2098     (*sim_vm_init)();
2099 sim_finit ();                                       /* init fio package */
2100 for (i = 0; cmd_table[i].name; i++) {
2101     size_t alias_len = strlen (cmd_table[i].name);
2102     char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2103     if (!cmd_name)
2104       {
2105         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2106                        __func__, __FILE__, __LINE__);
2107 # if defined(USE_BACKTRACE)
2108 #  if defined(SIGUSR2)
2109         (void)raise(SIGUSR2);
2110         /*NOTREACHED*/ /* unreachable */
2111 #  endif /* if defined(SIGUSR2) */
2112 # endif /* if defined(USE_BACKTRACE) */
2113         abort();
2114       }
2115 
2116     strcpy (cmd_name, cmd_table[i].name);
2117     while (alias_len > 1) {
2118         cmd_name[alias_len] = '\0';                 /* Possible short form command name */
2119         --alias_len;
2120         if (getenv (cmd_name))                      /* Externally defined command alias? */
2121             unsetenv (cmd_name);                    /* Remove it to protect against possibly malicious aliases */
2122         }
2123     FREE (cmd_name);
2124     }
2125 stop_cpu = 0;
2126 sim_interval = 0;
2127 sim_time = sim_rtime = 0;
2128 noqueue_time = 0;
2129 sim_clock_queue = QUEUE_LIST_END;
2130 sim_is_running = 0;
2131 sim_log = NULL;
2132 if (sim_emax <= 0)
2133     sim_emax = 1;
2134 
2135 /* stash our pthread_id */
2136 main_thread_id = pthread_self();
2137 
2138 /* stash current (default) thread scheduler and priority */
2139 save_thread_sched(pthread_self());
2140 
2141 /* real-time priority (always call before sim_timer_init) */
2142 if (sim_realtime) {
2143     if (nprocs < 2) {
2144         sir_emerg("FATAL: Real-time requires >1 CPU but only %u detected!", nprocs);
2145         exit(EXIT_FAILURE);
2146     } else {
2147         watchdog_startup();
2148     }
2149 }
2150 
2151 /* do setup for realtime or normal operation */
2152 if (realtime_ok) {
2153     set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2154     check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2155 } else {
2156 # if !defined(__QNX__)
2157     (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2158 # endif
2159 }
2160 
2161 sim_timer_init ();
2162 
2163 if ((stat = sim_ttinit ()) != SCPE_OK) {
2164     (void)fprintf (stderr, "Fatal terminal initialization error\r\n%s\r\n",
2165                    sim_error_text (stat));
2166     FREE(argv); //-V726
2167     return 1;
2168     }
2169 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2170     (void)fprintf (stderr, "Unable to allocate examine buffer\r\n");
2171     FREE(argv); //-V726
2172     return 1;
2173     };
2174 if ((stat = reset_all_p (0)) != SCPE_OK) {
2175     (void)fprintf (stderr, "Fatal simulator initialization error\r\n%s\r\n",
2176                    sim_error_text (stat));
2177     FREE(argv); //-V726
2178     return 1;
2179     }
2180 if ((stat = sim_brk_init ()) != SCPE_OK) {
2181     (void)fprintf (stderr, "Fatal breakpoint table initialization error\r\n%s\r\n",
2182                    sim_error_text (stat));
2183     FREE(argv); //-V726
2184     return 1;
2185     }
2186 if (!sim_quiet) {
2187     (void)printf ("\r\n");
2188     show_version (stdout, NULL, NULL, 0, NULL);
2189     }
2190 
2191 cptr = getenv("HOME");
2192 if (cptr == NULL) {
2193     cptr = getenv("HOMEPATH");
2194     cptr2 = getenv("HOMEDRIVE");
2195     }
2196 else
2197     cptr2 = NULL;
2198 (void)cptr2;
2199 if ( (*cbuf) && (strcmp(cbuf, "")) )                    /* cmd file arg? */
2200     stat = do_cmd (0, cbuf);                            /* proc cmd file */
2201 else if (*argv[0]) {                                    /* sim name arg? */
2202     char *np;                                           /* "path.ini" */
2203     nbuf[0] = '"';                                      /* starting " */
2204     stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;         /* proc default cmd file */
2205     if (stat == SCPE_OPENERR) {                         /* didn't exist/can't open? */
2206         np = strrchr (nbuf, '/');                       /* strip path and try again in cwd */
2207         if (np == NULL)
2208             np = strrchr (nbuf, '\\');                  /* windows path separator */
2209         if (np != NULL) {
2210             *np = '"';
2211             stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;   /* proc default cmd file */
2212             }
2213         }
2214     }
2215 
2216 argv = uv_setup_args(argc, argv);
2217 
2218 /* show if hints are not disabled and empty cbuf and not quiet mode */
2219 if (getenv("DPS8M_NO_HINTS") == NULL)
2220   if (!sim_quiet && 0 == strcmp(cbuf, ""))
2221     (void)show_hints(0, 0, 0, 1, 0);
2222 
2223 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2224 
2225 if (sim_vm_exit != NULL)                                /* call once only */
2226     (*sim_vm_exit)();
2227 
2228 detach_all (0, TRUE);                                   /* close files */
2229 sim_set_deboff (0, NULL);                               /* close debug */
2230 sim_set_logoff (0, NULL);                               /* close log */
2231 sim_set_notelnet (0, NULL);                             /* close Telnet */
2232 sim_ttclose ();                                         /* close console */
2233 sim_cleanup_sock ();                                    /* cleanup sockets */
2234 fclose (stdnul);                                        /* close bit bucket file handle */
2235 FREE (targv);                                           /* release any argv copy that was made */
2236 FREE (sim_prompt);
2237 FREE (sim_eval);
2238 FREE (sim_internal_devices);
2239 FREE (sim_brk_tab);
2240 FREE (sim_staba.comp);
2241 FREE (sim_staba.mask);
2242 FREE (sim_stabr.comp);
2243 FREE (sim_stabr.mask);
2244 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2245 }
2246 #endif
2247 
2248 t_stat process_stdin_commands (t_stat stat, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
2249 {
2250 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2251 CONST char *cptr;
2252 t_stat stat_nomessage;
2253 CTAB *cmdp = NULL;
2254 
2255 stat = SCPE_BARE_STATUS(stat);                          /* remove possible flag */
2256 while (stat != SCPE_EXIT) {                             /* in case exit */
2257     if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))   /* pending action? */
2258         (void)printf ("%s%s\r\n", sim_prompt, cptr);    /* echo */
2259     else if (sim_vm_read != NULL) {                     /* sim routine? */
2260         (void)printf ("%s", sim_prompt);                /* prompt */
2261         cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2262         }
2263     else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prompt*/
2264     if (cptr == NULL) {                                 /* EOF? */
2265         if (sim_ttisatty()) continue;                   /* ignore tty EOF */
2266         else break;                                     /* otherwise exit */
2267         }
2268     if (*cptr == 0)                                     /* ignore blank */
2269         continue;
2270     sim_sub_args (cbuf, sizeof(cbuf), argv);
2271     if (sim_log)                                        /* log cmd */
2272         (void)fprintf (sim_log, "%s%s\r\n", sim_prompt, cptr);
2273     if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2274         (void)fprintf (sim_deb, "%s%s\r\n", sim_prompt, cptr);
2275     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
2276     sim_switches = 0;                                   /* init switches */
2277     if ((cmdp = find_cmd (gbuf)))                       /* lookup command */
2278         stat = cmdp->action (cmdp->arg, cptr);          /* if found, exec */
2279     else
2280         stat = SCPE_UNK;
2281     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
2282     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
2283     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
2284     sim_last_cmd_stat = stat;                           /* save command error status */
2285     if (!stat_nomessage) {                              /* displaying message status? */
2286         if (cmdp && (cmdp->message))                    /* special message handler? */
2287             cmdp->message (NULL, stat);                 /* let it deal with display */
2288         else
2289             if (stat >= SCPE_BASE)                      /* error? */
2290                 sim_printf ("%s\r\n", sim_error_text (stat));
2291         }
2292     if (sim_vm_post != NULL)
2293         (*sim_vm_post) (TRUE);
2294     }                                                   /* end while */
2295 return stat;
2296 }
2297 
2298 /* Set prompt routine */
2299 
2300 t_stat set_prompt (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2301 {
2302 char gbuf[CBUFSIZE], *gptr;
2303 
2304 if ((NULL == cptr) || (*cptr == '\0'))
2305     return SCPE_ARG;
2306 
2307 cptr = get_glyph_nc (cptr, gbuf, '"');                  /* get quote delimited token */
2308 if (gbuf[0] == '\0') {                                  /* Token started with quote */
2309     gbuf[sizeof (gbuf)-1] = '\0';
2310     strncpy (gbuf, cptr, sizeof (gbuf)-1);
2311     gptr = strchr (gbuf, '"');
2312     if (NULL != gptr)
2313         *gptr = '\0';
2314     }
2315 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);   /* nul terminator and trailing blank */
2316 if (!sim_prompt)
2317   {
2318     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2319                    __func__, __FILE__, __LINE__);
2320 #if defined(USE_BACKTRACE)
2321 # if defined(SIGUSR2)
2322     (void)raise(SIGUSR2);
2323     /*NOTREACHED*/ /* unreachable */
2324 # endif /* if defined(SIGUSR2) */
2325 #endif /* if defined(USE_BACKTRACE) */
2326     abort();
2327   }
2328 (void)sprintf (sim_prompt, "%s ", gbuf);
2329 return SCPE_OK;
2330 }
2331 
2332 /* Find command routine */
2333 
2334 CTAB *find_cmd (const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
2335 {
2336 CTAB *cmdp = NULL;
2337 
2338 if (sim_vm_cmd)                                         /* try ext commands */
2339     cmdp = find_ctab (sim_vm_cmd, gbuf);
2340 if (cmdp == NULL)                                       /* try regular cmds */
2341     cmdp = find_ctab (cmd_table, gbuf);
2342 return cmdp;
2343 }
2344 
2345 /* Exit command */
2346 
2347 t_stat exit_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2348 {
2349 return SCPE_EXIT;
2350 }
2351 
2352 /* Help command */
2353 
2354 /* Used when sorting a list of command names */
2355 static int _cmd_name_compare (const void *pa, const void *pb)
     /* [previous][next][first][last][top][bottom][index][help] */
2356 {
2357 CTAB * const *a = (CTAB * const *)pa;
2358 CTAB * const *b = (CTAB * const *)pb;
2359 
2360 return strcmp((*a)->name, (*b)->name);
2361 }
2362 
2363 void fprint_help (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
2364 {
2365 CTAB *cmdp;
2366 CTAB **hlp_cmdp = NULL;
2367 size_t cmd_cnt = 0;
2368 size_t cmd_size = 0;
2369 size_t max_cmdname_size = 0;
2370 size_t i, line_offset;
2371 
2372 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2373     if (cmdp->help) {
2374         if (cmd_cnt >= cmd_size) {
2375             cmd_size += 20;
2376             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2377             if (!hlp_cmdp)
2378               {
2379                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2380                                __func__, __FILE__, __LINE__);
2381 #if defined(USE_BACKTRACE)
2382 # if defined(SIGUSR2)
2383                 (void)raise(SIGUSR2);
2384                 /*NOTREACHED*/ /* unreachable */
2385 # endif /* if defined(SIGUSR2) */
2386 #endif /* if defined(USE_BACKTRACE) */
2387                 abort();
2388               }
2389             }
2390         hlp_cmdp[cmd_cnt] = cmdp;
2391         ++cmd_cnt;
2392         if (strlen(cmdp->name) > max_cmdname_size)
2393             max_cmdname_size = strlen(cmdp->name);
2394         }
2395     }
2396 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2397     if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2398         if (cmd_cnt >= cmd_size) {
2399             cmd_size += 20;
2400             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2401             if (!hlp_cmdp)
2402               {
2403                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2404                                __func__, __FILE__, __LINE__);
2405 #if defined(USE_BACKTRACE)
2406 # if defined(SIGUSR2)
2407                 (void)raise(SIGUSR2);
2408                 /*NOTREACHED*/ /* unreachable */
2409 # endif /* if defined(SIGUSR2) */
2410 #endif /* if defined(USE_BACKTRACE) */
2411                 abort();
2412               }
2413             }
2414         hlp_cmdp[cmd_cnt] = cmdp;
2415         ++cmd_cnt;
2416         if (strlen (cmdp->name) > max_cmdname_size)
2417             max_cmdname_size = strlen(cmdp->name);
2418         }
2419     }
2420 (void)fprintf (st, "HELP is available for the following commands:\r\n\r\n    ");
2421 if (hlp_cmdp)
2422   qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2423 line_offset = 4;
2424 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2425     fputs (hlp_cmdp[i]->name, st);
2426     line_offset += 5 + max_cmdname_size;
2427     if (line_offset + max_cmdname_size > 79) {
2428         line_offset = 4;
2429         (void)fprintf (st, "\r\n    ");
2430         }
2431     else
2432         (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2433     }
2434 FREE (hlp_cmdp);
2435 (void)fprintf (st, "\r\n");
2436 return;
2437 }
2438 
2439 static void fprint_header (FILE *st, t_bool *pdone, char *context)
     /* [previous][next][first][last][top][bottom][index][help] */
2440 {
2441 if (!*pdone)
2442     (void)fprintf (st, "%s", context);
2443 *pdone = TRUE;
2444 }
2445 
2446 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2447 {
2448 REG *rptr, *trptr;
2449 t_bool found = FALSE;
2450 t_bool all_unique = TRUE;
2451 size_t max_namelen = 0;
2452 DEVICE *tdptr;
2453 CONST char *tptr;
2454 char *namebuf;
2455 char rangebuf[32];
2456 
2457 if (dptr->registers)
2458     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2459         if (rptr->flags & REG_HIDDEN)
2460             continue;
2461         if (rptr->depth > 1)
2462             (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2463         else
2464             strcpy (rangebuf, "");
2465         if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2466             max_namelen = strlen(rptr->name) + strlen (rangebuf);
2467         found = TRUE;
2468         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2469         if ((trptr == NULL) || (tdptr != dptr))
2470             all_unique = FALSE;
2471         }
2472 if (!found) {
2473     if (!silent)
2474         (void)fprintf (st, "No register HELP available for the %s device\r\n",
2475                        dptr->name);
2476     }
2477 else {
2478     namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2479     if (!namebuf)
2480       {
2481         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2482                        __func__, __FILE__, __LINE__);
2483 #if defined(USE_BACKTRACE)
2484 # if defined(SIGUSR2)
2485         (void)raise(SIGUSR2);
2486         /*NOTREACHED*/ /* unreachable */
2487 # endif /* if defined(SIGUSR2) */
2488 #endif /* if defined(USE_BACKTRACE) */
2489         abort();
2490       }
2491     (void)fprintf (st, "\r\nThe %s device implements these registers:\r\n\r\n",
2492                    dptr->name);
2493     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2494         if (rptr->flags & REG_HIDDEN)
2495             continue;
2496         if (rptr->depth <= 1)
2497             (void)sprintf (namebuf, "%*s",
2498                            -((int)max_namelen),
2499                            rptr->name);
2500         else {
2501             (void)sprintf (rangebuf, "[%d:%d]",
2502                            0,
2503                            rptr->depth-1);
2504             (void)sprintf (namebuf, "%s%*s",
2505                            rptr->name,
2506                            (int)(strlen(rptr->name))-((int)max_namelen),
2507                            rangebuf);
2508             }
2509         if (all_unique) {
2510             (void)fprintf (st, "  %s %4d  %s\r\n",
2511                            namebuf,
2512                            rptr->width,
2513                            rptr->desc ? rptr->desc : "");
2514             continue;
2515             }
2516         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2517         if ((trptr == NULL) || (tdptr != dptr))
2518             (void)fprintf (st, "  %s %s %4d  %s\r\n",
2519                            dptr->name,
2520                            namebuf,
2521                            rptr->width,
2522                            rptr->desc ? rptr->desc : "");
2523         else
2524             (void)fprintf (st, "  %*s %s %4d  %s\r\n",
2525                            (int)strlen(dptr->name), "",
2526                            namebuf,
2527                            rptr->width,
2528                            rptr->desc ? rptr->desc : "");
2529         }
2530     FREE (namebuf);
2531     }
2532 }
2533 
2534 void fprint_reg_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2535 {
2536 fprint_reg_help_ex (st, dptr, TRUE);
2537 }
2538 
2539 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2540 {
2541 if (dptr->attach_help) {
2542     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2543     dptr->attach_help (st, dptr, NULL, 0, NULL);
2544     return;
2545     }
2546 if (DEV_TYPE(dptr) == DEV_DISK) {
2547     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2548     sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2549     return;
2550     }
2551 if (DEV_TYPE(dptr) == DEV_TAPE) {
2552     (void)fprintf (st, "\r\n%s device ATTACH commands:\r\n\r\n", dptr->name);
2553     sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2554     return;
2555     }
2556 if (!silent) {
2557     (void)fprintf (st, "No ATTACH help is available for the %s device\r\n", dptr->name);
2558     if (dptr->help)
2559         dptr->help (st, dptr, NULL, 0, NULL);
2560     }
2561 }
2562 
2563 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2564 {
2565 MTAB *mptr;
2566 DEBTAB *dep;
2567 t_bool found = FALSE;
2568 char buf[CBUFSIZE], header[CBUFSIZE];
2569 uint32 enabled_units = dptr->numunits;
2570 uint32 unit;
2571 
2572 (void)sprintf (header, "\r\n%s device SET commands:\r\n\r\n", dptr->name);
2573 for (unit=0; unit < dptr->numunits; unit++)
2574     if (dptr->units[unit].flags & UNIT_DIS)
2575         --enabled_units;
2576 if (dptr->modifiers) {
2577     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2578         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2579             continue;                                       /* skip unit only extended modifiers */
2580         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2581             continue;                                       /* skip unit only simple modifiers */
2582         if (mptr->mstring) {
2583             fprint_header (st, &found, header);
2584             (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2585                            mptr->mstring,
2586                            (strchr(mptr->mstring, '=')) \
2587                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2588                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2589                                ? "{=val}" : "")));
2590             if ((strlen (buf) < 30) || (NULL == mptr->help))
2591                 (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2592             else
2593                 (void)fprintf (st, "%s\r\n%-30s\t%s\r\n", buf, "", mptr->help);
2594             }
2595         }
2596     }
2597 if (dptr->flags & DEV_DISABLE) {
2598     fprint_header (st, &found, header);
2599     (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2600     (void)fprintf (st,  "%-30s\tEnables device %s\r\n", buf, sim_dname (dptr));
2601     (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2602     (void)fprintf (st,  "%-30s\tDisables device %s\r\n", buf, sim_dname (dptr));
2603     }
2604 if (dptr->flags & DEV_DEBUG) {
2605     fprint_header (st, &found, header);
2606     (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2607     (void)fprintf (st,  "%-30s\tEnables debugging for device %s\r\n", buf, sim_dname (dptr));
2608     (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2609     (void)fprintf (st,  "%-30s\tDisables debugging for device %s\r\n", buf, sim_dname (dptr));
2610     if (dptr->debflags) {
2611         t_bool desc_available = FALSE;
2612         strcpy (buf, "");
2613         (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2614         for (dep = dptr->debflags; dep->name != NULL; dep++) {
2615             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2616             desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2617             }
2618         (void)fprintf (st, "\r\n");
2619         (void)fprintf (st,  "%-30s\tEnables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2620         (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2621         for (dep = dptr->debflags; dep->name != NULL; dep++)
2622             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2623         (void)fprintf (st, "\r\n");
2624         (void)fprintf (st,  "%-30s\tDisables specific debugging for device %s\r\n", buf, sim_dname (dptr));
2625         if (desc_available) {
2626             (void)fprintf (st, "\r\n*%s device DEBUG settings:\r\n", sim_dname (dptr));
2627             for (dep = dptr->debflags; dep->name != NULL; dep++)
2628                 (void)fprintf (st, "%4s%-12s%s\r\n", "", dep->name, dep->desc ? dep->desc : "");
2629             }
2630         }
2631     }
2632 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2633     if (dptr->units->flags & UNIT_DISABLE) {
2634         fprint_header (st, &found, header);
2635         (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2636         (void)fprintf (st,  "%-30s\tEnables unit %sn\r\n", buf, sim_dname (dptr));
2637         (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2638         (void)fprintf (st,  "%-30s\tDisables unit %sn\r\n", buf, sim_dname (dptr));
2639         }
2640     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2641         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2642             continue;                                           /* skip device only modifiers */
2643         if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2644             continue;                                           /* skip show only modifiers */
2645         if (mptr->mstring) {
2646             fprint_header (st, &found, header);
2647             (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2648                            (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2649                            (strchr(mptr->mstring, '=')) \
2650                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2651                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2652                                ? "{=val}" : "")));
2653             (void)fprintf (st, "%-30s\t%s\r\n", buf,
2654                            (strchr(mptr->mstring, '=')) \
2655                                ? "" : (mptr->help ? mptr->help : ""));
2656             }
2657         }
2658     }
2659 if (!found && !silent)
2660     (void)fprintf (st, "No SET help is available for the %s device\r\n", dptr->name);
2661 }
2662 
2663 void fprint_set_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2664 {
2665   fprint_set_help_ex (st, dptr, TRUE);
2666 }
2667 
2668 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2669 {
2670 MTAB *mptr;
2671 t_bool found = FALSE;
2672 char buf[CBUFSIZE], header[CBUFSIZE];
2673 uint32 enabled_units = dptr->numunits;
2674 uint32 unit;
2675 
2676 (void)sprintf (header, "\r\n%s device SHOW commands:\r\n\r\n", dptr->name);
2677 for (unit=0; unit < dptr->numunits; unit++)
2678     if (dptr->units[unit].flags & UNIT_DIS)
2679         --enabled_units;
2680 if (dptr->modifiers) {
2681     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2682         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2683             continue;                                       /* skip unit only extended modifiers */
2684         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2685             continue;                                       /* skip unit only simple modifiers */
2686         if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2687             continue;
2688         fprint_header (st, &found, header);
2689         (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2690                        mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2691         (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2692         }
2693     }
2694 if (dptr->flags & DEV_DEBUG) {
2695     fprint_header (st, &found, header);
2696     (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2697     (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\r\n", buf, sim_dname (dptr));
2698     }
2699 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2700     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2701         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2702             continue;                                           /* skip device only modifiers */
2703         if ((!mptr->disp) || (!mptr->pstring))
2704             continue;
2705         fprint_header (st, &found, header);
2706         (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2707                        (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2708                        MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2709         (void)fprintf (st, "%-30s\t%s\r\n", buf, mptr->help ? mptr->help : "");
2710         }
2711     }
2712 if (!found && !silent)
2713     (void)fprintf (st, "No SHOW help is available for the %s device\r\n", dptr->name);
2714 }
2715 
2716 void fprint_show_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2717     {
2718     fprint_show_help_ex (st, dptr, TRUE);
2719     }
2720 
2721 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2722 {
2723 BRKTYPTAB *brkt = dptr->brk_types;
2724 char gbuf[CBUFSIZE];
2725 
2726 if (sim_brk_types == 0) {
2727     if ((dptr != sim_dflt_dev) && (!silent)) {
2728         (void)fprintf (st, "Breakpoints are not supported in the %s simulator\r\n", sim_name);
2729         if (dptr->help)
2730             dptr->help (st, dptr, NULL, 0, NULL);
2731         }
2732     return;
2733     }
2734 if (brkt == NULL) {
2735     int i;
2736 
2737     if (dptr == sim_dflt_dev) {
2738         if (sim_brk_types & ~sim_brk_dflt) {
2739             (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2740             for (i=0; i<26; i++) {
2741                 if (sim_brk_types & (1<<i))
2742                     (void)fprintf (st, "  -%c\r\n", 'A'+i);
2743                 }
2744             }
2745         (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2746         }
2747     return;
2748     }
2749 (void)fprintf (st, "%s supports the following breakpoint types:\r\n", sim_dname (dptr));
2750 while (brkt->btyp) {
2751     (void)fprintf (st, "  %s     %s\r\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2752     ++brkt;
2753     }
2754 (void)fprintf (st, "The default breakpoint type is: %s\r\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2755 }
2756 
2757 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2758 {
2759 char gbuf[CBUFSIZE];
2760 CTAB *cmdp;
2761 
2762 if (*cptr) {
2763     (void)get_glyph (cptr, gbuf, 0);
2764     if ((cmdp = find_cmd (gbuf))) {
2765         if (cmdp->action == &exdep_cmd) {
2766             if (dptr->help) /* Shouldn't this pass cptr so the device knows which command invoked? */
2767                 return dptr->help (st, dptr, uptr, flag, cptr);
2768             else
2769                 (void)fprintf (st, "No HELP available for the %s %s command\r\n", cmdp->name, sim_dname(dptr));
2770             return SCPE_OK;
2771             }
2772         if (cmdp->action == &set_cmd) {
2773             fprint_set_help_ex (st, dptr, FALSE);
2774             return SCPE_OK;
2775             }
2776         if (cmdp->action == &show_cmd) {
2777             fprint_show_help_ex (st, dptr, FALSE);
2778             return SCPE_OK;
2779             }
2780         if (cmdp->action == &attach_cmd) {
2781             fprint_attach_help_ex (st, dptr, FALSE);
2782             return SCPE_OK;
2783             }
2784         if (cmdp->action == &brk_cmd) {
2785             fprint_brk_help_ex (st, dptr, FALSE);
2786             return SCPE_OK;
2787             }
2788         if (dptr->help)
2789             return dptr->help (st, dptr, uptr, flag, cptr);
2790         (void)fprintf (st, "No %s HELP is available for the %s device\r\n", cmdp->name, dptr->name);
2791         return SCPE_OK;
2792         }
2793     if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2794         fprint_reg_help_ex (st, dptr, FALSE);
2795         return SCPE_OK;
2796         }
2797     if (dptr->help)
2798         return dptr->help (st, dptr, uptr, flag, cptr);
2799     (void)fprintf (st, "No %s HELP is available for the %s device\r\n", gbuf, dptr->name);
2800     return SCPE_OK;
2801     }
2802 if (dptr->help) {
2803     return dptr->help (st, dptr, uptr, flag, cptr);
2804     }
2805 if (dptr->description)
2806     (void)fprintf (st, "%s %s HELP\r\n", dptr->description (dptr), dptr->name);
2807 else
2808     (void)fprintf (st, "%s HELP\r\n", dptr->name);
2809 fprint_set_help_ex    (st, dptr, TRUE);
2810 fprint_show_help_ex   (st, dptr, TRUE);
2811 fprint_attach_help_ex (st, dptr, TRUE);
2812 fprint_reg_help_ex    (st, dptr, TRUE);
2813 fprint_brk_help_ex    (st, dptr, TRUE);
2814 return SCPE_OK;
2815 }
2816 
2817 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
     /* [previous][next][first][last][top][bottom][index][help] */
2818 {
2819 switch (help[0]) {
2820     case '*':
2821         scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2822         if (sim_log)
2823             scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2824         break;
2825     default:
2826         fputs (help, stdout);
2827         if (sim_log)
2828             fputs (help, sim_log);
2829         break;
2830     }
2831 return SCPE_OK;
2832 }
2833 
2834 t_stat help_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2835 {
2836 char gbuf[CBUFSIZE];
2837 CTAB *cmdp;
2838 
2839 GET_SWITCHES (cptr);
2840 if (sim_switches & SWMASK ('F'))
2841     flag = flag | SCP_HELP_FLAT;
2842 if (*cptr) {
2843     cptr = get_glyph (cptr, gbuf, 0);
2844     if ((cmdp = find_cmd (gbuf))) {
2845         if (*cptr) {
2846             if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2847                 DEVICE *dptr;
2848                 UNIT *uptr;
2849                 t_stat r;
2850                 cptr = get_glyph (cptr, gbuf, 0);
2851                 dptr = find_unit (gbuf, &uptr);
2852                 if (dptr == NULL)
2853                     dptr = find_dev (gbuf);
2854                 if (dptr != NULL) {
2855                     r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2856                     if (sim_log)
2857                         help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2858                     return r;
2859                     }
2860                 if (cmdp->action == &set_cmd) { /* HELP SET xxx (not device or unit) */
2861                     /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
2862                     if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2863                          (cmdp->help))
2864                         return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2865                     }
2866                 else { /* HELP SHOW xxx (not device or unit) */
2867                     SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2868                     if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2869                         return SCPE_ARG;
2870                     return help_cmd_output (flag, shptr->help, NULL);
2871                     }
2872                 return SCPE_ARG;
2873                 }
2874             else
2875                 return SCPE_2MARG;
2876             }
2877         if (cmdp->help) {
2878             if (strcmp (cmdp->name, "HELP") == 0) {
2879 
2880 
2881 
2882 
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             else {
2915                 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2916                     sim_dflt_dev && sim_dflt_dev->help) {
2917                         sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2918                         if (sim_log)
2919                             sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2920                     }
2921                 }
2922             help_cmd_output (flag, cmdp->help, cmdp->help_base);
2923             }
2924         else { /* no help so it is likely a command alias */
2925             CTAB *cmdpa;
2926             for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2927                 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2928                     sim_printf ("%s is an alias for the %s command:\r\n%s",
2929                                 cmdp->name, cmdpa->name, cmdpa->help);
2930                     break;
2931                     }
2932             if (cmdpa->name == NULL)                /* not found? */
2933                 sim_printf ("No help available for the %s command\r\n", cmdp->name);
2934             }
2935         }
2936     else {
2937         DEVICE *dptr;
2938         UNIT *uptr;
2939         t_stat r;
2940         dptr = find_unit (gbuf, &uptr);
2941         if (dptr == NULL) {
2942             dptr = find_dev (gbuf);
2943             if (dptr == NULL)
2944                 return SCPE_ARG;
2945             if (dptr->flags & DEV_DIS)
2946                 sim_printf ("Device %s is currently disabled\r\n", dptr->name);
2947             }
2948         r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2949         if (sim_log)
2950             help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2951         return r;
2952         }
2953     }
2954 else {
2955     fprint_help (stdout);
2956     if (sim_log)
2957         fprint_help (sim_log);
2958     }
2959 return SCPE_OK;
2960 }
2961 
2962 /* Spawn command */
2963 
2964 t_stat spawn_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2965 {
2966 t_stat status;
2967 if ((cptr == NULL) || (strlen (cptr) == 0))
2968     cptr = getenv("SHELL");
2969 if ((cptr == NULL) || (strlen (cptr) == 0))
2970     cptr = getenv("ComSpec");
2971 (void)fflush(stdout);                                   /* flush stdout */
2972 if (sim_log)                                            /* flush log if enabled */
2973     (void)fflush (sim_log);
2974 if (sim_deb)                                            /* flush debug if enabled */
2975     (void)fflush (sim_deb);
2976 status = system (cptr);
2977 
2978 return status;
2979 }
2980 
2981 /* Echo command */
2982 
2983 t_stat echo_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2984 {
2985 sim_printf ("%s\r\n", cptr);
2986 return SCPE_OK;
2987 }
2988 
2989 /*
2990  * DO command
2991  *
2992  * Note that SCPE_STEP ("Step expired") is considered a note and
2993  * not an error; it does not abort command execution when using -E.
2994  *
2995  * Inputs:
2996  *      flag    =   caller and nesting level indicator
2997  *      fcptr   =   filename and optional arguments, space-separated
2998  * Outputs:
2999  *      status  =   error status
3000  *
3001  * The "flag" input value indicates the source of the call, as follows:
3002  *
3003  *      -1      =   initialization file (no error if not found)
3004  *       0      =   command line file
3005  *       1      =   "DO" command
3006  *      >1      =   nested "DO" command
3007  */
3008 
3009 t_stat do_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3010 {
3011 return do_cmd_label (flag, fcptr, NULL);
3012 }
3013 
3014 static char *do_position(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3015 {
3016 static char cbuf[4*CBUFSIZE];
3017 
3018 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
3019                 sim_do_label[sim_do_depth] ? "::" : "",
3020                 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
3021                 sim_goto_line[sim_do_depth]);
3022 return cbuf;
3023 }
3024 
3025 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
     /* [previous][next][first][last][top][bottom][index][help] */
3026 {
3027 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
3028 CONST char *cptr;
3029 FILE *fpin;
3030 CTAB *cmdp = NULL;
3031 int32 echo, nargs, errabort, i;
3032 int32 saved_sim_do_echo = sim_do_echo,
3033       saved_sim_show_message = sim_show_message,
3034       saved_sim_on_inherit = sim_on_inherit,
3035       saved_sim_quiet = sim_quiet;
3036 t_bool staying;
3037 t_stat stat, stat_nomessage;
3038 
3039 stat = SCPE_OK;
3040 staying = TRUE;
3041 if (flag > 0)                                           /* need switches? */
3042     GET_SWITCHES (fcptr);                               /* get switches */
3043 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;    /* -v means echo */
3044 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet; /* -q means quiet */
3045 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit; /* -o means inherit ON condition actions */
3046 errabort = sim_switches & SWMASK ('E');                 /* -e means abort on error */
3047 
3048 abuf[sizeof(abuf)-1] = '\0';
3049 strncpy (abuf, fcptr, sizeof(abuf)-1);
3050 c = abuf;
3051 do_arg[10] = NULL;                                      /* make sure the argument list always ends with a NULL */
3052 for (nargs = 0; nargs < 10; ) {                         /* extract arguments */
3053     while (sim_isspace (*c))                            /* skip blanks */
3054         c++;
3055     if (*c == 0)                                        /* all done? */
3056         do_arg [nargs++] = NULL;                        /* null argument */
3057     else {
3058         if (*c == '\'' || *c == '"')                    /* quoted string? */
3059             quote = *c++;
3060         else quote = 0;
3061         do_arg[nargs++] = c;                            /* save start */
3062         while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
3063             c++;
3064         if (*c)                                         /* term at quote/spc */
3065             *c++ = 0;
3066         }
3067     }                                                   /* end for */
3068 
3069 if (do_arg [0] == NULL)                                 /* need at least 1 */
3070     return SCPE_2FARG;
3071 if ((fpin = fopen (do_arg[0], "r")) == NULL) {          /* file failed to open? */
3072     strcat (strcpy (cbuf, do_arg[0]), ".ini");          /* try again with .ini extension */
3073     if ((fpin = fopen (cbuf, "r")) == NULL) {           /* failed a second time? */
3074         if (flag == 0)                                  /* cmd line file? */
3075              (void)fprintf (stderr, "Can't open file %s\r\n", do_arg[0]);
3076         return SCPE_OPENERR;                            /* return failure */
3077         }
3078     }
3079 if (flag >= 0) {                                        /* Only bump nesting from command or nested */
3080     ++sim_do_depth;
3081     if (sim_on_inherit) {                               /* inherit ON condition actions? */
3082         sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1]; /* inherit On mode */
3083         for (i=0; i<SCPE_MAX_ERR; i++) {                /* replicate any on commands */
3084             if (sim_on_actions[sim_do_depth-1][i]) {
3085                 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3086                 if (NULL == sim_on_actions[sim_do_depth][i]) {
3087                     while (--i >= 0) {
3088                         FREE(sim_on_actions[sim_do_depth][i]);
3089                         sim_on_actions[sim_do_depth][i] = NULL;
3090                         }
3091                     sim_on_check[sim_do_depth] = 0;
3092                     sim_brk_clract ();                  /* defang breakpoint actions */
3093                     --sim_do_depth;                     /* unwind nesting */
3094                     fclose(fpin);
3095                     return SCPE_MEM;
3096                     }
3097                 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3098                 }
3099             }
3100         }
3101     }
3102 
3103 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);      /* stash away do file name for possible use by 'call' command */
3104 sim_do_label[sim_do_depth] = label;                     /* stash away do label for possible use in messages */
3105 sim_goto_line[sim_do_depth] = 0;
3106 if (label) {
3107     sim_gotofile = fpin;
3108     sim_do_echo = echo;
3109     stat = goto_cmd (0, label);
3110     if (stat != SCPE_OK) {
3111         strcpy(cbuf, "RETURN SCPE_ARG");
3112         cptr = get_glyph (cbuf, gbuf, 0);               /* get command glyph */
3113         cmdp = find_cmd (gbuf);                         /* return the errorStage things to the stat will be returned */
3114         goto Cleanup_Return;
3115         }
3116     }
3117 if (errabort)                                           /* -e flag? */
3118     set_on (1, NULL);                                   /* equivalent to ON ERROR RETURN */
3119 
3120 do {
3121     sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */
3122     if (!sim_do_ocptr[sim_do_depth]) {                  /* no pending action? */
3123         sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */
3124         sim_goto_line[sim_do_depth] += 1;
3125         }
3126     if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {  /* validate */
3127         sim_sub_args(cbuf, sizeof(cbuf), do_arg);       /* substitute args */
3128         }
3129     sim_sub_args (cbuf, sizeof(cbuf), do_arg);          /* substitute args */
3130     if (cptr == NULL) {                                 /* EOF? */
3131         stat = SCPE_OK;                                 /* set good return */
3132         break;
3133         }
3134     if (*cptr == 0)                                     /* ignore blank */
3135         continue;
3136     if (echo)                                           /* echo if -v */
3137         sim_printf("%s> %s\r\n", do_position(), cptr);
3138     if (*cptr == ':')                                   /* ignore label */
3139         continue;
3140     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
3141     sim_switches = 0;                                   /* init switches */
3142     sim_gotofile = fpin;
3143     sim_do_echo = echo;
3144     if ((cmdp = find_cmd (gbuf))) {                     /* lookup command */
3145         if (cmdp->action == &return_cmd)                /* RETURN command? */
3146             break;                                      /*    done! */
3147         if (cmdp->action == &do_cmd) {                  /* DO command? */
3148             if (sim_do_depth >= MAX_DO_NEST_LVL)        /* nest too deep? */
3149                 stat = SCPE_NEST;
3150             else
3151                 stat = do_cmd (sim_do_depth+1, cptr);   /* exec DO cmd */
3152             }
3153         else
3154             stat = cmdp->action (cmdp->arg, cptr);      /* exec other cmd */
3155         }
3156     else stat = SCPE_UNK;                               /* bad cmd given */
3157     echo = sim_do_echo;                                 /* Allow for SET VERIFY */
3158     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
3159     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
3160     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
3161     if (cmdp)
3162       if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3163           ((cmdp->action != &return_cmd) &&
3164            (cmdp->action != &goto_cmd) &&
3165            (cmdp->action != &on_cmd) &&
3166            (cmdp->action != &echo_cmd)))
3167         sim_last_cmd_stat = stat;                       /* save command error status */
3168     switch (stat) {
3169         case SCPE_AFAIL:
3170             staying = (sim_on_check[sim_do_depth] &&        /* if trap action defined */
3171                        sim_on_actions[sim_do_depth][stat]); /* use it, otherwise exit */
3172             break;
3173         case SCPE_EXIT:
3174             staying = FALSE;
3175             break;
3176         case SCPE_OK:
3177         case SCPE_STEP:
3178             break;
3179         default:
3180             break;
3181         }
3182     if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&   /* error from cmd? */
3183         (stat != SCPE_STEP)) {
3184         if (!echo && !sim_quiet &&                      /* report if not echoing */
3185             !stat_nomessage &&                          /* and not suppressing messages */
3186             !(cmdp && cmdp->message)) {                 /* and not handling them specially */
3187             sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
3188             }
3189         }
3190     if (!stat_nomessage) {                              /* report error if not suppressed */
3191         if (cmdp && cmdp->message)                      /* special message handler */
3192             cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3193         else
3194             if (stat >= SCPE_BASE)                      /* report error if not suppressed */
3195                 sim_printf ("%s\r\n", sim_error_text (stat));
3196         }
3197     if (stat == SCPE_EXPECT)                            /* EXPECT status is non actionable */
3198         stat = SCPE_OK;                                 /* so adjust it to SCPE_OK */
3199     if (staying &&
3200         (sim_on_check[sim_do_depth]) &&
3201         (stat != SCPE_OK) &&
3202         (stat != SCPE_STEP)) {
3203         if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3204             sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3205         else
3206             sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3207         }
3208     if (sim_vm_post != NULL)
3209         (*sim_vm_post) (TRUE);
3210     } while (staying);
3211 Cleanup_Return:
3212 if (fpin) //-V547
3213     fclose (fpin);                                      /* close file */
3214 sim_gotofile = NULL;
3215 if (flag >= 0) {
3216     sim_do_echo = saved_sim_do_echo;                    /* restore echo state we entered with */
3217     sim_show_message = saved_sim_show_message;          /* restore message display state we entered with */
3218     sim_on_inherit = saved_sim_on_inherit;              /* restore ON inheritance state we entered with */
3219     }
3220 sim_quiet = saved_sim_quiet;                            /* restore quiet mode we entered with */
3221 if ((flag >= 0) || (!sim_on_inherit)) {
3222     for (i=0; i<SCPE_MAX_ERR; i++) {                    /* release any on commands */
3223         FREE (sim_on_actions[sim_do_depth][i]);
3224         sim_on_actions[sim_do_depth][i] = NULL;
3225         }
3226     sim_on_check[sim_do_depth] = 0;                     /* clear on mode */
3227     }
3228 if (flag >= 0)
3229     --sim_do_depth;                                     /* unwind nesting */
3230 sim_brk_clract ();                                      /* defang breakpoint actions */
3231 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) { /* return command with argument? */
3232     sim_string_to_stat (cptr, &stat);
3233     sim_last_cmd_stat = stat;                           /* save explicit status as command error status */
3234     if (sim_switches & SWMASK ('Q'))
3235         stat |= SCPE_NOMESSAGE;                         /* suppress error message display (in caller) if requested */
3236     return stat;                                        /* return with explicit return status */
3237     }
3238 return stat | SCPE_NOMESSAGE;                           /* suppress message since we've already done that here */
3239 }
3240 
3241 /*
3242  * Substitute_args - replace %n tokens in 'instr' with the do command's arguments
3243  *                   and other environment variables
3244  *
3245  * Calling sequence
3246  * instr        =       input string
3247  * instr_size   =       sizeof input string buffer
3248  * do_arg[10]   =       arguments
3249  *
3250  * Token "%0" expands to the command file name.
3251  * Token %n (n being a single digit) expands to the n'th argument
3252  * Tonen %* expands to the whole set of arguments (%1 ... %9)
3253  *
3254  * The input sequence "\%" represents a literal "%", and "\\" represents a
3255  * literal "\".  All other character combinations are rendered literally.
3256  *
3257  * Omitted parameters result in null-string substitutions.
3258  *
3259  * A Tokens preceded and followed by % characters are expanded as environment
3260  * variables, and if one isn't found then can be one of several special
3261  * variables:
3262  *   %DATE%              yyyy-mm-dd
3263  *   %TIME%              hh:mm:ss
3264  *   %STIME%             hh_mm_ss
3265  *   %CTIME%             Www Mmm dd hh:mm:ss yyyy
3266  *   %STATUS%            Status value from the last command executed
3267  *   %TSTATUS%           The text form of the last status value
3268  *   %SIM_VERIFY%        The Verify/Verbose mode of the current Do command file
3269  *   %SIM_VERBOSE%       The Verify/Verbose mode of the current Do command file
3270  *   %SIM_QUIET%         The Quiet mode of the current Do command file
3271  *   %SIM_MESSAGE%       The message display status of the current Do command file
3272  * Environment variable lookups are done first with the precise name between
3273  * the % characters and if that fails, then the name between the % characters
3274  * is upcased and a lookup of that value is attempted.
3275 
3276  * The first Space delimited token on the line is extracted in uppercase and
3277  * then looked up as an environment variable.  If found it the value is
3278  * substituted for the original string before expanding everything else.  If
3279  * it is not found, then the original beginning token on the line is left
3280  * untouched.
3281  */
3282 
3283 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
     /* [previous][next][first][last][top][bottom][index][help] */
3284 {
3285 char gbuf[CBUFSIZE];
3286 char *ip = instr, *op, *oend, *tmpbuf;
3287 const char *ap;
3288 char rbuf[CBUFSIZE];
3289 int i;
3290 time_t now;
3291 struct tm *tmnow;
3292 
3293 time(&now);
3294 tmnow = localtime(&now);
3295 tmpbuf = (char *)malloc(instr_size);
3296 if (!tmpbuf)
3297   {
3298      (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3299                    __func__, __FILE__, __LINE__);
3300 #if defined(USE_BACKTRACE)
3301 # if defined(SIGUSR2)
3302      (void)raise(SIGUSR2);
3303      /*NOTREACHED*/ /* unreachable */
3304 # endif /* if defined(SIGUSR2) */
3305 #endif /* if defined(USE_BACKTRACE) */
3306      abort();
3307   }
3308 op = tmpbuf;
3309 oend = tmpbuf + instr_size - 2;
3310 while (sim_isspace (*ip))                               /* skip leading spaces */
3311     *op++ = *ip++;
3312 for (; *ip && (op < oend); ) {
3313     if ((ip [0] == '\\') &&                             /* literal escape? */
3314         ((ip [1] == '%') || (ip [1] == '\\'))) {        /*   and followed by '%' or '\'? */
3315         ip++;                                           /* skip '\' */
3316         *op++ = *ip++;                                  /* copy escaped char */
3317         }
3318     else
3319         if ((*ip == '%') &&
3320             (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */
3321             if ((ip[1] >= '0') && (ip[1] <= ('9'))) {   /* %n = sub */
3322                 ap = do_arg[ip[1] - '0'];
3323                 for (i=0; i<ip[1] - '0'; ++i)           /* make sure we're not past the list end */
3324                     if (do_arg[i] == NULL) {
3325                         ap = NULL;
3326                         break;
3327                         }
3328                 ip = ip + 2;
3329                 }
3330             else if (ip[1] == '*') {                    /* %1 ... %9 = sub */
3331                 (void)memset (rbuf, '\0', sizeof(rbuf));
3332                 ap = rbuf;
3333                 for (i=1; i<=9; ++i)
3334                     if (do_arg[i] == NULL)
3335                         break;
3336                     else
3337                         if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3338                             if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
3339                                 char quote = '"';
3340                                 if (strchr(do_arg[i], quote))
3341                                     quote = '\'';
3342                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3343                                               (i != 1) ? " " : "", quote,
3344                                               do_arg[i], quote);
3345                                 }
3346                             else
3347                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3348                                               (i != 1) ? " " : "", do_arg[i]);
3349                             }
3350                         else
3351                             break;
3352                 ip = ip + 2;
3353                 }
3354             else {                                      /* environment variable */
3355                 ap = NULL;
3356                 (void)get_glyph_nc (ip+1, gbuf, '%');   /* first try using the literal name */
3357                 ap = getenv(gbuf);
3358                 if (!ap) {
3359                     (void)get_glyph (ip+1, gbuf, '%');  /* now try using the upcased name */
3360                     ap = getenv(gbuf);
3361                     }
3362                 ip += 1 + strlen (gbuf);
3363                 if (*ip == '%') ++ip;
3364                 if (!ap) {
3365                     /* ISO 8601 format date/time info */
3366                     if (!strcmp ("DATE", gbuf)) {
3367                         (void)sprintf (rbuf, "%4d-%02d-%02d",
3368                                        tmnow->tm_year + 1900,
3369                                        tmnow->tm_mon  + 1,
3370                                        tmnow->tm_mday);
3371                         ap = rbuf;
3372                         }
3373                     else if (!strcmp ("TIME", gbuf)) {
3374                         (void)sprintf (rbuf, "%02d:%02d:%02d",
3375                                        tmnow->tm_hour,
3376                                        tmnow->tm_min,
3377                                        tmnow->tm_sec);
3378                         ap = rbuf;
3379                         }
3380                     else if (!strcmp ("DATETIME", gbuf)) {
3381                         (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3382                                        tmnow->tm_year + 1900,
3383                                        tmnow->tm_mon  + 1,
3384                                        tmnow->tm_mday,
3385                                        tmnow->tm_hour,
3386                                        tmnow->tm_min,
3387                                        tmnow->tm_sec);
3388                         ap = rbuf;
3389                         }
3390                     /* Locale oriented formatted date/time info */
3391                     if (!strcmp ("LDATE", gbuf)) {
3392                         strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3393                         ap = rbuf;
3394                         }
3395                     else if (!strcmp ("LTIME", gbuf)) {
3396                         strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3397                         ap = rbuf;
3398                         }
3399                     else if (!strcmp ("CTIME", gbuf)) {
3400                         strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3401                         ap = rbuf;
3402                         }
3403                     /* Separate Date/Time info */
3404                     else if (!strcmp ("DATE_YYYY", gbuf)) {/* Year (0000-9999) */
3405                         strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3406                         ap = rbuf;
3407                         }
3408                     else if (!strcmp ("DATE_YY", gbuf)) {/* Year (00-99) */
3409                         strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3410                         ap = rbuf;
3411                         }
3412                     else if (!strcmp ("DATE_YC", gbuf)) {/* Century (year/100) */
3413                         (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3414                         ap = rbuf;
3415                         }
3416                     else if ((!strcmp ("DATE_19XX_YY", gbuf)) || /* Year with same calendar */
3417                              (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3418                         int year = tmnow->tm_year + 1900;
3419                         int days = year - 2001;
3420                         int leaps = days/4 - days/100 + days/400;
3421                         int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3422                         int selector = ((days + leaps + 7) % 7) + lyear * 7;
3423                         static int years[] = {90, 91, 97, 98, 99, 94, 89,
3424                                               96, 80, 92, 76, 88, 72, 84};
3425                         int cal_year = years[selector];
3426 
3427                         if (!strcmp ("DATE_19XX_YY", gbuf))
3428                             (void)sprintf (rbuf, "%d", cal_year);        /* 2 digit year */
3429                         else
3430                             (void)sprintf (rbuf, "%d", cal_year + 1900); /* 4 digit year */
3431                         ap = rbuf;
3432                         }
3433                     else if (!strcmp ("DATE_MM", gbuf)) {/* Month number (01-12) */
3434                         strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3435                         ap = rbuf;
3436                         }
3437                     else if (!strcmp ("DATE_MMM", gbuf)) {/* Month number (01-12) */
3438                         strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3439                         ap = rbuf;
3440                         }
3441                     else if (!strcmp ("DATE_DD", gbuf)) {/* Day of Month (01-31) */
3442                         strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3443                         ap = rbuf;
3444                         }
3445                     else if (!strcmp ("DATE_D", gbuf)) { /* ISO 8601 weekday number (1-7) */
3446                         (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3447                         ap = rbuf;
3448                         }
3449                     else if ((!strcmp ("DATE_WW", gbuf)) ||   /* ISO 8601 week number (01-53) */
3450                              (!strcmp ("DATE_WYYYY", gbuf))) {/* ISO 8601 week year number (0000-9999) */
3451                         int iso_yr = tmnow->tm_year + 1900;
3452                         int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3453 
3454                         if (iso_wk == 0) {
3455                             iso_yr = iso_yr - 1;
3456                             tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);  /* Adjust for Leap Year (Correct thru 2099) */
3457                             iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3458                             }
3459                         else
3460                             if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3461                                 ++iso_yr;
3462                                 iso_wk = 1;
3463                                 }
3464                         if (!strcmp ("DATE_WW", gbuf))
3465                             (void)sprintf (rbuf, "%02d", iso_wk);
3466                         else
3467                             (void)sprintf (rbuf, "%04d", iso_yr);
3468                         ap = rbuf;
3469                         }
3470                     else if (!strcmp ("DATE_JJJ", gbuf)) {/* day of year (001-366) */
3471                         strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3472                         ap = rbuf;
3473                         }
3474                     else if (!strcmp ("TIME_HH", gbuf)) {/* Hour of day (00-23) */
3475                         strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3476                         ap = rbuf;
3477                         }
3478                     else if (!strcmp ("TIME_MM", gbuf)) {/* Minute of hour (00-59) */
3479                         strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3480                         ap = rbuf;
3481                         }
3482                     else if (!strcmp ("TIME_SS", gbuf)) {/* Second of minute (00-59) */
3483                         strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3484                         ap = rbuf;
3485                         }
3486                     else if (!strcmp ("STATUS", gbuf)) {
3487                         (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3488                         ap = rbuf;
3489                         }
3490                     else if (!strcmp ("TSTATUS", gbuf)) {
3491                         (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3492                         ap = rbuf;
3493                         }
3494                     else if (!strcmp ("SIM_VERIFY", gbuf)) {
3495                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3496                         ap = rbuf;
3497                         }
3498                     else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3499                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3500                         ap = rbuf;
3501                         }
3502                     else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3503                         (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3504                         ap = rbuf;
3505                         }
3506                     else if (!strcmp ("SIM_QUIET", gbuf)) {
3507                         (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3508                         ap = rbuf;
3509                         }
3510                     else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3511                         (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3512                         ap = rbuf;
3513                         }
3514                     else if (!strcmp ("HOSTID", gbuf)) {
3515 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3516                         (void)sprintf (rbuf, "%ld", (long)gethostid());
3517 #else
3518                         (void)sprintf (rbuf, "00000000");
3519 #endif /* if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) */
3520                         ap = rbuf;
3521                         }
3522                     else if (!strcmp ("UID", gbuf)) {
3523 #if defined(HAVE_UNISTD)
3524                         (void)sprintf (rbuf, "%ld", (long)getuid());
3525 #else
3526                         (void)sprintf (rbuf, "0");
3527 #endif /* if defined(HAVE_UNISTD) */
3528                         ap = rbuf;
3529                         }
3530                     else if (!strcmp ("GID", gbuf)) {
3531 #if defined(HAVE_UNISTD)
3532                         (void)sprintf (rbuf, "%ld", (long)getgid());
3533 #else
3534                         (void)sprintf (rbuf, "0");
3535 #endif /* if defined(HAVE_UNISTD) */
3536                         ap = rbuf;
3537                         }
3538                     else if (!strcmp ("EUID", gbuf)) {
3539 #if defined(HAVE_UNISTD)
3540                         (void)sprintf (rbuf, "%ld", (long)geteuid());
3541 #else
3542                         (void)sprintf (rbuf, "0");
3543 #endif /* if defined(HAVE_UNISTD) */
3544                         ap = rbuf;
3545                         }
3546                     else if (!strcmp ("EGID", gbuf)) {
3547 #if defined(HAVE_UNISTD)
3548                         (void)sprintf (rbuf, "%ld", (long)getegid());
3549 #else
3550                         (void)sprintf (rbuf, "0");
3551 #endif /* if defined(HAVE_UNISTD) */
3552                         ap = rbuf;
3553                         }
3554                     else if (!strcmp ("PID", gbuf)) {
3555 #if defined(HAVE_UNISTD)
3556                         (void)sprintf (rbuf, "%ld", (long)_sir_getpid());
3557 #else
3558                         (void)sprintf (rbuf, "0");
3559 #endif /* if defined(HAVE_UNISTD) */
3560                         ap = rbuf;
3561                         }
3562                     else if (!strcmp ("PPID", gbuf)) {
3563 #if defined(HAVE_UNISTD)
3564                         (void)sprintf (rbuf, "%ld", (long)getppid());
3565 #else
3566                         (void)sprintf (rbuf, "0");
3567 #endif /* if defined(HAVE_UNISTD) */
3568                         ap = rbuf;
3569                         }
3570                     else if (!strcmp ("PGID", gbuf)) {
3571 #if defined(HAVE_UNISTD)
3572                         (void)sprintf (rbuf, "%ld", (long)getpgid(_sir_getpid()));
3573 #else
3574                         (void)sprintf (rbuf, "0");
3575 #endif /* if defined(HAVE_UNISTD) */
3576                         ap = rbuf;
3577                         }
3578                     else if (!strcmp ("SID", gbuf)) {
3579 #if defined(HAVE_UNISTD)
3580                         (void)sprintf (rbuf, "%ld", (long)getsid(_sir_getpid()));
3581 #else
3582                         (void)sprintf (rbuf, "0");
3583 #endif /* if defined(HAVE_UNISTD) */
3584                         ap = rbuf;
3585                         }
3586                     else if (!strcmp ("ENDIAN", gbuf)) {
3587 #if ( defined(DECLITEND) && DECLITEND == 1 )
3588                         (void)sprintf (rbuf, "LITTLE");
3589 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3590                         (void)sprintf (rbuf, "BIG");
3591 #else
3592                         (void)sprintf (rbuf, "UNKNOWN");
3593 #endif /* if ( defined(DECLITEND) && DECLITEND == 1 ) */
3594                         ap = rbuf;
3595                         }
3596                     else if (!strcmp("SIM_NAME", gbuf)) {
3597                         (void)sprintf (rbuf, "%s", sim_name);
3598                         ap = rbuf;
3599                         }
3600                     else if (!strcmp("SIM_VERSION", gbuf)) {
3601 #if defined(VER_H_GIT_VERSION)
3602                         (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3603 #else
3604                         (void)sprintf (rbuf, "UNKNOWN");
3605 #endif /* if defined(VER_H_GIT_VERSION) */
3606                         ap = rbuf;
3607                         }
3608                     else if (!strcmp("SIM_HASH", gbuf)) {
3609 #if defined(VER_H_GIT_HASH)
3610                         (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3611 #else
3612                         (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3613 #endif /* if defined(VER_H_GIT_HASH) */
3614                         ap = rbuf;
3615                         }
3616                     else if (!strcmp("SIM_RELT", gbuf)) {
3617 #if defined(VER_H_GIT_RELT)
3618                         (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3619 #else
3620                         (void)sprintf (rbuf, "X");
3621 #endif /* if defined(VER_H_GIT_RELT) */
3622                         ap = rbuf;
3623                         }
3624                     else if (!strcmp("SIM_DATE", gbuf)) {
3625 #if defined(VER_H_GIT_DATE)
3626                         (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3627 #else
3628                         (void)sprintf (rbuf, "UNKNOWN");
3629 #endif /* if defined(VER_H_GIT_DATE) */
3630                         ap = rbuf;
3631                         }
3632                     else if ((!strcmp("CORES", gbuf)) ||
3633                              (!strcmp("SIM_CORES", gbuf))) {
3634                         (void)sprintf(rbuf, "%u", (ncores >= 1 && nprocs >= 1) ? ((ncores > nprocs) ? nprocs : ncores) : 1);
3635                         ap = rbuf;
3636                         }
3637                     else if ((!strcmp("CPUS", gbuf)) ||
3638                              (!strcmp("SIM_PROCESSORS", gbuf))) {
3639                         (void)sprintf(rbuf, "%u", (nprocs < 2) ? 1U : nprocs);
3640                         ap = rbuf;
3641                         }
3642                     }
3643                 }
3644             if (ap) {                                   /* non-null arg? */
3645                 while (*ap && (op < oend))              /* copy the argument */
3646                     *op++ = *ap++;
3647                 }
3648             }
3649         else
3650             *op++ = *ip++;
3651     }
3652 *op = 0;                                                /* term buffer */
3653 strcpy (instr, tmpbuf);
3654 FREE (tmpbuf);
3655 return;
3656 }
3657 
3658 static
3659 int sim_cmp_string (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help] */
3660 {
3661 long int v1, v2;
3662 char *ep1, *ep2;
3663 
3664 v1 = strtol(s1+1, &ep1, 0);
3665 v2 = strtol(s2+1, &ep2, 0);
3666 if ((ep1 != s1 + strlen (s1) - 1) ||
3667     (ep2 != s2 + strlen (s2) - 1))
3668     return strcmp (s1, s2);
3669 if (v1 == v2)
3670     return 0;
3671 if (v1 < v2)
3672     return -1;
3673 return 1;
3674 }
3675 
3676 /* Assert command */
3677 
3678 t_stat assert_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3679 {
3680 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3681 CONST char *tptr, *gptr;
3682 REG *rptr;
3683 uint32 idx = 0;
3684 t_value val;
3685 t_stat r;
3686 t_bool Not = FALSE;
3687 t_bool result;
3688 t_addr addr = 0;
3689 t_stat reason = SCPE_AFAIL; /* default fail reason */
3690 
3691 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3692                                                         /* get sw, default */
3693 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3694 # pragma diagnostic push
3695 # pragma diag_suppress = integer_sign_change
3696 #endif
3697 sim_stabr.boolop = sim_staba.boolop = -1;               /* no relational op dflt */
3698 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3699 # pragma diagnostic pop
3700 #endif
3701 if (*cptr == 0)                                         /* must be more */
3702     return SCPE_2FARG;
3703 tptr = get_glyph (cptr, gbuf, 0);                       /* get token */
3704 if (!strcmp (gbuf, "NOT")) {                            /* Conditional Inversion? */
3705     Not = TRUE;                                         /* remember that, and */
3706     cptr = (CONST char *)tptr;
3707     }
3708 if (*cptr == '"') {                                     /* quoted string comparison? */
3709     char op[CBUFSIZE];
3710     static struct {
3711         const char *op;
3712         int aval;
3713         int bval;
3714         t_bool invert;
3715         } *optr, compare_ops[] =
3716         {
3717             { "==",   0,  0, FALSE },
3718             { "EQU",  0,  0, FALSE },
3719             { "!=",   0,  0, TRUE  },
3720             { "NEQ",  0,  0, TRUE  },
3721             { "<",   -1, -1, FALSE },
3722             { "LSS", -1, -1, FALSE },
3723             { "<=",   0, -1, FALSE },
3724             { "LEQ",  0, -1, FALSE },
3725             { ">",    1,  1, FALSE },
3726             { "GTR",  1,  1, FALSE },
3727             { ">=",   0,  1, FALSE },
3728             { "GEQ",  0,  1, FALSE },
3729             { NULL }
3730         };
3731 
3732     tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3733                                                     /* get first string */
3734     if (!*tptr)
3735         return SCPE_2FARG;
3736     cptr += strlen (gbuf);
3737     while (sim_isspace (*cptr))                     /* skip spaces */
3738         ++cptr;
3739     (void)get_glyph (cptr, op, '"');
3740     for (optr = compare_ops; optr->op; optr++)
3741         if (0 == strcmp (op, optr->op))
3742             break;
3743     if (!optr->op)
3744         return sim_messagef (SCPE_ARG, "Invalid operator: %s\r\n", op);
3745     cptr += strlen (op);
3746     while (sim_isspace (*cptr))                         /* skip spaces */
3747         ++cptr;
3748     cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3749                                                         /* get second string */
3750     if (*cptr) {                                        /* more? */
3751         if (flag)                                       /* ASSERT has no more args */
3752             return SCPE_2MARG;
3753         }
3754     else {
3755         if (!flag)
3756             return SCPE_2FARG;                          /* IF needs actions! */
3757         }
3758     result = sim_cmp_string (gbuf, gbuf2);
3759     result = ((result == optr->aval) || (result == optr->bval));
3760     if (optr->invert)
3761         result = !result;
3762     }
3763 else {
3764     cptr = get_glyph (cptr, gbuf, 0);                   /* get register */
3765     rptr = find_reg (gbuf, &gptr, sim_dfdev);           /* parse register */
3766     if (rptr) {                                         /* got register? */
3767         if (*gptr == '[') {                             /* subscript? */
3768             if (rptr->depth <= 1)                       /* array register? */
3769                 return SCPE_ARG;
3770             idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */
3771             if ((gptr == tptr) || (*tptr++ != ']'))
3772                 return SCPE_ARG;
3773             gptr = tptr;                                /* update */
3774             }
3775         else idx = 0;                                   /* not array */
3776         if (idx >= rptr->depth)                         /* validate subscript */
3777             return SCPE_SUB;
3778         }
3779     else {                                              /* not reg, check for memory */
3780         if (sim_dfdev && sim_vm_parse_addr)             /* get addr */
3781             addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3782         else if (sim_dfdev) //-V547
3783             addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix); //-V547
3784         if (gbuf == gptr)                               /* error? */
3785             return SCPE_NXREG;
3786         }
3787     if (*gptr != 0)                                     /* more? must be search */
3788         (void)get_glyph (gptr, gbuf, 0);
3789     else {
3790         if (*cptr == 0)                                 /* must be more */
3791             return SCPE_2FARG;
3792         cptr = get_glyph (cptr, gbuf, 0);               /* get search cond */
3793         }
3794     if (*cptr) {                                        /* more? */
3795         if (flag)                                       /* ASSERT has no more args */
3796             return SCPE_2MARG;
3797         }
3798     else {
3799         if (!flag)
3800             return SCPE_2FARG;                          /* IF needs actions! */
3801         }
3802     if (rptr) {                                         /* Handle register case */
3803 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3804 # pragma diagnostic push
3805 # pragma diag_suppress = integer_sign_change
3806 #endif
3807         if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||  /* parse condition */
3808             (sim_stabr.boolop == -1))                   /* relational op reqd */
3809             return SCPE_MISVAL;
3810 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3811 # pragma diagnostic pop
3812 #endif
3813         val = get_rval (rptr, idx);                     /* get register value */
3814         result = test_search (&val, &sim_stabr);        /* test condition */
3815         }
3816     else {                                              /* Handle memory case */
3817 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3818 # pragma diagnostic push
3819 # pragma diag_suppress = integer_sign_change
3820 #endif
3821         if (sim_dfdev)
3822             if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||  /* parse condition */
3823                 (sim_staba.boolop == -1))                    /* relational op reqd */
3824                 return SCPE_MISVAL;
3825 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3826 # pragma diagnostic pop
3827 #endif
3828         if (sim_dfdev)
3829             reason = get_aval (addr, sim_dfdev, sim_dfunit); /* get data */
3830         if (reason != SCPE_OK)                          /* return if error */
3831             return reason;
3832         result = test_search (sim_eval, &sim_staba);    /* test condition */
3833         }
3834     }
3835 if (Not ^ result) {
3836     if (!flag)
3837         sim_brk_setact (cptr);                          /* set up IF actions */
3838     }
3839 else
3840     if (flag)
3841         return SCPE_AFAIL;                              /* return assert status */
3842 return SCPE_OK;
3843 }
3844 
3845 /* Send command */
3846 
3847 t_stat send_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3848 {
3849 char gbuf[CBUFSIZE];
3850 CONST char *tptr;
3851 uint8 dbuf[CBUFSIZE];
3852 uint32 dsize = 0;
3853 uint32 delay = 0;
3854 uint32 after = 0;
3855 t_stat r;
3856 SEND *snd = NULL;
3857 
3858 GET_SWITCHES (cptr);                                    /* get switches */
3859 tptr = get_glyph (cptr, gbuf, ',');
3860 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3861     r = tmxr_locate_line_send (gbuf, &snd);
3862     if (r != SCPE_OK)
3863       return r;
3864     cptr = tptr;
3865     tptr = get_glyph (tptr, gbuf, ',');
3866     }
3867 else
3868     snd = sim_cons_get_send ();
3869 
3870 while (*cptr) {
3871     if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3872         delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3873         if (r != SCPE_OK)
3874             return sim_messagef (SCPE_ARG, "Invalid Delay Value\r\n");
3875         cptr = tptr;
3876         tptr = get_glyph (cptr, gbuf, ',');
3877         continue;
3878         }
3879     if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3880         after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3881         if (r != SCPE_OK)
3882             return sim_messagef (SCPE_ARG, "Invalid After Value\r\n");
3883         cptr = tptr;
3884         tptr = get_glyph (cptr, gbuf, ',');
3885         continue;
3886         }
3887     if ((*cptr == '"') || (*cptr == '\''))
3888         break;
3889     return SCPE_ARG;
3890     }
3891 if (*cptr) {
3892     if ((*cptr != '"') && (*cptr != '\'')) //-V560
3893         return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
3894     cptr = get_glyph_quoted (cptr, gbuf, 0);
3895     if (*cptr != '\0')
3896         return SCPE_2MARG;                  /* No more arguments */
3897 
3898     if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3899         return sim_messagef (SCPE_ARG, "Invalid String\r\n");
3900     }
3901 if ((dsize == 0) && (delay == 0) && (after == 0))
3902     return SCPE_2FARG;
3903 return sim_send_input (snd, dbuf, dsize, after, delay);
3904 }
3905 
3906 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3907 {
3908 char gbuf[CBUFSIZE];
3909 CONST char *tptr;
3910 t_stat r;
3911 SEND *snd = NULL;
3912 
3913 tptr = get_glyph (cptr, gbuf, ',');
3914 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3915     r = tmxr_locate_line_send (gbuf, &snd);
3916     if (r != SCPE_OK)
3917       return r;
3918     cptr = tptr;
3919     }
3920 else
3921     snd = sim_cons_get_send ();
3922 if (*cptr)
3923     return SCPE_2MARG;
3924 return sim_show_send_input (st, snd);
3925 }
3926 
3927 t_stat expect_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3928 {
3929 char gbuf[CBUFSIZE];
3930 CONST char *tptr;
3931 EXPECT *exp = NULL;
3932 
3933 GET_SWITCHES (cptr);                                    /* get switches */
3934 tptr = get_glyph (cptr, gbuf, ',');
3935 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3936     cptr = tptr;
3937 } else {
3938     exp = sim_cons_get_expect ();
3939 }
3940 
3941 if (flag) {
3942     return sim_set_expect (exp, cptr);
3943 } else {
3944     if (exp == NULL) {
3945         exp = sim_cons_get_expect();
3946     }
3947     return sim_set_noexpect (exp, cptr);
3948 }
3949 }
3950 
3951 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3952 {
3953 char gbuf[CBUFSIZE];
3954 CONST char *tptr;
3955 EXPECT *exp = NULL;
3956 t_stat r;
3957 
3958 tptr = get_glyph (cptr, gbuf, ',');
3959 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3960     r = tmxr_locate_line_expect (gbuf, &exp);
3961     if (r != SCPE_OK)
3962         return r;
3963     cptr = tptr;
3964     }
3965 else
3966     exp = sim_cons_get_expect ();
3967 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3968     return SCPE_ARG;            /* String must be quote delimited */
3969 tptr = get_glyph_quoted (cptr, gbuf, 0);
3970 if (*tptr != '\0')
3971     return SCPE_2MARG;          /* No more arguments */
3972 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3973     return SCPE_ARG;            /* String must be quote delimited */
3974 return sim_exp_show (st, exp, gbuf);
3975 }
3976 
3977 /* Goto command */
3978 
3979 t_stat goto_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3980 {
3981 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3982 const char *cptr;
3983 long fpos;
3984 int32 saved_do_echo = sim_do_echo;
3985 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3986 
3987 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
3988 (void)get_glyph (fcptr, gbuf1, 0);
3989 if ('\0' == gbuf1[0]) return SCPE_ARG;                  /* unspecified goto target */
3990 fpos = ftell(sim_gotofile);                             /* Save start position */
3991 rewind(sim_gotofile);                                   /* start search for label */
3992 sim_goto_line[sim_do_depth] = 0;                        /* reset line number */
3993 sim_do_echo = 0;                                        /* Don't echo while searching for label */
3994 while (1) {
3995     cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);/* get cmd line */
3996     if (cptr == NULL) break;                            /* exit on eof */
3997     sim_goto_line[sim_do_depth] += 1;                   /* record line number */
3998     if (*cptr == 0) continue;                           /* ignore blank */
3999     if (*cptr != ':') continue;                         /* ignore non-labels */
4000     ++cptr;                                             /* skip : */
4001     while (sim_isspace (*cptr)) ++cptr;                 /* skip blanks */
4002     cptr = get_glyph (cptr, gbuf, 0);                   /* get label glyph */
4003     if (0 == strcmp(gbuf, gbuf1)) {
4004         sim_brk_clract ();                              /* goto defangs current actions */
4005         sim_do_echo = saved_do_echo;                    /* restore echo mode */
4006         if (sim_do_echo)                                /* echo if -v */
4007             sim_printf("%s> %s\r\n", do_position(), cbuf);
4008         return SCPE_OK;
4009         }
4010     }
4011 sim_do_echo = saved_do_echo;                       /* restore echo mode         */
4012 fseek(sim_gotofile, fpos, SEEK_SET);               /* restore start position    */
4013 sim_goto_line[sim_do_depth] = saved_goto_line;     /* restore start line number */
4014 return SCPE_ARG;
4015 }
4016 
4017 /* Return command */
4018 
4019 /* The return command is invalid unless encountered in a do_cmd context,    */
4020 /* and in that context, it is handled as a special case inside of do_cmd()  */
4021 /* and not dispatched here, so if we get here a return has been issued from */
4022 /* interactive input */
4023 
4024 t_stat return_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4025 {
4026 return SCPE_UNK;                                 /* only valid inside of do_cmd */
4027 }
4028 
4029 /* Shift command */
4030 
4031 /* The shift command is invalid unless encountered in a do_cmd context,    */
4032 /* and in that context, it is handled as a special case inside of do_cmd() */
4033 /* and not dispatched here, so if we get here a shift has been issued from */
4034 /* interactive input (it is not valid interactively since it would have to */
4035 /* mess with the program's argv which is owned by the C runtime library    */
4036 
4037 t_stat shift_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4038 {
4039 return SCPE_UNK;                                 /* only valid inside of do_cmd */
4040 }
4041 
4042 /* Call command */
4043 
4044 /* The call command is invalid unless encountered in a do_cmd context,     */
4045 /* and in that context, it is handled as a special case inside of do_cmd() */
4046 /* and not dispatched here, so if we get here a call has been issued from  */
4047 /* interactive input                                                       */
4048 
4049 t_stat call_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4050 {
4051 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
4052 const char *cptr;
4053 
4054 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
4055 cptr = get_glyph (fcptr, gbuf, 0);
4056 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified goto target */
4057 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
4058 sim_switches |= SWMASK ('O');                           /* inherit ON state and actions */
4059 return do_cmd_label (flag, cbuf, gbuf);
4060 }
4061 
4062 /* On command */
4063 
4064 t_stat on_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4065 {
4066 char gbuf[CBUFSIZE];
4067 t_stat cond;
4068 
4069 cptr = get_glyph (cptr, gbuf, 0);
4070 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified condition */
4071 if (0 == strcmp("ERROR", gbuf))
4072     cond = 0;
4073 else
4074     if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4075         return SCPE_ARG;
4076 if ((NULL == cptr) || ('\0' == *cptr)) {                /* Empty Action */
4077     FREE(sim_on_actions[sim_do_depth][cond]);           /* Clear existing condition */
4078     sim_on_actions[sim_do_depth][cond] = NULL; }
4079 else {
4080     sim_on_actions[sim_do_depth][cond] =
4081         (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4082     if (!sim_on_actions[sim_do_depth][cond])
4083       {
4084         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4085                        __func__, __FILE__, __LINE__);
4086 #if defined(USE_BACKTRACE)
4087 # if defined(SIGUSR2)
4088         (void)raise(SIGUSR2);
4089         /*NOTREACHED*/ /* unreachable */
4090 # endif /* if defined(SIGUSR2) */
4091 #endif /* if defined(USE_BACKTRACE) */
4092         abort();
4093       }
4094     strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4095     }
4096 return SCPE_OK;
4097 }
4098 
4099 /* noop command */
4100 
4101 t_stat noop_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4102 {
4103 if (cptr && (*cptr != 0))                               /* now eol? */
4104     return SCPE_2MARG;
4105 return SCPE_OK;                                         /* we're happy doing nothing */
4106 }
4107 
4108 /* Set on/noon routine */
4109 
4110 t_stat set_on (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4111 {
4112 if ((flag) && (cptr) && (*cptr)) {                      /* Set ON with arg */
4113     char gbuf[CBUFSIZE];
4114 
4115     cptr = get_glyph (cptr, gbuf, 0);                   /* get command glyph */
4116     if (((MATCH_CMD(gbuf,"INHERIT")) &&
4117          (MATCH_CMD(gbuf,"NOINHERIT"))) || //-V600
4118         (*cptr))
4119         return SCPE_2MARG;
4120     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT"))) //-V560
4121         sim_on_inherit = 1;
4122     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT"))) //-V560
4123         sim_on_inherit = 0;
4124     return SCPE_OK;
4125     }
4126 if (cptr && (*cptr != 0))                               /* now eol? */
4127     return SCPE_2MARG;
4128 sim_on_check[sim_do_depth] = flag;
4129 if ((sim_do_depth != 0) &&
4130     (NULL == sim_on_actions[sim_do_depth][0])) {        /* default handler set? */
4131     sim_on_actions[sim_do_depth][0] =                   /* No, so make "RETURN" */
4132         (char *)malloc(1+strlen("RETURN"));             /* be the default action */
4133     strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4134     }
4135 if ((sim_do_depth != 0) &&
4136     (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {/* handler set for AFAIL? */
4137     sim_on_actions[sim_do_depth][SCPE_AFAIL] =           /* No, so make "RETURN" */
4138         (char *)malloc(1+strlen("RETURN"));              /* be the action */
4139     strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4140     }
4141 return SCPE_OK;
4142 }
4143 
4144 /* Set verify/noverify routine */
4145 
4146 t_stat set_verify (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4147 {
4148 if (cptr && (*cptr != 0))                               /* now eol? */
4149     return SCPE_2MARG;
4150 if (flag == sim_do_echo)                                /* already set correctly? */
4151     return SCPE_OK;
4152 sim_do_echo = flag;
4153 return SCPE_OK;
4154 }
4155 
4156 /* Set message/nomessage routine */
4157 
4158 t_stat set_message (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4159 {
4160 if (cptr && (*cptr != 0))                               /* now eol? */
4161     return SCPE_2MARG;
4162 if (flag == sim_show_message)                           /* already set correctly? */
4163     return SCPE_OK;
4164 sim_show_message = flag;
4165 return SCPE_OK;
4166 }
4167 
4168 /* Set localopc/nolocalopc routine */
4169 
4170 t_stat set_localopc (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4171 {
4172 if (cptr && (*cptr != 0))                               /* now eol? */
4173     return SCPE_2MARG;
4174 if (flag == sim_localopc)                               /* already set correctly? */
4175     return SCPE_OK;
4176 sim_localopc = flag;
4177 return SCPE_OK;
4178 }
4179 /* Set quiet/noquiet routine */
4180 
4181 t_stat set_quiet (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4182 {
4183 if (cptr && (*cptr != 0))                               /* now eol? */
4184     return SCPE_2MARG;
4185 if (flag == sim_quiet)                                  /* already set correctly? */
4186     return SCPE_OK;
4187 sim_quiet = flag;
4188 return SCPE_OK;
4189 }
4190 
4191 /* Set environment routine */
4192 
4193 t_stat sim_set_environment (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4194 {
4195 char varname[CBUFSIZE];
4196 
4197 if ((NULL == cptr) || (*cptr == 0))                            /* now eol? */
4198     return SCPE_2FARG;
4199 cptr = get_glyph (cptr, varname, '=');                  /* get environment variable name */
4200 setenv(varname, cptr, 1);
4201 return SCPE_OK;
4202 }
4203 
4204 /* Set command */
4205 
4206 t_stat set_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4207 {
4208 uint32 lvl = 0;
4209 t_stat r;
4210 char gbuf[CBUFSIZE], *cvptr;
4211 CONST char *svptr;
4212 DEVICE *dptr;
4213 UNIT *uptr;
4214 MTAB *mptr;
4215 CTAB *gcmdp;
4216 C1TAB *ctbr = NULL, *glbr;
4217 
4218 GET_SWITCHES (cptr);                                    /* get switches */
4219 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
4220     return SCPE_2FARG;
4221 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get glob/dev/unit */
4222 
4223 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4224     uptr = dptr->units;                                 /* first unit */
4225     ctbr = set_dev_tab;                                 /* global table */
4226     lvl = MTAB_VDV;                                     /* device match */
4227     GET_SWITCHES (cptr);                                /* get more switches */
4228     }
4229 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4230     if (uptr == NULL)                                   /* invalid unit */
4231         return SCPE_NXUN;
4232     ctbr = set_unit_tab;                                /* global table */
4233     lvl = MTAB_VUN;                                     /* unit match */
4234     GET_SWITCHES (cptr);                                /* get more switches */
4235     }
4236 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {    /* global? */
4237     GET_SWITCHES (cptr);                                /* get more switches */
4238     return gcmdp->action (gcmdp->arg, cptr);            /* do the rest */
4239     }
4240 else {
4241     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4242         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4243             *cvptr++ = 0;
4244         for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4245             if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4246                 dptr = sim_dflt_dev;
4247                 cptr = svptr;
4248                 while (sim_isspace(*cptr))
4249                     ++cptr;
4250                 break;
4251                 }
4252             }
4253         }
4254     if (!dptr)
4255         return SCPE_NXDEV;                              /* no match */
4256     lvl = MTAB_VDV;                                     /* device match */
4257     uptr = dptr->units;                                 /* first unit */
4258     }
4259 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4260     return SCPE_2FARG;
4261 GET_SWITCHES (cptr);                                    /* get more switches */
4262 
4263 while (*cptr != 0) {                                    /* do all mods */
4264     cptr = get_glyph (svptr = cptr, gbuf, ',');         /* get modifier */
4265     if (0 == strcmp (gbuf, ";"))
4266         break;
4267     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4268         *cvptr++ = 0;
4269     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4270         if ((mptr->mstring) &&                          /* match string */
4271             (MATCH_CMD (gbuf, mptr->mstring) == 0)) {   /* matches option? */
4272             if (mptr->mask & MTAB_XTD) {                /* extended? */
4273                 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4274                     return SCPE_ARG;
4275                 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4276                     return SCPE_UDIS;                   /* unit disabled? */
4277                 if (mptr->valid) {                      /* validation rtn? */
4278                     if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4279                         svptr = get_glyph_quoted (svptr, gbuf, ',');
4280                         if ((cvptr = strchr (gbuf, '='))) {
4281                             *cvptr++ = 0;
4282                             cptr = svptr;
4283                             }
4284                         }
4285                     else {
4286                         if (cvptr && MODMASK(mptr,MTAB_NC)) {
4287                             (void)get_glyph_nc (svptr, gbuf, ',');
4288                             if ((cvptr = strchr (gbuf, '=')))
4289                                 *cvptr++ = 0;
4290                             }
4291                         }
4292                     r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4293                     if (r != SCPE_OK)
4294                         return r;
4295                     }
4296                 else if (!mptr->desc)                   /* value desc? */
4297                     break;
4298                 else if (cvptr)                         /* = value? */
4299                     return SCPE_ARG;
4300                 else *((int32 *) mptr->desc) = mptr->match;
4301                 }                                       /* end if xtd */
4302             else {                                      /* old style */
4303                 if (cvptr)                              /* = value? */
4304                     return SCPE_ARG;
4305                 if (uptr->flags & UNIT_DIS)             /* disabled? */
4306                      return SCPE_UDIS;
4307                 if ((mptr->valid) &&                    /* invalid? */
4308                     ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4309                     return r;
4310                 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4311                     (mptr->match & mptr->mask);         /* set new value */
4312                 }                                       /* end else xtd */
4313             break;                                      /* terminate for */
4314             }                                           /* end if match */
4315         }                                               /* end for */
4316     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4317         if ((glbr = find_c1tab (ctbr, gbuf))) {         /* global match? */
4318             r = glbr->action (dptr, uptr, glbr->arg, cvptr);    /* do global */
4319             if (r != SCPE_OK)
4320                 return r;
4321             }
4322         else if (!dptr->modifiers)                      /* no modifiers? */
4323             return SCPE_NOPARAM;
4324         else return SCPE_NXPAR;
4325         }                                               /* end if no mat */
4326     }                                                   /* end while */
4327 return SCPE_OK;                                         /* done all */
4328 }
4329 
4330 /* Match CTAB/CTAB1 name */
4331 
4332 CTAB *find_ctab (CTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4333 {
4334 if (!tab)
4335     return NULL;
4336 for (; tab->name != NULL; tab++) {
4337     if (MATCH_CMD (gbuf, tab->name) == 0)
4338         return tab;
4339     }
4340 return NULL;
4341 }
4342 
4343 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4344 {
4345 if (!tab)
4346     return NULL;
4347 for (; tab->name != NULL; tab++) {
4348     if (MATCH_CMD (gbuf, tab->name) == 0)
4349         return tab;
4350     }
4351 return NULL;
4352 }
4353 
4354 /* Set device data radix routine */
4355 
4356 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4357 {
4358 if (cptr)
4359     return SCPE_ARG;
4360 dptr->dradix = flag & 037;
4361 return SCPE_OK;
4362 }
4363 
4364 /* Set device enabled/disabled routine */
4365 
4366 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4367 {
4368 UNIT *up;
4369 uint32 i;
4370 
4371 if (cptr)
4372     return SCPE_ARG;
4373 if ((dptr->flags & DEV_DISABLE) == 0)                   /* allowed? */
4374     return SCPE_NOFNC;
4375 if (flag) {                                             /* enable? */
4376     if ((dptr->flags & DEV_DIS) == 0)                   /* already enb? ok */
4377         return SCPE_OK;
4378     dptr->flags = dptr->flags & ~DEV_DIS;               /* no, enable */
4379     }
4380 else {
4381     if (dptr->flags & DEV_DIS)                          /* already dsb? ok */
4382         return SCPE_OK;
4383     for (i = 0; i < dptr->numunits; i++) {              /* check units */
4384         up = (dptr->units) + i;                         /* att or active? */
4385         if ((up->flags & UNIT_ATT) || sim_is_active (up))
4386             return SCPE_NOFNC;                          /* can't do it */
4387         }
4388     dptr->flags = dptr->flags | DEV_DIS;                /* disable */
4389     }
4390 if (dptr->reset)                                        /* reset device */
4391     return dptr->reset (dptr);
4392 else return SCPE_OK;
4393 }
4394 
4395 /* Set unit enabled/disabled routine */
4396 
4397 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4398 {
4399 if (cptr)
4400     return SCPE_ARG;
4401 if (!(uptr->flags & UNIT_DISABLE))                      /* allowed? */
4402     return SCPE_NOFNC;
4403 if (flag)                                               /* enb? enable */
4404     uptr->flags = uptr->flags & ~UNIT_DIS;
4405 else {
4406     if ((uptr->flags & UNIT_ATT) ||                     /* dsb */
4407         sim_is_active (uptr))                           /* more tests */
4408         return SCPE_NOFNC;
4409     uptr->flags = uptr->flags | UNIT_DIS;               /* disable */
4410     }
4411 return SCPE_OK;
4412 }
4413 
4414 /* Set device debug enabled/disabled routine */
4415 
4416 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4417 {
4418 char gbuf[CBUFSIZE];
4419 DEBTAB *dep;
4420 
4421 if ((dptr->flags & DEV_DEBUG) == 0)
4422     return SCPE_NOFNC;
4423 if (cptr == NULL) {                                     /* no arguments? */
4424     dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;/* disable/enable w/o table */
4425     if (flag && dptr->debflags) {                       /* enable with table? */
4426         for (dep = dptr->debflags; dep->name != NULL; dep++)
4427             dptr->dctrl = dptr->dctrl | dep->mask;      /* set all */
4428         }
4429     return SCPE_OK;
4430     }
4431 if (dptr->debflags == NULL)                             /* must have table */
4432     return SCPE_ARG;
4433 while (*cptr) {
4434     cptr = get_glyph (cptr, gbuf, ';');                 /* get debug flag */
4435     for (dep = dptr->debflags; dep->name != NULL; dep++) {
4436         if (strcmp (dep->name, gbuf) == 0) {            /* match? */
4437             if (flag)
4438                 dptr->dctrl = dptr->dctrl | dep->mask;
4439             else dptr->dctrl = dptr->dctrl & ~dep->mask;
4440             break;
4441             }
4442         }                                               /* end for */
4443     if (dep->mask == 0)                                 /* no match? */
4444         return SCPE_ARG;
4445     }                                                   /* end while */
4446 return SCPE_OK;
4447 }
4448 
4449 /* Show command */
4450 
4451 t_stat show_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4452 {
4453 t_stat r = SCPE_IERR;
4454 
4455 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4456                                                         /* get sw, ofile */
4457 if (NULL == cptr)                                              /* error? */
4458     return r;
4459 if (sim_ofile) {                                        /* output file? */
4460     r = show_cmd_fi (sim_ofile, flag, cptr);            /* do show */
4461     fclose (sim_ofile);
4462     }
4463 else {
4464     r = show_cmd_fi (stdout, flag, cptr);               /* no, stdout, log */
4465     if (sim_log && (sim_log != stdout))
4466         show_cmd_fi (sim_log, flag, cptr);
4467     if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4468         show_cmd_fi (sim_deb, flag, cptr);
4469     }
4470 return r;
4471 }
4472 
4473 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4474 {
4475 uint32 lvl = 0xFFFFFFFF;
4476 char gbuf[CBUFSIZE], *cvptr;
4477 CONST char *svptr;
4478 DEVICE *dptr;
4479 UNIT *uptr;
4480 MTAB *mptr;
4481 SHTAB *shtb = NULL, *shptr;
4482 
4483 GET_SWITCHES (cptr);                                    /* get switches */
4484 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4485     return SCPE_2FARG;
4486 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get next glyph */
4487 
4488 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4489     uptr = dptr->units;                                 /* first unit */
4490     shtb = show_dev_tab;                                /* global table */
4491     lvl = MTAB_VDV;                                     /* device match */
4492     GET_SWITCHES (cptr);                                /* get more switches */
4493     }
4494 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4495     if (uptr == NULL)                                   /* invalid unit */
4496         return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\r\n", gbuf);
4497     if (uptr->flags & UNIT_DIS)                         /* disabled? */
4498         return sim_messagef (SCPE_UDIS, "Unit disabled: %s\r\n", gbuf);
4499     shtb = show_unit_tab;                               /* global table */
4500     lvl = MTAB_VUN;                                     /* unit match */
4501     GET_SWITCHES (cptr);                                /* get more switches */
4502     }
4503 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {  /* global? */
4504     GET_SWITCHES (cptr);                                /* get more switches */
4505     return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4506     }
4507 else {
4508     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4509         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4510             *cvptr++ = 0;
4511         for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4512             if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4513                  (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) || //-V600
4514                 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4515                 dptr = sim_dflt_dev;
4516                 lvl = MTAB_VDV;                         /* device match */
4517                 cptr = svptr;
4518                 while (sim_isspace(*cptr))
4519                     ++cptr;
4520                 break;
4521                 }
4522             }
4523         }
4524     if (!dptr) {
4525         if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))  /* global match? */
4526             return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4527         else
4528             return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\r\n", gbuf);/* no match */
4529         }
4530     }
4531 
4532 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) { /* now eol? */
4533     return (lvl == MTAB_VDV)?
4534         show_device (ofile, dptr, 0):
4535         show_unit (ofile, dptr, uptr, -1);
4536     }
4537 GET_SWITCHES (cptr);                                    /* get more switches */
4538 
4539 while (*cptr != 0) {                                    /* do all mods */
4540     cptr = get_glyph (cptr, gbuf, ',');                 /* get modifier */
4541     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4542         *cvptr++ = 0;
4543     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4544         if (((mptr->mask & MTAB_XTD)?                   /* right level? */
4545             ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4546             ((mptr->disp && mptr->pstring &&            /* named disp? */
4547             (MATCH_CMD (gbuf, mptr->pstring) == 0))
4548             )) {
4549             if (cvptr && !MODMASK(mptr,MTAB_SHP))
4550                 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\r\n", gbuf, cvptr);
4551             show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4552             break;
4553             }                                           /* end if */
4554         }                                               /* end for */
4555     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4556         if (shtb && (shptr = find_shtab (shtb, gbuf))) {/* global match? */
4557             t_stat r;
4558 
4559             r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4560             if (r != SCPE_OK)
4561                 return r;
4562             }
4563         else {
4564             if (!dptr->modifiers)                       /* no modifiers? */
4565                 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\r\n", dptr->name);
4566             else
4567                 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\r\n", gbuf);
4568             }
4569         }                                               /* end if */
4570     }                                                   /* end while */
4571 return SCPE_OK;
4572 }
4573 
4574 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4575 {
4576 if (!tab)
4577     return NULL;
4578 for (; tab->name != NULL; tab++) {
4579     if (MATCH_CMD (gbuf, tab->name) == 0)
4580         return tab;
4581     }
4582 return NULL;
4583 }
4584 
4585 /* Show device and unit */
4586 
4587 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4588 {
4589 uint32 j, udbl, ucnt;
4590 UNIT *uptr;
4591 int32 toks = 0;
4592 
4593 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4594 (void)fprintf (st, "%s", sim_dname (dptr));                   /* print dev name */
4595 if ((flag == 2) && dptr->description) {
4596     (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4597     }
4598 else {
4599     if ((sim_switches & SWMASK ('D')) && dptr->description)
4600         (void)fprintf (st, "\t%s\r\n", dptr->description(dptr));
4601     }
4602 if (qdisable (dptr)) {                                  /* disabled? */
4603     (void)fprintf (st, "\tdisabled\r\n");
4604     return SCPE_OK;
4605     }
4606 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {    /* count units */
4607     uptr = dptr->units + j;
4608     if (!(uptr->flags & UNIT_DIS))                      /* count enabled units */
4609         ucnt++;
4610     else if (uptr->flags & UNIT_DISABLE)
4611         udbl++;                                         /* count user-disabled */
4612     }
4613 //show_all_mods (st, dptr, dptr->units, MTAB_VDV, &toks); /* show dev mods */
4614 if (dptr->numunits == 0) {
4615     // if (toks) //-V547
4616     //     (void)fprintf (st, "\r\n");
4617 }
4618  else
4619 {
4620     if (ucnt == 0) {
4621         fprint_sep (st, &toks);
4622         (void)fprintf (st, "all units disabled\r\n");
4623         }
4624     else if ((ucnt + udbl) == 1) {
4625         fprint_sep (st, &toks);
4626         (void)fprintf (st, " 1 unit\r\n");
4627         }
4628     else if ((ucnt > 1) || (udbl > 0)) {
4629         fprint_sep (st, &toks);
4630         (void)fprintf (st, "%2.d units\r\n", ucnt + udbl);
4631         }
4632     else
4633         if ((flag != 2) || !dptr->description || toks)
4634             (void)fprintf (st, "\r\n");
4635     toks = 0;
4636 }
4637 if (flag)                                               /* dev only? */
4638     return SCPE_OK;
4639 for (j = 0; j < dptr->numunits; j++) {                  /* loop thru units */
4640     uptr = dptr->units + j;
4641     if ((uptr->flags & UNIT_DIS) == 0)
4642         show_unit (st, dptr, uptr, ucnt + udbl);
4643     }
4644 }
4645 return SCPE_OK;
4646 }
4647 
4648 void fprint_sep (FILE *st, int32 *tokens)
     /* [previous][next][first][last][top][bottom][index][help] */
4649 {
4650 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4651 *tokens += 1;
4652 }
4653 
4654 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4655 {
4656 int32 u = (int32)(uptr - dptr->units);
4657 int32 toks = 0;
4658 
4659 if (flag > 1)
4660     (void)fprintf (st, "   %s%d\r\n", sim_dname (dptr), u);
4661 else if (flag < 0)
4662     (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4663 if (uptr->flags & UNIT_ATT) {
4664     fprint_sep (st, &toks);
4665     (void)fprintf (st, "status   : attached to %s", uptr->filename);
4666     if (uptr->flags & UNIT_RO)
4667         (void)fprintf (st, ", read only");
4668     }
4669 else {
4670     if (uptr->flags & UNIT_ATTABLE) {
4671         fprint_sep (st, &toks);
4672         (void)fprintf (st, "status   : not attached");
4673         }
4674     }
4675 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4676     fprint_sep (st, &toks);
4677     fprint_capac (st, dptr, uptr);
4678     }
4679 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);        /* show unit mods */
4680 if (toks || (flag < 0) || (flag > 1))
4681     (void)fprintf (st, "\r\n");
4682 return SCPE_OK;
4683 }
4684 
4685 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4686 {
4687 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4688 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4689 t_offset mval;
4690 t_offset psize = (t_offset)uptr->capac;
4691 char *scale, *width;
4692 
4693 if (sim_switches & SWMASK ('B'))
4694     kval = 1024;
4695 mval = kval * kval;
4696 if (dptr->flags & DEV_SECTORS) {
4697     kval = kval / 512;
4698     mval = mval / 512;
4699     }
4700 if ((dptr->dwidth / dptr->aincr) > 8)
4701     width = "W";
4702 else
4703     width = "B";
4704 if ((psize < (kval * 10)) &&
4705     (0 != (psize % kval))) {
4706     scale = "";
4707     }
4708 else if ((psize < (mval * 10)) &&
4709          (0 != (psize % mval))){
4710     scale = "K";
4711     psize = psize / kval;
4712     }
4713 else {
4714     scale = "M";
4715     psize = psize / mval;
4716     }
4717 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4718 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4719 return capac_buf;
4720 }
4721 
4722 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4723 {
4724 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4725 }
4726 
4727 /* Show <global name> processors  */
4728 
4729 extern void print_default_base_system_script (void);
4730 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] */
4731 {
4732 #if !defined(PERF_STRIP)
4733   print_default_base_system_script();
4734 #endif /* if !defined(PERF_STRIP) */
4735   return 0;
4736 }
4737 
4738 static void printp (unsigned char * PROM, char * label, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4739   sim_printf (" %s ", label);
4740   sim_printf ("   %2d     %3o(8)     '", length, offset);
4741   for (int l = 0; l < length; l ++)
4742     {
4743       unsigned int byte = PROM[offset + l];
4744       if (byte == 255)
4745         {
4746           byte = ' ';
4747         }
4748       sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4749     }
4750   sim_printf ("'\r\n");
4751 }
4752 
4753 static void strip_spaces(char* str) {
     /* [previous][next][first][last][top][bottom][index][help] */
4754   int i, x;
4755   for (i=x=0; str[i]; ++i)
4756     {
4757       if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)]))) //-V781
4758         {
4759           str[x++] = str[i];
4760         }
4761     }
4762   str[x] = '\0';
4763   i = -1;
4764   x = 0;
4765   while (str[x] != '\0')
4766     {
4767       if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4768         {
4769           i=x;
4770         }
4771       x++;
4772     }
4773   str[i+1] = '\0';
4774 }
4775 
4776 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4777   char sx[1024];
4778   sx[1023] = '\0';
4779   unsigned int lastbyte = 0;
4780   for (int l = 0; l < length; l ++)
4781     {
4782       unsigned int byte = PROM[offset + l];
4783       if (byte == 255)
4784         {
4785           byte = 20;
4786         }
4787       if ((lastbyte != 20) && (byte != 20))
4788         {
4789           (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4790         }
4791       lastbyte = byte;
4792     }
4793   strip_spaces(sx);
4794   (void)fprintf (st, "%s", sx);
4795 }
4796 
4797 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4798 {
4799   unsigned char PROM[1024];
4800   setupPROM (0, PROM);
4801 
4802   sim_printf (" PROM size: %llu bytes\r\n",
4803               (long long unsigned)sizeof(PROM));
4804   sim_printf (" PROM initialization data:\r\n\r\n");
4805 
4806   sim_printf ("     Field Description      Length   Offset              Contents\r\n");
4807   sim_printf (" ========================= ======== ======== ==================================\r\n");
4808   sim_printf ("\r\n");
4809 
4810   //                      Field                 Offset       Length
4811   //             -------------------------    ----------   ----------
4812   printp (PROM, "CPU Model                ",       0,          11);
4813   printp (PROM, "CPU Serial               ",      11,          11);
4814   printp (PROM, "Ship Date                ",      22,           6);
4815   printp (PROM, "PROM Layout Version      ",      60,           1);
4816   printp (PROM, "Release Git Commit Date  ",      70,          10);
4817   printp (PROM, "Release Major            ",      80,           3);
4818   printp (PROM, "Release Minor            ",      83,           3);
4819   printp (PROM, "Release Patch            ",      86,           3);
4820   printp (PROM, "Release Iteration        ",      89,           3);
4821   printp (PROM, "Release Build Number     ",      92,           8);  /* Reserved */
4822   printp (PROM, "Release Type             ",     100,           1);
4823   printp (PROM, "Release Version Text     ",     101,          29);
4824   printp (PROM, "Build Architecture       ",     130,          20);
4825   printp (PROM, "Build Operating System   ",     150,          20);
4826   printp (PROM, "Target Architecture      ",     170,          20);
4827   printp (PROM, "Target Operating System  ",     190,          20);
4828 
4829   sim_printf("\r\n");
4830   return 0;
4831 }
4832 
4833 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4834 {
4835     (void)fprintf (st, "\r Build Information:\r\n");
4836 #if defined(BUILDINFO_scp)
4837     (void)fprintf (st, "\r\n      Compilation info: %s\r\n", BUILDINFO_scp );
4838 #else
4839     (void)fprintf (st, "\r\n      Compilation info: Not available\r\n" );
4840 #endif
4841 #if !defined(__CYGWIN__)
4842 # if !defined(__APPLE__)
4843 #  if !defined(_AIX)
4844 #   if !defined(__MINGW32__)
4845 #    if !defined(__MINGW64__)
4846 #     if !defined(CROSS_MINGW32)
4847 #      if !defined(CROSS_MINGW64)
4848 #       if !defined(_WIN32)
4849 #        if !defined(__HAIKU__)
4850 #         if !defined(__QNX__)
4851     (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4852     if (dl_iterate_phdr_callback_called)
4853         (void)fprintf (st, "\r\n");
4854     dl_iterate_phdr_callback_called = 0;
4855 #         endif
4856 #        endif
4857 #       endif
4858 #      endif
4859 #     endif
4860 #    endif
4861 #   endif
4862 #  endif
4863 # endif
4864 #endif
4865 #if defined(UV_VERSION_MAJOR) && \
4866     defined(UV_VERSION_MINOR) && \
4867     defined(UV_VERSION_PATCH)
4868 # if defined(UV_VERSION_MAJOR)
4869 #  if !defined(UV_VERSION_MINOR) && \
4870       !defined(UV_VERSION_PATCH) && \
4871       !defined(UV_VERSION_SUFFIX)
4872     (void)fprintf (st, "\r\n    Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4873 #  endif /* if !defined(UV_VERSION_MINOR) && !defined(UV_VERSION_PATCH) && defined(UV_VERSION_SUFFIX) */
4874 #  if defined(UV_VERSION_MINOR)
4875 #   if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4876     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4877                    UV_VERSION_MINOR);
4878 #   endif /* if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX) */
4879 #   if defined(UV_VERSION_PATCH)
4880 #    if !defined(UV_VERSION_SUFFIX)
4881     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4882                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4883 #    endif /* if !defined(UV_VERSION_SUFFIX) */
4884 #    if defined(UV_VERSION_SUFFIX)
4885     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4886                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4887 #     if defined(UV_VERSION_IS_RELEASE)
4888 #      if UV_VERSION_IS_RELEASE == 1
4889 #       define UV_RELEASE_TYPE " (release)"
4890 #      endif /* if UV_VERSION_IS_RELEASE == 1 */
4891 #      if UV_VERSION_IS_RELEASE == 0
4892 #       define UV_RELEASE_TYPE "-dev"
4893 #      endif /* if UV_VERSION_IS_RELEASE == 0 */
4894 #      if !defined(UV_RELEASE_TYPE)
4895 #       define UV_RELEASE_TYPE ""
4896 #      endif /* if !defined(UV_RELEASE_TYPE) */
4897 #      if defined(UV_RELEASE_TYPE)
4898     (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4899 #      endif /* if defined(UV_RELEASE_TYPE) */
4900 #     endif /* if defined(UV_VERSION_IS_RELEASE) */
4901 #    endif /* if defined(UV_VERSION_SUFFIX) */
4902 #   endif /* if defined(UV_VERSION_PATCH) */
4903 #  endif /* if defined(UV_VERSION_MINOR) */
4904     unsigned int CurrentUvVersion = uv_version();
4905     if (CurrentUvVersion > 0)
4906         if (uv_version_string() != NULL)
4907             (void)fprintf (st, "; %s in use", uv_version_string());
4908 # endif /* if defined(UV_VERSION_MAJOR) */
4909 #else
4910     (void)fprintf (st, "\r\n    Event loop library: Using libuv (or compatible) library, unknown version");
4911 #endif /* if defined(UV_VERSION_MAJOR) &&  \
4912         *    defined(UV_VERSION_MINOR) &&  \
4913         *    defined(UV_VERSION_PATCH)     \
4914         */
4915     (void)fprintf (st, "\r\n   Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4916                    SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4917                    SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4918                    sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4919 #if defined(DECNUMBERLOC)
4920 # if defined(DECVERSION)
4921 #  if defined(DECVERSEXT)
4922     (void)fprintf (st, "\r\n          Math library: %s-%s", DECVERSION, DECVERSEXT);
4923 #  else
4924 #   if defined(DECNLAUTHOR)
4925     (void)fprintf (st, "\r\n          Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4926 #   else
4927     (void)fprintf (st, "\r\n          Math library: %s", DECVERSION);
4928 #   endif /* if defined(DECNLAUTHOR) */
4929 #  endif /* if defined(DECVERSEXT) */
4930 # else
4931     (void)fprintf (st, "\r\n          Math library: decNumber, unknown version");
4932 # endif /* if defined(DECVERSION) */
4933 #endif /* if defined(DECNUMBERLOC) */
4934 #if defined(LOCKLESS)
4935     (void)fprintf (st, "\r\n     Atomic operations: ");
4936 # if defined(AIX_ATOMICS)
4937     (void)fprintf (st, "C11 and IBM AIX-style");
4938 # elif defined(BSD_ATOMICS)
4939     (void)fprintf (st, "C11 and FreeBSD-style");
4940 # elif defined(GNU_ATOMICS)
4941     (void)fprintf (st, "C11 and GNU-style");
4942 # elif defined(SYNC_ATOMICS)
4943     (void)fprintf (st, "C11 and GNU sync-style");
4944 # elif defined(ISO_ATOMICS)
4945     (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4946 # elif defined(NT_ATOMICS)
4947     (void)fprintf (st, "C11 and Windows NT interlocked operations");
4948 # endif
4949 #endif /* if defined(LOCKLESS) */
4950     (void)fprintf (st, "\r\n          File locking: ");
4951 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4952     (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4953 #endif
4954 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4955     (void)fprintf (st, "POSIX-style fcntl() locking");
4956 #endif
4957 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4958     (void)fprintf (st, "BSD-style flock() locking");
4959 #endif
4960 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4961     (void)fprintf (st, "No file locking available");
4962 #endif
4963 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64) || defined(__CYGWIN__)
4964     (void)fprintf (st, "\r\n       Windows support: ");
4965 #endif
4966 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4967 # if defined(__MINGW64_VERSION_STR)
4968     (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
4969 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
4970     (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
4971 # else
4972     (void)fprintf (st, "Built with MinGW");
4973 # endif
4974 
4975 # if defined(MINGW_CRT)
4976     (void)fprintf (st, "; %s", MINGW_CRT);
4977 #  if !defined(_UCRT)
4978 #   if defined(__MSVCRT_VERSION__)
4979 #    if __MSVCRT_VERSION__ > 0x00
4980     (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
4981 #    endif
4982 #   endif
4983 #  else
4984 
4985     struct UCRTVersion ucrtversion;
4986     int result = GetUCRTVersion (&ucrtversion);
4987 
4988     if (result == 0)
4989       (void)fprintf (st, " %u.%u.%u.%u",
4990                      ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
4991                      ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
4992 #  endif
4993     (void)fprintf (st, " in use");
4994 # endif
4995 #elif defined(__CYGWIN__)
4996     struct utsname utsname;
4997     (void)fprintf (st, "Built with Cygwin %d.%d.%d",
4998                    CYGWIN_VERSION_DLL_MAJOR / 1000,
4999                    CYGWIN_VERSION_DLL_MAJOR % 1000,
5000                    CYGWIN_VERSION_DLL_MINOR);
5001     if (uname(&utsname) == 0)
5002       fprintf (st, "; %s in use", utsname.release);
5003 #endif
5004 
5005     (void)fprintf (st, "\r\n");
5006     return 0;
5007 }
5008 
5009 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5010 {
5011 const char *arch = "";
5012 char *whydirty = " ";
5013 int dirty = 0;
5014 
5015 if (cptr && (*cptr != 0))
5016     return SCPE_2MARG;
5017 if (flag) {
5018         (void)fprintf (st, " %s Simulator:", sim_name);
5019 #if defined(USE_DUMA)
5020 # undef NO_SUPPORT_VERSION
5021 # define NO_SUPPORT_VERSION 1
5022         nodist++;
5023 #endif /* if defined(USE_DUMA) */
5024 #if defined(NO_SUPPORT_VERSION) ||  \
5025     defined(WITH_SOCKET_DEV)    ||  \
5026     defined(WITH_ABSI_DEV)      ||  \
5027     defined(WITH_MGP_DEV)       ||  \
5028     defined(TESTING)            ||  \
5029     defined(ISOLTS)             ||  \
5030     defined(USE_DUMA)
5031 # if !defined(NO_SUPPORT_VERSION)
5032 #  define NO_SUPPORT_VERSION 1
5033 # endif /* if !defined(NO_SUPPORT_VERSION) */
5034 #endif
5035 #if defined(NO_SUPPORT_VERSION)
5036         dirty++;
5037 #endif
5038 #if defined(GENERATED_MAKE_VER_H)
5039 # if defined(VER_H_GIT_VERSION)
5040 
5041         /* Dirty if git source is dirty */
5042         if (strstr(VER_H_GIT_VERSION, "*"))
5043           {
5044                 dirty++;
5045           }
5046 
5047         /* Dirty if version contains "X", "D", "A", or "B" */
5048         if ((strstr(VER_H_GIT_VERSION, "X")) ||  \
5049             (strstr(VER_H_GIT_VERSION, "D")) ||  \
5050             (strstr(VER_H_GIT_VERSION, "A")) ||  \
5051             (strstr(VER_H_GIT_VERSION, "B")))
5052           {
5053                 dirty++;
5054           }
5055 
5056         /* Why? */
5057         if (dirty) //-V547
5058           {
5059             if ((strstr(VER_H_GIT_VERSION, "X")))
5060               {
5061                     whydirty = " ";
5062               }
5063             else if ((strstr(VER_H_GIT_VERSION, "D")))
5064               {
5065                     whydirty = " DEV ";
5066               }
5067             else if ((strstr(VER_H_GIT_VERSION, "A")))
5068               {
5069                     whydirty = " ALPHA ";
5070               }
5071             else if ((strstr(VER_H_GIT_VERSION, "B")))
5072               {
5073                     whydirty = " BETA ";
5074               }
5075           }
5076 
5077 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5078 #   if defined(VER_H_GIT_HASH)
5079 #    if VER_H_GIT_PATCH_INT < 1
5080     (void)fprintf (st, "\r\n   Version: %s (%ld-bit)\r\n    Commit: %s",
5081                    VER_H_GIT_VERSION,
5082                    (long)(CHAR_BIT*sizeof(void *)),
5083                    VER_H_GIT_HASH);
5084 #    else
5085 #     define NO_SUPPORT_VERSION 1
5086     (void)fprintf (st, "\r\n   Version: %s+%s (%ld-bit)\r\n    Commit: %s",
5087                    VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5088                    (long)(CHAR_BIT*sizeof(void *)),
5089                    VER_H_GIT_HASH);
5090 #    endif
5091 #   else
5092 #    if VER_H_GIT_PATCH_INT < 1
5093         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)",
5094                        VER_H_GIT_VERSION,
5095                        (long)(CHAR_BIT*sizeof(void *)));
5096 #    else
5097 #     define NO_SUPPORT_VERSION 1
5098         (void)fprintf (st, "\r\n   Version: %s+%s (%ld-bit)",
5099                        VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5100                        (long)(CHAR_BIT*sizeof(void *)));
5101 #    endif
5102 #   endif
5103 #  else
5104 #   if defined(VER_H_GIT_HASH)
5105         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)\r\n    Commit: %s",
5106                        VER_H_GIT_VERSION,
5107                        (long)(CHAR_BIT*sizeof(void *)),
5108                        VER_H_GIT_HASH);
5109 #   else
5110         (void)fprintf (st, "\r\n   Version: %s (%ld-bit)",
5111                        VER_H_GIT_VERSION,
5112                        (long)(CHAR_BIT*sizeof(void *)));
5113 #   endif
5114 #  endif
5115 # endif
5116 #endif
5117 
5118 /* TESTING */
5119 #if defined(TESTING)
5120     (void)fprintf (st, "\r\n   Options: ");
5121 # if !defined(HAVE_DPSOPT)
5122 #  define HAVE_DPSOPT 1
5123 # endif
5124     (void)fprintf (st, "TESTING");
5125 #endif /* if defined(TESTING) */
5126 
5127 /* ISOLTS */
5128 #if defined(ISOLTS)
5129 # if defined(HAVE_DPSOPT)
5130     (void)fprintf (st, ", ");
5131 # else
5132     (void)fprintf (st, "\r\n   Options: ");
5133 # endif
5134 # if !defined(HAVE_DPSOPT)
5135 #  define HAVE_DPSOPT 1
5136 # endif
5137     (void)fprintf (st, "ISOLTS");
5138 #endif /* if defined(ISOLTS) */
5139 
5140 /* NEED_128 */
5141 #if defined(NEED_128)
5142 # if defined(HAVE_DPSOPT)
5143     (void)fprintf (st, ", ");
5144 # else
5145     (void)fprintf (st, "\r\n   Options: ");
5146 # endif
5147 # if !defined(HAVE_DPSOPT)
5148 #  define HAVE_DPSOPT 1
5149 # endif
5150     (void)fprintf (st, "NEED_128");
5151 #endif /* if defined(NEED_128) */
5152 
5153 /* WAM */
5154 #if defined(WAM)
5155 # if defined(HAVE_DPSOPT)
5156     (void)fprintf (st, ", ");
5157 # else
5158     (void)fprintf (st, "\r\n   Options: ");
5159 # endif
5160 # if !defined(HAVE_DPSOPT)
5161 #  define HAVE_DPSOPT 1
5162 # endif
5163     (void)fprintf (st, "WAM");
5164 #endif /* if defined(WAM) */
5165 
5166 /* NO_LOCKLESS */
5167 #if !defined(LOCKLESS)
5168 # if defined(HAVE_DPSOPT)
5169     (void)fprintf (st, ", ");
5170 # else
5171     (void)fprintf (st, "\r\n   Options: ");
5172 # endif
5173 # if !defined(HAVE_DPSOPT)
5174 #  define HAVE_DPSOPT 1
5175 # endif
5176     (void)fprintf (st, "NO_LOCKLESS");
5177 #endif /* if !defined(LOCKLESS) */
5178 
5179 /* PANEL68 */
5180 #if defined(PANEL68)
5181 # if defined(HAVE_DPSOPT)
5182     (void)fprintf (st, ", ");
5183 # else
5184     (void)fprintf (st, "\r\n Options: ");
5185 # endif
5186 # if !defined(HAVE_DPSOPT)
5187 #  define HAVE_DPSOPT 1
5188 # endif
5189     (void)fprintf (st, "PANEL68");
5190 #endif /* if defined(PANEL68) */
5191 
5192 /* ABSI */  /* XXX: Change to NO_ABSI once code is non-experimental */
5193 #if defined(WITH_ABSI_DEV)
5194 # if defined(HAVE_DPSOPT)
5195     (void)fprintf (st, ", ");
5196 # else
5197     (void)fprintf (st, "\r\n   Options: ");
5198 # endif
5199 # if !defined(HAVE_DPSOPT)
5200 #  define HAVE_DPSOPT 1
5201 # endif
5202     (void)fprintf (st, "ABSI");
5203 #endif /* if defined(WITH_ABSI_DEV) */
5204 
5205 /* SOCKET */  /* XXX: Change to NO_SOCKET once code is non-experimental */
5206 #if defined(WITH_SOCKET_DEV)
5207 # if defined(HAVE_DPSOPT)
5208     (void)fprintf (st, ", ");
5209 # else
5210     (void)fprintf (st, "\r\n   Options: ");
5211 # endif
5212 # if !defined(HAVE_DPSOPT)
5213 #  define HAVE_DPSOPT 1
5214 # endif
5215     (void)fprintf (st, "SOCKET");
5216 #endif /* if defined(WITH_SOCKET_DEV) */
5217 
5218 /* CHAOSNET */  /* XXX: Change to NO_CHAOSNET once code is non-experimental */
5219 #if defined(WITH_MGP_DEV)
5220 # if defined(HAVE_DPSOPT)
5221     (void)fprintf (st, ", ");
5222 # else
5223     (void)fprintf (st, "\r\n   Options: ");
5224 # endif
5225 # if !defined(HAVE_DPSOPT)
5226 #  define HAVE_DPSOPT 1
5227 # endif
5228     (void)fprintf (st, "CHAOSNET");
5229 # if USE_SOCKET_DEV_APPROACH
5230     (void)fprintf (st, "-S");
5231 # endif /* if USE_SOCKET_DEV_APPROACH */
5232 #endif /* if defined(WITH_MGP_DEV) */
5233 
5234 /* DUMA */
5235 #if defined(USE_DUMA)
5236 # if defined(HAVE_DPSOPT)
5237     (void)fprintf (st, ", ");
5238 # else
5239     (void)fprintf (st, "\r\n   Options: ");
5240 # endif
5241 # if !defined(HAVE_DPSOPT)
5242 #  define HAVE_DPSOPT 1
5243 # endif
5244     (void)fprintf (st, "DUMA");
5245 #endif /* if defined(USE_DUMA) */
5246 
5247 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5248 # if defined(NO_SUPPORT_VERSION)
5249     (void)fprintf (st, "\r\n  Modified: %s", VER_H_GIT_DATE);
5250 # else
5251     (void)fprintf (st, "\r\n  Released: %s", VER_H_GIT_DATE);
5252 # endif
5253 #endif
5254 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5255     (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5256 #endif
5257 #if defined(VER_CURRENT_TIME)
5258     (void)fprintf (st, "\r\n  Compiled: %s", VER_CURRENT_TIME);
5259 #endif
5260     if (dirty) //-V547
5261       {
5262         (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5263       }
5264     (void)fprintf (st, "\r\n\r\n Build Information:");
5265 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5266     char build_os_version_raw[255];
5267     char build_os_arch_raw[255];
5268     (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5269     (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5270     char *build_os_version = strdup(build_os_version_raw);
5271     if (!build_os_version)
5272       {
5273         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5274                        __func__, __FILE__, __LINE__);
5275 # if defined(USE_BACKTRACE)
5276 #  if defined(SIGUSR2)
5277         (void)raise(SIGUSR2);
5278         /*NOTREACHED*/ /* unreachable */
5279 #  endif /* if defined(SIGUSR2) */
5280 # endif /* if defined(USE_BACKTRACE) */
5281         abort();
5282       }
5283     char *build_os_arch = strdup(build_os_arch_raw);
5284     if (!build_os_arch)
5285       {
5286         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5287                        __func__, __FILE__, __LINE__);
5288 # if defined(USE_BACKTRACE)
5289 #  if defined(SIGUSR2)
5290         (void)raise(SIGUSR2);
5291         /*NOTREACHED*/ /* unreachable */
5292 #  endif /* if defined(SIGUSR2) */
5293 # endif /* if defined(USE_BACKTRACE) */
5294         abort();
5295       }
5296     unsigned char SPROM[1024];
5297     setupPROM (0, SPROM);
5298     (void)fprintf (st, "\r\n    Target: ");
5299     printpq (SPROM, st, 190, 20);
5300     if (SPROM[170] != 20)
5301       {
5302         if (SPROM[170] != 255)
5303           {
5304             (void)fprintf (st, " on ");
5305             printpq (SPROM, st, 170, 20);
5306           }
5307       }
5308     strtrimspace(build_os_version, build_os_version_raw);
5309     strtrimspace(build_os_arch, build_os_arch_raw);
5310     (void)fprintf (st, "\r\n  Build OS: %s %s", build_os_version, build_os_arch);
5311     FREE(build_os_version);
5312     FREE(build_os_arch);
5313 #endif
5314 #if defined(__VERSION__)
5315     char gnumver[2];
5316     char postver[1024];
5317     (void)sprintf(gnumver, "%.1s", __VERSION__);
5318     (void)sprintf(postver, "%.1023s", __VERSION__);
5319     strremove(postver, "(TM)");
5320     strremove(postver, "(R)");
5321     strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5322     strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5323     strremove(postver, " gcc 4.9 mode");
5324     strremove(postver, "4.2.1 Compatible ");
5325     strremove(postver, "git@github.com:llvm/llvm-project.git ");
5326     strremove(postver, "https://github.com/llvm/llvm-project.git ");
5327     strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5328     strremove(postver, "https://github.com/yrnkrn/zapcc ");
5329     strremove(postver, "(experimental) ");
5330     strremove(postver, ".module+el8.7.0+20823+214a699d");
5331     strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5332     strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5333     strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5334     strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5335     strremove(postver, "llvmorg-16.0.6-0-");
5336     strremove(postver, " Clang 15.0.0 (build 760095e)");
5337     strremove(postver, " Clang 15.0.0 (build 6af5742)");
5338     strremove(postver, " Clang 15.0.0 (build ca7115e)");
5339     strremove(postver, " Clang 15.0.0 (build 232543c)");
5340     strremove(postver, " Clang 17.0.6 (build 19a779f)");
5341     strremove(postver, "CLANG: ");
5342 #endif
5343 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5344 # if !defined(__clang_version__)
5345     if (isdigit((unsigned char)gnumver[0])) {
5346         (void)fprintf (st, "\r\n  Compiler: GCC %s", postver);
5347     } else {
5348         (void)fprintf (st, "\r\n  Compiler: %s", postver);
5349     }
5350 # endif
5351 # if defined(__clang_analyzer__ )
5352     (void)fprintf (st, "\r\n  Compiler: Clang C/C++ Static Analyzer");
5353 # elif defined(__clang_version__) && defined(__VERSION__)
5354     char clangllvmver[1024];
5355     (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5356     strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5357     strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5358     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5359     strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5360     strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5361     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5362     strremove(clangllvmver, " ( )");
5363     strremove(clangllvmver, " ()");
5364     if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5365         (void)fprintf (st, "\r\n  Compiler: Clang %s", clangllvmver);
5366     } else {
5367         (void)fprintf (st, "\r\n  Compiler: %s", postver);
5368     }
5369 # elif defined(__clang_version__)
5370     (void)fprintf (st, "\r\n  Compiler: %s", postver);
5371 # endif
5372 #elif defined(__PGI) && !defined(__NVCOMPILER)
5373     (void)fprintf (st, "\r\n  Compiler: Portland Group, Inc. (PGI) C Compiler ");
5374 # if defined(__PGIC__)
5375     (void)fprintf (st, "%d", __PGIC__);
5376 #  if defined(__PGIC_MINOR__)
5377     (void)fprintf (st, ".%d", __PGIC_MINOR__);
5378 #   if defined(__PGIC_PATCHLEVEL__)
5379     (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5380 #   endif
5381 #  endif
5382 # endif
5383 #elif defined(__NVCOMPILER)
5384     (void)fprintf (st, "\r\n  Compiler: NVIDIA HPC SDK C Compiler ");
5385 # if defined(__NVCOMPILER_MAJOR__)
5386     (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5387 #  if defined(__NVCOMPILER_MINOR__)
5388     (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5389 #   if defined(__NVCOMPILER_PATCHLEVEL__)
5390     (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5391 #   endif
5392 #  endif
5393 # endif
5394 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5395     (void)fprintf (st, "\r\n  Compiler: Microsoft C %d.%02d.%05d.%02d",
5396                    _MSC_FULL_VER/10000000,
5397                    (_MSC_FULL_VER/100000)%100,
5398                    _MSC_FULL_VER%100000,
5399                    _MSC_BUILD);
5400 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5401 # if defined(_AIX) && defined(__PASE__)
5402     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5403 # endif
5404 # if defined(_AIX) && !defined(__PASE__)
5405     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5406 # endif
5407 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5408     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5409 # endif
5410 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5411 #  if defined(__PPC__) && defined(__APPLE__)
5412     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5413 #  else
5414     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s", __xlc__);
5415 #  endif
5416 # endif
5417 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5418 # define VER_ENC(maj, min, rev) \
5419   (((maj) * 1000000) + ((min) * 1000) + (rev))
5420 # define VER_DEC_MAJ(ver) \
5421   ((ver) / 1000000)
5422 # define VER_DEC_MIN(ver) \
5423   (((ver) % 1000000) / 1000)
5424 # define VER_DEC_REV(ver) \
5425   ((ver) % 1000)
5426 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5427 #  define COMP_VER VER_ENC(                                        \
5428    (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5429    (((__SUNPRO_C >>  8) & 0xf) * 10) + ((__SUNPRO_C >>  4) & 0xf), \
5430      (__SUNPRO_C & 0xf) * 10)
5431 # elif defined(__SUNPRO_C)
5432 #  define COMP_VER VER_ENC(    \
5433      (__SUNPRO_C >>  8) & 0xf, \
5434      (__SUNPRO_C >>  4) & 0xf, \
5435      (__SUNPRO_C) & 0xf)
5436 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5437 #  define COMP_VER VER_ENC(                                          \
5438    (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5439    (((__SUNPRO_CC >>  8) & 0xf) * 10) + ((__SUNPRO_CC >>  4) & 0xf), \
5440      (__SUNPRO_CC & 0xf) * 10)
5441 # elif defined(__SUNPRO_CC)
5442 #  define COMP_VER VER_ENC(     \
5443      (__SUNPRO_CC >>  8) & 0xf, \
5444      (__SUNPRO_CC >>  4) & 0xf, \
5445      (__SUNPRO_CC) & 0xf)
5446 # endif
5447 # if !defined(COMP_VER)
5448 #  define COMP_VER 0
5449 # endif
5450     (void)fprintf (st, "\r\n  Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5451                    VER_DEC_MAJ(COMP_VER),
5452                    VER_DEC_MIN(COMP_VER),
5453                    VER_DEC_REV(COMP_VER));
5454 #elif defined(__DMC__)
5455     (void)fprintf (st, "\r\n  Compiler: Digital Mars C/C++");
5456 #elif defined(__PCC__)
5457     (void)fprintf (st, "\r\n  Compiler: Portable C Compiler");
5458 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5459     (void)fprintf (st, "\r\n  Compiler: Plan 9 Compiler Suite");
5460 #elif defined(__ACK__)
5461     (void)fprintf (st, "\r\n  Compiler: Amsterdam Compiler Kit");
5462 #elif defined(__COMO__)
5463     (void)fprintf (st, "\r\n  Compiler: Comeau C++");
5464 #elif defined(__COMPCERT__)
5465     (void)fprintf (st, "\r\n  Compiler: CompCert C");
5466 #elif defined(__COVERITY__)
5467     (void)fprintf (st, "\r\n  Compiler: Coverity C/C++ Static Analyzer");
5468 #elif defined(__LCC__)
5469 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5470     (void)fprintf (st, "\r\n  Compiler: MCST Elbrus C Compiler");
5471 #  if __LCC__ > 99
5472     (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5473 #   if defined(__LCC_MINOR__)
5474 #    if __LCC_MINOR__ > 0
5475     (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5476 #    endif
5477 #   endif
5478 #  endif
5479 #  if defined(__EDG__) && defined(__EDG_VERSION__)
5480 #   if __EDG_VERSION__ > 99
5481     (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5482                   (int)(((__EDG_VERSION__) % 100) % 10));
5483 #   endif
5484 #  endif
5485 # else
5486     (void)fprintf (st, "\r\n  Compiler: Local/Little C Compiler (lcc)");
5487 # endif
5488 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5489     (void)fprintf (st, "\r\n  Compiler: SGI MIPSpro");
5490 #elif defined(__OPEN64__)
5491     (void)fprintf (st, "\r\n  Compiler: Open64 %s", __OPEN64__);
5492 #elif defined(__PGI) || defined(__PGIC__)
5493     (void)fprintf (st, "\r\n  Compiler: Portland Group/PGI C/C++");
5494 #elif defined(__VBCC__)
5495     (void)fprintf (st, "\r\n  Compiler: Volker Barthelmann C Compiler (vbcc)");
5496 #elif defined(__WATCOMC__)
5497     (void)fprintf (st, "\r\n  Compiler: Watcom C/C++ %d.%d",
5498                    __WATCOMC__ / 100,
5499                    __WATCOMC__ % 100);
5500 #elif defined(__xlC__)
5501     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++");
5502 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5503 # if defined(__INTEL_COMPILER_UPDATE)
5504 #  if defined(__INTEL_COMPILER_BUILD_DATE)
5505     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d.%d (%d)",
5506                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5507                    __INTEL_COMPILER_BUILD_DATE);
5508 #  else
5509     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d.%d",
5510                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5511 #  endif
5512 # else
5513     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d",
5514                    __INTEL_COMPILER);
5515 # endif
5516 #elif defined(SIM_COMPILER)
5517 # define S_xstr(a) S_str(a)
5518 # define S_str(a) #a
5519     (void)fprintf (st, "\r\n  Compiler: %s", S_xstr(SIM_COMPILER));
5520 # undef S_str
5521 # undef S_xstr
5522 #else
5523     (void)fprintf (st, "\r\n  Compiler: Unknown");
5524 #endif
5525 
5526 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5527     defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5528 # define SC_IS_PPC64 1
5529 #else
5530 # define SC_IS_PPC64 0
5531 #endif
5532 
5533 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5534     defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5535     defined(__PPC32)
5536 # define SC_IS_PPC32 1
5537 #else
5538 # define SC_IS_PPC32 0
5539 #endif
5540 
5541 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5542     arch = " x86_64";
5543 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5544     arch = " x86";
5545 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5546     arch = " arm64";
5547 #elif defined(_M_ARM) || defined(__arm__)
5548     arch = " arm";
5549 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5550     arch = " ia64";
5551 #elif SC_IS_PPC64
5552     arch = " powerpc64";
5553 #elif SC_IS_PPC32
5554     arch = " powerpc";
5555 #elif defined(__s390x__)
5556     arch = " s390x";
5557 #elif defined(__s390__)
5558     arch = " s390";
5559 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5560     arch = " j2";
5561 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5562     arch = " sh4";
5563 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5564     arch = " sh2";
5565 #elif defined(__alpha__)
5566     arch = " alpha";
5567 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5568     arch = " hppa";
5569 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5570     arch = " ice9";
5571 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5572     arch = " mips64";
5573 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5574     arch = " mips";
5575 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5576       defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5577     arch = " openrisc";
5578 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5579     arch = " sparc64";
5580 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5581     arch = " sparc";
5582 #elif defined(__riscv) || defined(__riscv__)
5583     arch = " riscv";
5584 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5585     arch = " e2k";
5586 #elif defined(__myriad2__)
5587     arch = " myriad2";
5588 #elif defined(__loongarch64) || defined(__loongarch__)
5589     arch = " loongarch";
5590 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5591     arch = " m68k";
5592 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5593     arch = " m88k";
5594 #elif defined(__VAX__) || defined(__vax__)
5595     arch = " vax";
5596 #elif defined(__NIOS2__) || defined(__nios2__)
5597     arch = " nios2";
5598 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5599     arch = " microblaze";
5600 #else
5601     arch = " ";
5602 #endif
5603     (void)fprintf (st, "%s", arch);
5604 #if defined(BUILD_BY_USER)
5605         (void)fprintf (st, "\r\n  Built by: %s", BUILD_BY_USER);
5606 #else
5607 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5608         (void)fprintf (st, "\r\n  Built by: %s", VER_H_PREP_USER);
5609 # endif
5610 #endif
5611                 (void)fprintf (st, "\r\n\r\n Host System Information:");
5612 #if defined(_WIN32)
5613     if (1) {
5614         char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5615         char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5616         char osversion[PATH_MAX+1] = "";
5617         FILE *f;
5618 
5619         if ((f = _popen ("ver", "r"))) {
5620             (void)memset (osversion, 0, sizeof(osversion));
5621             do {
5622                 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5623                     break;
5624                 sim_trim_endspc (osversion);
5625                 } while (osversion[0] == '\0');
5626             _pclose (f);
5627             }
5628         (void)fprintf (st, "\r\n   Host OS: %s", osversion);
5629         (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264  : "");
5630         }
5631 #else
5632     if (1) {
5633         char osversion[2*PATH_MAX+1] = "";
5634         FILE *f;
5635 # if !defined(_AIX)
5636         if ((f = popen \
5637              ("uname -mrs 2> /dev/null", "r"))) {
5638 # else
5639         if ((f = popen \
5640              ("sh -c 'echo \"$(command -p env uname -v \
5641                2> /dev/null).$(command -p env uname -r \
5642                2> /dev/null) $(command -p env uname -p \
5643                2> /dev/null)\"' 2> /dev/null", "r"))) {
5644 # endif /* if !defined(_AIX) */
5645             (void)memset (osversion, 0, sizeof(osversion));
5646             do {
5647               if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5648                     break;
5649               }
5650             sim_trim_endspc (osversion);
5651             } while (osversion[0] == '\0');
5652             pclose (f);
5653             strremove(osversion, "0000000000000000 ");
5654             strremove(osversion, " 0000000000000000");
5655             strremove(osversion, "000000000000 ");
5656             strremove(osversion, " 000000000000");
5657             strremove(osversion, "IBM ");
5658             strremove(osversion, " (emulated by qemu)");
5659             strremove(osversion, " (emulated by QEMU)");
5660         }
5661 # if !defined(_AIX)
5662             (void)fprintf (st, "\r\n   Host OS: %s", osversion);
5663 # else
5664             strremove(osversion, "AIX ");
5665 #  if !defined(__PASE__)
5666             (void)fprintf (st, "\r\n   Host OS: IBM AIX %s", osversion);
5667 #  else
5668             (void)fprintf (st, "\r\n   Host OS: IBM OS/400 (PASE) %s", osversion);
5669 #  endif /* if !defined(__PASE__) */
5670 # endif /* if !defined(_AIX) */
5671     } else {
5672 # if !defined(_AIX)
5673         (void)fprintf (st, "\r\n   Host OS: Unknown");
5674 # else
5675 #  if !defined(__PASE__)
5676         (void)fprintf (st, "\r\n   Host OS: IBM AIX");
5677 #  else
5678         (void)fprintf (st, "\r\n   Host OS: IBM OS/400 (PASE)");
5679 #  endif /* if !defined(__PASE__) */
5680 # endif /* if !defined(_AIX) */
5681     }
5682 #endif
5683     if (nodist)
5684       {
5685         sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5686       }
5687     else
5688       {
5689         (void)fprintf (st, "\r\n");
5690         (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5691         (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5692         (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5693       }
5694         (void)fprintf (st, "\r\n");
5695     }
5696 return SCPE_OK;
5697 }
5698 
5699 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5700 {
5701 size_t i;
5702 DEVICE *dptr;
5703 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5704 
5705 if (cptr && (*cptr != 0))
5706     return SCPE_2MARG;
5707 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5708 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5709     if (!only_enabled || !qdisable (dptr))
5710         show_device (st, dptr, flag);
5711 return SCPE_OK;
5712 }
5713 
5714 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5715 {
5716 int32 i;
5717 DEVICE *dptr;
5718 
5719 if (cptr && (*cptr != 0))
5720     return SCPE_2MARG;
5721 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5722     show_dev_logicals (st, dptr, NULL, 1, cptr);
5723 return SCPE_OK;
5724 }
5725 
5726 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5727 {
5728 if (dptr->lname)
5729     (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5730 else if (!flag)
5731     fputs ("no logical name assigned\r\n", st);
5732 return SCPE_OK;
5733 }
5734 
5735 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5736 {
5737 DEVICE *dptr;
5738 UNIT *uptr;
5739 int32 accum;
5740 
5741 if (cptr && (*cptr != 0))
5742     return SCPE_2MARG;
5743 if (sim_clock_queue == QUEUE_LIST_END)
5744     (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5745                    sim_name, sim_time, sim_timer_inst_per_sec ());
5746 else {
5747     const char *tim;
5748 
5749     (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5750                    sim_name, sim_time, sim_timer_inst_per_sec ());
5751     accum = 0;
5752     for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5753         if (uptr == &sim_step_unit)
5754             (void)fprintf (st, "  Step timer");
5755         else
5756             if (uptr == &sim_expect_unit)
5757                 (void)fprintf (st, "  Expect fired");
5758             else
5759                 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5760                     (void)fprintf (st, "  %s", sim_dname (dptr));
5761                     if (dptr->numunits > 1)
5762                         (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5763                     }
5764                 else
5765                     (void)fprintf (st, "  Unknown");
5766         tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5767         (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5768                        (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5769                        (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5770         accum = accum + uptr->time;
5771         }
5772     }
5773 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5774 return SCPE_OK;
5775 }
5776 
5777 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5778 {
5779 if (cptr && (*cptr != 0))
5780     return SCPE_2MARG;
5781 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5782 return SCPE_OK;
5783 }
5784 
5785 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5786 {
5787 t_stat r;
5788 
5789 if (cptr && (*cptr != 0))
5790     r = ssh_break (st, cptr, 1);  /* more? */
5791 else
5792     r = sim_brk_showall (st, (uint32)sim_switches);
5793 return r;
5794 }
5795 
5796 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5797 {
5798 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5799 return SCPE_OK;
5800 }
5801 
5802 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5803 {
5804 int32 any = 0;
5805 DEBTAB *dep;
5806 
5807 if (dptr->flags & DEV_DEBUG) {
5808     if (dptr->dctrl == 0)
5809         fputs ("Debugging disabled", st);
5810     else if (dptr->debflags == NULL)
5811         fputs ("Debugging enabled", st);
5812     else {
5813         uint32 dctrl = dptr->dctrl;
5814 
5815         fputs ("Debug=", st);
5816         for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5817             if ((dctrl & dep->mask) == dep->mask) {
5818                 dctrl &= ~dep->mask;
5819                 if (any)
5820                     fputc (';', st);
5821                 fputs (dep->name, st);
5822                 any = 1;
5823                 }
5824             }
5825         }
5826     fputc ('\n', st);
5827     return SCPE_OK;
5828     }
5829 else return SCPE_NOFNC;
5830 }
5831 
5832 /* Show On actions */
5833 
5834 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5835 {
5836 int32 lvl, i;
5837 
5838 if (cptr && (*cptr != 0)) return SCPE_2MARG;            /* now eol? */
5839 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5840     if (lvl > 0)
5841         (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5842     else
5843         (void)fprintf(st, "On Processing for input commands");
5844     (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5845     for (i=1; i<SCPE_BASE; ++i) {
5846         if (sim_on_actions[lvl][i])
5847             (void)fprintf(st, "    on %5d    %s\r\n", i, sim_on_actions[lvl][i]); }
5848     for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5849         if (sim_on_actions[lvl][i])
5850             (void)fprintf(st, "    on %-5s    %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5851     if (sim_on_actions[lvl][0])
5852         (void)fprintf(st, "    on ERROR    %s\r\n", sim_on_actions[lvl][0]);
5853     (void)fprintf(st, "\r\n");
5854     }
5855 if (sim_on_inherit)
5856     (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5857 return SCPE_OK;
5858 }
5859 
5860 /* Show modifiers */
5861 
5862 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5863 {
5864 int32 i;
5865 DEVICE *dptr;
5866 
5867 if (cptr && (*cptr != 0))                               /* now eol? */
5868     return SCPE_2MARG;
5869 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5870     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5871 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5872     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5873 return SCPE_OK;
5874 }
5875 
5876 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5877 {
5878 fprint_set_help (st, dptr);
5879 return SCPE_OK;
5880 }
5881 
5882 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
     /* [previous][next][first][last][top][bottom][index][help] */
5883 {
5884 MTAB *mptr;
5885 t_stat r = SCPE_OK;
5886 
5887 if (dptr->modifiers == NULL)
5888     return SCPE_OK;
5889 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5890     if (mptr->pstring &&
5891         ((mptr->mask & MTAB_XTD)?
5892             (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5893             ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5894         if (*toks > 0) {
5895             (void)fprintf (st, "\r\n");
5896             *toks = 0;
5897             }
5898         if (r == SCPE_OK)
5899             fprint_sep (st, toks);
5900         r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5901         }
5902     }
5903 return SCPE_OK;
5904 }
5905 
5906 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
     /* [previous][next][first][last][top][bottom][index][help] */
5907     CONST char *cptr, int32 flag)
5908 {
5909 t_stat r = SCPE_OK;
5910 
5911 if (mptr->disp)
5912     r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5913 else
5914     fputs (mptr->pstring, st);
5915 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5916     fputc ('\n', st);
5917 return r;
5918 }
5919 
5920 /* Show show commands */
5921 
5922 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5923 {
5924 int32 i;
5925 DEVICE *dptr;
5926 
5927 if (cptr && (*cptr != 0))                               /* now eol? */
5928     return SCPE_2MARG;
5929 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5930     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5931 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5932     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5933 return SCPE_OK;
5934 }
5935 
5936 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] */
5937 {
5938 fprint_show_help (st, dptr);
5939 return SCPE_OK;
5940 }
5941 
5942 /* Breakpoint commands */
5943 
5944 t_stat brk_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5945 {
5946 GET_SWITCHES (cptr);                                    /* get switches */
5947 return ssh_break (NULL, cptr, flg);                     /* call common code */
5948 }
5949 
5950 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
     /* [previous][next][first][last][top][bottom][index][help] */
5951 {
5952 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5953 CONST char *tptr, *t1ptr;
5954 DEVICE *dptr = sim_dflt_dev;
5955 UNIT *uptr;
5956 t_stat r;
5957 t_addr lo, hi, max;
5958 int32 cnt;
5959 
5960 if (sim_brk_types == 0)
5961     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
5962 if (dptr == NULL)
5963     return SCPE_IERR;
5964 uptr = dptr->units;
5965 if (uptr == NULL)
5966     return SCPE_IERR;
5967 max = uptr->capac - 1;
5968 abuf[sizeof(abuf)-1] = '\0';
5969 strncpy (abuf, cptr, sizeof(abuf)-1);
5970 cptr = abuf;
5971 if ((aptr = strchr (abuf, ';'))) {                      /* ;action? */
5972     if (flg != SSH_ST)                                  /* only on SET */
5973         return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
5974     *aptr++ = 0;                                        /* separate strings */
5975     }
5976 if (*cptr == 0) {                                       /* no argument? */
5977     lo = (t_addr) get_rval (sim_PC, 0);                 /* use PC */
5978     return ssh_break_one (st, flg, lo, 0, aptr);
5979     }
5980 while (*cptr) {
5981     cptr = get_glyph (cptr, gbuf, ',');
5982     tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5983     if (tptr == NULL)
5984         return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
5985     if (*tptr == '[') {
5986         cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5987         if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5988             return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
5989         tptr = t1ptr + 1;
5990         }
5991     else cnt = 0;
5992     if (*tptr != 0)
5993         return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
5994     if ((lo == 0) && (hi == max)) {
5995         if (flg == SSH_CL)
5996             sim_brk_clrall (sim_switches);
5997         else
5998             if (flg == SSH_SH)
5999                 sim_brk_showall (st, (uint32)sim_switches);
6000             else
6001                 return SCPE_ARG;
6002         }
6003     else {
6004         for ( ; lo <= hi; lo = lo + 1) {
6005             r = ssh_break_one (st, flg, lo, cnt, aptr);
6006             if (r != SCPE_OK)
6007                 return r;
6008             }
6009         }
6010     }
6011 return SCPE_OK;
6012 }
6013 
6014 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] */
6015 {
6016 if (!sim_brk_types)
6017     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6018 switch (flg) {
6019     case SSH_ST:
6020         return sim_brk_set (lo, sim_switches, cnt, aptr);
6021         /*NOTREACHED*/ /* unreachable */
6022         break;
6023 
6024     case SSH_CL:
6025         return sim_brk_clr (lo, sim_switches);
6026         /*NOTREACHED*/ /* unreachable */
6027         break;
6028 
6029     case SSH_SH:
6030         return sim_brk_show (st, lo, sim_switches);
6031         /*NOTREACHED*/ /* unreachable */
6032         break;
6033 
6034     default:
6035         return SCPE_ARG;
6036     }
6037 }
6038 
6039 /* Reset command and routines */
6040 
6041 static t_bool run_cmd_did_reset = FALSE;
6042 
6043 t_stat reset_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6044 {
6045 char gbuf[CBUFSIZE];
6046 DEVICE *dptr;
6047 
6048 GET_SWITCHES (cptr);                                    /* get switches */
6049 run_cmd_did_reset = FALSE;
6050 if (*cptr == 0)                                         /* reset(cr) */
6051     return (reset_all (0));
6052 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6053 if (*cptr != 0)                                         /* now eol? */
6054     return SCPE_2MARG;
6055 if (strcmp (gbuf, "ALL") == 0)
6056     return (reset_all (0));
6057 dptr = find_dev (gbuf);                                 /* locate device */
6058 if (dptr == NULL)                                       /* found it? */
6059     return SCPE_NXDEV;
6060 if (dptr->reset != NULL)
6061     return dptr->reset (dptr);
6062 else return SCPE_OK;
6063 }
6064 
6065 /* Reset devices start..end
6066 
6067    Inputs:
6068         start   =       number of starting device
6069    Outputs:
6070         status  =       error status
6071 */
6072 
6073 t_stat reset_all (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6074 {
6075 DEVICE *dptr;
6076 uint32 i;
6077 t_stat reason;
6078 
6079 for (i = 0; i < start; i++) {
6080     if (sim_devices[i] == NULL)
6081         return SCPE_IERR;
6082     }
6083 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6084     if (dptr->reset != NULL) {
6085         reason = dptr->reset (dptr);
6086         if (reason != SCPE_OK)
6087             return reason;
6088         }
6089     }
6090 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6091     if (dptr->reset != NULL) {
6092         reason = dptr->reset (dptr);
6093         if (reason != SCPE_OK)
6094             return reason;
6095         }
6096     }
6097 return SCPE_OK;
6098 }
6099 
6100 /* Reset to powerup state
6101 
6102    Inputs:
6103         start   =       number of starting device
6104    Outputs:
6105         status  =       error status
6106 */
6107 
6108 t_stat reset_all_p (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6109 {
6110 t_stat r;
6111 int32 old_sw = sim_switches;
6112 
6113 sim_switches = SWMASK ('P');
6114 r = reset_all (start);
6115 sim_switches = old_sw;
6116 return r;
6117 }
6118 
6119 /* Attach command */
6120 
6121 t_stat attach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6122 {
6123 char gbuf[4*CBUFSIZE];
6124 DEVICE *dptr;
6125 UNIT *uptr;
6126 t_stat r;
6127 
6128 GET_SWITCHES (cptr);                                    /* get switches */
6129 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6130     return SCPE_2FARG;
6131 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6132 GET_SWITCHES (cptr);                                    /* get switches */
6133 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* now eol? */
6134     return SCPE_2FARG;
6135 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6136 if (dptr == NULL)                                       /* found dev? */
6137     return SCPE_NXDEV;
6138 if (uptr == NULL)                                       /* valid unit? */
6139     return SCPE_NXUN;
6140 if (uptr->flags & UNIT_ATT) {                           /* already attached? */
6141     if (!(uptr->dynflags & UNIT_ATTMULT) &&             /* and only single attachable */
6142         !(dptr->flags & DEV_DONTAUTO)) {                /* and auto detachable */
6143         r = scp_detach_unit (dptr, uptr);               /* detach it */
6144         if (r != SCPE_OK)                               /* error? */
6145             return r; }
6146     else {
6147         if (!(uptr->dynflags & UNIT_ATTMULT))
6148             return SCPE_ALATT;                          /* Already attached */
6149         }
6150     }
6151 gbuf[sizeof(gbuf)-1] = '\0';
6152 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6153 sim_trim_endspc (gbuf);                                 /* trim trailing spc */
6154 return scp_attach_unit (dptr, uptr, gbuf);              /* attach */
6155 }
6156 
6157 /* Call device-specific or file-oriented attach unit routine */
6158 
6159 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6160 {
6161 if (dptr->attach != NULL)                               /* device routine? */
6162     return dptr->attach (uptr, (CONST char *)cptr);     /* call it */
6163 return attach_unit (uptr, (CONST char *)cptr);          /* no, std routine */
6164 }
6165 
6166 /* Attach unit to file */
6167 
6168 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6169 {
6170 DEVICE *dptr;
6171 
6172 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6173     return SCPE_UDIS;
6174 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
6175     return SCPE_NOATT;
6176 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6177     return SCPE_NOATT;
6178 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */
6179 if (uptr->filename == NULL)
6180     return SCPE_MEM;
6181 strncpy (uptr->filename, cptr, CBUFSIZE-1);             /* save name */
6182 if ((sim_switches & SWMASK ('R')) ||                    /* read only? */
6183     ((uptr->flags & UNIT_RO) != 0)) {
6184     if (((uptr->flags & UNIT_ROABLE) == 0) &&           /* allowed? */
6185         ((uptr->flags & UNIT_RO) == 0))
6186         return attach_err (uptr, SCPE_NORO);            /* no, error */
6187     uptr->fileref = sim_fopen (cptr, "rb");             /* open rd only */
6188     if (uptr->fileref == NULL)                          /* open fail? */
6189         return attach_err (uptr, SCPE_OPENERR);         /* yes, error */
6190     uptr->flags = uptr->flags | UNIT_RO;                /* set rd only */
6191     if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6192         sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6193         }
6194     }
6195 else {
6196     if (sim_switches & SWMASK ('N')) {                  /* new file only? */
6197         uptr->fileref = sim_fopen (cptr, "wb+");        /* open new file */
6198         if (uptr->fileref == NULL)                      /* open fail? */
6199             return attach_err (uptr, SCPE_OPENERR);     /* yes, error */
6200         if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6201             sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6202             }
6203         }
6204     else {                                              /* normal */
6205         uptr->fileref = sim_fopen (cptr, "rb+");        /* open r/w */
6206         if (uptr->fileref == NULL) {                    /* open fail? */
6207 #if defined(EWOULDBLOCK)
6208             if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6209 #else
6210             if ((errno == EAGAIN))
6211 #endif
6212                 return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6213 
6214 #if defined(EPERM)
6215             if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {/* read only? */
6216 #else
6217             if ((errno == EROFS) || (errno == EACCES)) {/* read only? */
6218 #endif
6219                 if ((uptr->flags & UNIT_ROABLE) == 0)   /* allowed? */
6220                     return attach_err (uptr, SCPE_NORO);/* no error */
6221                 uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */
6222                 if (uptr->fileref == NULL)              /* open fail? */
6223                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6224                 uptr->flags = uptr->flags | UNIT_RO;    /* set rd only */
6225                 if (!sim_quiet) {
6226                     sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6227                     }
6228                 }
6229             else {                                      /* doesn't exist */
6230                 if (sim_switches & SWMASK ('E'))        /* must exist? */
6231                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6232                 uptr->fileref = sim_fopen (cptr, "wb+");/* open new file */
6233                 if (uptr->fileref == NULL)              /* open fail? */
6234                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6235                 if (!sim_quiet) {
6236                     sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6237                     }
6238                 }
6239             }                                           /* end if null */
6240         }                                               /* end else */
6241     }
6242 if (uptr->flags & UNIT_BUFABLE) {                       /* buffer? */
6243     uint32 cap = ((uint32) uptr->capac) / dptr->aincr;  /* effective size */
6244     if (uptr->flags & UNIT_MUSTBUF)                     /* dyn alloc? */
6245         uptr->filebuf = calloc (cap, SZ_D (dptr));      /* allocate */
6246     if (uptr->filebuf == NULL)                          /* no buffer? */
6247         return attach_err (uptr, SCPE_MEM);             /* error */
6248     if (!sim_quiet) {
6249         sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6250         }
6251     uptr->hwmark = (uint32)sim_fread (uptr->filebuf,    /* read file */
6252         SZ_D (dptr), cap, uptr->fileref);
6253     uptr->flags = uptr->flags | UNIT_BUF;               /* set buffered */
6254     }
6255 uptr->flags = uptr->flags | UNIT_ATT;
6256 uptr->pos = 0;
6257 return SCPE_OK;
6258 }
6259 
6260 t_stat attach_err (UNIT *uptr, t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
6261 {
6262 FREE (uptr->filename);
6263 uptr->filename = NULL;
6264 return stat;
6265 }
6266 
6267 /* Detach command */
6268 
6269 t_stat detach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6270 {
6271 char gbuf[CBUFSIZE];
6272 DEVICE *dptr;
6273 UNIT *uptr;
6274 
6275 GET_SWITCHES (cptr);                                    /* get switches */
6276 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6277     return SCPE_2FARG;
6278 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6279 if (*cptr != 0)                                         /* now eol? */
6280     return SCPE_2MARG;
6281 if (strcmp (gbuf, "ALL") == 0)
6282     return (detach_all (0, FALSE));
6283 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6284 if (dptr == NULL)                                       /* found dev? */
6285     return SCPE_NXDEV;
6286 if (uptr == NULL)                                       /* valid unit? */
6287     return SCPE_NXUN;
6288 return scp_detach_unit (dptr, uptr);                    /* detach */
6289 }
6290 
6291 /* Detach devices start..end
6292 
6293    Inputs:
6294         start   =       number of starting device
6295         shutdown =      TRUE if simulator shutting down
6296    Outputs:
6297         status  =       error status
6298 
6299    Note that during shutdown, detach routines for non-attachable devices
6300    will be called.  These routines can implement simulator shutdown.  Error
6301    returns during shutdown are ignored.
6302 */
6303 
6304 t_stat detach_all (int32 start, t_bool shutdown)
     /* [previous][next][first][last][top][bottom][index][help] */
6305 {
6306 uint32 i, j;
6307 DEVICE *dptr;
6308 UNIT *uptr;
6309 t_stat r;
6310 
6311 if ((start < 0) || (start > 1))
6312     return SCPE_IERR;
6313 if (shutdown)
6314     sim_switches = sim_switches | SIM_SW_SHUT;          /* flag shutdown */
6315 for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
6316     for (j = 0; j < dptr->numunits; j++) {              /* loop thru units */
6317         uptr = (dptr->units) + j;
6318         if ((uptr->flags & UNIT_ATT) ||                 /* attached? */
6319             (shutdown && dptr->detach &&                /* shutdown, spec rtn, */
6320             !(uptr->flags & UNIT_ATTABLE))) {           /* !attachable? */
6321             r = scp_detach_unit (dptr, uptr);           /* detach unit */
6322 
6323             if ((r != SCPE_OK) && !shutdown)            /* error and not shutting down? */
6324                 return r;                               /* bail out now with error status */
6325             }
6326         }
6327     }
6328 return SCPE_OK;
6329 }
6330 
6331 /* Call device-specific or file-oriented detach unit routine */
6332 
6333 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6334 {
6335 if (dptr->detach != NULL)                               /* device routine? */
6336     return dptr->detach (uptr);
6337 return detach_unit (uptr);                              /* no, standard */
6338 }
6339 
6340 /* Detach unit from file */
6341 
6342 t_stat detach_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6343 {
6344 DEVICE *dptr;
6345 
6346 if (uptr == NULL)
6347     return SCPE_IERR;
6348 if (!(uptr->flags & UNIT_ATTABLE))                      /* attachable? */
6349     return SCPE_NOATT;
6350 if (!(uptr->flags & UNIT_ATT)) {                        /* not attached? */
6351     if (sim_switches & SIM_SW_REST)                     /* restoring? */
6352         return SCPE_OK;                                 /* allow detach */
6353     else
6354         return SCPE_NOTATT;                             /* complain */
6355     }
6356 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6357     return SCPE_OK;
6358 if (uptr->flags & UNIT_BUF) {
6359     uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6360     if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6361         if (!sim_quiet) {
6362             sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6363             }
6364         rewind (uptr->fileref);
6365         sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6366         if (ferror (uptr->fileref))
6367             sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6368                         sim_dname (dptr), xstrerror_l(errno), errno);
6369         }
6370     if (uptr->flags & UNIT_MUSTBUF) {                   /* dyn alloc? */
6371         FREE (uptr->filebuf);                           /* free buf */
6372         uptr->filebuf = NULL;
6373         }
6374     uptr->flags = uptr->flags & ~UNIT_BUF;
6375     }
6376 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6377 FREE (uptr->filename);
6378 uptr->filename = NULL;
6379 if (fclose (uptr->fileref) == EOF)
6380     return SCPE_IOERR;
6381 return SCPE_OK;
6382 }
6383 
6384 /* Get device display name */
6385 
6386 const char *sim_dname (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6387 {
6388 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6389 }
6390 
6391 /* Get unit display name */
6392 
6393 const char *sim_uname (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6394 {
6395 DEVICE *d = find_dev_from_unit(uptr);
6396 static char uname[CBUFSIZE];
6397 
6398 if (!d)
6399     return "";
6400 if (d->numunits == 1)
6401     return sim_dname (d);
6402 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6403 return uname;
6404 }
6405 
6406 /* Run, go, boot, cont, step, next commands */
6407 
6408 t_stat run_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6409 {
6410 char gbuf[CBUFSIZE] = "";
6411 CONST char *tptr;
6412 uint32 i, j;
6413 int32 sim_next = 0;
6414 int32 unitno;
6415 t_value pcv, orig_pcv;
6416 t_stat r;
6417 DEVICE *dptr;
6418 UNIT *uptr;
6419 
6420 GET_SWITCHES (cptr);                                    /* get switches */
6421 sim_step = 0;
6422 if ((flag == RU_RUN) || (flag == RU_GO)) {              /* run or go */
6423     orig_pcv = get_rval (sim_PC, 0);                    /* get current PC value */
6424     if (*cptr != 0) {                                   /* argument? */
6425         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6426         if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6427             if (sim_dflt_dev && sim_vm_parse_addr)      /* address parser? */
6428                 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6429             else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */
6430             if ((tptr == gbuf) || (*tptr != 0) ||       /* error? */
6431                 (pcv > width_mask[sim_PC->width]))
6432                 return SCPE_ARG;
6433             put_rval (sim_PC, 0, pcv);                  /* Save in PC */
6434             }
6435         }
6436     if ((flag == RU_RUN) &&                             /* run? */
6437         ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {  /* reset sim */
6438         put_rval (sim_PC, 0, orig_pcv);                 /* restore original PC */
6439         return r;
6440         }
6441     if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) { //-V600 /* should be end */
6442         int32 saved_switches = sim_switches;
6443 
6444         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6445             cptr = get_glyph (cptr, gbuf, 0);           /* get next glyph */
6446         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6447             return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6448                                              (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6449         sim_switches = 0;
6450         GET_SWITCHES (cptr);
6451         if ((*cptr == '\'') || (*cptr == '"')) {        /* Expect UNTIL condition */
6452             r = expect_cmd (1, cptr);
6453             if (r != SCPE_OK)
6454                 return r;
6455             }
6456         else {                                          /* BREAK UNTIL condition */
6457             if (sim_switches == 0)
6458                 sim_switches = sim_brk_dflt;
6459             sim_switches |= BRK_TYP_TEMP;               /* make this a one-shot breakpoint */
6460             sim_brk_types |= BRK_TYP_TEMP;
6461             r = ssh_break (NULL, cptr, SSH_ST);
6462             if (r != SCPE_OK)
6463                 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6464             }
6465         sim_switches = saved_switches;
6466         }
6467     }
6468 
6469 else if ((flag == RU_STEP) ||
6470          ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) { /* step */
6471     static t_bool not_implemented_message = FALSE;
6472 
6473     if ((!not_implemented_message) && (flag == RU_NEXT)) {
6474         not_implemented_message = TRUE;
6475         flag = RU_STEP;
6476         }
6477     if (*cptr != 0) {                                   /* argument? */
6478         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6479         if (*cptr != 0)                                 /* should be end */
6480             return SCPE_2MARG;
6481         sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6482         if ((r != SCPE_OK) || (sim_step <= 0))          /* error? */
6483             return SCPE_ARG;
6484         }
6485     else sim_step = 1;
6486     if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6487         sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6488     }
6489 else if (flag == RU_NEXT) {                             /* next */
6490     t_addr *addrs;
6491 
6492     if (*cptr != 0) {                                   /* argument? */
6493         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6494         if (*cptr != 0)                                 /* should be end */
6495             return SCPE_2MARG;
6496         sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6497         if ((r != SCPE_OK) || (sim_next <= 0))          /* error? */
6498             return SCPE_ARG;
6499         }
6500     else sim_next = 1;
6501     if (sim_vm_is_subroutine_call(&addrs)) {
6502         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6503         for (i=0; addrs[i]; i++)
6504             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6505         }
6506     else
6507         sim_step = 1;
6508     }
6509 else if (flag == RU_BOOT) {                             /* boot */
6510     if (*cptr == 0)                                     /* must be more */
6511         return SCPE_2FARG;
6512     cptr = get_glyph (cptr, gbuf, 0);                   /* get next glyph */
6513     if (*cptr != 0)                                     /* should be end */
6514         return SCPE_2MARG;
6515     dptr = find_unit (gbuf, &uptr);                     /* locate unit */
6516     if (dptr == NULL)                                   /* found dev? */
6517         return SCPE_NXDEV;
6518     if (uptr == NULL)                                   /* valid unit? */
6519         return SCPE_NXUN;
6520     if (dptr->boot == NULL)                             /* can it boot? */
6521         return SCPE_NOFNC;
6522     if (uptr->flags & UNIT_DIS)                         /* disabled? */
6523         return SCPE_UDIS;
6524     if ((uptr->flags & UNIT_ATTABLE) &&                 /* if attable, att? */
6525         !(uptr->flags & UNIT_ATT))
6526         return SCPE_UNATT;
6527     unitno = (int32) (uptr - dptr->units);              /* recover unit# */
6528     if ((r = sim_run_boot_prep (flag)) != SCPE_OK)      /* reset sim */
6529         return r;
6530     if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)     /* boot device */
6531         return r;
6532     }
6533 
6534 else
6535     if (flag != RU_CONT)                                /* must be cont */
6536         return SCPE_IERR;
6537     else                                                /* CONTINUE command */
6538         if (*cptr != 0)                                 /* should be end (no arguments allowed) */
6539             return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6540 
6541 if (sim_switches & SIM_SW_HIDE)                         /* Setup only for Remote Console Mode */
6542     return SCPE_OK;
6543 
6544 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* reposition all */
6545     for (j = 0; j < dptr->numunits; j++) {              /* seq devices */
6546         uptr = dptr->units + j;
6547         if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6548             sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6549         }
6550     }
6551 stop_cpu = 0;
6552 sim_is_running = 1;                                     /* flag running */
6553 if (sim_ttrun () != SCPE_OK) {                          /* set console mode */
6554     sim_is_running = 0;                                 /* flag idle */
6555     sim_ttcmd ();
6556     return SCPE_TTYERR;
6557     }
6558 if ((r = sim_check_console (30)) != SCPE_OK) {          /* check console, error? */
6559     sim_is_running = 0;                                 /* flag idle */
6560     sim_ttcmd ();
6561     return r;
6562     }
6563 #if !defined(IS_WINDOWS)
6564 # if defined(SIGINT)
6565 if (signal (SIGINT, int_handler) == SIG_ERR) {          /* set WRU */
6566     sim_is_running = 0;                                 /* flag idle */
6567     sim_ttcmd ();
6568     return SCPE_SIGERR;
6569     }
6570 # endif
6571 #endif
6572 #if !defined(IS_WINDOWS)
6573 # if defined(SIGHUP)
6574 if (signal (SIGHUP, int_handler) == SIG_ERR) {          /* set WRU */
6575     sim_is_running = 0;                                 /* flag idle */
6576     sim_ttcmd ();
6577     return SCPE_SIGERR;
6578     }
6579 # endif
6580 #endif
6581 #if !defined(IS_WINDOWS)
6582 # if defined(SIGTERM)
6583 if (signal (SIGTERM, int_handler) == SIG_ERR) {         /* set WRU */
6584     sim_is_running = 0;                                 /* flag idle */
6585     sim_ttcmd ();
6586     return SCPE_SIGERR;
6587     }
6588 # endif
6589 #endif
6590 if (sim_step)                                           /* set step timer */
6591     sim_activate (&sim_step_unit, sim_step);
6592 (void)fflush(stdout);                                   /* flush stdout */
6593 if (sim_log)                                            /* flush log if enabled */
6594     (void)fflush (sim_log);
6595 sim_rtcn_init_all ();                                   /* re-init clocks */
6596 sim_start_timer_services ();                            /* enable wall clock timing */
6597 
6598 do {
6599     t_addr *addrs;
6600 
6601     while (1) {
6602         r = sim_instr();
6603         if (r != SCPE_REMOTE)
6604             break;
6605         sim_remote_process_command ();                  /* Process the command and resume processing */
6606         }
6607     if ((flag != RU_NEXT) ||                            /* done if not doing NEXT */
6608         (--sim_next <=0))
6609         break;
6610     if (sim_step == 0) {                                /* doing a NEXT? */
6611         t_addr val;
6612         BRKTAB *bp;
6613 
6614         if (SCPE_BARE_STATUS(r) >= SCPE_BASE)           /* done if an error occurred */
6615             break;
6616         if (sim_vm_pc_value)                            /* done if didn't stop at a dynamic breakpoint */
6617             val = (t_addr)(*sim_vm_pc_value)();
6618         else
6619             val = (t_addr)get_rval (sim_PC, 0);
6620         if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6621             break;
6622         sim_brk_clrall (BRK_TYP_DYN_STEPOVER);          /* cancel any step/over subroutine breakpoints */
6623         }
6624     else {
6625         if (r != SCPE_STEP)                             /* done if step didn't complete with step expired */
6626             break;
6627         }
6628     /* setup another next/step */
6629     sim_step = 0;
6630     if (sim_vm_is_subroutine_call(&addrs)) {
6631         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6632         for (i=0; addrs[i]; i++)
6633             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6634         }
6635     else
6636         sim_step = 1;
6637     if (sim_step)                                       /* set step timer */
6638         sim_activate (&sim_step_unit, sim_step);
6639     } while (1);
6640 
6641 sim_is_running = 0;                                     /* flag idle */
6642 sim_stop_timer_services ();                             /* disable wall clock timing */
6643 sim_ttcmd ();                                           /* restore console */
6644 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);                  /* cancel any step/over subroutine breakpoints */
6645 signal (SIGINT, SIG_DFL);                               /* cancel WRU */
6646 #if defined(SIGHUP)
6647 signal (SIGHUP, SIG_DFL);                               /* cancel WRU */
6648 #endif
6649 signal (SIGTERM, SIG_DFL);                              /* cancel WRU */
6650 if (sim_log)                                            /* flush console log */
6651     (void)fflush (sim_log);
6652 if (sim_deb)                                            /* flush debug log */
6653     sim_debug_flush ();
6654 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* flush attached files */
6655     for (j = 0; j < dptr->numunits; j++) {              /* if not buffered in mem */
6656         uptr = dptr->units + j;
6657         if (uptr->flags & UNIT_ATT) {                   /* attached, */
6658             if (uptr->io_flush)                         /* unit specific flush routine */
6659                 uptr->io_flush (uptr);                  /* call it */
6660             else {
6661                 if (!(uptr->flags & UNIT_BUF) &&        /* not buffered, */
6662                     (uptr->fileref) &&                  /* real file, */
6663                     !(uptr->dynflags & UNIT_NO_FIO) &&  /* is FILE *, */
6664                     !(uptr->flags & UNIT_RO))           /* not read only? */
6665                     (void)fflush (uptr->fileref);
6666                 }
6667             }
6668         }
6669     }
6670 sim_cancel (&sim_step_unit);                            /* cancel step timer */
6671 UPDATE_SIM_TIME;                                        /* update sim time */
6672 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6673 }
6674 
6675 /* run command message handler */
6676 
6677 void
6678 run_cmd_message (const char *unechoed_cmdline, t_stat r)
     /* [previous][next][first][last][top][bottom][index][help] */
6679 {
6680 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6681     sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6682 #if defined(WIN_STDIO)
6683 (void)fflush(stderr);
6684 (void)fflush(stdout);
6685 #endif /* if defined(WIN_STDIO) */
6686 fprint_stopped (stdout, r);                         /* print msg */
6687 if (sim_log && (sim_log != stdout))                 /* log if enabled */
6688     fprint_stopped (sim_log, r);
6689 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))/* debug if enabled */
6690     fprint_stopped (sim_deb, r);
6691 #if defined(WIN_STDIO)
6692 (void)fflush(stderr);
6693 (void)fflush(stdout);
6694 #endif /* if defined(WIN_STDIO) */
6695 }
6696 
6697 /* Common setup for RUN or BOOT */
6698 
6699 t_stat sim_run_boot_prep (int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
6700 {
6701 UNIT *uptr;
6702 t_stat r;
6703 
6704 sim_interval = 0;                                       /* reset queue */
6705 sim_time = sim_rtime = 0;
6706 noqueue_time = 0;
6707 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6708     sim_clock_queue = uptr->next;
6709     uptr->next = NULL;
6710     }
6711 r = reset_all (0);
6712 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6713     if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6714         sim_printf ("Resetting all devices...  This may not have been your intention.\r\n");
6715         sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6716         }
6717     run_cmd_did_reset = TRUE;
6718     }
6719 return r;
6720 }
6721 
6722 /* Print stopped message
6723  * For VM stops, if a VM-specific "sim_vm_fprint_stopped" pointer is defined,
6724  * call the indicated routine to print additional information after the message
6725  * and before the PC value is printed.  If the routine returns FALSE, skip
6726  * printing the PC and its related instruction.
6727  */
6728 
6729 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6730 {
6731 int32 i;
6732 t_stat r = 0;
6733 t_addr k;
6734 t_value pcval;
6735 
6736 fputc ('\n', st);                                       /* start on a new line */
6737 
6738 if (v >= SCPE_BASE)                                     /* SCP error? */
6739     fputs (sim_error_text (v), st);                     /* print it from the SCP list */
6740 else {                                                  /* VM error */
6741     fputs (sim_stop_messages [v], st);                  /* print the VM-specific message */
6742 
6743     if ((sim_vm_fprint_stopped != NULL) &&              /* if a VM-specific stop handler is defined */
6744         (!sim_vm_fprint_stopped (st, v)))               /*   call it; if it returned FALSE, */
6745         return;                                         /*     we're done */
6746     }
6747 
6748 (void)fprintf (st, ", %s: ", pc->name);                       /* print the name of the PC register */
6749 
6750 pcval = get_rval (pc, 0);
6751 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)       /* if reg wants VM-specific printer */
6752     sim_vm_fprint_addr (st, dptr, (t_addr) pcval);      /*   call it to print the PC address */
6753 else fprint_val (st, pcval, pc->radix, pc->width,       /* otherwise, print as a numeric value */
6754     pc->flags & REG_FMT);                               /*   with the radix and formatting specified */
6755 if ((dptr != NULL) && (dptr->examine != NULL)) {
6756     for (i = 0; i < sim_emax; i++)
6757         sim_eval[i] = 0;
6758     for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6759         if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6760             break;
6761         }
6762     if ((r == SCPE_OK) || (i > 0)) {
6763         (void)fprintf (st, " (");
6764         if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6765             fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6766         (void)fprintf (st, ")");
6767         }
6768     }
6769 (void)fprintf (st, "\r\n");
6770 return;
6771 }
6772 
6773 void fprint_stopped (FILE *st, t_stat v)
     /* [previous][next][first][last][top][bottom][index][help] */
6774 {
6775 #if defined(WIN_STDIO)
6776 (void)fflush(stderr);
6777 (void)fflush(stdout);
6778 #endif /* if defined(WIN_STDIO) */
6779 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6780 return;
6781 }
6782 
6783 /* Unit service for step timeout, originally scheduled by STEP n command
6784    Return step timeout SCP code, will cause simulation to stop */
6785 
6786 t_stat step_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6787 {
6788 return SCPE_STEP;
6789 }
6790 
6791 /* Unit service to facilitate expect matching to stop simulation.
6792    Return expect SCP code, will cause simulation to stop */
6793 
6794 t_stat expect_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6795 {
6796 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6797 }
6798 
6799 /* Signal handler for ^C signal - set stop simulation flag */
6800 
6801 void int_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
6802 {
6803 stop_cpu = 1;
6804 return;
6805 }
6806 
6807 /* Examine/deposit commands */
6808 
6809 t_stat exdep_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6810 {
6811 char gbuf[CBUFSIZE];
6812 CONST char *gptr;
6813 CONST char *tptr = NULL;
6814 int32 opt;
6815 t_addr low, high;
6816 t_stat reason = SCPE_IERR;
6817 DEVICE *tdptr;
6818 REG *lowr, *highr;
6819 FILE *ofile;
6820 
6821 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;               /* options for all */
6822 if (flag == EX_E)                                       /* extra for EX */
6823     opt = opt | CMD_OPT_OF;
6824 cptr = get_sim_opt (opt, cptr, &reason);                /* get cmd options */
6825 if (NULL == cptr)                                       /* error? */
6826     return reason;
6827 if (*cptr == 0)                                         /* must be more */
6828     return SCPE_2FARG;
6829 if (sim_dfunit == NULL)                                 /* got a unit? */
6830     return SCPE_NXUN;
6831 cptr = get_glyph (cptr, gbuf, 0);                       /* get list */
6832 if ((flag == EX_D) && (*cptr == 0))                     /* deposit needs more */
6833 
6834     return SCPE_2FARG;
6835 ofile = sim_ofile? sim_ofile: stdout;                   /* no ofile? use stdout */
6836 
6837 for (gptr = gbuf, reason = SCPE_OK;
6838     (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6839     tdptr = sim_dfdev;                                  /* working dptr */
6840     if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6841         tptr = gptr + strlen ("STATE");
6842         if (*tptr && (*tptr++ != ','))
6843             return SCPE_ARG;
6844         if ((lowr = sim_dfdev->registers) == NULL)
6845             return SCPE_NXREG;
6846         for (highr = lowr; highr->name != NULL; highr++) ;
6847         sim_switches = sim_switches | SIM_SW_HIDE;
6848         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6849             lowr, --highr, 0, 0);
6850         continue;
6851         }
6852 
6853     /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
6854     if ((lowr = find_reg (gptr, &tptr, tdptr)) ||       /* local reg or */
6855         (!(sim_opt_out & CMD_OPT_DFT) &&                /* no dflt, global? */
6856         (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6857         low = high = 0;
6858         if ((*tptr == '-') || (*tptr == ':')) {
6859             highr = find_reg (tptr + 1, &tptr, tdptr);
6860             if (highr == NULL)
6861                 return SCPE_NXREG;
6862             }
6863         else {
6864             highr = lowr;
6865             if (*tptr == '[') {
6866                 if (lowr->depth <= 1)
6867                     return SCPE_ARG;
6868                 tptr = get_range (NULL, tptr + 1, &low, &high,
6869                     10, lowr->depth - 1, ']');
6870                 if (tptr == NULL)
6871                     return SCPE_ARG;
6872                 }
6873             }
6874         if (*tptr && (*tptr++ != ','))
6875             return SCPE_ARG;
6876         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6877             lowr, highr, (uint32) low, (uint32) high);
6878         continue;
6879         }
6880 
6881     tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6882         (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6883         sim_dfunit->capac - sim_dfdev->aincr), 0);
6884     if (tptr == NULL)
6885         return SCPE_ARG;
6886     if (*tptr && (*tptr++ != ','))
6887         return SCPE_ARG;
6888     reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6889         sim_dfdev, sim_dfunit);
6890     }                                                   /* end for */
6891 if (sim_ofile)                                          /* close output file */
6892     fclose (sim_ofile);
6893 return reason;
6894 }
6895 
6896 /* Loop controllers for examine/deposit
6897 
6898    exdep_reg_loop       examine/deposit range of registers
6899    exdep_addr_loop      examine/deposit range of addresses
6900 */
6901 
6902 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6903     REG *lowr, REG *highr, uint32 lows, uint32 highs)
6904 {
6905 t_stat reason;
6906 uint32 idx, val_start=lows;
6907 t_value val, last_val;
6908 REG *rptr;
6909 
6910 if ((lowr == NULL) || (highr == NULL))
6911     return SCPE_IERR;
6912 if (lowr > highr)
6913     return SCPE_ARG;
6914 for (rptr = lowr; rptr <= highr; rptr++) {
6915     if ((sim_switches & SIM_SW_HIDE) &&
6916         (rptr->flags & REG_HIDDEN))
6917         continue;
6918     val = last_val = 0;
6919     for (idx = lows; idx <= highs; idx++) {
6920         if (idx >= rptr->depth)
6921             return SCPE_SUB;
6922         val = get_rval (rptr, idx);
6923         if (schptr && !test_search (&val, schptr))
6924             continue;
6925         if (flag == EX_E) {
6926             if ((idx > lows) && (val == last_val))
6927                 continue;
6928             if (idx > val_start+1) {
6929                 if (idx-1 == val_start+1) {
6930                     reason = ex_reg (ofile, val, flag, rptr, idx-1);
6931                     if (reason != SCPE_OK)
6932                         return reason;
6933                     if (sim_log && (ofile == stdout))
6934                         ex_reg (sim_log, val, flag, rptr, idx-1);
6935                     }
6936                 else {
6937                     if (val_start+1 != idx-1) {
6938                         (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6939                         if (sim_log && (ofile == stdout))
6940                             (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6941                         }
6942                     else {
6943                         (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6944                         if (sim_log && (ofile == stdout))
6945                             (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6946                         }
6947                     }
6948                 }
6949             sim_last_val = last_val = val;
6950             val_start = idx;
6951             reason = ex_reg (ofile, val, flag, rptr, idx);
6952             if (reason != SCPE_OK)
6953                 return reason;
6954             if (sim_log && (ofile == stdout))
6955                 ex_reg (sim_log, val, flag, rptr, idx);
6956             }
6957         if (flag != EX_E) {
6958             reason = dep_reg (flag, cptr, rptr, idx);
6959             if (reason != SCPE_OK)
6960                 return reason;
6961             }
6962         }
6963     if ((flag == EX_E) && (val_start != highs)) {
6964         if (highs == val_start+1) {
6965             reason = ex_reg (ofile, val, flag, rptr, highs);
6966             if (reason != SCPE_OK)
6967                 return reason;
6968             if (sim_log && (ofile == stdout))
6969                 ex_reg (sim_log, val, flag, rptr, highs);
6970             }
6971         else {
6972             if (val_start+1 != highs) {
6973                 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6974                 if (sim_log && (ofile == stdout))
6975                     (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6976                 }
6977             else {
6978                 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6979                 if (sim_log && (ofile == stdout))
6980                     (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6981                 }
6982             }
6983         }
6984     }
6985 return SCPE_OK;
6986 }
6987 
6988 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6989     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6990 {
6991 t_addr i, mask;
6992 t_stat reason;
6993 
6994 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6995     return SCPE_UDIS;
6996 mask = (t_addr) width_mask[dptr->awidth];
6997 if ((low > mask) || (high > mask) || (low > high))
6998     return SCPE_ARG;
6999 for (i = low; i <= high; ) {                            /* all paths must incr!! */
7000     reason = get_aval (i, dptr, uptr);                  /* get data */
7001     if (reason != SCPE_OK)                              /* return if error */
7002         return reason;
7003     if (schptr && !test_search (sim_eval, schptr))
7004         i = i + dptr->aincr;                            /* sch fails, incr */
7005     else {                                              /* no sch or success */
7006         if (flag != EX_D) {                             /* ex, ie, or id? */
7007             reason = ex_addr (ofile, flag, i, dptr, uptr);
7008             if (reason > SCPE_OK)
7009                 return reason;
7010             if (sim_log && (ofile == stdout))
7011                 ex_addr (sim_log, flag, i, dptr, uptr);
7012             }
7013         else reason = 1 - dptr->aincr;                  /* no, dflt incr */
7014         if (flag != EX_E) {                             /* ie, id, or d? */
7015             reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7016             if (reason > SCPE_OK)
7017                 return reason;
7018             }
7019         i = i + (1 - reason);                           /* incr */
7020         }
7021     }
7022 return SCPE_OK;
7023 }
7024 
7025 /* Examine register routine
7026 
7027    Inputs:
7028         ofile   =       output stream
7029         val     =       current register value
7030         flag    =       type of ex/mod command (ex, iex, idep)
7031         rptr    =       pointer to register descriptor
7032         idx     =       index
7033    Outputs:
7034         return  =       error status
7035 */
7036 
7037 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7038 {
7039 int32 rdx;
7040 
7041 if (rptr == NULL)
7042     return SCPE_IERR;
7043 if (rptr->depth > 1)
7044     (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7045 else
7046     (void)Fprintf (ofile, "%s:\t", rptr->name);
7047 if (!(flag & EX_E))
7048     return SCPE_OK;
7049 GET_RADIX (rdx, rptr->radix);
7050 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7051     sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7052 else if (!(rptr->flags & REG_VMFLAGS) ||
7053     (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7054                  NULL, sim_switches | SIM_SW_REG) > 0)) {
7055         fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7056         if (rptr->fields) {
7057             (void)Fprintf (ofile, "\t");
7058             fprint_fields (ofile, val, val, rptr->fields);
7059             }
7060         }
7061 if (flag & EX_I)
7062     (void)Fprintf (ofile, "\t");
7063 else
7064     (void)Fprintf (ofile, "\r\n");
7065 return SCPE_OK;
7066 }
7067 
7068 /* Get register value
7069 
7070    Inputs:
7071         rptr    =       pointer to register descriptor
7072         idx     =       index
7073    Outputs:
7074         return  =       register value
7075 */
7076 
7077 t_value get_rval (REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7078 {
7079 size_t sz;
7080 t_value val;
7081 uint32 *ptr;
7082 
7083 sz = SZ_R (rptr);
7084 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7085     idx = idx + rptr->qptr;
7086     if (idx >= rptr->depth) idx = idx - rptr->depth;
7087     }
7088 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7089     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7090     if (sz <= sizeof (uint32))
7091         val = *ptr;
7092     else val = *((t_uint64 *) ptr); //-V1032
7093     }
7094 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7095     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7096     if (sz <= sizeof (uint32))
7097         val = *ptr;
7098     else val = *((t_uint64 *) ptr);
7099     }
7100 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7101     (sz == sizeof (uint8)))
7102     val = *(((uint8 *) rptr->loc) + idx);
7103 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7104     (sz == sizeof (uint16)))
7105     val = *(((uint16 *) rptr->loc) + idx);
7106 else if (sz <= sizeof (uint32))
7107      val = *(((uint32 *) rptr->loc) + idx);
7108 else val = *(((t_uint64 *) rptr->loc) + idx);
7109 val = (val >> rptr->offset) & width_mask[rptr->width];
7110 return val;
7111 }
7112 
7113 /* Deposit register routine
7114 
7115    Inputs:
7116         flag    =       type of deposit (normal/interactive)
7117         cptr    =       pointer to input string
7118         rptr    =       pointer to register descriptor
7119         idx     =       index
7120    Outputs:
7121         return  =       error status
7122 */
7123 
7124 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7125 {
7126 t_stat r;
7127 t_value val, mask;
7128 int32 rdx;
7129 CONST char *tptr;
7130 char gbuf[CBUFSIZE];
7131 
7132 if ((cptr == NULL) || (rptr == NULL))
7133     return SCPE_IERR;
7134 if (rptr->flags & REG_RO)
7135     return SCPE_RO;
7136 if (flag & EX_I) {
7137     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7138     if (sim_log)
7139         (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7140     if (cptr == NULL)                                   /* force exit */
7141         return 1;
7142     if (*cptr == 0)                                     /* success */
7143         return SCPE_OK;
7144     }
7145 mask = width_mask[rptr->width];
7146 GET_RADIX (rdx, rptr->radix);
7147 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {    /* address form? */
7148     val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7149     if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7150         return SCPE_ARG;
7151     }
7152 else
7153     if (!(rptr->flags & REG_VMFLAGS) ||                 /* don't use sym? */
7154         (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7155                     &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7156     val = get_uint (cptr, rdx, mask, &r);
7157     if (r != SCPE_OK)
7158         return SCPE_ARG;
7159     }
7160 if ((rptr->flags & REG_NZ) && (val == 0))
7161     return SCPE_ARG;
7162 put_rval (rptr, idx, val);
7163 return SCPE_OK;
7164 }
7165 
7166 /* Put register value
7167 
7168    Inputs:
7169         rptr    =       pointer to register descriptor
7170         idx     =       index
7171         val     =       new value
7172         mask    =       mask
7173    Outputs:
7174         none
7175 */
7176 
7177 void put_rval (REG *rptr, uint32 idx, t_value val)
     /* [previous][next][first][last][top][bottom][index][help] */
7178 {
7179 size_t sz;
7180 t_value mask;
7181 uint32 *ptr;
7182 
7183 #define PUT_RVAL(sz,rp,id,v,m)            \
7184     *(((sz *) rp->loc) + id) =            \
7185         (sz)((*(((sz *) rp->loc) + id) &  \
7186             ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7187 
7188 if (rptr == sim_PC)
7189     sim_brk_npc (0);
7190 sz = SZ_R (rptr);
7191 mask = width_mask[rptr->width];
7192 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7193     idx = idx + rptr->qptr;
7194     if (idx >= rptr->depth)
7195         idx = idx - rptr->depth;
7196     }
7197 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7198     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7199     if (sz <= sizeof (uint32))
7200         *ptr = (*ptr &
7201         ~(((uint32) mask) << rptr->offset)) |
7202         (((uint32) val) << rptr->offset);
7203     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr) //-V1032
7204         & ~(mask << rptr->offset)) | (val << rptr->offset);
7205     }
7206 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7207     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7208     if (sz <= sizeof (uint32))
7209         *((uint32 *) ptr) = (*((uint32 *) ptr) &
7210         ~(((uint32) mask) << rptr->offset)) |
7211         (((uint32) val) << rptr->offset);
7212     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7213         & ~(mask << rptr->offset)) | (val << rptr->offset);
7214     }
7215 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7216     (sz == sizeof (uint8)))
7217     PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7218 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7219     (sz == sizeof (uint16)))
7220     PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7221 else if (sz <= sizeof (uint32))
7222     PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7223 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7224 return;
7225 }
7226 
7227 /* Examine address routine
7228 
7229    Inputs: (sim_eval is an implicit argument)
7230         ofile   =       output stream
7231         flag    =       type of ex/mod command (ex, iex, idep)
7232         addr    =       address to examine
7233         dptr    =       pointer to device
7234         uptr    =       pointer to unit
7235    Outputs:
7236         return  =       if > 0, error status
7237                         if <= 0,-number of extra addr units retired
7238 */
7239 
7240 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7241 {
7242 t_stat reason;
7243 int32 rdx;
7244 
7245 if (sim_vm_fprint_addr)
7246     sim_vm_fprint_addr (ofile, dptr, addr);
7247 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7248 (void)Fprintf (ofile, ":\t");
7249 if (!(flag & EX_E))
7250     return (1 - dptr->aincr);
7251 
7252 GET_RADIX (rdx, dptr->dradix);
7253 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7254     fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7255     reason = 1 - dptr->aincr;
7256     }
7257 if (flag & EX_I)
7258     (void)Fprintf (ofile, "\t");
7259 else
7260     (void)Fprintf (ofile, "\r\n");
7261 return reason;
7262 }
7263 
7264 /* Get address routine
7265 
7266    Inputs:
7267         flag    =       type of ex/mod command (ex, iex, idep)
7268         addr    =       address to examine
7269         dptr    =       pointer to device
7270         uptr    =       pointer to unit
7271    Outputs: (sim_eval is an implicit output)
7272         return  =       error status
7273 */
7274 
7275 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7276 {
7277 int32 i;
7278 t_value mask;
7279 t_addr j, loc;
7280 size_t sz;
7281 t_stat reason = SCPE_OK;
7282 
7283 if ((dptr == NULL) || (uptr == NULL))
7284     return SCPE_IERR;
7285 mask = width_mask[dptr->dwidth];
7286 for (i = 0; i < sim_emax; i++)
7287     sim_eval[i] = 0;
7288 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7289     if (dptr->examine != NULL) {
7290         reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7291         if (reason != SCPE_OK)
7292             break;
7293         }
7294     else {
7295         if (!(uptr->flags & UNIT_ATT))
7296             return SCPE_UNATT;
7297         if (uptr->dynflags & UNIT_NO_FIO)
7298             return SCPE_NOFNC;
7299         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7300             reason = SCPE_NXM;
7301             break;
7302             }
7303         sz = SZ_D (dptr);
7304         loc = j / dptr->aincr;
7305         if (uptr->flags & UNIT_BUF) {
7306             SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7307             }
7308         else {
7309             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7310             sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7311             if ((feof (uptr->fileref)) &&
7312                !(uptr->flags & UNIT_FIX)) {
7313                 reason = SCPE_EOF;
7314                 break;
7315                 }
7316             else if (ferror (uptr->fileref)) {
7317                 clearerr (uptr->fileref);
7318                 reason = SCPE_IOERR;
7319                 break;
7320                 }
7321             }
7322         }
7323     sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7324     }
7325 if ((reason != SCPE_OK) && (i == 0))
7326     return reason;
7327 return SCPE_OK;
7328 }
7329 
7330 /* Deposit address routine
7331 
7332    Inputs:
7333         flag    =       type of deposit (normal/interactive)
7334         cptr    =       pointer to input string
7335         addr    =       address to examine
7336         dptr    =       pointer to device
7337         uptr    =       pointer to unit
7338         dfltinc =       value to return on cr input
7339    Outputs:
7340         return  =       if > 0, error status
7341                         if <= 0, -number of extra address units retired
7342 */
7343 
7344 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
7345     UNIT *uptr, int32 dfltinc)
7346 {
7347 int32 i, count, rdx;
7348 t_addr j, loc;
7349 t_stat r, reason;
7350 t_value mask;
7351 size_t sz;
7352 char gbuf[CBUFSIZE];
7353 
7354 if (dptr == NULL)
7355     return SCPE_IERR;
7356 if (flag & EX_I) {
7357     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7358     if (sim_log)
7359         (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7360     if (cptr == NULL)                                   /* force exit */
7361         return 1;
7362     if (*cptr == 0)                                     /* success */
7363         return dfltinc;
7364     }
7365 if (uptr->flags & UNIT_RO)                              /* read only? */
7366     return SCPE_RO;
7367 mask = width_mask[dptr->dwidth];
7368 
7369 GET_RADIX (rdx, dptr->dradix);
7370 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7371     sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7372     if (reason != SCPE_OK)
7373         return reason;
7374     reason = dfltinc;
7375     }
7376 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7377 
7378 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7379     sim_eval[i] = sim_eval[i] & mask;
7380     if (dptr->deposit != NULL) {
7381         r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7382         if (r != SCPE_OK)
7383             return r;
7384         }
7385     else {
7386         if (!(uptr->flags & UNIT_ATT))
7387             return SCPE_UNATT;
7388         if (uptr->dynflags & UNIT_NO_FIO)
7389             return SCPE_NOFNC;
7390         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7391             return SCPE_NXM;
7392         sz = SZ_D (dptr);
7393         loc = j / dptr->aincr;
7394         if (uptr->flags & UNIT_BUF) {
7395             SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7396             if (loc >= uptr->hwmark)
7397                 uptr->hwmark = (uint32) loc + 1;
7398             }
7399         else {
7400             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7401             sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7402             if (ferror (uptr->fileref)) {
7403                 clearerr (uptr->fileref);
7404                 return SCPE_IOERR;
7405                 }
7406             }
7407         }
7408     }
7409 return reason;
7410 }
7411 
7412 /* Evaluate command */
7413 
7414 t_stat eval_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7415 {
7416 if (!sim_dflt_dev)
7417   return SCPE_ARG;
7418 DEVICE *dptr = sim_dflt_dev;
7419 int32 i, rdx, a, lim;
7420 t_stat r;
7421 
7422 GET_SWITCHES (cptr);
7423 GET_RADIX (rdx, dptr->dradix);
7424 for (i = 0; i < sim_emax; i++)
7425 sim_eval[i] = 0;
7426 if (*cptr == 0)
7427     return SCPE_2FARG;
7428 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7429     sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7430     if (r != SCPE_OK)
7431         return r;
7432     }
7433 lim = 1 - r;
7434 for (i = a = 0; a < lim; ) {
7435     sim_printf ("%d:\t", a);
7436     if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7437         r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7438     if (sim_log) {
7439         if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7440             r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7441         }
7442     sim_printf ("\r\n");
7443     if (r < 0)
7444         a = a + 1 - r;
7445     else a = a + dptr->aincr;
7446     i = a / dptr->aincr;
7447     }
7448 return SCPE_OK;
7449 }
7450 
7451 /* String processing routines
7452 
7453    read_line            read line
7454 
7455    Inputs:
7456         cptr    =       pointer to buffer
7457         size    =       maximum size
7458         stream  =       pointer to input stream
7459    Outputs:
7460         optr    =       pointer to first non-blank character
7461                         NULL if EOF
7462 */
7463 
7464 char *read_line (char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7465 {
7466 return read_line_p (NULL, cptr, size, stream);
7467 }
7468 
7469 /* read_line_p          read line with prompt
7470 
7471    Inputs:
7472         prompt  =       pointer to prompt string
7473         cptr    =       pointer to buffer
7474         size    =       maximum size
7475         stream  =       pointer to input stream
7476    Outputs:
7477         optr    =       pointer to first non-blank character
7478                         NULL if EOF
7479 */
7480 
7481 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7482 {
7483 char *tptr;
7484 
7485 if (prompt) {                                           /* interactive? */
7486 #if defined(HAVE_LINEHISTORY)
7487         char *tmpc = linenoise (prompt);                /* get cmd line */
7488         if (tmpc == NULL)                               /* bad result? */
7489             cptr = NULL;
7490         else {
7491             strncpy (cptr, tmpc, size-1);               /* copy result */
7492             linenoiseHistoryAdd (tmpc);                 /* add to history */
7493             FREE (tmpc);                                /* free temp */
7494             }
7495         }
7496 #else
7497         (void)fflush (stdout);                          /* flush output */
7498         (void)printf ("%s", prompt);                    /* display prompt */
7499         (void)fflush (stdout);                          /* flush output */
7500         cptr = fgets (cptr, size, stream);              /* get cmd line */
7501         }
7502 #endif /* if defined(HAVE_LINEHISTORY) */
7503 else cptr = fgets (cptr, size, stream);                 /* get cmd line */
7504 
7505 if (cptr == NULL) {
7506     clearerr (stream);                                  /* clear error */
7507     return NULL;                                        /* ignore EOF */
7508     }
7509 for (tptr = cptr; tptr < (cptr + size); tptr++) {       /* remove cr or nl */
7510     if ((*tptr == '\n') || (*tptr == '\r') ||
7511         (tptr == (cptr + size - 1))) {                  /* str max length? */
7512         *tptr = 0;                                      /* terminate */
7513         break;
7514         }
7515     }
7516 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))              /* Skip/ignore UTF8_BOM */
7517     memmove (cptr, cptr + 3, strlen (cptr + 3));
7518 while (sim_isspace (*cptr))                             /* trim leading spc */
7519     cptr++;
7520 if ((*cptr == ';') || (*cptr == '#')) {                 /* ignore comment */
7521     if (sim_do_echo)                                    /* echo comments if -v */
7522         sim_printf("%s> %s\r\n", do_position(), cptr);
7523     *cptr = 0;
7524     }
7525 
7526 return cptr;
7527 }
7528 
7529 /* get_glyph            get next glyph (force upper case)
7530    get_glyph_nc         get next glyph (no conversion)
7531    get_glyph_quoted     get next glyph (potentially enclosed in quotes, no conversion)
7532    get_glyph_cmd        get command glyph (force upper case, extract leading !)
7533    get_glyph_gen        get next glyph (general case)
7534 
7535    Inputs:
7536         iptr        =   pointer to input string
7537         optr        =   pointer to output string
7538         mchar       =   optional end of glyph character
7539         uc          =   TRUE for convert to upper case (_gen only)
7540         quote       =   TRUE to allow quote enclosing values (_gen only)
7541         escape_char =   optional escape character within quoted strings (_gen only)
7542 
7543    Outputs
7544         result      =   pointer to next character in input string
7545 */
7546 
7547 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] */
7548 {
7549 t_bool quoting = FALSE;
7550 t_bool escaping = FALSE;
7551 char quote_char = 0;
7552 
7553 while ((*iptr != 0) &&
7554        ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7555     if (quote) {
7556         if (quoting) {
7557             if (!escaping) {
7558                 if (*iptr == escape_char)
7559                     escaping = TRUE;
7560                 else
7561                     if (*iptr == quote_char)
7562                         quoting = FALSE;
7563                 }
7564             else
7565                 escaping = FALSE;
7566             }
7567         else {
7568             if ((*iptr == '"') || (*iptr == '\'')) {
7569                 quoting = TRUE;
7570                 quote_char = *iptr;
7571                 }
7572             }
7573         }
7574     if (sim_islower (*iptr) && uc)
7575         *optr = (char)toupper (*iptr);
7576     else *optr = *iptr;
7577     iptr++; optr++;
7578     }
7579 if (mchar && (*iptr == mchar))              /* skip input terminator */
7580     iptr++;
7581 *optr = 0;                                  /* terminate result string */
7582 while (sim_isspace (*iptr))                 /* absorb additional input spaces */
7583     iptr++;
7584 return iptr;
7585 }
7586 
7587 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7588 {
7589 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7590 }
7591 
7592 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7593 {
7594 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7595 }
7596 
7597 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7598 {
7599 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7600 }
7601 
7602 CONST char *get_glyph_cmd (const char *iptr, char *optr)
     /* [previous][next][first][last][top][bottom][index][help] */
7603 {
7604 /* Tolerate "!subprocess" vs. requiring "! subprocess" */
7605 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7606     strcpy (optr, "!");                     /* return ! as command glyph */
7607     return (CONST char *)(iptr + 1);        /* and skip over the leading ! */
7608     }
7609 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7610 }
7611 
7612 /* Trim trailing spaces from a string
7613 
7614     Inputs:
7615         cptr    =       pointer to string
7616     Outputs:
7617         cptr    =       pointer to string
7618 */
7619 
7620 char *sim_trim_endspc (char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7621 {
7622 char *tptr;
7623 
7624 tptr = cptr + strlen (cptr);
7625 while ((--tptr >= cptr) && sim_isspace (*tptr))
7626     *tptr = 0;
7627 return cptr;
7628 }
7629 
7630 int sim_isspace (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7631 {
7632 return (c & 0x80) ? 0 : isspace (c);
7633 }
7634 
7635 int sim_islower (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7636 {
7637 return (c & 0x80) ? 0 : islower (c);
7638 }
7639 
7640 int sim_isalpha (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7641 {
7642 return (c & 0x80) ? 0 : isalpha (c);
7643 }
7644 
7645 int sim_isprint (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7646 {
7647 return (c & 0x80) ? 0 : isprint (c);
7648 }
7649 
7650 int sim_isdigit (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7651 {
7652 return (c & 0x80) ? 0 : isdigit (c);
7653 }
7654 
7655 int sim_isgraph (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7656 {
7657 return (c & 0x80) ? 0 : isgraph (c);
7658 }
7659 
7660 int sim_isalnum (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7661 {
7662 return (c & 0x80) ? 0 : isalnum (c);
7663 }
7664 
7665 /* get_uint             unsigned number
7666 
7667    Inputs:
7668         cptr    =       pointer to input string
7669         radix   =       input radix
7670         max     =       maximum acceptable value
7671         *status =       pointer to error status
7672    Outputs:
7673         val     =       value
7674 */
7675 
7676 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
     /* [previous][next][first][last][top][bottom][index][help] */
7677 {
7678 t_value val;
7679 CONST char *tptr;
7680 
7681 *status = SCPE_OK;
7682 val = strtotv ((CONST char *)cptr, &tptr, radix);
7683 if ((cptr == tptr) || (val > max))
7684     *status = SCPE_ARG;
7685 else {
7686     while (sim_isspace (*tptr)) tptr++;
7687     if (*tptr != 0)
7688         *status = SCPE_ARG;
7689     }
7690 return val;
7691 }
7692 
7693 /* get_range            range specification
7694 
7695    Inputs:
7696         dptr    =       pointer to device (NULL if none)
7697         cptr    =       pointer to input string
7698         *lo     =       pointer to low result
7699         *hi     =       pointer to high result
7700         aradix  =       radix
7701         max     =       default high value
7702         term    =       terminating character, 0 if none
7703    Outputs:
7704         tptr    =       input pointer after processing
7705                         NULL if error
7706 */
7707 
7708 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
     /* [previous][next][first][last][top][bottom][index][help] */
7709     uint32 rdx, t_addr max, char term)
7710 {
7711 CONST char *tptr;
7712 
7713 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {    /* ALL? */
7714     tptr = cptr + strlen ("ALL");
7715     *lo = 0;
7716     *hi = max;
7717     }
7718 else {
7719     if ((strncmp (cptr, ".", strlen (".")) == 0) &&             /* .? */
7720         ((cptr[1] == '\0') ||
7721          (cptr[1] == '-')  ||
7722          (cptr[1] == ':')  ||
7723          (cptr[1] == '/'))) {
7724         tptr = cptr + strlen (".");
7725         *lo = *hi = sim_last_addr;
7726         }
7727     else {
7728         if (strncmp (cptr, "$", strlen ("$")) == 0) {           /* $? */
7729             tptr = cptr + strlen ("$");
7730             *hi = *lo = (t_addr)sim_last_val;
7731             }
7732         else {
7733             if (dptr && sim_vm_parse_addr)                      /* get low */
7734                 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7735             else
7736                 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7737             if (cptr == tptr)                                   /* error? */
7738                     return NULL;
7739             }
7740         }
7741     if ((*tptr == '-') || (*tptr == ':')) {             /* range? */
7742         cptr = tptr + 1;
7743         if (dptr && sim_vm_parse_addr)                  /* get high */
7744             *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7745         else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7746         if (cptr == tptr)
7747             return NULL;
7748         if (*lo > *hi)
7749             return NULL;
7750         }
7751     else if (*tptr == '/') {                            /* relative? */
7752         cptr = tptr + 1;
7753         *hi = (t_addr) strtotv (cptr, &tptr, rdx);      /* get high */
7754         if ((cptr == tptr) || (*hi == 0))
7755             return NULL;
7756         *hi = *lo + *hi - 1;
7757         }
7758     else *hi = *lo;
7759     }
7760 sim_last_addr = *hi;
7761 if (term && (*tptr++ != term))
7762     return NULL;
7763 return tptr;
7764 }
7765 
7766 /* sim_decode_quoted_string
7767 
7768    Inputs:
7769         iptr        =   pointer to input string
7770         optr        =   pointer to output buffer
7771                         the output buffer must be allocated by the caller
7772                         and to avoid overrunat it must be at least as big
7773                         as the input string.
7774 
7775    Outputs
7776         result      =   status of decode SCPE_OK when good, SCPE_ARG otherwise
7777         osize       =   size of the data in the optr buffer
7778 
7779    The input string must be quoted.  Quotes may be either single or
7780    double but the opening anc closing quote characters must match.
7781    Within quotes C style character escapes are allowed.
7782 */
7783 
7784 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
     /* [previous][next][first][last][top][bottom][index][help] */
7785 {
7786 char quote_char;
7787 uint8 *ostart = optr;
7788 
7789 *osize = 0;
7790 if ((strlen(iptr) == 1) ||
7791     (iptr[0] != iptr[strlen(iptr)-1]) ||
7792     ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7793     return SCPE_ARG;            /* String must be quote delimited */
7794 quote_char = *iptr++;           /* Save quote character */
7795 while (iptr[1]) {               /* Skip trailing quote */
7796     if (*iptr != '\\') {
7797         if (*iptr == quote_char)
7798             return SCPE_ARG;    /* Embedded quotes must be escaped */
7799         *(optr++) = (uint8)(*(iptr++));
7800         continue;
7801         }
7802     ++iptr; /* Skip backslash */
7803     switch (*iptr) {
7804         case 'r':   /* ASCII Carriage Return character (Decimal value 13) */
7805             *(optr++) = 13; ++iptr;
7806             break;
7807         case 'n':   /* ASCII Linefeed character (Decimal value 10) */
7808             *(optr++) = 10; ++iptr;
7809             break;
7810         case 'f':   /* ASCII Formfeed character (Decimal value 12) */
7811             *(optr++) = 12; ++iptr;
7812             break;
7813         case 't':   /* ASCII Horizontal Tab character (Decimal value 9) */
7814             *(optr++) = 9; ++iptr;
7815             break;
7816         case 'v':   /* ASCII Vertical Tab character (Decimal value 11) */
7817             *(optr++) = 11; ++iptr;
7818             break;
7819         case 'b':   /* ASCII Backspace character (Decimal value 8) */
7820             *(optr++) = 8; ++iptr;
7821             break;
7822         case '\\':   /* ASCII Backslash character (Decimal value 92) */
7823             *(optr++) = 92; ++iptr;
7824             break;
7825         case 'e':   /* ASCII Escape character (Decimal value 27) */
7826             *(optr++) = 27; ++iptr;
7827             break;
7828         case '\'':   /* ASCII Single Quote character (Decimal value 39) */
7829             *(optr++) = 39; ++iptr;
7830             break;
7831         case '"':   /* ASCII Double Quote character (Decimal value 34) */
7832             *(optr++) = 34; ++iptr;
7833             break;
7834         case '?':   /* ASCII Question Mark character (Decimal value 63) */
7835             *(optr++) = 63; ++iptr;
7836             break;
7837         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7838             *optr = *(iptr++) - '0';
7839             if ((*iptr >= '0') && (*iptr <= '7'))
7840                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7841             if ((*iptr >= '0') && (*iptr <= '7'))
7842                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7843             ++optr;
7844             break;
7845         case 'x':
7846             if (1) {
7847                 static const char *hex_digits = "0123456789ABCDEF";
7848                 const char *c;
7849 
7850                 ++iptr;
7851                 *optr = 0;
7852                 c = strchr (hex_digits, toupper(*iptr));
7853                 if (c) {
7854                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7855                     ++iptr;
7856                     }
7857                 c = strchr (hex_digits, toupper(*iptr));
7858                 if (c) {
7859                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7860                     ++iptr;
7861                     }
7862                 ++optr;
7863                 }
7864             break;
7865         default:
7866             return SCPE_ARG;    /* Invalid escape */
7867         }
7868     }
7869 *optr = '\0';
7870 *osize = (uint32)(optr-ostart);
7871 return SCPE_OK;
7872 }
7873 
7874 /* sim_encode_quoted_string
7875 
7876    Inputs:
7877         iptr        =   pointer to input buffer
7878         size        =   number of bytes of data in the buffer
7879 
7880    Outputs
7881         optr        =   pointer to output buffer
7882                         the output buffer must be freed by the caller
7883 
7884    The input data will be encoded into a simply printable form.
7885 */
7886 
7887 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7888 {
7889 size_t i;
7890 t_bool double_quote_found = FALSE;
7891 t_bool single_quote_found = FALSE;
7892 char quote = '"';
7893 char *tptr, *optr;
7894 
7895 optr = (char *)malloc (4*size + 3);
7896 if (optr == NULL)
7897     return NULL;
7898 tptr = optr;
7899 for (i=0; i<size; i++)
7900     switch ((char)iptr[i]) {
7901         case '"':
7902             double_quote_found = TRUE;
7903             break;
7904         case '\'':
7905             single_quote_found = TRUE;
7906             break;
7907         }
7908 if (double_quote_found && (!single_quote_found))
7909     quote = '\'';
7910 *tptr++ = quote;
7911 while (size--) {
7912     switch (*iptr) {
7913         case '\r':
7914             *tptr++ = '\\'; *tptr++ = 'r'; break;
7915         case '\n':
7916             *tptr++ = '\\'; *tptr++ = 'n'; break;
7917         case '\f':
7918             *tptr++ = '\\'; *tptr++ = 'f'; break;
7919         case '\t':
7920             *tptr++ = '\\'; *tptr++ = 't'; break;
7921         case '\v':
7922             *tptr++ = '\\'; *tptr++ = 'v'; break;
7923         case '\b':
7924             *tptr++ = '\\'; *tptr++ = 'b'; break;
7925         case '\\':
7926             *tptr++ = '\\'; *tptr++ = '\\'; break;
7927         case '"':
7928         case '\'':
7929             if (quote == *iptr)
7930                 *tptr++ = '\\';
7931         /*FALLTHRU*/ /* fall through */ /* fallthrough */
7932         default:
7933             if (sim_isprint (*iptr))
7934                 *tptr++ = *iptr;
7935             else {
7936                 (void)sprintf (tptr, "\\%03o", *iptr);
7937                 tptr += 4;
7938                 }
7939             break;
7940         }
7941     ++iptr;
7942     }
7943 *tptr++ = quote;
7944 *tptr++ = '\0';
7945 return optr;
7946 }
7947 
7948 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7949 {
7950 char *string;
7951 
7952 string = sim_encode_quoted_string (buf, size);
7953 (void)fprintf (st, "%s", string);
7954 FREE (string);
7955 }
7956 
7957 /* Find_device          find device matching input string
7958 
7959    Inputs:
7960         cptr    =       pointer to input string
7961    Outputs:
7962         result  =       pointer to device
7963 */
7964 
7965 DEVICE *find_dev (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7966 {
7967 int32 i;
7968 DEVICE *dptr;
7969 
7970 if (cptr == NULL)
7971     return NULL;
7972 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7973     if ((strcmp (cptr, dptr->name) == 0) ||
7974         (dptr->lname &&
7975         (strcmp (cptr, dptr->lname) == 0)))
7976         return dptr;
7977     }
7978 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7979     if ((strcmp (cptr, dptr->name) == 0) ||
7980         (dptr->lname &&
7981         (strcmp (cptr, dptr->lname) == 0)))
7982         return dptr;
7983     }
7984 return NULL;
7985 }
7986 
7987 /* Find_unit            find unit matching input string
7988 
7989    Inputs:
7990         cptr    =       pointer to input string
7991         uptr    =       pointer to unit pointer
7992    Outputs:
7993         result  =       pointer to device (null if no dev)
7994         *iptr   =       pointer to unit (null if nx unit)
7995 
7996 */
7997 
7998 DEVICE *find_unit (const char *cptr, UNIT **uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7999 {
8000 uint32 i, u;
8001 const char *nptr;
8002 const char *tptr;
8003 t_stat r;
8004 DEVICE *dptr;
8005 
8006 if (uptr == NULL)                                       /* arg error? */
8007     return NULL;
8008 *uptr = NULL;
8009 if ((dptr = find_dev (cptr))) {                         /* exact match? */
8010     if (qdisable (dptr))                                /* disabled? */
8011         return NULL;
8012     *uptr = dptr->units;                                /* unit 0 */
8013     return dptr;
8014     }
8015 
8016 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {     /* base + unit#? */
8017     if (qdisable (dptr))                                /* device disabled? */
8018         continue;
8019     if (dptr->numunits && /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/ /* any units? */
8020         (((nptr = dptr->name) &&
8021           (strncmp (cptr, nptr, strlen (nptr)) == 0)) || /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8022          ((nptr = dptr->lname) &&
8023           (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8024         tptr = cptr + strlen (nptr);
8025         if (sim_isdigit (*tptr)) {
8026             if (qdisable (dptr))                        /* disabled? */
8027                 return NULL;
8028             u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8029             if (r != SCPE_OK)                           /* error? */
8030                 *uptr = NULL;
8031             else
8032                 *uptr = dptr->units + u;
8033             return dptr;
8034             }
8035         }
8036     for (u = 0; u < dptr->numunits; u++) {
8037         if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8038             *uptr = &dptr->units[u];
8039             return dptr;
8040             }
8041         }
8042     }
8043 return NULL;
8044 }
8045 
8046 /* sim_register_internal_device   Add device to internal device list
8047 
8048    Inputs:
8049         dptr    =       pointer to device
8050 */
8051 
8052 t_stat sim_register_internal_device (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8053 {
8054 uint32 i;
8055 
8056 for (i = 0; (sim_devices[i] != NULL); i++)
8057     if (sim_devices[i] == dptr)
8058         return SCPE_OK;
8059 for (i = 0; i < sim_internal_device_count; i++)
8060     if (sim_internal_devices[i] == dptr)
8061         return SCPE_OK;
8062 ++sim_internal_device_count;
8063 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8064 if (!sim_internal_devices)
8065   {
8066     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8067                    __func__, __FILE__, __LINE__);
8068 #if defined(USE_BACKTRACE)
8069 # if defined(SIGUSR2)
8070     (void)raise(SIGUSR2);
8071     /*NOTREACHED*/ /* unreachable */
8072 # endif /* if defined(SIGUSR2) */
8073 #endif /* if defined(USE_BACKTRACE) */
8074     abort();
8075   }
8076 sim_internal_devices[sim_internal_device_count-1] = dptr;
8077 sim_internal_devices[sim_internal_device_count] = NULL;
8078 return SCPE_OK;
8079 }
8080 
8081 /* Find_dev_from_unit   find device for unit
8082 
8083    Inputs:
8084         uptr    =       pointer to unit
8085    Outputs:
8086         result  =       pointer to device
8087 */
8088 
8089 DEVICE *find_dev_from_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8090 {
8091 DEVICE *dptr;
8092 uint32 i, j;
8093 
8094 if (uptr == NULL)
8095     return NULL;
8096 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8097     for (j = 0; j < dptr->numunits; j++) {
8098         if (uptr == (dptr->units + j))
8099             return dptr;
8100         }
8101     }
8102 for (i = 0; i<sim_internal_device_count; i++) {
8103     dptr = sim_internal_devices[i];
8104     for (j = 0; j < dptr->numunits; j++) {
8105         if (uptr == (dptr->units + j))
8106             return dptr;
8107         }
8108     }
8109 return NULL;
8110 }
8111 
8112 /* Test for disabled device */
8113 
8114 t_bool qdisable (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8115 {
8116 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8117 }
8118 
8119 /* find_reg_glob        find globally unique register
8120 
8121    Inputs:
8122         cptr    =       pointer to input string
8123         optr    =       pointer to output pointer (can be null)
8124         gdptr   =       pointer to global device
8125    Outputs:
8126         result  =       pointer to register, NULL if error
8127         *optr   =       pointer to next character in input string
8128         *gdptr  =       pointer to device where found
8129 */
8130 
8131 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8132 {
8133 int32 i;
8134 DEVICE *dptr;
8135 REG *rptr, *srptr = NULL;
8136 
8137 *gdptr = NULL;
8138 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {        /* all dev */
8139     if (dptr->flags & DEV_DIS)                          /* skip disabled */
8140         continue;
8141     if ((rptr = find_reg (cptr, optr, dptr))) {         /* found? */
8142         if (srptr)                                      /* ambig? err */
8143             return NULL;
8144         srptr = rptr;                                   /* save reg */
8145         *gdptr = dptr;                                  /* save unit */
8146         }
8147     }
8148 return srptr;
8149 }
8150 
8151 /* find_reg             find register matching input string
8152 
8153    Inputs:
8154         cptr    =       pointer to input string
8155         optr    =       pointer to output pointer (can be null)
8156         dptr    =       pointer to device
8157    Outputs:
8158         result  =       pointer to register, NULL if error
8159         *optr   =       pointer to next character in input string
8160 */
8161 
8162 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8163 {
8164 CONST char *tptr;
8165 REG *rptr;
8166 size_t slnt;
8167 
8168 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8169     return NULL;
8170 tptr = cptr;
8171 do {
8172     tptr++;
8173     } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8174 slnt = tptr - cptr;
8175 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8176     if ((slnt == strlen (rptr->name)) &&
8177         (strncmp (cptr, rptr->name, slnt) == 0)) {
8178         if (optr != NULL)
8179             *optr = tptr;
8180         return rptr;
8181         }
8182     }
8183 return NULL;
8184 }
8185 
8186 /* get_switches         get switches from input string
8187 
8188    Inputs:
8189         cptr    =       pointer to input string
8190    Outputs:
8191         sw      =       switch bit mask
8192                         0 if no switches, -1 if error
8193 */
8194 
8195 int32 get_switches (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8196 {
8197 int32 sw;
8198 
8199 if (*cptr != '-')
8200     return 0;
8201 sw = 0;
8202 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8203     if (sim_isalpha (*cptr) == 0)
8204         return -1;
8205     sw = sw | SWMASK (toupper (*cptr));
8206     }
8207 return sw;
8208 }
8209 
8210 /* get_sim_sw           accumulate sim_switches
8211 
8212    Inputs:
8213         cptr    =       pointer to input string
8214    Outputs:
8215         ptr     =       pointer to first non-string glyph
8216                         NULL if error
8217 */
8218 
8219 CONST char *get_sim_sw (CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8220 {
8221 int32 lsw;
8222 char gbuf[CBUFSIZE];
8223 
8224 while (*cptr == '-') {                                  /* while switches */
8225     cptr = get_glyph (cptr, gbuf, 0);                   /* get switch glyph */
8226     lsw = get_switches (gbuf);                          /* parse */
8227     if (lsw <= 0)                                       /* invalid? */
8228         return NULL;
8229     sim_switches = sim_switches | lsw;                  /* accumulate */
8230     }
8231 return cptr;
8232 }
8233 
8234 /* get_sim_opt          get simulator command options
8235 
8236    Inputs:
8237         opt     =       command options
8238         cptr    =       pointer to input string
8239    Outputs:
8240         ptr     =       pointer to next glyph, NULL if error
8241         *stat   =       error status
8242 */
8243 
8244 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
     /* [previous][next][first][last][top][bottom][index][help] */
8245 {
8246 int32 t;
8247 char gbuf[CBUFSIZE];
8248 CONST char *svptr;
8249 DEVICE *tdptr;
8250 UNIT *tuptr;
8251 
8252 sim_switches = 0;                                       /* no switches */
8253 sim_ofile = NULL;                                       /* no output file */
8254 sim_schrptr = NULL;                                     /* no search */
8255 sim_schaptr = NULL;                                     /* no search */
8256 sim_stabr.logic = sim_staba.logic = SCH_OR;             /* default search params */
8257 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8258 sim_stabr.count = 1;
8259 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8260 if (!sim_stabr.mask)
8261   {
8262     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8263                    __func__, __FILE__, __LINE__);
8264 #if defined(USE_BACKTRACE)
8265 # if defined(SIGUSR2)
8266     (void)raise(SIGUSR2);
8267     /*NOTREACHED*/ /* unreachable */
8268 # endif /* if defined(SIGUSR2) */
8269 #endif /* if defined(USE_BACKTRACE) */
8270     abort();
8271   }
8272 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8273 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8274 if (!sim_stabr.comp)
8275   {
8276     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8277                    __func__, __FILE__, __LINE__);
8278 #if defined(USE_BACKTRACE)
8279 # if defined(SIGUSR2)
8280     (void)raise(SIGUSR2);
8281     /*NOTREACHED*/ /* unreachable */
8282 # endif /* if defined(SIGUSR2) */
8283 #endif /* if defined(USE_BACKTRACE) */
8284     abort();
8285   }
8286 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8287 sim_staba.count = sim_emax;
8288 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8289 if (!sim_staba.mask)
8290   {
8291     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8292                    __func__, __FILE__, __LINE__);
8293 #if defined(USE_BACKTRACE)
8294 # if defined(SIGUSR2)
8295     (void)raise(SIGUSR2);
8296     /*NOTREACHED*/ /* unreachable */
8297 # endif /* if defined(SIGUSR2) */
8298 #endif /* if defined(USE_BACKTRACE) */
8299     abort();
8300   }
8301 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8302 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8303 if (!sim_staba.comp)
8304   {
8305     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8306                    __func__, __FILE__, __LINE__);
8307 #if defined(USE_BACKTRACE)
8308 # if defined(SIGUSR2)
8309     (void)raise(SIGUSR2);
8310     /*NOTREACHED*/ /* unreachable */
8311 # endif /* if defined(SIGUSR2) */
8312 #endif /* if defined(USE_BACKTRACE) */
8313     abort();
8314   }
8315 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8316 if (! sim_dflt_dev)
8317   return NULL;
8318 sim_dfdev = sim_dflt_dev;
8319 sim_dfunit = sim_dfdev->units;
8320 sim_opt_out = 0;                                        /* no options yet */
8321 *st = SCPE_OK;
8322 while (*cptr) {                                         /* loop through modifiers */
8323     svptr = cptr;                                       /* save current position */
8324     if ((opt & CMD_OPT_OF) && (*cptr == '@')) {         /* output file spec? */
8325         if (sim_ofile) {                                /* already got one? */
8326             fclose (sim_ofile);                         /* one per customer */
8327             *st = SCPE_ARG;
8328             return NULL;
8329             }
8330         cptr = get_glyph (cptr + 1, gbuf, 0);
8331         sim_ofile = sim_fopen (gbuf, "a");              /* open for append */
8332         if (sim_ofile == NULL) {                        /* open failed? */
8333             *st = SCPE_OPENERR;
8334             return NULL;
8335             }
8336         sim_opt_out |= CMD_OPT_OF;                      /* got output file */
8337         continue;
8338         }
8339     cptr = get_glyph (cptr, gbuf, 0);
8340     if ((t = get_switches (gbuf)) != 0) {               /* try for switches */
8341         if (t < 0) {                                    /* err if bad switch */
8342             *st = SCPE_INVSW;
8343             return NULL;
8344             }
8345         sim_switches = sim_switches | t;                /* or in new switches */
8346         }
8347     else if ((opt & CMD_OPT_SCH) &&                     /* if allowed, */
8348         get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) { /* try for search */
8349         sim_schrptr = &sim_stabr;                       /* set search */
8350         sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);/* populate memory version of the same expression */
8351         sim_opt_out |= CMD_OPT_SCH;                     /* got search */
8352         }
8353     else if ((opt & CMD_OPT_DFT) &&                     /* default allowed? */
8354         ((sim_opt_out & CMD_OPT_DFT) == 0) &&           /* none yet? */
8355         (tdptr = find_unit (gbuf, &tuptr)) &&           /* try for default */
8356         (tuptr != NULL)) {
8357         sim_dfdev = tdptr;                              /* set as default */
8358         sim_dfunit = tuptr;
8359         sim_opt_out |= CMD_OPT_DFT;                     /* got default */
8360         }
8361     else return svptr;                                  /* not rec, break out */
8362     }
8363 return cptr;
8364 }
8365 
8366 /* put_switches         put switches into string
8367 
8368    Inputs:
8369         buf     =       pointer to string buffer
8370         bufsize =       size of string buffer
8371         sw      =       switch bit mask
8372    Outputs:
8373         buf     =       buffer with switches converted to text
8374 */
8375 
8376 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
8377 {
8378 char *optr = buf;
8379 int32 bit;
8380 
8381 (void)memset (buf, 0, bufsize);
8382 if ((sw == 0) || (bufsize < 3))
8383     return buf;
8384 --bufsize;                          /* leave room for terminating NUL */
8385 *optr++ = '-';
8386 for (bit=0; bit <= ('Z'-'A'); bit++)
8387     if (sw & (1 << bit))
8388         if ((size_t)(optr - buf) < bufsize)
8389             *optr++ = 'A' + bit;
8390 return buf;
8391 }
8392 
8393 /* Get register search specification
8394 
8395    Inputs:
8396         cptr    =       pointer to input string
8397         radix   =       radix for numbers
8398         schptr =        pointer to search table
8399    Outputs:
8400         return =        NULL if error
8401                         schptr if valid search specification
8402 */
8403 
8404 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8405 {
8406 int32 c;
8407 size_t logop, cmpop;
8408 t_value logval, cmpval;
8409 const char *sptr;
8410 CONST char *tptr;
8411 const char logstr[] = "|&^", cmpstr[] = "=!><";
8412 /* Using a const instead of a #define. */
8413 const size_t invalid_op = (size_t) -1;
8414 
8415 logval = cmpval = 0;
8416 if (*cptr == 0)                                         /* check for clause */
8417     return NULL;
8418 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8419 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8420     if ((sptr = strchr (logstr, c))) {                  /* check for mask */
8421         logop = sptr - logstr;
8422         logval = strtotv (cptr, &tptr, radix);
8423         if (cptr == tptr)
8424             return NULL;
8425         cptr = tptr;
8426         }
8427     else if ((sptr = strchr (cmpstr, c))) {             /* check for boolop */
8428         cmpop = sptr - cmpstr;
8429         if (*cptr == '=') {
8430             cmpop = cmpop + strlen (cmpstr);
8431             cptr++;
8432             }
8433         cmpval = strtotv (cptr, &tptr, radix);
8434         if (cptr == tptr)
8435             return NULL;
8436         cptr = tptr;
8437         }
8438     else return NULL;
8439     }                                                   /* end for */
8440 if (schptr->count != 1) {
8441     FREE (schptr->mask);
8442     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8443     FREE (schptr->comp);
8444     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8445     }
8446 if (logop != invalid_op) {
8447     schptr->logic = logop;
8448     schptr->mask[0] = logval;
8449     }
8450 if (cmpop != invalid_op) {
8451     schptr->boolop = cmpop;
8452     schptr->comp[0] = cmpval;
8453     }
8454 schptr->count = 1;
8455 return schptr;
8456 }
8457 
8458 /* Get memory search specification
8459 
8460    Inputs:
8461         cptr    =       pointer to input string
8462         radix   =       radix for numbers
8463         schptr =        pointer to search table
8464    Outputs:
8465         return =        NULL if error
8466                         schptr if valid search specification
8467 */
8468 
8469 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8470 {
8471 int32 c;
8472 size_t logop, cmpop;
8473 t_value *logval, *cmpval;
8474 t_stat reason = SCPE_OK;
8475 CONST char *ocptr = cptr;
8476 const char *sptr;
8477 char gbuf[CBUFSIZE];
8478 const char logstr[] = "|&^", cmpstr[] = "=!><";
8479 /* Using a const instead of a #define. */
8480 const size_t invalid_op = (size_t) -1;
8481 
8482 if (*cptr == 0)                                         /* check for clause */
8483     return NULL;
8484 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8485 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8486 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8487 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8488     if (NULL != (sptr = strchr (logstr, c))) {          /* check for mask */
8489         logop = sptr - logstr;
8490         cptr = get_glyph (cptr, gbuf, 0);
8491         reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8492         if (reason > 0) {
8493             FREE (logval);
8494             FREE (cmpval);
8495             return get_rsearch (ocptr, radix, schptr);
8496             }
8497         }
8498     else if (NULL != (sptr = strchr (cmpstr, c))) {     /* check for boolop */
8499         cmpop = sptr - cmpstr;
8500         if (*cptr == '=') {
8501             cmpop = cmpop + strlen (cmpstr);
8502             cptr++;
8503             }
8504         cptr = get_glyph (cptr, gbuf, 0);
8505         reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8506         if (reason > 0) {
8507             FREE (logval);
8508             FREE (cmpval);
8509             return get_rsearch (ocptr, radix, schptr);
8510             }
8511         }
8512     else {
8513         FREE (logval);
8514         FREE (cmpval);
8515         return NULL;
8516         }
8517     }                                                   /* end for */
8518 if (schptr->count != (uint32)(1 - reason)) {
8519     schptr->count = 1 - reason;
8520     FREE (schptr->mask);
8521     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8522     FREE (schptr->comp);
8523     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8524     }
8525 if (logop != invalid_op) {
8526     schptr->logic = logop;
8527     FREE (schptr->mask);
8528     schptr->mask = logval;
8529     }
8530 else {
8531     FREE (logval);
8532     }
8533 if (cmpop != invalid_op) {
8534     schptr->boolop = cmpop;
8535     FREE (schptr->comp);
8536     schptr->comp = cmpval;
8537     }
8538 else {
8539     FREE (cmpval);
8540     }
8541 return schptr;
8542 }
8543 
8544 /* Test value against search specification
8545 
8546    Inputs:
8547         val    =        value list to test
8548         schptr =        pointer to search table
8549    Outputs:
8550         return =        1 if value passes search criteria, 0 if not
8551 */
8552 
8553 int32 test_search (t_value *values, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8554 {
8555 t_value *val = NULL;
8556 int32 i, updown;
8557 int32 ret = 0;
8558 
8559 if (schptr == NULL)
8560     return ret;
8561 
8562 val = (t_value *)malloc (schptr->count * sizeof (*values));
8563 if (!val)
8564   {
8565     (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8566                   __func__, __FILE__, __LINE__);
8567 #if defined(USE_BACKTRACE)
8568 # if defined(SIGUSR2)
8569     (void)raise(SIGUSR2);
8570     /*NOTREACHED*/ /* unreachable */
8571 # endif /* if defined(SIGUSR2) */
8572 #endif /* if defined(USE_BACKTRACE) */
8573     abort();
8574   }
8575 for (i=0; i<(int32)schptr->count; i++) {
8576     val[i] = values[i];
8577     switch (schptr->logic) {                            /* case on logical */
8578 
8579         case SCH_OR:
8580             val[i] = val[i] | schptr->mask[i];
8581             break;
8582 
8583         case SCH_AND:
8584             val[i] = val[i] & schptr->mask[i];
8585             break;
8586 
8587         case SCH_XOR:
8588             val[i] = val[i] ^ schptr->mask[i];
8589             break;
8590             }
8591     }
8592 
8593 ret = 1;
8594 if (1) {    /* Little Endian VM */
8595     updown = -1;
8596     i=schptr->count-1;
8597     }
8598 else {      /* Big Endian VM */
8599     updown = 1;
8600     i=0;
8601     }
8602 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8603     switch (schptr->boolop) {                           /* case on comparison */
8604 
8605         case SCH_E: case SCH_EE:
8606             if (val[i] != schptr->comp[i])
8607                 ret = 0;
8608             break;
8609 
8610         case SCH_N: case SCH_NE:
8611             if (val[i] == schptr->comp[i])
8612                 ret = 0;
8613             break;
8614 
8615         case SCH_G:
8616             if (val[i] <= schptr->comp[i])
8617                 ret = 0;
8618             break;
8619 
8620         case SCH_GE:
8621             if (val[i] < schptr->comp[i])
8622                 ret = 0;
8623             break;
8624 
8625         case SCH_L:
8626             if (val[i] >= schptr->comp[i])
8627                 ret = 0;
8628             break;
8629 
8630         case SCH_LE:
8631             if (val[i] > schptr->comp[i])
8632                 ret = 0;
8633             break;
8634         }
8635     }
8636 FREE (val);
8637 return ret;
8638 }
8639 
8640 /* Radix independent input/output package
8641 
8642    strtotv - general radix input routine
8643 
8644    Inputs:
8645         inptr   =       string to convert
8646         endptr  =       pointer to first unconverted character
8647         radix   =       radix for input
8648    Outputs:
8649         value   =       converted value
8650 
8651    On an error, the endptr will equal the inptr.
8652 */
8653 
8654 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
     /* [previous][next][first][last][top][bottom][index][help] */
8655 {
8656 int32 nodigit;
8657 t_value val;
8658 uint32 c, digit;
8659 
8660 *endptr = inptr;                                        /* assume fails */
8661 if ((radix < 2) || (radix > 36))
8662     return 0;
8663 while (sim_isspace (*inptr))                            /* bypass white space */
8664     inptr++;
8665 val = 0;
8666 nodigit = 1;
8667 for (c = *inptr; sim_isalnum(c); c = *++inptr) {        /* loop through char */
8668     if (sim_islower (c))
8669         c = toupper (c);
8670     if (sim_isdigit (c))                                /* digit? */
8671         digit = c - (uint32) '0';
8672     else if (radix <= 10)                               /* stop if not expected */
8673         break;
8674     else digit = c + 10 - (uint32) 'A';                 /* convert letter */
8675     if (digit >= radix)                                 /* valid in radix? */
8676         return 0;
8677     val = (val * radix) + digit;                        /* add to value */
8678     nodigit = 0;
8679     }
8680 if (nodigit)                                            /* no digits? */
8681     return 0;
8682 *endptr = inptr;                                        /* result pointer */
8683 return val;
8684 }
8685 
8686 /* fprint_val - general radix printing routine
8687 
8688    Inputs:
8689         stream  =       stream designator
8690         val     =       value to print
8691         radix   =       radix to print
8692         width   =       width to print
8693         format  =       leading zeroes format
8694    Outputs:
8695         status  =       error status
8696         if stream is NULL, returns length of output that would
8697         have been generated.
8698 */
8699 
8700 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8701                    size_t width, uint32 format)
8702 {
8703 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8704 t_value owtest, wtest;
8705 size_t d;
8706 size_t digit;
8707 size_t ndigits;
8708 size_t commas = 0;
8709 char dbuf[MAX_WIDTH + 1];
8710 
8711 for (d = 0; d < MAX_WIDTH; d++)
8712     dbuf[d] = (format == PV_RZRO)? '0': ' ';
8713 dbuf[MAX_WIDTH] = 0;
8714 d = MAX_WIDTH;
8715 do {
8716     d = d - 1;
8717     digit = val % radix;
8718     val = val / radix;
8719     dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8720     } while ((d > 0) && (val != 0));
8721 
8722 switch (format) {
8723     case PV_LEFT:
8724         break;
8725     case PV_RZRO:
8726         wtest = owtest = radix;
8727         ndigits = 1;
8728         while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8729             owtest = wtest;
8730             wtest = wtest * radix;
8731             ndigits = ndigits + 1;
8732             }
8733         if ((MAX_WIDTH - (ndigits + commas)) < d)
8734             d = MAX_WIDTH - (ndigits + commas);
8735         break;
8736     }
8737 if (NULL == buffer)                   /* Potentially unsafe wraparound if */
8738     return ((t_stat) strlen(dbuf+d)); /*  sizeof(t_stat) < sizeof(size_t) */
8739 *buffer = '\0';
8740 if (width < strlen(dbuf+d))
8741     return SCPE_IOERR;
8742 strcpy(buffer, dbuf+d);
8743 return SCPE_OK;
8744 }
8745 
8746 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8747     uint32 width, uint32 format)
8748 {
8749 char dbuf[MAX_WIDTH + 1];
8750 
8751 if (!stream)
8752     return sprint_val (NULL, val, radix, width, format);
8753 if (width > MAX_WIDTH)
8754     width = MAX_WIDTH;
8755 sprint_val (dbuf, val, radix, width, format);
8756 if (Fprintf (stream, "%s", dbuf) < 0)
8757     return SCPE_IOERR;
8758 return SCPE_OK;
8759 }
8760 
8761 const char *sim_fmt_secs (double seconds)
     /* [previous][next][first][last][top][bottom][index][help] */
8762 {
8763 static char buf[60];
8764 char frac[16] = "";
8765 const char *sign = "";
8766 double val = seconds;
8767 double days, hours, mins, secs, msecs, usecs;
8768 
8769 if (val == 0.0)
8770     return "";
8771 if (val < 0.0) {
8772     sign = "-";
8773     val = -val;
8774     }
8775 days = floor (val / (24.0*60.0*60.0));
8776 val -= (days * 24.0*60.0*60.0);
8777 hours = floor (val / (60.0*60.0));
8778 val -= (hours * 60.0 * 60.0);
8779 mins = floor (val / 60.0);
8780 val -= (mins * 60.0);
8781 secs = floor (val);
8782 val -= secs;
8783 val *= 1000.0;
8784 msecs = floor (val);
8785 val -= msecs;
8786 val *= 1000.0;
8787 usecs = floor (val+0.5);
8788 if (usecs == 1000.0) {
8789     usecs = 0.0;
8790     msecs += 1;
8791     }
8792 if ((msecs > 0.0) || (usecs > 0.0)) {
8793     (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8794     while (frac[strlen (frac) - 1] == '0') //-V557
8795         frac[strlen (frac) - 1] = '\0'; //-V557
8796     if (strlen (frac) == 1)
8797         frac[0] = '\0';
8798     }
8799 if (days > 0)
8800     (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8801                    sign, days, (days != 1) ? "s" : "", hours, mins,
8802                    secs, frac, (days == 1) ? "s" : "");
8803 else
8804     if (hours > 0)
8805         (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8806                        sign, hours, mins, secs, frac);
8807     else
8808         if (mins > 0)
8809             (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8810                            sign, mins, secs, frac);
8811         else
8812             if (secs > 0)
8813                 (void)sprintf (buf, "%s%.0f%s second",
8814                                sign, secs, frac);
8815             else
8816                 if (msecs > 0) {
8817                     if (usecs > 0)
8818                         (void)sprintf (buf, "%s%.0f.%s msec",
8819                                        sign, msecs, frac+4);
8820                     else
8821                         (void)sprintf (buf, "%s%.0f msec",
8822                                        sign, msecs);
8823                     }
8824                 else
8825                     (void)sprintf (buf, "%s%.0f usec",
8826                                    sign, usecs);
8827 if (0 != strncmp ("1 ", buf, 2))
8828     strcpy (&buf[strlen (buf)], "s");
8829 return buf;
8830 }
8831 
8832 /*
8833  * Event queue package
8834  *
8835  *      sim_activate            add entry to event queue
8836  *      sim_activate_abs        add entry to event queue even if event already scheduled
8837  *      sim_activate_after      add entry to event queue after a specified amount of wall time
8838  *      sim_cancel              remove entry from event queue
8839  *      sim_process_event       process entries on event queue
8840  *      sim_is_active           see if entry is on event queue
8841  *      sim_activate_time       return time until activation
8842  *      sim_atime               return absolute time for an entry
8843  *      sim_gtime               return global time
8844  *      sim_qcount              return event queue entry count
8845  */
8846 
8847 t_stat sim_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8848 {
8849 UNIT *uptr;
8850 t_stat reason;
8851 #if defined(TESTING)
8852 cpu_state_t * cpup = _cpup;
8853 #endif
8854 
8855 if (stop_cpu)                                           /* stop CPU? */
8856   {
8857 #if defined(WIN_STDIO)
8858     (void)fflush(stdout);
8859     (void)fflush(stderr);
8860 #endif /* if defined(WIN_STDIO) */
8861     return SCPE_STOP;
8862   }
8863 UPDATE_SIM_TIME;                                        /* update sim time */
8864 
8865 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8866     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8867     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8868                "Queue Empty New Interval = %d\r\n",
8869                sim_interval);
8870     return SCPE_OK;
8871     }
8872 sim_processing_event = TRUE;
8873 do {
8874     uptr = sim_clock_queue;                             /* get first */
8875     sim_clock_queue = uptr->next;                       /* remove first */
8876     uptr->next = NULL;                                  /* hygiene */
8877     sim_interval -= uptr->time;
8878     uptr->time = 0;
8879     if (sim_clock_queue != QUEUE_LIST_END)
8880         sim_interval = sim_clock_queue->time;
8881     else
8882         sim_interval = noqueue_time = NOQUEUE_WAIT;
8883     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8884                "Processing Event for %s\r\n", sim_uname (uptr));
8885     if (uptr->action != NULL)
8886         reason = uptr->action (uptr);
8887     else
8888         reason = SCPE_OK;
8889     } while ((reason == SCPE_OK) &&
8890              (sim_interval <= 0) &&
8891              (sim_clock_queue != QUEUE_LIST_END) &&
8892              (!stop_cpu));
8893 
8894 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8895     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8896     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8897                "Processing Queue Complete New Interval = %d\r\n",
8898                sim_interval);
8899     }
8900 else
8901     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8902                "Processing Queue Complete New Interval = %d(%s)\r\n",
8903                sim_interval, sim_uname(sim_clock_queue));
8904 
8905 if ((reason == SCPE_OK) && stop_cpu)
8906   {
8907 #if defined(WIN_STDIO)
8908     (void)fflush(stdout);
8909     (void)fflush(stderr);
8910 #endif /* if defined(WIN_STDIO) */
8911     reason = SCPE_STOP;
8912   }
8913 sim_processing_event = FALSE;
8914 return reason;
8915 }
8916 
8917 /* sim_activate - activate (queue) event
8918 
8919    Inputs:
8920         uptr    =       pointer to unit
8921         event_time =    relative timeout
8922    Outputs:
8923         reason  =       result (SCPE_OK if ok)
8924 */
8925 
8926 t_stat sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8927 {
8928 if (uptr->dynflags & UNIT_TMR_UNIT)
8929     return sim_timer_activate (uptr, event_time);
8930 return _sim_activate (uptr, event_time);
8931 }
8932 
8933 t_stat _sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8934 {
8935 UNIT *cptr, *prvptr;
8936 int32 accum;
8937 #if defined(TESTING)
8938 cpu_state_t * cpup = _cpup;
8939 #endif
8940 
8941 if (sim_is_active (uptr))                               /* already active? */
8942     return SCPE_OK;
8943 UPDATE_SIM_TIME;                                        /* update sim time */
8944 
8945 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
8946 
8947 prvptr = NULL;
8948 accum = 0;
8949 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8950     if (event_time < (accum + cptr->time))
8951         break;
8952     accum = accum + cptr->time;
8953     prvptr = cptr;
8954     }
8955 if (prvptr == NULL) {                                   /* insert at head */
8956     cptr = uptr->next = sim_clock_queue;
8957     sim_clock_queue = uptr;
8958     }
8959 else {
8960     cptr = uptr->next = prvptr->next;                   /* insert at prvptr */
8961     prvptr->next = uptr;
8962     }
8963 uptr->time = event_time - accum;
8964 if (cptr != QUEUE_LIST_END)
8965     cptr->time = cptr->time - uptr->time;
8966 sim_interval = sim_clock_queue->time;
8967 return SCPE_OK;
8968 }
8969 
8970 /* sim_activate_abs - activate (queue) event even if event already scheduled
8971 
8972    Inputs:
8973         uptr    =       pointer to unit
8974         event_time =    relative timeout
8975    Outputs:
8976         reason  =       result (SCPE_OK if ok)
8977 */
8978 
8979 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8980 {
8981 sim_cancel (uptr);
8982 return _sim_activate (uptr, event_time);
8983 }
8984 
8985 /* sim_activate_after - activate (queue) event
8986 
8987    Inputs:
8988         uptr    =       pointer to unit
8989         usec_delay =    relative timeout (in microseconds)
8990    Outputs:
8991         reason  =       result (SCPE_OK if ok)
8992 */
8993 
8994 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
8995 {
8996 return _sim_activate_after (uptr, usec_delay);
8997 }
8998 
8999 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
9000 {
9001 if (sim_is_active (uptr))                               /* already active? */
9002     return SCPE_OK;
9003 return sim_timer_activate_after (uptr, usec_delay);
9004 }
9005 
9006 /* sim_cancel - cancel (dequeue) event
9007 
9008    Inputs:
9009         uptr    =       pointer to unit
9010    Outputs:
9011         reason  =       result (SCPE_OK if ok)
9012 
9013 */
9014 
9015 t_stat sim_cancel (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9016 {
9017 UNIT *cptr, *nptr;
9018 #if defined(TESTING)
9019 cpu_state_t * cpup = _cpup;
9020 #endif
9021 
9022 if (sim_clock_queue == QUEUE_LIST_END)
9023     return SCPE_OK;
9024 if (!sim_is_active (uptr))
9025     return SCPE_OK;
9026 UPDATE_SIM_TIME;                                        /* update sim time */
9027 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9028 nptr = QUEUE_LIST_END;
9029 
9030 if (sim_clock_queue == uptr) {
9031     nptr = sim_clock_queue = uptr->next;
9032     uptr->next = NULL;                                  /* hygiene */
9033     }
9034 else {
9035     for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9036         if (cptr->next == uptr) {
9037             nptr = cptr->next = uptr->next;
9038             uptr->next = NULL;                          /* hygiene */
9039             break;                                      /* end queue scan */
9040             }
9041         }
9042     }
9043 if (nptr != QUEUE_LIST_END)
9044     nptr->time += (uptr->next) ? 0 : uptr->time;
9045 if (!uptr->next)
9046     uptr->time = 0;
9047 if (sim_clock_queue != QUEUE_LIST_END)
9048     sim_interval = sim_clock_queue->time;
9049 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9050 if (uptr->next) {
9051     sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9052     if (sim_deb)
9053         fclose(sim_deb);
9054     (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9055                    __func__, __FILE__, __LINE__);
9056     abort ();
9057     }
9058 return SCPE_OK;
9059 }
9060 
9061 /* sim_is_active - test for entry in queue
9062 
9063    Inputs:
9064         uptr    =       pointer to unit
9065    Outputs:
9066         result =        TRUE if unit is busy, FALSE inactive
9067 */
9068 
9069 t_bool sim_is_active (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9070 {
9071 if (uptr->next == NULL)
9072   return FALSE;
9073 else
9074 return TRUE;
9075 }
9076 
9077 /* sim_activate_time - return activation time
9078 
9079    Inputs:
9080         uptr    =       pointer to unit
9081    Outputs:
9082         result =        absolute activation time + 1, 0 if inactive
9083 */
9084 
9085 int32 sim_activate_time (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9086 {
9087 UNIT *cptr;
9088 int32 accum = 0;
9089 
9090 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9091     if (cptr == sim_clock_queue) {
9092         if (sim_interval > 0)
9093             accum = accum + sim_interval;
9094         }
9095     else
9096         accum = accum + cptr->time;
9097     if (cptr == uptr)
9098         return accum + 1;
9099     }
9100 return 0;
9101 }
9102 
9103 /* sim_gtime - return global time
9104 
9105    Inputs: none
9106    Outputs:
9107         time    =       global time
9108 */
9109 
9110 double sim_gtime (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9111 {
9112 return sim_time;
9113 }
9114 
9115 /* sim_qcount - return queue entry count
9116 
9117    Inputs: none
9118    Outputs:
9119         count   =       number of entries on the queue
9120 */
9121 
9122 int32 sim_qcount (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9123 {
9124 int32 cnt;
9125 UNIT *uptr;
9126 
9127 cnt = 0;
9128 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9129     cnt++;
9130 return cnt;
9131 }
9132 
9133 /* Breakpoint package.  This module replaces the VM-implemented one
9134    instruction breakpoint capability.
9135 
9136    Breakpoints are stored in table sim_brk_tab, which is ordered by address for
9137    efficient binary searching.  A breakpoint consists of a six entry structure:
9138 
9139         addr                    address of the breakpoint
9140         type                    types of breakpoints set on the address
9141                                 a bit mask representing letters A-Z
9142         cnt                     number of iterations before breakp is taken
9143         action                  pointer command string to be executed
9144                                 when break is taken
9145         next                    list of other breakpoints with the same addr specifier
9146         time_fired              array of when this breakpoint was fired for each class
9147 
9148    sim_brk_summ is a summary of the types of breakpoints that are currently set (it
9149    is the bitwise OR of all the type fields).  A simulator need only check for
9150    a breakpoint of type X if bit SWMASK('X') is set in sim_brk_summ.
9151 
9152    The package contains the following public routines:
9153 
9154         sim_brk_init            initialize
9155         sim_brk_set             set breakpoint
9156         sim_brk_clr             clear breakpoint
9157         sim_brk_clrall          clear all breakpoints
9158         sim_brk_show            show breakpoint
9159         sim_brk_showall         show all breakpoints
9160         sim_brk_test            test for breakpoint
9161         sim_brk_npc             PC has been changed
9162         sim_brk_getact          get next action
9163         sim_brk_clract          clear pending actions
9164 
9165    Initialize breakpoint system.
9166 */
9167 
9168 t_stat sim_brk_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9169 {
9170 int32 i;
9171 
9172 for (i=0; i<sim_brk_lnt; i++) {
9173     BRKTAB *bp;
9174     if (sim_brk_tab)
9175       {
9176         bp = sim_brk_tab[i];
9177 
9178         while (bp)
9179           {
9180             BRKTAB *bpt = bp->next;
9181 
9182             FREE (bp->act);
9183             FREE (bp);
9184             bp = bpt;
9185           }
9186       }
9187 }
9188 if (sim_brk_tab != NULL)
9189     (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9190 sim_brk_lnt = SIM_BRK_INILNT;
9191 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9192 if (sim_brk_tab == NULL)
9193     return SCPE_MEM;
9194 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9195 sim_brk_ent = sim_brk_ins = 0;
9196 sim_brk_clract ();
9197 sim_brk_npc (0);
9198 return SCPE_OK;
9199 }
9200 
9201 /* Search for a breakpoint in the sorted breakpoint table */
9202 
9203 BRKTAB *sim_brk_fnd (t_addr loc)
     /* [previous][next][first][last][top][bottom][index][help] */
9204 {
9205 int32 lo, hi, p;
9206 BRKTAB *bp;
9207 
9208 if (sim_brk_ent == 0) {                                 /* table empty? */
9209     sim_brk_ins = 0;                                    /* insrt at head */
9210     return NULL;                                        /* sch fails */
9211     }
9212 lo = 0;                                                 /* initial bounds */
9213 hi = sim_brk_ent - 1;
9214 do {
9215     p = (lo + hi) >> 1;                                 /* probe */
9216     bp = sim_brk_tab[p];                                /* table addr */
9217     if (loc == bp->addr) {                              /* match? */
9218         sim_brk_ins = p;
9219         return bp;
9220         }
9221     else if (loc < bp->addr)                            /* go down? p is upper */
9222         hi = p - 1;
9223     else lo = p + 1;                                    /* go up? p is lower */
9224     } while (lo <= hi);
9225 if (loc < bp->addr)                                     /* insrt before or */
9226     sim_brk_ins = p;
9227 else sim_brk_ins = p + 1;                               /* after last sch */
9228 return NULL;
9229 }
9230 
9231 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
     /* [previous][next][first][last][top][bottom][index][help] */
9232 {
9233 BRKTAB *bp = sim_brk_fnd (loc);
9234 
9235 while (bp) {
9236     if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9237                   (bp->typ == btyp))
9238         return bp;
9239     bp = bp->next;
9240     }
9241 return bp;
9242 }
9243 
9244 /* Insert a breakpoint */
9245 
9246 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9247 {
9248 int32 i, t;
9249 BRKTAB *bp, **newp;
9250 
9251 if (sim_brk_ins < 0)
9252     return NULL;
9253 if (sim_brk_ent >= sim_brk_lnt) {                       /* out of space? */
9254     t = sim_brk_lnt + SIM_BRK_INILNT;                   /* new size */
9255     newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));    /* new table */
9256     if (newp == NULL)                                   /* can't extend */
9257         return NULL;
9258     memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));/* copy table */
9259     (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));/* zero new entries */
9260     FREE (sim_brk_tab);                                 /* free old table */
9261     sim_brk_tab = newp;                                 /* new base, lnt */
9262     sim_brk_lnt = t;
9263     }
9264 if ((sim_brk_ins == sim_brk_ent) ||
9265     ((sim_brk_ins != sim_brk_ent) && //-V728
9266      (sim_brk_tab[sim_brk_ins]->addr != loc))) {        /* need to open a hole? */
9267     for (i = sim_brk_ent; i > sim_brk_ins; --i)
9268         sim_brk_tab[i] = sim_brk_tab[i - 1];
9269     sim_brk_tab[sim_brk_ins] = NULL;
9270     }
9271 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9272 if (!bp)
9273   {
9274     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9275                    __func__, __FILE__, __LINE__);
9276 #if defined(USE_BACKTRACE)
9277 # if defined(SIGUSR2)
9278     (void)raise(SIGUSR2);
9279     /*NOTREACHED*/ /* unreachable */
9280 # endif /* if defined(SIGUSR2) */
9281 #endif /* if defined(USE_BACKTRACE) */
9282     abort();
9283   }
9284 bp->next = sim_brk_tab[sim_brk_ins];
9285 sim_brk_tab[sim_brk_ins] = bp;
9286 if (bp->next == NULL)
9287     sim_brk_ent += 1;
9288 bp->addr = loc;
9289 bp->typ = btyp;
9290 bp->cnt = 0;
9291 bp->act = NULL;
9292 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9293     bp->time_fired[i] = -1.0;
9294 return bp;
9295 }
9296 
9297 /* Set a breakpoint of type sw */
9298 
9299 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
     /* [previous][next][first][last][top][bottom][index][help] */
9300 {
9301 BRKTAB *bp;
9302 
9303 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9304     sw |= sim_brk_dflt;
9305 if (~sim_brk_types & sw) {
9306     char gbuf[CBUFSIZE];
9307 
9308     return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9309     }
9310 if ((sw & BRK_TYP_DYN_ALL) && act)                      /* can't specify an action with a dynamic breakpoint */
9311     return SCPE_ARG;
9312 bp = sim_brk_fnd (loc);                                 /* loc present? */
9313 if (!bp)                                                /* no, allocate */
9314     bp = sim_brk_new (loc, sw);
9315 else {
9316     while (bp && (bp->typ != (uint32)sw))
9317         bp = bp->next;
9318     if (!bp)
9319         bp = sim_brk_new (loc, sw);
9320     }
9321 if (!bp)                                                /* still no? mem err */
9322     return SCPE_MEM;
9323 bp->cnt = ncnt;                                         /* set count */
9324 if ((!(sw & BRK_TYP_DYN_ALL)) &&                        /* Not Dynamic and */
9325     (bp->act != NULL) && (act != NULL)) {               /* replace old action? */
9326     FREE (bp->act);                                     /* deallocate */
9327     bp->act = NULL;                                     /* now no action */
9328     }
9329 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9330     char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char)); /* alloc buf */
9331     if (newp == NULL)                                   /* mem err? */
9332         return SCPE_MEM;
9333     strncpy (newp, act, CBUFSIZE);                      /* copy action */
9334     bp->act = newp;                                     /* set pointer */
9335     }
9336 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9337 return SCPE_OK;
9338 }
9339 
9340 /* Clear a breakpoint */
9341 
9342 t_stat sim_brk_clr (t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9343 {
9344 BRKTAB *bpl = NULL;
9345 BRKTAB *bp = sim_brk_fnd (loc);
9346 int32 i;
9347 
9348 if (!bp)                                                /* not there? ok */
9349     return SCPE_OK;
9350 if (sw == 0)
9351     sw = SIM_BRK_ALLTYP;
9352 
9353 #if !defined(__clang_analyzer__)
9354 while (bp) {
9355     if (bp->typ == (bp->typ & sw)) {
9356         FREE (bp->act);                                 /* deallocate action */
9357         if (bp == sim_brk_tab[sim_brk_ins])
9358             bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9359         else
9360           {
9361             if (bpl)
9362               bpl->next = bp->next;
9363           }
9364         FREE (bp);
9365         bp = bpl;
9366         }
9367     else {
9368         bpl = bp;
9369         bp = bp->next;
9370         }
9371     }
9372 #endif /* if !defined(__clang_analyzer__) */
9373 if (sim_brk_tab[sim_brk_ins] == NULL) {                 /* erased entry */
9374     sim_brk_ent = sim_brk_ent - 1;                      /* decrement count */
9375     for (i = sim_brk_ins; i < sim_brk_ent; i++)         /* shuffle remaining entries */
9376         sim_brk_tab[i] = sim_brk_tab[i+1];
9377     }
9378 sim_brk_summ = 0;                                       /* recalc summary */
9379 for (i = 0; i < sim_brk_ent; i++) {
9380     bp = sim_brk_tab[i];
9381     while (bp) {
9382         sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9383         bp = bp->next;
9384         }
9385     }
9386 return SCPE_OK;
9387 }
9388 
9389 /* Clear all breakpoints */
9390 
9391 t_stat sim_brk_clrall (int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9392 {
9393 int32 i;
9394 
9395 if (sw == 0)
9396     sw = SIM_BRK_ALLTYP;
9397 for (i = 0; i < sim_brk_ent;) {
9398     t_addr loc = sim_brk_tab[i]->addr;
9399     sim_brk_clr (loc, sw);
9400     if ((i < sim_brk_ent) &&
9401         (loc == sim_brk_tab[i]->addr))
9402         ++i;
9403     }
9404 return SCPE_OK;
9405 }
9406 
9407 /* Show a breakpoint */
9408 
9409 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9410 {
9411 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9412 DEVICE *dptr;
9413 uint32 i, any;
9414 
9415 if ((sw == 0) || (sw == SWMASK ('C'))) {
9416     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9417 if (!bp || (!(bp->typ & sw))) {
9418     return SCPE_OK; }
9419 dptr = sim_dflt_dev;
9420 if (dptr == NULL) {
9421     return SCPE_OK; }
9422 if (sw & SWMASK ('C')) {
9423     if (st != NULL) {
9424         (void)fprintf (st, "SET BREAK "); }
9425 } else {
9426     if (sim_vm_fprint_addr) {
9427         sim_vm_fprint_addr
9428             (st, dptr, loc);
9429     } else {
9430         fprint_val
9431             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9432     if (st != NULL) {
9433         (void)fprintf (st, ":\t"); }
9434     }
9435 for (i = any = 0; i < 26; i++) {
9436     if ((bp->typ >> i) & 1) {
9437         if ((sw & SWMASK ('C')) == 0) {
9438             if (any) {
9439                 if (st != NULL) {
9440                     (void)fprintf (st, ", "); } }
9441             if (st != NULL) {
9442                 fputc (i + 'A', st); }
9443             }
9444         } else {
9445             if (st != NULL) {
9446                 (void)fprintf (st, "-%c", i + 'A'); }
9447         any = 1;
9448         }
9449     }
9450 if (sw & SWMASK ('C')) {
9451     if (st != NULL) {
9452         (void)fprintf (st, " "); }
9453     if (sim_vm_fprint_addr) {
9454         if (st != NULL) {
9455             sim_vm_fprint_addr (st, dptr, loc); }
9456     } else {
9457         fprint_val
9458             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9459     }
9460 if (bp->cnt > 0) {
9461     if (st != NULL) {
9462         (void)fprintf (st, "[%d]", bp->cnt); } }
9463 if (bp->act != NULL) {
9464     if (st != NULL) {
9465         (void)fprintf (st, "; %s", bp->act); } }
9466 (void)fprintf (st, "\r\n");
9467 return SCPE_OK;
9468 }
9469 
9470 /* Show all breakpoints */
9471 
9472 t_stat sim_brk_showall (FILE *st, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9473 {
9474 int32 bit, mask, types;
9475 BRKTAB **bpt;
9476 
9477 if ((sw == 0) || (sw == SWMASK ('C')))
9478     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9479 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9480     if (sim_brk_types & (1 << bit))
9481         ++types;
9482 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9483     (void)fprintf (st, "Supported Breakpoint Types:"); //-V522
9484     for (bit=0; bit <= ('Z'-'A'); bit++)
9485         if (sim_brk_types & (1 << bit))
9486             (void)fprintf (st, " -%c", 'A' + bit);
9487     (void)fprintf (st, "\r\n");
9488     }
9489 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9490     mask = (sw & sim_brk_types);
9491     (void)fprintf (st, "Displaying Breakpoint Types:");
9492     for (bit=0; bit <= ('Z'-'A'); bit++)
9493         if (mask & (1 << bit))
9494             (void)fprintf (st, " -%c", 'A' + bit);
9495     (void)fprintf (st, "\r\n");
9496     }
9497 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9498     BRKTAB *prev = NULL;
9499     BRKTAB *cur = *bpt;
9500     BRKTAB *next;
9501     /* First reverse the list */
9502     while (cur) {
9503         next = cur->next;
9504         cur->next = prev;
9505         prev = cur;
9506         cur = next;
9507         }
9508     /* save reversed list in the head pointer so lookups work */
9509     *bpt = prev;
9510     /* Walk the reversed list and print it in the order it was defined in */
9511     cur = prev;
9512     while (cur) {
9513         if (cur->typ & sw)
9514             sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9515         cur = cur->next;
9516         }
9517     /* reversing the list again */
9518     cur = prev;
9519     prev = NULL;
9520     while (cur) {
9521         next = cur->next;
9522         cur->next = prev;
9523         prev = cur;
9524         cur = next;
9525         }
9526     /* restore original list */
9527     *bpt = prev;
9528     }
9529 return SCPE_OK;
9530 }
9531 
9532 /* Test for breakpoint */
9533 
9534 uint32 sim_brk_test (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9535 {
9536 BRKTAB *bp;
9537 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9538 
9539 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9540     btyp |= BRK_TYP_DYN_ALL;
9541 
9542 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {     /* in table, and type match? */
9543     double s_gtime = sim_gtime ();                      /* get time now */
9544 
9545     if (bp->time_fired[spc] == s_gtime)                 /* already taken?  */
9546         return 0;
9547     bp->time_fired[spc] = s_gtime;                      /* remember match time */
9548     if (--bp->cnt > 0)                                  /* count > 0? */
9549         return 0;
9550     bp->cnt = 0;                                        /* reset count */
9551     sim_brk_setact (bp->act);                           /* set up actions */
9552     sim_brk_match_type = btyp & bp->typ;                /* set return value */
9553     if (bp->typ & BRK_TYP_TEMP)
9554         sim_brk_clr (loc, bp->typ);                     /* delete one-shot breakpoint */
9555     sim_brk_match_addr = loc;
9556     return sim_brk_match_type;
9557     }
9558 return 0;
9559 }
9560 
9561 /* Get next pending action, if any */
9562 
9563 CONST char *sim_brk_getact (char *buf, int32 size)
     /* [previous][next][first][last][top][bottom][index][help] */
9564 {
9565 char *ep;
9566 size_t lnt;
9567 
9568 if (sim_brk_act[sim_do_depth] == NULL)                  /* any action? */
9569     return NULL;
9570 while (sim_isspace (*sim_brk_act[sim_do_depth]))        /* skip spaces */
9571     sim_brk_act[sim_do_depth]++;
9572 if (*sim_brk_act[sim_do_depth] == 0) {                  /* now empty? */
9573     return sim_brk_clract ();
9574     }
9575 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {   /* cmd delimiter? */
9576     lnt = ep - sim_brk_act[sim_do_depth];               /* cmd length */
9577     memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);   /* copy with ; */
9578     buf[lnt] = 0;                                       /* erase ; */
9579     sim_brk_act[sim_do_depth] += lnt + 1;               /* adv ptr */
9580     }
9581 else {
9582     strncpy (buf, sim_brk_act[sim_do_depth], size);     /* copy action */
9583     sim_brk_clract ();                                  /* no more */
9584     }
9585 return buf;
9586 }
9587 
9588 /* Clear pending actions */
9589 
9590 char *sim_brk_clract (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9591 {
9592 FREE (sim_brk_act_buf[sim_do_depth]);
9593 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9594 }
9595 
9596 /* Set up pending actions */
9597 
9598 void sim_brk_setact (const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
9599 {
9600 if (action) {
9601     sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9602     if (!sim_brk_act_buf[sim_do_depth])
9603       {
9604         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9605                        __func__, __FILE__, __LINE__);
9606 #if defined(USE_BACKTRACE)
9607 # if defined(SIGUSR2)
9608         (void)raise(SIGUSR2);
9609         /*NOTREACHED*/ /* unreachable */
9610 # endif /* if defined(SIGUSR2) */
9611 #endif /* if defined(USE_BACKTRACE) */
9612         abort();
9613       }
9614     strcpy (sim_brk_act_buf[sim_do_depth], action);
9615     sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9616     }
9617 else
9618     sim_brk_clract ();
9619 }
9620 
9621 /* New PC */
9622 
9623 void sim_brk_npc (uint32 cnt)
     /* [previous][next][first][last][top][bottom][index][help] */
9624 {
9625 uint32 spc;
9626 BRKTAB **bpt, *bp;
9627 
9628 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9629     cnt = SIM_BKPT_N_SPC;
9630 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9631     for (bp = *bpt; bp; bp = bp->next) {
9632         for (spc = 0; spc < cnt; spc++)
9633             bp->time_fired[spc] = -1.0;
9634         }
9635     }
9636 }
9637 
9638 /* Clear breakpoint space */
9639 
9640 void sim_brk_clrspc (uint32 spc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9641 {
9642 BRKTAB **bpt, *bp;
9643 
9644 if (spc < SIM_BKPT_N_SPC) {
9645     for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9646         for (bp = *bpt; bp; bp = bp->next) {
9647             if (bp->typ & btyp)
9648                 bp->time_fired[spc] = -1.0;
9649             }
9650         }
9651     }
9652 }
9653 
9654 const char *sim_brk_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
9655 {
9656 static char msg[256];
9657 char addr[65] = "";
9658 char buf[32];
9659 
9660 msg[0] = '\0';
9661 if (sim_dflt_dev) {
9662   if (sim_vm_sprint_addr)
9663     sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9664   else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9665 }
9666 if (sim_brk_type_desc) {
9667     BRKTYPTAB *brk = sim_brk_type_desc;
9668 
9669     while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9670         if (brk->btyp == sim_brk_match_type) {
9671             (void)sprintf (msg, "%s: %s", brk->desc, addr);
9672             break;
9673             }
9674         brk++;
9675         }
9676     }
9677 if (!msg[0])
9678     (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9679                    put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9680 
9681 return msg;
9682 }
9683 
9684 /* Expect package.  This code provides a mechanism to stop and control simulator
9685    execution based on traffic coming out of simulated ports and as well as a means
9686    to inject data into those ports.  It can conceptually viewed as a string
9687    breakpoint package.
9688 
9689    Expect rules are stored in tables associated with each port which can use this
9690    facility.  An expect rule consists of a five entry structure:
9691 
9692         match                   the expect match string
9693         size                    the number of bytes in the match string
9694         match_pattern           the expect match string in display format
9695         cnt                     number of iterations before match is declared
9696         action                  command string to be executed when match occurs
9697 
9698    All active expect rules are contained in an expect match context structure.
9699 
9700         rules                   the match rules
9701         size                    the count of match rules
9702         buf                     the buffer of output data which has been produced
9703         buf_ins                 the buffer insertion point for the next output data
9704         buf_size                the buffer size
9705 
9706    The package contains the following public routines:
9707 
9708         sim_set_expect          expect command parser and initializer
9709         sim_set_noexpect        noexpect command parser
9710         sim_exp_set             set or add an expect rule
9711         sim_exp_clr             clear or delete an expect rule
9712         sim_exp_clrall          clear all expect rules
9713         sim_exp_show            show an expect rule
9714         sim_exp_showall         show all expect rules
9715         sim_exp_check           test for rule match
9716 */
9717 
9718 /* Set expect */
9719 
9720 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9721 {
9722 char gbuf[CBUFSIZE];
9723 CONST char *tptr;
9724 CONST char *c1ptr;
9725 t_bool after_set = FALSE;
9726 uint32 after;
9727 int32 cnt = 0;
9728 t_stat r;
9729 
9730 if (exp == NULL)
9731     return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9732 after = exp->after;
9733 
9734 if ((cptr == NULL) || (*cptr == 0))
9735     return SCPE_2FARG;
9736 if (*cptr == '[') {
9737     cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9738     if ((cptr == c1ptr) || (*c1ptr != ']'))
9739         return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9740     cptr = c1ptr + 1;
9741     while (sim_isspace(*cptr))
9742         ++cptr;
9743     }
9744 tptr = get_glyph (cptr, gbuf, ',');
9745 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9746     after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9747     if (r != SCPE_OK)
9748         return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9749     after_set = TRUE;
9750     cptr = tptr;
9751     }
9752 if ((*cptr != '"') && (*cptr != '\''))
9753     return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9754 cptr = get_glyph_quoted (cptr, gbuf, 0);
9755 
9756 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9757 }
9758 
9759 /* Clear expect */
9760 
9761 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9762 {
9763 char gbuf[CBUFSIZE];
9764 
9765 if (NULL == cptr || !*cptr)
9766     return sim_exp_clrall (exp);                    /* clear all rules */
9767 if ((*cptr != '"') && (*cptr != '\''))
9768     return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9769 cptr = get_glyph_quoted (cptr, gbuf, 0);
9770 if (*cptr != '\0')
9771     return SCPE_2MARG;                              /* No more arguments */
9772 return sim_exp_clr (exp, gbuf);                     /* clear one rule */
9773 }
9774 
9775 /* Search for an expect rule in an expect context */
9776 
9777 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
     /* [previous][next][first][last][top][bottom][index][help] */
9778 {
9779 size_t i;
9780 
9781 if (NULL == exp->rules)
9782     return NULL;
9783 for (i=start_rule; i<exp->size; i++)
9784     if (!strcmp (exp->rules[i].match_pattern, match))
9785         return &exp->rules[i];
9786 return NULL;
9787 }
9788 
9789 /* Clear (delete) an expect rule */
9790 
9791 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9792 {
9793 size_t i;
9794 
9795 if (NULL == ep)                                         /* not there? ok */
9796     return SCPE_OK;
9797 FREE (ep->match);                                       /* deallocate match string */
9798 FREE (ep->match_pattern);                               /* deallocate the display format match string */
9799 FREE (ep->act);                                         /* deallocate action */
9800 exp->size -= 1;                                         /* decrement count */
9801 #if !defined(__clang_analyzer__)
9802 for (i=ep-exp->rules; i<exp->size; i++)                 /* shuffle up remaining rules */
9803     exp->rules[i] = exp->rules[i+1];
9804 if (exp->size == 0) {                                   /* No rules left? */
9805     FREE (exp->rules);
9806     exp->rules = NULL;
9807     }
9808 #endif /* if !defined(__clang_analyzer__) */
9809 return SCPE_OK;
9810 }
9811 
9812 t_stat sim_exp_clr (EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9813 {
9814 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9815 
9816 while (ep) {
9817     sim_exp_clr_tab (exp, ep);
9818     ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9819     }
9820 return SCPE_OK;
9821 }
9822 
9823 /* Clear all expect rules */
9824 
9825 t_stat sim_exp_clrall (EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
9826 {
9827 int32 i;
9828 
9829 for (i=0; i<exp->size; i++) {
9830     FREE (exp->rules[i].match);                         /* deallocate match string */
9831     FREE (exp->rules[i].match_pattern);                 /* deallocate display format match string */
9832     FREE (exp->rules[i].act);                           /* deallocate action */
9833     }
9834 FREE (exp->rules);
9835 exp->rules = NULL;
9836 exp->size = 0;
9837 FREE (exp->buf);
9838 exp->buf = NULL;
9839 exp->buf_size = 0;
9840 exp->buf_ins = 0;
9841 return SCPE_OK;
9842 }
9843 
9844 /* Set/Add an expect rule */
9845 
9846 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] */
9847 {
9848 EXPTAB *ep;
9849 uint8 *match_buf;
9850 uint32 match_size;
9851 size_t i;
9852 
9853 /* Validate the match string */
9854 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9855 if (!match_buf)
9856     return SCPE_MEM;
9857 if (switches & EXP_TYP_REGEX) {
9858     FREE (match_buf);
9859     return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9860     }
9861 else {
9862     if (switches & EXP_TYP_REGEX_I) {
9863         FREE (match_buf);
9864         return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9865         }
9866     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9867     if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9868         FREE (match_buf);
9869         return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9870         }
9871     }
9872 FREE (match_buf);
9873 for (i=0; i<exp->size; i++) {                           /* Make sure this rule won't be occluded */
9874     if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9875         (exp->rules[i].switches & EXP_TYP_PERSIST))
9876         return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9877     }
9878 if (after && exp->size)
9879     return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9880 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9881 if (!exp->rules)
9882   {
9883     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9884                    __func__, __FILE__, __LINE__);
9885 #if defined(USE_BACKTRACE)
9886 # if defined(SIGUSR2)
9887     (void)raise(SIGUSR2);
9888     /*NOTREACHED*/ /* unreachable */
9889 # endif /* if defined(SIGUSR2) */
9890 #endif /* if defined(USE_BACKTRACE) */
9891     abort();
9892   }
9893 ep = &exp->rules[exp->size];
9894 exp->size += 1;
9895 exp->after = after;                                     /* set halt after value */
9896 (void)memset (ep, 0, sizeof(*ep));
9897 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9898 if (ep->match_pattern)
9899     strcpy (ep->match_pattern, match);
9900 ep->cnt = cnt;                                          /* set proceed count */
9901 ep->switches = switches;                                /* set switches */
9902 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9903 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9904     sim_exp_clr_tab (exp, ep);                          /* clear it */
9905     FREE (match_buf);                                   /* release allocation */
9906     return SCPE_MEM;
9907     }
9908 if (switches & EXP_TYP_REGEX) {
9909     FREE (match_buf);
9910     match_buf = NULL;
9911     }
9912 else {
9913     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9914     sim_decode_quoted_string (match, match_buf, &match_size);
9915     ep->match = match_buf;
9916     ep->size = match_size;
9917     }
9918 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9919 if (!ep->match_pattern)
9920   {
9921     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9922                    __func__, __FILE__, __LINE__);
9923 #if defined(USE_BACKTRACE)
9924 # if defined(SIGUSR2)
9925     (void)raise(SIGUSR2);
9926     /*NOTREACHED*/ /* unreachable */
9927 # endif /* if defined(SIGUSR2) */
9928 #endif /* if defined(USE_BACKTRACE) */
9929     abort();
9930   }
9931 strcpy (ep->match_pattern, match);
9932 if (ep->act) {                                          /* replace old action? */
9933     FREE (ep->act);                                     /* deallocate */
9934     ep->act = NULL;                                     /* now no action */
9935     }
9936 if (act) while (sim_isspace(*act)) ++act;                   /* skip leading spaces in action string */
9937 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9938     char *newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */
9939     if (newp == NULL)                                   /* mem err? */
9940         return SCPE_MEM;
9941     strcpy (newp, act);                                 /* copy action */
9942     ep->act = newp;                                     /* set pointer */
9943     }
9944 /* Make sure that the production buffer is large enough to detect a match for all rules including a NUL termination byte */
9945 for (i=0; i<exp->size; i++) {
9946     size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9947     if (compare_size >= exp->buf_size) {
9948         exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2); /* Extra byte to null terminate regex compares */
9949         exp->buf_size = compare_size + 1;
9950         }
9951     }
9952 return SCPE_OK;
9953 }
9954 
9955 /* Show an expect rule */
9956 
9957 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9958 {
9959 if (!ep)
9960     return SCPE_OK;
9961 (void)fprintf (st, "EXPECT");
9962 if (ep->switches & EXP_TYP_PERSIST)
9963     (void)fprintf (st, " -p");
9964 if (ep->switches & EXP_TYP_CLEARALL)
9965     (void)fprintf (st, " -c");
9966 if (ep->switches & EXP_TYP_REGEX)
9967     (void)fprintf (st, " -r");
9968 if (ep->switches & EXP_TYP_REGEX_I)
9969     (void)fprintf (st, " -i");
9970 (void)fprintf (st, " %s", ep->match_pattern);
9971 if (ep->cnt > 0)
9972     (void)fprintf (st, " [%d]", ep->cnt);
9973 if (ep->act)
9974     (void)fprintf (st, " %s", ep->act);
9975 (void)fprintf (st, "\r\n");
9976 return SCPE_OK;
9977 }
9978 
9979 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9980 {
9981 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9982 
9983 if (exp->buf_size) {
9984     char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9985 
9986     (void)fprintf (st, "Match Buffer Size: %lld\r\n",
9987                    (long long)exp->buf_size);
9988     (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
9989                    (long long)exp->buf_ins);
9990     (void)fprintf (st, "Buffer Contents: %s\r\n",
9991                    bstr);
9992     FREE (bstr);
9993     }
9994 if (exp->after)
9995     (void)fprintf (st, "Halt After: %lld instructions\r\n",
9996                    (long long)exp->after);
9997 if (exp->dptr && exp->dbit)
9998     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
9999                    sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
10000                    exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
10001 (void)fprintf (st, "Match Rules:\r\n");
10002 if (!*match)
10003     return sim_exp_showall (st, exp);
10004 if (!ep) {
10005     (void)fprintf (st, "No Rules match '%s'\r\n", match);
10006     return SCPE_ARG;
10007     }
10008 do {
10009     sim_exp_show_tab (st, exp, ep);
10010     ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
10011     } while (ep);
10012 return SCPE_OK;
10013 }
10014 
10015 /* Show all expect rules */
10016 
10017 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
10018 {
10019 size_t i;
10020 
10021 for (i=0; i < exp->size; i++)
10022     sim_exp_show_tab (st, exp, &exp->rules[i]);
10023 return SCPE_OK;
10024 }
10025 
10026 /* Test for expect match */
10027 
10028 t_stat sim_exp_check (EXPECT *exp, uint8 data)
     /* [previous][next][first][last][top][bottom][index][help] */
10029 {
10030 size_t i;
10031 EXPTAB *ep = NULL;
10032 char *tstr = NULL;
10033 #if defined(TESTING)
10034 cpu_state_t * cpup = _cpup;
10035 #endif
10036 
10037 if ((!exp) || (!exp->rules))                            /* Anything to check? */
10038     return SCPE_OK;
10039 
10040 exp->buf[exp->buf_ins++] = data;                        /* Save new data */
10041 exp->buf[exp->buf_ins] = '\0';                          /* Nul terminate for RegEx match */
10042 
10043 for (i=0; i < exp->size; i++) {
10044     ep = &exp->rules[i];
10045     if (ep == NULL)
10046         break;
10047     if (ep->switches & EXP_TYP_REGEX) {
10048         }
10049     else {
10050         if (exp->buf_ins < ep->size) {                          /* Match stradle end of buffer */
10051             /*
10052              * First compare the newly deposited data at the beginning
10053              * of buffer with the end of the match string
10054              */
10055             if (exp->buf_ins > 0) {
10056                 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10057                     char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10058                     char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10059 
10060                     sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10061                                (long long)exp->buf_ins, estr);
10062                     sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10063                     FREE (estr);
10064                     FREE (mstr);
10065                     }
10066                 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10067                     continue;
10068                 }
10069             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10070                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10071                 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10072 
10073                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10074                            (long long)exp->buf_size-(ep->size-exp->buf_ins),
10075                            (long long)ep->size-exp->buf_ins, estr);
10076                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10077                 FREE (estr);
10078                 FREE (mstr);
10079                 }
10080             if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10081                 continue;
10082             break;
10083             }
10084         else {
10085             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10086                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10087                 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10088 
10089                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10090                            (long long)exp->buf_ins-ep->size,
10091                            (long long)ep->size, estr);
10092                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10093                 FREE (estr);
10094                 FREE (mstr);
10095                 }
10096             if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10097                 continue;
10098             break;
10099             }
10100         }
10101     }
10102 if (exp->buf_ins == exp->buf_size) {                    /* At end of match buffer? */
10103         exp->buf_ins = 0;                               /* wrap around to beginning */
10104         sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10105     }
10106 if ((ep != NULL) && (i != exp->size)) {                 /* Found? */
10107     sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10108     if (ep->cnt > 0) {
10109         ep->cnt -= 1;
10110         sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10111                    (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10112         }
10113     else {
10114         uint32 after   = exp->after;
10115         int32 switches = ep->switches;
10116         if (ep->act && *ep->act) {
10117             sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10118             }
10119         else {
10120             sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10121             }
10122         sim_brk_setact (ep->act);                       /* set up actions */
10123         if (ep->switches & EXP_TYP_CLEARALL)            /* Clear-all expect rule? */
10124             sim_exp_clrall (exp);                       /* delete all rules */
10125         else {
10126             if (!(ep->switches & EXP_TYP_PERSIST))      /* One shot expect rule? */
10127                 sim_exp_clr_tab (exp, ep);              /* delete it */
10128             }
10129         sim_activate (&sim_expect_unit,                 /* schedule simulation stop when indicated */
10130                       (switches & EXP_TYP_TIME) ?
10131                             (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10132                              after);
10133         }
10134     /* Matched data is no longer available for future matching */
10135     exp->buf_ins = 0;
10136     }
10137 if (tstr)  //-V547
10138   FREE (tstr);
10139 return SCPE_OK;
10140 }
10141 
10142 /* Queue input data for sending */
10143 
10144 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
     /* [previous][next][first][last][top][bottom][index][help] */
10145 {
10146 if (snd->extoff != 0) {
10147     if (snd->insoff > snd->extoff)
10148         memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10149     snd->insoff -= snd->extoff;
10150     snd->extoff  = 0;
10151     }
10152 if (snd->insoff+size > snd->bufsize) {
10153     snd->bufsize = snd->insoff+size;
10154     snd->buffer  = (uint8 *)realloc(snd->buffer, snd->bufsize);
10155     if (!snd->buffer)
10156       {
10157         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10158                        __func__, __FILE__, __LINE__);
10159 #if defined(USE_BACKTRACE)
10160 # if defined(SIGUSR2)
10161         (void)raise(SIGUSR2);
10162         /*NOTREACHED*/ /* unreachable */
10163 # endif /* if defined(SIGUSR2) */
10164 #endif /* if defined(USE_BACKTRACE) */
10165         abort();
10166       }
10167     }
10168 memcpy(snd->buffer+snd->insoff, data, size);
10169 snd->insoff += size;
10170 if (delay)
10171     snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10172 if (after)
10173     snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10174 if (snd->after == 0)
10175     snd->after = snd->delay;
10176 snd->next_time = sim_gtime() + snd->after;
10177 return SCPE_OK;
10178 }
10179 
10180 /* Cancel Queued input data */
10181 t_stat sim_send_clear (SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10182 {
10183 snd->insoff = 0;
10184 snd->extoff = 0;
10185 return SCPE_OK;
10186 }
10187 
10188 /* Display console Queued input data status */
10189 
10190 t_stat sim_show_send_input (FILE *st, const SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10191 {
10192 if (snd->extoff < snd->insoff) {
10193     (void)fprintf (st, "%lld bytes of pending input Data:\r\n    ",
10194                    (long long)snd->insoff-snd->extoff);
10195     fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10196     (void)fprintf (st, "\r\n");
10197     }
10198 else
10199     (void)fprintf (st, "No Pending Input Data\r\n");
10200 if ((snd->next_time - sim_gtime()) > 0) {
10201     if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10202         (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10203                        (int)(snd->next_time - sim_gtime()),
10204         (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10205     else
10206         (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10207                        (int)(snd->next_time - sim_gtime()));
10208     }
10209 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10210     (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10211                    (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10212 else
10213     (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10214                    (int)snd->delay);
10215 if (snd->dptr && snd->dbit)
10216     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10217                    sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10218                    snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10219 return SCPE_OK;
10220 }
10221 
10222 /* Poll for Queued input data */
10223 
10224 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10225 {
10226 #if defined(TESTING)
10227 cpu_state_t * cpup = _cpup;
10228 #endif
10229 if ((NULL != snd) && (snd->extoff < snd->insoff)) {     /* pending input characters available? */
10230     if (sim_gtime() < snd->next_time) {                 /* too soon? */
10231         *stat = SCPE_OK;
10232         sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10233         }
10234     else {
10235         char dstr[8] = "";
10236         *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;/* get one */
10237         snd->next_time = sim_gtime() + snd->delay;
10238         if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10239             (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10240         sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10241         }
10242     return TRUE;
10243     }
10244 return FALSE;
10245 }
10246 
10247 /* Message Text */
10248 
10249 const char *sim_error_text (t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10250 {
10251 static char msgbuf[64];
10252 
10253 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);        /* remove any flags */
10254 if (stat == SCPE_OK)
10255     return "No Error";
10256 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10257     return scp_errors[stat-SCPE_BASE].message;
10258 (void)sprintf(msgbuf, "Error %d", stat);
10259 return msgbuf;
10260 }
10261 
10262 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10263 {
10264 char gbuf[CBUFSIZE];
10265 size_t cond;
10266 
10267 *stat = SCPE_ARG;
10268 cptr = get_glyph (cptr, gbuf, 0);
10269 if (0 == memcmp("SCPE_", gbuf, 5))
10270     memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));  /* skip leading SCPE_ */
10271 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10272     if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10273         cond += SCPE_BASE;
10274         break;
10275         }
10276 if (0 == strcmp(gbuf, "OK"))
10277     cond = SCPE_OK;
10278 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {       /* not found? */
10279     unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10280     if (0 == numeric_cond)                    /* try explicit number */
10281         return SCPE_ARG;
10282     cond = (t_stat) numeric_cond;
10283     }
10284 if (cond > SCPE_MAX_ERR)
10285     return SCPE_ARG;
10286 *stat = cond;
10287 return SCPE_OK;
10288 }
10289 
10290 /* Debug printout routines, from Dave Hittner */
10291 
10292 const char* debug_bstates = "01_^";
10293 char debug_line_prefix[256];
10294 int32 debug_unterm  = 0;
10295 
10296 /* Finds debug phrase matching bitmask from from device DEBTAB table */
10297 
10298 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10299 {
10300 static const char *debtab_none    = "DEBTAB_ISNULL";
10301 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10302 const char *some_match = NULL;
10303 int32 offset = 0;
10304 
10305 if (dptr->debflags == 0)
10306     return debtab_none;
10307 
10308 dbits &= dptr->dctrl;                           /* Look for just the bits that matched */
10309 
10310 /* Find matching words for bitmask */
10311 
10312 while ((offset < 32) && dptr->debflags[offset].name) {
10313     if (dptr->debflags[offset].mask == dbits)   /* All Bits Match */
10314         return dptr->debflags[offset].name;
10315     if (dptr->debflags[offset].mask & dbits)
10316         some_match = dptr->debflags[offset].name;
10317     offset++;
10318     }
10319 return some_match ? some_match : debtab_nomatch;
10320 }
10321 
10322 /* Prints standard debug prefix unless previous call unterminated */
10323 
10324 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10325 {
10326 const char* debug_type = get_dbg_verb (dbits, dptr);
10327 char tim_t[32] = "";
10328 char tim_a[32] = "";
10329 char  pc_s[64] = "";
10330 struct timespec time_now;
10331 
10332 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10333     clock_gettime(CLOCK_REALTIME, &time_now);
10334     if (sim_deb_switches & SWMASK ('R'))
10335         sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10336     if (sim_deb_switches & SWMASK ('T')) {
10337         time_t tnow = (time_t)time_now.tv_sec;
10338         struct tm *now = gmtime(&tnow);
10339         (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10340                       (int)now->tm_hour,
10341                       (int)now->tm_min,
10342                       (int)now->tm_sec,
10343                       (long)(time_now.tv_nsec / 1000000));
10344         }
10345     if (sim_deb_switches & SWMASK ('A')) {
10346         (void)sprintf(tim_t, "%d.%03ld ",
10347                       (int)(time_now.tv_sec),
10348                       (long)(time_now.tv_nsec / 1000000));
10349         }
10350     }
10351 if (sim_deb_switches & SWMASK ('P')) {
10352     t_value val;
10353 
10354     if (sim_vm_pc_value)
10355         val = (*sim_vm_pc_value)();
10356     else
10357         val = get_rval (sim_PC, 0);
10358     (void)sprintf(pc_s, "-%s:", sim_PC->name);
10359     sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10360     }
10361 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10362               tim_t, tim_a, sim_gtime(), pc_s,
10363               "", dptr->name, debug_type);
10364 return debug_line_prefix;
10365 }
10366 
10367 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
     /* [previous][next][first][last][top][bottom][index][help] */
10368 {
10369 int32 i, fields, offset;
10370 uint32 value, beforevalue, mask;
10371 
10372 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10373     if (bitdefs[fields].offset == 0xffffffff)       /* fixup uninitialized offsets */
10374         bitdefs[fields].offset = offset;
10375     offset += bitdefs[fields].width;
10376     }
10377 for (i = fields-1; i >= 0; i--) {                   /* print xlation, transition */
10378     if (bitdefs[i].name[0] == '\0')
10379         continue;
10380     if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10381         int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10382         (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10383         }
10384     else {
10385         const char *delta = "";
10386         mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10387         value = (uint32)((after >> bitdefs[i].offset) & mask);
10388         beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10389         if (value < beforevalue)
10390             delta = "_";
10391         if (value > beforevalue)
10392             delta = "^";
10393         if (bitdefs[i].valuenames)
10394             (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10395         else
10396             if (bitdefs[i].format) {
10397                 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10398                 (void)Fprintf(stream, bitdefs[i].format, value);
10399                 (void)Fprintf(stream, " ");
10400                 }
10401             else
10402                 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10403         }
10404     }
10405 }
10406 
10407 /* Prints state of a register: bit translation + state (0,1,_,^)
10408    indicating the state and transition of the bit and bitfields. States:
10409    0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */
10410 
10411 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
     /* [previous][next][first][last][top][bottom][index][help] */
10412     BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10413 {
10414 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10415     if (!debug_unterm)
10416         (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));         /* print prefix if required */
10417     if (header)
10418         (void)fprintf(sim_deb, "%s: ", header);
10419     fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs); /* print xlation, transition */
10420     if (terminate)
10421         (void)fprintf(sim_deb, "\r\n");
10422     debug_unterm = terminate ? 0 : 1;                   /* set unterm for next */
10423     }
10424 }
10425 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
     /* [previous][next][first][last][top][bottom][index][help] */
10426     uint32 before, uint32 after, int terminate)
10427 {
10428 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10429 }
10430 
10431 /* Print message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10432 void sim_printf (const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10433 {
10434 char stackbuf[STACKBUFSIZE];
10435 int32 bufsize = sizeof(stackbuf);
10436 char *buf = stackbuf;
10437 int32 len;
10438 va_list arglist;
10439 
10440 while (1) {                                         /* format passed string, args */
10441     va_start (arglist, fmt);
10442     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10443     va_end (arglist);
10444 
10445 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10446 
10447     if ((len < 0) || (len >= bufsize-1)) {
10448         if (buf != stackbuf)
10449             FREE (buf);
10450         if (bufsize >= (INT_MAX / 2))
10451             return;                                 /* too big */
10452         bufsize = bufsize * 2;
10453         if (bufsize < len + 2)
10454             bufsize = len + 2;
10455         buf = (char *) malloc (bufsize);
10456         if (buf == NULL)                            /* out of memory */
10457             return;
10458         buf[bufsize-1] = '\0';
10459         continue;
10460         }
10461     break;
10462     }
10463 
10464 if (sim_is_running) {
10465     char *c, *remnant = buf;
10466     while ((c = strchr(remnant, '\n'))) { //-NLOK
10467         if ((c != buf) && (*(c - 1) != '\r')) //-NLOK
10468             (void)printf("%.*s\r\n", (int)(c-remnant), remnant); //-NLOK
10469         else
10470             (void)printf("%.*s\n", (int)(c-remnant), remnant); //-NLOK
10471         remnant = c + 1;
10472         }
10473     (void)printf("%s", remnant);
10474     }
10475 else
10476     (void)printf("%s", buf);
10477 if (sim_log && (sim_log != stdout))
10478     (void)fprintf (sim_log, "%s", buf);
10479 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10480     (void)fprintf (sim_deb, "%s", buf);
10481 
10482 if (buf != stackbuf)
10483     FREE (buf);
10484 }
10485 
10486 /* Print command result message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10487 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10488 {
10489 char stackbuf[STACKBUFSIZE];
10490 size_t bufsize = sizeof(stackbuf);
10491 char *buf = stackbuf;
10492 size_t len;
10493 va_list arglist;
10494 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10495 
10496 while (1) {                                         /* format passed string, args */
10497     va_start (arglist, fmt);
10498     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10499     va_end (arglist);
10500 
10501 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10502 
10503     if (len >= bufsize - 1) {
10504         if (buf != stackbuf)
10505             FREE (buf);
10506         bufsize = bufsize * 2;
10507         if (bufsize < len + 2)
10508             bufsize = len + 2;
10509         buf = (char *) malloc (bufsize);
10510         if (buf == NULL)                            /* out of memory */
10511             return SCPE_MEM;
10512         buf[bufsize-1] = '\0';
10513         continue;
10514         }
10515     break;
10516     }
10517 
10518 if (sim_do_ocptr[sim_do_depth]) {
10519     if (!sim_do_echo && !sim_quiet && !inhibit_message)
10520         sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10521     else {
10522         if (sim_deb)                        /* Always put context in debug output */
10523             (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10524         }
10525     }
10526 if (sim_is_running && !inhibit_message) {
10527     char *c, *remnant = buf;
10528     while ((c = strchr(remnant, '\n'))) { //-NLOK
10529         if ((c != buf) && (*(c - 1) != '\r')) //-NLOK
10530             (void)printf("%.*s\r\n", (int)(c-remnant), remnant); //-NLOK
10531         else
10532             (void)printf("%.*s\n", (int)(c-remnant), remnant); //-NLOK
10533         remnant = c + 1;
10534         }
10535     (void)printf("%s", remnant);
10536     }
10537 else {
10538     if (!inhibit_message)
10539         (void)printf("%s", buf);
10540     }
10541 if (sim_log && (sim_log != stdout) && !inhibit_message)
10542     (void)fprintf (sim_log, "%s", buf);
10543 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))/* Always display messages in debug output */
10544     (void)fprintf (sim_deb, "%s", buf);
10545 
10546 if (buf != stackbuf)
10547     FREE (buf);
10548 return stat | SCPE_NOMESSAGE;
10549 }
10550 
10551 /* Inline debugging - will print debug message if debug file is
10552    set and the bitmask matches the current device debug options.
10553    Extra returns are added for un*x systems, since the output
10554    device is set into 'raw' mode when the cpu is booted,
10555    and the extra returns don't hurt any other systems.
10556    Callers should be calling sim_debug() which is a macro
10557    defined in scp.h which evaluates the action condition before
10558    incurring call overhead. */
10559 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10560 {
10561 DEVICE *dptr = (DEVICE *)vdptr;
10562 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10563     char stackbuf[STACKBUFSIZE];
10564     int32 bufsize = sizeof(stackbuf);
10565     char *buf = stackbuf;
10566     va_list arglist;
10567     int32 i, j, len;
10568     const char* debug_prefix = sim_debug_prefix(dbits, dptr);   /* prefix to print if required */
10569 
10570     buf[bufsize-1] = '\0';
10571     while (1) {                                         /* format passed string, args */
10572         va_start (arglist, fmt);
10573         len = vsnprintf (buf, bufsize-1, fmt, arglist);
10574         va_end (arglist);
10575 
10576 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10577 
10578         if ((len < 0) || (len >= bufsize-1)) {
10579             if (buf != stackbuf)
10580                 FREE (buf);
10581             if (bufsize >= (INT_MAX / 2))
10582                 return;                                 /* too big */
10583             bufsize = bufsize * 2;
10584             if (bufsize < len + 2)
10585                 bufsize = len + 2;
10586             buf = (char *) malloc (bufsize);
10587             if (buf == NULL)                            /* out of memory */
10588                 return;
10589             buf[bufsize-1] = '\0';
10590             continue;
10591             }
10592         break;
10593         }
10594 
10595 /* Output the formatted data expanding newlines where they exist */
10596 
10597     for (i = j = 0; i < len; ++i) {
10598         if ('\n' == buf[i]) {
10599             if (i >= j) {
10600                 if ((i != j) || (i == 0)) {
10601                     if (debug_unterm)
10602                         (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10603                     else                                /* print prefix when required */
10604                         (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10605                     }
10606                 debug_unterm = 0;
10607                 }
10608             j = i + 1;
10609             }
10610         }
10611     if (i > j) {
10612         if (debug_unterm)
10613             (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10614         else                                        /* print prefix when required */
10615             (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10616         }
10617 
10618 /* Set unterminated flag for next time */
10619 
10620     debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10621     if (buf != stackbuf)
10622         FREE (buf);
10623     }
10624 return;
10625 }
10626 
10627 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] */
10628 {
10629 #if defined(TESTING)
10630 cpu_state_t * cpup = _cpup;
10631 #endif
10632 if (sim_deb && (dptr->dctrl & reason)) {
10633     sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10634     if (data && len) {
10635         size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10636         char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10637         static char hex[] = "0123456789ABCDEF";
10638         static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10639         static unsigned char ebcdic2ascii[] = {
10640             0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10641             0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10642             0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10643             0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10644             0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10645             0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10646             0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10647             0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10648             0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10649             0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10650             0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10651             0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10652             0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10653             0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10654             0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10655             0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10656             0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10657             0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10658             0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10659             0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10660             0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10661             0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10662             0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10663             0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10664             0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10665             0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10666             0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10667             0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10668             0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10669             0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10670             0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10671             0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10672             };
10673 
10674         for (i=same=0; i<len; i += 16) {
10675             if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10676                 ++same;
10677                 continue;
10678                 }
10679             if (same > 0) {
10680                 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10681                            (unsigned long int)(i - (16*same)),
10682                            (unsigned long int)(i - 1));
10683                 same = 0;
10684                 }
10685             group = (((len - i) > 16) ? 16 : (len - i));
10686             strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10687             eidx = strlen(ebcdicbuf);
10688             strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10689             ridx = strlen(rad50buf);
10690             strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10691             soff = strlen(strbuf);
10692             for (sidx=oidx=0; sidx<group; ++sidx) {
10693                 outbuf[oidx++] = ' ';
10694                 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10695                 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10696                 if (sim_isprint (data[i+sidx]))
10697                     strbuf[soff+sidx] = data[i+sidx];
10698                 else
10699                     strbuf[soff+sidx] = '.';
10700                 if (ridx && ((sidx&1) == 0)) {
10701                     uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10702 
10703                     if (word >= 64000) {
10704                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10705                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10706                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10707                         }
10708                     else {
10709                         rad50buf[ridx++] = rad50[word/1600];
10710                         rad50buf[ridx++] = rad50[(word/40)%40];
10711                         rad50buf[ridx++] = rad50[word%40];
10712                         }
10713                     }
10714                 if (eidx) {
10715                     if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10716                         ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10717                     else
10718                         ebcdicbuf[eidx++] = '.';
10719                     }
10720                 }
10721             outbuf[oidx] = '\0';
10722             strbuf[soff+sidx] = '\0';
10723             ebcdicbuf[eidx] = '\0';
10724             rad50buf[ridx] = '\0';
10725             sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10726                     (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10727             }
10728         if (same > 0) {
10729             sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10730                     (unsigned long int)(i-(16*same)),
10731                     (unsigned long int)(len-1));
10732             }
10733         }
10734     }
10735 }
10736 
10737 int Fprintf (FILE *f, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10738 {
10739 int ret = 0;
10740 va_list args;
10741 
10742 va_start (args, fmt);
10743     ret = vfprintf (f, fmt, args);
10744 va_end (args);
10745 return ret;
10746 }
10747 
10748 /* Hierarchical help presentation
10749  *
10750  * Device help can be presented hierarchically by calling
10751  *
10752  * t_stat scp_help (FILE *st, DEVICE *dptr,
10753  *                  UNIT *uptr, int flag, const char *help, char *cptr)
10754  *
10755  * or one of its three cousins from the device HELP routine.
10756  *
10757  * *help is the pointer to the structured help text to be displayed.
10758  *
10759  * The format and usage, and some helper macros can be found in scp_help.h
10760  * If you don't use the macros, it is not necessary to #include "scp_help.h".
10761  *
10762  * Actually, if you don't specify a DEVICE pointer and don't include
10763  * other device references, it can be used for non-device help.
10764  */
10765 
10766 #define blankch(x) ((x) == ' ' || (x) == '\t')
10767 
10768 typedef struct topic {
10769     size_t         level;
10770     char          *title;
10771     char          *label;
10772     struct topic  *parent;
10773     struct topic **children;
10774     uint32         kids;
10775     char          *text;
10776     size_t         len;
10777     uint32         flags;
10778     size_t         kidwid;
10779 #define HLP_MAGIC_TOPIC  1
10780     } TOPIC;
10781 
10782 static volatile struct {
10783     const char *error;
10784     const char *prox;
10785     size_t block;
10786     size_t line;
10787     } help_where = { "", NULL, 0, 0 };
10788 jmp_buf help_env;
10789 
10790 #define FAIL(why,text,here)        \
10791   {                                \
10792     help_where.error = #text;      \
10793     help_where.prox = here;        \
10794     longjmp ( help_env, (why) );   \
10795     /*LINTED E_STMT_NOT_REACHED*/  \
10796   }
10797 
10798 /*
10799  * Add to topic text.
10800  * Expands text buffer as necessary.
10801  */
10802 
10803 static void appendText (TOPIC *topic, const char *text, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
10804 {
10805 char *newt;
10806 
10807 if (!len)
10808     return;
10809 
10810 newt = (char *)realloc (topic->text, topic->len + len +1);
10811 if (!newt) {
10812 #if !defined(SUNLINT)
10813     FAIL (SCPE_MEM, No memory, NULL);
10814 #endif /* if !defined(SUNLINT) */
10815     }
10816 topic->text = newt;
10817 memcpy (newt + topic->len, text, len);
10818 topic->len +=len;
10819 newt[topic->len] = '\0';
10820 return;
10821 }
10822 
10823 /* Release memory held by a topic and its children.
10824  */
10825 static void cleanHelp (TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
10826 {
10827 TOPIC *child;
10828 size_t i;
10829 
10830 FREE (topic->title);
10831 FREE (topic->text);
10832 FREE (topic->label);
10833 for (i = 0; i < topic->kids; i++) {
10834     child = topic->children[i];
10835     cleanHelp (child);
10836     FREE (child);
10837     }
10838 FREE (topic->children);
10839 return;
10840 }
10841 
10842 /* Build a help tree from a string.
10843  * Handles substitutions, formatting.
10844  */
10845 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
10846                          UNIT *uptr, const char *htext, va_list ap)
10847 {
10848 char *end;
10849 size_t n, ilvl;
10850 #define VSMAX 100
10851 char *vstrings[VSMAX];
10852 size_t vsnum = 0;
10853 char * astrings[VSMAX+1];
10854 size_t asnum = 0;
10855 char *const *hblock;
10856 const char *ep;
10857 t_bool excluded = FALSE;
10858 
10859 /* variable arguments consumed table.
10860  * The scheme used allows arguments to be accessed in random
10861  * order, but for portability, all arguments must be char *.
10862  * If you try to violate this, there ARE machines that WILL break.
10863  */
10864 
10865 (void)memset (vstrings, 0, sizeof (vstrings));
10866 (void)memset (astrings, 0, sizeof (astrings));
10867 astrings[asnum++] = (char *) htext;
10868 
10869 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10870     help_where.block = hblock - astrings;
10871     help_where.line = 0;
10872     while (*htext) {
10873         const char *start;
10874 
10875         help_where.line++;
10876         if (sim_isspace (*htext) || *htext == '+') {/* Topic text, indented topic text */
10877             if (excluded) {                     /* Excluded topic text */
10878                 while (*htext && *htext != '\n')
10879                     htext++;
10880                 if (*htext)
10881                     ++htext;
10882                 continue;
10883                 }
10884             ilvl = 1;
10885             appendText (topic, "    ", 4);      /* Basic indentation */
10886             if (*htext == '+') {                /* More for each + */
10887                 while (*htext == '+') {
10888                     ilvl++;
10889                     appendText (topic, "    ", 4);
10890                     htext++;
10891                     }
10892                 }
10893             while (*htext && *htext != '\n' && sim_isspace (*htext))
10894                 htext++;
10895             if (!*htext)                        /* Empty after removing leading spaces */
10896                 break;
10897             start = htext;
10898             while (*htext) {                    /* Process line for substitutions */
10899                 if (*htext == '%') {
10900                     appendText (topic, start, htext - start); /* Flush up to escape */
10901                     switch (*++htext) {         /* Evaluate escape */
10902                         case 'U':
10903                             if (dptr) {
10904                                 char buf[129];
10905                                 n = uptr? uptr - dptr->units: 0;
10906                                 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10907                                 appendText (topic, buf, strlen (buf));
10908                                 }
10909                             break;
10910                         case 'D':
10911                             if (dptr != NULL)
10912                                 appendText (topic, dptr->name, strlen (dptr->name));
10913                             break;
10914                         case 'S':
10915                             appendText (topic, sim_name, strlen (sim_name));
10916                             break;
10917                         case '%':
10918                             appendText (topic, "%", 1);
10919                             break;
10920                         case '+':
10921                             appendText (topic, "+", 1);
10922                             break;
10923                         default:                    /* Check for vararg # */
10924                             if (sim_isdigit (*htext)) {
10925                                 n = 0;
10926                                 while (sim_isdigit (*htext))
10927                                     n += (n * 10) + (*htext++ - '0');
10928                                 if (( *htext != 'H' && *htext != 's') ||
10929                                     n == 0 || n >= VSMAX) {
10930 #if !defined(SUNLINT)
10931                                     FAIL (SCPE_ARG, Invalid escape, htext);
10932 #endif /* if !defined(SUNLINT) */
10933                                     }
10934                                 while (n > vsnum)   /* Get arg pointer if not cached */
10935                                     vstrings[vsnum++] = va_arg (ap, char *);
10936                                 start = vstrings[n-1]; /* Insert selected string */
10937                                 if (*htext == 'H') {   /* Append as more input */
10938                                     if (asnum >= VSMAX) {
10939 #if !defined(SUNLINT)
10940                                         FAIL (SCPE_ARG, Too many blocks, htext);
10941 #endif /* if !defined(SUNLINT) */
10942                                         }
10943                                     astrings[asnum++] = (char *)start;
10944                                     break;
10945                                     }
10946                                 ep = start;
10947                                 while (*ep) {
10948                                     if (*ep == '\n') {
10949                                         ep++;       /* Segment to \n */
10950                                         appendText (topic, start, ep - start);
10951                                         if (*ep) {  /* More past \n, indent */
10952                                             size_t i;
10953                                             for (i = 0; i < ilvl; i++)
10954                                                 appendText (topic, "    ", 4);
10955                                             }
10956                                         start = ep;
10957                                         }
10958                                     else
10959                                         ep++;
10960                                     }
10961                                 appendText (topic, start, ep-start);
10962                                 break;
10963                                 }
10964 #if !defined(SUNLINT)
10965                             FAIL (SCPE_ARG, Invalid escape, htext);
10966 #endif /* if !defined(SUNLINT) */
10967                         } /* switch (escape) */
10968                     start = ++htext;
10969                     continue;                   /* Current line */
10970                     } /* if (escape) */
10971                 if (*htext == '\n') {           /* End of line, append last segment */
10972                     htext++;
10973                     appendText (topic, start, htext - start);
10974                     break;                      /* To next line */
10975                     }
10976                 htext++;                        /* Regular character */
10977                 }
10978             continue;
10979             } /* topic text line */
10980         if (sim_isdigit (*htext)) {             /* Topic heading */
10981             TOPIC **children;
10982             TOPIC *newt;
10983             char nbuf[100];
10984 
10985             n = 0;
10986             start = htext;
10987             while (sim_isdigit (*htext))
10988                 n += (n * 10) + (*htext++ - '0');
10989             if ((htext == start) || !n) {
10990 #if !defined(SUNLINT)
10991                 FAIL (SCPE_ARG, Invalid topic heading, htext);
10992 #endif /* if !defined(SUNLINT) */
10993                 }
10994             if (n <= topic->level) {            /* Find level for new topic */
10995                 while (n <= topic->level)
10996                     topic = topic->parent;
10997                 }
10998             else {
10999                 if (n > topic->level + 1) {     /* Skipping down more than 1 */
11000 #if !defined(SUNLINT)
11001                     FAIL (SCPE_ARG, Level not contiguous, htext); /* E.g. 1 3, not reasonable */
11002 #endif /* if !defined(SUNLINT) */
11003                     }
11004                 }
11005             while (*htext && (*htext != '\n') && sim_isspace (*htext))
11006                 htext++;
11007             if (!*htext || (*htext == '\n')) {  /* Name missing */
11008 #if !defined(SUNLINT)
11009                 FAIL (SCPE_ARG, Missing topic name, htext);
11010 #endif /* if !defined(SUNLINT) */
11011                 }
11012             start = htext;
11013             while (*htext && (*htext != '\n'))
11014                 htext++;
11015             if (start == htext) {               /* Name NULL */
11016 #if !defined(SUNLINT)
11017                 FAIL (SCPE_ARG, Null topic name, htext);
11018 #endif /* if !defined(SUNLINT) */
11019                 }
11020             excluded = FALSE;
11021             if (*start == '?') {                /* Conditional topic? */
11022                 size_t n = 0;
11023                 start++;
11024                 while (sim_isdigit (*start))    /* Get param # */
11025                     n += (n * 10) + (*start++ - '0');
11026                 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11027 #if !defined(SUNLINT)
11028                     FAIL (SCPE_ARG, Invalid parameter number, start);
11029 #endif /* if !defined(SUNLINT) */
11030                     }
11031                 while (n > vsnum)               /* Get arg pointer if not cached */
11032                     vstrings[vsnum++] = va_arg (ap, char *);
11033                 end = vstrings[n-1];            /* Check for True */
11034                 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11035                     excluded = TRUE;            /* False, skip topic this time */
11036                     if (*htext)
11037                         htext++;
11038                     continue;
11039                     }
11040                 }
11041             newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11042             if (!newt) {
11043 #if !defined(SUNLINT)
11044                 FAIL (SCPE_MEM, No memory, NULL);
11045 #endif /* if !defined(SUNLINT) */
11046                 }
11047             size_t len = (htext > start) ? (htext - start) : 0;
11048             newt->title = (char *) malloc(len + 1);
11049             if (!newt->title) {
11050                 FREE (newt);
11051 #if !defined(SUNLINT)
11052                 FAIL (SCPE_MEM, No memory, NULL);
11053 #endif /* if !defined(SUNLINT) */
11054                 }
11055             memcpy (newt->title, start, htext - start);
11056             newt->title[htext - start] = '\0';
11057             if (*htext)
11058                 htext++;
11059 
11060             if (newt->title[0] == '$')
11061                 newt->flags |= HLP_MAGIC_TOPIC;
11062 
11063             children = (TOPIC **) realloc (topic->children,
11064                                            (topic->kids +1) * sizeof (TOPIC *));
11065             if (NULL == children) {
11066                 FREE (newt->title);
11067                 FREE (newt);
11068 #if !defined(SUNLINT)
11069                 FAIL (SCPE_MEM, No memory, NULL);
11070 #endif /* if !defined(SUNLINT) */
11071                 }
11072             topic->children = children;
11073             topic->children[topic->kids++] = newt;
11074             newt->level = n;
11075             newt->parent = topic;
11076             n = strlen (newt->title);
11077             if (n > topic->kidwid)
11078                 topic->kidwid = n;
11079             (void)sprintf (nbuf, ".%u", topic->kids);
11080             n = strlen (topic->label) + strlen (nbuf) + 1;
11081             newt->label = (char *) malloc (n);
11082             if (NULL == newt->label) {
11083                 FREE (newt->title);
11084                 topic->children[topic->kids -1] = NULL;
11085                 FREE (newt);
11086 #if !defined(SUNLINT)
11087                 FAIL (SCPE_MEM, No memory, NULL);
11088 #endif /* if !defined(SUNLINT) */
11089                 }
11090             (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11091             topic = newt;
11092             continue;
11093             } /* digits introducing a topic */
11094         if (*htext == ';') {                    /* Comment */
11095             while (*htext && *htext != '\n')
11096                 htext++;
11097             continue;
11098             }
11099 #if !defined(SUNLINT)
11100         FAIL (SCPE_ARG, Unknown line type, htext);     /* Unknown line */
11101 #endif /* if !defined(SUNLINT) */
11102         } /* htext not at end */
11103     (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11104     vsnum = 0;
11105     } /* all strings */
11106 
11107 return topic;
11108 }
11109 
11110 /*
11111  * Create prompt string - top thru current topic
11112  * Add prompt at end.
11113  */
11114 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
     /* [previous][next][first][last][top][bottom][index][help] */
11115 {
11116 char *prefix;
11117 char *newp, *newt;
11118 
11119 if (topic->level == 0) {
11120     prefix = (char *) calloc (2,1);
11121     if (!prefix) {
11122 #if !defined(SUNLINT)
11123         FAIL (SCPE_MEM, No memory, NULL);
11124 #endif /* if !defined(SUNLINT) */
11125         }
11126     prefix[0] = '\n';
11127     }
11128 else
11129     prefix = helpPrompt (topic->parent, "", oneword);
11130 
11131 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11132                         strlen (pstring) +1);
11133 if (!newp) {
11134     FREE (prefix);
11135 #if !defined(SUNLINT)
11136     FAIL (SCPE_MEM, No memory, NULL);
11137 #endif /* if !defined(SUNLINT) */
11138     }
11139 strcpy (newp, prefix);
11140 if (topic->children) {
11141     if (topic->level != 0)
11142         strcat (newp, " ");
11143     newt = (topic->flags & HLP_MAGIC_TOPIC)?
11144             topic->title+1: topic->title;
11145     if (oneword) {
11146         char *np = newp + strlen (newp);
11147         while (*newt) {
11148             *np++ = blankch (*newt)? '_' : *newt;
11149             newt++;
11150             }
11151         *np = '\0';
11152         }
11153     else
11154         strcat (newp, newt);
11155     if (*pstring && *pstring != '?')
11156         strcat (newp, " ");
11157     }
11158 strcat (newp, pstring);
11159 FREE (prefix);
11160 return newp;
11161 }
11162 
11163 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
11164 {
11165 char tbuf[CBUFSIZE];
11166 size_t i, skiplines;
11167 #if defined(_WIN32)
11168 FILE *tmp;
11169 char *tmpnam;
11170 
11171 do {
11172     int fd;
11173     tmpnam = _tempnam (NULL, "simh");
11174     fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11175     if (fd != -1) {
11176         tmp = _fdopen (fd, "w+");
11177         break;
11178         }
11179     } while (1);
11180 #else
11181 FILE *tmp = tmpfile();
11182 #endif /* if defined(_WIN32) */
11183 
11184 if (!tmp) {
11185     (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11186                    xstrerror_l(errno), errno);
11187     return;
11188     }
11189 
11190 if (topic->title)
11191     (void)fprintf (st, "%s\r\n", topic->title+1);
11192 
11193 skiplines = 0;
11194 if (topic->title) {
11195   if (!strcmp (topic->title+1, "Registers")) {
11196       fprint_reg_help (tmp, dptr) ;
11197       skiplines = 1;
11198       }
11199   else
11200       if (!strcmp (topic->title+1, "Set commands")) {
11201           fprint_set_help (tmp, dptr);
11202           skiplines = 3;
11203           }
11204       else
11205           if (!strcmp (topic->title+1, "Show commands")) {
11206               fprint_show_help (tmp, dptr);
11207               skiplines = 3;
11208               }
11209   }
11210 rewind (tmp);
11211 if (errno) {
11212     (void)fprintf (st, "rewind: error %d\r\n", errno);
11213 }
11214 
11215 /* Discard leading blank lines/redundant titles */
11216 
11217 for (i =0; i < skiplines; i++)
11218     if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11219 
11220 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11221     if (tbuf[0] != '\n')
11222         fputs ("    ", st);
11223     fputs (tbuf, st);
11224     }
11225 fclose (tmp);
11226 #if defined(_WIN32)
11227 remove (tmpnam);
11228 FREE (tmpnam);
11229 #endif /* if defined(_WIN32) */
11230 return;
11231 }
11232 /* Flatten and display help for those who say they prefer it. */
11233 
11234 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11235                                UNIT *uptr, int32 flag,
11236                                TOPIC *topic, va_list ap )
11237 {
11238 size_t i;
11239 
11240 if (topic->flags & HLP_MAGIC_TOPIC) {
11241     (void)fprintf (st, "\r\n%s ", topic->label);
11242     displayMagicTopic (st, dptr, topic);
11243     }
11244 else
11245     (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11246 
11247 /*
11248  * Topic text (for magic topics, follows for explanations)
11249  * It's possible/reasonable for a magic topic to have no text.
11250  */
11251 
11252 if (topic->text)
11253     fputs (topic->text, st);
11254 
11255 for (i = 0; i < topic->kids; i++)
11256     displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11257 
11258 return SCPE_OK;
11259 }
11260 
11261 #define HLP_MATCH_AMBIGUOUS (~0u)
11262 #define HLP_MATCH_WILDCARD  (~1U)
11263 #define HLP_MATCH_NONE      0
11264 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
     /* [previous][next][first][last][top][bottom][index][help] */
11265 {
11266 size_t i, match;
11267 char cbuf[CBUFSIZE], *cptr;
11268 
11269 if (!strcmp (token, "*"))
11270     return HLP_MATCH_WILDCARD;
11271 
11272 match = 0;
11273 for (i = 0; i < topic->kids; i++) {
11274     strcpy (cbuf,topic->children[i]->title +
11275             ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11276     cptr = cbuf;
11277     while (*cptr) {
11278         if (blankch (*cptr)) {
11279             *cptr++ = '_';
11280             }
11281         else {
11282             *cptr = (char)toupper (*cptr);
11283             cptr++;
11284             }
11285         }
11286     if (!strcmp (cbuf, token))      /* Exact Match */
11287         return i+1;
11288     if (!strncmp (cbuf, token, strlen (token))) {
11289         if (match)
11290             return HLP_MATCH_AMBIGUOUS;
11291         match = i+1;
11292         }
11293     }
11294 return match;
11295 }
11296 
11297 /* Main help routine */
11298 
11299 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11300                   UNIT *uptr, int32 flag,
11301                   const char *help, const char *cptr, va_list ap)
11302 {
11303 TOPIC top;
11304 TOPIC *topic = &top;
11305 int failed;
11306 size_t match;
11307 size_t i;
11308 const char *p;
11309 t_bool flat_help = FALSE;
11310 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11311 
11312 static const char attach_help[] = { " ATTACH" };
11313 static const char  brief_help[] = { "%s help.  Type <CR> to exit, HELP for navigation help.\r\n" };
11314 static const char onecmd_help[] = { "%s help.\r\n" };
11315 static const char   help_help[] = {
11316     /****|***********************80 column width guide********************************/
11317     "    To see more HELP information, type the listed subtopic name.  To move\r\n"
11318     "    up a level, just type <CR>.  To review the current subtopic, type \"?\".\r\n"
11319     "    To view all subtopics, type \"*\".  To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11320     };
11321 
11322 (void)memset (&top, 0, sizeof(top));
11323 top.parent = &top;
11324 if ((failed = setjmp (help_env)) != 0) {
11325     (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11326                            "Error in block %u line %u: %s\r\n"
11327                            "%s%*.*s%s\r\n",
11328                    (int)help_where.block, (int)help_where.line, help_where.error,
11329                    help_where.prox ? "Near '" : "",
11330                    help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11331                    help_where.prox ? help_where.prox : "",
11332                    help_where.prox ? "'" : "");
11333     cleanHelp (&top);
11334     return failed;
11335     }
11336 
11337 /* Compile string into navigation tree */
11338 
11339 /* Root */
11340 
11341 if (dptr) {
11342     p = dptr->name;
11343     flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11344     }
11345 else
11346     p = sim_name;
11347 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11348 if (!top.title)
11349   {
11350     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11351                    __func__, __FILE__, __LINE__);
11352 #if defined(USE_BACKTRACE)
11353 # if defined(SIGUSR2)
11354     (void)raise(SIGUSR2);
11355     /*NOTREACHED*/ /* unreachable */
11356 # endif /* if defined(SIGUSR2) */
11357 #endif /* if defined(USE_BACKTRACE) */
11358     abort();
11359   }
11360 for (i = 0; p[i]; i++ )
11361     top.title[i] = (char)toupper (p[i]);
11362 top.title[i] = '\0';
11363 if (flag & SCP_HELP_ATTACH)
11364     strcpy (top.title+i, attach_help);
11365 
11366 top.label = (char *) malloc (sizeof ("1"));
11367 if (!top.label)
11368   {
11369     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11370                    __func__, __FILE__, __LINE__);
11371 #if defined(USE_BACKTRACE)
11372 # if defined(SIGUSR2)
11373     (void)raise(SIGUSR2);
11374     /*NOTREACHED*/ /* unreachable */
11375 # endif /* if defined(SIGUSR2) */
11376 #endif /* if defined(USE_BACKTRACE) */
11377     abort();
11378   }
11379 strcpy (top.label, "1");
11380 
11381 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11382 
11383 if (flat_help) {
11384     flag |= SCP_HELP_FLAT;
11385     if (sim_ttisatty())
11386         (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11387     else
11388         (void)fprintf (st, "%s help.\r\n", top.title);
11389     }
11390 else
11391     (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11392 
11393 /* Add text and subtopics */
11394 
11395 (void) buildHelp (&top, dptr, uptr, help, ap);
11396 
11397 /* Go to initial topic if provided */
11398 
11399 while (cptr && *cptr) {
11400     cptr = get_glyph (cptr, gbuf, 0);
11401     if (!gbuf[0])
11402         break;
11403     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11404         (void)fprintf (st, "\r\n");
11405         fputs (help_help, st);
11406         break;
11407         }
11408     match =  matchHelpTopicName (topic, gbuf);
11409     if (match == HLP_MATCH_WILDCARD) {
11410         if (dptr)
11411             displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11412         cleanHelp (&top);
11413         return SCPE_OK;
11414         }
11415     if (match == HLP_MATCH_AMBIGUOUS) {
11416         (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11417         break;
11418         }
11419     if (match == HLP_MATCH_NONE) {
11420         (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11421         break;
11422         }
11423     topic = topic->children[match-1];
11424     }
11425 cptr = NULL;
11426 
11427 if (flat_help) {
11428     displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11429     cleanHelp (&top);
11430     return SCPE_OK;
11431     }
11432 
11433 /* Interactive loop displaying help */
11434 
11435 while (TRUE) {
11436     char *pstring;
11437     const char *prompt[2] = {"? ", "Subtopic? "};
11438 
11439     /* Some magic topic names for help from data structures */
11440 
11441     if (topic->flags & HLP_MAGIC_TOPIC) {
11442         fputc ('\n', st);
11443         displayMagicTopic (st, dptr, topic);
11444         }
11445     else
11446         (void)fprintf (st, "\r\n%s\r\n", topic->title);
11447 
11448     /* Topic text (for magic topics, follows for explanations)
11449      * It's possible/reasonable for a magic topic to have no text.
11450      */
11451 
11452     if (topic->text)
11453         fputs (topic->text, st);
11454 
11455     if (topic->kids) {
11456         size_t w = 0;
11457         char *p;
11458         char tbuf[CBUFSIZE];
11459 
11460         (void)fprintf (st, "\r\n    Additional information available:\r\n\r\n");
11461         for (i = 0; i < topic->kids; i++) {
11462             strcpy (tbuf, topic->children[i]->title +
11463                     ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11464             for (p = tbuf; *p; p++) {
11465                 if (blankch (*p))
11466                     *p = '_';
11467                 }
11468             w += 4 + topic->kidwid;
11469             if (w > 80) {
11470                 w = 4 + topic->kidwid;
11471                 fputc ('\r', st);
11472                 fputc ('\n', st);
11473                 }
11474             (void)fprintf (st, "    %-*s", (int32_t)topic->kidwid, tbuf);
11475             }
11476         (void)fprintf (st, "\r\n\r\n");
11477         if (flag & SCP_HELP_ONECMD) {
11478             pstring = helpPrompt (topic, "", TRUE);
11479             (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11480             FREE (pstring);
11481             break;
11482             }
11483         }
11484 
11485     if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11486         break;
11487 
11488   reprompt:
11489     if (NULL == cptr || !*cptr) {
11490         if (topic->kids == 0)
11491             topic = topic->parent;
11492         pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11493 
11494         cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11495         FREE (pstring);
11496         if ((cptr != NULL) &&                   /* Got something? */
11497             ((0 == strcmp (cptr, "\x04")) ||    /* was it a bare ^D? */
11498              (0 == strcmp (cptr, "\x1A"))))     /* was it a bare ^Z? */
11499             cptr = NULL;                        /* These are EOF synonyms */
11500         }
11501 
11502     if (NULL == cptr)                           /* EOF, exit help */
11503         break;
11504 
11505     cptr = get_glyph (cptr, gbuf, 0);
11506     if (!strcmp (gbuf, "*")) {              /* Wildcard */
11507         displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11508         gbuf[0] = '\0';                     /* Displayed all subtopics, go up */
11509         }
11510     if (!gbuf[0]) {                         /* Blank, up a level */
11511         if (topic->level == 0)
11512             break;
11513         topic = topic->parent;
11514         continue;
11515         }
11516     if (!strcmp (gbuf, "?"))                /* ?, repaint current topic */
11517         continue;
11518     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11519         fputs (help_help, st);
11520         goto reprompt;
11521         }
11522     if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))   /* EXIT (help) */
11523         break;
11524 
11525     /* String - look for that topic */
11526 
11527     if (!topic->kids) {
11528         (void)fprintf (st, "No additional help at this level.\r\n");
11529         cptr = NULL;
11530         goto reprompt;
11531         }
11532     match = matchHelpTopicName (topic, gbuf);
11533     if (match == HLP_MATCH_AMBIGUOUS) {
11534         (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11535         cptr = NULL;
11536         goto reprompt;
11537         }
11538 
11539     if (match == HLP_MATCH_NONE) {
11540         (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11541         cptr = NULL;
11542         goto reprompt;
11543         }
11544     /* Found, display subtopic */
11545 
11546     topic = topic->children[match-1];
11547     }
11548 
11549 /* Free structures and return */
11550 
11551 cleanHelp (&top);
11552 
11553 return SCPE_OK;
11554 }
11555 
11556 /* variable argument list shell - most commonly used */
11557 
11558 t_stat scp_help (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11559                  UNIT *uptr, int32 flag,
11560                  const char *help, const char *cptr, ...)
11561 {
11562 t_stat r;
11563 va_list ap;
11564 
11565 va_start (ap, cptr);
11566 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11567 va_end (ap);
11568 
11569 return r;
11570 }
11571 
11572 #if defined(_MSC_VER)
11573 # pragma warning(pop)
11574 #endif

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