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 /* NO_LOCKLESS */
5154 #if !defined(LOCKLESS)
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, "NO_LOCKLESS");
5164 #endif /* if !defined(LOCKLESS) */
5165 
5166 /* PANEL68 */
5167 #if defined(PANEL68)
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, "PANEL68");
5177 #endif /* if defined(PANEL68) */
5178 
5179 /* ABSI */  /* XXX: Change to NO_ABSI once code is non-experimental */
5180 #if defined(WITH_ABSI_DEV)
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, "ABSI");
5190 #endif /* if defined(WITH_ABSI_DEV) */
5191 
5192 /* SOCKET */  /* XXX: Change to NO_SOCKET once code is non-experimental */
5193 #if defined(WITH_SOCKET_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, "SOCKET");
5203 #endif /* if defined(WITH_SOCKET_DEV) */
5204 
5205 /* CHAOSNET */  /* XXX: Change to NO_CHAOSNET once code is non-experimental */
5206 #if defined(WITH_MGP_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, "CHAOSNET");
5216 # if USE_SOCKET_DEV_APPROACH
5217     (void)fprintf (st, "-S");
5218 # endif /* if USE_SOCKET_DEV_APPROACH */
5219 #endif /* if defined(WITH_MGP_DEV) */
5220 
5221 /* DUMA */
5222 #if defined(USE_DUMA)
5223 # if defined(HAVE_DPSOPT)
5224     (void)fprintf (st, ", ");
5225 # else
5226     (void)fprintf (st, "\r\n   Options: ");
5227 # endif
5228 # if !defined(HAVE_DPSOPT)
5229 #  define HAVE_DPSOPT 1
5230 # endif
5231     (void)fprintf (st, "DUMA");
5232 #endif /* if defined(USE_DUMA) */
5233 
5234 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5235 # if defined(NO_SUPPORT_VERSION)
5236     (void)fprintf (st, "\r\n  Modified: %s", VER_H_GIT_DATE);
5237 # else
5238     (void)fprintf (st, "\r\n  Released: %s", VER_H_GIT_DATE);
5239 # endif
5240 #endif
5241 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5242     (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5243 #endif
5244 #if defined(VER_CURRENT_TIME)
5245     (void)fprintf (st, "\r\n  Compiled: %s", VER_CURRENT_TIME);
5246 #endif
5247     if (dirty) //-V547
5248       {
5249         (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5250       }
5251     (void)fprintf (st, "\r\n\r\n Build Information:");
5252 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5253     char build_os_version_raw[255];
5254     char build_os_arch_raw[255];
5255     (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5256     (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5257     char *build_os_version = strdup(build_os_version_raw);
5258     if (!build_os_version)
5259       {
5260         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5261                        __func__, __FILE__, __LINE__);
5262 # if defined(USE_BACKTRACE)
5263 #  if defined(SIGUSR2)
5264         (void)raise(SIGUSR2);
5265         /*NOTREACHED*/ /* unreachable */
5266 #  endif /* if defined(SIGUSR2) */
5267 # endif /* if defined(USE_BACKTRACE) */
5268         abort();
5269       }
5270     char *build_os_arch = strdup(build_os_arch_raw);
5271     if (!build_os_arch)
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     unsigned char SPROM[1024];
5284     setupPROM (0, SPROM);
5285     (void)fprintf (st, "\r\n    Target: ");
5286     printpq (SPROM, st, 190, 20);
5287     if (SPROM[170] != 20)
5288       {
5289         if (SPROM[170] != 255)
5290           {
5291             (void)fprintf (st, " on ");
5292             printpq (SPROM, st, 170, 20);
5293           }
5294       }
5295     strtrimspace(build_os_version, build_os_version_raw);
5296     strtrimspace(build_os_arch, build_os_arch_raw);
5297     (void)fprintf (st, "\r\n  Build OS: %s %s", build_os_version, build_os_arch);
5298     FREE(build_os_version);
5299     FREE(build_os_arch);
5300 #endif
5301 #if defined(__VERSION__)
5302     char gnumver[2];
5303     char postver[1024];
5304     (void)sprintf(gnumver, "%.1s", __VERSION__);
5305     (void)sprintf(postver, "%.1023s", __VERSION__);
5306     strremove(postver, "(TM)");
5307     strremove(postver, "(R)");
5308     strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5309     strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5310     strremove(postver, " gcc 4.9 mode");
5311     strremove(postver, "4.2.1 Compatible ");
5312     strremove(postver, "git@github.com:llvm/llvm-project.git ");
5313     strremove(postver, "https://github.com/llvm/llvm-project.git ");
5314     strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5315     strremove(postver, "https://github.com/yrnkrn/zapcc ");
5316     strremove(postver, "(experimental) ");
5317     strremove(postver, ".module+el8.7.0+20823+214a699d");
5318     strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5319     strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5320     strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5321     strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5322     strremove(postver, "llvmorg-16.0.6-0-");
5323     strremove(postver, " Clang 15.0.0 (build 760095e)");
5324     strremove(postver, " Clang 15.0.0 (build 6af5742)");
5325     strremove(postver, " Clang 15.0.0 (build ca7115e)");
5326     strremove(postver, " Clang 15.0.0 (build 232543c)");
5327     strremove(postver, " Clang 17.0.6 (build 19a779f)");
5328     strremove(postver, "CLANG: ");
5329 #endif
5330 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5331 # if !defined(__clang_version__)
5332     if (isdigit((unsigned char)gnumver[0])) {
5333         (void)fprintf (st, "\r\n  Compiler: GCC %s", postver);
5334     } else {
5335         (void)fprintf (st, "\r\n  Compiler: %s", postver);
5336     }
5337 # endif
5338 # if defined(__clang_analyzer__ )
5339     (void)fprintf (st, "\r\n  Compiler: Clang C/C++ Static Analyzer");
5340 # elif defined(__clang_version__) && defined(__VERSION__)
5341     char clangllvmver[1024];
5342     (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5343     strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5344     strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5345     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5346     strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5347     strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5348     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5349     strremove(clangllvmver, " ( )");
5350     strremove(clangllvmver, " ()");
5351     if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5352         (void)fprintf (st, "\r\n  Compiler: Clang %s", clangllvmver);
5353     } else {
5354         (void)fprintf (st, "\r\n  Compiler: %s", postver);
5355     }
5356 # elif defined(__clang_version__)
5357     (void)fprintf (st, "\r\n  Compiler: %s", postver);
5358 # endif
5359 #elif defined(__PGI) && !defined(__NVCOMPILER)
5360     (void)fprintf (st, "\r\n  Compiler: Portland Group, Inc. (PGI) C Compiler ");
5361 # if defined(__PGIC__)
5362     (void)fprintf (st, "%d", __PGIC__);
5363 #  if defined(__PGIC_MINOR__)
5364     (void)fprintf (st, ".%d", __PGIC_MINOR__);
5365 #   if defined(__PGIC_PATCHLEVEL__)
5366     (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5367 #   endif
5368 #  endif
5369 # endif
5370 #elif defined(__NVCOMPILER)
5371     (void)fprintf (st, "\r\n  Compiler: NVIDIA HPC SDK C Compiler ");
5372 # if defined(__NVCOMPILER_MAJOR__)
5373     (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5374 #  if defined(__NVCOMPILER_MINOR__)
5375     (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5376 #   if defined(__NVCOMPILER_PATCHLEVEL__)
5377     (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5378 #   endif
5379 #  endif
5380 # endif
5381 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5382     (void)fprintf (st, "\r\n  Compiler: Microsoft C %d.%02d.%05d.%02d",
5383                    _MSC_FULL_VER/10000000,
5384                    (_MSC_FULL_VER/100000)%100,
5385                    _MSC_FULL_VER%100000,
5386                    _MSC_BUILD);
5387 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5388 # if defined(_AIX) && defined(__PASE__)
5389     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5390 # endif
5391 # if defined(_AIX) && !defined(__PASE__)
5392     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5393 # endif
5394 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5395     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5396 # endif
5397 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5398 #  if defined(__PPC__) && defined(__APPLE__)
5399     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5400 #  else
5401     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++ V%s", __xlc__);
5402 #  endif
5403 # endif
5404 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5405 # define VER_ENC(maj, min, rev) \
5406   (((maj) * 1000000) + ((min) * 1000) + (rev))
5407 # define VER_DEC_MAJ(ver) \
5408   ((ver) / 1000000)
5409 # define VER_DEC_MIN(ver) \
5410   (((ver) % 1000000) / 1000)
5411 # define VER_DEC_REV(ver) \
5412   ((ver) % 1000)
5413 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5414 #  define COMP_VER VER_ENC(                                        \
5415    (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5416    (((__SUNPRO_C >>  8) & 0xf) * 10) + ((__SUNPRO_C >>  4) & 0xf), \
5417      (__SUNPRO_C & 0xf) * 10)
5418 # elif defined(__SUNPRO_C)
5419 #  define COMP_VER VER_ENC(    \
5420      (__SUNPRO_C >>  8) & 0xf, \
5421      (__SUNPRO_C >>  4) & 0xf, \
5422      (__SUNPRO_C) & 0xf)
5423 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5424 #  define COMP_VER VER_ENC(                                          \
5425    (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5426    (((__SUNPRO_CC >>  8) & 0xf) * 10) + ((__SUNPRO_CC >>  4) & 0xf), \
5427      (__SUNPRO_CC & 0xf) * 10)
5428 # elif defined(__SUNPRO_CC)
5429 #  define COMP_VER VER_ENC(     \
5430      (__SUNPRO_CC >>  8) & 0xf, \
5431      (__SUNPRO_CC >>  4) & 0xf, \
5432      (__SUNPRO_CC) & 0xf)
5433 # endif
5434 # if !defined(COMP_VER)
5435 #  define COMP_VER 0
5436 # endif
5437     (void)fprintf (st, "\r\n  Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5438                    VER_DEC_MAJ(COMP_VER),
5439                    VER_DEC_MIN(COMP_VER),
5440                    VER_DEC_REV(COMP_VER));
5441 #elif defined(__DMC__)
5442     (void)fprintf (st, "\r\n  Compiler: Digital Mars C/C++");
5443 #elif defined(__PCC__)
5444     (void)fprintf (st, "\r\n  Compiler: Portable C Compiler");
5445 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5446     (void)fprintf (st, "\r\n  Compiler: Plan 9 Compiler Suite");
5447 #elif defined(__ACK__)
5448     (void)fprintf (st, "\r\n  Compiler: Amsterdam Compiler Kit");
5449 #elif defined(__COMO__)
5450     (void)fprintf (st, "\r\n  Compiler: Comeau C++");
5451 #elif defined(__COMPCERT__)
5452     (void)fprintf (st, "\r\n  Compiler: CompCert C");
5453 #elif defined(__COVERITY__)
5454     (void)fprintf (st, "\r\n  Compiler: Coverity C/C++ Static Analyzer");
5455 #elif defined(__LCC__)
5456 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5457     (void)fprintf (st, "\r\n  Compiler: MCST Elbrus C Compiler");
5458 #  if __LCC__ > 99
5459     (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5460 #   if defined(__LCC_MINOR__)
5461 #    if __LCC_MINOR__ > 0
5462     (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5463 #    endif
5464 #   endif
5465 #  endif
5466 #  if defined(__EDG__) && defined(__EDG_VERSION__)
5467 #   if __EDG_VERSION__ > 99
5468     (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5469                   (int)(((__EDG_VERSION__) % 100) % 10));
5470 #   endif
5471 #  endif
5472 # else
5473     (void)fprintf (st, "\r\n  Compiler: Local/Little C Compiler (lcc)");
5474 # endif
5475 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5476     (void)fprintf (st, "\r\n  Compiler: SGI MIPSpro");
5477 #elif defined(__OPEN64__)
5478     (void)fprintf (st, "\r\n  Compiler: Open64 %s", __OPEN64__);
5479 #elif defined(__PGI) || defined(__PGIC__)
5480     (void)fprintf (st, "\r\n  Compiler: Portland Group/PGI C/C++");
5481 #elif defined(__VBCC__)
5482     (void)fprintf (st, "\r\n  Compiler: Volker Barthelmann C Compiler (vbcc)");
5483 #elif defined(__WATCOMC__)
5484     (void)fprintf (st, "\r\n  Compiler: Watcom C/C++ %d.%d",
5485                    __WATCOMC__ / 100,
5486                    __WATCOMC__ % 100);
5487 #elif defined(__xlC__)
5488     (void)fprintf (st, "\r\n  Compiler: IBM XL C/C++");
5489 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5490 # if defined(__INTEL_COMPILER_UPDATE)
5491 #  if defined(__INTEL_COMPILER_BUILD_DATE)
5492     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d.%d (%d)",
5493                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5494                    __INTEL_COMPILER_BUILD_DATE);
5495 #  else
5496     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d.%d",
5497                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5498 #  endif
5499 # else
5500     (void)fprintf (st, "\r\n  Compiler: Intel C++ Compiler %d",
5501                    __INTEL_COMPILER);
5502 # endif
5503 #elif defined(SIM_COMPILER)
5504 # define S_xstr(a) S_str(a)
5505 # define S_str(a) #a
5506     (void)fprintf (st, "\r\n  Compiler: %s", S_xstr(SIM_COMPILER));
5507 # undef S_str
5508 # undef S_xstr
5509 #else
5510     (void)fprintf (st, "\r\n  Compiler: Unknown");
5511 #endif
5512 
5513 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5514     defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5515 # define SC_IS_PPC64 1
5516 #else
5517 # define SC_IS_PPC64 0
5518 #endif
5519 
5520 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5521     defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5522     defined(__PPC32)
5523 # define SC_IS_PPC32 1
5524 #else
5525 # define SC_IS_PPC32 0
5526 #endif
5527 
5528 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5529     arch = " x86_64";
5530 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5531     arch = " x86";
5532 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5533     arch = " arm64";
5534 #elif defined(_M_ARM) || defined(__arm__)
5535     arch = " arm";
5536 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5537     arch = " ia64";
5538 #elif SC_IS_PPC64
5539     arch = " powerpc64";
5540 #elif SC_IS_PPC32
5541     arch = " powerpc";
5542 #elif defined(__s390x__)
5543     arch = " s390x";
5544 #elif defined(__s390__)
5545     arch = " s390";
5546 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5547     arch = " j2";
5548 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5549     arch = " sh4";
5550 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5551     arch = " sh2";
5552 #elif defined(__alpha__)
5553     arch = " alpha";
5554 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5555     arch = " hppa";
5556 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5557     arch = " ice9";
5558 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5559     arch = " mips64";
5560 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5561     arch = " mips";
5562 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5563       defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5564     arch = " openrisc";
5565 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5566     arch = " sparc64";
5567 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5568     arch = " sparc";
5569 #elif defined(__riscv) || defined(__riscv__)
5570     arch = " riscv";
5571 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5572     arch = " e2k";
5573 #elif defined(__myriad2__)
5574     arch = " myriad2";
5575 #elif defined(__loongarch64) || defined(__loongarch__)
5576     arch = " loongarch";
5577 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5578     arch = " m68k";
5579 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5580     arch = " m88k";
5581 #elif defined(__VAX__) || defined(__vax__)
5582     arch = " vax";
5583 #elif defined(__NIOS2__) || defined(__nios2__)
5584     arch = " nios2";
5585 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5586     arch = " microblaze";
5587 #else
5588     arch = " ";
5589 #endif
5590     (void)fprintf (st, "%s", arch);
5591 #if defined(BUILD_BY_USER)
5592         (void)fprintf (st, "\r\n  Built by: %s", BUILD_BY_USER);
5593 #else
5594 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5595         (void)fprintf (st, "\r\n  Built by: %s", VER_H_PREP_USER);
5596 # endif
5597 #endif
5598                 (void)fprintf (st, "\r\n\r\n Host System Information:");
5599 #if defined(_WIN32)
5600     if (1) {
5601         char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5602         char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5603         char osversion[PATH_MAX+1] = "";
5604         FILE *f;
5605 
5606         if ((f = _popen ("ver", "r"))) {
5607             (void)memset (osversion, 0, sizeof(osversion));
5608             do {
5609                 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5610                     break;
5611                 sim_trim_endspc (osversion);
5612                 } while (osversion[0] == '\0');
5613             _pclose (f);
5614             }
5615         (void)fprintf (st, "\r\n   Host OS: %s", osversion);
5616         (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264  : "");
5617         }
5618 #else
5619     if (1) {
5620         char osversion[2*PATH_MAX+1] = "";
5621         FILE *f;
5622 # if !defined(_AIX)
5623         if ((f = popen \
5624              ("uname -mrs 2> /dev/null", "r"))) {
5625 # else
5626         if ((f = popen \
5627              ("sh -c 'echo \"$(command -p env uname -v \
5628                2> /dev/null).$(command -p env uname -r \
5629                2> /dev/null) $(command -p env uname -p \
5630                2> /dev/null)\"' 2> /dev/null", "r"))) {
5631 # endif /* if !defined(_AIX) */
5632             (void)memset (osversion, 0, sizeof(osversion));
5633             do {
5634               if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5635                     break;
5636               }
5637             sim_trim_endspc (osversion);
5638             } while (osversion[0] == '\0');
5639             pclose (f);
5640             strremove(osversion, "0000000000000000 ");
5641             strremove(osversion, " 0000000000000000");
5642             strremove(osversion, "000000000000 ");
5643             strremove(osversion, " 000000000000");
5644             strremove(osversion, "IBM ");
5645             strremove(osversion, " (emulated by qemu)");
5646             strremove(osversion, " (emulated by QEMU)");
5647         }
5648 # if !defined(_AIX)
5649             (void)fprintf (st, "\r\n   Host OS: %s", osversion);
5650 # else
5651             strremove(osversion, "AIX ");
5652 #  if !defined(__PASE__)
5653             (void)fprintf (st, "\r\n   Host OS: IBM AIX %s", osversion);
5654 #  else
5655             (void)fprintf (st, "\r\n   Host OS: IBM OS/400 (PASE) %s", osversion);
5656 #  endif /* if !defined(__PASE__) */
5657 # endif /* if !defined(_AIX) */
5658     } else {
5659 # if !defined(_AIX)
5660         (void)fprintf (st, "\r\n   Host OS: Unknown");
5661 # else
5662 #  if !defined(__PASE__)
5663         (void)fprintf (st, "\r\n   Host OS: IBM AIX");
5664 #  else
5665         (void)fprintf (st, "\r\n   Host OS: IBM OS/400 (PASE)");
5666 #  endif /* if !defined(__PASE__) */
5667 # endif /* if !defined(_AIX) */
5668     }
5669 #endif
5670     if (nodist)
5671       {
5672         sim_printf ("\r\n\r\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\r\n");
5673       }
5674     else
5675       {
5676         (void)fprintf (st, "\r\n");
5677         (void)fprintf (st, "\r\n This software is made available under the terms of the ICU License.");
5678         (void)fprintf (st, "\r\n For complete license details, see the LICENSE file included with the");
5679         (void)fprintf (st, "\r\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5680       }
5681         (void)fprintf (st, "\r\n");
5682     }
5683 return SCPE_OK;
5684 }
5685 
5686 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5687 {
5688 size_t i;
5689 DEVICE *dptr;
5690 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5691 
5692 if (cptr && (*cptr != 0))
5693     return SCPE_2MARG;
5694 (void)fprintf (st, "%s simulator configuration%s\r\n\r\n", sim_name, only_enabled ? " (enabled devices)" : "");
5695 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5696     if (!only_enabled || !qdisable (dptr))
5697         show_device (st, dptr, flag);
5698 return SCPE_OK;
5699 }
5700 
5701 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5702 {
5703 int32 i;
5704 DEVICE *dptr;
5705 
5706 if (cptr && (*cptr != 0))
5707     return SCPE_2MARG;
5708 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5709     show_dev_logicals (st, dptr, NULL, 1, cptr);
5710 return SCPE_OK;
5711 }
5712 
5713 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5714 {
5715 if (dptr->lname)
5716     (void)fprintf (st, "%s -> %s\r\n", dptr->lname, dptr->name);
5717 else if (!flag)
5718     fputs ("no logical name assigned\r\n", st);
5719 return SCPE_OK;
5720 }
5721 
5722 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5723 {
5724 DEVICE *dptr;
5725 UNIT *uptr;
5726 int32 accum;
5727 
5728 if (cptr && (*cptr != 0))
5729     return SCPE_2MARG;
5730 if (sim_clock_queue == QUEUE_LIST_END)
5731     (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\r\n",
5732                    sim_name, sim_time, sim_timer_inst_per_sec ());
5733 else {
5734     const char *tim;
5735 
5736     (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\r\n",
5737                    sim_name, sim_time, sim_timer_inst_per_sec ());
5738     accum = 0;
5739     for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5740         if (uptr == &sim_step_unit)
5741             (void)fprintf (st, "  Step timer");
5742         else
5743             if (uptr == &sim_expect_unit)
5744                 (void)fprintf (st, "  Expect fired");
5745             else
5746                 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5747                     (void)fprintf (st, "  %s", sim_dname (dptr));
5748                     if (dptr->numunits > 1)
5749                         (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5750                     }
5751                 else
5752                     (void)fprintf (st, "  Unknown");
5753         tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5754         (void)fprintf (st, " at %d%s%s%s%s\r\n", accum + uptr->time,
5755                        (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5756                        (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5757         accum = accum + uptr->time;
5758         }
5759     }
5760 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5761 return SCPE_OK;
5762 }
5763 
5764 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5765 {
5766 if (cptr && (*cptr != 0))
5767     return SCPE_2MARG;
5768 (void)fprintf (st, "Time:\t%.0f\r\n", sim_gtime());
5769 return SCPE_OK;
5770 }
5771 
5772 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5773 {
5774 t_stat r;
5775 
5776 if (cptr && (*cptr != 0))
5777     r = ssh_break (st, cptr, 1);  /* more? */
5778 else
5779     r = sim_brk_showall (st, (uint32)sim_switches);
5780 return r;
5781 }
5782 
5783 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5784 {
5785 (void)fprintf (st, "Radix=%d\r\n", dptr->dradix);
5786 return SCPE_OK;
5787 }
5788 
5789 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5790 {
5791 int32 any = 0;
5792 DEBTAB *dep;
5793 
5794 if (dptr->flags & DEV_DEBUG) {
5795     if (dptr->dctrl == 0)
5796         fputs ("Debugging disabled", st);
5797     else if (dptr->debflags == NULL)
5798         fputs ("Debugging enabled", st);
5799     else {
5800         uint32 dctrl = dptr->dctrl;
5801 
5802         fputs ("Debug=", st);
5803         for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5804             if ((dctrl & dep->mask) == dep->mask) {
5805                 dctrl &= ~dep->mask;
5806                 if (any)
5807                     fputc (';', st);
5808                 fputs (dep->name, st);
5809                 any = 1;
5810                 }
5811             }
5812         }
5813     fputc ('\n', st);
5814     return SCPE_OK;
5815     }
5816 else return SCPE_NOFNC;
5817 }
5818 
5819 /* Show On actions */
5820 
5821 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5822 {
5823 int32 lvl, i;
5824 
5825 if (cptr && (*cptr != 0)) return SCPE_2MARG;            /* now eol? */
5826 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5827     if (lvl > 0)
5828         (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5829     else
5830         (void)fprintf(st, "On Processing for input commands");
5831     (void)fprintf(st, " is %s\r\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5832     for (i=1; i<SCPE_BASE; ++i) {
5833         if (sim_on_actions[lvl][i])
5834             (void)fprintf(st, "    on %5d    %s\r\n", i, sim_on_actions[lvl][i]); }
5835     for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5836         if (sim_on_actions[lvl][i])
5837             (void)fprintf(st, "    on %-5s    %s\r\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5838     if (sim_on_actions[lvl][0])
5839         (void)fprintf(st, "    on ERROR    %s\r\n", sim_on_actions[lvl][0]);
5840     (void)fprintf(st, "\r\n");
5841     }
5842 if (sim_on_inherit)
5843     (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\r\n");
5844 return SCPE_OK;
5845 }
5846 
5847 /* Show modifiers */
5848 
5849 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5850 {
5851 int32 i;
5852 DEVICE *dptr;
5853 
5854 if (cptr && (*cptr != 0))                               /* now eol? */
5855     return SCPE_2MARG;
5856 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5857     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5858 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5859     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5860 return SCPE_OK;
5861 }
5862 
5863 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5864 {
5865 fprint_set_help (st, dptr);
5866 return SCPE_OK;
5867 }
5868 
5869 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
     /* [previous][next][first][last][top][bottom][index][help] */
5870 {
5871 MTAB *mptr;
5872 t_stat r = SCPE_OK;
5873 
5874 if (dptr->modifiers == NULL)
5875     return SCPE_OK;
5876 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5877     if (mptr->pstring &&
5878         ((mptr->mask & MTAB_XTD)?
5879             (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5880             ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5881         if (*toks > 0) {
5882             (void)fprintf (st, "\r\n");
5883             *toks = 0;
5884             }
5885         if (r == SCPE_OK)
5886             fprint_sep (st, toks);
5887         r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5888         }
5889     }
5890 return SCPE_OK;
5891 }
5892 
5893 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
     /* [previous][next][first][last][top][bottom][index][help] */
5894     CONST char *cptr, int32 flag)
5895 {
5896 t_stat r = SCPE_OK;
5897 
5898 if (mptr->disp)
5899     r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5900 else
5901     fputs (mptr->pstring, st);
5902 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5903     fputc ('\n', st);
5904 return r;
5905 }
5906 
5907 /* Show show commands */
5908 
5909 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5910 {
5911 int32 i;
5912 DEVICE *dptr;
5913 
5914 if (cptr && (*cptr != 0))                               /* now eol? */
5915     return SCPE_2MARG;
5916 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5917     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5918 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5919     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5920 return SCPE_OK;
5921 }
5922 
5923 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] */
5924 {
5925 fprint_show_help (st, dptr);
5926 return SCPE_OK;
5927 }
5928 
5929 /* Breakpoint commands */
5930 
5931 t_stat brk_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5932 {
5933 GET_SWITCHES (cptr);                                    /* get switches */
5934 return ssh_break (NULL, cptr, flg);                     /* call common code */
5935 }
5936 
5937 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
     /* [previous][next][first][last][top][bottom][index][help] */
5938 {
5939 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5940 CONST char *tptr, *t1ptr;
5941 DEVICE *dptr = sim_dflt_dev;
5942 UNIT *uptr;
5943 t_stat r;
5944 t_addr lo, hi, max;
5945 int32 cnt;
5946 
5947 if (sim_brk_types == 0)
5948     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
5949 if (dptr == NULL)
5950     return SCPE_IERR;
5951 uptr = dptr->units;
5952 if (uptr == NULL)
5953     return SCPE_IERR;
5954 max = uptr->capac - 1;
5955 abuf[sizeof(abuf)-1] = '\0';
5956 strncpy (abuf, cptr, sizeof(abuf)-1);
5957 cptr = abuf;
5958 if ((aptr = strchr (abuf, ';'))) {                      /* ;action? */
5959     if (flg != SSH_ST)                                  /* only on SET */
5960         return sim_messagef (SCPE_ARG, "Invalid argument: %s\r\n", aptr);
5961     *aptr++ = 0;                                        /* separate strings */
5962     }
5963 if (*cptr == 0) {                                       /* no argument? */
5964     lo = (t_addr) get_rval (sim_PC, 0);                 /* use PC */
5965     return ssh_break_one (st, flg, lo, 0, aptr);
5966     }
5967 while (*cptr) {
5968     cptr = get_glyph (cptr, gbuf, ',');
5969     tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5970     if (tptr == NULL)
5971         return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\r\n", gbuf);
5972     if (*tptr == '[') {
5973         cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5974         if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5975             return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\r\n", tptr + 1);
5976         tptr = t1ptr + 1;
5977         }
5978     else cnt = 0;
5979     if (*tptr != 0)
5980         return sim_messagef (SCPE_ARG, "Unexpected argument: %s\r\n", tptr);
5981     if ((lo == 0) && (hi == max)) {
5982         if (flg == SSH_CL)
5983             sim_brk_clrall (sim_switches);
5984         else
5985             if (flg == SSH_SH)
5986                 sim_brk_showall (st, (uint32)sim_switches);
5987             else
5988                 return SCPE_ARG;
5989         }
5990     else {
5991         for ( ; lo <= hi; lo = lo + 1) {
5992             r = ssh_break_one (st, flg, lo, cnt, aptr);
5993             if (r != SCPE_OK)
5994                 return r;
5995             }
5996         }
5997     }
5998 return SCPE_OK;
5999 }
6000 
6001 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] */
6002 {
6003 if (!sim_brk_types)
6004     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\r\n");
6005 switch (flg) {
6006     case SSH_ST:
6007         return sim_brk_set (lo, sim_switches, cnt, aptr);
6008         /*NOTREACHED*/ /* unreachable */
6009         break;
6010 
6011     case SSH_CL:
6012         return sim_brk_clr (lo, sim_switches);
6013         /*NOTREACHED*/ /* unreachable */
6014         break;
6015 
6016     case SSH_SH:
6017         return sim_brk_show (st, lo, sim_switches);
6018         /*NOTREACHED*/ /* unreachable */
6019         break;
6020 
6021     default:
6022         return SCPE_ARG;
6023     }
6024 }
6025 
6026 /* Reset command and routines */
6027 
6028 static t_bool run_cmd_did_reset = FALSE;
6029 
6030 t_stat reset_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6031 {
6032 char gbuf[CBUFSIZE];
6033 DEVICE *dptr;
6034 
6035 GET_SWITCHES (cptr);                                    /* get switches */
6036 run_cmd_did_reset = FALSE;
6037 if (*cptr == 0)                                         /* reset(cr) */
6038     return (reset_all (0));
6039 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6040 if (*cptr != 0)                                         /* now eol? */
6041     return SCPE_2MARG;
6042 if (strcmp (gbuf, "ALL") == 0)
6043     return (reset_all (0));
6044 dptr = find_dev (gbuf);                                 /* locate device */
6045 if (dptr == NULL)                                       /* found it? */
6046     return SCPE_NXDEV;
6047 if (dptr->reset != NULL)
6048     return dptr->reset (dptr);
6049 else return SCPE_OK;
6050 }
6051 
6052 /* Reset devices start..end
6053 
6054    Inputs:
6055         start   =       number of starting device
6056    Outputs:
6057         status  =       error status
6058 */
6059 
6060 t_stat reset_all (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6061 {
6062 DEVICE *dptr;
6063 uint32 i;
6064 t_stat reason;
6065 
6066 for (i = 0; i < start; i++) {
6067     if (sim_devices[i] == NULL)
6068         return SCPE_IERR;
6069     }
6070 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6071     if (dptr->reset != NULL) {
6072         reason = dptr->reset (dptr);
6073         if (reason != SCPE_OK)
6074             return reason;
6075         }
6076     }
6077 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6078     if (dptr->reset != NULL) {
6079         reason = dptr->reset (dptr);
6080         if (reason != SCPE_OK)
6081             return reason;
6082         }
6083     }
6084 return SCPE_OK;
6085 }
6086 
6087 /* Reset to powerup state
6088 
6089    Inputs:
6090         start   =       number of starting device
6091    Outputs:
6092         status  =       error status
6093 */
6094 
6095 t_stat reset_all_p (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6096 {
6097 t_stat r;
6098 int32 old_sw = sim_switches;
6099 
6100 sim_switches = SWMASK ('P');
6101 r = reset_all (start);
6102 sim_switches = old_sw;
6103 return r;
6104 }
6105 
6106 /* Attach command */
6107 
6108 t_stat attach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6109 {
6110 char gbuf[4*CBUFSIZE];
6111 DEVICE *dptr;
6112 UNIT *uptr;
6113 t_stat r;
6114 
6115 GET_SWITCHES (cptr);                                    /* get switches */
6116 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6117     return SCPE_2FARG;
6118 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6119 GET_SWITCHES (cptr);                                    /* get switches */
6120 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* now eol? */
6121     return SCPE_2FARG;
6122 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6123 if (dptr == NULL)                                       /* found dev? */
6124     return SCPE_NXDEV;
6125 if (uptr == NULL)                                       /* valid unit? */
6126     return SCPE_NXUN;
6127 if (uptr->flags & UNIT_ATT) {                           /* already attached? */
6128     if (!(uptr->dynflags & UNIT_ATTMULT) &&             /* and only single attachable */
6129         !(dptr->flags & DEV_DONTAUTO)) {                /* and auto detachable */
6130         r = scp_detach_unit (dptr, uptr);               /* detach it */
6131         if (r != SCPE_OK)                               /* error? */
6132             return r; }
6133     else {
6134         if (!(uptr->dynflags & UNIT_ATTMULT))
6135             return SCPE_ALATT;                          /* Already attached */
6136         }
6137     }
6138 gbuf[sizeof(gbuf)-1] = '\0';
6139 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6140 sim_trim_endspc (gbuf);                                 /* trim trailing spc */
6141 return scp_attach_unit (dptr, uptr, gbuf);              /* attach */
6142 }
6143 
6144 /* Call device-specific or file-oriented attach unit routine */
6145 
6146 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6147 {
6148 if (dptr->attach != NULL)                               /* device routine? */
6149     return dptr->attach (uptr, (CONST char *)cptr);     /* call it */
6150 return attach_unit (uptr, (CONST char *)cptr);          /* no, std routine */
6151 }
6152 
6153 /* Attach unit to file */
6154 
6155 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6156 {
6157 DEVICE *dptr;
6158 
6159 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6160     return SCPE_UDIS;
6161 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
6162     return SCPE_NOATT;
6163 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6164     return SCPE_NOATT;
6165 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */
6166 if (uptr->filename == NULL)
6167     return SCPE_MEM;
6168 strncpy (uptr->filename, cptr, CBUFSIZE-1);             /* save name */
6169 if ((sim_switches & SWMASK ('R')) ||                    /* read only? */
6170     ((uptr->flags & UNIT_RO) != 0)) {
6171     if (((uptr->flags & UNIT_ROABLE) == 0) &&           /* allowed? */
6172         ((uptr->flags & UNIT_RO) == 0))
6173         return attach_err (uptr, SCPE_NORO);            /* no, error */
6174     uptr->fileref = sim_fopen (cptr, "rb");             /* open rd only */
6175     if (uptr->fileref == NULL)                          /* open fail? */
6176         return attach_err (uptr, SCPE_OPENERR);         /* yes, error */
6177     uptr->flags = uptr->flags | UNIT_RO;                /* set rd only */
6178     if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6179         sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6180         }
6181     }
6182 else {
6183     if (sim_switches & SWMASK ('N')) {                  /* new file only? */
6184         uptr->fileref = sim_fopen (cptr, "wb+");        /* open new file */
6185         if (uptr->fileref == NULL)                      /* open fail? */
6186             return attach_err (uptr, SCPE_OPENERR);     /* yes, error */
6187         if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6188             sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6189             }
6190         }
6191     else {                                              /* normal */
6192         uptr->fileref = sim_fopen (cptr, "rb+");        /* open r/w */
6193         if (uptr->fileref == NULL) {                    /* open fail? */
6194 #if defined(EWOULDBLOCK)
6195             if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6196 #else
6197             if ((errno == EAGAIN))
6198 #endif
6199                 return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6200 
6201 #if defined(EPERM)
6202             if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {/* read only? */
6203 #else
6204             if ((errno == EROFS) || (errno == EACCES)) {/* read only? */
6205 #endif
6206                 if ((uptr->flags & UNIT_ROABLE) == 0)   /* allowed? */
6207                     return attach_err (uptr, SCPE_NORO);/* no error */
6208                 uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */
6209                 if (uptr->fileref == NULL)              /* open fail? */
6210                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6211                 uptr->flags = uptr->flags | UNIT_RO;    /* set rd only */
6212                 if (!sim_quiet) {
6213                     sim_printf ("%s: unit is read only (%s)\r\n", sim_dname (dptr), cptr);
6214                     }
6215                 }
6216             else {                                      /* doesn't exist */
6217                 if (sim_switches & SWMASK ('E'))        /* must exist? */
6218                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6219                 uptr->fileref = sim_fopen (cptr, "wb+");/* open new file */
6220                 if (uptr->fileref == NULL)              /* open fail? */
6221                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6222                 if (!sim_quiet) {
6223                     sim_printf ("%s: creating new file (%s)\r\n", sim_dname (dptr), cptr);
6224                     }
6225                 }
6226             }                                           /* end if null */
6227         }                                               /* end else */
6228     }
6229 if (uptr->flags & UNIT_BUFABLE) {                       /* buffer? */
6230     uint32 cap = ((uint32) uptr->capac) / dptr->aincr;  /* effective size */
6231     if (uptr->flags & UNIT_MUSTBUF)                     /* dyn alloc? */
6232         uptr->filebuf = calloc (cap, SZ_D (dptr));      /* allocate */
6233     if (uptr->filebuf == NULL)                          /* no buffer? */
6234         return attach_err (uptr, SCPE_MEM);             /* error */
6235     if (!sim_quiet) {
6236         sim_printf ("%s: buffering file in memory\r\n", sim_dname (dptr));
6237         }
6238     uptr->hwmark = (uint32)sim_fread (uptr->filebuf,    /* read file */
6239         SZ_D (dptr), cap, uptr->fileref);
6240     uptr->flags = uptr->flags | UNIT_BUF;               /* set buffered */
6241     }
6242 uptr->flags = uptr->flags | UNIT_ATT;
6243 uptr->pos = 0;
6244 return SCPE_OK;
6245 }
6246 
6247 t_stat attach_err (UNIT *uptr, t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
6248 {
6249 FREE (uptr->filename);
6250 uptr->filename = NULL;
6251 return stat;
6252 }
6253 
6254 /* Detach command */
6255 
6256 t_stat detach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6257 {
6258 char gbuf[CBUFSIZE];
6259 DEVICE *dptr;
6260 UNIT *uptr;
6261 
6262 GET_SWITCHES (cptr);                                    /* get switches */
6263 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6264     return SCPE_2FARG;
6265 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6266 if (*cptr != 0)                                         /* now eol? */
6267     return SCPE_2MARG;
6268 if (strcmp (gbuf, "ALL") == 0)
6269     return (detach_all (0, FALSE));
6270 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6271 if (dptr == NULL)                                       /* found dev? */
6272     return SCPE_NXDEV;
6273 if (uptr == NULL)                                       /* valid unit? */
6274     return SCPE_NXUN;
6275 return scp_detach_unit (dptr, uptr);                    /* detach */
6276 }
6277 
6278 /* Detach devices start..end
6279 
6280    Inputs:
6281         start   =       number of starting device
6282         shutdown =      TRUE if simulator shutting down
6283    Outputs:
6284         status  =       error status
6285 
6286    Note that during shutdown, detach routines for non-attachable devices
6287    will be called.  These routines can implement simulator shutdown.  Error
6288    returns during shutdown are ignored.
6289 */
6290 
6291 t_stat detach_all (int32 start, t_bool shutdown)
     /* [previous][next][first][last][top][bottom][index][help] */
6292 {
6293 uint32 i, j;
6294 DEVICE *dptr;
6295 UNIT *uptr;
6296 t_stat r;
6297 
6298 if ((start < 0) || (start > 1))
6299     return SCPE_IERR;
6300 if (shutdown)
6301     sim_switches = sim_switches | SIM_SW_SHUT;          /* flag shutdown */
6302 for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
6303     for (j = 0; j < dptr->numunits; j++) {              /* loop thru units */
6304         uptr = (dptr->units) + j;
6305         if ((uptr->flags & UNIT_ATT) ||                 /* attached? */
6306             (shutdown && dptr->detach &&                /* shutdown, spec rtn, */
6307             !(uptr->flags & UNIT_ATTABLE))) {           /* !attachable? */
6308             r = scp_detach_unit (dptr, uptr);           /* detach unit */
6309 
6310             if ((r != SCPE_OK) && !shutdown)            /* error and not shutting down? */
6311                 return r;                               /* bail out now with error status */
6312             }
6313         }
6314     }
6315 return SCPE_OK;
6316 }
6317 
6318 /* Call device-specific or file-oriented detach unit routine */
6319 
6320 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6321 {
6322 if (dptr->detach != NULL)                               /* device routine? */
6323     return dptr->detach (uptr);
6324 return detach_unit (uptr);                              /* no, standard */
6325 }
6326 
6327 /* Detach unit from file */
6328 
6329 t_stat detach_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6330 {
6331 DEVICE *dptr;
6332 
6333 if (uptr == NULL)
6334     return SCPE_IERR;
6335 if (!(uptr->flags & UNIT_ATTABLE))                      /* attachable? */
6336     return SCPE_NOATT;
6337 if (!(uptr->flags & UNIT_ATT)) {                        /* not attached? */
6338     if (sim_switches & SIM_SW_REST)                     /* restoring? */
6339         return SCPE_OK;                                 /* allow detach */
6340     else
6341         return SCPE_NOTATT;                             /* complain */
6342     }
6343 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6344     return SCPE_OK;
6345 if (uptr->flags & UNIT_BUF) {
6346     uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6347     if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6348         if (!sim_quiet) {
6349             sim_printf ("%s: writing buffer to file\r\n", sim_dname (dptr));
6350             }
6351         rewind (uptr->fileref);
6352         sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6353         if (ferror (uptr->fileref))
6354             sim_printf ("%s: I/O error - %s (Error %d)\r\n",
6355                         sim_dname (dptr), xstrerror_l(errno), errno);
6356         }
6357     if (uptr->flags & UNIT_MUSTBUF) {                   /* dyn alloc? */
6358         FREE (uptr->filebuf);                           /* free buf */
6359         uptr->filebuf = NULL;
6360         }
6361     uptr->flags = uptr->flags & ~UNIT_BUF;
6362     }
6363 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6364 FREE (uptr->filename);
6365 uptr->filename = NULL;
6366 if (fclose (uptr->fileref) == EOF)
6367     return SCPE_IOERR;
6368 return SCPE_OK;
6369 }
6370 
6371 /* Get device display name */
6372 
6373 const char *sim_dname (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6374 {
6375 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6376 }
6377 
6378 /* Get unit display name */
6379 
6380 const char *sim_uname (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6381 {
6382 DEVICE *d = find_dev_from_unit(uptr);
6383 static char uname[CBUFSIZE];
6384 
6385 if (!d)
6386     return "";
6387 if (d->numunits == 1)
6388     return sim_dname (d);
6389 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6390 return uname;
6391 }
6392 
6393 /* Run, go, boot, cont, step, next commands */
6394 
6395 t_stat run_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6396 {
6397 char gbuf[CBUFSIZE] = "";
6398 CONST char *tptr;
6399 uint32 i, j;
6400 int32 sim_next = 0;
6401 int32 unitno;
6402 t_value pcv, orig_pcv;
6403 t_stat r;
6404 DEVICE *dptr;
6405 UNIT *uptr;
6406 
6407 GET_SWITCHES (cptr);                                    /* get switches */
6408 sim_step = 0;
6409 if ((flag == RU_RUN) || (flag == RU_GO)) {              /* run or go */
6410     orig_pcv = get_rval (sim_PC, 0);                    /* get current PC value */
6411     if (*cptr != 0) {                                   /* argument? */
6412         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6413         if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6414             if (sim_dflt_dev && sim_vm_parse_addr)      /* address parser? */
6415                 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6416             else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */
6417             if ((tptr == gbuf) || (*tptr != 0) ||       /* error? */
6418                 (pcv > width_mask[sim_PC->width]))
6419                 return SCPE_ARG;
6420             put_rval (sim_PC, 0, pcv);                  /* Save in PC */
6421             }
6422         }
6423     if ((flag == RU_RUN) &&                             /* run? */
6424         ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {  /* reset sim */
6425         put_rval (sim_PC, 0, orig_pcv);                 /* restore original PC */
6426         return r;
6427         }
6428     if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) { //-V600 /* should be end */
6429         int32 saved_switches = sim_switches;
6430 
6431         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6432             cptr = get_glyph (cptr, gbuf, 0);           /* get next glyph */
6433         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6434             return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\r\n",
6435                                              (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6436         sim_switches = 0;
6437         GET_SWITCHES (cptr);
6438         if ((*cptr == '\'') || (*cptr == '"')) {        /* Expect UNTIL condition */
6439             r = expect_cmd (1, cptr);
6440             if (r != SCPE_OK)
6441                 return r;
6442             }
6443         else {                                          /* BREAK UNTIL condition */
6444             if (sim_switches == 0)
6445                 sim_switches = sim_brk_dflt;
6446             sim_switches |= BRK_TYP_TEMP;               /* make this a one-shot breakpoint */
6447             sim_brk_types |= BRK_TYP_TEMP;
6448             r = ssh_break (NULL, cptr, SSH_ST);
6449             if (r != SCPE_OK)
6450                 return sim_messagef (r, "Unable to establish breakpoint at: %s\r\n", cptr);
6451             }
6452         sim_switches = saved_switches;
6453         }
6454     }
6455 
6456 else if ((flag == RU_STEP) ||
6457          ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) { /* step */
6458     static t_bool not_implemented_message = FALSE;
6459 
6460     if ((!not_implemented_message) && (flag == RU_NEXT)) {
6461         not_implemented_message = TRUE;
6462         flag = RU_STEP;
6463         }
6464     if (*cptr != 0) {                                   /* argument? */
6465         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6466         if (*cptr != 0)                                 /* should be end */
6467             return SCPE_2MARG;
6468         sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6469         if ((r != SCPE_OK) || (sim_step <= 0))          /* error? */
6470             return SCPE_ARG;
6471         }
6472     else sim_step = 1;
6473     if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6474         sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6475     }
6476 else if (flag == RU_NEXT) {                             /* next */
6477     t_addr *addrs;
6478 
6479     if (*cptr != 0) {                                   /* argument? */
6480         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6481         if (*cptr != 0)                                 /* should be end */
6482             return SCPE_2MARG;
6483         sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6484         if ((r != SCPE_OK) || (sim_next <= 0))          /* error? */
6485             return SCPE_ARG;
6486         }
6487     else sim_next = 1;
6488     if (sim_vm_is_subroutine_call(&addrs)) {
6489         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6490         for (i=0; addrs[i]; i++)
6491             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6492         }
6493     else
6494         sim_step = 1;
6495     }
6496 else if (flag == RU_BOOT) {                             /* boot */
6497     if (*cptr == 0)                                     /* must be more */
6498         return SCPE_2FARG;
6499     cptr = get_glyph (cptr, gbuf, 0);                   /* get next glyph */
6500     if (*cptr != 0)                                     /* should be end */
6501         return SCPE_2MARG;
6502     dptr = find_unit (gbuf, &uptr);                     /* locate unit */
6503     if (dptr == NULL)                                   /* found dev? */
6504         return SCPE_NXDEV;
6505     if (uptr == NULL)                                   /* valid unit? */
6506         return SCPE_NXUN;
6507     if (dptr->boot == NULL)                             /* can it boot? */
6508         return SCPE_NOFNC;
6509     if (uptr->flags & UNIT_DIS)                         /* disabled? */
6510         return SCPE_UDIS;
6511     if ((uptr->flags & UNIT_ATTABLE) &&                 /* if attable, att? */
6512         !(uptr->flags & UNIT_ATT))
6513         return SCPE_UNATT;
6514     unitno = (int32) (uptr - dptr->units);              /* recover unit# */
6515     if ((r = sim_run_boot_prep (flag)) != SCPE_OK)      /* reset sim */
6516         return r;
6517     if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)     /* boot device */
6518         return r;
6519     }
6520 
6521 else
6522     if (flag != RU_CONT)                                /* must be cont */
6523         return SCPE_IERR;
6524     else                                                /* CONTINUE command */
6525         if (*cptr != 0)                                 /* should be end (no arguments allowed) */
6526             return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\r\n");
6527 
6528 if (sim_switches & SIM_SW_HIDE)                         /* Setup only for Remote Console Mode */
6529     return SCPE_OK;
6530 
6531 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* reposition all */
6532     for (j = 0; j < dptr->numunits; j++) {              /* seq devices */
6533         uptr = dptr->units + j;
6534         if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6535             sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6536         }
6537     }
6538 stop_cpu = 0;
6539 sim_is_running = 1;                                     /* flag running */
6540 if (sim_ttrun () != SCPE_OK) {                          /* set console mode */
6541     sim_is_running = 0;                                 /* flag idle */
6542     sim_ttcmd ();
6543     return SCPE_TTYERR;
6544     }
6545 if ((r = sim_check_console (30)) != SCPE_OK) {          /* check console, error? */
6546     sim_is_running = 0;                                 /* flag idle */
6547     sim_ttcmd ();
6548     return r;
6549     }
6550 #if !defined(IS_WINDOWS)
6551 # if defined(SIGINT)
6552 if (signal (SIGINT, int_handler) == SIG_ERR) {          /* set WRU */
6553     sim_is_running = 0;                                 /* flag idle */
6554     sim_ttcmd ();
6555     return SCPE_SIGERR;
6556     }
6557 # endif
6558 #endif
6559 #if !defined(IS_WINDOWS)
6560 # if defined(SIGHUP)
6561 if (signal (SIGHUP, int_handler) == SIG_ERR) {          /* set WRU */
6562     sim_is_running = 0;                                 /* flag idle */
6563     sim_ttcmd ();
6564     return SCPE_SIGERR;
6565     }
6566 # endif
6567 #endif
6568 #if !defined(IS_WINDOWS)
6569 # if defined(SIGTERM)
6570 if (signal (SIGTERM, int_handler) == SIG_ERR) {         /* set WRU */
6571     sim_is_running = 0;                                 /* flag idle */
6572     sim_ttcmd ();
6573     return SCPE_SIGERR;
6574     }
6575 # endif
6576 #endif
6577 if (sim_step)                                           /* set step timer */
6578     sim_activate (&sim_step_unit, sim_step);
6579 (void)fflush(stdout);                                   /* flush stdout */
6580 if (sim_log)                                            /* flush log if enabled */
6581     (void)fflush (sim_log);
6582 sim_rtcn_init_all ();                                   /* re-init clocks */
6583 sim_start_timer_services ();                            /* enable wall clock timing */
6584 
6585 do {
6586     t_addr *addrs;
6587 
6588     while (1) {
6589         r = sim_instr();
6590         if (r != SCPE_REMOTE)
6591             break;
6592         sim_remote_process_command ();                  /* Process the command and resume processing */
6593         }
6594     if ((flag != RU_NEXT) ||                            /* done if not doing NEXT */
6595         (--sim_next <=0))
6596         break;
6597     if (sim_step == 0) {                                /* doing a NEXT? */
6598         t_addr val;
6599         BRKTAB *bp;
6600 
6601         if (SCPE_BARE_STATUS(r) >= SCPE_BASE)           /* done if an error occurred */
6602             break;
6603         if (sim_vm_pc_value)                            /* done if didn't stop at a dynamic breakpoint */
6604             val = (t_addr)(*sim_vm_pc_value)();
6605         else
6606             val = (t_addr)get_rval (sim_PC, 0);
6607         if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6608             break;
6609         sim_brk_clrall (BRK_TYP_DYN_STEPOVER);          /* cancel any step/over subroutine breakpoints */
6610         }
6611     else {
6612         if (r != SCPE_STEP)                             /* done if step didn't complete with step expired */
6613             break;
6614         }
6615     /* setup another next/step */
6616     sim_step = 0;
6617     if (sim_vm_is_subroutine_call(&addrs)) {
6618         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6619         for (i=0; addrs[i]; i++)
6620             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6621         }
6622     else
6623         sim_step = 1;
6624     if (sim_step)                                       /* set step timer */
6625         sim_activate (&sim_step_unit, sim_step);
6626     } while (1);
6627 
6628 sim_is_running = 0;                                     /* flag idle */
6629 sim_stop_timer_services ();                             /* disable wall clock timing */
6630 sim_ttcmd ();                                           /* restore console */
6631 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);                  /* cancel any step/over subroutine breakpoints */
6632 signal (SIGINT, SIG_DFL);                               /* cancel WRU */
6633 #if defined(SIGHUP)
6634 signal (SIGHUP, SIG_DFL);                               /* cancel WRU */
6635 #endif
6636 signal (SIGTERM, SIG_DFL);                              /* cancel WRU */
6637 if (sim_log)                                            /* flush console log */
6638     (void)fflush (sim_log);
6639 if (sim_deb)                                            /* flush debug log */
6640     sim_debug_flush ();
6641 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* flush attached files */
6642     for (j = 0; j < dptr->numunits; j++) {              /* if not buffered in mem */
6643         uptr = dptr->units + j;
6644         if (uptr->flags & UNIT_ATT) {                   /* attached, */
6645             if (uptr->io_flush)                         /* unit specific flush routine */
6646                 uptr->io_flush (uptr);                  /* call it */
6647             else {
6648                 if (!(uptr->flags & UNIT_BUF) &&        /* not buffered, */
6649                     (uptr->fileref) &&                  /* real file, */
6650                     !(uptr->dynflags & UNIT_NO_FIO) &&  /* is FILE *, */
6651                     !(uptr->flags & UNIT_RO))           /* not read only? */
6652                     (void)fflush (uptr->fileref);
6653                 }
6654             }
6655         }
6656     }
6657 sim_cancel (&sim_step_unit);                            /* cancel step timer */
6658 UPDATE_SIM_TIME;                                        /* update sim time */
6659 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6660 }
6661 
6662 /* run command message handler */
6663 
6664 void
6665 run_cmd_message (const char *unechoed_cmdline, t_stat r)
     /* [previous][next][first][last][top][bottom][index][help] */
6666 {
6667 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6668     sim_printf("%s> %s\r\n", do_position(), unechoed_cmdline);
6669 #if defined(WIN_STDIO)
6670 (void)fflush(stderr);
6671 (void)fflush(stdout);
6672 #endif /* if defined(WIN_STDIO) */
6673 fprint_stopped (stdout, r);                         /* print msg */
6674 if (sim_log && (sim_log != stdout))                 /* log if enabled */
6675     fprint_stopped (sim_log, r);
6676 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))/* debug if enabled */
6677     fprint_stopped (sim_deb, r);
6678 #if defined(WIN_STDIO)
6679 (void)fflush(stderr);
6680 (void)fflush(stdout);
6681 #endif /* if defined(WIN_STDIO) */
6682 }
6683 
6684 /* Common setup for RUN or BOOT */
6685 
6686 t_stat sim_run_boot_prep (int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
6687 {
6688 UNIT *uptr;
6689 t_stat r;
6690 
6691 sim_interval = 0;                                       /* reset queue */
6692 sim_time = sim_rtime = 0;
6693 noqueue_time = 0;
6694 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6695     sim_clock_queue = uptr->next;
6696     uptr->next = NULL;
6697     }
6698 r = reset_all (0);
6699 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6700     if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6701         sim_printf ("Resetting all devices...  This may not have been your intention.\r\n");
6702         sim_printf ("The GO and CONTINUE commands do not reset devices.\r\n");
6703         }
6704     run_cmd_did_reset = TRUE;
6705     }
6706 return r;
6707 }
6708 
6709 /* Print stopped message
6710  * For VM stops, if a VM-specific "sim_vm_fprint_stopped" pointer is defined,
6711  * call the indicated routine to print additional information after the message
6712  * and before the PC value is printed.  If the routine returns FALSE, skip
6713  * printing the PC and its related instruction.
6714  */
6715 
6716 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6717 {
6718 int32 i;
6719 t_stat r = 0;
6720 t_addr k;
6721 t_value pcval;
6722 
6723 fputc ('\n', st);                                       /* start on a new line */
6724 
6725 if (v >= SCPE_BASE)                                     /* SCP error? */
6726     fputs (sim_error_text (v), st);                     /* print it from the SCP list */
6727 else {                                                  /* VM error */
6728     fputs (sim_stop_messages [v], st);                  /* print the VM-specific message */
6729 
6730     if ((sim_vm_fprint_stopped != NULL) &&              /* if a VM-specific stop handler is defined */
6731         (!sim_vm_fprint_stopped (st, v)))               /*   call it; if it returned FALSE, */
6732         return;                                         /*     we're done */
6733     }
6734 
6735 (void)fprintf (st, ", %s: ", pc->name);                       /* print the name of the PC register */
6736 
6737 pcval = get_rval (pc, 0);
6738 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)       /* if reg wants VM-specific printer */
6739     sim_vm_fprint_addr (st, dptr, (t_addr) pcval);      /*   call it to print the PC address */
6740 else fprint_val (st, pcval, pc->radix, pc->width,       /* otherwise, print as a numeric value */
6741     pc->flags & REG_FMT);                               /*   with the radix and formatting specified */
6742 if ((dptr != NULL) && (dptr->examine != NULL)) {
6743     for (i = 0; i < sim_emax; i++)
6744         sim_eval[i] = 0;
6745     for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6746         if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6747             break;
6748         }
6749     if ((r == SCPE_OK) || (i > 0)) {
6750         (void)fprintf (st, " (");
6751         if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6752             fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6753         (void)fprintf (st, ")");
6754         }
6755     }
6756 (void)fprintf (st, "\r\n");
6757 return;
6758 }
6759 
6760 void fprint_stopped (FILE *st, t_stat v)
     /* [previous][next][first][last][top][bottom][index][help] */
6761 {
6762 #if defined(WIN_STDIO)
6763 (void)fflush(stderr);
6764 (void)fflush(stdout);
6765 #endif /* if defined(WIN_STDIO) */
6766 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6767 return;
6768 }
6769 
6770 /* Unit service for step timeout, originally scheduled by STEP n command
6771    Return step timeout SCP code, will cause simulation to stop */
6772 
6773 t_stat step_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6774 {
6775 return SCPE_STEP;
6776 }
6777 
6778 /* Unit service to facilitate expect matching to stop simulation.
6779    Return expect SCP code, will cause simulation to stop */
6780 
6781 t_stat expect_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6782 {
6783 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6784 }
6785 
6786 /* Signal handler for ^C signal - set stop simulation flag */
6787 
6788 void int_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
6789 {
6790 stop_cpu = 1;
6791 return;
6792 }
6793 
6794 /* Examine/deposit commands */
6795 
6796 t_stat exdep_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6797 {
6798 char gbuf[CBUFSIZE];
6799 CONST char *gptr;
6800 CONST char *tptr = NULL;
6801 int32 opt;
6802 t_addr low, high;
6803 t_stat reason = SCPE_IERR;
6804 DEVICE *tdptr;
6805 REG *lowr, *highr;
6806 FILE *ofile;
6807 
6808 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;               /* options for all */
6809 if (flag == EX_E)                                       /* extra for EX */
6810     opt = opt | CMD_OPT_OF;
6811 cptr = get_sim_opt (opt, cptr, &reason);                /* get cmd options */
6812 if (NULL == cptr)                                       /* error? */
6813     return reason;
6814 if (*cptr == 0)                                         /* must be more */
6815     return SCPE_2FARG;
6816 if (sim_dfunit == NULL)                                 /* got a unit? */
6817     return SCPE_NXUN;
6818 cptr = get_glyph (cptr, gbuf, 0);                       /* get list */
6819 if ((flag == EX_D) && (*cptr == 0))                     /* deposit needs more */
6820 
6821     return SCPE_2FARG;
6822 ofile = sim_ofile? sim_ofile: stdout;                   /* no ofile? use stdout */
6823 
6824 for (gptr = gbuf, reason = SCPE_OK;
6825     (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6826     tdptr = sim_dfdev;                                  /* working dptr */
6827     if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6828         tptr = gptr + strlen ("STATE");
6829         if (*tptr && (*tptr++ != ','))
6830             return SCPE_ARG;
6831         if ((lowr = sim_dfdev->registers) == NULL)
6832             return SCPE_NXREG;
6833         for (highr = lowr; highr->name != NULL; highr++) ;
6834         sim_switches = sim_switches | SIM_SW_HIDE;
6835         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6836             lowr, --highr, 0, 0);
6837         continue;
6838         }
6839 
6840     /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
6841     if ((lowr = find_reg (gptr, &tptr, tdptr)) ||       /* local reg or */
6842         (!(sim_opt_out & CMD_OPT_DFT) &&                /* no dflt, global? */
6843         (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6844         low = high = 0;
6845         if ((*tptr == '-') || (*tptr == ':')) {
6846             highr = find_reg (tptr + 1, &tptr, tdptr);
6847             if (highr == NULL)
6848                 return SCPE_NXREG;
6849             }
6850         else {
6851             highr = lowr;
6852             if (*tptr == '[') {
6853                 if (lowr->depth <= 1)
6854                     return SCPE_ARG;
6855                 tptr = get_range (NULL, tptr + 1, &low, &high,
6856                     10, lowr->depth - 1, ']');
6857                 if (tptr == NULL)
6858                     return SCPE_ARG;
6859                 }
6860             }
6861         if (*tptr && (*tptr++ != ','))
6862             return SCPE_ARG;
6863         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6864             lowr, highr, (uint32) low, (uint32) high);
6865         continue;
6866         }
6867 
6868     tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6869         (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6870         sim_dfunit->capac - sim_dfdev->aincr), 0);
6871     if (tptr == NULL)
6872         return SCPE_ARG;
6873     if (*tptr && (*tptr++ != ','))
6874         return SCPE_ARG;
6875     reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6876         sim_dfdev, sim_dfunit);
6877     }                                                   /* end for */
6878 if (sim_ofile)                                          /* close output file */
6879     fclose (sim_ofile);
6880 return reason;
6881 }
6882 
6883 /* Loop controllers for examine/deposit
6884 
6885    exdep_reg_loop       examine/deposit range of registers
6886    exdep_addr_loop      examine/deposit range of addresses
6887 */
6888 
6889 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6890     REG *lowr, REG *highr, uint32 lows, uint32 highs)
6891 {
6892 t_stat reason;
6893 uint32 idx, val_start=lows;
6894 t_value val, last_val;
6895 REG *rptr;
6896 
6897 if ((lowr == NULL) || (highr == NULL))
6898     return SCPE_IERR;
6899 if (lowr > highr)
6900     return SCPE_ARG;
6901 for (rptr = lowr; rptr <= highr; rptr++) {
6902     if ((sim_switches & SIM_SW_HIDE) &&
6903         (rptr->flags & REG_HIDDEN))
6904         continue;
6905     val = last_val = 0;
6906     for (idx = lows; idx <= highs; idx++) {
6907         if (idx >= rptr->depth)
6908             return SCPE_SUB;
6909         val = get_rval (rptr, idx);
6910         if (schptr && !test_search (&val, schptr))
6911             continue;
6912         if (flag == EX_E) {
6913             if ((idx > lows) && (val == last_val))
6914                 continue;
6915             if (idx > val_start+1) {
6916                 if (idx-1 == val_start+1) {
6917                     reason = ex_reg (ofile, val, flag, rptr, idx-1);
6918                     if (reason != SCPE_OK)
6919                         return reason;
6920                     if (sim_log && (ofile == stdout))
6921                         ex_reg (sim_log, val, flag, rptr, idx-1);
6922                     }
6923                 else {
6924                     if (val_start+1 != idx-1) {
6925                         (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6926                         if (sim_log && (ofile == stdout))
6927                             (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, idx-1);
6928                         }
6929                     else {
6930                         (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6931                         if (sim_log && (ofile == stdout))
6932                             (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6933                         }
6934                     }
6935                 }
6936             sim_last_val = last_val = val;
6937             val_start = idx;
6938             reason = ex_reg (ofile, val, flag, rptr, idx);
6939             if (reason != SCPE_OK)
6940                 return reason;
6941             if (sim_log && (ofile == stdout))
6942                 ex_reg (sim_log, val, flag, rptr, idx);
6943             }
6944         if (flag != EX_E) {
6945             reason = dep_reg (flag, cptr, rptr, idx);
6946             if (reason != SCPE_OK)
6947                 return reason;
6948             }
6949         }
6950     if ((flag == EX_E) && (val_start != highs)) {
6951         if (highs == val_start+1) {
6952             reason = ex_reg (ofile, val, flag, rptr, highs);
6953             if (reason != SCPE_OK)
6954                 return reason;
6955             if (sim_log && (ofile == stdout))
6956                 ex_reg (sim_log, val, flag, rptr, highs);
6957             }
6958         else {
6959             if (val_start+1 != highs) {
6960                 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6961                 if (sim_log && (ofile == stdout))
6962                     (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\r\n", rptr->name, val_start+1, rptr->name, highs);
6963                 }
6964             else {
6965                 (void)Fprintf (ofile, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6966                 if (sim_log && (ofile == stdout))
6967                     (void)Fprintf (sim_log, "%s[%d]: same as above\r\n", rptr->name, val_start+1);
6968                 }
6969             }
6970         }
6971     }
6972 return SCPE_OK;
6973 }
6974 
6975 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6976     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6977 {
6978 t_addr i, mask;
6979 t_stat reason;
6980 
6981 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6982     return SCPE_UDIS;
6983 mask = (t_addr) width_mask[dptr->awidth];
6984 if ((low > mask) || (high > mask) || (low > high))
6985     return SCPE_ARG;
6986 for (i = low; i <= high; ) {                            /* all paths must incr!! */
6987     reason = get_aval (i, dptr, uptr);                  /* get data */
6988     if (reason != SCPE_OK)                              /* return if error */
6989         return reason;
6990     if (schptr && !test_search (sim_eval, schptr))
6991         i = i + dptr->aincr;                            /* sch fails, incr */
6992     else {                                              /* no sch or success */
6993         if (flag != EX_D) {                             /* ex, ie, or id? */
6994             reason = ex_addr (ofile, flag, i, dptr, uptr);
6995             if (reason > SCPE_OK)
6996                 return reason;
6997             if (sim_log && (ofile == stdout))
6998                 ex_addr (sim_log, flag, i, dptr, uptr);
6999             }
7000         else reason = 1 - dptr->aincr;                  /* no, dflt incr */
7001         if (flag != EX_E) {                             /* ie, id, or d? */
7002             reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
7003             if (reason > SCPE_OK)
7004                 return reason;
7005             }
7006         i = i + (1 - reason);                           /* incr */
7007         }
7008     }
7009 return SCPE_OK;
7010 }
7011 
7012 /* Examine register routine
7013 
7014    Inputs:
7015         ofile   =       output stream
7016         val     =       current register value
7017         flag    =       type of ex/mod command (ex, iex, idep)
7018         rptr    =       pointer to register descriptor
7019         idx     =       index
7020    Outputs:
7021         return  =       error status
7022 */
7023 
7024 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7025 {
7026 int32 rdx;
7027 
7028 if (rptr == NULL)
7029     return SCPE_IERR;
7030 if (rptr->depth > 1)
7031     (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
7032 else
7033     (void)Fprintf (ofile, "%s:\t", rptr->name);
7034 if (!(flag & EX_E))
7035     return SCPE_OK;
7036 GET_RADIX (rdx, rptr->radix);
7037 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
7038     sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
7039 else if (!(rptr->flags & REG_VMFLAGS) ||
7040     (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
7041                  NULL, sim_switches | SIM_SW_REG) > 0)) {
7042         fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7043         if (rptr->fields) {
7044             (void)Fprintf (ofile, "\t");
7045             fprint_fields (ofile, val, val, rptr->fields);
7046             }
7047         }
7048 if (flag & EX_I)
7049     (void)Fprintf (ofile, "\t");
7050 else
7051     (void)Fprintf (ofile, "\r\n");
7052 return SCPE_OK;
7053 }
7054 
7055 /* Get register value
7056 
7057    Inputs:
7058         rptr    =       pointer to register descriptor
7059         idx     =       index
7060    Outputs:
7061         return  =       register value
7062 */
7063 
7064 t_value get_rval (REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7065 {
7066 size_t sz;
7067 t_value val;
7068 uint32 *ptr;
7069 
7070 sz = SZ_R (rptr);
7071 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7072     idx = idx + rptr->qptr;
7073     if (idx >= rptr->depth) idx = idx - rptr->depth;
7074     }
7075 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7076     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7077     if (sz <= sizeof (uint32))
7078         val = *ptr;
7079     else val = *((t_uint64 *) ptr); //-V1032
7080     }
7081 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7082     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7083     if (sz <= sizeof (uint32))
7084         val = *ptr;
7085     else val = *((t_uint64 *) ptr);
7086     }
7087 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7088     (sz == sizeof (uint8)))
7089     val = *(((uint8 *) rptr->loc) + idx);
7090 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7091     (sz == sizeof (uint16)))
7092     val = *(((uint16 *) rptr->loc) + idx);
7093 else if (sz <= sizeof (uint32))
7094      val = *(((uint32 *) rptr->loc) + idx);
7095 else val = *(((t_uint64 *) rptr->loc) + idx);
7096 val = (val >> rptr->offset) & width_mask[rptr->width];
7097 return val;
7098 }
7099 
7100 /* Deposit register routine
7101 
7102    Inputs:
7103         flag    =       type of deposit (normal/interactive)
7104         cptr    =       pointer to input string
7105         rptr    =       pointer to register descriptor
7106         idx     =       index
7107    Outputs:
7108         return  =       error status
7109 */
7110 
7111 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7112 {
7113 t_stat r;
7114 t_value val, mask;
7115 int32 rdx;
7116 CONST char *tptr;
7117 char gbuf[CBUFSIZE];
7118 
7119 if ((cptr == NULL) || (rptr == NULL))
7120     return SCPE_IERR;
7121 if (rptr->flags & REG_RO)
7122     return SCPE_RO;
7123 if (flag & EX_I) {
7124     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7125     if (sim_log)
7126         (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7127     if (cptr == NULL)                                   /* force exit */
7128         return 1;
7129     if (*cptr == 0)                                     /* success */
7130         return SCPE_OK;
7131     }
7132 mask = width_mask[rptr->width];
7133 GET_RADIX (rdx, rptr->radix);
7134 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {    /* address form? */
7135     val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7136     if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7137         return SCPE_ARG;
7138     }
7139 else
7140     if (!(rptr->flags & REG_VMFLAGS) ||                 /* don't use sym? */
7141         (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7142                     &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7143     val = get_uint (cptr, rdx, mask, &r);
7144     if (r != SCPE_OK)
7145         return SCPE_ARG;
7146     }
7147 if ((rptr->flags & REG_NZ) && (val == 0))
7148     return SCPE_ARG;
7149 put_rval (rptr, idx, val);
7150 return SCPE_OK;
7151 }
7152 
7153 /* Put register value
7154 
7155    Inputs:
7156         rptr    =       pointer to register descriptor
7157         idx     =       index
7158         val     =       new value
7159         mask    =       mask
7160    Outputs:
7161         none
7162 */
7163 
7164 void put_rval (REG *rptr, uint32 idx, t_value val)
     /* [previous][next][first][last][top][bottom][index][help] */
7165 {
7166 size_t sz;
7167 t_value mask;
7168 uint32 *ptr;
7169 
7170 #define PUT_RVAL(sz,rp,id,v,m)            \
7171     *(((sz *) rp->loc) + id) =            \
7172         (sz)((*(((sz *) rp->loc) + id) &  \
7173             ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7174 
7175 if (rptr == sim_PC)
7176     sim_brk_npc (0);
7177 sz = SZ_R (rptr);
7178 mask = width_mask[rptr->width];
7179 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7180     idx = idx + rptr->qptr;
7181     if (idx >= rptr->depth)
7182         idx = idx - rptr->depth;
7183     }
7184 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7185     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7186     if (sz <= sizeof (uint32))
7187         *ptr = (*ptr &
7188         ~(((uint32) mask) << rptr->offset)) |
7189         (((uint32) val) << rptr->offset);
7190     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr) //-V1032
7191         & ~(mask << rptr->offset)) | (val << rptr->offset);
7192     }
7193 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7194     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7195     if (sz <= sizeof (uint32))
7196         *((uint32 *) ptr) = (*((uint32 *) ptr) &
7197         ~(((uint32) mask) << rptr->offset)) |
7198         (((uint32) val) << rptr->offset);
7199     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7200         & ~(mask << rptr->offset)) | (val << rptr->offset);
7201     }
7202 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7203     (sz == sizeof (uint8)))
7204     PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7205 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7206     (sz == sizeof (uint16)))
7207     PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7208 else if (sz <= sizeof (uint32))
7209     PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7210 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7211 return;
7212 }
7213 
7214 /* Examine address routine
7215 
7216    Inputs: (sim_eval is an implicit argument)
7217         ofile   =       output stream
7218         flag    =       type of ex/mod command (ex, iex, idep)
7219         addr    =       address to examine
7220         dptr    =       pointer to device
7221         uptr    =       pointer to unit
7222    Outputs:
7223         return  =       if > 0, error status
7224                         if <= 0,-number of extra addr units retired
7225 */
7226 
7227 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7228 {
7229 t_stat reason;
7230 int32 rdx;
7231 
7232 if (sim_vm_fprint_addr)
7233     sim_vm_fprint_addr (ofile, dptr, addr);
7234 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7235 (void)Fprintf (ofile, ":\t");
7236 if (!(flag & EX_E))
7237     return (1 - dptr->aincr);
7238 
7239 GET_RADIX (rdx, dptr->dradix);
7240 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7241     fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7242     reason = 1 - dptr->aincr;
7243     }
7244 if (flag & EX_I)
7245     (void)Fprintf (ofile, "\t");
7246 else
7247     (void)Fprintf (ofile, "\r\n");
7248 return reason;
7249 }
7250 
7251 /* Get address routine
7252 
7253    Inputs:
7254         flag    =       type of ex/mod command (ex, iex, idep)
7255         addr    =       address to examine
7256         dptr    =       pointer to device
7257         uptr    =       pointer to unit
7258    Outputs: (sim_eval is an implicit output)
7259         return  =       error status
7260 */
7261 
7262 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7263 {
7264 int32 i;
7265 t_value mask;
7266 t_addr j, loc;
7267 size_t sz;
7268 t_stat reason = SCPE_OK;
7269 
7270 if ((dptr == NULL) || (uptr == NULL))
7271     return SCPE_IERR;
7272 mask = width_mask[dptr->dwidth];
7273 for (i = 0; i < sim_emax; i++)
7274     sim_eval[i] = 0;
7275 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7276     if (dptr->examine != NULL) {
7277         reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7278         if (reason != SCPE_OK)
7279             break;
7280         }
7281     else {
7282         if (!(uptr->flags & UNIT_ATT))
7283             return SCPE_UNATT;
7284         if (uptr->dynflags & UNIT_NO_FIO)
7285             return SCPE_NOFNC;
7286         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7287             reason = SCPE_NXM;
7288             break;
7289             }
7290         sz = SZ_D (dptr);
7291         loc = j / dptr->aincr;
7292         if (uptr->flags & UNIT_BUF) {
7293             SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7294             }
7295         else {
7296             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7297             sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7298             if ((feof (uptr->fileref)) &&
7299                !(uptr->flags & UNIT_FIX)) {
7300                 reason = SCPE_EOF;
7301                 break;
7302                 }
7303             else if (ferror (uptr->fileref)) {
7304                 clearerr (uptr->fileref);
7305                 reason = SCPE_IOERR;
7306                 break;
7307                 }
7308             }
7309         }
7310     sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7311     }
7312 if ((reason != SCPE_OK) && (i == 0))
7313     return reason;
7314 return SCPE_OK;
7315 }
7316 
7317 /* Deposit address routine
7318 
7319    Inputs:
7320         flag    =       type of deposit (normal/interactive)
7321         cptr    =       pointer to input string
7322         addr    =       address to examine
7323         dptr    =       pointer to device
7324         uptr    =       pointer to unit
7325         dfltinc =       value to return on cr input
7326    Outputs:
7327         return  =       if > 0, error status
7328                         if <= 0, -number of extra address units retired
7329 */
7330 
7331 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
7332     UNIT *uptr, int32 dfltinc)
7333 {
7334 int32 i, count, rdx;
7335 t_addr j, loc;
7336 t_stat r, reason;
7337 t_value mask;
7338 size_t sz;
7339 char gbuf[CBUFSIZE];
7340 
7341 if (dptr == NULL)
7342     return SCPE_IERR;
7343 if (flag & EX_I) {
7344     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7345     if (sim_log)
7346         (void)fprintf (sim_log, "%s\r\n", cptr? cptr: "");
7347     if (cptr == NULL)                                   /* force exit */
7348         return 1;
7349     if (*cptr == 0)                                     /* success */
7350         return dfltinc;
7351     }
7352 if (uptr->flags & UNIT_RO)                              /* read only? */
7353     return SCPE_RO;
7354 mask = width_mask[dptr->dwidth];
7355 
7356 GET_RADIX (rdx, dptr->dradix);
7357 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7358     sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7359     if (reason != SCPE_OK)
7360         return reason;
7361     reason = dfltinc;
7362     }
7363 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7364 
7365 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7366     sim_eval[i] = sim_eval[i] & mask;
7367     if (dptr->deposit != NULL) {
7368         r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7369         if (r != SCPE_OK)
7370             return r;
7371         }
7372     else {
7373         if (!(uptr->flags & UNIT_ATT))
7374             return SCPE_UNATT;
7375         if (uptr->dynflags & UNIT_NO_FIO)
7376             return SCPE_NOFNC;
7377         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7378             return SCPE_NXM;
7379         sz = SZ_D (dptr);
7380         loc = j / dptr->aincr;
7381         if (uptr->flags & UNIT_BUF) {
7382             SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7383             if (loc >= uptr->hwmark)
7384                 uptr->hwmark = (uint32) loc + 1;
7385             }
7386         else {
7387             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7388             sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7389             if (ferror (uptr->fileref)) {
7390                 clearerr (uptr->fileref);
7391                 return SCPE_IOERR;
7392                 }
7393             }
7394         }
7395     }
7396 return reason;
7397 }
7398 
7399 /* Evaluate command */
7400 
7401 t_stat eval_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7402 {
7403 if (!sim_dflt_dev)
7404   return SCPE_ARG;
7405 DEVICE *dptr = sim_dflt_dev;
7406 int32 i, rdx, a, lim;
7407 t_stat r;
7408 
7409 GET_SWITCHES (cptr);
7410 GET_RADIX (rdx, dptr->dradix);
7411 for (i = 0; i < sim_emax; i++)
7412 sim_eval[i] = 0;
7413 if (*cptr == 0)
7414     return SCPE_2FARG;
7415 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7416     sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7417     if (r != SCPE_OK)
7418         return r;
7419     }
7420 lim = 1 - r;
7421 for (i = a = 0; a < lim; ) {
7422     sim_printf ("%d:\t", a);
7423     if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7424         r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7425     if (sim_log) {
7426         if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7427             r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7428         }
7429     sim_printf ("\r\n");
7430     if (r < 0)
7431         a = a + 1 - r;
7432     else a = a + dptr->aincr;
7433     i = a / dptr->aincr;
7434     }
7435 return SCPE_OK;
7436 }
7437 
7438 /* String processing routines
7439 
7440    read_line            read line
7441 
7442    Inputs:
7443         cptr    =       pointer to buffer
7444         size    =       maximum size
7445         stream  =       pointer to input stream
7446    Outputs:
7447         optr    =       pointer to first non-blank character
7448                         NULL if EOF
7449 */
7450 
7451 char *read_line (char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7452 {
7453 return read_line_p (NULL, cptr, size, stream);
7454 }
7455 
7456 /* read_line_p          read line with prompt
7457 
7458    Inputs:
7459         prompt  =       pointer to prompt string
7460         cptr    =       pointer to buffer
7461         size    =       maximum size
7462         stream  =       pointer to input stream
7463    Outputs:
7464         optr    =       pointer to first non-blank character
7465                         NULL if EOF
7466 */
7467 
7468 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7469 {
7470 char *tptr;
7471 
7472 if (prompt) {                                           /* interactive? */
7473 #if defined(HAVE_LINEHISTORY)
7474         char *tmpc = linenoise (prompt);                /* get cmd line */
7475         if (tmpc == NULL)                               /* bad result? */
7476             cptr = NULL;
7477         else {
7478             strncpy (cptr, tmpc, size-1);               /* copy result */
7479             linenoiseHistoryAdd (tmpc);                 /* add to history */
7480             FREE (tmpc);                                /* free temp */
7481             }
7482         }
7483 #else
7484         (void)fflush (stdout);                          /* flush output */
7485         (void)printf ("%s", prompt);                    /* display prompt */
7486         (void)fflush (stdout);                          /* flush output */
7487         cptr = fgets (cptr, size, stream);              /* get cmd line */
7488         }
7489 #endif /* if defined(HAVE_LINEHISTORY) */
7490 else cptr = fgets (cptr, size, stream);                 /* get cmd line */
7491 
7492 if (cptr == NULL) {
7493     clearerr (stream);                                  /* clear error */
7494     return NULL;                                        /* ignore EOF */
7495     }
7496 for (tptr = cptr; tptr < (cptr + size); tptr++) {       /* remove cr or nl */
7497     if ((*tptr == '\n') || (*tptr == '\r') ||
7498         (tptr == (cptr + size - 1))) {                  /* str max length? */
7499         *tptr = 0;                                      /* terminate */
7500         break;
7501         }
7502     }
7503 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))              /* Skip/ignore UTF8_BOM */
7504     memmove (cptr, cptr + 3, strlen (cptr + 3));
7505 while (sim_isspace (*cptr))                             /* trim leading spc */
7506     cptr++;
7507 if ((*cptr == ';') || (*cptr == '#')) {                 /* ignore comment */
7508     if (sim_do_echo)                                    /* echo comments if -v */
7509         sim_printf("%s> %s\r\n", do_position(), cptr);
7510     *cptr = 0;
7511     }
7512 
7513 return cptr;
7514 }
7515 
7516 /* get_glyph            get next glyph (force upper case)
7517    get_glyph_nc         get next glyph (no conversion)
7518    get_glyph_quoted     get next glyph (potentially enclosed in quotes, no conversion)
7519    get_glyph_cmd        get command glyph (force upper case, extract leading !)
7520    get_glyph_gen        get next glyph (general case)
7521 
7522    Inputs:
7523         iptr        =   pointer to input string
7524         optr        =   pointer to output string
7525         mchar       =   optional end of glyph character
7526         uc          =   TRUE for convert to upper case (_gen only)
7527         quote       =   TRUE to allow quote enclosing values (_gen only)
7528         escape_char =   optional escape character within quoted strings (_gen only)
7529 
7530    Outputs
7531         result      =   pointer to next character in input string
7532 */
7533 
7534 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] */
7535 {
7536 t_bool quoting = FALSE;
7537 t_bool escaping = FALSE;
7538 char quote_char = 0;
7539 
7540 while ((*iptr != 0) &&
7541        ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7542     if (quote) {
7543         if (quoting) {
7544             if (!escaping) {
7545                 if (*iptr == escape_char)
7546                     escaping = TRUE;
7547                 else
7548                     if (*iptr == quote_char)
7549                         quoting = FALSE;
7550                 }
7551             else
7552                 escaping = FALSE;
7553             }
7554         else {
7555             if ((*iptr == '"') || (*iptr == '\'')) {
7556                 quoting = TRUE;
7557                 quote_char = *iptr;
7558                 }
7559             }
7560         }
7561     if (sim_islower (*iptr) && uc)
7562         *optr = (char)toupper (*iptr);
7563     else *optr = *iptr;
7564     iptr++; optr++;
7565     }
7566 if (mchar && (*iptr == mchar))              /* skip input terminator */
7567     iptr++;
7568 *optr = 0;                                  /* terminate result string */
7569 while (sim_isspace (*iptr))                 /* absorb additional input spaces */
7570     iptr++;
7571 return iptr;
7572 }
7573 
7574 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7575 {
7576 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7577 }
7578 
7579 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7580 {
7581 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7582 }
7583 
7584 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7585 {
7586 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7587 }
7588 
7589 CONST char *get_glyph_cmd (const char *iptr, char *optr)
     /* [previous][next][first][last][top][bottom][index][help] */
7590 {
7591 /* Tolerate "!subprocess" vs. requiring "! subprocess" */
7592 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7593     strcpy (optr, "!");                     /* return ! as command glyph */
7594     return (CONST char *)(iptr + 1);        /* and skip over the leading ! */
7595     }
7596 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7597 }
7598 
7599 /* Trim trailing spaces from a string
7600 
7601     Inputs:
7602         cptr    =       pointer to string
7603     Outputs:
7604         cptr    =       pointer to string
7605 */
7606 
7607 char *sim_trim_endspc (char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7608 {
7609 char *tptr;
7610 
7611 tptr = cptr + strlen (cptr);
7612 while ((--tptr >= cptr) && sim_isspace (*tptr))
7613     *tptr = 0;
7614 return cptr;
7615 }
7616 
7617 int sim_isspace (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7618 {
7619 return (c & 0x80) ? 0 : isspace (c);
7620 }
7621 
7622 int sim_islower (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7623 {
7624 return (c & 0x80) ? 0 : islower (c);
7625 }
7626 
7627 int sim_isalpha (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7628 {
7629 return (c & 0x80) ? 0 : isalpha (c);
7630 }
7631 
7632 int sim_isprint (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7633 {
7634 return (c & 0x80) ? 0 : isprint (c);
7635 }
7636 
7637 int sim_isdigit (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7638 {
7639 return (c & 0x80) ? 0 : isdigit (c);
7640 }
7641 
7642 int sim_isgraph (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7643 {
7644 return (c & 0x80) ? 0 : isgraph (c);
7645 }
7646 
7647 int sim_isalnum (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7648 {
7649 return (c & 0x80) ? 0 : isalnum (c);
7650 }
7651 
7652 /* get_uint             unsigned number
7653 
7654    Inputs:
7655         cptr    =       pointer to input string
7656         radix   =       input radix
7657         max     =       maximum acceptable value
7658         *status =       pointer to error status
7659    Outputs:
7660         val     =       value
7661 */
7662 
7663 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
     /* [previous][next][first][last][top][bottom][index][help] */
7664 {
7665 t_value val;
7666 CONST char *tptr;
7667 
7668 *status = SCPE_OK;
7669 val = strtotv ((CONST char *)cptr, &tptr, radix);
7670 if ((cptr == tptr) || (val > max))
7671     *status = SCPE_ARG;
7672 else {
7673     while (sim_isspace (*tptr)) tptr++;
7674     if (*tptr != 0)
7675         *status = SCPE_ARG;
7676     }
7677 return val;
7678 }
7679 
7680 /* get_range            range specification
7681 
7682    Inputs:
7683         dptr    =       pointer to device (NULL if none)
7684         cptr    =       pointer to input string
7685         *lo     =       pointer to low result
7686         *hi     =       pointer to high result
7687         aradix  =       radix
7688         max     =       default high value
7689         term    =       terminating character, 0 if none
7690    Outputs:
7691         tptr    =       input pointer after processing
7692                         NULL if error
7693 */
7694 
7695 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
     /* [previous][next][first][last][top][bottom][index][help] */
7696     uint32 rdx, t_addr max, char term)
7697 {
7698 CONST char *tptr;
7699 
7700 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {    /* ALL? */
7701     tptr = cptr + strlen ("ALL");
7702     *lo = 0;
7703     *hi = max;
7704     }
7705 else {
7706     if ((strncmp (cptr, ".", strlen (".")) == 0) &&             /* .? */
7707         ((cptr[1] == '\0') ||
7708          (cptr[1] == '-')  ||
7709          (cptr[1] == ':')  ||
7710          (cptr[1] == '/'))) {
7711         tptr = cptr + strlen (".");
7712         *lo = *hi = sim_last_addr;
7713         }
7714     else {
7715         if (strncmp (cptr, "$", strlen ("$")) == 0) {           /* $? */
7716             tptr = cptr + strlen ("$");
7717             *hi = *lo = (t_addr)sim_last_val;
7718             }
7719         else {
7720             if (dptr && sim_vm_parse_addr)                      /* get low */
7721                 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7722             else
7723                 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7724             if (cptr == tptr)                                   /* error? */
7725                     return NULL;
7726             }
7727         }
7728     if ((*tptr == '-') || (*tptr == ':')) {             /* range? */
7729         cptr = tptr + 1;
7730         if (dptr && sim_vm_parse_addr)                  /* get high */
7731             *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7732         else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7733         if (cptr == tptr)
7734             return NULL;
7735         if (*lo > *hi)
7736             return NULL;
7737         }
7738     else if (*tptr == '/') {                            /* relative? */
7739         cptr = tptr + 1;
7740         *hi = (t_addr) strtotv (cptr, &tptr, rdx);      /* get high */
7741         if ((cptr == tptr) || (*hi == 0))
7742             return NULL;
7743         *hi = *lo + *hi - 1;
7744         }
7745     else *hi = *lo;
7746     }
7747 sim_last_addr = *hi;
7748 if (term && (*tptr++ != term))
7749     return NULL;
7750 return tptr;
7751 }
7752 
7753 /* sim_decode_quoted_string
7754 
7755    Inputs:
7756         iptr        =   pointer to input string
7757         optr        =   pointer to output buffer
7758                         the output buffer must be allocated by the caller
7759                         and to avoid overrunat it must be at least as big
7760                         as the input string.
7761 
7762    Outputs
7763         result      =   status of decode SCPE_OK when good, SCPE_ARG otherwise
7764         osize       =   size of the data in the optr buffer
7765 
7766    The input string must be quoted.  Quotes may be either single or
7767    double but the opening anc closing quote characters must match.
7768    Within quotes C style character escapes are allowed.
7769 */
7770 
7771 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
     /* [previous][next][first][last][top][bottom][index][help] */
7772 {
7773 char quote_char;
7774 uint8 *ostart = optr;
7775 
7776 *osize = 0;
7777 if ((strlen(iptr) == 1) ||
7778     (iptr[0] != iptr[strlen(iptr)-1]) ||
7779     ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7780     return SCPE_ARG;            /* String must be quote delimited */
7781 quote_char = *iptr++;           /* Save quote character */
7782 while (iptr[1]) {               /* Skip trailing quote */
7783     if (*iptr != '\\') {
7784         if (*iptr == quote_char)
7785             return SCPE_ARG;    /* Embedded quotes must be escaped */
7786         *(optr++) = (uint8)(*(iptr++));
7787         continue;
7788         }
7789     ++iptr; /* Skip backslash */
7790     switch (*iptr) {
7791         case 'r':   /* ASCII Carriage Return character (Decimal value 13) */
7792             *(optr++) = 13; ++iptr;
7793             break;
7794         case 'n':   /* ASCII Linefeed character (Decimal value 10) */
7795             *(optr++) = 10; ++iptr;
7796             break;
7797         case 'f':   /* ASCII Formfeed character (Decimal value 12) */
7798             *(optr++) = 12; ++iptr;
7799             break;
7800         case 't':   /* ASCII Horizontal Tab character (Decimal value 9) */
7801             *(optr++) = 9; ++iptr;
7802             break;
7803         case 'v':   /* ASCII Vertical Tab character (Decimal value 11) */
7804             *(optr++) = 11; ++iptr;
7805             break;
7806         case 'b':   /* ASCII Backspace character (Decimal value 8) */
7807             *(optr++) = 8; ++iptr;
7808             break;
7809         case '\\':   /* ASCII Backslash character (Decimal value 92) */
7810             *(optr++) = 92; ++iptr;
7811             break;
7812         case 'e':   /* ASCII Escape character (Decimal value 27) */
7813             *(optr++) = 27; ++iptr;
7814             break;
7815         case '\'':   /* ASCII Single Quote character (Decimal value 39) */
7816             *(optr++) = 39; ++iptr;
7817             break;
7818         case '"':   /* ASCII Double Quote character (Decimal value 34) */
7819             *(optr++) = 34; ++iptr;
7820             break;
7821         case '?':   /* ASCII Question Mark character (Decimal value 63) */
7822             *(optr++) = 63; ++iptr;
7823             break;
7824         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7825             *optr = *(iptr++) - '0';
7826             if ((*iptr >= '0') && (*iptr <= '7'))
7827                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7828             if ((*iptr >= '0') && (*iptr <= '7'))
7829                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7830             ++optr;
7831             break;
7832         case 'x':
7833             if (1) {
7834                 static const char *hex_digits = "0123456789ABCDEF";
7835                 const char *c;
7836 
7837                 ++iptr;
7838                 *optr = 0;
7839                 c = strchr (hex_digits, toupper(*iptr));
7840                 if (c) {
7841                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7842                     ++iptr;
7843                     }
7844                 c = strchr (hex_digits, toupper(*iptr));
7845                 if (c) {
7846                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7847                     ++iptr;
7848                     }
7849                 ++optr;
7850                 }
7851             break;
7852         default:
7853             return SCPE_ARG;    /* Invalid escape */
7854         }
7855     }
7856 *optr = '\0';
7857 *osize = (uint32)(optr-ostart);
7858 return SCPE_OK;
7859 }
7860 
7861 /* sim_encode_quoted_string
7862 
7863    Inputs:
7864         iptr        =   pointer to input buffer
7865         size        =   number of bytes of data in the buffer
7866 
7867    Outputs
7868         optr        =   pointer to output buffer
7869                         the output buffer must be freed by the caller
7870 
7871    The input data will be encoded into a simply printable form.
7872 */
7873 
7874 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7875 {
7876 size_t i;
7877 t_bool double_quote_found = FALSE;
7878 t_bool single_quote_found = FALSE;
7879 char quote = '"';
7880 char *tptr, *optr;
7881 
7882 optr = (char *)malloc (4*size + 3);
7883 if (optr == NULL)
7884     return NULL;
7885 tptr = optr;
7886 for (i=0; i<size; i++)
7887     switch ((char)iptr[i]) {
7888         case '"':
7889             double_quote_found = TRUE;
7890             break;
7891         case '\'':
7892             single_quote_found = TRUE;
7893             break;
7894         }
7895 if (double_quote_found && (!single_quote_found))
7896     quote = '\'';
7897 *tptr++ = quote;
7898 while (size--) {
7899     switch (*iptr) {
7900         case '\r':
7901             *tptr++ = '\\'; *tptr++ = 'r'; break;
7902         case '\n':
7903             *tptr++ = '\\'; *tptr++ = 'n'; break;
7904         case '\f':
7905             *tptr++ = '\\'; *tptr++ = 'f'; break;
7906         case '\t':
7907             *tptr++ = '\\'; *tptr++ = 't'; break;
7908         case '\v':
7909             *tptr++ = '\\'; *tptr++ = 'v'; break;
7910         case '\b':
7911             *tptr++ = '\\'; *tptr++ = 'b'; break;
7912         case '\\':
7913             *tptr++ = '\\'; *tptr++ = '\\'; break;
7914         case '"':
7915         case '\'':
7916             if (quote == *iptr)
7917                 *tptr++ = '\\';
7918         /*FALLTHRU*/ /* fall through */ /* fallthrough */
7919         default:
7920             if (sim_isprint (*iptr))
7921                 *tptr++ = *iptr;
7922             else {
7923                 (void)sprintf (tptr, "\\%03o", *iptr);
7924                 tptr += 4;
7925                 }
7926             break;
7927         }
7928     ++iptr;
7929     }
7930 *tptr++ = quote;
7931 *tptr++ = '\0';
7932 return optr;
7933 }
7934 
7935 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7936 {
7937 char *string;
7938 
7939 string = sim_encode_quoted_string (buf, size);
7940 (void)fprintf (st, "%s", string);
7941 FREE (string);
7942 }
7943 
7944 /* Find_device          find device matching input string
7945 
7946    Inputs:
7947         cptr    =       pointer to input string
7948    Outputs:
7949         result  =       pointer to device
7950 */
7951 
7952 DEVICE *find_dev (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7953 {
7954 int32 i;
7955 DEVICE *dptr;
7956 
7957 if (cptr == NULL)
7958     return NULL;
7959 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7960     if ((strcmp (cptr, dptr->name) == 0) ||
7961         (dptr->lname &&
7962         (strcmp (cptr, dptr->lname) == 0)))
7963         return dptr;
7964     }
7965 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7966     if ((strcmp (cptr, dptr->name) == 0) ||
7967         (dptr->lname &&
7968         (strcmp (cptr, dptr->lname) == 0)))
7969         return dptr;
7970     }
7971 return NULL;
7972 }
7973 
7974 /* Find_unit            find unit matching input string
7975 
7976    Inputs:
7977         cptr    =       pointer to input string
7978         uptr    =       pointer to unit pointer
7979    Outputs:
7980         result  =       pointer to device (null if no dev)
7981         *iptr   =       pointer to unit (null if nx unit)
7982 
7983 */
7984 
7985 DEVICE *find_unit (const char *cptr, UNIT **uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7986 {
7987 uint32 i, u;
7988 const char *nptr;
7989 const char *tptr;
7990 t_stat r;
7991 DEVICE *dptr;
7992 
7993 if (uptr == NULL)                                       /* arg error? */
7994     return NULL;
7995 *uptr = NULL;
7996 if ((dptr = find_dev (cptr))) {                         /* exact match? */
7997     if (qdisable (dptr))                                /* disabled? */
7998         return NULL;
7999     *uptr = dptr->units;                                /* unit 0 */
8000     return dptr;
8001     }
8002 
8003 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {     /* base + unit#? */
8004     if (qdisable (dptr))                                /* device disabled? */
8005         continue;
8006     if (dptr->numunits && /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/ /* any units? */
8007         (((nptr = dptr->name) &&
8008           (strncmp (cptr, nptr, strlen (nptr)) == 0)) || /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8009          ((nptr = dptr->lname) &&
8010           (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
8011         tptr = cptr + strlen (nptr);
8012         if (sim_isdigit (*tptr)) {
8013             if (qdisable (dptr))                        /* disabled? */
8014                 return NULL;
8015             u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
8016             if (r != SCPE_OK)                           /* error? */
8017                 *uptr = NULL;
8018             else
8019                 *uptr = dptr->units + u;
8020             return dptr;
8021             }
8022         }
8023     for (u = 0; u < dptr->numunits; u++) {
8024         if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
8025             *uptr = &dptr->units[u];
8026             return dptr;
8027             }
8028         }
8029     }
8030 return NULL;
8031 }
8032 
8033 /* sim_register_internal_device   Add device to internal device list
8034 
8035    Inputs:
8036         dptr    =       pointer to device
8037 */
8038 
8039 t_stat sim_register_internal_device (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8040 {
8041 uint32 i;
8042 
8043 for (i = 0; (sim_devices[i] != NULL); i++)
8044     if (sim_devices[i] == dptr)
8045         return SCPE_OK;
8046 for (i = 0; i < sim_internal_device_count; i++)
8047     if (sim_internal_devices[i] == dptr)
8048         return SCPE_OK;
8049 ++sim_internal_device_count;
8050 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8051 if (!sim_internal_devices)
8052   {
8053     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8054                    __func__, __FILE__, __LINE__);
8055 #if defined(USE_BACKTRACE)
8056 # if defined(SIGUSR2)
8057     (void)raise(SIGUSR2);
8058     /*NOTREACHED*/ /* unreachable */
8059 # endif /* if defined(SIGUSR2) */
8060 #endif /* if defined(USE_BACKTRACE) */
8061     abort();
8062   }
8063 sim_internal_devices[sim_internal_device_count-1] = dptr;
8064 sim_internal_devices[sim_internal_device_count] = NULL;
8065 return SCPE_OK;
8066 }
8067 
8068 /* Find_dev_from_unit   find device for unit
8069 
8070    Inputs:
8071         uptr    =       pointer to unit
8072    Outputs:
8073         result  =       pointer to device
8074 */
8075 
8076 DEVICE *find_dev_from_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8077 {
8078 DEVICE *dptr;
8079 uint32 i, j;
8080 
8081 if (uptr == NULL)
8082     return NULL;
8083 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8084     for (j = 0; j < dptr->numunits; j++) {
8085         if (uptr == (dptr->units + j))
8086             return dptr;
8087         }
8088     }
8089 for (i = 0; i<sim_internal_device_count; i++) {
8090     dptr = sim_internal_devices[i];
8091     for (j = 0; j < dptr->numunits; j++) {
8092         if (uptr == (dptr->units + j))
8093             return dptr;
8094         }
8095     }
8096 return NULL;
8097 }
8098 
8099 /* Test for disabled device */
8100 
8101 t_bool qdisable (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8102 {
8103 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8104 }
8105 
8106 /* find_reg_glob        find globally unique register
8107 
8108    Inputs:
8109         cptr    =       pointer to input string
8110         optr    =       pointer to output pointer (can be null)
8111         gdptr   =       pointer to global device
8112    Outputs:
8113         result  =       pointer to register, NULL if error
8114         *optr   =       pointer to next character in input string
8115         *gdptr  =       pointer to device where found
8116 */
8117 
8118 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8119 {
8120 int32 i;
8121 DEVICE *dptr;
8122 REG *rptr, *srptr = NULL;
8123 
8124 *gdptr = NULL;
8125 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {        /* all dev */
8126     if (dptr->flags & DEV_DIS)                          /* skip disabled */
8127         continue;
8128     if ((rptr = find_reg (cptr, optr, dptr))) {         /* found? */
8129         if (srptr)                                      /* ambig? err */
8130             return NULL;
8131         srptr = rptr;                                   /* save reg */
8132         *gdptr = dptr;                                  /* save unit */
8133         }
8134     }
8135 return srptr;
8136 }
8137 
8138 /* find_reg             find register matching input string
8139 
8140    Inputs:
8141         cptr    =       pointer to input string
8142         optr    =       pointer to output pointer (can be null)
8143         dptr    =       pointer to device
8144    Outputs:
8145         result  =       pointer to register, NULL if error
8146         *optr   =       pointer to next character in input string
8147 */
8148 
8149 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8150 {
8151 CONST char *tptr;
8152 REG *rptr;
8153 size_t slnt;
8154 
8155 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8156     return NULL;
8157 tptr = cptr;
8158 do {
8159     tptr++;
8160     } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8161 slnt = tptr - cptr;
8162 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8163     if ((slnt == strlen (rptr->name)) &&
8164         (strncmp (cptr, rptr->name, slnt) == 0)) {
8165         if (optr != NULL)
8166             *optr = tptr;
8167         return rptr;
8168         }
8169     }
8170 return NULL;
8171 }
8172 
8173 /* get_switches         get switches from input string
8174 
8175    Inputs:
8176         cptr    =       pointer to input string
8177    Outputs:
8178         sw      =       switch bit mask
8179                         0 if no switches, -1 if error
8180 */
8181 
8182 int32 get_switches (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8183 {
8184 int32 sw;
8185 
8186 if (*cptr != '-')
8187     return 0;
8188 sw = 0;
8189 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8190     if (sim_isalpha (*cptr) == 0)
8191         return -1;
8192     sw = sw | SWMASK (toupper (*cptr));
8193     }
8194 return sw;
8195 }
8196 
8197 /* get_sim_sw           accumulate sim_switches
8198 
8199    Inputs:
8200         cptr    =       pointer to input string
8201    Outputs:
8202         ptr     =       pointer to first non-string glyph
8203                         NULL if error
8204 */
8205 
8206 CONST char *get_sim_sw (CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8207 {
8208 int32 lsw;
8209 char gbuf[CBUFSIZE];
8210 
8211 while (*cptr == '-') {                                  /* while switches */
8212     cptr = get_glyph (cptr, gbuf, 0);                   /* get switch glyph */
8213     lsw = get_switches (gbuf);                          /* parse */
8214     if (lsw <= 0)                                       /* invalid? */
8215         return NULL;
8216     sim_switches = sim_switches | lsw;                  /* accumulate */
8217     }
8218 return cptr;
8219 }
8220 
8221 /* get_sim_opt          get simulator command options
8222 
8223    Inputs:
8224         opt     =       command options
8225         cptr    =       pointer to input string
8226    Outputs:
8227         ptr     =       pointer to next glyph, NULL if error
8228         *stat   =       error status
8229 */
8230 
8231 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
     /* [previous][next][first][last][top][bottom][index][help] */
8232 {
8233 int32 t;
8234 char gbuf[CBUFSIZE];
8235 CONST char *svptr;
8236 DEVICE *tdptr;
8237 UNIT *tuptr;
8238 
8239 sim_switches = 0;                                       /* no switches */
8240 sim_ofile = NULL;                                       /* no output file */
8241 sim_schrptr = NULL;                                     /* no search */
8242 sim_schaptr = NULL;                                     /* no search */
8243 sim_stabr.logic = sim_staba.logic = SCH_OR;             /* default search params */
8244 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8245 sim_stabr.count = 1;
8246 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8247 if (!sim_stabr.mask)
8248   {
8249     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8250                    __func__, __FILE__, __LINE__);
8251 #if defined(USE_BACKTRACE)
8252 # if defined(SIGUSR2)
8253     (void)raise(SIGUSR2);
8254     /*NOTREACHED*/ /* unreachable */
8255 # endif /* if defined(SIGUSR2) */
8256 #endif /* if defined(USE_BACKTRACE) */
8257     abort();
8258   }
8259 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8260 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8261 if (!sim_stabr.comp)
8262   {
8263     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8264                    __func__, __FILE__, __LINE__);
8265 #if defined(USE_BACKTRACE)
8266 # if defined(SIGUSR2)
8267     (void)raise(SIGUSR2);
8268     /*NOTREACHED*/ /* unreachable */
8269 # endif /* if defined(SIGUSR2) */
8270 #endif /* if defined(USE_BACKTRACE) */
8271     abort();
8272   }
8273 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8274 sim_staba.count = sim_emax;
8275 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8276 if (!sim_staba.mask)
8277   {
8278     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8279                    __func__, __FILE__, __LINE__);
8280 #if defined(USE_BACKTRACE)
8281 # if defined(SIGUSR2)
8282     (void)raise(SIGUSR2);
8283     /*NOTREACHED*/ /* unreachable */
8284 # endif /* if defined(SIGUSR2) */
8285 #endif /* if defined(USE_BACKTRACE) */
8286     abort();
8287   }
8288 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8289 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8290 if (!sim_staba.comp)
8291   {
8292     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8293                    __func__, __FILE__, __LINE__);
8294 #if defined(USE_BACKTRACE)
8295 # if defined(SIGUSR2)
8296     (void)raise(SIGUSR2);
8297     /*NOTREACHED*/ /* unreachable */
8298 # endif /* if defined(SIGUSR2) */
8299 #endif /* if defined(USE_BACKTRACE) */
8300     abort();
8301   }
8302 (void)memset (sim_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8303 if (! sim_dflt_dev)
8304   return NULL;
8305 sim_dfdev = sim_dflt_dev;
8306 sim_dfunit = sim_dfdev->units;
8307 sim_opt_out = 0;                                        /* no options yet */
8308 *st = SCPE_OK;
8309 while (*cptr) {                                         /* loop through modifiers */
8310     svptr = cptr;                                       /* save current position */
8311     if ((opt & CMD_OPT_OF) && (*cptr == '@')) {         /* output file spec? */
8312         if (sim_ofile) {                                /* already got one? */
8313             fclose (sim_ofile);                         /* one per customer */
8314             *st = SCPE_ARG;
8315             return NULL;
8316             }
8317         cptr = get_glyph (cptr + 1, gbuf, 0);
8318         sim_ofile = sim_fopen (gbuf, "a");              /* open for append */
8319         if (sim_ofile == NULL) {                        /* open failed? */
8320             *st = SCPE_OPENERR;
8321             return NULL;
8322             }
8323         sim_opt_out |= CMD_OPT_OF;                      /* got output file */
8324         continue;
8325         }
8326     cptr = get_glyph (cptr, gbuf, 0);
8327     if ((t = get_switches (gbuf)) != 0) {               /* try for switches */
8328         if (t < 0) {                                    /* err if bad switch */
8329             *st = SCPE_INVSW;
8330             return NULL;
8331             }
8332         sim_switches = sim_switches | t;                /* or in new switches */
8333         }
8334     else if ((opt & CMD_OPT_SCH) &&                     /* if allowed, */
8335         get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) { /* try for search */
8336         sim_schrptr = &sim_stabr;                       /* set search */
8337         sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);/* populate memory version of the same expression */
8338         sim_opt_out |= CMD_OPT_SCH;                     /* got search */
8339         }
8340     else if ((opt & CMD_OPT_DFT) &&                     /* default allowed? */
8341         ((sim_opt_out & CMD_OPT_DFT) == 0) &&           /* none yet? */
8342         (tdptr = find_unit (gbuf, &tuptr)) &&           /* try for default */
8343         (tuptr != NULL)) {
8344         sim_dfdev = tdptr;                              /* set as default */
8345         sim_dfunit = tuptr;
8346         sim_opt_out |= CMD_OPT_DFT;                     /* got default */
8347         }
8348     else return svptr;                                  /* not rec, break out */
8349     }
8350 return cptr;
8351 }
8352 
8353 /* put_switches         put switches into string
8354 
8355    Inputs:
8356         buf     =       pointer to string buffer
8357         bufsize =       size of string buffer
8358         sw      =       switch bit mask
8359    Outputs:
8360         buf     =       buffer with switches converted to text
8361 */
8362 
8363 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
8364 {
8365 char *optr = buf;
8366 int32 bit;
8367 
8368 (void)memset (buf, 0, bufsize);
8369 if ((sw == 0) || (bufsize < 3))
8370     return buf;
8371 --bufsize;                          /* leave room for terminating NUL */
8372 *optr++ = '-';
8373 for (bit=0; bit <= ('Z'-'A'); bit++)
8374     if (sw & (1 << bit))
8375         if ((size_t)(optr - buf) < bufsize)
8376             *optr++ = 'A' + bit;
8377 return buf;
8378 }
8379 
8380 /* Get register search specification
8381 
8382    Inputs:
8383         cptr    =       pointer to input string
8384         radix   =       radix for numbers
8385         schptr =        pointer to search table
8386    Outputs:
8387         return =        NULL if error
8388                         schptr if valid search specification
8389 */
8390 
8391 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8392 {
8393 int32 c;
8394 size_t logop, cmpop;
8395 t_value logval, cmpval;
8396 const char *sptr;
8397 CONST char *tptr;
8398 const char logstr[] = "|&^", cmpstr[] = "=!><";
8399 /* Using a const instead of a #define. */
8400 const size_t invalid_op = (size_t) -1;
8401 
8402 logval = cmpval = 0;
8403 if (*cptr == 0)                                         /* check for clause */
8404     return NULL;
8405 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8406 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8407     if ((sptr = strchr (logstr, c))) {                  /* check for mask */
8408         logop = sptr - logstr;
8409         logval = strtotv (cptr, &tptr, radix);
8410         if (cptr == tptr)
8411             return NULL;
8412         cptr = tptr;
8413         }
8414     else if ((sptr = strchr (cmpstr, c))) {             /* check for boolop */
8415         cmpop = sptr - cmpstr;
8416         if (*cptr == '=') {
8417             cmpop = cmpop + strlen (cmpstr);
8418             cptr++;
8419             }
8420         cmpval = strtotv (cptr, &tptr, radix);
8421         if (cptr == tptr)
8422             return NULL;
8423         cptr = tptr;
8424         }
8425     else return NULL;
8426     }                                                   /* end for */
8427 if (schptr->count != 1) {
8428     FREE (schptr->mask);
8429     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8430     FREE (schptr->comp);
8431     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8432     }
8433 if (logop != invalid_op) {
8434     schptr->logic = logop;
8435     schptr->mask[0] = logval;
8436     }
8437 if (cmpop != invalid_op) {
8438     schptr->boolop = cmpop;
8439     schptr->comp[0] = cmpval;
8440     }
8441 schptr->count = 1;
8442 return schptr;
8443 }
8444 
8445 /* Get memory search specification
8446 
8447    Inputs:
8448         cptr    =       pointer to input string
8449         radix   =       radix for numbers
8450         schptr =        pointer to search table
8451    Outputs:
8452         return =        NULL if error
8453                         schptr if valid search specification
8454 */
8455 
8456 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8457 {
8458 int32 c;
8459 size_t logop, cmpop;
8460 t_value *logval, *cmpval;
8461 t_stat reason = SCPE_OK;
8462 CONST char *ocptr = cptr;
8463 const char *sptr;
8464 char gbuf[CBUFSIZE];
8465 const char logstr[] = "|&^", cmpstr[] = "=!><";
8466 /* Using a const instead of a #define. */
8467 const size_t invalid_op = (size_t) -1;
8468 
8469 if (*cptr == 0)                                         /* check for clause */
8470     return NULL;
8471 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8472 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8473 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8474 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8475     if (NULL != (sptr = strchr (logstr, c))) {          /* check for mask */
8476         logop = sptr - logstr;
8477         cptr = get_glyph (cptr, gbuf, 0);
8478         reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8479         if (reason > 0) {
8480             FREE (logval);
8481             FREE (cmpval);
8482             return get_rsearch (ocptr, radix, schptr);
8483             }
8484         }
8485     else if (NULL != (sptr = strchr (cmpstr, c))) {     /* check for boolop */
8486         cmpop = sptr - cmpstr;
8487         if (*cptr == '=') {
8488             cmpop = cmpop + strlen (cmpstr);
8489             cptr++;
8490             }
8491         cptr = get_glyph (cptr, gbuf, 0);
8492         reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8493         if (reason > 0) {
8494             FREE (logval);
8495             FREE (cmpval);
8496             return get_rsearch (ocptr, radix, schptr);
8497             }
8498         }
8499     else {
8500         FREE (logval);
8501         FREE (cmpval);
8502         return NULL;
8503         }
8504     }                                                   /* end for */
8505 if (schptr->count != (uint32)(1 - reason)) {
8506     schptr->count = 1 - reason;
8507     FREE (schptr->mask);
8508     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8509     FREE (schptr->comp);
8510     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8511     }
8512 if (logop != invalid_op) {
8513     schptr->logic = logop;
8514     FREE (schptr->mask);
8515     schptr->mask = logval;
8516     }
8517 else {
8518     FREE (logval);
8519     }
8520 if (cmpop != invalid_op) {
8521     schptr->boolop = cmpop;
8522     FREE (schptr->comp);
8523     schptr->comp = cmpval;
8524     }
8525 else {
8526     FREE (cmpval);
8527     }
8528 return schptr;
8529 }
8530 
8531 /* Test value against search specification
8532 
8533    Inputs:
8534         val    =        value list to test
8535         schptr =        pointer to search table
8536    Outputs:
8537         return =        1 if value passes search criteria, 0 if not
8538 */
8539 
8540 int32 test_search (t_value *values, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8541 {
8542 t_value *val = NULL;
8543 int32 i, updown;
8544 int32 ret = 0;
8545 
8546 if (schptr == NULL)
8547     return ret;
8548 
8549 val = (t_value *)malloc (schptr->count * sizeof (*values));
8550 if (!val)
8551   {
8552     (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8553                   __func__, __FILE__, __LINE__);
8554 #if defined(USE_BACKTRACE)
8555 # if defined(SIGUSR2)
8556     (void)raise(SIGUSR2);
8557     /*NOTREACHED*/ /* unreachable */
8558 # endif /* if defined(SIGUSR2) */
8559 #endif /* if defined(USE_BACKTRACE) */
8560     abort();
8561   }
8562 for (i=0; i<(int32)schptr->count; i++) {
8563     val[i] = values[i];
8564     switch (schptr->logic) {                            /* case on logical */
8565 
8566         case SCH_OR:
8567             val[i] = val[i] | schptr->mask[i];
8568             break;
8569 
8570         case SCH_AND:
8571             val[i] = val[i] & schptr->mask[i];
8572             break;
8573 
8574         case SCH_XOR:
8575             val[i] = val[i] ^ schptr->mask[i];
8576             break;
8577             }
8578     }
8579 
8580 ret = 1;
8581 if (1) {    /* Little Endian VM */
8582     updown = -1;
8583     i=schptr->count-1;
8584     }
8585 else {      /* Big Endian VM */
8586     updown = 1;
8587     i=0;
8588     }
8589 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8590     switch (schptr->boolop) {                           /* case on comparison */
8591 
8592         case SCH_E: case SCH_EE:
8593             if (val[i] != schptr->comp[i])
8594                 ret = 0;
8595             break;
8596 
8597         case SCH_N: case SCH_NE:
8598             if (val[i] == schptr->comp[i])
8599                 ret = 0;
8600             break;
8601 
8602         case SCH_G:
8603             if (val[i] <= schptr->comp[i])
8604                 ret = 0;
8605             break;
8606 
8607         case SCH_GE:
8608             if (val[i] < schptr->comp[i])
8609                 ret = 0;
8610             break;
8611 
8612         case SCH_L:
8613             if (val[i] >= schptr->comp[i])
8614                 ret = 0;
8615             break;
8616 
8617         case SCH_LE:
8618             if (val[i] > schptr->comp[i])
8619                 ret = 0;
8620             break;
8621         }
8622     }
8623 FREE (val);
8624 return ret;
8625 }
8626 
8627 /* Radix independent input/output package
8628 
8629    strtotv - general radix input routine
8630 
8631    Inputs:
8632         inptr   =       string to convert
8633         endptr  =       pointer to first unconverted character
8634         radix   =       radix for input
8635    Outputs:
8636         value   =       converted value
8637 
8638    On an error, the endptr will equal the inptr.
8639 */
8640 
8641 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
     /* [previous][next][first][last][top][bottom][index][help] */
8642 {
8643 int32 nodigit;
8644 t_value val;
8645 uint32 c, digit;
8646 
8647 *endptr = inptr;                                        /* assume fails */
8648 if ((radix < 2) || (radix > 36))
8649     return 0;
8650 while (sim_isspace (*inptr))                            /* bypass white space */
8651     inptr++;
8652 val = 0;
8653 nodigit = 1;
8654 for (c = *inptr; sim_isalnum(c); c = *++inptr) {        /* loop through char */
8655     if (sim_islower (c))
8656         c = toupper (c);
8657     if (sim_isdigit (c))                                /* digit? */
8658         digit = c - (uint32) '0';
8659     else if (radix <= 10)                               /* stop if not expected */
8660         break;
8661     else digit = c + 10 - (uint32) 'A';                 /* convert letter */
8662     if (digit >= radix)                                 /* valid in radix? */
8663         return 0;
8664     val = (val * radix) + digit;                        /* add to value */
8665     nodigit = 0;
8666     }
8667 if (nodigit)                                            /* no digits? */
8668     return 0;
8669 *endptr = inptr;                                        /* result pointer */
8670 return val;
8671 }
8672 
8673 /* fprint_val - general radix printing routine
8674 
8675    Inputs:
8676         stream  =       stream designator
8677         val     =       value to print
8678         radix   =       radix to print
8679         width   =       width to print
8680         format  =       leading zeroes format
8681    Outputs:
8682         status  =       error status
8683         if stream is NULL, returns length of output that would
8684         have been generated.
8685 */
8686 
8687 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8688                    size_t width, uint32 format)
8689 {
8690 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8691 t_value owtest, wtest;
8692 size_t d;
8693 size_t digit;
8694 size_t ndigits;
8695 size_t commas = 0;
8696 char dbuf[MAX_WIDTH + 1];
8697 
8698 for (d = 0; d < MAX_WIDTH; d++)
8699     dbuf[d] = (format == PV_RZRO)? '0': ' ';
8700 dbuf[MAX_WIDTH] = 0;
8701 d = MAX_WIDTH;
8702 do {
8703     d = d - 1;
8704     digit = val % radix;
8705     val = val / radix;
8706     dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8707     } while ((d > 0) && (val != 0));
8708 
8709 switch (format) {
8710     case PV_LEFT:
8711         break;
8712     case PV_RZRO:
8713         wtest = owtest = radix;
8714         ndigits = 1;
8715         while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8716             owtest = wtest;
8717             wtest = wtest * radix;
8718             ndigits = ndigits + 1;
8719             }
8720         if ((MAX_WIDTH - (ndigits + commas)) < d)
8721             d = MAX_WIDTH - (ndigits + commas);
8722         break;
8723     }
8724 if (NULL == buffer)                   /* Potentially unsafe wraparound if */
8725     return ((t_stat) strlen(dbuf+d)); /*  sizeof(t_stat) < sizeof(size_t) */
8726 *buffer = '\0';
8727 if (width < strlen(dbuf+d))
8728     return SCPE_IOERR;
8729 strcpy(buffer, dbuf+d);
8730 return SCPE_OK;
8731 }
8732 
8733 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8734     uint32 width, uint32 format)
8735 {
8736 char dbuf[MAX_WIDTH + 1];
8737 
8738 if (!stream)
8739     return sprint_val (NULL, val, radix, width, format);
8740 if (width > MAX_WIDTH)
8741     width = MAX_WIDTH;
8742 sprint_val (dbuf, val, radix, width, format);
8743 if (Fprintf (stream, "%s", dbuf) < 0)
8744     return SCPE_IOERR;
8745 return SCPE_OK;
8746 }
8747 
8748 const char *sim_fmt_secs (double seconds)
     /* [previous][next][first][last][top][bottom][index][help] */
8749 {
8750 static char buf[60];
8751 char frac[16] = "";
8752 const char *sign = "";
8753 double val = seconds;
8754 double days, hours, mins, secs, msecs, usecs;
8755 
8756 if (val == 0.0)
8757     return "";
8758 if (val < 0.0) {
8759     sign = "-";
8760     val = -val;
8761     }
8762 days = floor (val / (24.0*60.0*60.0));
8763 val -= (days * 24.0*60.0*60.0);
8764 hours = floor (val / (60.0*60.0));
8765 val -= (hours * 60.0 * 60.0);
8766 mins = floor (val / 60.0);
8767 val -= (mins * 60.0);
8768 secs = floor (val);
8769 val -= secs;
8770 val *= 1000.0;
8771 msecs = floor (val);
8772 val -= msecs;
8773 val *= 1000.0;
8774 usecs = floor (val+0.5);
8775 if (usecs == 1000.0) {
8776     usecs = 0.0;
8777     msecs += 1;
8778     }
8779 if ((msecs > 0.0) || (usecs > 0.0)) {
8780     (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8781     while (frac[strlen (frac) - 1] == '0') //-V557
8782         frac[strlen (frac) - 1] = '\0'; //-V557
8783     if (strlen (frac) == 1)
8784         frac[0] = '\0';
8785     }
8786 if (days > 0)
8787     (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8788                    sign, days, (days != 1) ? "s" : "", hours, mins,
8789                    secs, frac, (days == 1) ? "s" : "");
8790 else
8791     if (hours > 0)
8792         (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8793                        sign, hours, mins, secs, frac);
8794     else
8795         if (mins > 0)
8796             (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8797                            sign, mins, secs, frac);
8798         else
8799             if (secs > 0)
8800                 (void)sprintf (buf, "%s%.0f%s second",
8801                                sign, secs, frac);
8802             else
8803                 if (msecs > 0) {
8804                     if (usecs > 0)
8805                         (void)sprintf (buf, "%s%.0f.%s msec",
8806                                        sign, msecs, frac+4);
8807                     else
8808                         (void)sprintf (buf, "%s%.0f msec",
8809                                        sign, msecs);
8810                     }
8811                 else
8812                     (void)sprintf (buf, "%s%.0f usec",
8813                                    sign, usecs);
8814 if (0 != strncmp ("1 ", buf, 2))
8815     strcpy (&buf[strlen (buf)], "s");
8816 return buf;
8817 }
8818 
8819 /*
8820  * Event queue package
8821  *
8822  *      sim_activate            add entry to event queue
8823  *      sim_activate_abs        add entry to event queue even if event already scheduled
8824  *      sim_activate_after      add entry to event queue after a specified amount of wall time
8825  *      sim_cancel              remove entry from event queue
8826  *      sim_process_event       process entries on event queue
8827  *      sim_is_active           see if entry is on event queue
8828  *      sim_activate_time       return time until activation
8829  *      sim_atime               return absolute time for an entry
8830  *      sim_gtime               return global time
8831  *      sim_qcount              return event queue entry count
8832  */
8833 
8834 t_stat sim_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8835 {
8836 UNIT *uptr;
8837 t_stat reason;
8838 #if defined(TESTING)
8839 cpu_state_t * cpup = _cpup;
8840 #endif
8841 
8842 if (stop_cpu)                                           /* stop CPU? */
8843   {
8844 #if defined(WIN_STDIO)
8845     (void)fflush(stdout);
8846     (void)fflush(stderr);
8847 #endif /* if defined(WIN_STDIO) */
8848     return SCPE_STOP;
8849   }
8850 UPDATE_SIM_TIME;                                        /* update sim time */
8851 
8852 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8853     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8854     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8855                "Queue Empty New Interval = %d\r\n",
8856                sim_interval);
8857     return SCPE_OK;
8858     }
8859 sim_processing_event = TRUE;
8860 do {
8861     uptr = sim_clock_queue;                             /* get first */
8862     sim_clock_queue = uptr->next;                       /* remove first */
8863     uptr->next = NULL;                                  /* hygiene */
8864     sim_interval -= uptr->time;
8865     uptr->time = 0;
8866     if (sim_clock_queue != QUEUE_LIST_END)
8867         sim_interval = sim_clock_queue->time;
8868     else
8869         sim_interval = noqueue_time = NOQUEUE_WAIT;
8870     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8871                "Processing Event for %s\r\n", sim_uname (uptr));
8872     if (uptr->action != NULL)
8873         reason = uptr->action (uptr);
8874     else
8875         reason = SCPE_OK;
8876     } while ((reason == SCPE_OK) &&
8877              (sim_interval <= 0) &&
8878              (sim_clock_queue != QUEUE_LIST_END) &&
8879              (!stop_cpu));
8880 
8881 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8882     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8883     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8884                "Processing Queue Complete New Interval = %d\r\n",
8885                sim_interval);
8886     }
8887 else
8888     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8889                "Processing Queue Complete New Interval = %d(%s)\r\n",
8890                sim_interval, sim_uname(sim_clock_queue));
8891 
8892 if ((reason == SCPE_OK) && stop_cpu)
8893   {
8894 #if defined(WIN_STDIO)
8895     (void)fflush(stdout);
8896     (void)fflush(stderr);
8897 #endif /* if defined(WIN_STDIO) */
8898     reason = SCPE_STOP;
8899   }
8900 sim_processing_event = FALSE;
8901 return reason;
8902 }
8903 
8904 /* sim_activate - activate (queue) event
8905 
8906    Inputs:
8907         uptr    =       pointer to unit
8908         event_time =    relative timeout
8909    Outputs:
8910         reason  =       result (SCPE_OK if ok)
8911 */
8912 
8913 t_stat sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8914 {
8915 if (uptr->dynflags & UNIT_TMR_UNIT)
8916     return sim_timer_activate (uptr, event_time);
8917 return _sim_activate (uptr, event_time);
8918 }
8919 
8920 t_stat _sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8921 {
8922 UNIT *cptr, *prvptr;
8923 int32 accum;
8924 #if defined(TESTING)
8925 cpu_state_t * cpup = _cpup;
8926 #endif
8927 
8928 if (sim_is_active (uptr))                               /* already active? */
8929     return SCPE_OK;
8930 UPDATE_SIM_TIME;                                        /* update sim time */
8931 
8932 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\r\n", sim_uname (uptr), event_time);
8933 
8934 prvptr = NULL;
8935 accum = 0;
8936 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8937     if (event_time < (accum + cptr->time))
8938         break;
8939     accum = accum + cptr->time;
8940     prvptr = cptr;
8941     }
8942 if (prvptr == NULL) {                                   /* insert at head */
8943     cptr = uptr->next = sim_clock_queue;
8944     sim_clock_queue = uptr;
8945     }
8946 else {
8947     cptr = uptr->next = prvptr->next;                   /* insert at prvptr */
8948     prvptr->next = uptr;
8949     }
8950 uptr->time = event_time - accum;
8951 if (cptr != QUEUE_LIST_END)
8952     cptr->time = cptr->time - uptr->time;
8953 sim_interval = sim_clock_queue->time;
8954 return SCPE_OK;
8955 }
8956 
8957 /* sim_activate_abs - activate (queue) event even if event already scheduled
8958 
8959    Inputs:
8960         uptr    =       pointer to unit
8961         event_time =    relative timeout
8962    Outputs:
8963         reason  =       result (SCPE_OK if ok)
8964 */
8965 
8966 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8967 {
8968 sim_cancel (uptr);
8969 return _sim_activate (uptr, event_time);
8970 }
8971 
8972 /* sim_activate_after - activate (queue) event
8973 
8974    Inputs:
8975         uptr    =       pointer to unit
8976         usec_delay =    relative timeout (in microseconds)
8977    Outputs:
8978         reason  =       result (SCPE_OK if ok)
8979 */
8980 
8981 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
8982 {
8983 return _sim_activate_after (uptr, usec_delay);
8984 }
8985 
8986 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
8987 {
8988 if (sim_is_active (uptr))                               /* already active? */
8989     return SCPE_OK;
8990 return sim_timer_activate_after (uptr, usec_delay);
8991 }
8992 
8993 /* sim_cancel - cancel (dequeue) event
8994 
8995    Inputs:
8996         uptr    =       pointer to unit
8997    Outputs:
8998         reason  =       result (SCPE_OK if ok)
8999 
9000 */
9001 
9002 t_stat sim_cancel (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9003 {
9004 UNIT *cptr, *nptr;
9005 #if defined(TESTING)
9006 cpu_state_t * cpup = _cpup;
9007 #endif
9008 
9009 if (sim_clock_queue == QUEUE_LIST_END)
9010     return SCPE_OK;
9011 if (!sim_is_active (uptr))
9012     return SCPE_OK;
9013 UPDATE_SIM_TIME;                                        /* update sim time */
9014 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\r\n", sim_uname(uptr));
9015 nptr = QUEUE_LIST_END;
9016 
9017 if (sim_clock_queue == uptr) {
9018     nptr = sim_clock_queue = uptr->next;
9019     uptr->next = NULL;                                  /* hygiene */
9020     }
9021 else {
9022     for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9023         if (cptr->next == uptr) {
9024             nptr = cptr->next = uptr->next;
9025             uptr->next = NULL;                          /* hygiene */
9026             break;                                      /* end queue scan */
9027             }
9028         }
9029     }
9030 if (nptr != QUEUE_LIST_END)
9031     nptr->time += (uptr->next) ? 0 : uptr->time;
9032 if (!uptr->next)
9033     uptr->time = 0;
9034 if (sim_clock_queue != QUEUE_LIST_END)
9035     sim_interval = sim_clock_queue->time;
9036 else sim_interval = noqueue_time = NOQUEUE_WAIT;
9037 if (uptr->next) {
9038     sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
9039     if (sim_deb)
9040         fclose(sim_deb);
9041     (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
9042                    __func__, __FILE__, __LINE__);
9043     abort ();
9044     }
9045 return SCPE_OK;
9046 }
9047 
9048 /* sim_is_active - test for entry in queue
9049 
9050    Inputs:
9051         uptr    =       pointer to unit
9052    Outputs:
9053         result =        TRUE if unit is busy, FALSE inactive
9054 */
9055 
9056 t_bool sim_is_active (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9057 {
9058 if (uptr->next == NULL)
9059   return FALSE;
9060 else
9061 return TRUE;
9062 }
9063 
9064 /* sim_activate_time - return activation time
9065 
9066    Inputs:
9067         uptr    =       pointer to unit
9068    Outputs:
9069         result =        absolute activation time + 1, 0 if inactive
9070 */
9071 
9072 int32 sim_activate_time (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9073 {
9074 UNIT *cptr;
9075 int32 accum = 0;
9076 
9077 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9078     if (cptr == sim_clock_queue) {
9079         if (sim_interval > 0)
9080             accum = accum + sim_interval;
9081         }
9082     else
9083         accum = accum + cptr->time;
9084     if (cptr == uptr)
9085         return accum + 1;
9086     }
9087 return 0;
9088 }
9089 
9090 /* sim_gtime - return global time
9091 
9092    Inputs: none
9093    Outputs:
9094         time    =       global time
9095 */
9096 
9097 double sim_gtime (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9098 {
9099 return sim_time;
9100 }
9101 
9102 /* sim_qcount - return queue entry count
9103 
9104    Inputs: none
9105    Outputs:
9106         count   =       number of entries on the queue
9107 */
9108 
9109 int32 sim_qcount (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9110 {
9111 int32 cnt;
9112 UNIT *uptr;
9113 
9114 cnt = 0;
9115 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9116     cnt++;
9117 return cnt;
9118 }
9119 
9120 /* Breakpoint package.  This module replaces the VM-implemented one
9121    instruction breakpoint capability.
9122 
9123    Breakpoints are stored in table sim_brk_tab, which is ordered by address for
9124    efficient binary searching.  A breakpoint consists of a six entry structure:
9125 
9126         addr                    address of the breakpoint
9127         type                    types of breakpoints set on the address
9128                                 a bit mask representing letters A-Z
9129         cnt                     number of iterations before breakp is taken
9130         action                  pointer command string to be executed
9131                                 when break is taken
9132         next                    list of other breakpoints with the same addr specifier
9133         time_fired              array of when this breakpoint was fired for each class
9134 
9135    sim_brk_summ is a summary of the types of breakpoints that are currently set (it
9136    is the bitwise OR of all the type fields).  A simulator need only check for
9137    a breakpoint of type X if bit SWMASK('X') is set in sim_brk_summ.
9138 
9139    The package contains the following public routines:
9140 
9141         sim_brk_init            initialize
9142         sim_brk_set             set breakpoint
9143         sim_brk_clr             clear breakpoint
9144         sim_brk_clrall          clear all breakpoints
9145         sim_brk_show            show breakpoint
9146         sim_brk_showall         show all breakpoints
9147         sim_brk_test            test for breakpoint
9148         sim_brk_npc             PC has been changed
9149         sim_brk_getact          get next action
9150         sim_brk_clract          clear pending actions
9151 
9152    Initialize breakpoint system.
9153 */
9154 
9155 t_stat sim_brk_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9156 {
9157 int32 i;
9158 
9159 for (i=0; i<sim_brk_lnt; i++) {
9160     BRKTAB *bp;
9161     if (sim_brk_tab)
9162       {
9163         bp = sim_brk_tab[i];
9164 
9165         while (bp)
9166           {
9167             BRKTAB *bpt = bp->next;
9168 
9169             FREE (bp->act);
9170             FREE (bp);
9171             bp = bpt;
9172           }
9173       }
9174 }
9175 if (sim_brk_tab != NULL)
9176     (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9177 sim_brk_lnt = SIM_BRK_INILNT;
9178 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9179 if (sim_brk_tab == NULL)
9180     return SCPE_MEM;
9181 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9182 sim_brk_ent = sim_brk_ins = 0;
9183 sim_brk_clract ();
9184 sim_brk_npc (0);
9185 return SCPE_OK;
9186 }
9187 
9188 /* Search for a breakpoint in the sorted breakpoint table */
9189 
9190 BRKTAB *sim_brk_fnd (t_addr loc)
     /* [previous][next][first][last][top][bottom][index][help] */
9191 {
9192 int32 lo, hi, p;
9193 BRKTAB *bp;
9194 
9195 if (sim_brk_ent == 0) {                                 /* table empty? */
9196     sim_brk_ins = 0;                                    /* insrt at head */
9197     return NULL;                                        /* sch fails */
9198     }
9199 lo = 0;                                                 /* initial bounds */
9200 hi = sim_brk_ent - 1;
9201 do {
9202     p = (lo + hi) >> 1;                                 /* probe */
9203     bp = sim_brk_tab[p];                                /* table addr */
9204     if (loc == bp->addr) {                              /* match? */
9205         sim_brk_ins = p;
9206         return bp;
9207         }
9208     else if (loc < bp->addr)                            /* go down? p is upper */
9209         hi = p - 1;
9210     else lo = p + 1;                                    /* go up? p is lower */
9211     } while (lo <= hi);
9212 if (loc < bp->addr)                                     /* insrt before or */
9213     sim_brk_ins = p;
9214 else sim_brk_ins = p + 1;                               /* after last sch */
9215 return NULL;
9216 }
9217 
9218 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
     /* [previous][next][first][last][top][bottom][index][help] */
9219 {
9220 BRKTAB *bp = sim_brk_fnd (loc);
9221 
9222 while (bp) {
9223     if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9224                   (bp->typ == btyp))
9225         return bp;
9226     bp = bp->next;
9227     }
9228 return bp;
9229 }
9230 
9231 /* Insert a breakpoint */
9232 
9233 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9234 {
9235 int32 i, t;
9236 BRKTAB *bp, **newp;
9237 
9238 if (sim_brk_ins < 0)
9239     return NULL;
9240 if (sim_brk_ent >= sim_brk_lnt) {                       /* out of space? */
9241     t = sim_brk_lnt + SIM_BRK_INILNT;                   /* new size */
9242     newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));    /* new table */
9243     if (newp == NULL)                                   /* can't extend */
9244         return NULL;
9245     memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));/* copy table */
9246     (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));/* zero new entries */
9247     FREE (sim_brk_tab);                                 /* free old table */
9248     sim_brk_tab = newp;                                 /* new base, lnt */
9249     sim_brk_lnt = t;
9250     }
9251 if ((sim_brk_ins == sim_brk_ent) ||
9252     ((sim_brk_ins != sim_brk_ent) && //-V728
9253      (sim_brk_tab[sim_brk_ins]->addr != loc))) {        /* need to open a hole? */
9254     for (i = sim_brk_ent; i > sim_brk_ins; --i)
9255         sim_brk_tab[i] = sim_brk_tab[i - 1];
9256     sim_brk_tab[sim_brk_ins] = NULL;
9257     }
9258 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9259 if (!bp)
9260   {
9261     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9262                    __func__, __FILE__, __LINE__);
9263 #if defined(USE_BACKTRACE)
9264 # if defined(SIGUSR2)
9265     (void)raise(SIGUSR2);
9266     /*NOTREACHED*/ /* unreachable */
9267 # endif /* if defined(SIGUSR2) */
9268 #endif /* if defined(USE_BACKTRACE) */
9269     abort();
9270   }
9271 bp->next = sim_brk_tab[sim_brk_ins];
9272 sim_brk_tab[sim_brk_ins] = bp;
9273 if (bp->next == NULL)
9274     sim_brk_ent += 1;
9275 bp->addr = loc;
9276 bp->typ = btyp;
9277 bp->cnt = 0;
9278 bp->act = NULL;
9279 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9280     bp->time_fired[i] = -1.0;
9281 return bp;
9282 }
9283 
9284 /* Set a breakpoint of type sw */
9285 
9286 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
     /* [previous][next][first][last][top][bottom][index][help] */
9287 {
9288 BRKTAB *bp;
9289 
9290 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9291     sw |= sim_brk_dflt;
9292 if (~sim_brk_types & sw) {
9293     char gbuf[CBUFSIZE];
9294 
9295     return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\r\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9296     }
9297 if ((sw & BRK_TYP_DYN_ALL) && act)                      /* can't specify an action with a dynamic breakpoint */
9298     return SCPE_ARG;
9299 bp = sim_brk_fnd (loc);                                 /* loc present? */
9300 if (!bp)                                                /* no, allocate */
9301     bp = sim_brk_new (loc, sw);
9302 else {
9303     while (bp && (bp->typ != (uint32)sw))
9304         bp = bp->next;
9305     if (!bp)
9306         bp = sim_brk_new (loc, sw);
9307     }
9308 if (!bp)                                                /* still no? mem err */
9309     return SCPE_MEM;
9310 bp->cnt = ncnt;                                         /* set count */
9311 if ((!(sw & BRK_TYP_DYN_ALL)) &&                        /* Not Dynamic and */
9312     (bp->act != NULL) && (act != NULL)) {               /* replace old action? */
9313     FREE (bp->act);                                     /* deallocate */
9314     bp->act = NULL;                                     /* now no action */
9315     }
9316 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9317     char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char)); /* alloc buf */
9318     if (newp == NULL)                                   /* mem err? */
9319         return SCPE_MEM;
9320     strncpy (newp, act, CBUFSIZE);                      /* copy action */
9321     bp->act = newp;                                     /* set pointer */
9322     }
9323 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9324 return SCPE_OK;
9325 }
9326 
9327 /* Clear a breakpoint */
9328 
9329 t_stat sim_brk_clr (t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9330 {
9331 BRKTAB *bpl = NULL;
9332 BRKTAB *bp = sim_brk_fnd (loc);
9333 int32 i;
9334 
9335 if (!bp)                                                /* not there? ok */
9336     return SCPE_OK;
9337 if (sw == 0)
9338     sw = SIM_BRK_ALLTYP;
9339 
9340 #if !defined(__clang_analyzer__)
9341 while (bp) {
9342     if (bp->typ == (bp->typ & sw)) {
9343         FREE (bp->act);                                 /* deallocate action */
9344         if (bp == sim_brk_tab[sim_brk_ins])
9345             bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9346         else
9347           {
9348             if (bpl)
9349               bpl->next = bp->next;
9350           }
9351         FREE (bp);
9352         bp = bpl;
9353         }
9354     else {
9355         bpl = bp;
9356         bp = bp->next;
9357         }
9358     }
9359 #endif /* if !defined(__clang_analyzer__) */
9360 if (sim_brk_tab[sim_brk_ins] == NULL) {                 /* erased entry */
9361     sim_brk_ent = sim_brk_ent - 1;                      /* decrement count */
9362     for (i = sim_brk_ins; i < sim_brk_ent; i++)         /* shuffle remaining entries */
9363         sim_brk_tab[i] = sim_brk_tab[i+1];
9364     }
9365 sim_brk_summ = 0;                                       /* recalc summary */
9366 for (i = 0; i < sim_brk_ent; i++) {
9367     bp = sim_brk_tab[i];
9368     while (bp) {
9369         sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9370         bp = bp->next;
9371         }
9372     }
9373 return SCPE_OK;
9374 }
9375 
9376 /* Clear all breakpoints */
9377 
9378 t_stat sim_brk_clrall (int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9379 {
9380 int32 i;
9381 
9382 if (sw == 0)
9383     sw = SIM_BRK_ALLTYP;
9384 for (i = 0; i < sim_brk_ent;) {
9385     t_addr loc = sim_brk_tab[i]->addr;
9386     sim_brk_clr (loc, sw);
9387     if ((i < sim_brk_ent) &&
9388         (loc == sim_brk_tab[i]->addr))
9389         ++i;
9390     }
9391 return SCPE_OK;
9392 }
9393 
9394 /* Show a breakpoint */
9395 
9396 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9397 {
9398 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9399 DEVICE *dptr;
9400 uint32 i, any;
9401 
9402 if ((sw == 0) || (sw == SWMASK ('C'))) {
9403     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9404 if (!bp || (!(bp->typ & sw))) {
9405     return SCPE_OK; }
9406 dptr = sim_dflt_dev;
9407 if (dptr == NULL) {
9408     return SCPE_OK; }
9409 if (sw & SWMASK ('C')) {
9410     if (st != NULL) {
9411         (void)fprintf (st, "SET BREAK "); }
9412 } else {
9413     if (sim_vm_fprint_addr) {
9414         sim_vm_fprint_addr
9415             (st, dptr, loc);
9416     } else {
9417         fprint_val
9418             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9419     if (st != NULL) {
9420         (void)fprintf (st, ":\t"); }
9421     }
9422 for (i = any = 0; i < 26; i++) {
9423     if ((bp->typ >> i) & 1) {
9424         if ((sw & SWMASK ('C')) == 0) {
9425             if (any) {
9426                 if (st != NULL) {
9427                     (void)fprintf (st, ", "); } }
9428             if (st != NULL) {
9429                 fputc (i + 'A', st); }
9430             }
9431         } else {
9432             if (st != NULL) {
9433                 (void)fprintf (st, "-%c", i + 'A'); }
9434         any = 1;
9435         }
9436     }
9437 if (sw & SWMASK ('C')) {
9438     if (st != NULL) {
9439         (void)fprintf (st, " "); }
9440     if (sim_vm_fprint_addr) {
9441         if (st != NULL) {
9442             sim_vm_fprint_addr (st, dptr, loc); }
9443     } else {
9444         fprint_val
9445             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9446     }
9447 if (bp->cnt > 0) {
9448     if (st != NULL) {
9449         (void)fprintf (st, "[%d]", bp->cnt); } }
9450 if (bp->act != NULL) {
9451     if (st != NULL) {
9452         (void)fprintf (st, "; %s", bp->act); } }
9453 (void)fprintf (st, "\r\n");
9454 return SCPE_OK;
9455 }
9456 
9457 /* Show all breakpoints */
9458 
9459 t_stat sim_brk_showall (FILE *st, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9460 {
9461 int32 bit, mask, types;
9462 BRKTAB **bpt;
9463 
9464 if ((sw == 0) || (sw == SWMASK ('C')))
9465     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9466 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9467     if (sim_brk_types & (1 << bit))
9468         ++types;
9469 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9470     (void)fprintf (st, "Supported Breakpoint Types:"); //-V522
9471     for (bit=0; bit <= ('Z'-'A'); bit++)
9472         if (sim_brk_types & (1 << bit))
9473             (void)fprintf (st, " -%c", 'A' + bit);
9474     (void)fprintf (st, "\r\n");
9475     }
9476 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9477     mask = (sw & sim_brk_types);
9478     (void)fprintf (st, "Displaying Breakpoint Types:");
9479     for (bit=0; bit <= ('Z'-'A'); bit++)
9480         if (mask & (1 << bit))
9481             (void)fprintf (st, " -%c", 'A' + bit);
9482     (void)fprintf (st, "\r\n");
9483     }
9484 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9485     BRKTAB *prev = NULL;
9486     BRKTAB *cur = *bpt;
9487     BRKTAB *next;
9488     /* First reverse the list */
9489     while (cur) {
9490         next = cur->next;
9491         cur->next = prev;
9492         prev = cur;
9493         cur = next;
9494         }
9495     /* save reversed list in the head pointer so lookups work */
9496     *bpt = prev;
9497     /* Walk the reversed list and print it in the order it was defined in */
9498     cur = prev;
9499     while (cur) {
9500         if (cur->typ & sw)
9501             sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9502         cur = cur->next;
9503         }
9504     /* reversing the list again */
9505     cur = prev;
9506     prev = NULL;
9507     while (cur) {
9508         next = cur->next;
9509         cur->next = prev;
9510         prev = cur;
9511         cur = next;
9512         }
9513     /* restore original list */
9514     *bpt = prev;
9515     }
9516 return SCPE_OK;
9517 }
9518 
9519 /* Test for breakpoint */
9520 
9521 uint32 sim_brk_test (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9522 {
9523 BRKTAB *bp;
9524 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9525 
9526 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9527     btyp |= BRK_TYP_DYN_ALL;
9528 
9529 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {     /* in table, and type match? */
9530     double s_gtime = sim_gtime ();                      /* get time now */
9531 
9532     if (bp->time_fired[spc] == s_gtime)                 /* already taken?  */
9533         return 0;
9534     bp->time_fired[spc] = s_gtime;                      /* remember match time */
9535     if (--bp->cnt > 0)                                  /* count > 0? */
9536         return 0;
9537     bp->cnt = 0;                                        /* reset count */
9538     sim_brk_setact (bp->act);                           /* set up actions */
9539     sim_brk_match_type = btyp & bp->typ;                /* set return value */
9540     if (bp->typ & BRK_TYP_TEMP)
9541         sim_brk_clr (loc, bp->typ);                     /* delete one-shot breakpoint */
9542     sim_brk_match_addr = loc;
9543     return sim_brk_match_type;
9544     }
9545 return 0;
9546 }
9547 
9548 /* Get next pending action, if any */
9549 
9550 CONST char *sim_brk_getact (char *buf, int32 size)
     /* [previous][next][first][last][top][bottom][index][help] */
9551 {
9552 char *ep;
9553 size_t lnt;
9554 
9555 if (sim_brk_act[sim_do_depth] == NULL)                  /* any action? */
9556     return NULL;
9557 while (sim_isspace (*sim_brk_act[sim_do_depth]))        /* skip spaces */
9558     sim_brk_act[sim_do_depth]++;
9559 if (*sim_brk_act[sim_do_depth] == 0) {                  /* now empty? */
9560     return sim_brk_clract ();
9561     }
9562 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {   /* cmd delimiter? */
9563     lnt = ep - sim_brk_act[sim_do_depth];               /* cmd length */
9564     memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);   /* copy with ; */
9565     buf[lnt] = 0;                                       /* erase ; */
9566     sim_brk_act[sim_do_depth] += lnt + 1;               /* adv ptr */
9567     }
9568 else {
9569     strncpy (buf, sim_brk_act[sim_do_depth], size);     /* copy action */
9570     sim_brk_clract ();                                  /* no more */
9571     }
9572 return buf;
9573 }
9574 
9575 /* Clear pending actions */
9576 
9577 char *sim_brk_clract (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9578 {
9579 FREE (sim_brk_act_buf[sim_do_depth]);
9580 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9581 }
9582 
9583 /* Set up pending actions */
9584 
9585 void sim_brk_setact (const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
9586 {
9587 if (action) {
9588     sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9589     if (!sim_brk_act_buf[sim_do_depth])
9590       {
9591         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9592                        __func__, __FILE__, __LINE__);
9593 #if defined(USE_BACKTRACE)
9594 # if defined(SIGUSR2)
9595         (void)raise(SIGUSR2);
9596         /*NOTREACHED*/ /* unreachable */
9597 # endif /* if defined(SIGUSR2) */
9598 #endif /* if defined(USE_BACKTRACE) */
9599         abort();
9600       }
9601     strcpy (sim_brk_act_buf[sim_do_depth], action);
9602     sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9603     }
9604 else
9605     sim_brk_clract ();
9606 }
9607 
9608 /* New PC */
9609 
9610 void sim_brk_npc (uint32 cnt)
     /* [previous][next][first][last][top][bottom][index][help] */
9611 {
9612 uint32 spc;
9613 BRKTAB **bpt, *bp;
9614 
9615 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9616     cnt = SIM_BKPT_N_SPC;
9617 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9618     for (bp = *bpt; bp; bp = bp->next) {
9619         for (spc = 0; spc < cnt; spc++)
9620             bp->time_fired[spc] = -1.0;
9621         }
9622     }
9623 }
9624 
9625 /* Clear breakpoint space */
9626 
9627 void sim_brk_clrspc (uint32 spc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9628 {
9629 BRKTAB **bpt, *bp;
9630 
9631 if (spc < SIM_BKPT_N_SPC) {
9632     for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9633         for (bp = *bpt; bp; bp = bp->next) {
9634             if (bp->typ & btyp)
9635                 bp->time_fired[spc] = -1.0;
9636             }
9637         }
9638     }
9639 }
9640 
9641 const char *sim_brk_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
9642 {
9643 static char msg[256];
9644 char addr[65] = "";
9645 char buf[32];
9646 
9647 msg[0] = '\0';
9648 if (sim_dflt_dev) {
9649   if (sim_vm_sprint_addr)
9650     sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9651   else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9652 }
9653 if (sim_brk_type_desc) {
9654     BRKTYPTAB *brk = sim_brk_type_desc;
9655 
9656     while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9657         if (brk->btyp == sim_brk_match_type) {
9658             (void)sprintf (msg, "%s: %s", brk->desc, addr);
9659             break;
9660             }
9661         brk++;
9662         }
9663     }
9664 if (!msg[0])
9665     (void)sprintf (msg, "%s Breakpoint at: %s\r\n",
9666                    put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9667 
9668 return msg;
9669 }
9670 
9671 /* Expect package.  This code provides a mechanism to stop and control simulator
9672    execution based on traffic coming out of simulated ports and as well as a means
9673    to inject data into those ports.  It can conceptually viewed as a string
9674    breakpoint package.
9675 
9676    Expect rules are stored in tables associated with each port which can use this
9677    facility.  An expect rule consists of a five entry structure:
9678 
9679         match                   the expect match string
9680         size                    the number of bytes in the match string
9681         match_pattern           the expect match string in display format
9682         cnt                     number of iterations before match is declared
9683         action                  command string to be executed when match occurs
9684 
9685    All active expect rules are contained in an expect match context structure.
9686 
9687         rules                   the match rules
9688         size                    the count of match rules
9689         buf                     the buffer of output data which has been produced
9690         buf_ins                 the buffer insertion point for the next output data
9691         buf_size                the buffer size
9692 
9693    The package contains the following public routines:
9694 
9695         sim_set_expect          expect command parser and initializer
9696         sim_set_noexpect        noexpect command parser
9697         sim_exp_set             set or add an expect rule
9698         sim_exp_clr             clear or delete an expect rule
9699         sim_exp_clrall          clear all expect rules
9700         sim_exp_show            show an expect rule
9701         sim_exp_showall         show all expect rules
9702         sim_exp_check           test for rule match
9703 */
9704 
9705 /* Set expect */
9706 
9707 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9708 {
9709 char gbuf[CBUFSIZE];
9710 CONST char *tptr;
9711 CONST char *c1ptr;
9712 t_bool after_set = FALSE;
9713 uint32 after;
9714 int32 cnt = 0;
9715 t_stat r;
9716 
9717 if (exp == NULL)
9718     return sim_messagef (SCPE_ARG, "Null exp!\r\n");
9719 after = exp->after;
9720 
9721 if ((cptr == NULL) || (*cptr == 0))
9722     return SCPE_2FARG;
9723 if (*cptr == '[') {
9724     cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9725     if ((cptr == c1ptr) || (*c1ptr != ']'))
9726         return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\r\n");
9727     cptr = c1ptr + 1;
9728     while (sim_isspace(*cptr))
9729         ++cptr;
9730     }
9731 tptr = get_glyph (cptr, gbuf, ',');
9732 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9733     after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9734     if (r != SCPE_OK)
9735         return sim_messagef (SCPE_ARG, "Invalid Halt After Value\r\n");
9736     after_set = TRUE;
9737     cptr = tptr;
9738     }
9739 if ((*cptr != '"') && (*cptr != '\''))
9740     return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9741 cptr = get_glyph_quoted (cptr, gbuf, 0);
9742 
9743 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9744 }
9745 
9746 /* Clear expect */
9747 
9748 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9749 {
9750 char gbuf[CBUFSIZE];
9751 
9752 if (NULL == cptr || !*cptr)
9753     return sim_exp_clrall (exp);                    /* clear all rules */
9754 if ((*cptr != '"') && (*cptr != '\''))
9755     return sim_messagef (SCPE_ARG, "String must be quote delimited\r\n");
9756 cptr = get_glyph_quoted (cptr, gbuf, 0);
9757 if (*cptr != '\0')
9758     return SCPE_2MARG;                              /* No more arguments */
9759 return sim_exp_clr (exp, gbuf);                     /* clear one rule */
9760 }
9761 
9762 /* Search for an expect rule in an expect context */
9763 
9764 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
     /* [previous][next][first][last][top][bottom][index][help] */
9765 {
9766 size_t i;
9767 
9768 if (NULL == exp->rules)
9769     return NULL;
9770 for (i=start_rule; i<exp->size; i++)
9771     if (!strcmp (exp->rules[i].match_pattern, match))
9772         return &exp->rules[i];
9773 return NULL;
9774 }
9775 
9776 /* Clear (delete) an expect rule */
9777 
9778 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9779 {
9780 size_t i;
9781 
9782 if (NULL == ep)                                         /* not there? ok */
9783     return SCPE_OK;
9784 FREE (ep->match);                                       /* deallocate match string */
9785 FREE (ep->match_pattern);                               /* deallocate the display format match string */
9786 FREE (ep->act);                                         /* deallocate action */
9787 exp->size -= 1;                                         /* decrement count */
9788 #if !defined(__clang_analyzer__)
9789 for (i=ep-exp->rules; i<exp->size; i++)                 /* shuffle up remaining rules */
9790     exp->rules[i] = exp->rules[i+1];
9791 if (exp->size == 0) {                                   /* No rules left? */
9792     FREE (exp->rules);
9793     exp->rules = NULL;
9794     }
9795 #endif /* if !defined(__clang_analyzer__) */
9796 return SCPE_OK;
9797 }
9798 
9799 t_stat sim_exp_clr (EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9800 {
9801 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9802 
9803 while (ep) {
9804     sim_exp_clr_tab (exp, ep);
9805     ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9806     }
9807 return SCPE_OK;
9808 }
9809 
9810 /* Clear all expect rules */
9811 
9812 t_stat sim_exp_clrall (EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
9813 {
9814 int32 i;
9815 
9816 for (i=0; i<exp->size; i++) {
9817     FREE (exp->rules[i].match);                         /* deallocate match string */
9818     FREE (exp->rules[i].match_pattern);                 /* deallocate display format match string */
9819     FREE (exp->rules[i].act);                           /* deallocate action */
9820     }
9821 FREE (exp->rules);
9822 exp->rules = NULL;
9823 exp->size = 0;
9824 FREE (exp->buf);
9825 exp->buf = NULL;
9826 exp->buf_size = 0;
9827 exp->buf_ins = 0;
9828 return SCPE_OK;
9829 }
9830 
9831 /* Set/Add an expect rule */
9832 
9833 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] */
9834 {
9835 EXPTAB *ep;
9836 uint8 *match_buf;
9837 uint32 match_size;
9838 size_t i;
9839 
9840 /* Validate the match string */
9841 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9842 if (!match_buf)
9843     return SCPE_MEM;
9844 if (switches & EXP_TYP_REGEX) {
9845     FREE (match_buf);
9846     return sim_messagef (SCPE_ARG, "RegEx support not available\r\n");
9847     }
9848 else {
9849     if (switches & EXP_TYP_REGEX_I) {
9850         FREE (match_buf);
9851         return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\r\n");
9852         }
9853     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9854     if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9855         FREE (match_buf);
9856         return sim_messagef (SCPE_ARG, "Invalid quoted string\r\n");
9857         }
9858     }
9859 FREE (match_buf);
9860 for (i=0; i<exp->size; i++) {                           /* Make sure this rule won't be occluded */
9861     if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9862         (exp->rules[i].switches & EXP_TYP_PERSIST))
9863         return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\r\n");
9864     }
9865 if (after && exp->size)
9866     return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\r\n");
9867 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9868 if (!exp->rules)
9869   {
9870     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9871                    __func__, __FILE__, __LINE__);
9872 #if defined(USE_BACKTRACE)
9873 # if defined(SIGUSR2)
9874     (void)raise(SIGUSR2);
9875     /*NOTREACHED*/ /* unreachable */
9876 # endif /* if defined(SIGUSR2) */
9877 #endif /* if defined(USE_BACKTRACE) */
9878     abort();
9879   }
9880 ep = &exp->rules[exp->size];
9881 exp->size += 1;
9882 exp->after = after;                                     /* set halt after value */
9883 (void)memset (ep, 0, sizeof(*ep));
9884 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9885 if (ep->match_pattern)
9886     strcpy (ep->match_pattern, match);
9887 ep->cnt = cnt;                                          /* set proceed count */
9888 ep->switches = switches;                                /* set switches */
9889 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9890 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9891     sim_exp_clr_tab (exp, ep);                          /* clear it */
9892     FREE (match_buf);                                   /* release allocation */
9893     return SCPE_MEM;
9894     }
9895 if (switches & EXP_TYP_REGEX) {
9896     FREE (match_buf);
9897     match_buf = NULL;
9898     }
9899 else {
9900     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9901     sim_decode_quoted_string (match, match_buf, &match_size);
9902     ep->match = match_buf;
9903     ep->size = match_size;
9904     }
9905 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9906 if (!ep->match_pattern)
9907   {
9908     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9909                    __func__, __FILE__, __LINE__);
9910 #if defined(USE_BACKTRACE)
9911 # if defined(SIGUSR2)
9912     (void)raise(SIGUSR2);
9913     /*NOTREACHED*/ /* unreachable */
9914 # endif /* if defined(SIGUSR2) */
9915 #endif /* if defined(USE_BACKTRACE) */
9916     abort();
9917   }
9918 strcpy (ep->match_pattern, match);
9919 if (ep->act) {                                          /* replace old action? */
9920     FREE (ep->act);                                     /* deallocate */
9921     ep->act = NULL;                                     /* now no action */
9922     }
9923 if (act) while (sim_isspace(*act)) ++act;                   /* skip leading spaces in action string */
9924 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9925     char *newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */
9926     if (newp == NULL)                                   /* mem err? */
9927         return SCPE_MEM;
9928     strcpy (newp, act);                                 /* copy action */
9929     ep->act = newp;                                     /* set pointer */
9930     }
9931 /* Make sure that the production buffer is large enough to detect a match for all rules including a NUL termination byte */
9932 for (i=0; i<exp->size; i++) {
9933     size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9934     if (compare_size >= exp->buf_size) {
9935         exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2); /* Extra byte to null terminate regex compares */
9936         exp->buf_size = compare_size + 1;
9937         }
9938     }
9939 return SCPE_OK;
9940 }
9941 
9942 /* Show an expect rule */
9943 
9944 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9945 {
9946 if (!ep)
9947     return SCPE_OK;
9948 (void)fprintf (st, "EXPECT");
9949 if (ep->switches & EXP_TYP_PERSIST)
9950     (void)fprintf (st, " -p");
9951 if (ep->switches & EXP_TYP_CLEARALL)
9952     (void)fprintf (st, " -c");
9953 if (ep->switches & EXP_TYP_REGEX)
9954     (void)fprintf (st, " -r");
9955 if (ep->switches & EXP_TYP_REGEX_I)
9956     (void)fprintf (st, " -i");
9957 (void)fprintf (st, " %s", ep->match_pattern);
9958 if (ep->cnt > 0)
9959     (void)fprintf (st, " [%d]", ep->cnt);
9960 if (ep->act)
9961     (void)fprintf (st, " %s", ep->act);
9962 (void)fprintf (st, "\r\n");
9963 return SCPE_OK;
9964 }
9965 
9966 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9967 {
9968 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9969 
9970 if (exp->buf_size) {
9971     char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9972 
9973     (void)fprintf (st, "Match Buffer Size: %lld\r\n",
9974                    (long long)exp->buf_size);
9975     (void)fprintf (st, "Buffer Insert Offset: %lld\r\n",
9976                    (long long)exp->buf_ins);
9977     (void)fprintf (st, "Buffer Contents: %s\r\n",
9978                    bstr);
9979     FREE (bstr);
9980     }
9981 if (exp->after)
9982     (void)fprintf (st, "Halt After: %lld instructions\r\n",
9983                    (long long)exp->after);
9984 if (exp->dptr && exp->dbit)
9985     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
9986                    sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
9987                    exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
9988 (void)fprintf (st, "Match Rules:\r\n");
9989 if (!*match)
9990     return sim_exp_showall (st, exp);
9991 if (!ep) {
9992     (void)fprintf (st, "No Rules match '%s'\r\n", match);
9993     return SCPE_ARG;
9994     }
9995 do {
9996     sim_exp_show_tab (st, exp, ep);
9997     ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
9998     } while (ep);
9999 return SCPE_OK;
10000 }
10001 
10002 /* Show all expect rules */
10003 
10004 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
10005 {
10006 size_t i;
10007 
10008 for (i=0; i < exp->size; i++)
10009     sim_exp_show_tab (st, exp, &exp->rules[i]);
10010 return SCPE_OK;
10011 }
10012 
10013 /* Test for expect match */
10014 
10015 t_stat sim_exp_check (EXPECT *exp, uint8 data)
     /* [previous][next][first][last][top][bottom][index][help] */
10016 {
10017 size_t i;
10018 EXPTAB *ep = NULL;
10019 char *tstr = NULL;
10020 #if defined(TESTING)
10021 cpu_state_t * cpup = _cpup;
10022 #endif
10023 
10024 if ((!exp) || (!exp->rules))                            /* Anything to check? */
10025     return SCPE_OK;
10026 
10027 exp->buf[exp->buf_ins++] = data;                        /* Save new data */
10028 exp->buf[exp->buf_ins] = '\0';                          /* Nul terminate for RegEx match */
10029 
10030 for (i=0; i < exp->size; i++) {
10031     ep = &exp->rules[i];
10032     if (ep == NULL) //-V547
10033         break;
10034     if (ep->switches & EXP_TYP_REGEX) {
10035         }
10036     else {
10037         if (exp->buf_ins < ep->size) {                          /* Match stradle end of buffer */
10038             /*
10039              * First compare the newly deposited data at the beginning
10040              * of buffer with the end of the match string
10041              */
10042             if (exp->buf_ins > 0) {
10043                 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10044                     char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10045                     char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10046 
10047                     sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\r\n",
10048                                (long long)exp->buf_ins, estr);
10049                     sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10050                     FREE (estr);
10051                     FREE (mstr);
10052                     }
10053                 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10054                     continue;
10055                 }
10056             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10057                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10058                 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10059 
10060                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10061                            (long long)exp->buf_size-(ep->size-exp->buf_ins),
10062                            (long long)ep->size-exp->buf_ins, estr);
10063                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10064                 FREE (estr);
10065                 FREE (mstr);
10066                 }
10067             if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10068                 continue;
10069             break;
10070             }
10071         else {
10072             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10073                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10074                 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10075 
10076                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\r\n",
10077                            (long long)exp->buf_ins-ep->size,
10078                            (long long)ep->size, estr);
10079                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\r\n", mstr);
10080                 FREE (estr);
10081                 FREE (mstr);
10082                 }
10083             if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10084                 continue;
10085             break;
10086             }
10087         }
10088     }
10089 if (exp->buf_ins == exp->buf_size) {                    /* At end of match buffer? */
10090         exp->buf_ins = 0;                               /* wrap around to beginning */
10091         sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\r\n");
10092     }
10093 if ((ep != NULL) && (i != exp->size)) {                 /* Found? */
10094     sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\r\n");
10095     if (ep->cnt > 0) {
10096         ep->cnt -= 1;
10097         sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\r\n",
10098                    (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10099         }
10100     else {
10101         uint32 after   = exp->after;
10102         int32 switches = ep->switches;
10103         if (ep->act && *ep->act) {
10104             sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\r\n", ep->act);
10105             }
10106         else {
10107             sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\r\n");
10108             }
10109         sim_brk_setact (ep->act);                       /* set up actions */
10110         if (ep->switches & EXP_TYP_CLEARALL)            /* Clear-all expect rule? */
10111             sim_exp_clrall (exp);                       /* delete all rules */
10112         else {
10113             if (!(ep->switches & EXP_TYP_PERSIST))      /* One shot expect rule? */
10114                 sim_exp_clr_tab (exp, ep);              /* delete it */
10115             }
10116         sim_activate (&sim_expect_unit,                 /* schedule simulation stop when indicated */
10117                       (switches & EXP_TYP_TIME) ?
10118                             (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10119                              after);
10120         }
10121     /* Matched data is no longer available for future matching */
10122     exp->buf_ins = 0;
10123     }
10124 if (tstr)  //-V547
10125   FREE (tstr);
10126 return SCPE_OK;
10127 }
10128 
10129 /* Queue input data for sending */
10130 
10131 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
     /* [previous][next][first][last][top][bottom][index][help] */
10132 {
10133 if (snd->extoff != 0) {
10134     if (snd->insoff > snd->extoff)
10135         memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10136     snd->insoff -= snd->extoff;
10137     snd->extoff  = 0;
10138     }
10139 if (snd->insoff+size > snd->bufsize) {
10140     snd->bufsize = snd->insoff+size;
10141     snd->buffer  = (uint8 *)realloc(snd->buffer, snd->bufsize);
10142     if (!snd->buffer)
10143       {
10144         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10145                        __func__, __FILE__, __LINE__);
10146 #if defined(USE_BACKTRACE)
10147 # if defined(SIGUSR2)
10148         (void)raise(SIGUSR2);
10149         /*NOTREACHED*/ /* unreachable */
10150 # endif /* if defined(SIGUSR2) */
10151 #endif /* if defined(USE_BACKTRACE) */
10152         abort();
10153       }
10154     }
10155 memcpy(snd->buffer+snd->insoff, data, size);
10156 snd->insoff += size;
10157 if (delay)
10158     snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10159 if (after)
10160     snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10161 if (snd->after == 0)
10162     snd->after = snd->delay;
10163 snd->next_time = sim_gtime() + snd->after;
10164 return SCPE_OK;
10165 }
10166 
10167 /* Cancel Queued input data */
10168 t_stat sim_send_clear (SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10169 {
10170 snd->insoff = 0;
10171 snd->extoff = 0;
10172 return SCPE_OK;
10173 }
10174 
10175 /* Display console Queued input data status */
10176 
10177 t_stat sim_show_send_input (FILE *st, const SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10178 {
10179 if (snd->extoff < snd->insoff) {
10180     (void)fprintf (st, "%lld bytes of pending input Data:\r\n    ",
10181                    (long long)snd->insoff-snd->extoff);
10182     fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10183     (void)fprintf (st, "\r\n");
10184     }
10185 else
10186     (void)fprintf (st, "No Pending Input Data\r\n");
10187 if ((snd->next_time - sim_gtime()) > 0) {
10188     if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10189         (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\r\n",
10190                        (int)(snd->next_time - sim_gtime()),
10191         (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10192     else
10193         (void)fprintf (st, "Minimum of %d instructions before sending first character\r\n",
10194                        (int)(snd->next_time - sim_gtime()));
10195     }
10196 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10197     (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\r\n",
10198                    (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10199 else
10200     (void)fprintf (st, "Minimum of %d instructions between characters\r\n",
10201                    (int)snd->delay);
10202 if (snd->dptr && snd->dbit)
10203     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\r\n",
10204                    sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10205                    snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10206 return SCPE_OK;
10207 }
10208 
10209 /* Poll for Queued input data */
10210 
10211 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10212 {
10213 #if defined(TESTING)
10214 cpu_state_t * cpup = _cpup;
10215 #endif
10216 if ((NULL != snd) && (snd->extoff < snd->insoff)) {     /* pending input characters available? */
10217     if (sim_gtime() < snd->next_time) {                 /* too soon? */
10218         *stat = SCPE_OK;
10219         sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\r\n");
10220         }
10221     else {
10222         char dstr[8] = "";
10223         *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;/* get one */
10224         snd->next_time = sim_gtime() + snd->delay;
10225         if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10226             (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10227         sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\r\n", *stat & 0xFF, dstr);
10228         }
10229     return TRUE;
10230     }
10231 return FALSE;
10232 }
10233 
10234 /* Message Text */
10235 
10236 const char *sim_error_text (t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10237 {
10238 static char msgbuf[64];
10239 
10240 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);        /* remove any flags */
10241 if (stat == SCPE_OK)
10242     return "No Error";
10243 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10244     return scp_errors[stat-SCPE_BASE].message;
10245 (void)sprintf(msgbuf, "Error %d", stat);
10246 return msgbuf;
10247 }
10248 
10249 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10250 {
10251 char gbuf[CBUFSIZE];
10252 size_t cond;
10253 
10254 *stat = SCPE_ARG;
10255 cptr = get_glyph (cptr, gbuf, 0);
10256 if (0 == memcmp("SCPE_", gbuf, 5))
10257     memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));  /* skip leading SCPE_ */
10258 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10259     if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10260         cond += SCPE_BASE;
10261         break;
10262         }
10263 if (0 == strcmp(gbuf, "OK"))
10264     cond = SCPE_OK;
10265 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {       /* not found? */
10266     unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10267     if (0 == numeric_cond)                    /* try explicit number */
10268         return SCPE_ARG;
10269     cond = (t_stat) numeric_cond;
10270     }
10271 if (cond > SCPE_MAX_ERR)
10272     return SCPE_ARG;
10273 *stat = cond;
10274 return SCPE_OK;
10275 }
10276 
10277 /* Debug printout routines, from Dave Hittner */
10278 
10279 const char* debug_bstates = "01_^";
10280 char debug_line_prefix[256];
10281 int32 debug_unterm  = 0;
10282 
10283 /* Finds debug phrase matching bitmask from from device DEBTAB table */
10284 
10285 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10286 {
10287 static const char *debtab_none    = "DEBTAB_ISNULL";
10288 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10289 const char *some_match = NULL;
10290 int32 offset = 0;
10291 
10292 if (dptr->debflags == 0)
10293     return debtab_none;
10294 
10295 dbits &= dptr->dctrl;                           /* Look for just the bits that matched */
10296 
10297 /* Find matching words for bitmask */
10298 
10299 while ((offset < 32) && dptr->debflags[offset].name) {
10300     if (dptr->debflags[offset].mask == dbits)   /* All Bits Match */
10301         return dptr->debflags[offset].name;
10302     if (dptr->debflags[offset].mask & dbits)
10303         some_match = dptr->debflags[offset].name;
10304     offset++;
10305     }
10306 return some_match ? some_match : debtab_nomatch;
10307 }
10308 
10309 /* Prints standard debug prefix unless previous call unterminated */
10310 
10311 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10312 {
10313 const char* debug_type = get_dbg_verb (dbits, dptr);
10314 char tim_t[32] = "";
10315 char tim_a[32] = "";
10316 char  pc_s[64] = "";
10317 struct timespec time_now;
10318 
10319 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10320     clock_gettime(CLOCK_REALTIME, &time_now);
10321     if (sim_deb_switches & SWMASK ('R'))
10322         sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10323     if (sim_deb_switches & SWMASK ('T')) {
10324         time_t tnow = (time_t)time_now.tv_sec;
10325         struct tm *now = gmtime(&tnow);
10326         (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10327                       (int)now->tm_hour,
10328                       (int)now->tm_min,
10329                       (int)now->tm_sec,
10330                       (long)(time_now.tv_nsec / 1000000));
10331         }
10332     if (sim_deb_switches & SWMASK ('A')) {
10333         (void)sprintf(tim_t, "%d.%03ld ",
10334                       (int)(time_now.tv_sec),
10335                       (long)(time_now.tv_nsec / 1000000));
10336         }
10337     }
10338 if (sim_deb_switches & SWMASK ('P')) {
10339     t_value val;
10340 
10341     if (sim_vm_pc_value)
10342         val = (*sim_vm_pc_value)();
10343     else
10344         val = get_rval (sim_PC, 0);
10345     (void)sprintf(pc_s, "-%s:", sim_PC->name);
10346     sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10347     }
10348 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10349               tim_t, tim_a, sim_gtime(), pc_s,
10350               "", dptr->name, debug_type);
10351 return debug_line_prefix;
10352 }
10353 
10354 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
     /* [previous][next][first][last][top][bottom][index][help] */
10355 {
10356 int32 i, fields, offset;
10357 uint32 value, beforevalue, mask;
10358 
10359 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10360     if (bitdefs[fields].offset == 0xffffffff)       /* fixup uninitialized offsets */
10361         bitdefs[fields].offset = offset;
10362     offset += bitdefs[fields].width;
10363     }
10364 for (i = fields-1; i >= 0; i--) {                   /* print xlation, transition */
10365     if (bitdefs[i].name[0] == '\0')
10366         continue;
10367     if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10368         int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10369         (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10370         }
10371     else {
10372         const char *delta = "";
10373         mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10374         value = (uint32)((after >> bitdefs[i].offset) & mask);
10375         beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10376         if (value < beforevalue)
10377             delta = "_";
10378         if (value > beforevalue)
10379             delta = "^";
10380         if (bitdefs[i].valuenames)
10381             (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10382         else
10383             if (bitdefs[i].format) {
10384                 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10385                 (void)Fprintf(stream, bitdefs[i].format, value);
10386                 (void)Fprintf(stream, " ");
10387                 }
10388             else
10389                 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10390         }
10391     }
10392 }
10393 
10394 /* Prints state of a register: bit translation + state (0,1,_,^)
10395    indicating the state and transition of the bit and bitfields. States:
10396    0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */
10397 
10398 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
     /* [previous][next][first][last][top][bottom][index][help] */
10399     BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10400 {
10401 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10402     if (!debug_unterm)
10403         (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));         /* print prefix if required */
10404     if (header)
10405         (void)fprintf(sim_deb, "%s: ", header);
10406     fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs); /* print xlation, transition */
10407     if (terminate)
10408         (void)fprintf(sim_deb, "\r\n");
10409     debug_unterm = terminate ? 0 : 1;                   /* set unterm for next */
10410     }
10411 }
10412 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
     /* [previous][next][first][last][top][bottom][index][help] */
10413     uint32 before, uint32 after, int terminate)
10414 {
10415 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10416 }
10417 
10418 /* Print message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10419 void sim_printf (const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10420 {
10421 char stackbuf[STACKBUFSIZE];
10422 int32 bufsize = sizeof(stackbuf);
10423 char *buf = stackbuf;
10424 int32 len;
10425 va_list arglist;
10426 
10427 while (1) {                                         /* format passed string, args */
10428     va_start (arglist, fmt);
10429     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10430     va_end (arglist);
10431 
10432 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10433 
10434     if ((len < 0) || (len >= bufsize-1)) {
10435         if (buf != stackbuf)
10436             FREE (buf);
10437         if (bufsize >= (INT_MAX / 2))
10438             return;                                 /* too big */
10439         bufsize = bufsize * 2;
10440         if (bufsize < len + 2)
10441             bufsize = len + 2;
10442         buf = (char *) malloc (bufsize);
10443         if (buf == NULL)                            /* out of memory */
10444             return;
10445         buf[bufsize-1] = '\0';
10446         continue;
10447         }
10448     break;
10449     }
10450 
10451 if (sim_is_running) {
10452     char *c, *remnant = buf;
10453     while ((c = strchr(remnant, '\n'))) { //-NLOK
10454         if ((c != buf) && (*(c - 1) != '\r')) //-NLOK
10455             (void)printf("%.*s\r\n", (int)(c-remnant), remnant); //-NLOK
10456         else
10457             (void)printf("%.*s\n", (int)(c-remnant), remnant); //-NLOK
10458         remnant = c + 1;
10459         }
10460     (void)printf("%s", remnant);
10461     }
10462 else
10463     (void)printf("%s", buf);
10464 if (sim_log && (sim_log != stdout))
10465     (void)fprintf (sim_log, "%s", buf);
10466 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10467     (void)fprintf (sim_deb, "%s", buf);
10468 
10469 if (buf != stackbuf)
10470     FREE (buf);
10471 }
10472 
10473 /* Print command result message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10474 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10475 {
10476 char stackbuf[STACKBUFSIZE];
10477 size_t bufsize = sizeof(stackbuf);
10478 char *buf = stackbuf;
10479 size_t len;
10480 va_list arglist;
10481 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10482 
10483 while (1) {                                         /* format passed string, args */
10484     va_start (arglist, fmt);
10485     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10486     va_end (arglist);
10487 
10488 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10489 
10490     if (len >= bufsize - 1) {
10491         if (buf != stackbuf)
10492             FREE (buf);
10493         bufsize = bufsize * 2;
10494         if (bufsize < len + 2)
10495             bufsize = len + 2;
10496         buf = (char *) malloc (bufsize);
10497         if (buf == NULL)                            /* out of memory */
10498             return SCPE_MEM;
10499         buf[bufsize-1] = '\0';
10500         continue;
10501         }
10502     break;
10503     }
10504 
10505 if (sim_do_ocptr[sim_do_depth]) {
10506     if (!sim_do_echo && !sim_quiet && !inhibit_message)
10507         sim_printf("%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10508     else {
10509         if (sim_deb)                        /* Always put context in debug output */
10510             (void)fprintf (sim_deb, "%s> %s\r\n", do_position(), sim_do_ocptr[sim_do_depth]);
10511         }
10512     }
10513 if (sim_is_running && !inhibit_message) {
10514     char *c, *remnant = buf;
10515     while ((c = strchr(remnant, '\n'))) { //-NLOK
10516         if ((c != buf) && (*(c - 1) != '\r')) //-NLOK
10517             (void)printf("%.*s\r\n", (int)(c-remnant), remnant); //-NLOK
10518         else
10519             (void)printf("%.*s\n", (int)(c-remnant), remnant); //-NLOK
10520         remnant = c + 1;
10521         }
10522     (void)printf("%s", remnant);
10523     }
10524 else {
10525     if (!inhibit_message)
10526         (void)printf("%s", buf);
10527     }
10528 if (sim_log && (sim_log != stdout) && !inhibit_message)
10529     (void)fprintf (sim_log, "%s", buf);
10530 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))/* Always display messages in debug output */
10531     (void)fprintf (sim_deb, "%s", buf);
10532 
10533 if (buf != stackbuf)
10534     FREE (buf);
10535 return stat | SCPE_NOMESSAGE;
10536 }
10537 
10538 /* Inline debugging - will print debug message if debug file is
10539    set and the bitmask matches the current device debug options.
10540    Extra returns are added for un*x systems, since the output
10541    device is set into 'raw' mode when the cpu is booted,
10542    and the extra returns don't hurt any other systems.
10543    Callers should be calling sim_debug() which is a macro
10544    defined in scp.h which evaluates the action condition before
10545    incurring call overhead. */
10546 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10547 {
10548 DEVICE *dptr = (DEVICE *)vdptr;
10549 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10550     char stackbuf[STACKBUFSIZE];
10551     int32 bufsize = sizeof(stackbuf);
10552     char *buf = stackbuf;
10553     va_list arglist;
10554     int32 i, j, len;
10555     const char* debug_prefix = sim_debug_prefix(dbits, dptr);   /* prefix to print if required */
10556 
10557     buf[bufsize-1] = '\0';
10558     while (1) {                                         /* format passed string, args */
10559         va_start (arglist, fmt);
10560         len = vsnprintf (buf, bufsize-1, fmt, arglist);
10561         va_end (arglist);
10562 
10563 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10564 
10565         if ((len < 0) || (len >= bufsize-1)) {
10566             if (buf != stackbuf)
10567                 FREE (buf);
10568             if (bufsize >= (INT_MAX / 2))
10569                 return;                                 /* too big */
10570             bufsize = bufsize * 2;
10571             if (bufsize < len + 2)
10572                 bufsize = len + 2;
10573             buf = (char *) malloc (bufsize);
10574             if (buf == NULL)                            /* out of memory */
10575                 return;
10576             buf[bufsize-1] = '\0';
10577             continue;
10578             }
10579         break;
10580         }
10581 
10582 /* Output the formatted data expanding newlines where they exist */
10583 
10584     for (i = j = 0; i < len; ++i) {
10585         if ('\n' == buf[i]) {
10586             if (i >= j) {
10587                 if ((i != j) || (i == 0)) {
10588                     if (debug_unterm)
10589                         (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10590                     else                                /* print prefix when required */
10591                         (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10592                     }
10593                 debug_unterm = 0;
10594                 }
10595             j = i + 1;
10596             }
10597         }
10598     if (i > j) {
10599         if (debug_unterm)
10600             (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10601         else                                        /* print prefix when required */
10602             (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10603         }
10604 
10605 /* Set unterminated flag for next time */
10606 
10607     debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10608     if (buf != stackbuf)
10609         FREE (buf);
10610     }
10611 return;
10612 }
10613 
10614 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] */
10615 {
10616 #if defined(TESTING)
10617 cpu_state_t * cpup = _cpup;
10618 #endif
10619 if (sim_deb && (dptr->dctrl & reason)) {
10620     sim_debug (reason, dptr, "%s %s %slen: %08X\r\n", sim_uname(uptr), txt, position, (unsigned int)len);
10621     if (data && len) {
10622         size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10623         char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10624         static char hex[] = "0123456789ABCDEF";
10625         static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10626         static unsigned char ebcdic2ascii[] = {
10627             0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10628             0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10629             0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10630             0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10631             0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10632             0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10633             0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10634             0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10635             0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10636             0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10637             0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10638             0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10639             0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10640             0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10641             0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10642             0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10643             0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10644             0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10645             0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10646             0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10647             0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10648             0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10649             0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10650             0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10651             0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10652             0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10653             0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10654             0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10655             0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10656             0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10657             0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10658             0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10659             };
10660 
10661         for (i=same=0; i<len; i += 16) {
10662             if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10663                 ++same;
10664                 continue;
10665                 }
10666             if (same > 0) {
10667                 sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10668                            (unsigned long int)(i - (16*same)),
10669                            (unsigned long int)(i - 1));
10670                 same = 0;
10671                 }
10672             group = (((len - i) > 16) ? 16 : (len - i));
10673             strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10674             eidx = strlen(ebcdicbuf);
10675             strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10676             ridx = strlen(rad50buf);
10677             strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10678             soff = strlen(strbuf);
10679             for (sidx=oidx=0; sidx<group; ++sidx) {
10680                 outbuf[oidx++] = ' ';
10681                 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10682                 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10683                 if (sim_isprint (data[i+sidx]))
10684                     strbuf[soff+sidx] = data[i+sidx];
10685                 else
10686                     strbuf[soff+sidx] = '.';
10687                 if (ridx && ((sidx&1) == 0)) {
10688                     uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10689 
10690                     if (word >= 64000) {
10691                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10692                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10693                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10694                         }
10695                     else {
10696                         rad50buf[ridx++] = rad50[word/1600];
10697                         rad50buf[ridx++] = rad50[(word/40)%40];
10698                         rad50buf[ridx++] = rad50[word%40];
10699                         }
10700                     }
10701                 if (eidx) {
10702                     if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10703                         ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10704                     else
10705                         ebcdicbuf[eidx++] = '.';
10706                     }
10707                 }
10708             outbuf[oidx] = '\0';
10709             strbuf[soff+sidx] = '\0';
10710             ebcdicbuf[eidx] = '\0';
10711             rad50buf[ridx] = '\0';
10712             sim_debug (reason, dptr, "%04lx%-48s %s%s%s\r\n",
10713                     (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10714             }
10715         if (same > 0) {
10716             sim_debug (reason, dptr, "%04lx thru %04lx same as above\r\n",
10717                     (unsigned long int)(i-(16*same)),
10718                     (unsigned long int)(len-1));
10719             }
10720         }
10721     }
10722 }
10723 
10724 int Fprintf (FILE *f, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10725 {
10726 int ret = 0;
10727 va_list args;
10728 
10729 va_start (args, fmt);
10730     ret = vfprintf (f, fmt, args);
10731 va_end (args);
10732 return ret;
10733 }
10734 
10735 /* Hierarchical help presentation
10736  *
10737  * Device help can be presented hierarchically by calling
10738  *
10739  * t_stat scp_help (FILE *st, DEVICE *dptr,
10740  *                  UNIT *uptr, int flag, const char *help, char *cptr)
10741  *
10742  * or one of its three cousins from the device HELP routine.
10743  *
10744  * *help is the pointer to the structured help text to be displayed.
10745  *
10746  * The format and usage, and some helper macros can be found in scp_help.h
10747  * If you don't use the macros, it is not necessary to #include "scp_help.h".
10748  *
10749  * Actually, if you don't specify a DEVICE pointer and don't include
10750  * other device references, it can be used for non-device help.
10751  */
10752 
10753 #define blankch(x) ((x) == ' ' || (x) == '\t')
10754 
10755 typedef struct topic {
10756     size_t         level;
10757     char          *title;
10758     char          *label;
10759     struct topic  *parent;
10760     struct topic **children;
10761     uint32         kids;
10762     char          *text;
10763     size_t         len;
10764     uint32         flags;
10765     size_t         kidwid;
10766 #define HLP_MAGIC_TOPIC  1
10767     } TOPIC;
10768 
10769 static volatile struct {
10770     const char *error;
10771     const char *prox;
10772     size_t block;
10773     size_t line;
10774     } help_where = { "", NULL, 0, 0 };
10775 jmp_buf help_env;
10776 
10777 #define FAIL(why,text,here)        \
10778   {                                \
10779     help_where.error = #text;      \
10780     help_where.prox = here;        \
10781     longjmp ( help_env, (why) );   \
10782     /*LINTED E_STMT_NOT_REACHED*/  \
10783   }
10784 
10785 /*
10786  * Add to topic text.
10787  * Expands text buffer as necessary.
10788  */
10789 
10790 static void appendText (TOPIC *topic, const char *text, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
10791 {
10792 char *newt;
10793 
10794 if (!len)
10795     return;
10796 
10797 newt = (char *)realloc (topic->text, topic->len + len +1);
10798 if (!newt) {
10799 #if !defined(SUNLINT)
10800     FAIL (SCPE_MEM, No memory, NULL);
10801 #endif /* if !defined(SUNLINT) */
10802     }
10803 topic->text = newt;
10804 memcpy (newt + topic->len, text, len);
10805 topic->len +=len;
10806 newt[topic->len] = '\0';
10807 return;
10808 }
10809 
10810 /* Release memory held by a topic and its children.
10811  */
10812 static void cleanHelp (TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
10813 {
10814 TOPIC *child;
10815 size_t i;
10816 
10817 FREE (topic->title);
10818 FREE (topic->text);
10819 FREE (topic->label);
10820 for (i = 0; i < topic->kids; i++) {
10821     child = topic->children[i];
10822     cleanHelp (child);
10823     FREE (child);
10824     }
10825 FREE (topic->children);
10826 return;
10827 }
10828 
10829 /* Build a help tree from a string.
10830  * Handles substitutions, formatting.
10831  */
10832 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
10833                          UNIT *uptr, const char *htext, va_list ap)
10834 {
10835 char *end;
10836 size_t n, ilvl;
10837 #define VSMAX 100
10838 char *vstrings[VSMAX];
10839 size_t vsnum = 0;
10840 char * astrings[VSMAX+1];
10841 size_t asnum = 0;
10842 char *const *hblock;
10843 const char *ep;
10844 t_bool excluded = FALSE;
10845 
10846 /* variable arguments consumed table.
10847  * The scheme used allows arguments to be accessed in random
10848  * order, but for portability, all arguments must be char *.
10849  * If you try to violate this, there ARE machines that WILL break.
10850  */
10851 
10852 (void)memset (vstrings, 0, sizeof (vstrings));
10853 (void)memset (astrings, 0, sizeof (astrings));
10854 astrings[asnum++] = (char *) htext;
10855 
10856 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10857     help_where.block = hblock - astrings;
10858     help_where.line = 0;
10859     while (*htext) {
10860         const char *start;
10861 
10862         help_where.line++;
10863         if (sim_isspace (*htext) || *htext == '+') {/* Topic text, indented topic text */
10864             if (excluded) {                     /* Excluded topic text */
10865                 while (*htext && *htext != '\n')
10866                     htext++;
10867                 if (*htext)
10868                     ++htext;
10869                 continue;
10870                 }
10871             ilvl = 1;
10872             appendText (topic, "    ", 4);      /* Basic indentation */
10873             if (*htext == '+') {                /* More for each + */
10874                 while (*htext == '+') {
10875                     ilvl++;
10876                     appendText (topic, "    ", 4);
10877                     htext++;
10878                     }
10879                 }
10880             while (*htext && *htext != '\n' && sim_isspace (*htext))
10881                 htext++;
10882             if (!*htext)                        /* Empty after removing leading spaces */
10883                 break;
10884             start = htext;
10885             while (*htext) {                    /* Process line for substitutions */
10886                 if (*htext == '%') {
10887                     appendText (topic, start, htext - start); /* Flush up to escape */
10888                     switch (*++htext) {         /* Evaluate escape */
10889                         case 'U':
10890                             if (dptr) {
10891                                 char buf[129];
10892                                 n = uptr? uptr - dptr->units: 0;
10893                                 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10894                                 appendText (topic, buf, strlen (buf));
10895                                 }
10896                             break;
10897                         case 'D':
10898                             if (dptr != NULL)
10899                                 appendText (topic, dptr->name, strlen (dptr->name));
10900                             break;
10901                         case 'S':
10902                             appendText (topic, sim_name, strlen (sim_name));
10903                             break;
10904                         case '%':
10905                             appendText (topic, "%", 1);
10906                             break;
10907                         case '+':
10908                             appendText (topic, "+", 1);
10909                             break;
10910                         default:                    /* Check for vararg # */
10911                             if (sim_isdigit (*htext)) {
10912                                 n = 0;
10913                                 while (sim_isdigit (*htext))
10914                                     n += (n * 10) + (*htext++ - '0');
10915                                 if (( *htext != 'H' && *htext != 's') ||
10916                                     n == 0 || n >= VSMAX) {
10917 #if !defined(SUNLINT)
10918                                     FAIL (SCPE_ARG, Invalid escape, htext);
10919 #endif /* if !defined(SUNLINT) */
10920                                     }
10921                                 while (n > vsnum)   /* Get arg pointer if not cached */
10922                                     vstrings[vsnum++] = va_arg (ap, char *);
10923                                 start = vstrings[n-1]; /* Insert selected string */
10924                                 if (*htext == 'H') {   /* Append as more input */
10925                                     if (asnum >= VSMAX) {
10926 #if !defined(SUNLINT)
10927                                         FAIL (SCPE_ARG, Too many blocks, htext);
10928 #endif /* if !defined(SUNLINT) */
10929                                         }
10930                                     astrings[asnum++] = (char *)start;
10931                                     break;
10932                                     }
10933                                 ep = start;
10934                                 while (*ep) {
10935                                     if (*ep == '\n') {
10936                                         ep++;       /* Segment to \n */
10937                                         appendText (topic, start, ep - start);
10938                                         if (*ep) {  /* More past \n, indent */
10939                                             size_t i;
10940                                             for (i = 0; i < ilvl; i++)
10941                                                 appendText (topic, "    ", 4);
10942                                             }
10943                                         start = ep;
10944                                         }
10945                                     else
10946                                         ep++;
10947                                     }
10948                                 appendText (topic, start, ep-start);
10949                                 break;
10950                                 }
10951 #if !defined(SUNLINT)
10952                             FAIL (SCPE_ARG, Invalid escape, htext);
10953 #endif /* if !defined(SUNLINT) */
10954                         } /* switch (escape) */
10955                     start = ++htext;
10956                     continue;                   /* Current line */
10957                     } /* if (escape) */
10958                 if (*htext == '\n') {           /* End of line, append last segment */
10959                     htext++;
10960                     appendText (topic, start, htext - start);
10961                     break;                      /* To next line */
10962                     }
10963                 htext++;                        /* Regular character */
10964                 }
10965             continue;
10966             } /* topic text line */
10967         if (sim_isdigit (*htext)) {             /* Topic heading */
10968             TOPIC **children;
10969             TOPIC *newt;
10970             char nbuf[100];
10971 
10972             n = 0;
10973             start = htext;
10974             while (sim_isdigit (*htext))
10975                 n += (n * 10) + (*htext++ - '0');
10976             if ((htext == start) || !n) {
10977 #if !defined(SUNLINT)
10978                 FAIL (SCPE_ARG, Invalid topic heading, htext);
10979 #endif /* if !defined(SUNLINT) */
10980                 }
10981             if (n <= topic->level) {            /* Find level for new topic */
10982                 while (n <= topic->level)
10983                     topic = topic->parent;
10984                 }
10985             else {
10986                 if (n > topic->level + 1) {     /* Skipping down more than 1 */
10987 #if !defined(SUNLINT)
10988                     FAIL (SCPE_ARG, Level not contiguous, htext); /* E.g. 1 3, not reasonable */
10989 #endif /* if !defined(SUNLINT) */
10990                     }
10991                 }
10992             while (*htext && (*htext != '\n') && sim_isspace (*htext))
10993                 htext++;
10994             if (!*htext || (*htext == '\n')) {  /* Name missing */
10995 #if !defined(SUNLINT)
10996                 FAIL (SCPE_ARG, Missing topic name, htext);
10997 #endif /* if !defined(SUNLINT) */
10998                 }
10999             start = htext;
11000             while (*htext && (*htext != '\n'))
11001                 htext++;
11002             if (start == htext) {               /* Name NULL */
11003 #if !defined(SUNLINT)
11004                 FAIL (SCPE_ARG, Null topic name, htext);
11005 #endif /* if !defined(SUNLINT) */
11006                 }
11007             excluded = FALSE;
11008             if (*start == '?') {                /* Conditional topic? */
11009                 size_t n = 0;
11010                 start++;
11011                 while (sim_isdigit (*start))    /* Get param # */
11012                     n += (n * 10) + (*start++ - '0');
11013                 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
11014 #if !defined(SUNLINT)
11015                     FAIL (SCPE_ARG, Invalid parameter number, start);
11016 #endif /* if !defined(SUNLINT) */
11017                     }
11018                 while (n > vsnum)               /* Get arg pointer if not cached */
11019                     vstrings[vsnum++] = va_arg (ap, char *);
11020                 end = vstrings[n-1];            /* Check for True */
11021                 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
11022                     excluded = TRUE;            /* False, skip topic this time */
11023                     if (*htext)
11024                         htext++;
11025                     continue;
11026                     }
11027                 }
11028             newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
11029             if (!newt) {
11030 #if !defined(SUNLINT)
11031                 FAIL (SCPE_MEM, No memory, NULL);
11032 #endif /* if !defined(SUNLINT) */
11033                 }
11034             size_t len = (htext > start) ? (htext - start) : 0;
11035             newt->title = (char *) malloc(len + 1);
11036             if (!newt->title) {
11037                 FREE (newt);
11038 #if !defined(SUNLINT)
11039                 FAIL (SCPE_MEM, No memory, NULL);
11040 #endif /* if !defined(SUNLINT) */
11041                 }
11042             memcpy (newt->title, start, htext - start);
11043             newt->title[htext - start] = '\0';
11044             if (*htext)
11045                 htext++;
11046 
11047             if (newt->title[0] == '$')
11048                 newt->flags |= HLP_MAGIC_TOPIC;
11049 
11050             children = (TOPIC **) realloc (topic->children,
11051                                            (topic->kids +1) * sizeof (TOPIC *));
11052             if (NULL == children) {
11053                 FREE (newt->title);
11054                 FREE (newt);
11055 #if !defined(SUNLINT)
11056                 FAIL (SCPE_MEM, No memory, NULL);
11057 #endif /* if !defined(SUNLINT) */
11058                 }
11059             topic->children = children;
11060             topic->children[topic->kids++] = newt;
11061             newt->level = n;
11062             newt->parent = topic;
11063             n = strlen (newt->title);
11064             if (n > topic->kidwid)
11065                 topic->kidwid = n;
11066             (void)sprintf (nbuf, ".%u", topic->kids);
11067             n = strlen (topic->label) + strlen (nbuf) + 1;
11068             newt->label = (char *) malloc (n);
11069             if (NULL == newt->label) {
11070                 FREE (newt->title);
11071                 topic->children[topic->kids -1] = NULL;
11072                 FREE (newt);
11073 #if !defined(SUNLINT)
11074                 FAIL (SCPE_MEM, No memory, NULL);
11075 #endif /* if !defined(SUNLINT) */
11076                 }
11077             (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11078             topic = newt;
11079             continue;
11080             } /* digits introducing a topic */
11081         if (*htext == ';') {                    /* Comment */
11082             while (*htext && *htext != '\n')
11083                 htext++;
11084             continue;
11085             }
11086 #if !defined(SUNLINT)
11087         FAIL (SCPE_ARG, Unknown line type, htext);     /* Unknown line */
11088 #endif /* if !defined(SUNLINT) */
11089         } /* htext not at end */
11090     (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11091     vsnum = 0;
11092     } /* all strings */
11093 
11094 return topic;
11095 }
11096 
11097 /*
11098  * Create prompt string - top thru current topic
11099  * Add prompt at end.
11100  */
11101 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
     /* [previous][next][first][last][top][bottom][index][help] */
11102 {
11103 char *prefix;
11104 char *newp, *newt;
11105 
11106 if (topic->level == 0) {
11107     prefix = (char *) calloc (2,1);
11108     if (!prefix) {
11109 #if !defined(SUNLINT)
11110         FAIL (SCPE_MEM, No memory, NULL);
11111 #endif /* if !defined(SUNLINT) */
11112         }
11113     prefix[0] = '\n';
11114     }
11115 else
11116     prefix = helpPrompt (topic->parent, "", oneword);
11117 
11118 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11119                         strlen (pstring) +1);
11120 if (!newp) {
11121     FREE (prefix);
11122 #if !defined(SUNLINT)
11123     FAIL (SCPE_MEM, No memory, NULL);
11124 #endif /* if !defined(SUNLINT) */
11125     }
11126 strcpy (newp, prefix);
11127 if (topic->children) {
11128     if (topic->level != 0)
11129         strcat (newp, " ");
11130     newt = (topic->flags & HLP_MAGIC_TOPIC)?
11131             topic->title+1: topic->title;
11132     if (oneword) {
11133         char *np = newp + strlen (newp);
11134         while (*newt) {
11135             *np++ = blankch (*newt)? '_' : *newt;
11136             newt++;
11137             }
11138         *np = '\0';
11139         }
11140     else
11141         strcat (newp, newt);
11142     if (*pstring && *pstring != '?')
11143         strcat (newp, " ");
11144     }
11145 strcat (newp, pstring);
11146 FREE (prefix);
11147 return newp;
11148 }
11149 
11150 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
11151 {
11152 char tbuf[CBUFSIZE];
11153 size_t i, skiplines;
11154 #if defined(_WIN32)
11155 FILE *tmp;
11156 char *tmpnam;
11157 
11158 do {
11159     int fd;
11160     tmpnam = _tempnam (NULL, "simh");
11161     fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11162     if (fd != -1) {
11163         tmp = _fdopen (fd, "w+");
11164         break;
11165         }
11166     } while (1);
11167 #else
11168 FILE *tmp = tmpfile();
11169 #endif /* if defined(_WIN32) */
11170 
11171 if (!tmp) {
11172     (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\r\n",
11173                    xstrerror_l(errno), errno);
11174     return;
11175     }
11176 
11177 if (topic->title)
11178     (void)fprintf (st, "%s\r\n", topic->title+1);
11179 
11180 skiplines = 0;
11181 if (topic->title) {
11182   if (!strcmp (topic->title+1, "Registers")) {
11183       fprint_reg_help (tmp, dptr) ;
11184       skiplines = 1;
11185       }
11186   else
11187       if (!strcmp (topic->title+1, "Set commands")) {
11188           fprint_set_help (tmp, dptr);
11189           skiplines = 3;
11190           }
11191       else
11192           if (!strcmp (topic->title+1, "Show commands")) {
11193               fprint_show_help (tmp, dptr);
11194               skiplines = 3;
11195               }
11196   }
11197 rewind (tmp);
11198 if (errno) {
11199     (void)fprintf (st, "rewind: error %d\r\n", errno);
11200 }
11201 
11202 /* Discard leading blank lines/redundant titles */
11203 
11204 for (i =0; i < skiplines; i++)
11205     if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11206 
11207 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11208     if (tbuf[0] != '\n')
11209         fputs ("    ", st);
11210     fputs (tbuf, st);
11211     }
11212 fclose (tmp);
11213 #if defined(_WIN32)
11214 remove (tmpnam);
11215 FREE (tmpnam);
11216 #endif /* if defined(_WIN32) */
11217 return;
11218 }
11219 /* Flatten and display help for those who say they prefer it. */
11220 
11221 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11222                                UNIT *uptr, int32 flag,
11223                                TOPIC *topic, va_list ap )
11224 {
11225 size_t i;
11226 
11227 if (topic->flags & HLP_MAGIC_TOPIC) {
11228     (void)fprintf (st, "\r\n%s ", topic->label);
11229     displayMagicTopic (st, dptr, topic);
11230     }
11231 else
11232     (void)fprintf (st, "\r\n%s %s\r\n", topic->label, topic->title);
11233 
11234 /*
11235  * Topic text (for magic topics, follows for explanations)
11236  * It's possible/reasonable for a magic topic to have no text.
11237  */
11238 
11239 if (topic->text)
11240     fputs (topic->text, st);
11241 
11242 for (i = 0; i < topic->kids; i++)
11243     displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11244 
11245 return SCPE_OK;
11246 }
11247 
11248 #define HLP_MATCH_AMBIGUOUS (~0u)
11249 #define HLP_MATCH_WILDCARD  (~1U)
11250 #define HLP_MATCH_NONE      0
11251 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
     /* [previous][next][first][last][top][bottom][index][help] */
11252 {
11253 size_t i, match;
11254 char cbuf[CBUFSIZE], *cptr;
11255 
11256 if (!strcmp (token, "*"))
11257     return HLP_MATCH_WILDCARD;
11258 
11259 match = 0;
11260 for (i = 0; i < topic->kids; i++) {
11261     strcpy (cbuf,topic->children[i]->title +
11262             ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11263     cptr = cbuf;
11264     while (*cptr) {
11265         if (blankch (*cptr)) {
11266             *cptr++ = '_';
11267             }
11268         else {
11269             *cptr = (char)toupper (*cptr);
11270             cptr++;
11271             }
11272         }
11273     if (!strcmp (cbuf, token))      /* Exact Match */
11274         return i+1;
11275     if (!strncmp (cbuf, token, strlen (token))) {
11276         if (match)
11277             return HLP_MATCH_AMBIGUOUS;
11278         match = i+1;
11279         }
11280     }
11281 return match;
11282 }
11283 
11284 /* Main help routine */
11285 
11286 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11287                   UNIT *uptr, int32 flag,
11288                   const char *help, const char *cptr, va_list ap)
11289 {
11290 TOPIC top;
11291 TOPIC *topic = &top;
11292 int failed;
11293 size_t match;
11294 size_t i;
11295 const char *p;
11296 t_bool flat_help = FALSE;
11297 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11298 
11299 static const char attach_help[] = { " ATTACH" };
11300 static const char  brief_help[] = { "%s help.  Type <CR> to exit, HELP for navigation help.\r\n" };
11301 static const char onecmd_help[] = { "%s help.\r\n" };
11302 static const char   help_help[] = {
11303     /****|***********************80 column width guide********************************/
11304     "    To see more HELP information, type the listed subtopic name.  To move\r\n"
11305     "    up a level, just type <CR>.  To review the current subtopic, type \"?\".\r\n"
11306     "    To view all subtopics, type \"*\".  To exit type \"EXIT\", \"^C\", or \"^D\".\r\n\r\n"
11307     };
11308 
11309 (void)memset (&top, 0, sizeof(top));
11310 top.parent = &top;
11311 if ((failed = setjmp (help_env)) != 0) {
11312     (void)fprintf (stderr, "\r\nHELP was unable to process HELP for this device.\r\n"
11313                            "Error in block %u line %u: %s\r\n"
11314                            "%s%*.*s%s\r\n",
11315                    (int)help_where.block, (int)help_where.line, help_where.error,
11316                    help_where.prox ? "Near '" : "",
11317                    help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11318                    help_where.prox ? help_where.prox : "",
11319                    help_where.prox ? "'" : "");
11320     cleanHelp (&top);
11321     return failed;
11322     }
11323 
11324 /* Compile string into navigation tree */
11325 
11326 /* Root */
11327 
11328 if (dptr) {
11329     p = dptr->name;
11330     flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11331     }
11332 else
11333     p = sim_name;
11334 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11335 if (!top.title)
11336   {
11337     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11338                    __func__, __FILE__, __LINE__);
11339 #if defined(USE_BACKTRACE)
11340 # if defined(SIGUSR2)
11341     (void)raise(SIGUSR2);
11342     /*NOTREACHED*/ /* unreachable */
11343 # endif /* if defined(SIGUSR2) */
11344 #endif /* if defined(USE_BACKTRACE) */
11345     abort();
11346   }
11347 for (i = 0; p[i]; i++ )
11348     top.title[i] = (char)toupper (p[i]);
11349 top.title[i] = '\0';
11350 if (flag & SCP_HELP_ATTACH)
11351     strcpy (top.title+i, attach_help);
11352 
11353 top.label = (char *) malloc (sizeof ("1"));
11354 if (!top.label)
11355   {
11356     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11357                    __func__, __FILE__, __LINE__);
11358 #if defined(USE_BACKTRACE)
11359 # if defined(SIGUSR2)
11360     (void)raise(SIGUSR2);
11361     /*NOTREACHED*/ /* unreachable */
11362 # endif /* if defined(SIGUSR2) */
11363 #endif /* if defined(USE_BACKTRACE) */
11364     abort();
11365   }
11366 strcpy (top.label, "1");
11367 
11368 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11369 
11370 if (flat_help) {
11371     flag |= SCP_HELP_FLAT;
11372     if (sim_ttisatty())
11373         (void)fprintf (st, "%s help.\r\nThis help is also available in hierarchical form.\r\n", top.title);
11374     else
11375         (void)fprintf (st, "%s help.\r\n", top.title);
11376     }
11377 else
11378     (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11379 
11380 /* Add text and subtopics */
11381 
11382 (void) buildHelp (&top, dptr, uptr, help, ap);
11383 
11384 /* Go to initial topic if provided */
11385 
11386 while (cptr && *cptr) {
11387     cptr = get_glyph (cptr, gbuf, 0);
11388     if (!gbuf[0])
11389         break;
11390     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11391         (void)fprintf (st, "\r\n");
11392         fputs (help_help, st);
11393         break;
11394         }
11395     match =  matchHelpTopicName (topic, gbuf);
11396     if (match == HLP_MATCH_WILDCARD) {
11397         if (dptr)
11398             displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11399         cleanHelp (&top);
11400         return SCPE_OK;
11401         }
11402     if (match == HLP_MATCH_AMBIGUOUS) {
11403         (void)fprintf (st, "\r\n%s is ambiguous in %s\r\n", gbuf, topic->title);
11404         break;
11405         }
11406     if (match == HLP_MATCH_NONE) {
11407         (void)fprintf (st, "\r\n%s is not available in %s\r\n", gbuf, topic->title);
11408         break;
11409         }
11410     topic = topic->children[match-1];
11411     }
11412 cptr = NULL;
11413 
11414 if (flat_help) {
11415     displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11416     cleanHelp (&top);
11417     return SCPE_OK;
11418     }
11419 
11420 /* Interactive loop displaying help */
11421 
11422 while (TRUE) {
11423     char *pstring;
11424     const char *prompt[2] = {"? ", "Subtopic? "};
11425 
11426     /* Some magic topic names for help from data structures */
11427 
11428     if (topic->flags & HLP_MAGIC_TOPIC) {
11429         fputc ('\n', st);
11430         displayMagicTopic (st, dptr, topic);
11431         }
11432     else
11433         (void)fprintf (st, "\r\n%s\r\n", topic->title);
11434 
11435     /* Topic text (for magic topics, follows for explanations)
11436      * It's possible/reasonable for a magic topic to have no text.
11437      */
11438 
11439     if (topic->text)
11440         fputs (topic->text, st);
11441 
11442     if (topic->kids) {
11443         size_t w = 0;
11444         char *p;
11445         char tbuf[CBUFSIZE];
11446 
11447         (void)fprintf (st, "\r\n    Additional information available:\r\n\r\n");
11448         for (i = 0; i < topic->kids; i++) {
11449             strcpy (tbuf, topic->children[i]->title +
11450                     ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11451             for (p = tbuf; *p; p++) {
11452                 if (blankch (*p))
11453                     *p = '_';
11454                 }
11455             w += 4 + topic->kidwid;
11456             if (w > 80) {
11457                 w = 4 + topic->kidwid;
11458                 fputc ('\r', st);
11459                 fputc ('\n', st);
11460                 }
11461             (void)fprintf (st, "    %-*s", (int32_t)topic->kidwid, tbuf);
11462             }
11463         (void)fprintf (st, "\r\n\r\n");
11464         if (flag & SCP_HELP_ONECMD) {
11465             pstring = helpPrompt (topic, "", TRUE);
11466             (void)fprintf (st, "To view additional topics, type HELP %s topicname\r\n", pstring+1);
11467             FREE (pstring);
11468             break;
11469             }
11470         }
11471 
11472     if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11473         break;
11474 
11475   reprompt:
11476     if (NULL == cptr || !*cptr) {
11477         if (topic->kids == 0)
11478             topic = topic->parent;
11479         pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11480 
11481         cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11482         FREE (pstring);
11483         if ((cptr != NULL) &&                   /* Got something? */
11484             ((0 == strcmp (cptr, "\x04")) ||    /* was it a bare ^D? */
11485              (0 == strcmp (cptr, "\x1A"))))     /* was it a bare ^Z? */
11486             cptr = NULL;                        /* These are EOF synonyms */
11487         }
11488 
11489     if (NULL == cptr)                           /* EOF, exit help */
11490         break;
11491 
11492     cptr = get_glyph (cptr, gbuf, 0);
11493     if (!strcmp (gbuf, "*")) {              /* Wildcard */
11494         displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11495         gbuf[0] = '\0';                     /* Displayed all subtopics, go up */
11496         }
11497     if (!gbuf[0]) {                         /* Blank, up a level */
11498         if (topic->level == 0)
11499             break;
11500         topic = topic->parent;
11501         continue;
11502         }
11503     if (!strcmp (gbuf, "?"))                /* ?, repaint current topic */
11504         continue;
11505     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11506         fputs (help_help, st);
11507         goto reprompt;
11508         }
11509     if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))   /* EXIT (help) */
11510         break;
11511 
11512     /* String - look for that topic */
11513 
11514     if (!topic->kids) {
11515         (void)fprintf (st, "No additional help at this level.\r\n");
11516         cptr = NULL;
11517         goto reprompt;
11518         }
11519     match = matchHelpTopicName (topic, gbuf);
11520     if (match == HLP_MATCH_AMBIGUOUS) {
11521         (void)fprintf (st, "%s is ambiguous, please type more of the topic name\r\n", gbuf);
11522         cptr = NULL;
11523         goto reprompt;
11524         }
11525 
11526     if (match == HLP_MATCH_NONE) {
11527         (void)fprintf (st, "Help for %s is not available\r\n", gbuf);
11528         cptr = NULL;
11529         goto reprompt;
11530         }
11531     /* Found, display subtopic */
11532 
11533     topic = topic->children[match-1];
11534     }
11535 
11536 /* Free structures and return */
11537 
11538 cleanHelp (&top);
11539 
11540 return SCPE_OK;
11541 }
11542 
11543 /* variable argument list shell - most commonly used */
11544 
11545 t_stat scp_help (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11546                  UNIT *uptr, int32 flag,
11547                  const char *help, const char *cptr, ...)
11548 {
11549 t_stat r;
11550 va_list ap;
11551 
11552 va_start (ap, cptr);
11553 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11554 va_end (ap);
11555 
11556 return r;
11557 }
11558 
11559 #if defined(_MSC_VER)
11560 # pragma warning(pop)
11561 #endif

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