root/src/simh/scp.c

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

DEFINITIONS

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

   1 /*
   2  * scp.c: simulator control program
   3  *
   4  * vim: filetype=c:tabstop=4:ai:colorcolumn=84:expandtab
   5  * SPDX-License-Identifier: MIT
   6  * scspell-id: 7cde852c-f62a-11ec-8444-80ee73e9b8e7
   7  *
   8  * ---------------------------------------------------------------------------
   9  *
  10  * Copyright (c) 1993-2022 Robert M. Supnik
  11  * Copyright (c) 2021-2023 Jeffrey H. Johnson
  12  * Copyright (c) 2006-2025 The DPS8M Development Team
  13  *
  14  * Permission is hereby granted, free of charge, to any person obtaining a
  15  * copy of this software and associated documentation files (the "Software"),
  16  * to deal in the Software without restriction, including without limitation
  17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  18  * and/or sell copies of the Software, and to permit persons to whom the
  19  * Software is furnished to do so, subject to the following conditions:
  20  *
  21  * The above copyright notice and this permission notice shall be included in
  22  * all copies or substantial portions of the Software.
  23  *
  24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  27  * ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  28  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  29  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30  * SOFTWARE.
  31  *
  32  * Except as contained in this notice, the name of Robert M. Supnik shall not
  33  * be used in advertising or otherwise to promote the sale, use or other
  34  * dealings in this Software without prior written authorization from
  35  * Robert M. Supnik.
  36  *
  37  * ---------------------------------------------------------------------------
  38  */
  39 
  40 //-V::701
  41 
  42 #if !defined(__EXTENSIONS__)
  43 # define __EXTENSIONS__
  44 #endif
  45 
  46 #if !defined(__STDC_WANT_LIB_EXT1__)
  47 # define __STDC_WANT_LIB_EXT1__ 1
  48 #endif
  49 
  50 #if !defined(_GNU_SOURCE)
  51 # define _GNU_SOURCE
  52 #endif
  53 
  54 /* Macros and data structures */
  55 
  56 #include "sim_defs.h"
  57 #include "sim_disk.h"
  58 #include "sim_tape.h"
  59 #include "sim_sock.h"
  60 
  61 #include <signal.h>
  62 #include <ctype.h>
  63 #include <time.h>
  64 #include <math.h>
  65 #include <stddef.h>
  66 #if defined(_WIN32)
  67 # if !defined(WIN32_LEAN_AND_MEAN)
  68 #  define WIN32_LEAN_AND_MEAN
  69 # endif /* if !defined(WIN32_LEAN_AND_MEAN) */
  70 # if defined(_MSC_VER)
  71 #  pragma warning(push, 3)
  72 # endif
  73 # include <direct.h>
  74 # include <io.h>
  75 # include <fcntl.h>
  76 #else
  77 # include <unistd.h>
  78 # define HAVE_UNISTD 1
  79 #endif
  80 #include <sys/stat.h>
  81 #include <sys/types.h>
  82 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
  83 # include <sys/resource.h>
  84 #endif
  85 #include <setjmp.h>
  86 #include <stdint.h>
  87 #include <limits.h>
  88 #if defined(__APPLE__)
  89 # include <xlocale.h>
  90 #endif
  91 #include <locale.h>
  92 
  93 #include "linehistory.h"
  94 
  95 #if defined(__APPLE__)
  96 # include <sys/sysctl.h>
  97 #endif /* if defined(_APPLE_) */
  98 
  99 #if ( defined(__linux__) || defined(__linux) || defined(_linux) || defined(linux) ) //-V1040
 100 # include <sys/sysinfo.h>
 101 # define LINUX_OS
 102 #endif
 103 
 104 #include <uv.h>
 105 
 106 #if !defined(HAVE_UNISTD)
 107 # undef USE_BACKTRACE
 108 #endif /* if !defined(HAVE_UNISTD) */
 109 
 110 #if defined(USE_BACKTRACE)
 111 # include <string.h>
 112 # include <signal.h>
 113 #endif /* if defined(USE_BACKTRACE) */
 114 
 115 #if defined(__HAIKU__)
 116 # include <OS.h>
 117 #endif /* if defined(__HAIKU__) */
 118 
 119 #if !defined(__CYGWIN__)
 120 # if !defined(__APPLE__)
 121 #  if !defined(_AIX)
 122 #   if !defined(__MINGW32__)
 123 #    if !defined(__MINGW64__)
 124 #     if !defined(CROSS_MINGW32)
 125 #      if !defined(CROSS_MINGW64)
 126 #       if !defined(_WIN32)
 127 #        if !defined(__HAIKU__)
 128 #         if !defined(__QNX__)
 129 #          include <link.h>
 130 #         endif
 131 #        endif
 132 #       endif
 133 #      endif
 134 #     endif
 135 #    endif
 136 #   endif
 137 #  endif
 138 # endif
 139 #endif
 140 
 141 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
 142 # include <windows.h>
 143 #endif
 144 
 145 #if defined(__CYGWIN__)
 146 # include <windows.h>
 147 # include <sys/utsname.h>
 148 # include <sys/cygwin.h>
 149 # include <cygwin/version.h>
 150 #endif
 151 
 152 #define DBG_CTR 0
 153 
 154 #include "../dps8/dps8.h"
 155 #include "../dps8/dps8_cpu.h"
 156 #include "../dps8/ver.h"
 157 
 158 #include "../dps8/dps8_iom.h"
 159 #include "../dps8/dps8_fnp2.h"
 160 
 161 #include "../decNumber/decContext.h"
 162 #include "../decNumber/decNumberLocal.h"
 163 
 164 #include "../dps8/dps8_math128.h"
 165 
 166 #include "../dps8/dps8_sir.h"
 167 
 168 #if !defined(__CYGWIN__)
 169 # if !defined(__APPLE__)
 170 #  if !defined(_AIX)
 171 #   if !defined(__MINGW32__)
 172 #    if !defined(__MINGW64__)
 173 #     if !defined(CROSS_MINGW32)
 174 #      if !defined(CROSS_MINGW64)
 175 #       if !defined(_WIN32)
 176 #        if !defined(__HAIKU__)
 177 #         if !defined(__QNX__)
 178 static unsigned int dl_iterate_phdr_callback_called = 0;
 179 #         endif
 180 #        endif
 181 #       endif
 182 #      endif
 183 #     endif
 184 #    endif
 185 #   endif
 186 #  endif
 187 # endif
 188 #endif
 189 
 190 #if defined(MAX)
 191 # undef MAX
 192 #endif /* if defined(MAX) */
 193 #define MAX(a,b)  (((a) >= (b)) ? (a) : (b))
 194 
 195 #if defined(FREE)
 196 # undef FREE
 197 #endif /* if defined(FREE) */
 198 #define FREE(p) do  \
 199   {                 \
 200     free((p));      \
 201     (p) = NULL;     \
 202   } while(0)
 203 
 204 /* search logical and boolean ops */
 205 
 206 #define SCH_OR          0                               /* search logicals */
 207 #define SCH_AND         1
 208 #define SCH_XOR         2
 209 #define SCH_E           0                               /* search booleans */
 210 #define SCH_N           1
 211 #define SCH_G           2
 212 #define SCH_L           3
 213 #define SCH_EE          4
 214 #define SCH_NE          5
 215 #define SCH_GE          6
 216 #define SCH_LE          7
 217 
 218 #define MAX_DO_NEST_LVL 20                              /* DO cmd nesting level */
 219 #define SRBSIZ          1024                            /* save/restore buffer */
 220 #define SIM_BRK_INILNT  4096                            /* bpt tbl length */
 221 #define SIM_BRK_ALLTYP  0xFFFFFFFB
 222 
 223 #define UPDATE_SIM_TIME                                         \
 224     if (1) {                                                    \
 225         int32 _x;                                               \
 226         if (sim_clock_queue == QUEUE_LIST_END)                  \
 227             _x = noqueue_time;                                  \
 228         else                                                    \
 229             _x = sim_clock_queue->time;                         \
 230         sim_time = sim_time + (_x - sim_interval);              \
 231         sim_rtime = sim_rtime + ((uint32) (_x - sim_interval)); \
 232         if (sim_clock_queue == QUEUE_LIST_END)                  \
 233             noqueue_time = sim_interval;                        \
 234         else                                                    \
 235             sim_clock_queue->time = sim_interval;               \
 236         }                                                       \
 237     else                                                        \
 238         (void)0
 239 
 240 #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
 241 
 242 #define SZ_R(rp) \
 243     (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
 244 
 245 #define SZ_LOAD(sz,v,mb,j)                                                 \
 246     if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j));        \
 247     else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \
 248     else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \
 249     else v = *(((t_uint64 *) mb) + ((uint32) j));
 250 
 251 #define SZ_STORE(sz,v,mb,j)                                                         \
 252     if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v;                    \
 253     else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \
 254     else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \
 255     else *(((t_uint64 *) mb) + ((uint32) j)) = v;
 256 
 257 #define GET_SWITCHES(cp) \
 258     if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
 259 
 260 #define GET_RADIX(val,dft)                          \
 261     if (sim_switches & SWMASK ('O')) val = 8;       \
 262     else if (sim_switches & SWMASK ('D')) val = 10; \
 263     else if (sim_switches & SWMASK ('H')) val = 16; \
 264     else val = dft;
 265 
 266 /*
 267  * The per-simulator init routine is a weak global that defaults to NULL
 268  * The other per-simulator pointers can be overridden by the init routine
 269  */
 270 
 271 t_bool sim_asynch_enabled = FALSE;
 272 t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
 273 t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
 274 extern void (*sim_vm_init) (void);
 275 extern void (*sim_vm_exit) (void);
 276 char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL;
 277 void (*sim_vm_post) (t_bool from_scp) = NULL;
 278 CTAB *sim_vm_cmd = NULL;
 279 void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr) = NULL;
 280 void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL;
 281 t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr) = NULL;
 282 t_value (*sim_vm_pc_value) (void) = NULL;
 283 t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs) = NULL;
 284 t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL;
 285 unsigned int nprocs;
 286 
 287 /* Prototypes */
 288 
 289 /* Set and show command processors */
 290 
 291 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 292 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 293 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 294 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 295 t_stat ssh_break (FILE *st, const char *cptr, int32 flg);
 296 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr);
 297 t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 298 t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 299 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 300 t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 301 t_stat show_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 302 t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 303 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 304 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 305 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 306 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 307 t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 308 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 309 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cprr);
 310 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 311 t_stat show_default_base_system_script (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 312 t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 313 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 314 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 315 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 316 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 317 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag);
 318 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag);
 319 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg, int32 *toks);
 320 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, CONST char *cptr, int32 flag);
 321 t_stat sim_save (FILE *sfile);
 322 t_stat sim_rest (FILE *rfile);
 323 
 324 /* Breakpoint package */
 325 
 326 t_stat sim_brk_init (void);
 327 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act);
 328 t_stat sim_brk_clr (t_addr loc, int32 sw);
 329 t_stat sim_brk_clrall (int32 sw);
 330 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw);
 331 t_stat sim_brk_showall (FILE *st, uint32 sw);
 332 CONST char *sim_brk_getact (char *buf, int32 size);
 333 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp);
 334 char *sim_brk_clract (void);
 335 
 336 FILE *stdnul;
 337 
 338 /* Command support routines */
 339 
 340 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 341 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr);
 342 int32 test_search (t_value *val, SCHTAB *schptr);
 343 static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char);
 344 int32 get_switches (const char *cptr);
 345 CONST char *get_sim_sw (CONST char *cptr);
 346 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
 347 t_value get_rval (REG *rptr, uint32 idx);
 348 void put_rval (REG *rptr, uint32 idx, t_value val);
 349 void fprint_help (FILE *st);
 350 void fprint_stopped (FILE *st, t_stat r);
 351 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
 352 void fprint_sep (FILE *st, int32 *tokens);
 353 char *read_line (char *ptr, int32 size, FILE *stream);
 354 char *read_line_p (const char *prompt, char *ptr, int32 size, FILE *stream);
 355 REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
 356 char *sim_trim_endspc (char *cptr);
 357 
 358 /* Forward references */
 359 
 360 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr);
 361 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr);
 362 t_bool qdisable (DEVICE *dptr);
 363 t_stat attach_err (UNIT *uptr, t_stat stat);
 364 t_stat detach_all (int32 start_device, t_bool shutdown);
 365 t_stat assign_device (DEVICE *dptr, const char *cptr);
 366 t_stat deassign_device (DEVICE *dptr);
 367 t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr);
 368 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
 369     REG *lowr, REG *highr, uint32 lows, uint32 highs);
 370 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx);
 371 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx);
 372 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
 373     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr);
 374 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
 375 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
 376     UNIT *uptr, int32 dfltinc);
 377 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
 378 t_stat step_svc (UNIT *ptr);
 379 t_stat expect_svc (UNIT *ptr);
 380 t_stat set_on (int32 flag, CONST char *cptr);
 381 t_stat set_verify (int32 flag, CONST char *cptr);
 382 t_stat set_message (int32 flag, CONST char *cptr);
 383 t_stat set_quiet (int32 flag, CONST char *cptr);
 384 t_stat set_localopc (int32 flag, CONST char *cptr);
 385 t_stat set_asynch (int32 flag, CONST char *cptr);
 386 t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
 387 t_stat do_cmd_label (int32 flag, CONST char *cptr, CONST char *label);
 388 void int_handler (int signal);
 389 t_stat set_prompt (int32 flag, CONST char *cptr);
 390 t_stat sim_set_asynch (int32 flag, CONST char *cptr);
 391 t_stat sim_set_environment (int32 flag, CONST char *cptr);
 392 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr);
 393 
 394 /* Global data */
 395 
 396 DEVICE *sim_dflt_dev             = NULL;
 397 UNIT *sim_clock_queue            = QUEUE_LIST_END;
 398 int32 sim_interval               = 0;
 399 int32 sim_switches               = 0;
 400 FILE *sim_ofile                  = NULL;
 401 SCHTAB *sim_schrptr              = NULL;
 402 SCHTAB *sim_schaptr              = NULL;
 403 DEVICE *sim_dfdev                = NULL;
 404 UNIT *sim_dfunit                 = NULL;
 405 DEVICE **sim_internal_devices    = NULL;
 406 uint32 sim_internal_device_count = 0;
 407 int32 sim_opt_out                = 0;
 408 int32 sim_is_running             = 0;
 409 t_bool sim_processing_event      = FALSE;
 410 uint32 sim_brk_summ              = 0;
 411 uint32 sim_brk_types             = 0;
 412 BRKTYPTAB *sim_brk_type_desc     = NULL;         /* type descriptions */
 413 uint32 sim_brk_dflt              = 0;
 414 uint32 sim_brk_match_type;
 415 t_addr sim_brk_match_addr;
 416 char *sim_brk_act[MAX_DO_NEST_LVL];
 417 char *sim_brk_act_buf[MAX_DO_NEST_LVL];
 418 BRKTAB **sim_brk_tab             = NULL;
 419 int32 sim_brk_ent                = 0;
 420 int32 sim_brk_lnt                = 0;
 421 int32 sim_brk_ins                = 0;
 422 int32 sim_iglock                 = 0;
 423 int32 sim_nolock                 = 0;
 424 int32 sim_quiet                  = 0;
 425 int32 sim_localopc               = 1;
 426 int32 sim_randompst              = 0;
 427 int32 sim_randstate              = 0;
 428 int32 sim_step                   = 0;
 429 int nodist                       = 0;
 430 #if defined(PERF_STRIP)
 431 int32 sim_nostate                = 1;
 432 #else
 433 int32 sim_nostate                = 0;
 434 #endif /* if defined(PERF_STRIP) */
 435 static double sim_time;
 436 static uint32 sim_rtime;
 437 static int32 noqueue_time;
 438 volatile int32 stop_cpu          = 0;
 439 t_value *sim_eval                = NULL;
 440 static t_value sim_last_val;
 441 static t_addr sim_last_addr;
 442 FILE *sim_log                    = NULL;         /* log file */
 443 FILEREF *sim_log_ref             = NULL;         /* log file file reference */
 444 FILE *sim_deb                    = NULL;         /* debug file */
 445 FILEREF *sim_deb_ref             = NULL;         /* debug file file reference */
 446 int32 sim_deb_switches           = 0;            /* debug switches */
 447 struct timespec sim_deb_basetime;                /* debug timestamp relative base time */
 448 char *sim_prompt                 = NULL;         /* prompt string */
 449 static FILE *sim_gotofile;                       /* the currently open do file */
 450 static int32 sim_goto_line[MAX_DO_NEST_LVL+1];   /* the current line number in the currently open do file */
 451 static int32 sim_do_echo         = 0;            /* the echo status of the currently open do file */
 452 static int32 sim_show_message    = 1;            /* the message display status of the currently open do file */
 453 static int32 sim_on_inherit      = 0;            /* the inherit status of on state and conditions when executing do files */
 454 static int32 sim_do_depth        = 0;
 455 
 456 static int32 sim_on_check[MAX_DO_NEST_LVL+1];
 457 static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
 458 static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
 459 static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
 460 static const char *sim_do_label[MAX_DO_NEST_LVL+1];
 461 
 462 t_stat sim_last_cmd_stat;                        /* Command Status */
 463 
 464 static SCHTAB sim_stabr;                         /* Register search specifier */
 465 static SCHTAB sim_staba;                         /* Memory search specifier */
 466 
 467 static UNIT sim_step_unit   = { UDATA (&step_svc, 0, 0)  };
 468 static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0)  };
 469 
 470 /* Tables and strings */
 471 
 472 const char save_vercur[] = "V4.1";
 473 const char save_ver40[]  = "V4.0";
 474 const char save_ver35[]  = "V3.5";
 475 const char save_ver32[]  = "V3.2";
 476 const char save_ver30[]  = "V3.0";
 477 const struct scp_error {
 478     const char *code;
 479     const char *message;
 480     } scp_errors[1+SCPE_MAX_ERR-SCPE_BASE] =
 481         {{"NXM",     "Address space exceeded"},
 482          {"UNATT",   "Unit not attached"},
 483          {"IOERR",   "I/O error"},
 484          {"CSUM",    "Checksum error"},
 485          {"FMT",     "Format error"},
 486          {"NOATT",   "Unit not attachable"},
 487          {"OPENERR", "File open error"},
 488          {"MEM",     "Memory exhausted"},
 489          {"ARG",     "Invalid argument"},
 490          {"STEP",    "Step expired"},
 491          {"UNK",     "Unknown command"},
 492          {"RO",      "Read only argument"},
 493          {"INCOMP",  "Command not completed"},
 494          {"STOP",    "Simulation stopped"},
 495          {"EXIT",    "Goodbye"},
 496          {"TTIERR",  "Console input I/O error"},
 497          {"TTOERR",  "Console output I/O error"},
 498          {"EOF",     "End of file"},
 499          {"REL",     "Relocation error"},
 500          {"NOPARAM", "No settable parameters"},
 501          {"ALATT",   "Unit already attached"},
 502          {"TIMER",   "Hardware timer error"},
 503          {"SIGERR",  "Signal handler setup error"},
 504          {"TTYERR",  "Console terminal setup error"},
 505          {"SUB",     "Subscript out of range"},
 506          {"NOFNC",   "Command not allowed"},
 507          {"UDIS",    "Unit disabled"},
 508          {"NORO",    "Read only operation not allowed"},
 509          {"INVSW",   "Invalid switch"},
 510          {"MISVAL",  "Missing value"},
 511          {"2FARG",   "Too few arguments"},
 512          {"2MARG",   "Too many arguments"},
 513          {"NXDEV",   "Non-existent device"},
 514          {"NXUN",    "Non-existent unit"},
 515          {"NXREG",   "Non-existent register"},
 516          {"NXPAR",   "Non-existent parameter"},
 517          {"NEST",    "Nested DO command limit exceeded"},
 518          {"IERR",    "Internal error"},
 519          {"MTRLNT",  "Invalid magtape record length"},
 520          {"LOST",    "Console Telnet connection lost"},
 521          {"TTMO",    "Console Telnet connection timed out"},
 522          {"STALL",   "Console Telnet output stall"},
 523          {"AFAIL",   "Assertion failed"},
 524          {"INVREM",  "Invalid remote console command"},
 525          {"NOTATT",  "Not attached"},
 526          {"EXPECT",  "Expect matched"},
 527          {"REMOTE",  "Remote console command"},
 528     };
 529 
 530 const size_t size_map[] = { sizeof (int8),
 531     sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
 532     , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64)
 533 };
 534 
 535 const t_value width_mask[] = { 0,
 536     0x1, 0x3, 0x7, 0xF,
 537     0x1F, 0x3F, 0x7F, 0xFF,
 538     0x1FF, 0x3FF, 0x7FF, 0xFFF,
 539     0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
 540     0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
 541     0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
 542     0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
 543     0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
 544     0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
 545     0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
 546     0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
 547     0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
 548     0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
 549     0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
 550     0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
 551     0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
 552     };
 553 
 554 static const char simh_help[] =
 555        /***************** 80 character line width template *************************/
 556       "1Commands\n"
 557 #define HLP_RESET       "*Commands Resetting Devices"
 558        /***************** 80 character line width template *************************/
 559       "2Resetting Devices\n"
 560       " The `RESET` command (*abbreviated* `RE`) resets a device or the entire\n"
 561       " simulator to a predefined condition.  If the switch \"`-p`\" is specified,\n"
 562       " the device is reset to its initial power-on state:\n\n"
 563       "++RESET                  resets all devices\n"
 564       "++RESET -p               power-cycle all devices\n"
 565       "++RESET ALL              resets all devices\n"
 566       "++RESET <device>         resets the specified <device>\n\n"
 567       " * Typically, `RESET` *aborts* in-progress I/O operations, *clears* any\n"
 568       " interrupt requests, and returns the device to a quiescent state.\n\n"
 569       " * It does **NOT** clear the main memory or affect associated I/O\n"
 570       " connections.\n"
 571 #define HLP_EXAMINE     "*Commands Examining_and_Changing_State"
 572 #define HLP_IEXAMINE    "*Commands Examining_and_Changing_State"
 573 #define HLP_DEPOSIT     "*Commands Examining_and_Changing_State"
 574 #define HLP_IDEPOSIT    "*Commands Examining_and_Changing_State"
 575        /***************** 80 character line width template *************************/
 576       "2Examining and Changing State\n"
 577       " There are four commands to examine and change state:\n\n"
 578       " * `EXAMINE` (*abbreviated* `E`) examines state\n"
 579       " * `DEPOSIT` (*abbreviated* `D`) changes state\n"
 580       " * `IEXAMINE` (\"interactive examine\", *abbreviated* `IE`) examines state\n"
 581       "    and allows the user to interactively change it\n"
 582       " * `IDEPOSIT` (interactive deposit, *abbreviated* `ID`) allows the user to\n"
 583       "    interactively change state\n\n"
 584       " All four commands take the form:\n\n"
 585       "++command {modifiers} <object list>\n\n"
 586       " The `DEPOSIT` command requires the deposit value at the end of the command.\n\n"
 587       " There are four kinds of modifiers: **switches**, **device/unit name**,\n"
 588       " **search specifier**, and for `EXAMINE`, **output file**.\n\n"
 589       " * **Switches** have been described previously.\n"
 590       " * A **device/unit name** identifies the device and unit whose address\n"
 591       " space is to be examined or modified. If no device is specified, the CPU\n"
 592       " main memory is selected. If a device but no unit is specified, unit `0`\n"
 593       " of the specified device is selected automatically.\n"
 594       " * The **search specifier** provides criteria for testing addresses or\n"
 595       " registers to see if they should be processed.  The search specifier\n"
 596       " consists of a \"<`logical operator`>\", a \"<`relational operator`>\", or\n"
 597       " both, optionally separated by spaces:\n\n"
 598       "++{ < logical op >  < value > }  < relational op >  < value >\n\n"
 599        /***************** 80 character line width template *************************/
 600       " * * The \"<`logical operator`>\" may be \"`&`\" (*and*), \"`|`\" (*or*),\n"
 601       " or \"`^`\" (*exclusive or*), and the \"<`relational operator`>\" may\n"
 602       " be \"`=`\" or \"`==`\" (*equal*), \"`!`\" or \"`!=`\" (*not\n"
 603       " equal*), \">=\" (*greater than or equal*), \">\" (*greater\n"
 604       " than*), \"<=\" (*less than or equal*), or \"<\" (*less than*).\n"
 605       " * * If any \"<`logical operator`>\" is specified without\n"
 606       " a \"<`relational operator`>\", it is ignored.\n"
 607       " * * If any \"<`relational operator`>\" is specified without\n"
 608       " a \"<`logical operator`>\", no logical operation is performed.\n"
 609       " * * All comparisons are unsigned.\n\n"
 610       " * The **output file** modifier redirects the command output to a file\n"
 611       " instead of the console.  The **output file** modifier is specified with\n"
 612       " the \"`@`\" (*commercial-at*) character, followed by a valid file name.\n\n"
 613       " **NOTE**: Modifiers may be specified in any order.  If multiple\n"
 614       " modifiers of the same type are specified, later modifiers override earlier\n"
 615       " modifiers. If the **device/unit name** comes *after* the search specifier,\n"
 616       " the search values will interpreted in the *radix of the CPU*, rather than\n"
 617       " of the device/unit.\n\n"
 618       " The \"<`object list`>\" argument consists of one or more of the following,\n"
 619       " separated by commas:\n\n"
 620        /***************** 80 character line width template *************************/
 621       "++register                the specified register\n"
 622       "++register[sub1-sub2]     the specified register array locations,\n"
 623       "++++++++                  starting at location sub1 up to and\n"
 624       "++++++++                  including location sub2\n"
 625       "++register[sub1/length]   the specified register array locations,\n"
 626       "++++++++                  starting at location sub1 up to but\n"
 627       "++++++++                  not including sub1+length\n"
 628       "++register[ALL]           all locations in the specified register\n"
 629       "++++++++                  array\n"
 630       "++register1-register2     all the registers starting at register1\n"
 631       "++++++++                  up to and including register2\n"
 632       "++address                 the specified location\n"
 633       "++address1-address2       all locations starting at address1 up to\n"
 634       "++++++++                  and including address2\n"
 635       "++address/length          all location starting at address up to\n"
 636       "++++++++                  but not including address+length\n"
 637       "++STATE                   all registers in the device\n"
 638       "++ALL                     all locations in the unit\n"
 639       "++$                       the last value displayed by an EXAMINE\n"
 640       "++++++++                  command interpreted as an address\n"
 641       "3Switches\n"
 642       "4Formatting Control\n"
 643       " Switches can be used to control the format of the displayed information:\n\n"
 644        /***************** 80 character line width template *************************/
 645       "5-a\n"
 646       " display as ASCII\n"
 647       "5-c\n"
 648       " display as character string\n"
 649       "5-m\n"
 650       " display as instruction mnemonics\n"
 651       "5-o\n"
 652       " display as octal\n"
 653       "5-d\n"
 654       " display as decimal\n"
 655       "5-h\n"
 656       " display as hexadecimal\n\n"
 657       "3Examples\n"
 658       "++ex 1000-1100                examine 1000 to 1100\n"
 659       "++de PC 1040                  set PC to 1040\n"
 660       "++ie 40-50                    interactively examine 40:50\n"
 661       "++ie >1000 40-50              interactively examine the subset\n"
 662       "+++++++++                     of locations 40:50 that are >1000\n"
 663       "++ex rx0 50060                examine 50060, RX unit 0\n"
 664       "++ex rx sbuf[3-6]             examine SBUF[3] to SBUF[6] in RX\n"
 665       "++de all 0                    set main memory to 0\n"
 666       "++de &77>0 0                  set all addresses whose low order\n"
 667       "+++++++++                     bits are non-zero to 0\n"
 668       "++ex -m @memdump.txt 0-7777   dump memory to file\n\n"
 669       " * **NOTE**: To terminate an interactive command, simply type any bad value\n"
 670       "           (*e.g.* `XYZ`) when input is requested.\n"
 671 #define HLP_EVALUATE    "*Commands Evaluating_Instructions"
 672        /***************** 80 character line width template *************************/
 673       "2Evaluating Instructions\n"
 674       " The `EVAL` command evaluates a symbolic expression and returns the\n"
 675       " equivalent numeric value.\n\n"
 676        /***************** 80 character line width template *************************/
 677       "2Running A Simulated Program\n"
 678 #define HLP_RUN         "*Commands Running_A_Simulated_Program RUN"
 679       "3RUN\n"
 680       " The `RUN` command (*abbreviated* `RU`) resets all devices, deposits its\n"
 681       " argument, if given, in the PC (program counter), and starts execution.\n"
 682       " If no argument is given execution starts at the current PC.\n"
 683 #define HLP_GO          "*Commands Running_A_Simulated_Program GO"
 684       "3GO\n"
 685       " The `GO` command does *not* reset devices, deposits its argument (if\n"
 686       " given) in the PC, and starts execution.  If no argument is given,\n"
 687       " execution starts at the current PC (program counter).\n"
 688 #define HLP_CONTINUE    "*Commands Running_A_Simulated_Program Continuing_Execution"
 689       "3Continuing Execution\n"
 690       " The `CONTINUE` command (*abbreviated* `CONT` or `CO`) resumes execution\n"
 691       " (if execution was stopped, possibly due to hitting a breakpoint) at the\n"
 692       " current program counter without resetting any devices.\n"
 693 #define HLP_STEP        "*Commands Running_A_Simulated_Program Step_Execution"
 694       "3Step Execution\n"
 695       " The `STEP` command (*abbreviated* `S`) resumes execution at the current\n"
 696       " PC for the number of instructions given by its argument.  If no argument\n"
 697       " is supplied, one instruction is executed.\n"
 698       "4Switches\n"
 699       "5`-T`\n"
 700       " If the `STEP` command is invoked with the \"`-T`\" switch, the step\n"
 701       " command will cause execution to run for *microseconds* rather than\n"
 702       " instructions.\n"
 703 #define HLP_NEXT        "*Commands Running_A_Simulated_Program NEXT"
 704       "3NEXT\n"
 705       " The `NEXT` command (*abbreviated* `N`) resumes execution at the current PC\n"
 706       " for one instruction, attempting to execute *through* subroutine calls.\n"
 707       " If the next instruction to be executed is *not* a subroutine call, then\n"
 708       " one instruction is executed.\n"
 709 #define HLP_BOOT        "*Commands Running_A_Simulated_Program Booting_the_system"
 710       "3Booting the system\n"
 711       " The `BOOT` command (*abbreviated* `BO`) resets all devices and bootstraps\n"
 712       " the device and unit given by its argument. If no unit is supplied,\n"
 713       " unit `0` is bootstrapped.  The specified unit must be `ATTACH`'ed.\n\n"
 714       " When booting Multics, the boot device should always be `iom0`.\n"
 715       " Assuming a tape is attached to the `tape0` device, it will be bootstrapped\n"
 716       " into memory and the system will transfer control to the boot record.\n\n"
 717       " **Example**\n\n"
 718       "++; Boot Multics using iom0\n"
 719       "++boot iom0\n\n"
 720        /***************** 80 character line width template *************************/
 721       "2Stopping The Simulator\n"
 722       " The simulator runs until the simulated hardware encounters an error, or\n"
 723       " until the user forces a stop condition.\n"
 724       "3Simulator Detected Stop Conditions\n"
 725       " These simulator-detected conditions stop simulation:\n\n"
 726       "++-  HALT instruction.  If a HALT instruction is decoded, simulation stops.\n\n"
 727       "++-  I/O error.  If an I/O error occurs during simulation of an I/O\n"
 728       "+++operation, and the device stop-on-I/O-error flag is set, simulation\n"
 729       "+++usually stops.\n\n"
 730       "++-  Processor condition.  Certain processor conditions can stop\n"
 731       "+++the simulation.\n"
 732       "3User Specified Stop Conditions\n"
 733       " Typing the interrupt character stops simulation.  The interrupt character\n"
 734       " is defined by the `WRU` (*Where aRe yoU*) console option, and is initially\n"
 735       " set to `005` (`^E`).\n\n"
 736        /***************** 80 character line width template *************************/
 737 #define HLP_BREAK       "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 738 #define HLP_NOBREAK     "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions BREAK"
 739       "4Breakpoints\n"
 740       " The simulator offers breakpoint capability for debugging. Users may define\n"
 741       " breakpoints of different types, identified by letter (for example, `E`\n"
 742       " for *execution*, `R` for *read*, `W` for *write*, etc).\n\n"
 743       " Associated with each breakpoint is a count and, optionally, one or more\n"
 744       " actions.  Each time a breakpoint occurs, the associated count\n"
 745       " is *decremented*.  If the count is less than or equal to `0`, the breakpoint\n"
 746       " occurs; otherwise, it is deferred.  When the breakpoint occurs, any\n"
 747       " optional actions are automatically executed.\n\n"
 748       " A breakpoint is set by the `BREAK` (or `SET BREAK`) command:\n\n"
 749       "++BREAK {-types} {<addr range>{[count]},{addr range...}}{;action;action...}\n\n"
 750       " If no type is specified, the default breakpoint type (`E`, *execution*) is\n"
 751       " used.  If no address range is specified, the current PC is used.  As\n"
 752       " with `EXAMINE` and `DEPOSIT`, an address range may be a single address, a\n"
 753       " range of addresses low-high, or a relative range of address/length.\n"
 754        /***************** 80 character line width template *************************/
 755       "5Displaying Breakpoints\n"
 756       " Currently set breakpoints can be displayed with the `SHOW BREAK` command:\n\n"
 757       "++SHOW {-C} {-types} BREAK {ALL|<addr range>{,<addr range>...}}\n\n"
 758       " Locations with breakpoints of the specified type are displayed.\n\n"
 759       " The \"`-C`\" switch displays the selected breakpoint(s) formatted as\n"
 760       " commands which may be subsequently used to establish the same\n"
 761       " breakpoint(s).\n\n"
 762       "5Removing Breakpoints\n"
 763       " Breakpoints can be cleared by the `NOBREAK` or the `SET NOBREAK` commands.\n"
 764       "5Examples\n"
 765       " The following examples illustrate breakpoint usage:\n\n"
 766       "++BREAK                      set E break at current PC\n"
 767       "++BREAK -e 200               set E break at 200\n"
 768       "++BREAK 2000/2[2]            set E breaks at 2000,2001 with count = 2\n"
 769       "++BREAK 100;EX AC;D MQ 0     set E break at 100 with actions EX AC and\n"
 770       "+++++++++D MQ 0\n"
 771       "++BREAK 100;                 delete action on break at 100\n\n"
 772        /***************** 80 character line width template *************************/
 773       "2Connecting and Disconnecting Devices\n"
 774       " Units are simulated as files on the host file system.  Before using any\n"
 775       " simulated unit, the user must specify the file to be accessed by that unit.\n"
 776 #define HLP_ATTACH      "*Commands Connecting_and_Disconnecting_Devices Attaching_devices"
 777       "3Attaching devices\n"
 778       " The `ATTACH` (*abbreviation* `AT`) command associates a unit and a file:\n\n"
 779       "++ATTACH <unit> <filename>\n\n"
 780       " Some devices have more detailed or specific help available with:\n\n"
 781       "++HELP <device> ATTACH\n\n"
 782       "4Switches\n"
 783       "5-n\n"
 784       " If the \"`-n`\" switch is specified when `ATTACH` is executed, a new\n"
 785       " file will be created when the filename specified does not exist, or an\n"
 786       " existing file will have it's size truncated to zero, and an appropriate\n"
 787       " message is printed.\n"
 788       "5-e\n"
 789       " If the file does not exist, and the \"`-e`\" switch *was not* specified,\n"
 790       " a new file is created, and an appropriate message is printed.  If\n"
 791       " the \"`-e`\" switch *was* specified, a new file is *not* created, and an\n"
 792       " error message is printed.\n"
 793       "5-r\n"
 794       " If the \"`-r`\" switch is specified, or the file is write protected by\n"
 795       " host operating system, `ATTACH` tries to open the file in read only mode.\n"
 796       " If the file does not exist, or the unit does not support read only\n"
 797       " operation, an error occurs.  Input-only devices, such as card readers, or\n"
 798       " storage devices with write locking switches, such as disks or tapes,\n"
 799       " support read only operation - other devices do not.  If a file is\n"
 800       " attached read only, its contents can be examined but not modified.\n"
 801       "5-q\n"
 802       " If the \"`-q`\" switch is specified when creating a new file (\"`-n`\")\n"
 803       " or opening one read only (\"`-r`\"), the message announcing this fact\n"
 804       " is suppressed.\n"
 805       "5-f\n"
 806       " For simulated magnetic tapes, the `ATTACH` command can specify the format\n"
 807       " of the attached tape image file:\n\n"
 808       "++ATTACH -f <tape_unit> <format> <filename>\n\n"
 809       " * The currently supported magnetic tape image file formats are:\n\n"
 810       " |                  |                                                      |\n"
 811       " | ----------------:|:---------------------------------------------------- |\n"
 812       " | \"**`SIMH`**\"   | The **SIMH** / **DPS8M** native portable tape format |\n"
 813       " | \"**`E11`**\"    | The *D Bit* **Ersatz-11** simulator format           |\n"
 814       " | \"**`TPC`**\"    | The **TPC** format (*used by _SIMH_ prior to V2.3*)  |\n"
 815       " | \"**`P7B`**\"    | The **Paul Pierce** `7`-track tape archive format    |\n\n"
 816        /***************** 80 character line width template *************************/
 817       " * The default tape format can also be specified with the `SET` command\n"
 818       " prior to using the `ATTACH` command:\n\n"
 819       "++SET <tape_unit> FORMAT=<format>\n"
 820       "++ATTACH <tape_unit> <filename>\n\n"
 821       " * The format of a currently attached tape image can be displayed with\n"
 822       "   the `SHOW FORMAT` command:\n\n"
 823       "++SHOW <unit> FORMAT\n\n"
 824       " **Examples**\n\n"
 825       " The following example illustrates common `ATTACH` usage:\n"
 826       "++; Associate the tape image file \"12.7MULTICS.tap\" with the tape0 unit\n"
 827       "++; in read-only mode, where tape0 corresponds to the first tape device.\n"
 828       "++ATTACH -r tape0 12.7MULTICS.tap\n\n"
 829       "++; Associate the disk image file \"root.dsk\" with the disk0 unit.\n"
 830       "++; The disk0 unit corresponds to the first disk device.\n"
 831       "++ATTACH disk0 root.dsk\n\n"
 832        /***************** 80 character line width template *************************/
 833 #define HLP_DETACH      "*Commands Connecting_and_Disconnecting_Devices Detaching_devices"
 834       "3Detaching devices\n"
 835       " The `DETACH` (*abbreviation* `DET`) command breaks the association between\n"
 836       " a unit and its backing file or device:\n\n"
 837       "++DETACH ALL             Detach all units\n"
 838       "++DETACH <unit>          Detach specified unit\n\n"
 839       " * **NOTE:** The `EXIT` command performs an automatic `DETACH ALL`.\n"
 840 #define HLP_SET         "*Commands SET"
 841       "2SET\n"
 842        /***************** 80 character line width template *************************/
 843 #define HLP_SET_LOG    "*Commands SET Logging"
 844       "3Logging\n"
 845       " Interactions with the simulator session can be recorded to a log file.\n\n"
 846       "+SET LOG log_file            Specify the log destination\n"
 847       "++++++++                     (STDOUT, DEBUG, or filename)\n"
 848       "+SET NOLOG                   Disables any currently active logging\n"
 849       "4Switches\n"
 850       "5`-N`\n"
 851       " By default, log output is written at the *end* of the specified log file.\n"
 852       " A new log file can created if the \"`-N`\" switch is used on the command\n"
 853       " line.\n\n"
 854       "5`-B`\n"
 855       " By default, log output is written in *text* mode.  The log file can be\n"
 856       " opened for *binary* mode writing if the \"`-B`\" switch is used on the\n"
 857       " command line.\n"
 858 #define HLP_SET_DEBUG  "*Commands SET Debug_Messages"
 859        /***************** 80 character line width template *************************/
 860       "3Debug Messages\n"
 861       "+SET DEBUG debug_file        Specify the debug destination\n"
 862       "++++++++                     (STDOUT, STDERR, LOG, or filename)\n"
 863       "+SET NODEBUG                 Disables any currently active debug output\n"
 864       "4Switches\n"
 865       " Debug message output contains a timestamp which indicates the number of\n"
 866       " simulated instructions which have been executed prior to the debug event.\n\n"
 867       " Debug message output can be enhanced to contain additional, potentially\n"
 868       " useful information.\n\n\n"
 869       " **NOTE**: If neither \"`-T`\" or \"`-A`\" is specified, \"`-T`\" is implied.\n"
 870       "5-T\n"
 871       " The \"`-T`\" switch causes debug output to contain a time of day displayed\n"
 872       " as `hh:mm:ss.msec`.\n"
 873       "5-A\n"
 874       " The \"`-A`\" switch causes debug output to contain a time of day displayed\n"
 875       " as `seconds.msec`.\n"
 876       "5-R\n"
 877       " The \"`-R`\" switch causes timing to be relative to the start of debugging.\n"
 878       "5-P\n"
 879       " The \"`-P`\" switch adds the output of the PC (program counter) to each\n"
 880       " debug message.\n"
 881       "5-N\n"
 882       " The \"`-N`\" switch causes a new (empty) file to be written to.\n"
 883       " (The default is to append to an existing debug log file).\n"
 884       "5-D\n"
 885       " The \"`-D`\" switch causes data blob output to also display the data\n"
 886       " as **`RADIX-50`** characters.\n"
 887       "5-E\n"
 888       " The \"`-E`\" switch causes data blob output to also display the data\n"
 889       " as \"**EBCDIC**\" characters.\n"
 890        /***************** 80 character line width template *************************/
 891 #define HLP_SET_ENVIRON "*Commands SET Environment_Variables"
 892       "3Environment Variables\n"
 893       "+SET ENVIRONMENT NAME=val    Set environment variable\n"
 894       "+SET ENVIRONMENT NAME        Clear environment variable\n"
 895 #define HLP_SET_ON      "*Commands SET Command_Status_Trap_Dispatching"
 896       "3Command Status Trap Dispatching\n"
 897       "+SET ON                      Enables error checking command execution\n"
 898       "+SET NOON                    Disables error checking command execution\n"
 899       "+SET ON INHERIT              Enables inheritance of ON state and actions\n"
 900       "+SET ON NOINHERIT            Disables inheritance of ON state and actions\n"
 901 #define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
 902       "3Command Execution Display\n"
 903       "+SET VERIFY                  Enables display of processed script commands\n"
 904       "+SET VERBOSE                 Enables display of processed script commands\n"
 905       "+SET NOVERIFY                Disables display of processed script commands\n"
 906       "+SET NOVERBOSE               Disables display of processed script commands\n"
 907 #define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
 908       "3Command Error Status Display\n"
 909       "+SET MESSAGE                 Re-enables display of script error messages\n"
 910       "+SET NOMESSAGE               Disables display of script error messages\n"
 911 #define HLP_SET_QUIET "*Commands SET Command_Output_Display"
 912       "3Command Output Display\n"
 913       "+SET QUIET                   Disables suppression of some messages\n"
 914       "+SET NOQUIET                 Re-enables suppression of some messages\n"
 915 #define HLP_SET_LOCALOPC "*Commands SET Local_Operator_Console"
 916       "3Local Operator Console\n"
 917       "+SET LOCALOPC                Enables local operator console\n"
 918       "+SET NOLOCALOPC              Disables local operator console\n"
 919 #define HLP_SET_PROMPT "*Commands SET Command_Prompt"
 920       "3Command Prompt\n"
 921       "+SET PROMPT \"string\"         Sets an alternate simulator prompt string\n"
 922       "3Device and Unit Settings\n"
 923       "+SET <dev> OCT|DEC|HEX       Set device display radix\n"
 924       "+SET <dev> ENABLED           Enable device\n"
 925       "+SET <dev> DISABLED          Disable device\n"
 926       "+SET <dev> DEBUG{=arg}       Set device debug flags\n"
 927       "+SET <dev> NODEBUG={arg}     Clear device debug flags\n"
 928       "+SET <dev> arg{,arg...}      Set device parameters\n"
 929       "+SET <unit> ENABLED          Enable unit\n"
 930       "+SET <unit> DISABLED         Disable unit\n"
 931       "+SET <unit> arg{,arg...}     Set unit parameters\n"
 932       "+HELP <dev> SET              Displays any device specific SET commands\n"
 933       " \n\n"
 934       " See the Omnibus documentation for a complete SET command reference.\n"
 935        /***************** 80 character line width template *************************/
 936 #define HLP_SHOW        "*Commands SHOW"
 937       "2SHOW\n"
 938       "+SH{OW} B{UILDINFO}               Show build-time compilation information\n"
 939       "+SH{OW} CL{OCKS}                  Show wall clock and timer information\n"
 940       "+SH{OW} C{ONFIGURATION}           Show simulator configuration\n"
 941       "+SH{OW} D{EFAULT_BASE_SYSTEM}     Show default base system script\n"
 942       "+SH{OW} DEV{ICES}                 Show devices\n"
 943       "+SH{OW} M{ODIFIERS}               Show SET commands for all devices\n"
 944       "+SH{OW} O{N}                      Show ON condition actions\n"
 945       "+SH{OW} P{ROM}                    Show CPU ID PROM initialization data\n"
 946       "+SH{OW} Q{UEUE}                   Show event queue\n"
 947       "+SH{OW} S{HOW}                    Show SHOW commands for all devices\n"
 948       "+SH{OW} T{IME}                    Show simulated timer\n"
 949       "+SH{OW} VE{RSION}                 Show simulator version\n"
 950       "+H{ELP} <dev> SHOW                Show device-specific SHOW commands\n"
 951       "+SH{OW} <dev> {arg,...}           Show device parameters\n"
 952       "+SH{OW} <dev> DEBUG               Show device debug flags\n"
 953       "+SH{OW} <dev> MODIFIERS           Show device modifiers\n"
 954       "+SH{OW} <dev> RADIX               Show device display radix\n"
 955       "+SH{OW} <dev> SHOW                Show device SHOW commands\n"
 956       "+SH{OW} <unit> {arg,...}          Show unit parameters\n\n"
 957       " See the Omnibus documentation for a complete SHOW command reference.\n\n"
 958 #define HLP_SHOW_CONFIG         "*Commands SHOW"
 959 #define HLP_SHOW_DEVICES        "*Commands SHOW"
 960 #define HLP_SHOW_FEATURES       "*Commands SHOW"
 961 #define HLP_SHOW_QUEUE          "*Commands SHOW"
 962 #define HLP_SHOW_TIME           "*Commands SHOW"
 963 #define HLP_SHOW_MODIFIERS      "*Commands SHOW"
 964 #define HLP_SHOW_NAMES          "*Commands SHOW"
 965 #define HLP_SHOW_SHOW           "*Commands SHOW"
 966 #define HLP_SHOW_VERSION        "*Commands SHOW"
 967 #define HLP_SHOW_BUILDINFO      "*Commands SHOW"
 968 #define HLP_SHOW_PROM           "*Commands SHOW"
 969 #define HLP_SHOW_DBS            "*Commands SHOW"
 970 #define HLP_SHOW_DEFAULT        "*Commands SHOW"
 971 #define HLP_SHOW_CONSOLE        "*Commands SHOW"
 972 #define HLP_SHOW_REMOTE         "*Commands SHOW"
 973 #define HLP_SHOW_BREAK          "*Commands SHOW"
 974 #define HLP_SHOW_LOG            "*Commands SHOW"
 975 #define HLP_SHOW_DEBUG          "*Commands SHOW"
 976 #define HLP_SHOW_CLOCKS         "*Commands SHOW"
 977 #define HLP_SHOW_ON             "*Commands SHOW"
 978 #define HLP_SHOW_SEND           "*Commands SHOW"
 979 #define HLP_SHOW_EXPECT         "*Commands SHOW"
 980 #define HLP_HELP                "*Commands HELP"
 981        /***************** 80 character line width template *************************/
 982       "2HELP\n"
 983       "+H{ELP}                      Show this message\n"
 984       "+H{ELP} <command>            Show help for command\n"
 985       "+H{ELP} <dev>                Show help for device\n"
 986       "+H{ELP} <dev> REGISTERS      Show help for device register variables\n"
 987       "+H{ELP} <dev> ATTACH         Show help for device specific ATTACH command\n"
 988       "+H{ELP} <dev> SET            Show help for device specific SET commands\n"
 989       "+H{ELP} <dev> SHOW           Show help for device specific SHOW commands\n"
 990       "+H{ELP} <dev> <command>      Show help for device specific <command> command\n"
 991        /***************** 80 character line width template *************************/
 992       "2Altering The Simulated Configuration\n"
 993       " The \"SET <device> DISABLED\" command removes a device from the configuration.\n"
 994       " A `DISABLED` device is invisible to running programs.  The device can still\n"
 995       " be `RESET`, but it cannot be `ATTACH`ed, `DETACH`ed, or `BOOT`ed.\n\n"
 996       " The \"SET <device> ENABLED\" command restores a disabled device to a\n"
 997       " configuration.\n\n"
 998       " Most multi-unit devices allow units to be enabled or disabled:\n\n"
 999       "++SET <unit> ENABLED\n"
1000       "++SET <unit> DISABLED\n\n"
1001       " When a unit is disabled, it will not be displayed by SHOW DEVICE.\n\n"
1002        /***************** 80 character line width template *************************/
1003 #define HLP_DO          "*Commands Executing_Command_Files Processing_Command_Files"
1004       "2Executing Command Files\n"
1005       "3Processing Command Files\n"
1006       " The simulator can invoke another script file with the \"`DO`\" command:\n\n"
1007       "++DO <filename> {arguments...}       execute commands in specified file\n\n"
1008       " The \"`DO`\" command allows command files to contain substitutable\n"
1009       " arguments. The string \"`%%n`\", where \"`n`\" is a number\n"
1010       " between \"`1`\" and \"`9`\", is replaced with argument \"`n`\" from\n"
1011       " the \"`DO`\" command line. (*i.e.* \"`%%0`\", \"`%%1`\", \"`%%2`\", etc.).\n"
1012       " The string \"`%%0`\" is replaced with \"<`filename`>\".\n The\n"
1013       " sequences \"`\\%%`\" and \"`\\\\`\" are replaced with the literal\n"
1014       " characters \"`%%`\" and \"`\\`\", respectively. Arguments with spaces must\n"
1015       " be enclosed in matching single or double quotation marks.\n\n"
1016       " * **NOTE**: Nested \"`DO`\" commands are supported, up to ten invocations\n"
1017       " deep.\n\n"
1018       "4Switches\n"
1019       "5`-v`\n\n"
1020       " If the switch \"`-v`\" is specified, commands in the command file are\n"
1021       " echoed *before* they are executed.\n\n"
1022       "5`-e`\n\n"
1023       " If the switch \"`-e`\" is specified, command processing (including nested\n"
1024       " command invocations) will be aborted if any command error is encountered.\n"
1025       " (A simulation stop **never** aborts processing; use `ASSERT` to catch\n"
1026       " unexpected stops.) Without this switch, all errors except `ASSERT` failures\n"
1027       " will be ignored, and command processing will continue.\n\n"
1028       "5`-o`\n\n"
1029       " If the switch \"`-o`\" is specified, the `ON` conditions and actions from\n"
1030       " the calling command file will be inherited by the command file being\n"
1031       " invoked.\n"
1032       "5`-q`\n\n"
1033       " If the switch \"`-q`\" is specified, *quiet mode* will be explicitly\n"
1034       " enabled for the called command file, otherwise the *quiet mode* setting\n"
1035       " is inherited from the calling context.\n"
1036        /***************** 80 character line width template *************************/
1037 #define HLP_GOTO        "*Commands Executing_Command_Files GOTO"
1038       "3GOTO\n"
1039       " Commands in a command file execute in sequence until either an error\n"
1040       " trap occurs (when a command completes with an error status), or when an\n"
1041       " explicit request is made to start command execution elsewhere with\n"
1042       " the `GOTO` command:\n\n"
1043       "++GOTO <label>\n\n"
1044       " * Labels are lines in a command file which the first non-whitespace\n"
1045       " character is a \"`:`\".\n"
1046       " * The target of a `GOTO` is the first matching label in the current `DO`\n"
1047       " command file which is encountered.\n\n"
1048       " **Example**\n\n"
1049       " The following example illustrates usage of the `GOTO` command (by\n"
1050       " creating an infinite loop):\n\n"
1051       "++:Label\n"
1052       "++:: This is a loop.\n"
1053       "++GOTO Label\n\n"
1054 #define HLP_RETURN      "*Commands Executing_Command_Files RETURN"
1055        /***************** 80 character line width template *************************/
1056       "3RETURN\n"
1057       " The `RETURN` command causes the current procedure call to be restored to\n"
1058       " the calling context, possibly returning a specific return status.\n"
1059       " If no return status is specified, the return status from the last command\n"
1060       " executed will be returned.  The calling context may have `ON` traps defined\n"
1061       " which may redirect command flow in that context.\n\n"
1062       "++RETURN                 return from command file with last command status\n"
1063       "++RETURN {-Q} <status>   return from command file with specific status\n\n"
1064       " * The status return can be any numeric value or one of the standard SCPE_\n"
1065       " condition names.\n\n"
1066       " * The \"`-Q`\" switch on the `RETURN` command will cause the specified\n"
1067       " status to be returned, but normal error status message printing to be\n"
1068       " suppressed.\n\n"
1069       " **Condition Names**\n\n"
1070       " The available standard SCPE_ condition names and their meanings are:\n\n"
1071       " | Name    | Meaning                         | Name    | Meaning                             |\n"
1072       " | ------- | --------------------------------| ------- | ----------------------------------- |\n"
1073       " | NXM     | Address space exceeded          | UNATT   | Unit not attached                   |\n"
1074       " | IOERR   | I/O error                       | CSUM    | Checksum error                      |\n"
1075       " | FMT     | Format error                    | NOATT   | Unit not attachable                 |\n"
1076       " | OPENERR | File open error                 | MEM     | Memory exhausted                    |\n"
1077       " | ARG     | Invalid argument                | STEP    | Step expired                        |\n"
1078       " | UNK     | Unknown command                 | RO      | Read only argument                  |\n"
1079       " | INCOMP  | Command not completed           | STOP    | Simulation stopped                  |\n"
1080       " | EXIT    | Goodbye                         | TTIERR  | Console input I/O error             |\n"
1081       " | TTOERR  | Console output I/O error        | EOF     | End of file                         |\n"
1082       " | REL     | Relocation error                | NOPARAM | No settable parameters              |\n"
1083       " | ALATT   | Unit already attached           | TIMER   | Hardware timer error                |\n"
1084       " | SIGERR  | Signal handler setup error      | TTYERR  | Console terminal setup error        |\n"
1085       " | NOFNC   | Command not allowed             | UDIS    | Unit disabled                       |\n"
1086       " | NORO    | Read only operation not allowed | INVSW   | Invalid switch                      |\n"
1087       " | MISVAL  | Missing value                   | 2FARG   | Too few arguments                   |\n"
1088       " | 2MARG   | Too many arguments              | NXDEV   | Non-existent device                 |\n"
1089       " | NXUN    | Non-existent unit               | NXREG   | Non-existent register               |\n"
1090       " | NXPAR   | Non-existent parameter          | NEST    | Nested DO command limit exceeded    |\n"
1091       " | IERR    | Internal error                  | MTRLNT  | Invalid magtape record length       |\n"
1092       " | LOST    | Console Telnet connection lost  | TTMO    | Console Telnet connection timed out |\n"
1093       " | STALL   | Console Telnet output stall     | AFAIL   | Assertion failed                    |\n"
1094       " | INVREM  | Invalid remote console command  |         |                                     |\n"
1095       "\n\n"
1096 #define HLP_SHIFT       "*Commands Executing_Command_Files Shift_Parameters"
1097       "3Shift Parameters\n"
1098       " Shift the command files positional parameters\n"
1099 #define HLP_CALL        "*Commands Executing_Command_Files Call_a_subroutine"
1100       "3Call a subroutine\n"
1101       " Control can be transferred to a labeled subroutine using `CALL`.\n\n"
1102       " **Example**\n\n"
1103       "++CALL routine\n"
1104       "++BYE\n"
1105       "++\n"
1106       "++:routine\n"
1107       "++ECHO routine called\n"
1108       "++RETURN\n\n"
1109 #define HLP_ON          "*Commands Executing_Command_Files ON"
1110       "3ON\n"
1111       " The `ON` command performs actions after a condition, or clears a condition.\n"
1112       "++ON <condition> <action>  Perform action after condition\n"
1113       "++ON <condition>           Clears action of specified condition\n"
1114 #define HLP_PROCEED     "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1115 #define HLP_IGNORE      "*Commands Executing_Command_Files PROCEED_or_IGNORE"
1116        /***************** 80 character line width template *************************/
1117       "3PROCEED or IGNORE\n"
1118       " The `PROCEED` (or `IGNORE`) command does nothing.  It is potentially\n"
1119       " useful as a placeholder for any `ON` action condition that should be\n"
1120       " explicitly ignored, allowing command file execution to continue without\n"
1121       " taking any specific action.\n"
1122 #define HLP_ECHO        "*Commands Executing_Command_Files Displaying_Arbitrary_Text"
1123        /***************** 80 character line width template *************************/
1124       "3Displaying Arbitrary Text\n"
1125       " The `ECHO` command is a useful way of annotating command files.  `ECHO`\n"
1126       " prints out its arguments to the console (and to any applicable log file):\n\n"
1127       "++ECHO <string>      Output string to console\n\n"
1128       " **NOTE**: If no arguments are specified, `ECHO` prints a blank line.\n"
1129       " This may be used to provide spacing for console messages or log file\n"
1130       " output.\n"
1131        /***************** 80 character line width template *************************/
1132 #define HLP_ASSERT      "*Commands Executing_Command_Files Testing_Assertions"
1133       "3Testing Assertions\n"
1134       " The `ASSERT` command tests a simulator state condition and halts command\n"
1135       " file execution if the condition is false:\n\n"
1136       "++ASSERT <Simulator State Expressions>\n\n"
1137       " * If the indicated expression evaluates to false, the command completes\n"
1138       " with an `AFAIL` condition.  By default, when a command file encounters a\n"
1139       " command which returns the `AFAIL` condition, it will exit the running\n"
1140       " command file with the `AFAIL` status to the calling command file.  This\n"
1141       " behavior can be changed with the `ON` command as well as switches to the\n"
1142       " invoking `DO` command.\n\n"
1143       " **Examples**\n\n"
1144       " The command file below might be used to bootstrap a hypothetical system\n"
1145       " that halts after the initial load from disk. The `ASSERT` command can then\n"
1146       " be used to confirm that the load completed successfully by examining the\n"
1147       " CPU's \"`A`\" register for the expected value:\n\n"
1148       "++; Example INI file\n"
1149       "++BOOT\n"
1150       "++; A register contains error code; 0 = good boot\n"
1151       "++ASSERT A=0\n"
1152       "++RUN\n\n"
1153        /***************** 80 character line width template *************************/
1154       " * In the above example, if the \"`A`\" register is *not* `0`,\n"
1155       " the \"`ASSERT A=0`\" command will be displayed to the user, and the\n"
1156       " command file will be aborted with an \"`Assertion failed`\" message.\n"
1157       " Otherwise, the command file will continue to bring up the system.\n\n"
1158       " * See the **`IF`** command documentation for more information and details\n"
1159       " regarding simulator state expressions.\n\n"
1160 #define HLP_IF          "*Commands Executing_Command_Files Testing_Conditions"
1161       "3Testing Conditions\n"
1162       " The `IF` command tests a simulator state condition and executes additional\n"
1163       " commands if the condition is true:\n\n"
1164       "++IF <Simulator State Expressions> commandtoprocess{; additionalcommand}...\n\n"
1165       " **Examples**\n\n"
1166       " The command file below might be used to bootstrap a hypothetical system\n"
1167       " that halts after the initial load from disk. The `IF` command can then\n"
1168       " be used to confirm that the load completed successfully by examining the\n"
1169       " CPU's \"`A`\" register for an expected value:\n\n"
1170       "++; Example INI file\n"
1171       "++BOOT\n"
1172       "++; A register contains error code; 0 = good boot\n"
1173       "++IF NOT A=0 echo Boot failed - Failure Code ; EX A; exit AFAIL\n"
1174       "++RUN\n\n"
1175        /***************** 80 character line width template *************************/
1176       " * In the above example, if the \"`A`\" register is *not* `0`, the\n"
1177       " message \"`Boot failed - Failure Code `\" will be displayed, the contents\n"
1178       " of the \"`A`\" register will be displayed, and the command file will be\n"
1179       " aborted with an \"`Assertion failed`\" message.  Otherwise, the command\n"
1180       " file will continue to bring up the system.\n"
1181       "4Conditional Expressions\n"
1182       " The `IF` and `ASSERT` commands evaluate the following two different forms\n"
1183       " of conditional expressions.\n\n"
1184       "5Simulator State Expressions\n"
1185       "  &nbsp;\n \n"
1186       " The values of simulator registers can be evaluated with:\n\n"
1187       "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n"
1188       " * If \"<`dev`>\" is not specified, `CPU` is assumed.  \"<`reg`>\" is a\n"
1189       " register belonging to the indicated device.\n"
1190       " * The \"<`addr`>\" is an address in the address space of the indicated\n"
1191       " device.\n"
1192       " * The \"<`conditional-op`>\" and optional \"<`logical-op`>\" are\n"
1193       " the same as those used for \"search specifiers\" by the `EXAMINE` and\n"
1194       " `DEPOSIT` commands.\n"
1195       " The \"<`value`>\" is expressed in the radix specified for \"<`reg`>\",\n"
1196       " not in the radix for the device when referencing a register; when an\n"
1197       " address is referenced the device radix is used as the default.\n\n"
1198       " * If \"<`logical-op`>\" and \"<`value`>\" are specified, the target\n"
1199       " register value is first altered as indicated.  The result is then compared\n"
1200       " to the \"<`value`>\" via the \"<`conditional-op`>\".\n"
1201       " * * If the result is *true*, the command(s) are executed before proceeding\n"
1202       " to the next line in the command file.\n"
1203       " * * If the result is *false*, the next command in the command file is\n"
1204       " processed.\n\n"
1205       "5String Comparison Expressions\n"
1206       "  &nbsp;\n \n"
1207       " String Values can be compared with:\n\n"
1208       "++{-i} {NOT} \"<string1>\" <compare-op> \"<string2>\"\n\n"
1209       " * The \"`-i`\" switch, if present, causes a comparison to be case\n"
1210       "   insensitive.\n"
1211       " * The \"<`string1`>\" and \"<`string2`>\" arguments are quoted string\n"
1212       "   values which may have environment variables substituted as desired.\n"
1213       " * The \"<`compare-op`>\" may be one of:\n\n"
1214       " |                |                        |\n"
1215       " | --------------:|:---------------------- |\n"
1216       " | \"**`==`**\"     |  equal                 |\n"
1217       " | \"**`EQU`**\"    |  equal                 |\n"
1218       " | \"**`!=`**\"     |  not equal             |\n"
1219       " | \"**`NEQ`**\"    |  not equal             |\n"
1220       " | \"**<**\"        |  less than             |\n"
1221       " | \"**`LSS`**\"    |  less than             |\n"
1222       " | \"**<=**\"       |  less than or equal    |\n"
1223       " | \"**`LEQ`**\"    |  less than or equal    |\n"
1224       " | \"**>**\"        |  greater than          |\n"
1225       " | \"**`GTR`**\"    |  greater than          |\n"
1226       " | \"**>=**\"       |  greater than or equal |\n"
1227       " | \"**`GEQ`**\"    |  greater than or equal |\n"
1228       " * **NOTE**: Comparisons are *generic*.  This means that if\n"
1229       " both \"<`string1`>\" and \"<`string2`>\" are comprised of all numeric\n"
1230       " digits, then the strings are converted to numbers and a numeric\n"
1231       " comparison is performed.  For example, the comparison\n"
1232       " '`\"+1\"` `EQU` `\"1\"`' evaluates to *true*.\n"
1233        /***************** 80 character line width template *************************/
1234 #define HLP_EXIT        "*Commands Exiting_the_Simulator"
1235       "2Exiting the Simulator\n"
1236       " The `EXIT` command (*synonyms* `QUIT` *and* `BYE`) exits the simulator,\n"
1237       " returning control to the host operating system.\n"
1238        /***************** 80 character line width template *************************/
1239 #define HLP_SPAWN       "*Commands Executing_System_Commands"
1240       "2Executing System Commands\n"
1241       " * The simulator can execute host operating system commands with\n"
1242       " the \"`!`\" (*spawn*) command.\n\n"
1243       " |                         |                                             |\n"
1244       " |:----------------------- |:------------------------------------------- |\n"
1245       " | \"**`!`**\"             | Spawn the hosts default command interpreter |\n"
1246       " | \"**`!`** <`command`>\" | Execute the host operating system `command` |\n\n"
1247       " * **NOTE**: The *exit status* from the command which was executed is set\n"
1248       " as the *command completion status* for the \"`!`\" command.  This may\n"
1249       " influence any enabled `ON` condition traps.\n" ;
1250        /***************** 80 character line width template *************************/
1251 
1252 static CTAB cmd_table[] = {
1253     { "RESET",    &reset_cmd,  0,         HLP_RESET     },
1254     { "EXAMINE",  &exdep_cmd,  EX_E,      HLP_EXAMINE   },
1255     { "IEXAMINE", &exdep_cmd,  EX_E+EX_I, HLP_IEXAMINE  },
1256     { "DEPOSIT",  &exdep_cmd,  EX_D,      HLP_DEPOSIT   },
1257     { "IDEPOSIT", &exdep_cmd,  EX_D+EX_I, HLP_IDEPOSIT  },
1258     { "EVALUATE", &eval_cmd,   0,         HLP_EVALUATE  },
1259     { "RUN",      &run_cmd,    RU_RUN,    HLP_RUN,      NULL, &run_cmd_message },
1260     { "GO",       &run_cmd,    RU_GO,     HLP_GO,       NULL, &run_cmd_message },
1261     { "STEP",     &run_cmd,    RU_STEP,   HLP_STEP,     NULL, &run_cmd_message },
1262     { "NEXT",     &run_cmd,    RU_NEXT,   HLP_NEXT,     NULL, &run_cmd_message },
1263     { "CONTINUE", &run_cmd,    RU_CONT,   HLP_CONTINUE, NULL, &run_cmd_message },
1264     { "BOOT",     &run_cmd,    RU_BOOT,   HLP_BOOT,     NULL, &run_cmd_message },
1265     { "BREAK",    &brk_cmd,    SSH_ST,    HLP_BREAK     },
1266     { "NOBREAK",  &brk_cmd,    SSH_CL,    HLP_NOBREAK   },
1267     { "ATTACH",   &attach_cmd, 0,         HLP_ATTACH    },
1268     { "DETACH",   &detach_cmd, 0,         HLP_DETACH    },
1269     { "EXIT",     &exit_cmd,   0,         HLP_EXIT      },
1270     { "QUIT",     &exit_cmd,   0,         NULL          },
1271     { "BYE",      &exit_cmd,   0,         NULL          },
1272     { "SET",      &set_cmd,    0,         HLP_SET       },
1273     { "SHOW",     &show_cmd,   0,         HLP_SHOW      },
1274     { "DO",       &do_cmd,     1,         HLP_DO        },
1275     { "GOTO",     &goto_cmd,   1,         HLP_GOTO      },
1276     { "RETURN",   &return_cmd, 0,         HLP_RETURN    },
1277     { "SHIFT",    &shift_cmd,  0,         HLP_SHIFT     },
1278     { "CALL",     &call_cmd,   0,         HLP_CALL      },
1279     { "ON",       &on_cmd,     0,         HLP_ON        },
1280     { "IF",       &assert_cmd, 0,         HLP_IF        },
1281     { "PROCEED",  &noop_cmd,   0,         HLP_PROCEED   },
1282     { "IGNORE",   &noop_cmd,   0,         HLP_IGNORE    },
1283     { "ECHO",     &echo_cmd,   0,         HLP_ECHO      },
1284     { "ASSERT",   &assert_cmd, 1,         HLP_ASSERT    },
1285     { "SEND",     &send_cmd,   0          },            /* deprecated */
1286     { "EXPECT",   &expect_cmd, 1          },            /* deprecated */
1287     { "NOEXPECT", &expect_cmd, 0          },            /* deprecated */
1288     { "!",        &spawn_cmd,  0,         HLP_SPAWN     },
1289     { "HELP",     &help_cmd,   0,         HLP_HELP      },
1290     { NULL,       NULL,        0          }
1291     };
1292 
1293 static CTAB set_glob_tab[] = {
1294     { "CONSOLE",     &sim_set_console,        0      }, /* deprecated */
1295     { "REMOTE",      &sim_set_remote_console, 0      }, /* deprecated */
1296     { "BREAK",       &brk_cmd,                SSH_ST }, /* deprecated */
1297     { "NOBREAK",     &brk_cmd,                SSH_CL }, /* deprecated */
1298     { "TELNET",      &sim_set_telnet,         0      }, /* deprecated */
1299     { "NOTELNET",    &sim_set_notelnet,       0      }, /* deprecated */
1300     { "LOG",         &sim_set_logon,          0,     HLP_SET_LOG      },
1301     { "NOLOG",       &sim_set_logoff,         0,     HLP_SET_LOG      },
1302     { "DEBUG",       &sim_set_debon,          0,     HLP_SET_DEBUG    },
1303     { "NODEBUG",     &sim_set_deboff,         0,     HLP_SET_DEBUG    },
1304     { "ENVIRONMENT", &sim_set_environment,    1,     HLP_SET_ENVIRON  },
1305     { "ON",          &set_on,                 1,     HLP_SET_ON       },
1306     { "NOON",        &set_on,                 0,     HLP_SET_ON       },
1307     { "VERIFY",      &set_verify,             1,     HLP_SET_VERIFY   },
1308     { "VERBOSE",     &set_verify,             1,     HLP_SET_VERIFY   },
1309     { "NOVERIFY",    &set_verify,             0,     HLP_SET_VERIFY   },
1310     { "NOVERBOSE",   &set_verify,             0,     HLP_SET_VERIFY   },
1311     { "MESSAGE",     &set_message,            1,     HLP_SET_MESSAGE  },
1312     { "NOMESSAGE",   &set_message,            0,     HLP_SET_MESSAGE  },
1313     { "QUIET",       &set_quiet,              1,     HLP_SET_QUIET    },
1314     { "NOQUIET",     &set_quiet,              0,     HLP_SET_QUIET    },
1315     { "LOCALOPC",    &set_localopc,           1,     HLP_SET_LOCALOPC },
1316     { "NOLOCALOPC",  &set_localopc,           0,     HLP_SET_LOCALOPC },
1317     { "PROMPT",      &set_prompt,             0,     HLP_SET_PROMPT   },
1318     { NULL,          NULL,                    0      }
1319     };
1320 
1321 static C1TAB set_dev_tab[] = {
1322     { "OCTAL",    &set_dev_radix,   8  },
1323     { "DECIMAL",  &set_dev_radix,  10  },
1324     { "HEX",      &set_dev_radix,  16  },
1325     { "ENABLED",  &set_dev_enbdis,  1  },
1326     { "DISABLED", &set_dev_enbdis,  0  },
1327     { "DEBUG",    &set_dev_debug,   1  },
1328     { "NODEBUG",  &set_dev_debug,   0  },
1329     { NULL,       NULL,             0  }
1330     };
1331 
1332 static C1TAB set_unit_tab[] = {
1333     { "ENABLED",  &set_unit_enbdis, 1 },
1334     { "DISABLED", &set_unit_enbdis, 0 },
1335     { NULL,       NULL,             0 }
1336     };
1337 
1338 static SHTAB show_glob_tab[] = {
1339     { "CONFIGURATION",  &show_config,        0, HLP_SHOW_CONFIG    },
1340     { "DEFAULT_BASE_SYSTEM_SCRIPT",
1341            &show_default_base_system_script, 0, HLP_SHOW_DBS       },
1342     { "DEVICES",   &show_config,             1, HLP_SHOW_DEVICES   },
1343     { "FEATURES",  &show_config,             2, HLP_SHOW_FEATURES  },
1344     { "QUEUE",     &show_queue,              0, HLP_SHOW_QUEUE     },
1345     { "TIME",      &show_time,               0, HLP_SHOW_TIME      },
1346     { "MODIFIERS", &show_mod_names,          0, HLP_SHOW_MODIFIERS },
1347     { "NAMES",     &show_log_names,          0, HLP_SHOW_NAMES     },
1348     { "SHOW",      &show_show_commands,      0, HLP_SHOW_SHOW      },
1349     { "VERSION",   &show_version,            1, HLP_SHOW_VERSION   },
1350     { "BUILDINFO", &show_buildinfo,          1, HLP_SHOW_BUILDINFO },
1351     { "PROM",      &show_prom,               0, HLP_SHOW_PROM      },
1352     { "CONSOLE",   &sim_show_console,        0, HLP_SHOW_CONSOLE   },
1353     { "REMOTE",    &sim_show_remote_console, 0, HLP_SHOW_REMOTE    },
1354     { "BREAK",     &show_break,              0, HLP_SHOW_BREAK     },
1355     { "LOG",       &sim_show_log,            0, HLP_SHOW_LOG       },
1356     { "TELNET",    &sim_show_telnet,         0  },  /* deprecated */
1357     { "DEBUG",     &sim_show_debug,          0, HLP_SHOW_DEBUG     },
1358     { "CLOCKS",    &sim_show_timers,         0, HLP_SHOW_CLOCKS    },
1359     { "SEND",      &sim_show_send,           0, HLP_SHOW_SEND      },
1360     { "EXPECT",    &sim_show_expect,         0, HLP_SHOW_EXPECT    },
1361     { "ON",        &show_on,                 0, HLP_SHOW_ON        },
1362     { NULL,        NULL,                     0  }
1363     };
1364 
1365 static SHTAB show_dev_tab[] = {
1366     { "RADIX",     &show_dev_radix,         0 },
1367     { "DEBUG",     &show_dev_debug,         0 },
1368     { "MODIFIERS", &show_dev_modifiers,     0 },
1369     { "NAMES",     &show_dev_logicals,      0 },
1370     { "SHOW",      &show_dev_show_commands, 0 },
1371     { NULL,        NULL,                    0 }
1372     };
1373 
1374 static SHTAB show_unit_tab[] = {
1375     { NULL, NULL, 0 }
1376     };
1377 
1378 #if defined(_WIN32)
1379 static
1380 int setenv(const char *envname, const char *envval, int overwrite)
     /* [previous][next][first][last][top][bottom][index][help] */
1381 {
1382 char *envstr = (char *)malloc(strlen(envname)+strlen(envval)+2);
1383 int r;
1384 
1385 (void)sprintf(envstr, "%s=%s", envname, envval);
1386 r = _putenv(envstr);
1387 FREE(envstr);
1388 return r;
1389 }
1390 
1391 static
1392 int unsetenv(const char *envname)
     /* [previous][next][first][last][top][bottom][index][help] */
1393 {
1394 setenv(envname, "", 1);
1395 return 0;
1396 }
1397 #endif /* if defined(_WIN32) */
1398 
1399 #if !defined(NO_LOCALE)
1400 # define XSTR_EMAXLEN 32767
1401 
1402 const char
1403 *xstrerror_l(int errnum)
     /* [previous][next][first][last][top][bottom][index][help] */
1404 {
1405   int saved = errno;
1406   const char *ret = NULL;
1407   static __thread char buf[XSTR_EMAXLEN];
1408 
1409 # if defined(__APPLE__) || defined(_AIX) || defined(__MINGW32__) || \
1410      defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1411 #  if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1412   if (strerror_s(buf, sizeof(buf), errnum) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1413 #  else
1414   if (strerror_r(errnum, buf, sizeof(buf)) == 0) ret = buf; /*LINTOK: xstrerror_l*/
1415 #  endif
1416 # else
1417 #  if defined(__NetBSD__)
1418   locale_t loc = LC_GLOBAL_LOCALE;
1419 #  else
1420   locale_t loc = uselocale((locale_t)0);
1421 #  endif
1422   locale_t copy = loc;
1423   if (copy == LC_GLOBAL_LOCALE)
1424     copy = duplocale(copy);
1425 
1426   if (copy != (locale_t)0)
1427     {
1428       ret = strerror_l(errnum, copy); /*LINTOK: xstrerror_l*/
1429       if (loc == LC_GLOBAL_LOCALE)
1430         {
1431           freelocale(copy);
1432         }
1433     }
1434 # endif
1435 
1436   if (!ret)
1437     {
1438       (void)snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
1439       ret = buf;
1440     }
1441 
1442   errno = saved;
1443   return ret;
1444 }
1445 #else
1446 # define xstrerror_l strerror
1447 #endif
1448 
1449 t_stat process_stdin_commands (t_stat stat, char *argv[]);
1450 
1451 /* Check if running on Rosetta 2 */
1452 
1453 #if defined(__APPLE__)
1454 int processIsTranslated(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1455 {
1456     int ret = 0;
1457     size_t size = sizeof(ret);
1458     if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
1459         if (errno == ENOENT)
1460             return 0;
1461         return -1; }
1462     return ret;
1463 }
1464 #endif /* if defined(_APPLE_) */
1465 
1466 /* Substring removal hack */
1467 
1468 char *strremove(char *str, const char *sub)
     /* [previous][next][first][last][top][bottom][index][help] */
1469 {
1470     char *p, *q, *r;
1471     if (*sub && (q = r = strstr(str, sub)) != NULL) {
1472         size_t len = strlen(sub);
1473         while ((r = strstr(p = r + len, sub)) != NULL) {
1474             while (p < r)
1475                 *q++ = *p++;
1476         }
1477         while ((*q++ = *p++) != '\0')
1478             continue;
1479     }
1480     return str;
1481 }
1482 
1483 /* Trim whitespace */
1484 
1485 void strtrimspace (char *str_trimmed, const char *str_untrimmed)
     /* [previous][next][first][last][top][bottom][index][help] */
1486 {
1487     while (*str_untrimmed != '\0') {
1488       if(!isspace((unsigned char)*str_untrimmed)) {
1489         *str_trimmed = (char)*str_untrimmed;
1490         str_trimmed++;
1491       }
1492       str_untrimmed++;
1493     }
1494     *str_trimmed = '\0';
1495 }
1496 
1497 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1498 void allowCores(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1499 {
1500   int ret;
1501   struct rlimit limit;
1502 # if defined(RLIMIT_CORE)
1503   ret = getrlimit(RLIMIT_CORE, &limit);
1504   (void)ret;
1505 #  if defined(TESTING)
1506   if (ret != 0)
1507     {
1508       sim_warn ("Failed to query core dump configuration.");
1509       return;
1510     }
1511 #  endif /* if defined(TESTING) */
1512   limit.rlim_cur = limit.rlim_max;
1513   ret = setrlimit(RLIMIT_CORE, &limit);
1514 #  if defined(TESTING)
1515   if (ret != 0)
1516     {
1517       sim_warn ("Failed to enable unlimited core dumps.");
1518       return;
1519     }
1520 #  endif /* if defined(TESTING) */
1521 # else
1522 #  if defined(TESTING)
1523   sim_warn ("Unable to query core dump configuration.");
1524 #  endif /* if defined(TESTING) */
1525 # endif /* if defined(RLIMIT_CORE) */
1526   return;
1527 }
1528 #endif
1529 
1530 #if defined(USE_DUMA)
1531 void CleanDUMA(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1532 {
1533   (void)fflush(stdout);
1534   DUMA_CHECKALL();
1535   (void)fflush(stderr);
1536 }
1537 # undef USE_DUMA
1538 # define USE_DUMA 1
1539 #endif /* if defined(USE_DUMA) */
1540 
1541 #if !defined(SIG_SETMASK)
1542 # undef USE_BACKTRACE
1543 #endif /* if !defined(SIG_SETMASK) */
1544 
1545 #if defined(PERF_STRIP)
1546 # undef USE_BACKTRACE
1547 #endif /* if defined(PERF_STRIP) */
1548 
1549 #if defined(USE_BACKTRACE)
1550 # include <backtrace.h>
1551 # include <backtrace-supported.h>
1552 # define BACKTRACE_SKIP 1
1553 # define BACKTRACE_MAIN "main"
1554 # undef USE_BACKTRACE
1555 # define USE_BACKTRACE 1
1556 #endif /* if defined(USE_BACKTRACE) */
1557 
1558 #if defined(BACKTRACE_SUPPORTED)
1559 # if defined(BACKTRACE_SUPPORTS_THREADS)
1560 #  if !(BACKTRACE_SUPPORTED)
1561 #   undef USE_BACKTRACE
1562 #  endif /* if !(BACKTRACE_SUPPORTED) */
1563 # else  /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1564 #  undef USE_BACKTRACE
1565 # endif /* if defined(BACKTRACE_SUPPORTS_THREADS) */
1566 #else  /* if defined(BACKTRACE_SUPPORTED) */
1567 # undef USE_BACKTRACE
1568 #endif /* if defined(BACKTRACE_SUPPORTED) */
1569 
1570 #if defined(USE_BACKTRACE)
1571 # if defined(BACKTRACE_SUPPORTED)
1572 #  include "backtrace_func.c"
1573 # endif /* if defined(BACKTRACE_SUPPORTED) */
1574 #endif /* if defined(USE_BACKTRACE) */
1575 
1576 #if !defined(__CYGWIN__)
1577 # if !defined(__APPLE__)
1578 #  if !defined(_AIX)
1579 #   if !defined(__MINGW32__)
1580 #    if !defined(__MINGW64__)
1581 #     if !defined(CROSS_MINGW32)
1582 #      if !defined(CROSS_MINGW64)
1583 #       if !defined(_WIN32)
1584 #        if !defined(__HAIKU__)
1585 #         if !defined(__QNX__)
1586 static int
1587 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1588 {
1589   (void)size;
1590   (void)data;
1591 
1592   if (strlen(info->dlpi_name) >= 2) {
1593       if (!dl_iterate_phdr_callback_called)
1594           (void)printf ("\r\n Loaded shared objects: ");
1595 
1596       dl_iterate_phdr_callback_called++;
1597       (void)printf ("%s ", info->dlpi_name);
1598   }
1599 
1600   return 0;
1601 }
1602 #         endif
1603 #        endif
1604 #       endif
1605 #      endif
1606 #     endif
1607 #    endif
1608 #   endif
1609 #  endif
1610 # endif
1611 #endif
1612 
1613 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1614 # if defined(_UCRT)
1615 #  define MINGW_CRT "UCRT"
1616 # else
1617 #  define MINGW_CRT "MSVCRT"
1618 # endif
1619 #endif
1620 
1621 #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
1622 struct UCRTVersion
1623 {
1624   uint16_t ProductVersion[4];
1625 };
1626 
1627 int
1628 GetUCRTVersion (struct UCRTVersion *ucrtversion)
     /* [previous][next][first][last][top][bottom][index][help] */
1629 {
1630 # ifdef _DEBUG
1631   static const wchar_t *DllName = L"ucrtbased.dll";
1632 # else
1633   static const wchar_t *DllName = L"ucrtbase.dll";
1634 # endif
1635 
1636   HMODULE ucrt = GetModuleHandleW (DllName);
1637   if (!ucrt)
1638     return GetLastError ();
1639 
1640   wchar_t path[MAX_PATH];
1641   if (!GetModuleFileNameW (ucrt, path, MAX_PATH))
1642     return GetLastError ();
1643 
1644   DWORD versionInfoSize = GetFileVersionInfoSizeW (path, NULL);
1645   if (!versionInfoSize)
1646     return GetLastError ();
1647 
1648   uint8_t versionInfo[versionInfoSize];
1649 
1650   if (!GetFileVersionInfoW (path, 0, versionInfoSize, versionInfo))
1651     return GetLastError ();
1652 
1653   VS_FIXEDFILEINFO *fixedFileInfo;
1654   UINT fixedFileInfoSize;
1655   if (!VerQueryValueW (versionInfo, L"\\", (void **)&fixedFileInfo, &fixedFileInfoSize))
1656     return GetLastError ();
1657 
1658   memcpy (ucrtversion->ProductVersion, &fixedFileInfo->dwProductVersionMS, sizeof (uint32_t) * 2);
1659 
1660   return 0;
1661 }
1662 #endif
1663 
1664 /* libsir support */
1665 
1666 #if !defined(PERF_STRIP)
1667 static int dps8_sir_report_error(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1668 {
1669   char message[SIR_MAXERROR] = {0};
1670   (void)sir_geterror(message);
1671   (void)fprintf(stderr, SIR_BREDB("libsir error: ") SIR_RED("%s%s"), message, SIR_EOL);
1672   return EXIT_FAILURE;
1673 }
1674 
1675 /* Main command loop */
1676 
1677 int main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
1678 {
1679 char *cptr, *cptr2;
1680 char nbuf[PATH_MAX + 7];
1681 char cbuf[4*CBUFSIZE];
1682 char **targv = NULL;
1683 int32 i, sw;
1684 t_bool lookswitch;
1685 t_stat stat;
1686 
1687 # if defined(_AIX)
1688 if (getenv("DPS8M_SKIP_AIX_VARIABLES") == NULL) {
1689   if (setenv("DPS8M_SKIP_AIX_VARIABLES", "1", 1)) {
1690     (void)fprintf(stderr, "\rFATAL: Failed to set \"DPS8M_SKIP_AIX_VARIABLES=1\"! Aborting at %s[%s:%d]\r\n",
1691                   __func__, __FILE__, __LINE__);
1692     abort();
1693   }
1694 
1695   if (setenv("AIXTHREAD_AFFINITY", "strict", 1)) {
1696     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_AFFINITY=strict\".\r\n");
1697   }
1698 
1699   if (setenv("AIXTHREAD_MUTEX_FAST", "ON", 1)) {
1700     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_MUTEX_FAST=ON\".\r\n");
1701   }
1702 
1703   if (setenv("MALLOCOPTIONS", "multiheap", 1)) {
1704     (void)fprintf(stderr, "\rWARN: Failed to set \"MALLOCOPTIONS=multiheap\".\r\n");
1705   }
1706 
1707 #  if !defined(__PASE__)
1708   if (setenv("AIXTHREAD_SCOPE", "S", 1)) {
1709     (void)fprintf(stderr, "\rWARN: Failed to set \"AIXTHREAD_SCOPE=S\".\r\n");
1710   }
1711 #  endif
1712 
1713   if (execvp(argv[0], argv) == -1) {
1714     (void)fprintf(stderr, "\rFATAL: execvp failed! Aborting at %s[%s:%d]\r\n",
1715                   __func__, __FILE__, __LINE__);
1716     abort();
1717   }
1718 }
1719 # endif
1720 
1721 # if defined(USE_BACKTRACE)
1722 #  if defined(BACKTRACE_SUPPORTED)
1723 #   if defined(_INC_BACKTRACE_FUNC)
1724 bt_pid = (long)getpid();
1725 (void)bt_pid;
1726 #   endif /* if defined(_INC_BACKTRACE_FUNC) */
1727 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1728 # endif /* if defined(USE_BACKTRACE) */
1729 
1730 # if defined(__MINGW32__)
1731 #  undef IS_WINDOWS
1732 #  define IS_WINDOWS 1
1733 #  if !defined(NEED_CONSOLE_SETUP)
1734 #   define NEED_CONSOLE_SETUP
1735 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1736 # endif /* if defined(__MINGW32__)*/
1737 
1738 # if defined(CROSS_MINGW32)
1739 #  undef IS_WINDOWS
1740 #  define IS_WINDOWS 1
1741 #  if !defined(NEED_CONSOLE_SETUP)
1742 #   define NEED_CONSOLE_SETUP
1743 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1744 # endif /* if defined(CROSS_MINGW32) */
1745 
1746 # if defined(__MINGW64__)
1747 #  undef IS_WINDOWS
1748 #  define IS_WINDOWS 1
1749 #  if !defined(NEED_CONSOLE_SETUP)
1750 #   define NEED_CONSOLE_SETUP
1751 #  endif /* if !defined(NEED_CONSOLE_SETUP) */
1752 # endif /* if defined(__MINGW64__) */
1753 
1754 # if defined(CROSS_MINGW64)
1755 #  undef IS_WINDOWS
1756 #  define IS_WINDOWS 1
1757 #  if !defined(NEED_CONSOLE_SETUP)
1758 #   define NEED_CONSOLE_SETUP
1759 #  endif /* if !defined(NEED_CONSOLE_SETUP */
1760 # endif /* if defined(CROSS_MINGW64) */
1761 
1762 # if defined(__CYGWIN__)
1763 #  if defined(IS_WINDOWS)
1764 #   undef IS_WINDOWS
1765 #  endif /* if defined(IS_WINDOWS) */
1766 # endif /* if defined(__CYGWIN__) */
1767 
1768 # if defined(USE_DUMA)
1769 #  if defined(DUMA_EXPLICIT_INIT)
1770 duma_init();
1771 (void)fflush(stderr);
1772 #  endif /* if defined(DUMA_EXPLICIT_INIT) */
1773 #  if defined(DUMA_MIN_ALIGNMENT)
1774 #   if DUMA_MIN_ALIGNMENT > 0
1775 DUMA_SET_ALIGNMENT(DUMA_MIN_ALIGNMENT);
1776 #   endif /* if DUMA_MIN_ALIGNMENT > 0 */
1777 #  endif /* if defined(DUMA_MIN_ALIGNMENT) */
1778 DUMA_SET_FILL(0x2E);
1779 (void)fflush(stderr);
1780 (void)atexit(CleanDUMA);
1781 # endif /* if defined(USE_DUMA) */
1782 
1783 # if defined(USE_BACKTRACE)
1784 #  if defined(BACKTRACE_SUPPORTED)
1785 #   include "backtrace_main.c"
1786 #  endif /* if defined(BACKTRACE_SUPPORTED) */
1787 # endif /* if defined(USE_BACKTRACE) */
1788 
1789 # if !defined(NO_LOCALE)
1790 (void)setlocale(LC_ALL, "");
1791 # endif
1792 
1793 # if defined(NEED_CONSOLE_SETUP) && defined(_WIN32)
1794 #  if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
1795 #   define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1796 #  endif /* if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) */
1797 # endif /* if defined(NEED_CONSOLE_SETUP) && defined(_WIN32) */
1798 
1799 # if defined(NEED_CONSOLE_SETUP)
1800 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1801 if (handle != INVALID_HANDLE_VALUE)
1802   {
1803     DWORD mode = 0;
1804     if (GetConsoleMode(handle, &mode))
1805       {
1806         mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1807         SetConsoleMode(handle, mode);
1808       }
1809   }
1810 puts ("\e[0m");
1811 # endif /* if defined(NEED_CONSOLE_SETUP) */
1812 
1813 # if defined(__HAIKU__)
1814 (void)disable_debugger(1);
1815 # endif /* if defined(__HAIKU__) */
1816 
1817 /* libsir init */
1818 
1819 sirinit si;
1820 if (!sir_makeinit(&si))
1821     return dps8_sir_report_error();
1822 
1823 /* Levels for stdout: send debug, information, warning, and notice there. */
1824 si.d_stdout.levels = SIRL_DEBUG | SIRL_INFO | SIRL_WARN | SIRL_NOTICE;
1825 
1826 /* Options for stdout: don't show the name, level, timestamp, hostname, or PID. */
1827 si.d_stdout.opts = SIRO_NONAME | SIRO_NOLEVEL | SIRO_NOTIME | SIRO_NOHOST | SIRO_NOPID;
1828 
1829 /* Levels for stderr: send error and above there. */
1830 si.d_stderr.levels = SIRL_ERROR | SIRL_CRIT | SIRL_ALERT | SIRL_EMERG;
1831 
1832 /* Options for stderr: don't show the hostname. */
1833 si.d_stderr.opts = SIRO_NOHOST;
1834 
1835 /* Levels for the system logger: don't send any output there. */
1836 si.d_syslog.levels = SIRL_NONE;
1837 
1838 /* Options for the system logger: use the default value. */
1839 si.d_syslog.opts = SIRO_DEFAULT;
1840 
1841 /* Configure a name to associate with our output. */
1842 (void)_sir_strncpy(si.name, SIR_MAXNAME, appname, strnlen(appname, SIR_MAXNAME));
1843 
1844 /* Initialize libsir. */
1845 if (!sir_init(&si))
1846     return dps8_sir_report_error();
1847 
1848 /* Set a friendly name for the current thread. */
1849 char thread_name[SIR_MAXPID] = {0};
1850 _sir_snprintf_trunc(thread_name, SIR_MAXPID, "%s", appname);
1851 (void)_sir_setthreadname(thread_name);
1852 
1853 /* sanity checks */
1854 
1855 # if defined(__clang_analyzer__)
1856 (void)fprintf (stderr, "Error: Attempting to execute a Clang Analyzer build!\n");
1857 return 1;
1858 # endif /* if defined(__clang_analyzer__) */
1859 
1860 if (argc == 0) {
1861     (void)fprintf (stderr, "Error: main() called directly!\n");
1862     return 1;
1863 }
1864 
1865 /* Enable unlimited core dumps */
1866 # if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
1867 allowCores();
1868 # endif
1869 
1870 int testEndian = decContextTestEndian();
1871 if (testEndian != 0) {
1872   if (testEndian == 1) {
1873     (void)fprintf (stderr,
1874                    "Error: Compiled for big-endian, but little-endian ordering detected; aborting.\n");
1875     return 1;
1876   }
1877   if (testEndian == -1) {
1878     (void)fprintf (stderr,
1879                    "Error: Compiled for little-endian, but big-endian ordering detected; aborting.\n");
1880     return 1;
1881   }
1882   (void)fprintf (stderr,
1883                  "Error: Unable to determine system byte order; aborting.\n");
1884   return 1;
1885 }
1886 # if defined(NEED_128)
1887 test_math128();
1888 # endif /* if defined(NEED_128) */
1889 
1890 # define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
1891 
1892 # if defined(LINUX_OS) && UV_VERSION_HEX >= UV_VERSION(1, 44, 0)
1893 // Only use uv_available_parallelism on Linux and only on libuv 1.44.0 or higher.
1894 // This will return a value less than the actual number of CPUs if, for example,
1895 // the CPU affinity mask has been pinned to specific CPUs.  On all other systems,
1896 // prefer the _sir_nprocs routine to query the number of actual CPUs available.
1897 nprocs = (unsigned int)uv_available_parallelism();
1898 # else
1899 nprocs = (unsigned int)_sir_nprocs();
1900 # endif
1901 
1902 /* Make sure that argv has at least 10 elements and that it ends in a NULL pointer */
1903 targv = (char **)calloc (1+MAX(10, argc), sizeof(*targv));
1904 if (!targv)
1905   {
1906     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1907                    __func__, __FILE__, __LINE__);
1908 # if defined(USE_BACKTRACE)
1909 #  if defined(SIGUSR2)
1910     (void)raise(SIGUSR2);
1911     /*NOTREACHED*/ /* unreachable */
1912 #  endif /* if defined(SIGUSR2) */
1913 # endif /* if defined(USE_BACKTRACE) */
1914     abort();
1915   }
1916 for (i=0; i<argc; i++)
1917     targv[i] = argv[i];
1918 argv = targv;
1919 
1920 /* setup defaults */
1921 set_prompt (0, "sim>");                                 /* start with set standard prompt */
1922 *cbuf = 0;                                              /* init arg buffer */
1923 sim_switches = 0;                                       /* init switches */
1924 lookswitch = TRUE;
1925 stdnul = fopen(NULL_DEVICE,"wb");
1926 
1927 /* process arguments */
1928 for (i = 1; i < argc; i++) {                            /* loop thru args */
1929     if (argv[i] == NULL)                                /* paranoia */
1930         continue;
1931 
1932 # if defined(THREADZ) || defined(LOCKLESS)
1933 /* performance test */
1934     int perftestflag  = strcmp(argv[i], "--perftest");
1935     if (perftestflag == 0) {
1936       char * testName = NULL;
1937       if (i + 1 < argc)
1938         testName = argv[i + 1];
1939       perfTest (testName);
1940       return 0;
1941     }
1942 # endif
1943 
1944 /* requested only version? */
1945     int onlyvers  = strcmp(argv[i], "--version");
1946     if (onlyvers == 0) {
1947 # if defined(VER_H_GIT_VERSION)
1948 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1949 #   if VER_H_GIT_PATCH_INT < 1
1950         (void)fprintf (stdout, "%s simulator %s\n",
1951                        sim_name, VER_H_GIT_VERSION);
1952 #   else
1953         (void)fprintf (stdout, "%s simulator %s+%s\n",
1954                        sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1955 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
1956 #  else
1957         (void)fprintf (stdout, "%s simulator %s\n",
1958                        sim_name, VER_H_GIT_VERSION);
1959 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
1960 # else
1961         (void)fprintf (stdout, "%s simulator\n", sim_name);
1962 # endif /* if defined(VER_H_GIT_VERSION) */
1963         FREE (targv);
1964         return 0;
1965     }
1966 
1967 /* requested short or long help? */
1968     int longhelp  = strcmp(argv[i], "--help");
1969     int shorthelp = strcmp(argv[i], "-h");
1970     if (shorthelp != 0) shorthelp = strcmp(argv[i], "-H");
1971     if (longhelp == 0 || shorthelp == 0) {
1972 # if defined(VER_H_GIT_VERSION)
1973 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
1974 #   if VER_H_GIT_PATCH_INT < 1
1975         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1976 #   else
1977         (void)fprintf (stdout, "%s simulator %s+%s", sim_name, VER_H_GIT_VERSION, VER_H_GIT_PATCH);
1978 #   endif /* if VER_H_GIT_PATCH_INT < 1 */
1979 #  else
1980         (void)fprintf (stdout, "%s simulator %s", sim_name, VER_H_GIT_VERSION);
1981 #  endif /* if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT) */
1982 # else
1983         (void)fprintf (stdout, "%s simulator", sim_name);
1984 # endif /* if defined(VER_H_GIT_VERSION) */
1985         (void)fprintf (stdout, "\n");
1986         (void)fprintf (stdout, "\n USAGE: %s { [ SWITCHES ] ... } { < SCRIPT > }", argv[0]);
1987         (void)fprintf (stdout, "\n");
1988         (void)fprintf (stdout, "\n Invokes the %s simulator, with optional switches and/or script file.", sim_name);
1989         (void)fprintf (stdout, "\n");
1990         (void)fprintf (stdout, "\n Switches:");
1991         (void)fprintf (stdout, "\n  -e, -E            Aborts script processing immediately upon any error");
1992         (void)fprintf (stdout, "\n  -h, -H, --help    Prints only this informational help text and exit");
1993         (void)fprintf (stdout, "\n  -k, -K            Disables all support for exclusive file locking");
1994         (void)fprintf (stdout, "\n  -l, -L            Reports but ignores all exclusive file locking errors");
1995         (void)fprintf (stdout, "\n  -o, -O            Makes scripting ON conditions and actions inheritable");
1996         (void)fprintf (stdout, "\n  -q, -Q            Disables printing of non-fatal informational messages");
1997         (void)fprintf (stdout, "\n  -r, -R            Enables an unlinked ephemeral system state file");
1998         (void)fprintf (stdout, "\n  -s, -S            Enables a randomized persistent system state file");
1999         (void)fprintf (stdout, "\n  -t, -T            Disables fsync and creation/usage of system state file");
2000         (void)fprintf (stdout, "\n  -v, -V            Prints commands read from script file before execution");
2001         (void)fprintf (stdout, "\n  --version         Prints only the simulator identification text and exit");
2002         (void)fprintf (stdout, "\n");
2003 # if defined(USE_DUMA)
2004         nodist++;
2005 # endif /* if defined(USE_DUMA) */
2006 if (!nodist) {
2007         (void)fprintf (stdout, "\n This software is made available under the terms of the ICU License.");
2008         (void)fprintf (stdout, "\n For complete license details, see the LICENSE file included with the");
2009         (void)fprintf (stdout, "\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md\n");
2010 }
2011 else
2012 {
2013         (void)fprintf (stdout, "\n********** LICENSE RESTRICTED BUILD ****** NOT FOR REDISTRIBUTION **********");
2014 }
2015         (void)fprintf (stdout, "\n");
2016         FREE(argv); //-V726
2017         return 0;
2018     }
2019     /* invalid arguments? */
2020     if ((*argv[i] == '-') && lookswitch) {              /* switch? */
2021         if ((sw = get_switches (argv[i])) < 0) {
2022             (void)fprintf (stderr, "Invalid switch \"%s\".\nTry \"%s -h\" for help.\n", argv[i], argv[0]);
2023             FREE(argv); //-V726
2024             return 1;
2025             }
2026         sim_switches = sim_switches | sw;
2027         }
2028     /* parse arguments */
2029     else {
2030         if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) {
2031             (void)fprintf (stderr, "Argument string too long\n");
2032             FREE(argv); //-V726
2033             return 1;
2034             }
2035         if (*cbuf)                                  /* concat args */
2036             strcat (cbuf, " ");
2037         (void)sprintf(&cbuf[strlen(cbuf)], "%s%s%s", //-V755
2038                       strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : ""); //-V755
2039         lookswitch = FALSE;                         /* no more switches */
2040         }
2041     }                                               /* end for */
2042 sim_nolock = sim_switches & SWMASK ('K');           /* -k means skip locking     */
2043 sim_iglock = sim_switches & SWMASK ('L');           /* -l means ignore locking   */
2044 sim_randompst = sim_switches & SWMASK ('S');        /* -s means persist random   */
2045 sim_quiet = sim_switches & SWMASK ('Q');            /* -q means quiet            */
2046 sim_randstate = sim_switches & SWMASK ('R');        /* -r means random sys_state */
2047 if (sim_randompst) sim_randstate = 1;               /*    and is implied with -s */
2048 sim_nostate = sim_switches & SWMASK ('T');          /* -t means no sys_state     */
2049 if (sim_nostate)                                    /*    and disables -s and -r */
2050   {
2051     sim_randompst = 0;
2052     sim_randstate = 0;
2053   }
2054 sim_on_inherit = sim_switches & SWMASK ('O');       /* -o means inherit on state */
2055 
2056 sim_init_sock ();                                   /* init socket capabilities */
2057 if (sim_dflt_dev == NULL)                           /* if no default */
2058     sim_dflt_dev = sim_devices[0];
2059 if (sim_vm_init != NULL)                            /* call once only */
2060     (*sim_vm_init)();
2061 sim_finit ();                                       /* init fio package */
2062 for (i = 0; cmd_table[i].name; i++) {
2063     size_t alias_len = strlen (cmd_table[i].name);
2064     char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));
2065     if (!cmd_name)
2066       {
2067         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2068                        __func__, __FILE__, __LINE__);
2069 # if defined(USE_BACKTRACE)
2070 #  if defined(SIGUSR2)
2071         (void)raise(SIGUSR2);
2072         /*NOTREACHED*/ /* unreachable */
2073 #  endif /* if defined(SIGUSR2) */
2074 # endif /* if defined(USE_BACKTRACE) */
2075         abort();
2076       }
2077 
2078     strcpy (cmd_name, cmd_table[i].name);
2079     while (alias_len > 1) {
2080         cmd_name[alias_len] = '\0';                 /* Possible short form command name */
2081         --alias_len;
2082         if (getenv (cmd_name))                      /* Externally defined command alias? */
2083             unsetenv (cmd_name);                    /* Remove it to protect against possibly malicious aliases */
2084         }
2085     FREE (cmd_name);
2086     }
2087 stop_cpu = 0;
2088 sim_interval = 0;
2089 sim_time = sim_rtime = 0;
2090 noqueue_time = 0;
2091 sim_clock_queue = QUEUE_LIST_END;
2092 sim_is_running = 0;
2093 sim_log = NULL;
2094 if (sim_emax <= 0)
2095     sim_emax = 1;
2096 sim_timer_init ();
2097 
2098 if ((stat = sim_ttinit ()) != SCPE_OK) {
2099     (void)fprintf (stderr, "Fatal terminal initialization error\n%s\n",
2100                    sim_error_text (stat));
2101     FREE(argv); //-V726
2102     return 1;
2103     }
2104 if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) {
2105     (void)fprintf (stderr, "Unable to allocate examine buffer\n");
2106     FREE(argv); //-V726
2107     return 1;
2108     };
2109 if ((stat = reset_all_p (0)) != SCPE_OK) {
2110     (void)fprintf (stderr, "Fatal simulator initialization error\n%s\n",
2111                    sim_error_text (stat));
2112     FREE(argv); //-V726
2113     return 1;
2114     }
2115 if ((stat = sim_brk_init ()) != SCPE_OK) {
2116     (void)fprintf (stderr, "Fatal breakpoint table initialization error\n%s\n",
2117                    sim_error_text (stat));
2118     FREE(argv); //-V726
2119     return 1;
2120     }
2121 if (!sim_quiet) {
2122     (void)printf ("\n");
2123     show_version (stdout, NULL, NULL, 0, NULL);
2124     }
2125 
2126 cptr = getenv("HOME");
2127 if (cptr == NULL) {
2128     cptr = getenv("HOMEPATH");
2129     cptr2 = getenv("HOMEDRIVE");
2130     }
2131 else
2132     cptr2 = NULL;
2133 (void)cptr2;
2134 if ( (*cbuf) && (strcmp(cbuf, "")) )                    /* cmd file arg? */
2135     stat = do_cmd (0, cbuf);                            /* proc cmd file */
2136 else if (*argv[0]) {                                    /* sim name arg? */
2137     char *np;                                           /* "path.ini" */
2138     nbuf[0] = '"';                                      /* starting " */
2139     stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE;         /* proc default cmd file */
2140     if (stat == SCPE_OPENERR) {                         /* didn't exist/can't open? */
2141         np = strrchr (nbuf, '/');                       /* strip path and try again in cwd */
2142         if (np == NULL)
2143             np = strrchr (nbuf, '\\');                  /* windows path separator */
2144         if (np != NULL) {
2145             *np = '"';
2146             stat = do_cmd (-1, np) & ~SCPE_NOMESSAGE;   /* proc default cmd file */
2147             }
2148         }
2149     }
2150 
2151 argv = uv_setup_args(argc, argv);
2152 
2153 stat = process_stdin_commands (SCPE_BARE_STATUS(stat), argv);
2154 
2155 if (sim_vm_exit != NULL)                                /* call once only */
2156     (*sim_vm_exit)();
2157 
2158 detach_all (0, TRUE);                                   /* close files */
2159 sim_set_deboff (0, NULL);                               /* close debug */
2160 sim_set_logoff (0, NULL);                               /* close log */
2161 sim_set_notelnet (0, NULL);                             /* close Telnet */
2162 sim_ttclose ();                                         /* close console */
2163 sim_cleanup_sock ();                                    /* cleanup sockets */
2164 fclose (stdnul);                                        /* close bit bucket file handle */
2165 FREE (targv);                                           /* release any argv copy that was made */
2166 FREE (sim_prompt);
2167 FREE (sim_eval);
2168 FREE (sim_internal_devices);
2169 FREE (sim_brk_tab);
2170 FREE (sim_staba.comp);
2171 FREE (sim_staba.mask);
2172 FREE (sim_stabr.comp);
2173 FREE (sim_stabr.mask);
2174 return sir_cleanup() ? EXIT_SUCCESS : dps8_sir_report_error();
2175 }
2176 #endif
2177 
2178 t_stat process_stdin_commands (t_stat stat, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
2179 {
2180 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE];
2181 CONST char *cptr;
2182 t_stat stat_nomessage;
2183 CTAB *cmdp = NULL;
2184 
2185 stat = SCPE_BARE_STATUS(stat);                          /* remove possible flag */
2186 while (stat != SCPE_EXIT) {                             /* in case exit */
2187     if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf))))   /* pending action? */
2188         (void)printf ("%s%s\n", sim_prompt, cptr);      /* echo */
2189     else if (sim_vm_read != NULL) {                     /* sim routine? */
2190         (void)printf ("%s", sim_prompt);                /* prompt */
2191         cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
2192         }
2193     else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prompt*/
2194     if (cptr == NULL) {                                 /* EOF? */
2195         if (sim_ttisatty()) continue;                   /* ignore tty EOF */
2196         else break;                                     /* otherwise exit */
2197         }
2198     if (*cptr == 0)                                     /* ignore blank */
2199         continue;
2200     sim_sub_args (cbuf, sizeof(cbuf), argv);
2201     if (sim_log)                                        /* log cmd */
2202         (void)fprintf (sim_log, "%s%s\n", sim_prompt, cptr);
2203     if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout))
2204         (void)fprintf (sim_deb, "%s%s\n", sim_prompt, cptr);
2205     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
2206     sim_switches = 0;                                   /* init switches */
2207     if ((cmdp = find_cmd (gbuf)))                       /* lookup command */
2208         stat = cmdp->action (cmdp->arg, cptr);          /* if found, exec */
2209     else
2210         stat = SCPE_UNK;
2211     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
2212     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
2213     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
2214     sim_last_cmd_stat = stat;                           /* save command error status */
2215     if (!stat_nomessage) {                              /* displaying message status? */
2216         if (cmdp && (cmdp->message))                    /* special message handler? */
2217             cmdp->message (NULL, stat);                 /* let it deal with display */
2218         else
2219             if (stat >= SCPE_BASE)                      /* error? */
2220                 sim_printf ("%s\n", sim_error_text (stat));
2221         }
2222     if (sim_vm_post != NULL)
2223         (*sim_vm_post) (TRUE);
2224     }                                                   /* end while */
2225 return stat;
2226 }
2227 
2228 /* Set prompt routine */
2229 
2230 t_stat set_prompt (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2231 {
2232 char gbuf[CBUFSIZE], *gptr;
2233 
2234 if ((NULL == cptr) || (*cptr == '\0'))
2235     return SCPE_ARG;
2236 
2237 cptr = get_glyph_nc (cptr, gbuf, '"');                  /* get quote delimited token */
2238 if (gbuf[0] == '\0') {                                  /* Token started with quote */
2239     gbuf[sizeof (gbuf)-1] = '\0';
2240     strncpy (gbuf, cptr, sizeof (gbuf)-1);
2241     gptr = strchr (gbuf, '"');
2242     if (NULL != gptr)
2243         *gptr = '\0';
2244     }
2245 sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2);   /* nul terminator and trailing blank */
2246 if (!sim_prompt)
2247   {
2248     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2249                    __func__, __FILE__, __LINE__);
2250 #if defined(USE_BACKTRACE)
2251 # if defined(SIGUSR2)
2252     (void)raise(SIGUSR2);
2253     /*NOTREACHED*/ /* unreachable */
2254 # endif /* if defined(SIGUSR2) */
2255 #endif /* if defined(USE_BACKTRACE) */
2256     abort();
2257   }
2258 (void)sprintf (sim_prompt, "%s ", gbuf);
2259 return SCPE_OK;
2260 }
2261 
2262 /* Find command routine */
2263 
2264 CTAB *find_cmd (const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
2265 {
2266 CTAB *cmdp = NULL;
2267 
2268 if (sim_vm_cmd)                                         /* try ext commands */
2269     cmdp = find_ctab (sim_vm_cmd, gbuf);
2270 if (cmdp == NULL)                                       /* try regular cmds */
2271     cmdp = find_ctab (cmd_table, gbuf);
2272 return cmdp;
2273 }
2274 
2275 /* Exit command */
2276 
2277 t_stat exit_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2278 {
2279 return SCPE_EXIT;
2280 }
2281 
2282 /* Help command */
2283 
2284 /* Used when sorting a list of command names */
2285 static int _cmd_name_compare (const void *pa, const void *pb)
     /* [previous][next][first][last][top][bottom][index][help] */
2286 {
2287 CTAB * const *a = (CTAB * const *)pa;
2288 CTAB * const *b = (CTAB * const *)pb;
2289 
2290 return strcmp((*a)->name, (*b)->name);
2291 }
2292 
2293 void fprint_help (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
2294 {
2295 CTAB *cmdp;
2296 CTAB **hlp_cmdp = NULL;
2297 size_t cmd_cnt = 0;
2298 size_t cmd_size = 0;
2299 size_t max_cmdname_size = 0;
2300 size_t i, line_offset;
2301 
2302 for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) {
2303     if (cmdp->help) {
2304         if (cmd_cnt >= cmd_size) {
2305             cmd_size += 20;
2306             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2307             if (!hlp_cmdp)
2308               {
2309                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2310                                __func__, __FILE__, __LINE__);
2311 #if defined(USE_BACKTRACE)
2312 # if defined(SIGUSR2)
2313                 (void)raise(SIGUSR2);
2314                 /*NOTREACHED*/ /* unreachable */
2315 # endif /* if defined(SIGUSR2) */
2316 #endif /* if defined(USE_BACKTRACE) */
2317                 abort();
2318               }
2319             }
2320         hlp_cmdp[cmd_cnt] = cmdp;
2321         ++cmd_cnt;
2322         if (strlen(cmdp->name) > max_cmdname_size)
2323             max_cmdname_size = strlen(cmdp->name);
2324         }
2325     }
2326 for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) {
2327     if (cmdp->help && (NULL == sim_vm_cmd || NULL == find_ctab (sim_vm_cmd, cmdp->name))) {
2328         if (cmd_cnt >= cmd_size) {
2329             cmd_size += 20;
2330             hlp_cmdp = (CTAB **)realloc (hlp_cmdp, sizeof(*hlp_cmdp)*cmd_size);
2331             if (!hlp_cmdp)
2332               {
2333                 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2334                                __func__, __FILE__, __LINE__);
2335 #if defined(USE_BACKTRACE)
2336 # if defined(SIGUSR2)
2337                 (void)raise(SIGUSR2);
2338                 /*NOTREACHED*/ /* unreachable */
2339 # endif /* if defined(SIGUSR2) */
2340 #endif /* if defined(USE_BACKTRACE) */
2341                 abort();
2342               }
2343             }
2344         hlp_cmdp[cmd_cnt] = cmdp;
2345         ++cmd_cnt;
2346         if (strlen (cmdp->name) > max_cmdname_size)
2347             max_cmdname_size = strlen(cmdp->name);
2348         }
2349     }
2350 (void)fprintf (st, "HELP is available for the following commands:\n\n    ");
2351 if (hlp_cmdp)
2352   qsort (hlp_cmdp, cmd_cnt, sizeof(*hlp_cmdp), _cmd_name_compare);
2353 line_offset = 4;
2354 for ( i = 0 ; i < cmd_cnt ; ++i ) {
2355     fputs (hlp_cmdp[i]->name, st);
2356     line_offset += 5 + max_cmdname_size;
2357     if (line_offset + max_cmdname_size > 79) {
2358         line_offset = 4;
2359         (void)fprintf (st, "\n    ");
2360         }
2361     else
2362         (void)fprintf (st, "%*s", (int)(max_cmdname_size + 5 - strlen (hlp_cmdp[i]->name)), "");
2363     }
2364 FREE (hlp_cmdp);
2365 (void)fprintf (st, "\n");
2366 return;
2367 }
2368 
2369 static void fprint_header (FILE *st, t_bool *pdone, char *context)
     /* [previous][next][first][last][top][bottom][index][help] */
2370 {
2371 if (!*pdone)
2372     (void)fprintf (st, "%s", context);
2373 *pdone = TRUE;
2374 }
2375 
2376 void fprint_reg_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2377 {
2378 REG *rptr, *trptr;
2379 t_bool found = FALSE;
2380 t_bool all_unique = TRUE;
2381 size_t max_namelen = 0;
2382 DEVICE *tdptr;
2383 CONST char *tptr;
2384 char *namebuf;
2385 char rangebuf[32];
2386 
2387 if (dptr->registers)
2388     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2389         if (rptr->flags & REG_HIDDEN)
2390             continue;
2391         if (rptr->depth > 1)
2392             (void)sprintf (rangebuf, "[%d:%d]", 0, rptr->depth-1);
2393         else
2394             strcpy (rangebuf, "");
2395         if (max_namelen < (strlen(rptr->name) + strlen (rangebuf)))
2396             max_namelen = strlen(rptr->name) + strlen (rangebuf);
2397         found = TRUE;
2398         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2399         if ((trptr == NULL) || (tdptr != dptr))
2400             all_unique = FALSE;
2401         }
2402 if (!found) {
2403     if (!silent)
2404         (void)fprintf (st, "No register HELP available for the %s device\n",
2405                        dptr->name);
2406     }
2407 else {
2408     namebuf = (char *)calloc (max_namelen + 1, sizeof (*namebuf));
2409     if (!namebuf)
2410       {
2411         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2412                        __func__, __FILE__, __LINE__);
2413 #if defined(USE_BACKTRACE)
2414 # if defined(SIGUSR2)
2415         (void)raise(SIGUSR2);
2416         /*NOTREACHED*/ /* unreachable */
2417 # endif /* if defined(SIGUSR2) */
2418 #endif /* if defined(USE_BACKTRACE) */
2419         abort();
2420       }
2421     (void)fprintf (st, "\nThe %s device implements these registers:\n\n",
2422                    dptr->name);
2423     for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
2424         if (rptr->flags & REG_HIDDEN)
2425             continue;
2426         if (rptr->depth <= 1)
2427             (void)sprintf (namebuf, "%*s",
2428                            -((int)max_namelen),
2429                            rptr->name);
2430         else {
2431             (void)sprintf (rangebuf, "[%d:%d]",
2432                            0,
2433                            rptr->depth-1);
2434             (void)sprintf (namebuf, "%s%*s",
2435                            rptr->name,
2436                            (int)(strlen(rptr->name))-((int)max_namelen),
2437                            rangebuf);
2438             }
2439         if (all_unique) {
2440             (void)fprintf (st, "  %s %4d  %s\n",
2441                            namebuf,
2442                            rptr->width,
2443                            rptr->desc ? rptr->desc : "");
2444             continue;
2445             }
2446         trptr = find_reg_glob (rptr->name, &tptr, &tdptr);
2447         if ((trptr == NULL) || (tdptr != dptr))
2448             (void)fprintf (st, "  %s %s %4d  %s\n",
2449                            dptr->name,
2450                            namebuf,
2451                            rptr->width,
2452                            rptr->desc ? rptr->desc : "");
2453         else
2454             (void)fprintf (st, "  %*s %s %4d  %s\n",
2455                            (int)strlen(dptr->name), "",
2456                            namebuf,
2457                            rptr->width,
2458                            rptr->desc ? rptr->desc : "");
2459         }
2460     FREE (namebuf);
2461     }
2462 }
2463 
2464 void fprint_reg_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2465 {
2466 fprint_reg_help_ex (st, dptr, TRUE);
2467 }
2468 
2469 void fprint_attach_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2470 {
2471 if (dptr->attach_help) {
2472     (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2473     dptr->attach_help (st, dptr, NULL, 0, NULL);
2474     return;
2475     }
2476 if (DEV_TYPE(dptr) == DEV_DISK) {
2477     (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2478     sim_disk_attach_help (st, dptr, NULL, 0, NULL);
2479     return;
2480     }
2481 if (DEV_TYPE(dptr) == DEV_TAPE) {
2482     (void)fprintf (st, "\n%s device ATTACH commands:\n\n", dptr->name);
2483     sim_tape_attach_help (st, dptr, NULL, 0, NULL);
2484     return;
2485     }
2486 if (!silent) {
2487     (void)fprintf (st, "No ATTACH help is available for the %s device\n", dptr->name);
2488     if (dptr->help)
2489         dptr->help (st, dptr, NULL, 0, NULL);
2490     }
2491 }
2492 
2493 void fprint_set_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2494 {
2495 MTAB *mptr;
2496 DEBTAB *dep;
2497 t_bool found = FALSE;
2498 char buf[CBUFSIZE], header[CBUFSIZE];
2499 uint32 enabled_units = dptr->numunits;
2500 uint32 unit;
2501 
2502 (void)sprintf (header, "\n%s device SET commands:\n\n", dptr->name);
2503 for (unit=0; unit < dptr->numunits; unit++)
2504     if (dptr->units[unit].flags & UNIT_DIS)
2505         --enabled_units;
2506 if (dptr->modifiers) {
2507     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2508         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2509             continue;                                       /* skip unit only extended modifiers */
2510         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2511             continue;                                       /* skip unit only simple modifiers */
2512         if (mptr->mstring) {
2513             fprint_header (st, &found, header);
2514             (void)sprintf (buf, "SET %s %s%s", sim_dname (dptr),
2515                            mptr->mstring,
2516                            (strchr(mptr->mstring, '=')) \
2517                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2518                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2519                                ? "{=val}" : "")));
2520             if ((strlen (buf) < 30) || (NULL == mptr->help))
2521                 (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2522             else
2523                 (void)fprintf (st, "%s\n%-30s\t%s\n", buf, "", mptr->help);
2524             }
2525         }
2526     }
2527 if (dptr->flags & DEV_DISABLE) {
2528     fprint_header (st, &found, header);
2529     (void)sprintf (buf, "SET %s ENABLE", sim_dname (dptr));
2530     (void)fprintf (st,  "%-30s\tEnables device %s\n", buf, sim_dname (dptr));
2531     (void)sprintf (buf, "SET %s DISABLE", sim_dname (dptr));
2532     (void)fprintf (st,  "%-30s\tDisables device %s\n", buf, sim_dname (dptr));
2533     }
2534 if (dptr->flags & DEV_DEBUG) {
2535     fprint_header (st, &found, header);
2536     (void)sprintf (buf, "SET %s DEBUG", sim_dname (dptr));
2537     (void)fprintf (st,  "%-30s\tEnables debugging for device %s\n", buf, sim_dname (dptr));
2538     (void)sprintf (buf, "SET %s NODEBUG", sim_dname (dptr));
2539     (void)fprintf (st,  "%-30s\tDisables debugging for device %s\n", buf, sim_dname (dptr));
2540     if (dptr->debflags) {
2541         t_bool desc_available = FALSE;
2542         strcpy (buf, "");
2543         (void)fprintf (st, "SET %s DEBUG=", sim_dname (dptr));
2544         for (dep = dptr->debflags; dep->name != NULL; dep++) {
2545             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2546             desc_available |= ((dep->desc != NULL) && (dep->desc[0] != '\0'));
2547             }
2548         (void)fprintf (st, "\n");
2549         (void)fprintf (st,  "%-30s\tEnables specific debugging for device %s\n", buf, sim_dname (dptr));
2550         (void)fprintf (st, "SET %s NODEBUG=", sim_dname (dptr));
2551         for (dep = dptr->debflags; dep->name != NULL; dep++)
2552             (void)fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ";"), dep->name);
2553         (void)fprintf (st, "\n");
2554         (void)fprintf (st,  "%-30s\tDisables specific debugging for device %s\n", buf, sim_dname (dptr));
2555         if (desc_available) {
2556             (void)fprintf (st, "\n*%s device DEBUG settings:\n", sim_dname (dptr));
2557             for (dep = dptr->debflags; dep->name != NULL; dep++)
2558                 (void)fprintf (st, "%4s%-12s%s\n", "", dep->name, dep->desc ? dep->desc : "");
2559             }
2560         }
2561     }
2562 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2563     if (dptr->units->flags & UNIT_DISABLE) {
2564         fprint_header (st, &found, header);
2565         (void)sprintf (buf, "SET %sn ENABLE", sim_dname (dptr));
2566         (void)fprintf (st,  "%-30s\tEnables unit %sn\n", buf, sim_dname (dptr));
2567         (void)sprintf (buf, "SET %sn DISABLE", sim_dname (dptr));
2568         (void)fprintf (st,  "%-30s\tDisables unit %sn\n", buf, sim_dname (dptr));
2569         }
2570     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2571         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2572             continue;                                           /* skip device only modifiers */
2573         if ((NULL == mptr->valid) && MODMASK(mptr,MTAB_XTD))
2574             continue;                                           /* skip show only modifiers */
2575         if (mptr->mstring) {
2576             fprint_header (st, &found, header);
2577             (void)sprintf (buf, "SET %s%s %s%s", sim_dname (dptr),
2578                            (dptr->numunits > 1) ? "n" : "0", mptr->mstring,
2579                            (strchr(mptr->mstring, '=')) \
2580                                ? ""       : (MODMASK(mptr,MTAB_VALR) \
2581                                ? "=val"   : (MODMASK(mptr,MTAB_VALO) \
2582                                ? "{=val}" : "")));
2583             (void)fprintf (st, "%-30s\t%s\n", buf,
2584                            (strchr(mptr->mstring, '=')) \
2585                                ? "" : (mptr->help ? mptr->help : ""));
2586             }
2587         }
2588     }
2589 if (!found && !silent)
2590     (void)fprintf (st, "No SET help is available for the %s device\n", dptr->name);
2591 }
2592 
2593 void fprint_set_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2594 {
2595   fprint_set_help_ex (st, dptr, TRUE);
2596 }
2597 
2598 void fprint_show_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2599 {
2600 MTAB *mptr;
2601 t_bool found = FALSE;
2602 char buf[CBUFSIZE], header[CBUFSIZE];
2603 uint32 enabled_units = dptr->numunits;
2604 uint32 unit;
2605 
2606 (void)sprintf (header, "\n%s device SHOW commands:\n\n", dptr->name);
2607 for (unit=0; unit < dptr->numunits; unit++)
2608     if (dptr->units[unit].flags & UNIT_DIS)
2609         --enabled_units;
2610 if (dptr->modifiers) {
2611     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2612         if (!MODMASK(mptr,MTAB_VDV) && MODMASK(mptr,MTAB_VUN) && (dptr->numunits != 1))
2613             continue;                                       /* skip unit only extended modifiers */
2614         if ((enabled_units != 1) && !(mptr->mask & MTAB_XTD))
2615             continue;                                       /* skip unit only simple modifiers */
2616         if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring))
2617             continue;
2618         fprint_header (st, &found, header);
2619         (void)sprintf (buf, "SHOW %s %s%s", sim_dname (dptr),
2620                        mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "{=arg}" : "");
2621         (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2622         }
2623     }
2624 if (dptr->flags & DEV_DEBUG) {
2625     fprint_header (st, &found, header);
2626     (void)sprintf (buf, "SHOW %s DEBUG", sim_dname (dptr));
2627     (void)fprintf (st, "%-30s\tDisplays debugging status for device %s\n", buf, sim_dname (dptr));
2628     }
2629 if ((dptr->modifiers) && (dptr->units) && (enabled_units != 1)) {
2630     for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
2631         if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD))
2632             continue;                                           /* skip device only modifiers */
2633         if ((!mptr->disp) || (!mptr->pstring))
2634             continue;
2635         fprint_header (st, &found, header);
2636         (void)sprintf (buf, "SHOW %s%s %s%s", sim_dname (dptr),
2637                        (dptr->numunits > 1) ? "n" : "0", mptr->pstring,
2638                        MODMASK(mptr,MTAB_SHP) ? "=arg" : "");
2639         (void)fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : "");
2640         }
2641     }
2642 if (!found && !silent)
2643     (void)fprintf (st, "No SHOW help is available for the %s device\n", dptr->name);
2644 }
2645 
2646 void fprint_show_help (FILE *st, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2647     {
2648     fprint_show_help_ex (st, dptr, TRUE);
2649     }
2650 
2651 void fprint_brk_help_ex (FILE *st, DEVICE *dptr, t_bool silent)
     /* [previous][next][first][last][top][bottom][index][help] */
2652 {
2653 BRKTYPTAB *brkt = dptr->brk_types;
2654 char gbuf[CBUFSIZE];
2655 
2656 if (sim_brk_types == 0) {
2657     if ((dptr != sim_dflt_dev) && (!silent)) {
2658         (void)fprintf (st, "Breakpoints are not supported in the %s simulator\n", sim_name);
2659         if (dptr->help)
2660             dptr->help (st, dptr, NULL, 0, NULL);
2661         }
2662     return;
2663     }
2664 if (brkt == NULL) {
2665     int i;
2666 
2667     if (dptr == sim_dflt_dev) {
2668         if (sim_brk_types & ~sim_brk_dflt) {
2669             (void)fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2670             for (i=0; i<26; i++) {
2671                 if (sim_brk_types & (1<<i))
2672                     (void)fprintf (st, "  -%c\n", 'A'+i);
2673                 }
2674             }
2675         (void)fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2676         }
2677     return;
2678     }
2679 (void)fprintf (st, "%s supports the following breakpoint types:\n", sim_dname (dptr));
2680 while (brkt->btyp) {
2681     (void)fprintf (st, "  %s     %s\n", put_switches (gbuf, sizeof(gbuf), brkt->btyp), brkt->desc);
2682     ++brkt;
2683     }
2684 (void)fprintf (st, "The default breakpoint type is: %s\n", put_switches (gbuf, sizeof(gbuf), sim_brk_dflt));
2685 }
2686 
2687 t_stat help_dev_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2688 {
2689 char gbuf[CBUFSIZE];
2690 CTAB *cmdp;
2691 
2692 if (*cptr) {
2693     (void)get_glyph (cptr, gbuf, 0);
2694     if ((cmdp = find_cmd (gbuf))) {
2695         if (cmdp->action == &exdep_cmd) {
2696             if (dptr->help) /* Shouldn't this pass cptr so the device knows which command invoked? */
2697                 return dptr->help (st, dptr, uptr, flag, cptr);
2698             else
2699                 (void)fprintf (st, "No HELP available for the %s %s command\n", cmdp->name, sim_dname(dptr));
2700             return SCPE_OK;
2701             }
2702         if (cmdp->action == &set_cmd) {
2703             fprint_set_help_ex (st, dptr, FALSE);
2704             return SCPE_OK;
2705             }
2706         if (cmdp->action == &show_cmd) {
2707             fprint_show_help_ex (st, dptr, FALSE);
2708             return SCPE_OK;
2709             }
2710         if (cmdp->action == &attach_cmd) {
2711             fprint_attach_help_ex (st, dptr, FALSE);
2712             return SCPE_OK;
2713             }
2714         if (cmdp->action == &brk_cmd) {
2715             fprint_brk_help_ex (st, dptr, FALSE);
2716             return SCPE_OK;
2717             }
2718         if (dptr->help)
2719             return dptr->help (st, dptr, uptr, flag, cptr);
2720         (void)fprintf (st, "No %s HELP is available for the %s device\n", cmdp->name, dptr->name);
2721         return SCPE_OK;
2722         }
2723     if (MATCH_CMD (gbuf, "REGISTERS") == 0) {
2724         fprint_reg_help_ex (st, dptr, FALSE);
2725         return SCPE_OK;
2726         }
2727     if (dptr->help)
2728         return dptr->help (st, dptr, uptr, flag, cptr);
2729     (void)fprintf (st, "No %s HELP is available for the %s device\n", gbuf, dptr->name);
2730     return SCPE_OK;
2731     }
2732 if (dptr->help) {
2733     return dptr->help (st, dptr, uptr, flag, cptr);
2734     }
2735 if (dptr->description)
2736     (void)fprintf (st, "%s %s HELP\n", dptr->description (dptr), dptr->name);
2737 else
2738     (void)fprintf (st, "%s HELP\n", dptr->name);
2739 fprint_set_help_ex    (st, dptr, TRUE);
2740 fprint_show_help_ex   (st, dptr, TRUE);
2741 fprint_attach_help_ex (st, dptr, TRUE);
2742 fprint_reg_help_ex    (st, dptr, TRUE);
2743 fprint_brk_help_ex    (st, dptr, TRUE);
2744 return SCPE_OK;
2745 }
2746 
2747 t_stat help_cmd_output (int32 flag, const char *help, const char *help_base)
     /* [previous][next][first][last][top][bottom][index][help] */
2748 {
2749 switch (help[0]) {
2750     case '*':
2751         scp_help (stdout, NULL, NULL, flag, help_base ? help_base : simh_help, help+1);
2752         if (sim_log)
2753             scp_help (sim_log, NULL, NULL, flag | SCP_HELP_FLAT, help_base ? help_base : simh_help, help+1);
2754         break;
2755     default:
2756         fputs (help, stdout);
2757         if (sim_log)
2758             fputs (help, sim_log);
2759         break;
2760     }
2761 return SCPE_OK;
2762 }
2763 
2764 t_stat help_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2765 {
2766 char gbuf[CBUFSIZE];
2767 CTAB *cmdp;
2768 
2769 GET_SWITCHES (cptr);
2770 if (sim_switches & SWMASK ('F'))
2771     flag = flag | SCP_HELP_FLAT;
2772 if (*cptr) {
2773     cptr = get_glyph (cptr, gbuf, 0);
2774     if ((cmdp = find_cmd (gbuf))) {
2775         if (*cptr) {
2776             if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) {
2777                 DEVICE *dptr;
2778                 UNIT *uptr;
2779                 t_stat r;
2780                 cptr = get_glyph (cptr, gbuf, 0);
2781                 dptr = find_unit (gbuf, &uptr);
2782                 if (dptr == NULL)
2783                     dptr = find_dev (gbuf);
2784                 if (dptr != NULL) {
2785                     r = help_dev_help (stdout, dptr, uptr, flag, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2786                     if (sim_log)
2787                         help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, (cmdp->action == &set_cmd) ? "SET" : "SHOW");
2788                     return r;
2789                     }
2790                 if (cmdp->action == &set_cmd) { /* HELP SET xxx (not device or unit) */
2791                     /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
2792                     if ((cmdp = find_ctab (set_glob_tab, gbuf)) &&
2793                          (cmdp->help))
2794                         return help_cmd_output (flag, cmdp->help, cmdp->help_base);
2795                     }
2796                 else { /* HELP SHOW xxx (not device or unit) */
2797                     SHTAB *shptr = find_shtab (show_glob_tab, gbuf);
2798                     if ((shptr == NULL) || (shptr->help == NULL) || (*shptr->help == '\0'))
2799                         return SCPE_ARG;
2800                     return help_cmd_output (flag, shptr->help, NULL);
2801                     }
2802                 return SCPE_ARG;
2803                 }
2804             else
2805                 return SCPE_2MARG;
2806             }
2807         if (cmdp->help) {
2808             if (strcmp (cmdp->name, "HELP") == 0) {
2809 
2810 
2811 
2812 
2813 
2814 
2815 
2816 
2817 
2818 
2819 
2820 
2821 
2822 
2823 
2824 
2825 
2826 
2827 
2828 
2829 
2830 
2831 
2832 
2833 
2834 
2835 
2836 
2837 
2838 
2839 
2840 
2841 
2842 
2843                 }
2844             else {
2845                 if (((cmdp->action == &exdep_cmd) || (0 == strcmp(cmdp->name, "BOOT"))) &&
2846                     sim_dflt_dev && sim_dflt_dev->help) {
2847                         sim_dflt_dev->help (stdout, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2848                         if (sim_log)
2849                             sim_dflt_dev->help (sim_log, sim_dflt_dev, sim_dflt_dev->units, 0, cmdp->name);
2850                     }
2851                 }
2852             help_cmd_output (flag, cmdp->help, cmdp->help_base);
2853             }
2854         else { /* no help so it is likely a command alias */
2855             CTAB *cmdpa;
2856             for (cmdpa=cmd_table; cmdpa->name != NULL; cmdpa++)
2857                 if ((cmdpa->action == cmdp->action) && (cmdpa->help)) {
2858                     sim_printf ("%s is an alias for the %s command:\n%s",
2859                                 cmdp->name, cmdpa->name, cmdpa->help);
2860                     break;
2861                     }
2862             if (cmdpa->name == NULL)                /* not found? */
2863                 sim_printf ("No help available for the %s command\n", cmdp->name);
2864             }
2865         }
2866     else {
2867         DEVICE *dptr;
2868         UNIT *uptr;
2869         t_stat r;
2870         dptr = find_unit (gbuf, &uptr);
2871         if (dptr == NULL) {
2872             dptr = find_dev (gbuf);
2873             if (dptr == NULL)
2874                 return SCPE_ARG;
2875             if (dptr->flags & DEV_DIS)
2876                 sim_printf ("Device %s is currently disabled\n", dptr->name);
2877             }
2878         r = help_dev_help (stdout, dptr, uptr, flag, cptr);
2879         if (sim_log)
2880             help_dev_help (sim_log, dptr, uptr, flag | SCP_HELP_FLAT, cptr);
2881         return r;
2882         }
2883     }
2884 else {
2885     fprint_help (stdout);
2886     if (sim_log)
2887         fprint_help (sim_log);
2888     }
2889 return SCPE_OK;
2890 }
2891 
2892 /* Spawn command */
2893 
2894 t_stat spawn_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2895 {
2896 t_stat status;
2897 if ((cptr == NULL) || (strlen (cptr) == 0))
2898     cptr = getenv("SHELL");
2899 if ((cptr == NULL) || (strlen (cptr) == 0))
2900     cptr = getenv("ComSpec");
2901 (void)fflush(stdout);                                   /* flush stdout */
2902 if (sim_log)                                            /* flush log if enabled */
2903     (void)fflush (sim_log);
2904 if (sim_deb)                                            /* flush debug if enabled */
2905     (void)fflush (sim_deb);
2906 status = system (cptr);
2907 
2908 return status;
2909 }
2910 
2911 /* Echo command */
2912 
2913 t_stat echo_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2914 {
2915 sim_printf ("%s\n", cptr);
2916 return SCPE_OK;
2917 }
2918 
2919 /*
2920  * DO command
2921  *
2922  * Note that SCPE_STEP ("Step expired") is considered a note and
2923  * not an error; it does not abort command execution when using -E.
2924  *
2925  * Inputs:
2926  *      flag    =   caller and nesting level indicator
2927  *      fcptr   =   filename and optional arguments, space-separated
2928  * Outputs:
2929  *      status  =   error status
2930  *
2931  * The "flag" input value indicates the source of the call, as follows:
2932  *
2933  *      -1      =   initialization file (no error if not found)
2934  *       0      =   command line file
2935  *       1      =   "DO" command
2936  *      >1      =   nested "DO" command
2937  */
2938 
2939 t_stat do_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2940 {
2941 return do_cmd_label (flag, fcptr, NULL);
2942 }
2943 
2944 static char *do_position(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2945 {
2946 static char cbuf[4*CBUFSIZE];
2947 
2948 (void)snprintf (cbuf, sizeof (cbuf), "%s%s%s-%d", sim_do_filename[sim_do_depth],
2949                 sim_do_label[sim_do_depth] ? "::" : "",
2950                 sim_do_label[sim_do_depth] ? sim_do_label[sim_do_depth] : "",
2951                 sim_goto_line[sim_do_depth]);
2952 return cbuf;
2953 }
2954 
2955 t_stat do_cmd_label (int32 flag, CONST char *fcptr, CONST char *label)
     /* [previous][next][first][last][top][bottom][index][help] */
2956 {
2957 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], abuf[4*CBUFSIZE], quote, *c, *do_arg[11];
2958 CONST char *cptr;
2959 FILE *fpin;
2960 CTAB *cmdp = NULL;
2961 int32 echo, nargs, errabort, i;
2962 int32 saved_sim_do_echo = sim_do_echo,
2963       saved_sim_show_message = sim_show_message,
2964       saved_sim_on_inherit = sim_on_inherit,
2965       saved_sim_quiet = sim_quiet;
2966 t_bool staying;
2967 t_stat stat, stat_nomessage;
2968 
2969 stat = SCPE_OK;
2970 staying = TRUE;
2971 if (flag > 0)                                           /* need switches? */
2972     GET_SWITCHES (fcptr);                               /* get switches */
2973 echo = (sim_switches & SWMASK ('V')) || sim_do_echo;    /* -v means echo */
2974 sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet; /* -q means quiet */
2975 sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit; /* -o means inherit ON condition actions */
2976 errabort = sim_switches & SWMASK ('E');                 /* -e means abort on error */
2977 
2978 abuf[sizeof(abuf)-1] = '\0';
2979 strncpy (abuf, fcptr, sizeof(abuf)-1);
2980 c = abuf;
2981 do_arg[10] = NULL;                                      /* make sure the argument list always ends with a NULL */
2982 for (nargs = 0; nargs < 10; ) {                         /* extract arguments */
2983     while (sim_isspace (*c))                            /* skip blanks */
2984         c++;
2985     if (*c == 0)                                        /* all done? */
2986         do_arg [nargs++] = NULL;                        /* null argument */
2987     else {
2988         if (*c == '\'' || *c == '"')                    /* quoted string? */
2989             quote = *c++;
2990         else quote = 0;
2991         do_arg[nargs++] = c;                            /* save start */
2992         while (*c && (quote ? (*c != quote) : !sim_isspace (*c)))
2993             c++;
2994         if (*c)                                         /* term at quote/spc */
2995             *c++ = 0;
2996         }
2997     }                                                   /* end for */
2998 
2999 if (do_arg [0] == NULL)                                 /* need at least 1 */
3000     return SCPE_2FARG;
3001 if ((fpin = fopen (do_arg[0], "r")) == NULL) {          /* file failed to open? */
3002     strcat (strcpy (cbuf, do_arg[0]), ".ini");          /* try again with .ini extension */
3003     if ((fpin = fopen (cbuf, "r")) == NULL) {           /* failed a second time? */
3004         if (flag == 0)                                  /* cmd line file? */
3005              (void)fprintf (stderr, "Can't open file %s\n", do_arg[0]);
3006         return SCPE_OPENERR;                            /* return failure */
3007         }
3008     }
3009 if (flag >= 0) {                                        /* Only bump nesting from command or nested */
3010     ++sim_do_depth;
3011     if (sim_on_inherit) {                               /* inherit ON condition actions? */
3012         sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1]; /* inherit On mode */
3013         for (i=0; i<SCPE_MAX_ERR; i++) {                /* replicate any on commands */
3014             if (sim_on_actions[sim_do_depth-1][i]) {
3015                 sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
3016                 if (NULL == sim_on_actions[sim_do_depth][i]) {
3017                     while (--i >= 0) {
3018                         FREE(sim_on_actions[sim_do_depth][i]);
3019                         sim_on_actions[sim_do_depth][i] = NULL;
3020                         }
3021                     sim_on_check[sim_do_depth] = 0;
3022                     sim_brk_clract ();                  /* defang breakpoint actions */
3023                     --sim_do_depth;                     /* unwind nesting */
3024                     fclose(fpin);
3025                     return SCPE_MEM;
3026                     }
3027                 strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]);
3028                 }
3029             }
3030         }
3031     }
3032 
3033 strcpy( sim_do_filename[sim_do_depth], do_arg[0]);      /* stash away do file name for possible use by 'call' command */
3034 sim_do_label[sim_do_depth] = label;                     /* stash away do label for possible use in messages */
3035 sim_goto_line[sim_do_depth] = 0;
3036 if (label) {
3037     sim_gotofile = fpin;
3038     sim_do_echo = echo;
3039     stat = goto_cmd (0, label);
3040     if (stat != SCPE_OK) {
3041         strcpy(cbuf, "RETURN SCPE_ARG");
3042         cptr = get_glyph (cbuf, gbuf, 0);               /* get command glyph */
3043         cmdp = find_cmd (gbuf);                         /* return the errorStage things to the stat will be returned */
3044         goto Cleanup_Return;
3045         }
3046     }
3047 if (errabort)                                           /* -e flag? */
3048     set_on (1, NULL);                                   /* equivalent to ON ERROR RETURN */
3049 
3050 do {
3051     sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */
3052     if (!sim_do_ocptr[sim_do_depth]) {                  /* no pending action? */
3053         sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */
3054         sim_goto_line[sim_do_depth] += 1;
3055         }
3056     if (cptr != NULL && strlen(cptr) < sizeof(cbuf)) {  /* validate */
3057         sim_sub_args(cbuf, sizeof(cbuf), do_arg);       /* substitute args */
3058         }
3059     sim_sub_args (cbuf, sizeof(cbuf), do_arg);          /* substitute args */
3060     if (cptr == NULL) {                                 /* EOF? */
3061         stat = SCPE_OK;                                 /* set good return */
3062         break;
3063         }
3064     if (*cptr == 0)                                     /* ignore blank */
3065         continue;
3066     if (echo)                                           /* echo if -v */
3067         sim_printf("%s> %s\n", do_position(), cptr);
3068     if (*cptr == ':')                                   /* ignore label */
3069         continue;
3070     cptr = get_glyph_cmd (cptr, gbuf);                  /* get command glyph */
3071     sim_switches = 0;                                   /* init switches */
3072     sim_gotofile = fpin;
3073     sim_do_echo = echo;
3074     if ((cmdp = find_cmd (gbuf))) {                     /* lookup command */
3075         if (cmdp->action == &return_cmd)                /* RETURN command? */
3076             break;                                      /*    done! */
3077         if (cmdp->action == &do_cmd) {                  /* DO command? */
3078             if (sim_do_depth >= MAX_DO_NEST_LVL)        /* nest too deep? */
3079                 stat = SCPE_NEST;
3080             else
3081                 stat = do_cmd (sim_do_depth+1, cptr);   /* exec DO cmd */
3082             }
3083         else
3084             stat = cmdp->action (cmdp->arg, cptr);      /* exec other cmd */
3085         }
3086     else stat = SCPE_UNK;                               /* bad cmd given */
3087     echo = sim_do_echo;                                 /* Allow for SET VERIFY */
3088     stat_nomessage = stat & SCPE_NOMESSAGE;             /* extract possible message suppression flag */
3089     stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
3090     stat = SCPE_BARE_STATUS(stat);                      /* remove possible flag */
3091     if (cmdp)
3092       if (((stat != SCPE_OK) && (stat != SCPE_EXPECT)) ||
3093           ((cmdp->action != &return_cmd) &&
3094            (cmdp->action != &goto_cmd) &&
3095            (cmdp->action != &on_cmd) &&
3096            (cmdp->action != &echo_cmd)))
3097         sim_last_cmd_stat = stat;                       /* save command error status */
3098     switch (stat) {
3099         case SCPE_AFAIL:
3100             staying = (sim_on_check[sim_do_depth] &&        /* if trap action defined */
3101                        sim_on_actions[sim_do_depth][stat]); /* use it, otherwise exit */
3102             break;
3103         case SCPE_EXIT:
3104             staying = FALSE;
3105             break;
3106         case SCPE_OK:
3107         case SCPE_STEP:
3108             break;
3109         default:
3110             break;
3111         }
3112     if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) &&   /* error from cmd? */
3113         (stat != SCPE_STEP)) {
3114         if (!echo && !sim_quiet &&                      /* report if not echoing */
3115             !stat_nomessage &&                          /* and not suppressing messages */
3116             !(cmdp && cmdp->message)) {                 /* and not handling them specially */
3117             sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
3118             }
3119         }
3120     if (!stat_nomessage) {                              /* report error if not suppressed */
3121         if (cmdp && cmdp->message)                      /* special message handler */
3122             cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
3123         else
3124             if (stat >= SCPE_BASE)                      /* report error if not suppressed */
3125                 sim_printf ("%s\n", sim_error_text (stat));
3126         }
3127     if (stat == SCPE_EXPECT)                            /* EXPECT status is non actionable */
3128         stat = SCPE_OK;                                 /* so adjust it to SCPE_OK */
3129     if (staying &&
3130         (sim_on_check[sim_do_depth]) &&
3131         (stat != SCPE_OK) &&
3132         (stat != SCPE_STEP)) {
3133         if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
3134             sim_brk_setact (sim_on_actions[sim_do_depth][stat]);
3135         else
3136             sim_brk_setact (sim_on_actions[sim_do_depth][0]);
3137         }
3138     if (sim_vm_post != NULL)
3139         (*sim_vm_post) (TRUE);
3140     } while (staying);
3141 Cleanup_Return:
3142 if (fpin) //-V547
3143     fclose (fpin);                                      /* close file */
3144 sim_gotofile = NULL;
3145 if (flag >= 0) {
3146     sim_do_echo = saved_sim_do_echo;                    /* restore echo state we entered with */
3147     sim_show_message = saved_sim_show_message;          /* restore message display state we entered with */
3148     sim_on_inherit = saved_sim_on_inherit;              /* restore ON inheritance state we entered with */
3149     }
3150 sim_quiet = saved_sim_quiet;                            /* restore quiet mode we entered with */
3151 if ((flag >= 0) || (!sim_on_inherit)) {
3152     for (i=0; i<SCPE_MAX_ERR; i++) {                    /* release any on commands */
3153         FREE (sim_on_actions[sim_do_depth][i]);
3154         sim_on_actions[sim_do_depth][i] = NULL;
3155         }
3156     sim_on_check[sim_do_depth] = 0;                     /* clear on mode */
3157     }
3158 if (flag >= 0)
3159     --sim_do_depth;                                     /* unwind nesting */
3160 sim_brk_clract ();                                      /* defang breakpoint actions */
3161 if (cmdp && (cmdp->action == &return_cmd) && (0 != *cptr)) { /* return command with argument? */
3162     sim_string_to_stat (cptr, &stat);
3163     sim_last_cmd_stat = stat;                           /* save explicit status as command error status */
3164     if (sim_switches & SWMASK ('Q'))
3165         stat |= SCPE_NOMESSAGE;                         /* suppress error message display (in caller) if requested */
3166     return stat;                                        /* return with explicit return status */
3167     }
3168 return stat | SCPE_NOMESSAGE;                           /* suppress message since we've already done that here */
3169 }
3170 
3171 /*
3172  * Substitute_args - replace %n tokens in 'instr' with the do command's arguments
3173  *                   and other environment variables
3174  *
3175  * Calling sequence
3176  * instr        =       input string
3177  * instr_size   =       sizeof input string buffer
3178  * do_arg[10]   =       arguments
3179  *
3180  * Token "%0" expands to the command file name.
3181  * Token %n (n being a single digit) expands to the n'th argument
3182  * Tonen %* expands to the whole set of arguments (%1 ... %9)
3183  *
3184  * The input sequence "\%" represents a literal "%", and "\\" represents a
3185  * literal "\".  All other character combinations are rendered literally.
3186  *
3187  * Omitted parameters result in null-string substitutions.
3188  *
3189  * A Tokens preceded and followed by % characters are expanded as environment
3190  * variables, and if one isn't found then can be one of several special
3191  * variables:
3192  *   %DATE%              yyyy-mm-dd
3193  *   %TIME%              hh:mm:ss
3194  *   %STIME%             hh_mm_ss
3195  *   %CTIME%             Www Mmm dd hh:mm:ss yyyy
3196  *   %STATUS%            Status value from the last command executed
3197  *   %TSTATUS%           The text form of the last status value
3198  *   %SIM_VERIFY%        The Verify/Verbose mode of the current Do command file
3199  *   %SIM_VERBOSE%       The Verify/Verbose mode of the current Do command file
3200  *   %SIM_QUIET%         The Quiet mode of the current Do command file
3201  *   %SIM_MESSAGE%       The message display status of the current Do command file
3202  * Environment variable lookups are done first with the precise name between
3203  * the % characters and if that fails, then the name between the % characters
3204  * is upcased and a lookup of that value is attempted.
3205 
3206  * The first Space delimited token on the line is extracted in uppercase and
3207  * then looked up as an environment variable.  If found it the value is
3208  * substituted for the original string before expanding everything else.  If
3209  * it is not found, then the original beginning token on the line is left
3210  * untouched.
3211  */
3212 
3213 void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
     /* [previous][next][first][last][top][bottom][index][help] */
3214 {
3215 char gbuf[CBUFSIZE];
3216 char *ip = instr, *op, *oend, *tmpbuf;
3217 const char *ap;
3218 char rbuf[CBUFSIZE];
3219 int i;
3220 time_t now;
3221 struct tm *tmnow;
3222 
3223 time(&now);
3224 tmnow = localtime(&now);
3225 tmpbuf = (char *)malloc(instr_size);
3226 if (!tmpbuf)
3227   {
3228      (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
3229                    __func__, __FILE__, __LINE__);
3230 #if defined(USE_BACKTRACE)
3231 # if defined(SIGUSR2)
3232      (void)raise(SIGUSR2);
3233      /*NOTREACHED*/ /* unreachable */
3234 # endif /* if defined(SIGUSR2) */
3235 #endif /* if defined(USE_BACKTRACE) */
3236      abort();
3237   }
3238 op = tmpbuf;
3239 oend = tmpbuf + instr_size - 2;
3240 while (sim_isspace (*ip))                               /* skip leading spaces */
3241     *op++ = *ip++;
3242 for (; *ip && (op < oend); ) {
3243     if ((ip [0] == '\\') &&                             /* literal escape? */
3244         ((ip [1] == '%') || (ip [1] == '\\'))) {        /*   and followed by '%' or '\'? */
3245         ip++;                                           /* skip '\' */
3246         *op++ = *ip++;                                  /* copy escaped char */
3247         }
3248     else
3249         if ((*ip == '%') &&
3250             (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */
3251             if ((ip[1] >= '0') && (ip[1] <= ('9'))) {   /* %n = sub */
3252                 ap = do_arg[ip[1] - '0'];
3253                 for (i=0; i<ip[1] - '0'; ++i)           /* make sure we're not past the list end */
3254                     if (do_arg[i] == NULL) {
3255                         ap = NULL;
3256                         break;
3257                         }
3258                 ip = ip + 2;
3259                 }
3260             else if (ip[1] == '*') {                    /* %1 ... %9 = sub */
3261                 (void)memset (rbuf, '\0', sizeof(rbuf));
3262                 ap = rbuf;
3263                 for (i=1; i<=9; ++i)
3264                     if (do_arg[i] == NULL)
3265                         break;
3266                     else
3267                         if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
3268                             if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
3269                                 char quote = '"';
3270                                 if (strchr(do_arg[i], quote))
3271                                     quote = '\'';
3272                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"",
3273                                               (i != 1) ? " " : "", quote,
3274                                               do_arg[i], quote);
3275                                 }
3276                             else
3277                                 (void)sprintf(&rbuf[strlen(rbuf)], "%s%s",
3278                                               (i != 1) ? " " : "", do_arg[i]);
3279                             }
3280                         else
3281                             break;
3282                 ip = ip + 2;
3283                 }
3284             else {                                      /* environment variable */
3285                 ap = NULL;
3286                 (void)get_glyph_nc (ip+1, gbuf, '%');   /* first try using the literal name */
3287                 ap = getenv(gbuf);
3288                 if (!ap) {
3289                     (void)get_glyph (ip+1, gbuf, '%');  /* now try using the upcased name */
3290                     ap = getenv(gbuf);
3291                     }
3292                 ip += 1 + strlen (gbuf);
3293                 if (*ip == '%') ++ip;
3294                 if (!ap) {
3295                     /* ISO 8601 format date/time info */
3296                     if (!strcmp ("DATE", gbuf)) {
3297                         (void)sprintf (rbuf, "%4d-%02d-%02d",
3298                                        tmnow->tm_year + 1900,
3299                                        tmnow->tm_mon  + 1,
3300                                        tmnow->tm_mday);
3301                         ap = rbuf;
3302                         }
3303                     else if (!strcmp ("TIME", gbuf)) {
3304                         (void)sprintf (rbuf, "%02d:%02d:%02d",
3305                                        tmnow->tm_hour,
3306                                        tmnow->tm_min,
3307                                        tmnow->tm_sec);
3308                         ap = rbuf;
3309                         }
3310                     else if (!strcmp ("DATETIME", gbuf)) {
3311                         (void)sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d",
3312                                        tmnow->tm_year + 1900,
3313                                        tmnow->tm_mon  + 1,
3314                                        tmnow->tm_mday,
3315                                        tmnow->tm_hour,
3316                                        tmnow->tm_min,
3317                                        tmnow->tm_sec);
3318                         ap = rbuf;
3319                         }
3320                     /* Locale oriented formatted date/time info */
3321                     if (!strcmp ("LDATE", gbuf)) {
3322                         strftime (rbuf, sizeof(rbuf), "%x", tmnow);
3323                         ap = rbuf;
3324                         }
3325                     else if (!strcmp ("LTIME", gbuf)) {
3326                         strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
3327                         ap = rbuf;
3328                         }
3329                     else if (!strcmp ("CTIME", gbuf)) {
3330                         strftime (rbuf, sizeof(rbuf), "%c", tmnow);
3331                         ap = rbuf;
3332                         }
3333                     /* Separate Date/Time info */
3334                     else if (!strcmp ("DATE_YYYY", gbuf)) {/* Year (0000-9999) */
3335                         strftime (rbuf, sizeof(rbuf), "%Y", tmnow);
3336                         ap = rbuf;
3337                         }
3338                     else if (!strcmp ("DATE_YY", gbuf)) {/* Year (00-99) */
3339                         strftime (rbuf, sizeof(rbuf), "%y", tmnow);
3340                         ap = rbuf;
3341                         }
3342                     else if (!strcmp ("DATE_YC", gbuf)) {/* Century (year/100) */
3343                         (void)sprintf (rbuf, "%d", (tmnow->tm_year + 1900)/100);
3344                         ap = rbuf;
3345                         }
3346                     else if ((!strcmp ("DATE_19XX_YY", gbuf)) || /* Year with same calendar */
3347                              (!strcmp ("DATE_19XX_YYYY", gbuf))) {
3348                         int year = tmnow->tm_year + 1900;
3349                         int days = year - 2001;
3350                         int leaps = days/4 - days/100 + days/400;
3351                         int lyear = ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
3352                         int selector = ((days + leaps + 7) % 7) + lyear * 7;
3353                         static int years[] = {90, 91, 97, 98, 99, 94, 89,
3354                                               96, 80, 92, 76, 88, 72, 84};
3355                         int cal_year = years[selector];
3356 
3357                         if (!strcmp ("DATE_19XX_YY", gbuf))
3358                             (void)sprintf (rbuf, "%d", cal_year);        /* 2 digit year */
3359                         else
3360                             (void)sprintf (rbuf, "%d", cal_year + 1900); /* 4 digit year */
3361                         ap = rbuf;
3362                         }
3363                     else if (!strcmp ("DATE_MM", gbuf)) {/* Month number (01-12) */
3364                         strftime (rbuf, sizeof(rbuf), "%m", tmnow);
3365                         ap = rbuf;
3366                         }
3367                     else if (!strcmp ("DATE_MMM", gbuf)) {/* Month number (01-12) */
3368                         strftime (rbuf, sizeof(rbuf), "%b", tmnow);
3369                         ap = rbuf;
3370                         }
3371                     else if (!strcmp ("DATE_DD", gbuf)) {/* Day of Month (01-31) */
3372                         strftime (rbuf, sizeof(rbuf), "%d", tmnow);
3373                         ap = rbuf;
3374                         }
3375                     else if (!strcmp ("DATE_D", gbuf)) { /* ISO 8601 weekday number (1-7) */
3376                         (void)sprintf (rbuf, "%d", (tmnow->tm_wday ? tmnow->tm_wday : 7));
3377                         ap = rbuf;
3378                         }
3379                     else if ((!strcmp ("DATE_WW", gbuf)) ||   /* ISO 8601 week number (01-53) */
3380                              (!strcmp ("DATE_WYYYY", gbuf))) {/* ISO 8601 week year number (0000-9999) */
3381                         int iso_yr = tmnow->tm_year + 1900;
3382                         int iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;;
3383 
3384                         if (iso_wk == 0) {
3385                             iso_yr = iso_yr - 1;
3386                             tmnow->tm_yday += 365 + (((iso_yr % 4) == 0) ? 1 : 0);  /* Adjust for Leap Year (Correct thru 2099) */
3387                             iso_wk = (tmnow->tm_yday + 11 - (tmnow->tm_wday ? tmnow->tm_wday : 7))/7;
3388                             }
3389                         else
3390                             if ((iso_wk == 53) && (((31 - tmnow->tm_mday) + tmnow->tm_wday) < 4)) {
3391                                 ++iso_yr;
3392                                 iso_wk = 1;
3393                                 }
3394                         if (!strcmp ("DATE_WW", gbuf))
3395                             (void)sprintf (rbuf, "%02d", iso_wk);
3396                         else
3397                             (void)sprintf (rbuf, "%04d", iso_yr);
3398                         ap = rbuf;
3399                         }
3400                     else if (!strcmp ("DATE_JJJ", gbuf)) {/* day of year (001-366) */
3401                         strftime (rbuf, sizeof(rbuf), "%j", tmnow);
3402                         ap = rbuf;
3403                         }
3404                     else if (!strcmp ("TIME_HH", gbuf)) {/* Hour of day (00-23) */
3405                         strftime (rbuf, sizeof(rbuf), "%H", tmnow);
3406                         ap = rbuf;
3407                         }
3408                     else if (!strcmp ("TIME_MM", gbuf)) {/* Minute of hour (00-59) */
3409                         strftime (rbuf, sizeof(rbuf), "%M", tmnow);
3410                         ap = rbuf;
3411                         }
3412                     else if (!strcmp ("TIME_SS", gbuf)) {/* Second of minute (00-59) */
3413                         strftime (rbuf, sizeof(rbuf), "%S", tmnow);
3414                         ap = rbuf;
3415                         }
3416                     else if (!strcmp ("STATUS", gbuf)) {
3417                         (void)sprintf (rbuf, "%08X", sim_last_cmd_stat);
3418                         ap = rbuf;
3419                         }
3420                     else if (!strcmp ("TSTATUS", gbuf)) {
3421                         (void)sprintf (rbuf, "%s", sim_error_text (sim_last_cmd_stat));
3422                         ap = rbuf;
3423                         }
3424                     else if (!strcmp ("SIM_VERIFY", gbuf)) {
3425                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3426                         ap = rbuf;
3427                         }
3428                     else if (!strcmp ("SIM_VERBOSE", gbuf)) {
3429                         (void)sprintf (rbuf, "%s", sim_do_echo ? "-V" : "");
3430                         ap = rbuf;
3431                         }
3432                     else if (!strcmp ("SIM_LOCALOPC", gbuf)) {
3433                         (void)sprintf (rbuf, "%s", sim_localopc ? "1" : "");
3434                         ap = rbuf;
3435                         }
3436                     else if (!strcmp ("SIM_QUIET", gbuf)) {
3437                         (void)sprintf (rbuf, "%s", sim_quiet ? "-Q" : "");
3438                         ap = rbuf;
3439                         }
3440                     else if (!strcmp ("SIM_MESSAGE", gbuf)) {
3441                         (void)sprintf (rbuf, "%s", sim_show_message ? "" : "-Q");
3442                         ap = rbuf;
3443                         }
3444                     else if (!strcmp ("HOSTID", gbuf)) {
3445 #if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) && !defined(__QNX__)
3446                         (void)sprintf (rbuf, "%ld", (long)gethostid());
3447 #else
3448                         (void)sprintf (rbuf, "00000000");
3449 #endif /* if defined(HAVE_UNISTD) && !defined(__HAIKU__) && !defined(__ANDROID__) && !defined(__serenity__) */
3450                         ap = rbuf;
3451                         }
3452                     else if (!strcmp ("UID", gbuf)) {
3453 #if defined(HAVE_UNISTD)
3454                         (void)sprintf (rbuf, "%ld", (long)getuid());
3455 #else
3456                         (void)sprintf (rbuf, "0");
3457 #endif /* if defined(HAVE_UNISTD) */
3458                         ap = rbuf;
3459                         }
3460                     else if (!strcmp ("GID", gbuf)) {
3461 #if defined(HAVE_UNISTD)
3462                         (void)sprintf (rbuf, "%ld", (long)getgid());
3463 #else
3464                         (void)sprintf (rbuf, "0");
3465 #endif /* if defined(HAVE_UNISTD) */
3466                         ap = rbuf;
3467                         }
3468                     else if (!strcmp ("EUID", gbuf)) {
3469 #if defined(HAVE_UNISTD)
3470                         (void)sprintf (rbuf, "%ld", (long)geteuid());
3471 #else
3472                         (void)sprintf (rbuf, "0");
3473 #endif /* if defined(HAVE_UNISTD) */
3474                         ap = rbuf;
3475                         }
3476                     else if (!strcmp ("EGID", gbuf)) {
3477 #if defined(HAVE_UNISTD)
3478                         (void)sprintf (rbuf, "%ld", (long)getegid());
3479 #else
3480                         (void)sprintf (rbuf, "0");
3481 #endif /* if defined(HAVE_UNISTD) */
3482                         ap = rbuf;
3483                         }
3484                     else if (!strcmp ("PID", gbuf)) {
3485 #if defined(HAVE_UNISTD)
3486                         (void)sprintf (rbuf, "%ld", (long)getpid());
3487 #else
3488                         (void)sprintf (rbuf, "0");
3489 #endif /* if defined(HAVE_UNISTD) */
3490                         ap = rbuf;
3491                         }
3492                     else if (!strcmp ("PPID", gbuf)) {
3493 #if defined(HAVE_UNISTD)
3494                         (void)sprintf (rbuf, "%ld", (long)getppid());
3495 #else
3496                         (void)sprintf (rbuf, "0");
3497 #endif /* if defined(HAVE_UNISTD) */
3498                         ap = rbuf;
3499                         }
3500                     else if (!strcmp ("PGID", gbuf)) {
3501 #if defined(HAVE_UNISTD)
3502                         (void)sprintf (rbuf, "%ld", (long)getpgid(getpid()));
3503 #else
3504                         (void)sprintf (rbuf, "0");
3505 #endif /* if defined(HAVE_UNISTD) */
3506                         ap = rbuf;
3507                         }
3508                     else if (!strcmp ("SID", gbuf)) {
3509 #if defined(HAVE_UNISTD)
3510                         (void)sprintf (rbuf, "%ld", (long)getsid(getpid()));
3511 #else
3512                         (void)sprintf (rbuf, "0");
3513 #endif /* if defined(HAVE_UNISTD) */
3514                         ap = rbuf;
3515                         }
3516                     else if (!strcmp ("ENDIAN", gbuf)) {
3517 #if ( defined(DECLITEND) && DECLITEND == 1 )
3518                         (void)sprintf (rbuf, "LITTLE");
3519 #elif ( defined(DECLITEND) && DECLITEND == 0 )
3520                         (void)sprintf (rbuf, "BIG");
3521 #else
3522                         (void)sprintf (rbuf, "UNKNOWN");
3523 #endif /* if ( defined(DECLITEND) && DECLITEND == 1 ) */
3524                         ap = rbuf;
3525                         }
3526                     else if (!strcmp("SIM_NAME", gbuf)) {
3527                         (void)sprintf (rbuf, "%s", sim_name);
3528                         ap = rbuf;
3529                         }
3530                     else if (!strcmp("SIM_VERSION", gbuf)) {
3531 #if defined(VER_H_GIT_VERSION)
3532                         (void)sprintf (rbuf, "%s", VER_H_GIT_VERSION);
3533 #else
3534                         (void)sprintf (rbuf, "UNKNOWN");
3535 #endif /* if defined(VER_H_GIT_VERSION) */
3536                         ap = rbuf;
3537                         }
3538                     else if (!strcmp("SIM_HASH", gbuf)) {
3539 #if defined(VER_H_GIT_HASH)
3540                         (void)sprintf (rbuf, "%s", VER_H_GIT_HASH);
3541 #else
3542                         (void)sprintf (rbuf, "0000000000000000000000000000000000000000");
3543 #endif /* if defined(VER_H_GIT_HASH) */
3544                         ap = rbuf;
3545                         }
3546                     else if (!strcmp("SIM_RELT", gbuf)) {
3547 #if defined(VER_H_GIT_RELT)
3548                         (void)sprintf (rbuf, "%s", VER_H_GIT_RELT);
3549 #else
3550                         (void)sprintf (rbuf, "X");
3551 #endif /* if defined(VER_H_GIT_RELT) */
3552                         ap = rbuf;
3553                         }
3554                     else if (!strcmp("SIM_DATE", gbuf)) {
3555 #if defined(VER_H_GIT_DATE)
3556                         (void)sprintf (rbuf, "%s", VER_H_GIT_DATE);
3557 #else
3558                         (void)sprintf (rbuf, "UNKNOWN");
3559 #endif /* if defined(VER_H_GIT_DATE) */
3560                         ap = rbuf;
3561                         }
3562                     else if ( (!strcmp("CPUS", gbuf)) \
3563                       || (!strcmp("SIM_PROCESSORS", gbuf) ) ) {
3564                         (void)sprintf(rbuf, "%u", nprocs);
3565                         ap = rbuf;
3566                         }
3567                     }
3568                 }
3569             if (ap) {                                   /* non-null arg? */
3570                 while (*ap && (op < oend))              /* copy the argument */
3571                     *op++ = *ap++;
3572                 }
3573             }
3574         else
3575             *op++ = *ip++;
3576     }
3577 *op = 0;                                                /* term buffer */
3578 strcpy (instr, tmpbuf);
3579 FREE (tmpbuf);
3580 return;
3581 }
3582 
3583 static
3584 int sim_cmp_string (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help] */
3585 {
3586 long int v1, v2;
3587 char *ep1, *ep2;
3588 
3589 v1 = strtol(s1+1, &ep1, 0);
3590 v2 = strtol(s2+1, &ep2, 0);
3591 if ((ep1 != s1 + strlen (s1) - 1) ||
3592     (ep2 != s2 + strlen (s2) - 1))
3593     return strcmp (s1, s2);
3594 if (v1 == v2)
3595     return 0;
3596 if (v1 < v2)
3597     return -1;
3598 return 1;
3599 }
3600 
3601 /* Assert command */
3602 
3603 t_stat assert_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3604 {
3605 char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
3606 CONST char *tptr, *gptr;
3607 REG *rptr;
3608 uint32 idx = 0;
3609 t_value val;
3610 t_stat r;
3611 t_bool Not = FALSE;
3612 t_bool result;
3613 t_addr addr = 0;
3614 t_stat reason = SCPE_AFAIL; /* default fail reason */
3615 
3616 cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r);
3617                                                         /* get sw, default */
3618 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3619 # pragma diagnostic push
3620 # pragma diag_suppress = integer_sign_change
3621 #endif
3622 sim_stabr.boolop = sim_staba.boolop = -1;               /* no relational op dflt */
3623 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3624 # pragma diagnostic pop
3625 #endif
3626 if (*cptr == 0)                                         /* must be more */
3627     return SCPE_2FARG;
3628 tptr = get_glyph (cptr, gbuf, 0);                       /* get token */
3629 if (!strcmp (gbuf, "NOT")) {                            /* Conditional Inversion? */
3630     Not = TRUE;                                         /* remember that, and */
3631     cptr = (CONST char *)tptr;
3632     }
3633 if (*cptr == '"') {                                     /* quoted string comparison? */
3634     char op[CBUFSIZE];
3635     static struct {
3636         const char *op;
3637         int aval;
3638         int bval;
3639         t_bool invert;
3640         } *optr, compare_ops[] =
3641         {
3642             { "==",   0,  0, FALSE },
3643             { "EQU",  0,  0, FALSE },
3644             { "!=",   0,  0, TRUE  },
3645             { "NEQ",  0,  0, TRUE  },
3646             { "<",   -1, -1, FALSE },
3647             { "LSS", -1, -1, FALSE },
3648             { "<=",   0, -1, FALSE },
3649             { "LEQ",  0, -1, FALSE },
3650             { ">",    1,  1, FALSE },
3651             { "GTR",  1,  1, FALSE },
3652             { ">=",   0,  1, FALSE },
3653             { "GEQ",  0,  1, FALSE },
3654             { NULL }
3655         };
3656 
3657     tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
3658                                                     /* get first string */
3659     if (!*tptr)
3660         return SCPE_2FARG;
3661     cptr += strlen (gbuf);
3662     while (sim_isspace (*cptr))                     /* skip spaces */
3663         ++cptr;
3664     (void)get_glyph (cptr, op, '"');
3665     for (optr = compare_ops; optr->op; optr++)
3666         if (0 == strcmp (op, optr->op))
3667             break;
3668     if (!optr->op)
3669         return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op);
3670     cptr += strlen (op);
3671     while (sim_isspace (*cptr))                         /* skip spaces */
3672         ++cptr;
3673     cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
3674                                                         /* get second string */
3675     if (*cptr) {                                        /* more? */
3676         if (flag)                                       /* ASSERT has no more args */
3677             return SCPE_2MARG;
3678         }
3679     else {
3680         if (!flag)
3681             return SCPE_2FARG;                          /* IF needs actions! */
3682         }
3683     result = sim_cmp_string (gbuf, gbuf2);
3684     result = ((result == optr->aval) || (result == optr->bval));
3685     if (optr->invert)
3686         result = !result;
3687     }
3688 else {
3689     cptr = get_glyph (cptr, gbuf, 0);                   /* get register */
3690     rptr = find_reg (gbuf, &gptr, sim_dfdev);           /* parse register */
3691     if (rptr) {                                         /* got register? */
3692         if (*gptr == '[') {                             /* subscript? */
3693             if (rptr->depth <= 1)                       /* array register? */
3694                 return SCPE_ARG;
3695             idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */
3696             if ((gptr == tptr) || (*tptr++ != ']'))
3697                 return SCPE_ARG;
3698             gptr = tptr;                                /* update */
3699             }
3700         else idx = 0;                                   /* not array */
3701         if (idx >= rptr->depth)                         /* validate subscript */
3702             return SCPE_SUB;
3703         }
3704     else {                                              /* not reg, check for memory */
3705         if (sim_dfdev && sim_vm_parse_addr)             /* get addr */
3706             addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
3707         else if (sim_dfdev) //-V547
3708             addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix); //-V547
3709         if (gbuf == gptr)                               /* error? */
3710             return SCPE_NXREG;
3711         }
3712     if (*gptr != 0)                                     /* more? must be search */
3713         (void)get_glyph (gptr, gbuf, 0);
3714     else {
3715         if (*cptr == 0)                                 /* must be more */
3716             return SCPE_2FARG;
3717         cptr = get_glyph (cptr, gbuf, 0);               /* get search cond */
3718         }
3719     if (*cptr) {                                        /* more? */
3720         if (flag)                                       /* ASSERT has no more args */
3721             return SCPE_2MARG;
3722         }
3723     else {
3724         if (!flag)
3725             return SCPE_2FARG;                          /* IF needs actions! */
3726         }
3727     if (rptr) {                                         /* Handle register case */
3728 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3729 # pragma diagnostic push
3730 # pragma diag_suppress = integer_sign_change
3731 #endif
3732         if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) ||  /* parse condition */
3733             (sim_stabr.boolop == -1))                   /* relational op reqd */
3734             return SCPE_MISVAL;
3735 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3736 # pragma diagnostic pop
3737 #endif
3738         val = get_rval (rptr, idx);                     /* get register value */
3739         result = test_search (&val, &sim_stabr);        /* test condition */
3740         }
3741     else {                                              /* Handle memory case */
3742 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3743 # pragma diagnostic push
3744 # pragma diag_suppress = integer_sign_change
3745 #endif
3746         if (sim_dfdev)
3747             if (!get_asearch (gbuf, sim_dfdev->dradix, &sim_staba) ||  /* parse condition */
3748                 (sim_staba.boolop == -1))                    /* relational op reqd */
3749                 return SCPE_MISVAL;
3750 #if defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__) || defined(__PGI) || defined(__PGLLVM__)
3751 # pragma diagnostic pop
3752 #endif
3753         if (sim_dfdev)
3754             reason = get_aval (addr, sim_dfdev, sim_dfunit); /* get data */
3755         if (reason != SCPE_OK)                          /* return if error */
3756             return reason;
3757         result = test_search (sim_eval, &sim_staba);    /* test condition */
3758         }
3759     }
3760 if (Not ^ result) {
3761     if (!flag)
3762         sim_brk_setact (cptr);                          /* set up IF actions */
3763     }
3764 else
3765     if (flag)
3766         return SCPE_AFAIL;                              /* return assert status */
3767 return SCPE_OK;
3768 }
3769 
3770 /* Send command */
3771 
3772 t_stat send_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3773 {
3774 char gbuf[CBUFSIZE];
3775 CONST char *tptr;
3776 uint8 dbuf[CBUFSIZE];
3777 uint32 dsize = 0;
3778 uint32 delay = 0;
3779 uint32 after = 0;
3780 t_stat r;
3781 SEND *snd = NULL;
3782 
3783 GET_SWITCHES (cptr);                                    /* get switches */
3784 tptr = get_glyph (cptr, gbuf, ',');
3785 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3786     r = tmxr_locate_line_send (gbuf, &snd);
3787     if (r != SCPE_OK)
3788       return r;
3789     cptr = tptr;
3790     tptr = get_glyph (tptr, gbuf, ',');
3791     }
3792 else
3793     snd = sim_cons_get_send ();
3794 
3795 while (*cptr) {
3796     if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
3797         delay = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3798         if (r != SCPE_OK)
3799             return sim_messagef (SCPE_ARG, "Invalid Delay Value\n");
3800         cptr = tptr;
3801         tptr = get_glyph (cptr, gbuf, ',');
3802         continue;
3803         }
3804     if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
3805         after = (uint32)get_uint (&gbuf[6], 10, 2000000000, &r);
3806         if (r != SCPE_OK)
3807             return sim_messagef (SCPE_ARG, "Invalid After Value\n");
3808         cptr = tptr;
3809         tptr = get_glyph (cptr, gbuf, ',');
3810         continue;
3811         }
3812     if ((*cptr == '"') || (*cptr == '\''))
3813         break;
3814     return SCPE_ARG;
3815     }
3816 if (*cptr) {
3817     if ((*cptr != '"') && (*cptr != '\'')) //-V560
3818         return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
3819     cptr = get_glyph_quoted (cptr, gbuf, 0);
3820     if (*cptr != '\0')
3821         return SCPE_2MARG;                  /* No more arguments */
3822 
3823     if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
3824         return sim_messagef (SCPE_ARG, "Invalid String\n");
3825     }
3826 if ((dsize == 0) && (delay == 0) && (after == 0))
3827     return SCPE_2FARG;
3828 return sim_send_input (snd, dbuf, dsize, after, delay);
3829 }
3830 
3831 t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3832 {
3833 char gbuf[CBUFSIZE];
3834 CONST char *tptr;
3835 t_stat r;
3836 SEND *snd = NULL;
3837 
3838 tptr = get_glyph (cptr, gbuf, ',');
3839 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3840     r = tmxr_locate_line_send (gbuf, &snd);
3841     if (r != SCPE_OK)
3842       return r;
3843     cptr = tptr;
3844     }
3845 else
3846     snd = sim_cons_get_send ();
3847 if (*cptr)
3848     return SCPE_2MARG;
3849 return sim_show_send_input (st, snd);
3850 }
3851 
3852 t_stat expect_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3853 {
3854 char gbuf[CBUFSIZE];
3855 CONST char *tptr;
3856 EXPECT *exp = NULL;
3857 
3858 GET_SWITCHES (cptr);                                    /* get switches */
3859 tptr = get_glyph (cptr, gbuf, ',');
3860 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3861     cptr = tptr;
3862 } else {
3863     exp = sim_cons_get_expect ();
3864 }
3865 
3866 if (flag) {
3867     return sim_set_expect (exp, cptr);
3868 } else {
3869     if (exp == NULL) {
3870         exp = sim_cons_get_expect();
3871     }
3872     return sim_set_noexpect (exp, cptr);
3873 }
3874 }
3875 
3876 t_stat sim_show_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3877 {
3878 char gbuf[CBUFSIZE];
3879 CONST char *tptr;
3880 EXPECT *exp = NULL;
3881 t_stat r;
3882 
3883 tptr = get_glyph (cptr, gbuf, ',');
3884 if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
3885     r = tmxr_locate_line_expect (gbuf, &exp);
3886     if (r != SCPE_OK)
3887         return r;
3888     cptr = tptr;
3889     }
3890 else
3891     exp = sim_cons_get_expect ();
3892 if (*cptr && (*cptr != '"') && (*cptr != '\''))
3893     return SCPE_ARG;            /* String must be quote delimited */
3894 tptr = get_glyph_quoted (cptr, gbuf, 0);
3895 if (*tptr != '\0')
3896     return SCPE_2MARG;          /* No more arguments */
3897 if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\''))
3898     return SCPE_ARG;            /* String must be quote delimited */
3899 return sim_exp_show (st, exp, gbuf);
3900 }
3901 
3902 /* Goto command */
3903 
3904 t_stat goto_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3905 {
3906 char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE];
3907 const char *cptr;
3908 long fpos;
3909 int32 saved_do_echo = sim_do_echo;
3910 int32 saved_goto_line = sim_goto_line[sim_do_depth];
3911 
3912 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
3913 (void)get_glyph (fcptr, gbuf1, 0);
3914 if ('\0' == gbuf1[0]) return SCPE_ARG;                  /* unspecified goto target */
3915 fpos = ftell(sim_gotofile);                             /* Save start position */
3916 rewind(sim_gotofile);                                   /* start search for label */
3917 sim_goto_line[sim_do_depth] = 0;                        /* reset line number */
3918 sim_do_echo = 0;                                        /* Don't echo while searching for label */
3919 while (1) {
3920     cptr = read_line (cbuf, sizeof(cbuf), sim_gotofile);/* get cmd line */
3921     if (cptr == NULL) break;                            /* exit on eof */
3922     sim_goto_line[sim_do_depth] += 1;                   /* record line number */
3923     if (*cptr == 0) continue;                           /* ignore blank */
3924     if (*cptr != ':') continue;                         /* ignore non-labels */
3925     ++cptr;                                             /* skip : */
3926     while (sim_isspace (*cptr)) ++cptr;                 /* skip blanks */
3927     cptr = get_glyph (cptr, gbuf, 0);                   /* get label glyph */
3928     if (0 == strcmp(gbuf, gbuf1)) {
3929         sim_brk_clract ();                              /* goto defangs current actions */
3930         sim_do_echo = saved_do_echo;                    /* restore echo mode */
3931         if (sim_do_echo)                                /* echo if -v */
3932             sim_printf("%s> %s\n", do_position(), cbuf);
3933         return SCPE_OK;
3934         }
3935     }
3936 sim_do_echo = saved_do_echo;                       /* restore echo mode         */
3937 fseek(sim_gotofile, fpos, SEEK_SET);               /* restore start position    */
3938 sim_goto_line[sim_do_depth] = saved_goto_line;     /* restore start line number */
3939 return SCPE_ARG;
3940 }
3941 
3942 /* Return command */
3943 
3944 /* The return command is invalid unless encountered in a do_cmd context,    */
3945 /* and in that context, it is handled as a special case inside of do_cmd()  */
3946 /* and not dispatched here, so if we get here a return has been issued from */
3947 /* interactive input */
3948 
3949 t_stat return_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3950 {
3951 return SCPE_UNK;                                 /* only valid inside of do_cmd */
3952 }
3953 
3954 /* Shift command */
3955 
3956 /* The shift command is invalid unless encountered in a do_cmd context,    */
3957 /* and in that context, it is handled as a special case inside of do_cmd() */
3958 /* and not dispatched here, so if we get here a shift has been issued from */
3959 /* interactive input (it is not valid interactively since it would have to */
3960 /* mess with the program's argv which is owned by the C runtime library    */
3961 
3962 t_stat shift_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3963 {
3964 return SCPE_UNK;                                 /* only valid inside of do_cmd */
3965 }
3966 
3967 /* Call command */
3968 
3969 /* The call command is invalid unless encountered in a do_cmd context,     */
3970 /* and in that context, it is handled as a special case inside of do_cmd() */
3971 /* and not dispatched here, so if we get here a call has been issued from  */
3972 /* interactive input                                                       */
3973 
3974 t_stat call_cmd (int32 flag, CONST char *fcptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3975 {
3976 char cbuf[2*CBUFSIZE], gbuf[CBUFSIZE];
3977 const char *cptr;
3978 
3979 if (NULL == sim_gotofile) return SCPE_UNK;              /* only valid inside of do_cmd */
3980 cptr = get_glyph (fcptr, gbuf, 0);
3981 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified goto target */
3982 (void)snprintf(cbuf, sizeof (cbuf), "%s %s", sim_do_filename[sim_do_depth], cptr);
3983 sim_switches |= SWMASK ('O');                           /* inherit ON state and actions */
3984 return do_cmd_label (flag, cbuf, gbuf);
3985 }
3986 
3987 /* On command */
3988 
3989 t_stat on_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
3990 {
3991 char gbuf[CBUFSIZE];
3992 t_stat cond;
3993 
3994 cptr = get_glyph (cptr, gbuf, 0);
3995 if ('\0' == gbuf[0]) return SCPE_ARG;                   /* unspecified condition */
3996 if (0 == strcmp("ERROR", gbuf))
3997     cond = 0;
3998 else
3999     if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
4000         return SCPE_ARG;
4001 if ((NULL == cptr) || ('\0' == *cptr)) {                /* Empty Action */
4002     FREE(sim_on_actions[sim_do_depth][cond]);           /* Clear existing condition */
4003     sim_on_actions[sim_do_depth][cond] = NULL; }
4004 else {
4005     sim_on_actions[sim_do_depth][cond] =
4006         (char *)realloc(sim_on_actions[sim_do_depth][cond], 1+strlen(cptr));
4007     if (!sim_on_actions[sim_do_depth][cond])
4008       {
4009         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
4010                        __func__, __FILE__, __LINE__);
4011 #if defined(USE_BACKTRACE)
4012 # if defined(SIGUSR2)
4013         (void)raise(SIGUSR2);
4014         /*NOTREACHED*/ /* unreachable */
4015 # endif /* if defined(SIGUSR2) */
4016 #endif /* if defined(USE_BACKTRACE) */
4017         abort();
4018       }
4019     strcpy(sim_on_actions[sim_do_depth][cond], cptr);
4020     }
4021 return SCPE_OK;
4022 }
4023 
4024 /* noop command */
4025 
4026 t_stat noop_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4027 {
4028 if (cptr && (*cptr != 0))                               /* now eol? */
4029     return SCPE_2MARG;
4030 return SCPE_OK;                                         /* we're happy doing nothing */
4031 }
4032 
4033 /* Set on/noon routine */
4034 
4035 t_stat set_on (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4036 {
4037 if ((flag) && (cptr) && (*cptr)) {                      /* Set ON with arg */
4038     char gbuf[CBUFSIZE];
4039 
4040     cptr = get_glyph (cptr, gbuf, 0);                   /* get command glyph */
4041     if (((MATCH_CMD(gbuf,"INHERIT")) &&
4042          (MATCH_CMD(gbuf,"NOINHERIT"))) || //-V600
4043         (*cptr))
4044         return SCPE_2MARG;
4045     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"INHERIT"))) //-V560
4046         sim_on_inherit = 1;
4047     if ((gbuf[0]) && (0 == MATCH_CMD(gbuf,"NOINHERIT"))) //-V560
4048         sim_on_inherit = 0;
4049     return SCPE_OK;
4050     }
4051 if (cptr && (*cptr != 0))                               /* now eol? */
4052     return SCPE_2MARG;
4053 sim_on_check[sim_do_depth] = flag;
4054 if ((sim_do_depth != 0) &&
4055     (NULL == sim_on_actions[sim_do_depth][0])) {        /* default handler set? */
4056     sim_on_actions[sim_do_depth][0] =                   /* No, so make "RETURN" */
4057         (char *)malloc(1+strlen("RETURN"));             /* be the default action */
4058     strcpy(sim_on_actions[sim_do_depth][0], "RETURN");
4059     }
4060 if ((sim_do_depth != 0) &&
4061     (NULL == sim_on_actions[sim_do_depth][SCPE_AFAIL])) {/* handler set for AFAIL? */
4062     sim_on_actions[sim_do_depth][SCPE_AFAIL] =          /* No, so make "RETURN" */
4063         (char *)malloc(1+strlen("RETURN"));             /* be the action */
4064     strcpy(sim_on_actions[sim_do_depth][SCPE_AFAIL], "RETURN");
4065     }
4066 return SCPE_OK;
4067 }
4068 
4069 /* Set verify/noverify routine */
4070 
4071 t_stat set_verify (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4072 {
4073 if (cptr && (*cptr != 0))                               /* now eol? */
4074     return SCPE_2MARG;
4075 if (flag == sim_do_echo)                                /* already set correctly? */
4076     return SCPE_OK;
4077 sim_do_echo = flag;
4078 return SCPE_OK;
4079 }
4080 
4081 /* Set message/nomessage routine */
4082 
4083 t_stat set_message (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4084 {
4085 if (cptr && (*cptr != 0))                               /* now eol? */
4086     return SCPE_2MARG;
4087 if (flag == sim_show_message)                           /* already set correctly? */
4088     return SCPE_OK;
4089 sim_show_message = flag;
4090 return SCPE_OK;
4091 }
4092 
4093 /* Set localopc/nolocalopc routine */
4094 
4095 t_stat set_localopc (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4096 {
4097 if (cptr && (*cptr != 0))                               /* now eol? */
4098     return SCPE_2MARG;
4099 if (flag == sim_localopc)                               /* already set correctly? */
4100     return SCPE_OK;
4101 sim_localopc = flag;
4102 return SCPE_OK;
4103 }
4104 /* Set quiet/noquiet routine */
4105 
4106 t_stat set_quiet (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4107 {
4108 if (cptr && (*cptr != 0))                               /* now eol? */
4109     return SCPE_2MARG;
4110 if (flag == sim_quiet)                                  /* already set correctly? */
4111     return SCPE_OK;
4112 sim_quiet = flag;
4113 return SCPE_OK;
4114 }
4115 
4116 /* Set environment routine */
4117 
4118 t_stat sim_set_environment (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4119 {
4120 char varname[CBUFSIZE];
4121 
4122 if ((NULL == cptr) || (*cptr == 0))                            /* now eol? */
4123     return SCPE_2FARG;
4124 cptr = get_glyph (cptr, varname, '=');                  /* get environment variable name */
4125 setenv(varname, cptr, 1);
4126 return SCPE_OK;
4127 }
4128 
4129 /* Set command */
4130 
4131 t_stat set_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4132 {
4133 uint32 lvl = 0;
4134 t_stat r;
4135 char gbuf[CBUFSIZE], *cvptr;
4136 CONST char *svptr;
4137 DEVICE *dptr;
4138 UNIT *uptr;
4139 MTAB *mptr;
4140 CTAB *gcmdp;
4141 C1TAB *ctbr = NULL, *glbr;
4142 
4143 GET_SWITCHES (cptr);                                    /* get switches */
4144 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
4145     return SCPE_2FARG;
4146 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get glob/dev/unit */
4147 
4148 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4149     uptr = dptr->units;                                 /* first unit */
4150     ctbr = set_dev_tab;                                 /* global table */
4151     lvl = MTAB_VDV;                                     /* device match */
4152     GET_SWITCHES (cptr);                                /* get more switches */
4153     }
4154 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4155     if (uptr == NULL)                                   /* invalid unit */
4156         return SCPE_NXUN;
4157     ctbr = set_unit_tab;                                /* global table */
4158     lvl = MTAB_VUN;                                     /* unit match */
4159     GET_SWITCHES (cptr);                                /* get more switches */
4160     }
4161 else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) {    /* global? */
4162     GET_SWITCHES (cptr);                                /* get more switches */
4163     return gcmdp->action (gcmdp->arg, cptr);            /* do the rest */
4164     }
4165 else {
4166     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4167         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4168             *cvptr++ = 0;
4169         for (mptr = sim_dflt_dev->modifiers; mptr->mask != 0; mptr++) {
4170             if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) {
4171                 dptr = sim_dflt_dev;
4172                 cptr = svptr;
4173                 while (sim_isspace(*cptr))
4174                     ++cptr;
4175                 break;
4176                 }
4177             }
4178         }
4179     if (!dptr)
4180         return SCPE_NXDEV;                              /* no match */
4181     lvl = MTAB_VDV;                                     /* device match */
4182     uptr = dptr->units;                                 /* first unit */
4183     }
4184 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4185     return SCPE_2FARG;
4186 GET_SWITCHES (cptr);                                    /* get more switches */
4187 
4188 while (*cptr != 0) {                                    /* do all mods */
4189     cptr = get_glyph (svptr = cptr, gbuf, ',');         /* get modifier */
4190     if (0 == strcmp (gbuf, ";"))
4191         break;
4192     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4193         *cvptr++ = 0;
4194     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4195         if ((mptr->mstring) &&                          /* match string */
4196             (MATCH_CMD (gbuf, mptr->mstring) == 0)) {   /* matches option? */
4197             if (mptr->mask & MTAB_XTD) {                /* extended? */
4198                 if (((lvl & mptr->mask) & ~MTAB_XTD) == 0)
4199                     return SCPE_ARG;
4200                 if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS))
4201                     return SCPE_UDIS;                   /* unit disabled? */
4202                 if (mptr->valid) {                      /* validation rtn? */
4203                     if (cvptr && MODMASK(mptr,MTAB_QUOTE)) {
4204                         svptr = get_glyph_quoted (svptr, gbuf, ',');
4205                         if ((cvptr = strchr (gbuf, '='))) {
4206                             *cvptr++ = 0;
4207                             cptr = svptr;
4208                             }
4209                         }
4210                     else {
4211                         if (cvptr && MODMASK(mptr,MTAB_NC)) {
4212                             (void)get_glyph_nc (svptr, gbuf, ',');
4213                             if ((cvptr = strchr (gbuf, '=')))
4214                                 *cvptr++ = 0;
4215                             }
4216                         }
4217                     r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc);
4218                     if (r != SCPE_OK)
4219                         return r;
4220                     }
4221                 else if (!mptr->desc)                   /* value desc? */
4222                     break;
4223                 else if (cvptr)                         /* = value? */
4224                     return SCPE_ARG;
4225                 else *((int32 *) mptr->desc) = mptr->match;
4226                 }                                       /* end if xtd */
4227             else {                                      /* old style */
4228                 if (cvptr)                              /* = value? */
4229                     return SCPE_ARG;
4230                 if (uptr->flags & UNIT_DIS)             /* disabled? */
4231                      return SCPE_UDIS;
4232                 if ((mptr->valid) &&                    /* invalid? */
4233                     ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK))
4234                     return r;
4235                 uptr->flags = (uptr->flags & ~(mptr->mask)) |
4236                     (mptr->match & mptr->mask);         /* set new value */
4237                 }                                       /* end else xtd */
4238             break;                                      /* terminate for */
4239             }                                           /* end if match */
4240         }                                               /* end for */
4241     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4242         if ((glbr = find_c1tab (ctbr, gbuf))) {         /* global match? */
4243             r = glbr->action (dptr, uptr, glbr->arg, cvptr);    /* do global */
4244             if (r != SCPE_OK)
4245                 return r;
4246             }
4247         else if (!dptr->modifiers)                      /* no modifiers? */
4248             return SCPE_NOPARAM;
4249         else return SCPE_NXPAR;
4250         }                                               /* end if no mat */
4251     }                                                   /* end while */
4252 return SCPE_OK;                                         /* done all */
4253 }
4254 
4255 /* Match CTAB/CTAB1 name */
4256 
4257 CTAB *find_ctab (CTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4258 {
4259 if (!tab)
4260     return NULL;
4261 for (; tab->name != NULL; tab++) {
4262     if (MATCH_CMD (gbuf, tab->name) == 0)
4263         return tab;
4264     }
4265 return NULL;
4266 }
4267 
4268 C1TAB *find_c1tab (C1TAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4269 {
4270 if (!tab)
4271     return NULL;
4272 for (; tab->name != NULL; tab++) {
4273     if (MATCH_CMD (gbuf, tab->name) == 0)
4274         return tab;
4275     }
4276 return NULL;
4277 }
4278 
4279 /* Set device data radix routine */
4280 
4281 t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4282 {
4283 if (cptr)
4284     return SCPE_ARG;
4285 dptr->dradix = flag & 037;
4286 return SCPE_OK;
4287 }
4288 
4289 /* Set device enabled/disabled routine */
4290 
4291 t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4292 {
4293 UNIT *up;
4294 uint32 i;
4295 
4296 if (cptr)
4297     return SCPE_ARG;
4298 if ((dptr->flags & DEV_DISABLE) == 0)                   /* allowed? */
4299     return SCPE_NOFNC;
4300 if (flag) {                                             /* enable? */
4301     if ((dptr->flags & DEV_DIS) == 0)                   /* already enb? ok */
4302         return SCPE_OK;
4303     dptr->flags = dptr->flags & ~DEV_DIS;               /* no, enable */
4304     }
4305 else {
4306     if (dptr->flags & DEV_DIS)                          /* already dsb? ok */
4307         return SCPE_OK;
4308     for (i = 0; i < dptr->numunits; i++) {              /* check units */
4309         up = (dptr->units) + i;                         /* att or active? */
4310         if ((up->flags & UNIT_ATT) || sim_is_active (up))
4311             return SCPE_NOFNC;                          /* can't do it */
4312         }
4313     dptr->flags = dptr->flags | DEV_DIS;                /* disable */
4314     }
4315 if (dptr->reset)                                        /* reset device */
4316     return dptr->reset (dptr);
4317 else return SCPE_OK;
4318 }
4319 
4320 /* Set unit enabled/disabled routine */
4321 
4322 t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4323 {
4324 if (cptr)
4325     return SCPE_ARG;
4326 if (!(uptr->flags & UNIT_DISABLE))                      /* allowed? */
4327     return SCPE_NOFNC;
4328 if (flag)                                               /* enb? enable */
4329     uptr->flags = uptr->flags & ~UNIT_DIS;
4330 else {
4331     if ((uptr->flags & UNIT_ATT) ||                     /* dsb */
4332         sim_is_active (uptr))                           /* more tests */
4333         return SCPE_NOFNC;
4334     uptr->flags = uptr->flags | UNIT_DIS;               /* disable */
4335     }
4336 return SCPE_OK;
4337 }
4338 
4339 /* Set device debug enabled/disabled routine */
4340 
4341 t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4342 {
4343 char gbuf[CBUFSIZE];
4344 DEBTAB *dep;
4345 
4346 if ((dptr->flags & DEV_DEBUG) == 0)
4347     return SCPE_NOFNC;
4348 if (cptr == NULL) {                                     /* no arguments? */
4349     dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;/* disable/enable w/o table */
4350     if (flag && dptr->debflags) {                       /* enable with table? */
4351         for (dep = dptr->debflags; dep->name != NULL; dep++)
4352             dptr->dctrl = dptr->dctrl | dep->mask;      /* set all */
4353         }
4354     return SCPE_OK;
4355     }
4356 if (dptr->debflags == NULL)                             /* must have table */
4357     return SCPE_ARG;
4358 while (*cptr) {
4359     cptr = get_glyph (cptr, gbuf, ';');                 /* get debug flag */
4360     for (dep = dptr->debflags; dep->name != NULL; dep++) {
4361         if (strcmp (dep->name, gbuf) == 0) {            /* match? */
4362             if (flag)
4363                 dptr->dctrl = dptr->dctrl | dep->mask;
4364             else dptr->dctrl = dptr->dctrl & ~dep->mask;
4365             break;
4366             }
4367         }                                               /* end for */
4368     if (dep->mask == 0)                                 /* no match? */
4369         return SCPE_ARG;
4370     }                                                   /* end while */
4371 return SCPE_OK;
4372 }
4373 
4374 /* Show command */
4375 
4376 t_stat show_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4377 {
4378 t_stat r = SCPE_IERR;
4379 
4380 cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r);
4381                                                         /* get sw, ofile */
4382 if (NULL == cptr)                                              /* error? */
4383     return r;
4384 if (sim_ofile) {                                        /* output file? */
4385     r = show_cmd_fi (sim_ofile, flag, cptr);            /* do show */
4386     fclose (sim_ofile);
4387     }
4388 else {
4389     r = show_cmd_fi (stdout, flag, cptr);               /* no, stdout, log */
4390     if (sim_log && (sim_log != stdout))
4391         show_cmd_fi (sim_log, flag, cptr);
4392     if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
4393         show_cmd_fi (sim_deb, flag, cptr);
4394     }
4395 return r;
4396 }
4397 
4398 t_stat show_cmd_fi (FILE *ofile, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4399 {
4400 uint32 lvl = 0xFFFFFFFF;
4401 char gbuf[CBUFSIZE], *cvptr;
4402 CONST char *svptr;
4403 DEVICE *dptr;
4404 UNIT *uptr;
4405 MTAB *mptr;
4406 SHTAB *shtb = NULL, *shptr;
4407 
4408 GET_SWITCHES (cptr);                                    /* get switches */
4409 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#'))   /* must be more */
4410     return SCPE_2FARG;
4411 cptr = get_glyph (svptr = cptr, gbuf, 0);               /* get next glyph */
4412 
4413 if ((dptr = find_dev (gbuf))) {                         /* device match? */
4414     uptr = dptr->units;                                 /* first unit */
4415     shtb = show_dev_tab;                                /* global table */
4416     lvl = MTAB_VDV;                                     /* device match */
4417     GET_SWITCHES (cptr);                                /* get more switches */
4418     }
4419 else if ((dptr = find_unit (gbuf, &uptr))) {            /* unit match? */
4420     if (uptr == NULL)                                   /* invalid unit */
4421         return sim_messagef (SCPE_NXUN, "Non-existent unit: %s\n", gbuf);
4422     if (uptr->flags & UNIT_DIS)                         /* disabled? */
4423         return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", gbuf);
4424     shtb = show_unit_tab;                               /* global table */
4425     lvl = MTAB_VUN;                                     /* unit match */
4426     GET_SWITCHES (cptr);                                /* get more switches */
4427     }
4428 else if ((shptr = find_shtab (show_glob_tab, gbuf))) {  /* global? */
4429     GET_SWITCHES (cptr);                                /* get more switches */
4430     return shptr->action (ofile, NULL, NULL, shptr->arg, cptr);
4431     }
4432 else {
4433     if (sim_dflt_dev && sim_dflt_dev->modifiers) {
4434         if ((cvptr = strchr (gbuf, '=')))               /* = value? */
4435             *cvptr++ = 0;
4436         for (mptr = sim_dflt_dev->modifiers; mptr && (mptr->mask != 0); mptr++) {
4437             if ((((mptr->mask & MTAB_VDV) == MTAB_VDV) &&
4438                  (mptr->pstring && (MATCH_CMD (gbuf, mptr->pstring) == 0))) || //-V600
4439                 (!(mptr->mask & MTAB_VDV) && (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)))) {
4440                 dptr = sim_dflt_dev;
4441                 lvl = MTAB_VDV;                         /* device match */
4442                 cptr = svptr;
4443                 while (sim_isspace(*cptr))
4444                     ++cptr;
4445                 break;
4446                 }
4447             }
4448         }
4449     if (!dptr) {
4450         if (sim_dflt_dev && (shptr = find_shtab (show_dev_tab, gbuf)))  /* global match? */
4451             return shptr->action (ofile, sim_dflt_dev, uptr, shptr->arg, cptr);
4452         else
4453             return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf);/* no match */
4454         }
4455     }
4456 
4457 if ((*cptr == 0) || (*cptr == ';') || (*cptr == '#')) { /* now eol? */
4458     return (lvl == MTAB_VDV)?
4459         show_device (ofile, dptr, 0):
4460         show_unit (ofile, dptr, uptr, -1);
4461     }
4462 GET_SWITCHES (cptr);                                    /* get more switches */
4463 
4464 while (*cptr != 0) {                                    /* do all mods */
4465     cptr = get_glyph (cptr, gbuf, ',');                 /* get modifier */
4466     if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
4467         *cvptr++ = 0;
4468     for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) {
4469         if (((mptr->mask & MTAB_XTD)?                   /* right level? */
4470             ((mptr->mask & lvl) == lvl): (MTAB_VUN & lvl)) &&
4471             ((mptr->disp && mptr->pstring &&            /* named disp? */
4472             (MATCH_CMD (gbuf, mptr->pstring) == 0))
4473             )) {
4474             if (cvptr && !MODMASK(mptr,MTAB_SHP))
4475                 return sim_messagef (SCPE_ARG, "Invalid Argument: %s=%s\n", gbuf, cvptr);
4476             show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1);
4477             break;
4478             }                                           /* end if */
4479         }                                               /* end for */
4480     if (!mptr || (mptr->mask == 0)) {                   /* no match? */
4481         if (shtb && (shptr = find_shtab (shtb, gbuf))) {/* global match? */
4482             t_stat r;
4483 
4484             r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr);
4485             if (r != SCPE_OK)
4486                 return r;
4487             }
4488         else {
4489             if (!dptr->modifiers)                       /* no modifiers? */
4490                 return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\n", dptr->name);
4491             else
4492                 return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\n", gbuf);
4493             }
4494         }                                               /* end if */
4495     }                                                   /* end while */
4496 return SCPE_OK;
4497 }
4498 
4499 SHTAB *find_shtab (SHTAB *tab, const char *gbuf)
     /* [previous][next][first][last][top][bottom][index][help] */
4500 {
4501 if (!tab)
4502     return NULL;
4503 for (; tab->name != NULL; tab++) {
4504     if (MATCH_CMD (gbuf, tab->name) == 0)
4505         return tab;
4506     }
4507 return NULL;
4508 }
4509 
4510 /* Show device and unit */
4511 
4512 t_stat show_device (FILE *st, DEVICE *dptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4513 {
4514 uint32 j, udbl, ucnt;
4515 UNIT *uptr;
4516 int32 toks = 0;
4517 
4518 if (strcmp(sim_dname (dptr),"SYS") != 0) {
4519 (void)fprintf (st, "%s", sim_dname (dptr));                   /* print dev name */
4520 if ((flag == 2) && dptr->description) {
4521     (void)fprintf (st, "\t%s\n", dptr->description(dptr));
4522     }
4523 else {
4524     if ((sim_switches & SWMASK ('D')) && dptr->description)
4525         (void)fprintf (st, "\t%s\n", dptr->description(dptr));
4526     }
4527 if (qdisable (dptr)) {                                  /* disabled? */
4528     (void)fprintf (st, "\tdisabled\n");
4529     return SCPE_OK;
4530     }
4531 for (j = ucnt = udbl = 0; j < dptr->numunits; j++) {    /* count units */
4532     uptr = dptr->units + j;
4533     if (!(uptr->flags & UNIT_DIS))                      /* count enabled units */
4534         ucnt++;
4535     else if (uptr->flags & UNIT_DISABLE)
4536         udbl++;                                         /* count user-disabled */
4537     }
4538 //show_all_mods (st, dptr, dptr->units, MTAB_VDV, &toks); /* show dev mods */
4539 if (dptr->numunits == 0) {
4540     // if (toks) //-V547
4541     //     (void)fprintf (st, "\n");
4542 }
4543  else
4544 {
4545     if (ucnt == 0) {
4546         fprint_sep (st, &toks);
4547         (void)fprintf (st, "all units disabled\n");
4548         }
4549     else if ((ucnt + udbl) == 1) {
4550         fprint_sep (st, &toks);
4551         (void)fprintf (st, " 1 unit\n");
4552         }
4553     else if ((ucnt > 1) || (udbl > 0)) {
4554         fprint_sep (st, &toks);
4555         (void)fprintf (st, "%2.d units\n", ucnt + udbl);
4556         }
4557     else
4558         if ((flag != 2) || !dptr->description || toks)
4559             (void)fprintf (st, "\n");
4560     toks = 0;
4561 }
4562 if (flag)                                               /* dev only? */
4563     return SCPE_OK;
4564 for (j = 0; j < dptr->numunits; j++) {                  /* loop thru units */
4565     uptr = dptr->units + j;
4566     if ((uptr->flags & UNIT_DIS) == 0)
4567         show_unit (st, dptr, uptr, ucnt + udbl);
4568     }
4569 }
4570 return SCPE_OK;
4571 }
4572 
4573 void fprint_sep (FILE *st, int32 *tokens)
     /* [previous][next][first][last][top][bottom][index][help] */
4574 {
4575 (void)fprintf (st, "%s", (*tokens > 0) ? "" : "\t");
4576 *tokens += 1;
4577 }
4578 
4579 t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
4580 {
4581 int32 u = (int32)(uptr - dptr->units);
4582 int32 toks = 0;
4583 
4584 if (flag > 1)
4585     (void)fprintf (st, "   %s%d \n", sim_dname (dptr), u);
4586 else if (flag < 0)
4587     (void)fprintf (st, " %s%d ", sim_dname (dptr), u);
4588 if (uptr->flags & UNIT_ATT) {
4589     fprint_sep (st, &toks);
4590     (void)fprintf (st, "status   : attached to %s", uptr->filename);
4591     if (uptr->flags & UNIT_RO)
4592         (void)fprintf (st, ", read only");
4593     }
4594 else {
4595     if (uptr->flags & UNIT_ATTABLE) {
4596         fprint_sep (st, &toks);
4597         (void)fprintf (st, "status   : not attached");
4598         }
4599     }
4600 if ((uptr->capac > 0) && (uptr->flags & UNIT_FIX)) {
4601     fprint_sep (st, &toks);
4602     fprint_capac (st, dptr, uptr);
4603     }
4604 show_all_mods (st, dptr, uptr, MTAB_VUN, &toks);        /* show unit mods */
4605 if (toks || (flag < 0) || (flag > 1))
4606     (void)fprintf (st, "\n");
4607 return SCPE_OK;
4608 }
4609 
4610 const char *sprint_capac (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4611 {
4612 static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
4613 t_offset kval = (t_offset)((uptr->flags & UNIT_BINK) ? 1024: 1000);
4614 t_offset mval;
4615 t_offset psize = (t_offset)uptr->capac;
4616 char *scale, *width;
4617 
4618 if (sim_switches & SWMASK ('B'))
4619     kval = 1024;
4620 mval = kval * kval;
4621 if (dptr->flags & DEV_SECTORS) {
4622     kval = kval / 512;
4623     mval = mval / 512;
4624     }
4625 if ((dptr->dwidth / dptr->aincr) > 8)
4626     width = "W";
4627 else
4628     width = "B";
4629 if ((psize < (kval * 10)) &&
4630     (0 != (psize % kval))) {
4631     scale = "";
4632     }
4633 else if ((psize < (mval * 10)) &&
4634          (0 != (psize % mval))){
4635     scale = "K";
4636     psize = psize / kval;
4637     }
4638 else {
4639     scale = "M";
4640     psize = psize / mval;
4641     }
4642 sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT);
4643 (void)sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width);
4644 return capac_buf;
4645 }
4646 
4647 void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4648 {
4649 (void)fprintf (st, " %s", sprint_capac (dptr, uptr));
4650 }
4651 
4652 /* Show <global name> processors  */
4653 
4654 extern void print_default_base_system_script (void);
4655 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] */
4656 {
4657 #if !defined(PERF_STRIP)
4658   print_default_base_system_script();
4659 #endif /* if !defined(PERF_STRIP) */
4660   return 0;
4661 }
4662 
4663 static void printp (unsigned char * PROM, char * label, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4664   sim_printf (" %s ", label);
4665   sim_printf ("   %2d     %3o(8)     '", length, offset);
4666   for (int l = 0; l < length; l ++)
4667     {
4668       unsigned int byte = PROM[offset + l];
4669       if (byte == 255)
4670         {
4671           byte = ' ';
4672         }
4673       sim_printf (isprint (byte) ? "%c" : "\\%03o", byte);
4674     }
4675   sim_printf ("'\r\n");
4676 }
4677 
4678 static void strip_spaces(char* str) {
     /* [previous][next][first][last][top][bottom][index][help] */
4679   int i, x;
4680   for (i=x=0; str[i]; ++i)
4681     {
4682       if (!isspace((int)str[i]) || (i > 0 && !isspace((int)str[(int)(i-1)]))) //-V781
4683         {
4684           str[x++] = str[i];
4685         }
4686     }
4687   str[x] = '\0';
4688   i = -1;
4689   x = 0;
4690   while (str[x] != '\0')
4691     {
4692       if (str[x] != ' ' && str[x] != '\t' && str[x] != '\n')
4693         {
4694           i=x;
4695         }
4696       x++;
4697     }
4698   str[i+1] = '\0';
4699 }
4700 
4701 static void printpq (unsigned char * PROM, FILE * st, int offset, int length) {
     /* [previous][next][first][last][top][bottom][index][help] */
4702   char sx[1024];
4703   sx[1023] = '\0';
4704   unsigned int lastbyte = 0;
4705   for (int l = 0; l < length; l ++)
4706     {
4707       unsigned int byte = PROM[offset + l];
4708       if (byte == 255)
4709         {
4710           byte = 20;
4711         }
4712       if ((lastbyte != 20) && (byte != 20))
4713         {
4714           (void)sprintf(&sx[l], isprint (byte) ? "%c" : " ", byte);
4715         }
4716       lastbyte = byte;
4717     }
4718   strip_spaces(sx);
4719   (void)fprintf (st, "%s", sx);
4720 }
4721 
4722 t_stat show_prom (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4723 {
4724   unsigned char PROM[1024];
4725   setupPROM (0, PROM);
4726 
4727   sim_printf (" PROM size: %llu bytes\r\n",
4728               (long long unsigned)sizeof(PROM));
4729   sim_printf (" PROM initialization data:\r\n\r\n");
4730 
4731   sim_printf ("     Field Description      Length   Offset              Contents\r\n");
4732   sim_printf (" ========================= ======== ======== ==================================\r\n");
4733   sim_printf ("\r\n");
4734 
4735   //                      Field                 Offset       Length
4736   //             -------------------------    ----------   ----------
4737   printp (PROM, "CPU Model                ",       0,          11);
4738   printp (PROM, "CPU Serial               ",      11,          11);
4739   printp (PROM, "Ship Date                ",      22,           6);
4740   printp (PROM, "PROM Layout Version      ",      60,           1);
4741   printp (PROM, "Release Git Commit Date  ",      70,          10);
4742   printp (PROM, "Release Major            ",      80,           3);
4743   printp (PROM, "Release Minor            ",      83,           3);
4744   printp (PROM, "Release Patch            ",      86,           3);
4745   printp (PROM, "Release Iteration        ",      89,           3);
4746   printp (PROM, "Release Build Number     ",      92,           8);  /* Reserved */
4747   printp (PROM, "Release Type             ",     100,           1);
4748   printp (PROM, "Release Version Text     ",     101,          29);
4749   printp (PROM, "Build Architecture       ",     130,          20);
4750   printp (PROM, "Build Operating System   ",     150,          20);
4751   printp (PROM, "Target Architecture      ",     170,          20);
4752   printp (PROM, "Target Operating System  ",     190,          20);
4753 
4754   sim_printf("\r\n");
4755   return 0;
4756 }
4757 
4758 t_stat show_buildinfo (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4759 {
4760     (void)fprintf (st, "\r Build Information:\n");
4761 #if defined(BUILDINFO_scp)
4762     (void)fprintf (st, "\r\n      Compilation info: %s\n", BUILDINFO_scp );
4763 #else
4764     (void)fprintf (st, "\r\n      Compilation info: Not available\n" );
4765 #endif
4766 #if !defined(__CYGWIN__)
4767 # if !defined(__APPLE__)
4768 #  if !defined(_AIX)
4769 #   if !defined(__MINGW32__)
4770 #    if !defined(__MINGW64__)
4771 #     if !defined(CROSS_MINGW32)
4772 #      if !defined(CROSS_MINGW64)
4773 #       if !defined(_WIN32)
4774 #        if !defined(__HAIKU__)
4775 #         if !defined(__QNX__)
4776     (void)dl_iterate_phdr (dl_iterate_phdr_callback, NULL);
4777     if (dl_iterate_phdr_callback_called)
4778         (void)fprintf (st, "\n");
4779     dl_iterate_phdr_callback_called = 0;
4780 #         endif
4781 #        endif
4782 #       endif
4783 #      endif
4784 #     endif
4785 #    endif
4786 #   endif
4787 #  endif
4788 # endif
4789 #endif
4790 #if defined(UV_VERSION_MAJOR) && \
4791     defined(UV_VERSION_MINOR) && \
4792     defined(UV_VERSION_PATCH)
4793 # if defined(UV_VERSION_MAJOR)
4794 #  if !defined(UV_VERSION_MINOR) && \
4795       !defined(UV_VERSION_PATCH) && \
4796       !defined(UV_VERSION_SUFFIX)
4797     (void)fprintf (st, "\r\n    Event loop library: Built with libuv v%d", UV_VERSION_MAJOR);
4798 #  endif /* if !defined(UV_VERSION_MINOR) && !defined(UV_VERSION_PATCH) && defined(UV_VERSION_SUFFIX) */
4799 #  if defined(UV_VERSION_MINOR)
4800 #   if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX)
4801     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d", UV_VERSION_MAJOR,
4802                    UV_VERSION_MINOR);
4803 #   endif /* if !defined(UV_VERSION_PATCH) && !defined(UV_VERSION_SUFFIX) */
4804 #   if defined(UV_VERSION_PATCH)
4805 #    if !defined(UV_VERSION_SUFFIX)
4806     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4807                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4808 #    endif /* if !defined(UV_VERSION_SUFFIX) */
4809 #    if defined(UV_VERSION_SUFFIX)
4810     (void)fprintf (st, "\r\n    Event loop library: Built with libuv %d.%d.%d", UV_VERSION_MAJOR,
4811                    UV_VERSION_MINOR, UV_VERSION_PATCH);
4812 #     if defined(UV_VERSION_IS_RELEASE)
4813 #      if UV_VERSION_IS_RELEASE == 1
4814 #       define UV_RELEASE_TYPE " (release)"
4815 #      endif /* if UV_VERSION_IS_RELEASE == 1 */
4816 #      if UV_VERSION_IS_RELEASE == 0
4817 #       define UV_RELEASE_TYPE "-dev"
4818 #      endif /* if UV_VERSION_IS_RELEASE == 0 */
4819 #      if !defined(UV_RELEASE_TYPE)
4820 #       define UV_RELEASE_TYPE ""
4821 #      endif /* if !defined(UV_RELEASE_TYPE) */
4822 #      if defined(UV_RELEASE_TYPE)
4823     (void)fprintf (st, "%s", UV_RELEASE_TYPE);
4824 #      endif /* if defined(UV_RELEASE_TYPE) */
4825 #     endif /* if defined(UV_VERSION_IS_RELEASE) */
4826 #    endif /* if defined(UV_VERSION_SUFFIX) */
4827 #   endif /* if defined(UV_VERSION_PATCH) */
4828 #  endif /* if defined(UV_VERSION_MINOR) */
4829     unsigned int CurrentUvVersion = uv_version();
4830     if (CurrentUvVersion > 0)
4831         if (uv_version_string() != NULL)
4832             (void)fprintf (st, "; %s in use", uv_version_string());
4833 # endif /* if defined(UV_VERSION_MAJOR) */
4834 #else
4835     (void)fprintf (st, "\r\n    Event loop library: Using libuv (or compatible) library, unknown version");
4836 #endif /* if defined(UV_VERSION_MAJOR) &&  \
4837         *    defined(UV_VERSION_MINOR) &&  \
4838         *    defined(UV_VERSION_PATCH)     \
4839         */
4840     (void)fprintf (st, "\r\n   Log support library: Built with libsir %d.%d.%d%s%s; %s%s in use",
4841                    SIR_VERSION_MAJOR, SIR_VERSION_MINOR, SIR_VERSION_PATCH,
4842                    SIR_VERSION_SUFFIX, SIR_VERSION_IS_RELEASE ? " (release)" : "",
4843                    sir_getversionstring(), SIR_VERSION_IS_RELEASE ? "" : sir_isprerelease() ? "" : " (release)");
4844 #if defined(DECNUMBERLOC)
4845 # if defined(DECVERSION)
4846 #  if defined(DECVERSEXT)
4847     (void)fprintf (st, "\r\n          Math library: %s-%s", DECVERSION, DECVERSEXT);
4848 #  else
4849 #   if defined(DECNLAUTHOR)
4850     (void)fprintf (st, "\r\n          Math library: %s (%s and contributors)", DECVERSION, DECNLAUTHOR);
4851 #   else
4852     (void)fprintf (st, "\r\n          Math library: %s", DECVERSION);
4853 #   endif /* if defined(DECNLAUTHOR) */
4854 #  endif /* if defined(DECVERSEXT) */
4855 # else
4856     (void)fprintf (st, "\r\n          Math library: decNumber, unknown version");
4857 # endif /* if defined(DECVERSION) */
4858 #endif /* if defined(DECNUMBERLOC) */
4859 #if defined(LOCKLESS)
4860     (void)fprintf (st, "\r\n     Atomic operations: ");
4861 # if defined(AIX_ATOMICS)
4862     (void)fprintf (st, "C11 and IBM AIX-style");
4863 # elif defined(BSD_ATOMICS)
4864     (void)fprintf (st, "C11 and FreeBSD-style");
4865 # elif defined(GNU_ATOMICS)
4866     (void)fprintf (st, "C11 and GNU-style");
4867 # elif defined(SYNC_ATOMICS)
4868     (void)fprintf (st, "C11 and GNU sync-style");
4869 # elif defined(ISO_ATOMICS)
4870     (void)fprintf (st, "ISO/IEC 9899:2011 (C11) standard");
4871 # elif defined(NT_ATOMICS)
4872     (void)fprintf (st, "C11 and Windows NT interlocked operations");
4873 # endif
4874 #endif /* if defined(LOCKLESS) */
4875     (void)fprintf (st, "\r\n          File locking: ");
4876 #if defined(USE_FCNTL) && defined(USE_FLOCK)
4877     (void)fprintf (st, "POSIX-style fcntl() and BSD-style flock() locking");
4878 #endif
4879 #if defined(USE_FCNTL) && !defined(USE_FLOCK)
4880     (void)fprintf (st, "POSIX-style fcntl() locking");
4881 #endif
4882 #if defined(USE_FLOCK) && !defined(USE_FCNTL)
4883     (void)fprintf (st, "BSD-style flock() locking");
4884 #endif
4885 #if !defined(USE_FLOCK) && !defined(USE_FCNTL)
4886     (void)fprintf (st, "No file locking available");
4887 #endif
4888     (void)fprintf (st, "\r\n       Windows support: ");
4889 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
4890 # if defined(__MINGW64_VERSION_STR)
4891     (void)fprintf (st, "Built with MinGW-w64 %s", __MINGW64_VERSION_STR);
4892 # elif defined(__MINGW32_MAJOR_VERSION) && defined(__MINGW32_MINOR_VERSION)
4893     (void)fprintf (st, "Built with MinGW %d.%d", __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
4894 # else
4895     (void)fprintf (st, "Built with MinGW");
4896 # endif
4897 
4898 # if defined(MINGW_CRT)
4899     (void)fprintf (st, "; %s", MINGW_CRT);
4900 #  if !defined(_UCRT)
4901 #   if defined(__MSVCRT_VERSION__)
4902 #    if __MSVCRT_VERSION__ > 0x00
4903     (void)fprintf (st, " %d.%d", (__MSVCRT_VERSION__ >> CHAR_BIT) & UCHAR_MAX, __MSVCRT_VERSION__ & UCHAR_MAX);
4904 #    endif
4905 #   endif
4906 #  else
4907 
4908     struct UCRTVersion ucrtversion;
4909     int result = GetUCRTVersion (&ucrtversion);
4910 
4911     if (result == 0)
4912       (void)fprintf (st, " %u.%u.%u.%u",
4913                      ucrtversion.ProductVersion[1], ucrtversion.ProductVersion[0],
4914                      ucrtversion.ProductVersion[3], ucrtversion.ProductVersion[2]);
4915 #  endif
4916     (void)fprintf (st, " in use");
4917 # endif
4918 #elif defined(__CYGWIN__)
4919     struct utsname utsname;
4920     (void)fprintf (st, "Built with Cygwin %d.%d.%d",
4921                    CYGWIN_VERSION_DLL_MAJOR / 1000,
4922                    CYGWIN_VERSION_DLL_MAJOR % 1000,
4923                    CYGWIN_VERSION_DLL_MINOR);
4924     if (uname(&utsname) == 0)
4925       fprintf (st, "; %s in use", utsname.release);
4926 #else
4927     (void)fprintf (st, "Disabled");
4928 #endif
4929 
4930     (void)fprintf (st, "\r\n");
4931     return 0;
4932 }
4933 
4934 t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4935 {
4936 const char *arch = "";
4937 char *whydirty = " ";
4938 int dirty = 0;
4939 
4940 if (cptr && (*cptr != 0))
4941     return SCPE_2MARG;
4942 if (flag) {
4943         (void)fprintf (st, " %s Simulator:", sim_name);
4944 #if defined(USE_DUMA)
4945 # undef NO_SUPPORT_VERSION
4946 # define NO_SUPPORT_VERSION 1
4947         nodist++;
4948 #endif /* if defined(USE_DUMA) */
4949 #if defined(NO_SUPPORT_VERSION) ||  \
4950     defined(WITH_SOCKET_DEV)    ||  \
4951     defined(WITH_ABSI_DEV)      ||  \
4952     defined(WITH_MGP_DEV)       ||  \
4953     defined(TESTING)            ||  \
4954     defined(ISOLTS)             ||  \
4955     defined(USE_DUMA)
4956 # if !defined(NO_SUPPORT_VERSION)
4957 #  define NO_SUPPORT_VERSION 1
4958 # endif /* if !defined(NO_SUPPORT_VERSION) */
4959 #endif
4960 #if defined(NO_SUPPORT_VERSION)
4961         dirty++;
4962 #endif
4963 #if defined(GENERATED_MAKE_VER_H)
4964 # if defined(VER_H_GIT_VERSION)
4965 
4966         /* Dirty if git source is dirty */
4967         if (strstr(VER_H_GIT_VERSION, "*"))
4968           {
4969                 dirty++;
4970           }
4971 
4972         /* Dirty if version contains "X", "D", "A", or "B" */
4973         if ((strstr(VER_H_GIT_VERSION, "X")) ||  \
4974             (strstr(VER_H_GIT_VERSION, "D")) ||  \
4975             (strstr(VER_H_GIT_VERSION, "A")) ||  \
4976             (strstr(VER_H_GIT_VERSION, "B")))
4977           {
4978                 dirty++;
4979           }
4980 
4981         /* Why? */
4982         if (dirty) //-V547
4983           {
4984             if ((strstr(VER_H_GIT_VERSION, "X")))
4985               {
4986                     whydirty = " ";
4987               }
4988             else if ((strstr(VER_H_GIT_VERSION, "D")))
4989               {
4990                     whydirty = " DEV ";
4991               }
4992             else if ((strstr(VER_H_GIT_VERSION, "A")))
4993               {
4994                     whydirty = " ALPHA ";
4995               }
4996             else if ((strstr(VER_H_GIT_VERSION, "B")))
4997               {
4998                     whydirty = " BETA ";
4999               }
5000           }
5001 
5002 #  if defined(VER_H_GIT_PATCH) && defined(VER_H_GIT_PATCH_INT)
5003 #   if defined(VER_H_GIT_HASH)
5004 #    if VER_H_GIT_PATCH_INT < 1
5005     (void)fprintf (st, "\n   Version: %s (%ld-bit)\n    Commit: %s",
5006                    VER_H_GIT_VERSION,
5007                    (long)(CHAR_BIT*sizeof(void *)),
5008                    VER_H_GIT_HASH);
5009 #    else
5010 #     define NO_SUPPORT_VERSION 1
5011     (void)fprintf (st, "\n   Version: %s+%s (%ld-bit)\n    Commit: %s",
5012                    VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5013                    (long)(CHAR_BIT*sizeof(void *)),
5014                    VER_H_GIT_HASH);
5015 #    endif
5016 #   else
5017 #    if VER_H_GIT_PATCH_INT < 1
5018         (void)fprintf (st, "\n   Version: %s (%ld-bit)",
5019                        VER_H_GIT_VERSION,
5020                        (long)(CHAR_BIT*sizeof(void *)));
5021 #    else
5022 #     define NO_SUPPORT_VERSION 1
5023         (void)fprintf (st, "\n   Version: %s+%s (%ld-bit)",
5024                        VER_H_GIT_VERSION, VER_H_GIT_PATCH,
5025                        (long)(CHAR_BIT*sizeof(void *)));
5026 #    endif
5027 #   endif
5028 #  else
5029 #   if defined(VER_H_GIT_HASH)
5030         (void)fprintf (st, "\n   Version: %s (%ld-bit)\n    Commit: %s",
5031                        VER_H_GIT_VERSION,
5032                        (long)(CHAR_BIT*sizeof(void *)),
5033                        VER_H_GIT_HASH);
5034 #   else
5035         (void)fprintf (st, "\n   Version: %s (%ld-bit)",
5036                        VER_H_GIT_VERSION,
5037                        (long)(CHAR_BIT*sizeof(void *)));
5038 #   endif
5039 #  endif
5040 # endif
5041 #endif
5042 
5043 /* TESTING */
5044 #if defined(TESTING)
5045     (void)fprintf (st, "\n   Options: ");
5046 # if !defined(HAVE_DPSOPT)
5047 #  define HAVE_DPSOPT 1
5048 # endif
5049     (void)fprintf (st, "TESTING");
5050 #endif /* if defined(TESTING) */
5051 
5052 /* ISOLTS */
5053 #if defined(ISOLTS)
5054 # if defined(HAVE_DPSOPT)
5055     (void)fprintf (st, ", ");
5056 # else
5057     (void)fprintf (st, "\n   Options: ");
5058 # endif
5059 # if !defined(HAVE_DPSOPT)
5060 #  define HAVE_DPSOPT 1
5061 # endif
5062     (void)fprintf (st, "ISOLTS");
5063 #endif /* if defined(ISOLTS) */
5064 
5065 /* NO_UCACHE */
5066 #if defined(NO_UCACHE)
5067 # if defined(HAVE_DPSOPT)
5068     (void)fprintf (st, ", ");
5069 # else
5070     (void)fprintf (st, "\n   Options: ");
5071 # endif
5072 # if !defined(HAVE_DPSOPT)
5073 #  define HAVE_DPSOPT 1
5074 # endif
5075     (void)fprintf (st, "NO_UCACHE");
5076 #endif /* if defined(NO_UCACHE) */
5077 
5078 /* NEED_128 */
5079 #if defined(NEED_128)
5080 # if defined(HAVE_DPSOPT)
5081     (void)fprintf (st, ", ");
5082 # else
5083     (void)fprintf (st, "\n   Options: ");
5084 # endif
5085 # if !defined(HAVE_DPSOPT)
5086 #  define HAVE_DPSOPT 1
5087 # endif
5088     (void)fprintf (st, "NEED_128");
5089 #endif /* if defined(NEED_128) */
5090 
5091 /* WAM */
5092 #if defined(WAM)
5093 # if defined(HAVE_DPSOPT)
5094     (void)fprintf (st, ", ");
5095 # else
5096     (void)fprintf (st, "\n   Options: ");
5097 # endif
5098 # if !defined(HAVE_DPSOPT)
5099 #  define HAVE_DPSOPT 1
5100 # endif
5101     (void)fprintf (st, "WAM");
5102 #endif /* if defined(WAM) */
5103 
5104 /* ROUND_ROBIN */
5105 #if defined(ROUND_ROBIN)
5106 # if defined(HAVE_DPSOPT)
5107     (void)fprintf (st, ", ");
5108 # else
5109     (void)fprintf (st, "\n   Options: ");
5110 # endif
5111 # if !defined(HAVE_DPSOPT)
5112 #  define HAVE_DPSOPT 1
5113 # endif
5114     (void)fprintf (st, "ROUND_ROBIN");
5115 #endif /* if defined(ROUND_ROBIN) */
5116 
5117 /* NO_LOCKLESS */
5118 #if !defined(LOCKLESS)
5119 # if defined(HAVE_DPSOPT)
5120     (void)fprintf (st, ", ");
5121 # else
5122     (void)fprintf (st, "\n   Options: ");
5123 # endif
5124 # if !defined(HAVE_DPSOPT)
5125 #  define HAVE_DPSOPT 1
5126 # endif
5127     (void)fprintf (st, "NO_LOCKLESS");
5128 #endif /* if !defined(LOCKLESS) */
5129 
5130 /* ABSI */  /* XXX: Change to NO_ABSI once code is non-experimental */
5131 #if defined(WITH_ABSI_DEV)
5132 # if defined(HAVE_DPSOPT)
5133     (void)fprintf (st, ", ");
5134 # else
5135     (void)fprintf (st, "\n   Options: ");
5136 # endif
5137 # if !defined(HAVE_DPSOPT)
5138 #  define HAVE_DPSOPT 1
5139 # endif
5140     (void)fprintf (st, "ABSI");
5141 #endif /* if defined(WITH_ABSI_DEV) */
5142 
5143 /* SOCKET */  /* XXX: Change to NO_SOCKET once code is non-experimental */
5144 #if defined(WITH_SOCKET_DEV)
5145 # if defined(HAVE_DPSOPT)
5146     (void)fprintf (st, ", ");
5147 # else
5148     (void)fprintf (st, "\n   Options: ");
5149 # endif
5150 # if !defined(HAVE_DPSOPT)
5151 #  define HAVE_DPSOPT 1
5152 # endif
5153     (void)fprintf (st, "SOCKET");
5154 #endif /* if defined(WITH_SOCKET_DEV) */
5155 
5156 /* CHAOSNET */  /* XXX: Change to NO_CHAOSNET once code is non-experimental */
5157 #if defined(WITH_MGP_DEV)
5158 # if defined(HAVE_DPSOPT)
5159     (void)fprintf (st, ", ");
5160 # else
5161     (void)fprintf (st, "\n   Options: ");
5162 # endif
5163 # if !defined(HAVE_DPSOPT)
5164 #  define HAVE_DPSOPT 1
5165 # endif
5166     (void)fprintf (st, "CHAOSNET");
5167 # if USE_SOCKET_DEV_APPROACH
5168     (void)fprintf (st, "-S");
5169 # endif /* if USE_SOCKET_DEV_APPROACH */
5170 #endif /* if defined(WITH_MGP_DEV) */
5171 
5172 /* DUMA */
5173 #if defined(USE_DUMA)
5174 # if defined(HAVE_DPSOPT)
5175     (void)fprintf (st, ", ");
5176 # else
5177     (void)fprintf (st, "\n   Options: ");
5178 # endif
5179 # if !defined(HAVE_DPSOPT)
5180 #  define HAVE_DPSOPT 1
5181 # endif
5182     (void)fprintf (st, "DUMA");
5183 #endif /* if defined(USE_DUMA) */
5184 
5185 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE)
5186 # if defined(NO_SUPPORT_VERSION)
5187     (void)fprintf (st, "\n  Modified: %s", VER_H_GIT_DATE);
5188 # else
5189     (void)fprintf (st, "\n  Released: %s", VER_H_GIT_DATE);
5190 # endif
5191 #endif
5192 #if defined(GENERATED_MAKE_VER_H) && defined(VER_H_GIT_DATE) && defined(VER_H_PREP_DATE)
5193     (void)fprintf (st, " - Kit Prepared: %s", VER_H_PREP_DATE);
5194 #endif
5195 #if defined(VER_CURRENT_TIME)
5196     (void)fprintf (st, "\n  Compiled: %s", VER_CURRENT_TIME);
5197 #endif
5198     if (dirty) //-V547
5199       {
5200         (void)fprintf (st, "\r\n\r\n ****** THIS%sBUILD IS NOT SUPPORTED BY THE DPS8M DEVELOPMENT TEAM ******", whydirty);
5201       }
5202     (void)fprintf (st, "\r\n\r\n Build Information:");
5203 #if defined(BUILD_PROM_OSV_TEXT) && defined(BUILD_PROM_OSA_TEXT)
5204     char build_os_version_raw[255];
5205     char build_os_arch_raw[255];
5206     (void)sprintf(build_os_version_raw, "%.254s", BUILD_PROM_OSV_TEXT);
5207     (void)sprintf(build_os_arch_raw, "%.254s", BUILD_PROM_OSA_TEXT);
5208     char *build_os_version = strdup(build_os_version_raw);
5209     if (!build_os_version)
5210       {
5211         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5212                        __func__, __FILE__, __LINE__);
5213 # if defined(USE_BACKTRACE)
5214 #  if defined(SIGUSR2)
5215         (void)raise(SIGUSR2);
5216         /*NOTREACHED*/ /* unreachable */
5217 #  endif /* if defined(SIGUSR2) */
5218 # endif /* if defined(USE_BACKTRACE) */
5219         abort();
5220       }
5221     char *build_os_arch = strdup(build_os_arch_raw);
5222     if (!build_os_arch)
5223       {
5224         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5225                        __func__, __FILE__, __LINE__);
5226 # if defined(USE_BACKTRACE)
5227 #  if defined(SIGUSR2)
5228         (void)raise(SIGUSR2);
5229         /*NOTREACHED*/ /* unreachable */
5230 #  endif /* if defined(SIGUSR2) */
5231 # endif /* if defined(USE_BACKTRACE) */
5232         abort();
5233       }
5234     unsigned char SPROM[1024];
5235     setupPROM (0, SPROM);
5236     (void)fprintf (st, "\n    Target: ");
5237     printpq (SPROM, st, 190, 20);
5238     if (SPROM[170] != 20)
5239       {
5240         if (SPROM[170] != 255)
5241           {
5242             (void)fprintf (st, " on ");
5243             printpq (SPROM, st, 170, 20);
5244           }
5245       }
5246     strtrimspace(build_os_version, build_os_version_raw);
5247     strtrimspace(build_os_arch, build_os_arch_raw);
5248     (void)fprintf (st, "\n  Build OS: %s %s", build_os_version, build_os_arch);
5249     FREE(build_os_version);
5250     FREE(build_os_arch);
5251 #endif
5252 #if defined(__VERSION__)
5253     char gnumver[2];
5254     char postver[1024];
5255     (void)sprintf(gnumver, "%.1s", __VERSION__);
5256     (void)sprintf(postver, "%.1023s", __VERSION__);
5257     strremove(postver, "(TM)");
5258     strremove(postver, "(R)");
5259     strremove(postver, "git://github.com/OpenIndiana/oi-userland.git ");
5260     strremove(postver, "https://github.com/OpenIndiana/oi-userland.git ");
5261     strremove(postver, " gcc 4.9 mode");
5262     strremove(postver, "4.2.1 Compatible ");
5263     strremove(postver, "git@github.com:llvm/llvm-project.git ");
5264     strremove(postver, "https://github.com/llvm/llvm-project.git ");
5265     strremove(postver, " (https://github.com/yrnkrn/zapcc)");
5266     strremove(postver, "https://github.com/yrnkrn/zapcc ");
5267     strremove(postver, "(experimental) ");
5268     strremove(postver, ".module+el8.7.0+20823+214a699d");
5269     strremove(postver, "17.1.1 (5725-C72, 5765-J20), version ");
5270     strremove(postver, "17.1.1 (5725-C72, 5765-J18), version ");
5271     strremove(postver, "17.1.2 (5725-C72, 5765-J20), version ");
5272     strremove(postver, "17.1.2 (5725-C72, 5765-J18), version ");
5273     strremove(postver, "llvmorg-16.0.6-0-");
5274     strremove(postver, " Clang 15.0.0 (build 760095e)");
5275     strremove(postver, " Clang 15.0.0 (build 6af5742)");
5276     strremove(postver, " Clang 15.0.0 (build ca7115e)");
5277     strremove(postver, " Clang 15.0.0 (build 232543c)");
5278     strremove(postver, " Clang 17.0.6 (build 19a779f)");
5279     strremove(postver, "CLANG: ");
5280 #endif
5281 #if ( defined(__GNUC__) && defined(__VERSION__) ) && !defined(__EDG__)
5282 # if !defined(__clang_version__)
5283     if (isdigit((unsigned char)gnumver[0])) {
5284         (void)fprintf (st, "\n  Compiler: GCC %s", postver);
5285     } else {
5286         (void)fprintf (st, "\n  Compiler: %s", postver);
5287     }
5288 # endif
5289 # if defined(__clang_analyzer__ )
5290     (void)fprintf (st, "\n  Compiler: Clang C/C++ Static Analyzer");
5291 # elif defined(__clang_version__) && defined(__VERSION__)
5292     char clangllvmver[1024];
5293     (void)sprintf(clangllvmver, "%.1023s", __clang_version__);
5294     strremove(clangllvmver, "git://github.com/OpenIndiana/oi-userland.git ");
5295     strremove(clangllvmver, "https://github.com/OpenIndiana/oi-userland.git ");
5296     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git ");
5297     strremove(clangllvmver, "c13b7485b87909fcf739f62cfa382b55407433c0");
5298     strremove(clangllvmver, "e6c3289804a67ea0bb6a86fadbe454dd93b8d855");
5299     strremove(clangllvmver, "https://github.com/llvm/llvm-project.git");
5300     strremove(clangllvmver, " ( )");
5301     strremove(clangllvmver, " ()");
5302     if (gnumver[0] == 'c' || gnumver[0] == 'C') {
5303         (void)fprintf (st, "\n  Compiler: Clang %s", clangllvmver);
5304     } else {
5305         (void)fprintf (st, "\n  Compiler: %s", postver);
5306     }
5307 # elif defined(__clang_version__)
5308     (void)fprintf (st, "\n  Compiler: %s", postver);
5309 # endif
5310 #elif defined(__PGI) && !defined(__NVCOMPILER)
5311     (void)fprintf (st, "\n  Compiler: Portland Group, Inc. (PGI) C Compiler ");
5312 # if defined(__PGIC__)
5313     (void)fprintf (st, "%d", __PGIC__);
5314 #  if defined(__PGIC_MINOR__)
5315     (void)fprintf (st, ".%d", __PGIC_MINOR__);
5316 #   if defined(__PGIC_PATCHLEVEL__)
5317     (void)fprintf (st, ".%d", __PGIC_PATCHLEVEL__);
5318 #   endif
5319 #  endif
5320 # endif
5321 #elif defined(__NVCOMPILER)
5322     (void)fprintf (st, "\n  Compiler: NVIDIA HPC SDK C Compiler ");
5323 # if defined(__NVCOMPILER_MAJOR__)
5324     (void)fprintf (st, "%d", __NVCOMPILER_MAJOR__);
5325 #  if defined(__NVCOMPILER_MINOR__)
5326     (void)fprintf (st, ".%d", __NVCOMPILER_MINOR__);
5327 #   if defined(__NVCOMPILER_PATCHLEVEL__)
5328     (void)fprintf (st, ".%d", __NVCOMPILER_PATCHLEVEL__);
5329 #   endif
5330 #  endif
5331 # endif
5332 #elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
5333     (void)fprintf (st, "\n  Compiler: Microsoft C %d.%02d.%05d.%02d",
5334                    _MSC_FULL_VER/10000000,
5335                    (_MSC_FULL_VER/100000)%100,
5336                    _MSC_FULL_VER%100000,
5337                    _MSC_BUILD);
5338 #elif ( defined(__xlc__) && !defined(__clang_version__) )
5339 # if defined(_AIX) && defined(__PASE__)
5340     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ V%s (PASE for IBM i)", __xlc__);
5341 # endif
5342 # if defined(_AIX) && !defined(__PASE__)
5343     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ for AIX V%s", __xlc__);
5344 # endif
5345 # if defined(__linux__) && ( !defined(_AIX) || !defined(__PASE__) )
5346     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ for Linux V%s", __xlc__);
5347 # endif
5348 # if ( !defined(_AIX) && !defined(__clang_version__) && !defined(__PASE__) && !defined(__linux__) && defined(__xlc__) )
5349 #  if defined(__PPC__) && defined(__APPLE__)
5350     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ V%s for Mac OS X", __xlc__);
5351 #  else
5352     (void)fprintf (st, "\n  Compiler: IBM XL C/C++ V%s", __xlc__);
5353 #  endif
5354 # endif
5355 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__SUNPRO_CC_COMPAT)
5356 # define VER_ENC(maj, min, rev) \
5357   (((maj) * 1000000) + ((min) * 1000) + (rev))
5358 # define VER_DEC_MAJ(ver) \
5359   ((ver) / 1000000)
5360 # define VER_DEC_MIN(ver) \
5361   (((ver) % 1000000) / 1000)
5362 # define VER_DEC_REV(ver) \
5363   ((ver) % 1000)
5364 # if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
5365 #  define COMP_VER VER_ENC(                                        \
5366    (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
5367    (((__SUNPRO_C >>  8) & 0xf) * 10) + ((__SUNPRO_C >>  4) & 0xf), \
5368      (__SUNPRO_C & 0xf) * 10)
5369 # elif defined(__SUNPRO_C)
5370 #  define COMP_VER VER_ENC(    \
5371      (__SUNPRO_C >>  8) & 0xf, \
5372      (__SUNPRO_C >>  4) & 0xf, \
5373      (__SUNPRO_C) & 0xf)
5374 # elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
5375 #  define COMP_VER VER_ENC(                                          \
5376    (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
5377    (((__SUNPRO_CC >>  8) & 0xf) * 10) + ((__SUNPRO_CC >>  4) & 0xf), \
5378      (__SUNPRO_CC & 0xf) * 10)
5379 # elif defined(__SUNPRO_CC)
5380 #  define COMP_VER VER_ENC(     \
5381      (__SUNPRO_CC >>  8) & 0xf, \
5382      (__SUNPRO_CC >>  4) & 0xf, \
5383      (__SUNPRO_CC) & 0xf)
5384 # endif
5385 # if !defined(COMP_VER)
5386 #  define COMP_VER 0
5387 # endif
5388     (void)fprintf (st, "\n  Compiler: Oracle Developer Studio C/C++ %d.%d.%d",
5389                    VER_DEC_MAJ(COMP_VER),
5390                    VER_DEC_MIN(COMP_VER),
5391                    VER_DEC_REV(COMP_VER));
5392 #elif defined(__DMC__)
5393     (void)fprintf (st, "\n  Compiler: Digital Mars C/C++");
5394 #elif defined(__PCC__)
5395     (void)fprintf (st, "\n  Compiler: Portable C Compiler");
5396 #elif defined(KENC) || defined(KENCC) || defined(__KENC__) || defined(__KENCC__)
5397     (void)fprintf (st, "\n  Compiler: Plan 9 Compiler Suite");
5398 #elif defined(__ACK__)
5399     (void)fprintf (st, "\n  Compiler: Amsterdam Compiler Kit");
5400 #elif defined(__COMO__)
5401     (void)fprintf (st, "\n  Compiler: Comeau C++");
5402 #elif defined(__COMPCERT__)
5403     (void)fprintf (st, "\n  Compiler: CompCert C");
5404 #elif defined(__COVERITY__)
5405     (void)fprintf (st, "\n  Compiler: Coverity C/C++ Static Analyzer");
5406 #elif defined(__LCC__)
5407 # if defined(__e2k__) || defined(__e2k64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__elbrus64__) || defined(__E2K__)
5408     (void)fprintf (st, "\n  Compiler: MCST Elbrus C Compiler");
5409 #  if __LCC__ > 99
5410     (void)fprintf(st, " - LCC %1.2f", (double)(__LCC__) / (double)100);
5411 #   if defined(__LCC_MINOR__)
5412 #    if __LCC_MINOR__ > 0
5413     (void)fprintf(st, ".%02ld", (long)(__LCC_MINOR__));
5414 #    endif
5415 #   endif
5416 #  endif
5417 #  if defined(__EDG__) && defined(__EDG_VERSION__)
5418 #   if __EDG_VERSION__ > 99
5419     (void)fprintf(st, " - EDG %d.%d", (int)((__EDG_VERSION__) / 100),
5420                   (int)(((__EDG_VERSION__) % 100) % 10));
5421 #   endif
5422 #  endif
5423 # else
5424     (void)fprintf (st, "\n  Compiler: Local/Little C Compiler (lcc)");
5425 # endif
5426 #elif defined(sgi) || defined(__sgi) || defined(_sgi) || defined(_SGI_COMPILER_VERSION)
5427     (void)fprintf (st, "\n  Compiler: SGI MIPSpro");
5428 #elif defined(__OPEN64__)
5429     (void)fprintf (st, "\n  Compiler: Open64 %s", __OPEN64__);
5430 #elif defined(__PGI) || defined(__PGIC__)
5431     (void)fprintf (st, "\n  Compiler: Portland Group/PGI C/C++");
5432 #elif defined(__VBCC__)
5433     (void)fprintf (st, "\n  Compiler: Volker Barthelmann C Compiler (vbcc)");
5434 #elif defined(__WATCOMC__)
5435     (void)fprintf (st, "\n  Compiler: Watcom C/C++ %d.%d",
5436                    __WATCOMC__ / 100,
5437                    __WATCOMC__ % 100);
5438 #elif defined(__xlC__)
5439     (void)fprintf (st, "\n  Compiler: IBM XL C/C++");
5440 #elif defined(__INTEL_COMPILER) || defined(__ICC)
5441 # if defined(__INTEL_COMPILER_UPDATE)
5442 #  if defined(__INTEL_COMPILER_BUILD_DATE)
5443     (void)fprintf (st, "\n  Compiler: Intel C++ Compiler %d.%d (%d)",
5444                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE,
5445                    __INTEL_COMPILER_BUILD_DATE);
5446 #  else
5447     (void)fprintf (st, "\n  Compiler: Intel C++ Compiler %d.%d",
5448                    __INTEL_COMPILER, __INTEL_COMPILER_UPDATE);
5449 #  endif
5450 # else
5451     (void)fprintf (st, "\n  Compiler: Intel C++ Compiler %d",
5452                    __INTEL_COMPILER);
5453 # endif
5454 #elif defined(SIM_COMPILER)
5455 # define S_xstr(a) S_str(a)
5456 # define S_str(a) #a
5457     (void)fprintf (st, "\n  Compiler: %s", S_xstr(SIM_COMPILER));
5458 # undef S_str
5459 # undef S_xstr
5460 #else
5461     (void)fprintf (st, "\n  Compiler: Unknown");
5462 #endif
5463 
5464 #if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5465     defined(__POWERPC64__) || defined(_M_PPC64) || defined(__PPC64) || defined(_ARCH_PPC64)
5466 # define SC_IS_PPC64 1
5467 #else
5468 # define SC_IS_PPC64 0
5469 #endif
5470 
5471 #if defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__PPC) || \
5472     defined(__ppc32__) || defined(__PPC32__) || defined(__powerpc32__) || defined(__POWERPC32__) || defined(_M_PPC32) || \
5473     defined(__PPC32)
5474 # define SC_IS_PPC32 1
5475 #else
5476 # define SC_IS_PPC32 0
5477 #endif
5478 
5479 #if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5480     arch = " x86_64";
5481 #elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5482     arch = " x86";
5483 #elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5484     arch = " arm64";
5485 #elif defined(_M_ARM) || defined(__arm__)
5486     arch = " arm";
5487 #elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5488     arch = " ia64";
5489 #elif SC_IS_PPC64
5490     arch = " powerpc64";
5491 #elif SC_IS_PPC32
5492     arch = " powerpc";
5493 #elif defined(__s390x__)
5494     arch = " s390x";
5495 #elif defined(__s390__)
5496     arch = " s390";
5497 #elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5498     arch = " j2";
5499 #elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5500     arch = " sh4";
5501 #elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5502     arch = " sh2";
5503 #elif defined(__alpha__)
5504     arch = " alpha";
5505 #elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5506     arch = " hppa";
5507 #elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5508     arch = " ice9";
5509 #elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5510     arch = " mips64";
5511 #elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5512     arch = " mips";
5513 #elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || \
5514       defined(__OR1K__) || defined(__JOR1K__) || defined(__OPENRISC1K__) || defined(__OPENRISC1200__)
5515     arch = " openrisc";
5516 #elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5517     arch = " sparc64";
5518 #elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5519     arch = " sparc";
5520 #elif defined(__riscv) || defined(__riscv__)
5521     arch = " riscv";
5522 #elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__)
5523     arch = " e2k";
5524 #elif defined(__myriad2__)
5525     arch = " myriad2";
5526 #elif defined(__loongarch64) || defined(__loongarch__)
5527     arch = " loongarch";
5528 #elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5529     arch = " m68k";
5530 #elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5531     arch = " m88k";
5532 #elif defined(__VAX__) || defined(__vax__)
5533     arch = " vax";
5534 #elif defined(__NIOS2__) || defined(__nios2__)
5535     arch = " nios2";
5536 #elif defined(__MICROBLAZE__) || defined(__microblaze__)
5537     arch = " microblaze";
5538 #else
5539     arch = " ";
5540 #endif
5541     (void)fprintf (st, "%s", arch);
5542 #if defined(BUILD_BY_USER)
5543         (void)fprintf (st, "\n  Built by: %s", BUILD_BY_USER);
5544 #else
5545 # if defined(GENERATED_MAKE_VER_H) && defined(VER_H_PREP_USER)
5546         (void)fprintf (st, "\n  Built by: %s", VER_H_PREP_USER);
5547 # endif
5548 #endif
5549                 (void)fprintf (st, "\n\n Host System Information:");
5550 #if defined(_WIN32)
5551     if (1) {
5552         char *arch = getenv ("PROCESSOR_ARCHITECTURE");
5553         char *proc_arch3264 = getenv ("PROCESSOR_ARCHITEW6432");
5554         char osversion[PATH_MAX+1] = "";
5555         FILE *f;
5556 
5557         if ((f = _popen ("ver", "r"))) {
5558             (void)memset (osversion, 0, sizeof(osversion));
5559             do {
5560                 if (NULL == fgets (osversion, sizeof(osversion)-1, f))
5561                     break;
5562                 sim_trim_endspc (osversion);
5563                 } while (osversion[0] == '\0');
5564             _pclose (f);
5565             }
5566         (void)fprintf (st, "\n   Host OS: %s", osversion);
5567         (void)fprintf (st, " %s%s%s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264  : "");
5568         }
5569 #else
5570     if (1) {
5571         char osversion[2*PATH_MAX+1] = "";
5572         FILE *f;
5573 # if !defined(_AIX)
5574         if ((f = popen \
5575              ("uname -mrs 2> /dev/null", "r"))) {
5576 # else
5577         if ((f = popen \
5578              ("sh -c 'echo \"$(command -p env uname -v \
5579                2> /dev/null).$(command -p env uname -r \
5580                2> /dev/null) $(command -p env uname -p \
5581                2> /dev/null)\"' 2> /dev/null", "r"))) {
5582 # endif /* if !defined(_AIX) */
5583             (void)memset (osversion, 0, sizeof(osversion));
5584             do {
5585               if (NULL == fgets (osversion, sizeof(osversion)-1, f)) {
5586                     break;
5587               }
5588             sim_trim_endspc (osversion);
5589             } while (osversion[0] == '\0');
5590             pclose (f);
5591             strremove(osversion, "0000000000000000 ");
5592             strremove(osversion, " 0000000000000000");
5593             strremove(osversion, "000000000000 ");
5594             strremove(osversion, " 000000000000");
5595             strremove(osversion, "IBM ");
5596             strremove(osversion, " (emulated by qemu)");
5597             strremove(osversion, " (emulated by QEMU)");
5598         }
5599 # if !defined(_AIX)
5600             (void)fprintf (st, "\n   Host OS: %s", osversion);
5601 # else
5602             strremove(osversion, "AIX ");
5603 #  if !defined(__PASE__)
5604             (void)fprintf (st, "\n   Host OS: IBM AIX %s", osversion);
5605 #  else
5606             (void)fprintf (st, "\n   Host OS: IBM OS/400 (PASE) %s", osversion);
5607 #  endif /* if !defined(__PASE__) */
5608 # endif /* if !defined(_AIX) */
5609     } else {
5610 # if !defined(_AIX)
5611         (void)fprintf (st, "\n   Host OS: Unknown");
5612 # else
5613 #  if !defined(__PASE__)
5614         (void)fprintf (st, "\n   Host OS: IBM AIX");
5615 #  else
5616         (void)fprintf (st, "\n   Host OS: IBM OS/400 (PASE)");
5617 #  endif /* if !defined(__PASE__) */
5618 # endif /* if !defined(_AIX) */
5619     }
5620 #endif
5621 #if defined(__APPLE__)
5622     int isRosetta = processIsTranslated();
5623     if (isRosetta == 1) {
5624         sim_printf ("\n\n  ****** RUNNING UNDER APPLE ROSETTA 2, EXPECT REDUCED PERFORMANCE ******");
5625     }
5626 #endif
5627     if (nodist)
5628       {
5629         sim_printf ("\n\n ********* LICENSE RESTRICTED BUILD *** NOT FOR REDISTRIBUTION *********\n");
5630       }
5631     else
5632       {
5633         (void)fprintf (st, "\n");
5634         (void)fprintf (st, "\n This software is made available under the terms of the ICU License.");
5635         (void)fprintf (st, "\n For complete license details, see the LICENSE file included with the");
5636         (void)fprintf (st, "\n software or https://gitlab.com/dps8m/dps8m/-/blob/master/LICENSE.md");
5637       }
5638         (void)fprintf (st, "\n");
5639     }
5640 return SCPE_OK;
5641 }
5642 
5643 t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5644 {
5645 size_t i;
5646 DEVICE *dptr;
5647 t_bool only_enabled = (sim_switches & SWMASK ('E'));
5648 
5649 if (cptr && (*cptr != 0))
5650     return SCPE_2MARG;
5651 (void)fprintf (st, "%s simulator configuration%s\n\n", sim_name, only_enabled ? " (enabled devices)" : "");
5652 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5653     if (!only_enabled || !qdisable (dptr))
5654         show_device (st, dptr, flag);
5655 return SCPE_OK;
5656 }
5657 
5658 t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5659 {
5660 int32 i;
5661 DEVICE *dptr;
5662 
5663 if (cptr && (*cptr != 0))
5664     return SCPE_2MARG;
5665 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5666     show_dev_logicals (st, dptr, NULL, 1, cptr);
5667 return SCPE_OK;
5668 }
5669 
5670 t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5671 {
5672 if (dptr->lname)
5673     (void)fprintf (st, "%s -> %s\n", dptr->lname, dptr->name);
5674 else if (!flag)
5675     fputs ("no logical name assigned\n", st);
5676 return SCPE_OK;
5677 }
5678 
5679 t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5680 {
5681 DEVICE *dptr;
5682 UNIT *uptr;
5683 int32 accum;
5684 
5685 if (cptr && (*cptr != 0))
5686     return SCPE_2MARG;
5687 if (sim_clock_queue == QUEUE_LIST_END)
5688     (void)fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructions/sec\n",
5689                    sim_name, sim_time, sim_timer_inst_per_sec ());
5690 else {
5691     const char *tim;
5692 
5693     (void)fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\n",
5694                    sim_name, sim_time, sim_timer_inst_per_sec ());
5695     accum = 0;
5696     for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
5697         if (uptr == &sim_step_unit)
5698             (void)fprintf (st, "  Step timer");
5699         else
5700             if (uptr == &sim_expect_unit)
5701                 (void)fprintf (st, "  Expect fired");
5702             else
5703                 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
5704                     (void)fprintf (st, "  %s", sim_dname (dptr));
5705                     if (dptr->numunits > 1)
5706                         (void)fprintf (st, " unit %d", (int32) (uptr - dptr->units));
5707                     }
5708                 else
5709                     (void)fprintf (st, "  Unknown");
5710         tim = sim_fmt_secs((accum + uptr->time)/sim_timer_inst_per_sec ());
5711         (void)fprintf (st, " at %d%s%s%s%s\n", accum + uptr->time,
5712                        (*tim) ? " (" : "", tim, (*tim) ? ")" : "",
5713                        (uptr->flags & UNIT_IDLE) ? " (Idle capable)" : "");
5714         accum = accum + uptr->time;
5715         }
5716     }
5717 sim_show_clock_queues (st, dnotused, unotused, flag, cptr);
5718 return SCPE_OK;
5719 }
5720 
5721 t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5722 {
5723 if (cptr && (*cptr != 0))
5724     return SCPE_2MARG;
5725 (void)fprintf (st, "Time:\t%.0f\n", sim_gtime());
5726 return SCPE_OK;
5727 }
5728 
5729 t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5730 {
5731 t_stat r;
5732 
5733 if (cptr && (*cptr != 0))
5734     r = ssh_break (st, cptr, 1);  /* more? */
5735 else
5736     r = sim_brk_showall (st, (uint32)sim_switches);
5737 return r;
5738 }
5739 
5740 t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5741 {
5742 (void)fprintf (st, "Radix=%d\n", dptr->dradix);
5743 return SCPE_OK;
5744 }
5745 
5746 t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5747 {
5748 int32 any = 0;
5749 DEBTAB *dep;
5750 
5751 if (dptr->flags & DEV_DEBUG) {
5752     if (dptr->dctrl == 0)
5753         fputs ("Debugging disabled", st);
5754     else if (dptr->debflags == NULL)
5755         fputs ("Debugging enabled", st);
5756     else {
5757         uint32 dctrl = dptr->dctrl;
5758 
5759         fputs ("Debug=", st);
5760         for (dep = dptr->debflags; (dctrl != 0) && (dep->name != NULL); dep++) {
5761             if ((dctrl & dep->mask) == dep->mask) {
5762                 dctrl &= ~dep->mask;
5763                 if (any)
5764                     fputc (';', st);
5765                 fputs (dep->name, st);
5766                 any = 1;
5767                 }
5768             }
5769         }
5770     fputc ('\n', st);
5771     return SCPE_OK;
5772     }
5773 else return SCPE_NOFNC;
5774 }
5775 
5776 /* Show On actions */
5777 
5778 t_stat show_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5779 {
5780 int32 lvl, i;
5781 
5782 if (cptr && (*cptr != 0)) return SCPE_2MARG;            /* now eol? */
5783 for (lvl=sim_do_depth; lvl >= 0; --lvl) {
5784     if (lvl > 0)
5785         (void)fprintf(st, "On Processing at Do Nest Level: %d", lvl);
5786     else
5787         (void)fprintf(st, "On Processing for input commands");
5788     (void)fprintf(st, " is %s\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
5789     for (i=1; i<SCPE_BASE; ++i) {
5790         if (sim_on_actions[lvl][i])
5791             (void)fprintf(st, "    on %5d    %s\n", i, sim_on_actions[lvl][i]); }
5792     for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
5793         if (sim_on_actions[lvl][i])
5794             (void)fprintf(st, "    on %-5s    %s\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
5795     if (sim_on_actions[lvl][0])
5796         (void)fprintf(st, "    on ERROR    %s\n", sim_on_actions[lvl][0]);
5797     (void)fprintf(st, "\n");
5798     }
5799 if (sim_on_inherit)
5800     (void)fprintf(st, "on state and actions are inherited by nested do commands and subroutines\n");
5801 return SCPE_OK;
5802 }
5803 
5804 /* Show modifiers */
5805 
5806 t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5807 {
5808 int32 i;
5809 DEVICE *dptr;
5810 
5811 if (cptr && (*cptr != 0))                               /* now eol? */
5812     return SCPE_2MARG;
5813 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5814     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5815 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5816     show_dev_modifiers (st, dptr, NULL, flag, cptr);
5817 return SCPE_OK;
5818 }
5819 
5820 t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5821 {
5822 fprint_set_help (st, dptr);
5823 return SCPE_OK;
5824 }
5825 
5826 t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, int32 *toks)
     /* [previous][next][first][last][top][bottom][index][help] */
5827 {
5828 MTAB *mptr;
5829 t_stat r = SCPE_OK;
5830 
5831 if (dptr->modifiers == NULL)
5832     return SCPE_OK;
5833 for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) {
5834     if (mptr->pstring &&
5835         ((mptr->mask & MTAB_XTD)?
5836             (MODMASK(mptr,flag) && !MODMASK(mptr,MTAB_NMO)):
5837             ((MTAB_VUN == (uint32)flag) && ((uptr->flags & mptr->mask) == mptr->match)))) {
5838         if (*toks > 0) {
5839             (void)fprintf (st, "\n");
5840             *toks = 0;
5841             }
5842         if (r == SCPE_OK)
5843             fprint_sep (st, toks);
5844         r = show_one_mod (st, dptr, uptr, mptr, NULL, 0);
5845         }
5846     }
5847 return SCPE_OK;
5848 }
5849 
5850 t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr,
     /* [previous][next][first][last][top][bottom][index][help] */
5851     CONST char *cptr, int32 flag)
5852 {
5853 t_stat r = SCPE_OK;
5854 
5855 if (mptr->disp)
5856     r = mptr->disp (st, uptr, mptr->match, (CONST void *)(cptr? cptr: mptr->desc));
5857 else
5858     fputs (mptr->pstring, st);
5859 if ((r == SCPE_OK) && (flag && !((mptr->mask & MTAB_XTD) && MODMASK(mptr,MTAB_NMO))))
5860     fputc ('\n', st);
5861 return r;
5862 }
5863 
5864 /* Show show commands */
5865 
5866 t_stat show_show_commands (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5867 {
5868 int32 i;
5869 DEVICE *dptr;
5870 
5871 if (cptr && (*cptr != 0))                               /* now eol? */
5872     return SCPE_2MARG;
5873 for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
5874     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5875 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
5876     show_dev_show_commands (st, dptr, NULL, flag, cptr);
5877 return SCPE_OK;
5878 }
5879 
5880 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] */
5881 {
5882 fprint_show_help (st, dptr);
5883 return SCPE_OK;
5884 }
5885 
5886 /* Breakpoint commands */
5887 
5888 t_stat brk_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5889 {
5890 GET_SWITCHES (cptr);                                    /* get switches */
5891 return ssh_break (NULL, cptr, flg);                     /* call common code */
5892 }
5893 
5894 t_stat ssh_break (FILE *st, const char *cptr, int32 flg)
     /* [previous][next][first][last][top][bottom][index][help] */
5895 {
5896 char gbuf[CBUFSIZE], *aptr, abuf[4*CBUFSIZE];
5897 CONST char *tptr, *t1ptr;
5898 DEVICE *dptr = sim_dflt_dev;
5899 UNIT *uptr;
5900 t_stat r;
5901 t_addr lo, hi, max;
5902 int32 cnt;
5903 
5904 if (sim_brk_types == 0)
5905     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5906 if (dptr == NULL)
5907     return SCPE_IERR;
5908 uptr = dptr->units;
5909 if (uptr == NULL)
5910     return SCPE_IERR;
5911 max = uptr->capac - 1;
5912 abuf[sizeof(abuf)-1] = '\0';
5913 strncpy (abuf, cptr, sizeof(abuf)-1);
5914 cptr = abuf;
5915 if ((aptr = strchr (abuf, ';'))) {                      /* ;action? */
5916     if (flg != SSH_ST)                                  /* only on SET */
5917         return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", aptr);
5918     *aptr++ = 0;                                        /* separate strings */
5919     }
5920 if (*cptr == 0) {                                       /* no argument? */
5921     lo = (t_addr) get_rval (sim_PC, 0);                 /* use PC */
5922     return ssh_break_one (st, flg, lo, 0, aptr);
5923     }
5924 while (*cptr) {
5925     cptr = get_glyph (cptr, gbuf, ',');
5926     tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0);
5927     if (tptr == NULL)
5928         return sim_messagef (SCPE_ARG, "Invalid address specifier: %s\n", gbuf);
5929     if (*tptr == '[') {
5930         cnt = (int32) strtotv (tptr + 1, &t1ptr, 10);
5931         if ((tptr == t1ptr) || (*t1ptr != ']') || (flg != SSH_ST))
5932             return sim_messagef (SCPE_ARG, "Invalid repeat count specifier: %s\n", tptr + 1);
5933         tptr = t1ptr + 1;
5934         }
5935     else cnt = 0;
5936     if (*tptr != 0)
5937         return sim_messagef (SCPE_ARG, "Unexpected argument: %s\n", tptr);
5938     if ((lo == 0) && (hi == max)) {
5939         if (flg == SSH_CL)
5940             sim_brk_clrall (sim_switches);
5941         else
5942             if (flg == SSH_SH)
5943                 sim_brk_showall (st, (uint32)sim_switches);
5944             else
5945                 return SCPE_ARG;
5946         }
5947     else {
5948         for ( ; lo <= hi; lo = lo + 1) {
5949             r = ssh_break_one (st, flg, lo, cnt, aptr);
5950             if (r != SCPE_OK)
5951                 return r;
5952             }
5953         }
5954     }
5955 return SCPE_OK;
5956 }
5957 
5958 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] */
5959 {
5960 if (!sim_brk_types)
5961     return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n");
5962 switch (flg) {
5963     case SSH_ST:
5964         return sim_brk_set (lo, sim_switches, cnt, aptr);
5965         /*NOTREACHED*/ /* unreachable */
5966         break;
5967 
5968     case SSH_CL:
5969         return sim_brk_clr (lo, sim_switches);
5970         /*NOTREACHED*/ /* unreachable */
5971         break;
5972 
5973     case SSH_SH:
5974         return sim_brk_show (st, lo, sim_switches);
5975         /*NOTREACHED*/ /* unreachable */
5976         break;
5977 
5978     default:
5979         return SCPE_ARG;
5980     }
5981 }
5982 
5983 /* Reset command and routines */
5984 
5985 static t_bool run_cmd_did_reset = FALSE;
5986 
5987 t_stat reset_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5988 {
5989 char gbuf[CBUFSIZE];
5990 DEVICE *dptr;
5991 
5992 GET_SWITCHES (cptr);                                    /* get switches */
5993 run_cmd_did_reset = FALSE;
5994 if (*cptr == 0)                                         /* reset(cr) */
5995     return (reset_all (0));
5996 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
5997 if (*cptr != 0)                                         /* now eol? */
5998     return SCPE_2MARG;
5999 if (strcmp (gbuf, "ALL") == 0)
6000     return (reset_all (0));
6001 dptr = find_dev (gbuf);                                 /* locate device */
6002 if (dptr == NULL)                                       /* found it? */
6003     return SCPE_NXDEV;
6004 if (dptr->reset != NULL)
6005     return dptr->reset (dptr);
6006 else return SCPE_OK;
6007 }
6008 
6009 /* Reset devices start..end
6010 
6011    Inputs:
6012         start   =       number of starting device
6013    Outputs:
6014         status  =       error status
6015 */
6016 
6017 t_stat reset_all (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6018 {
6019 DEVICE *dptr;
6020 uint32 i;
6021 t_stat reason;
6022 
6023 for (i = 0; i < start; i++) {
6024     if (sim_devices[i] == NULL)
6025         return SCPE_IERR;
6026     }
6027 for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
6028     if (dptr->reset != NULL) {
6029         reason = dptr->reset (dptr);
6030         if (reason != SCPE_OK)
6031             return reason;
6032         }
6033     }
6034 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
6035     if (dptr->reset != NULL) {
6036         reason = dptr->reset (dptr);
6037         if (reason != SCPE_OK)
6038             return reason;
6039         }
6040     }
6041 return SCPE_OK;
6042 }
6043 
6044 /* Reset to powerup state
6045 
6046    Inputs:
6047         start   =       number of starting device
6048    Outputs:
6049         status  =       error status
6050 */
6051 
6052 t_stat reset_all_p (uint32 start)
     /* [previous][next][first][last][top][bottom][index][help] */
6053 {
6054 t_stat r;
6055 int32 old_sw = sim_switches;
6056 
6057 sim_switches = SWMASK ('P');
6058 r = reset_all (start);
6059 sim_switches = old_sw;
6060 return r;
6061 }
6062 
6063 /* Attach command */
6064 
6065 t_stat attach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6066 {
6067 char gbuf[4*CBUFSIZE];
6068 DEVICE *dptr;
6069 UNIT *uptr;
6070 t_stat r;
6071 
6072 GET_SWITCHES (cptr);                                    /* get switches */
6073 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6074     return SCPE_2FARG;
6075 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6076 GET_SWITCHES (cptr);                                    /* get switches */
6077 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* now eol? */
6078     return SCPE_2FARG;
6079 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6080 if (dptr == NULL)                                       /* found dev? */
6081     return SCPE_NXDEV;
6082 if (uptr == NULL)                                       /* valid unit? */
6083     return SCPE_NXUN;
6084 if (uptr->flags & UNIT_ATT) {                           /* already attached? */
6085     if (!(uptr->dynflags & UNIT_ATTMULT) &&             /* and only single attachable */
6086         !(dptr->flags & DEV_DONTAUTO)) {                /* and auto detachable */
6087         r = scp_detach_unit (dptr, uptr);               /* detach it */
6088         if (r != SCPE_OK)                               /* error? */
6089             return r; }
6090     else {
6091         if (!(uptr->dynflags & UNIT_ATTMULT))
6092             return SCPE_ALATT;                          /* Already attached */
6093         }
6094     }
6095 gbuf[sizeof(gbuf)-1] = '\0';
6096 strncpy (gbuf, cptr, sizeof(gbuf)-1);
6097 sim_trim_endspc (gbuf);                                 /* trim trailing spc */
6098 return scp_attach_unit (dptr, uptr, gbuf);              /* attach */
6099 }
6100 
6101 /* Call device-specific or file-oriented attach unit routine */
6102 
6103 t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6104 {
6105 if (dptr->attach != NULL)                               /* device routine? */
6106     return dptr->attach (uptr, (CONST char *)cptr);     /* call it */
6107 return attach_unit (uptr, (CONST char *)cptr);          /* no, std routine */
6108 }
6109 
6110 /* Attach unit to file */
6111 
6112 t_stat attach_unit (UNIT *uptr, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6113 {
6114 DEVICE *dptr;
6115 
6116 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6117     return SCPE_UDIS;
6118 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
6119     return SCPE_NOATT;
6120 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6121     return SCPE_NOATT;
6122 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */
6123 if (uptr->filename == NULL)
6124     return SCPE_MEM;
6125 strncpy (uptr->filename, cptr, CBUFSIZE-1);             /* save name */
6126 if ((sim_switches & SWMASK ('R')) ||                    /* read only? */
6127     ((uptr->flags & UNIT_RO) != 0)) {
6128     if (((uptr->flags & UNIT_ROABLE) == 0) &&           /* allowed? */
6129         ((uptr->flags & UNIT_RO) == 0))
6130         return attach_err (uptr, SCPE_NORO);            /* no, error */
6131     uptr->fileref = sim_fopen (cptr, "rb");             /* open rd only */
6132     if (uptr->fileref == NULL)                          /* open fail? */
6133         return attach_err (uptr, SCPE_OPENERR);         /* yes, error */
6134     uptr->flags = uptr->flags | UNIT_RO;                /* set rd only */
6135     if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6136         sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
6137         }
6138     }
6139 else {
6140     if (sim_switches & SWMASK ('N')) {                  /* new file only? */
6141         uptr->fileref = sim_fopen (cptr, "wb+");        /* open new file */
6142         if (uptr->fileref == NULL)                      /* open fail? */
6143             return attach_err (uptr, SCPE_OPENERR);     /* yes, error */
6144         if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) {
6145             sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
6146             }
6147         }
6148     else {                                              /* normal */
6149         uptr->fileref = sim_fopen (cptr, "rb+");        /* open r/w */
6150         if (uptr->fileref == NULL) {                    /* open fail? */
6151 #if defined(EWOULDBLOCK)
6152             if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
6153 #else
6154             if ((errno == EAGAIN))
6155 #endif
6156                 return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6157 
6158 #if defined(EPERM)
6159             if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {/* read only? */
6160 #else
6161             if ((errno == EROFS) || (errno == EACCES)) {/* read only? */
6162 #endif
6163                 if ((uptr->flags & UNIT_ROABLE) == 0)   /* allowed? */
6164                     return attach_err (uptr, SCPE_NORO);/* no error */
6165                 uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */
6166                 if (uptr->fileref == NULL)              /* open fail? */
6167                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6168                 uptr->flags = uptr->flags | UNIT_RO;    /* set rd only */
6169                 if (!sim_quiet) {
6170                     sim_printf ("%s: unit is read only (%s)\n", sim_dname (dptr), cptr);
6171                     }
6172                 }
6173             else {                                      /* doesn't exist */
6174                 if (sim_switches & SWMASK ('E'))        /* must exist? */
6175                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6176                 uptr->fileref = sim_fopen (cptr, "wb+");/* open new file */
6177                 if (uptr->fileref == NULL)              /* open fail? */
6178                     return attach_err (uptr, SCPE_OPENERR); /* yes, error */
6179                 if (!sim_quiet) {
6180                     sim_printf ("%s: creating new file (%s)\n", sim_dname (dptr), cptr);
6181                     }
6182                 }
6183             }                                           /* end if null */
6184         }                                               /* end else */
6185     }
6186 if (uptr->flags & UNIT_BUFABLE) {                       /* buffer? */
6187     uint32 cap = ((uint32) uptr->capac) / dptr->aincr;  /* effective size */
6188     if (uptr->flags & UNIT_MUSTBUF)                     /* dyn alloc? */
6189         uptr->filebuf = calloc (cap, SZ_D (dptr));      /* allocate */
6190     if (uptr->filebuf == NULL)                          /* no buffer? */
6191         return attach_err (uptr, SCPE_MEM);             /* error */
6192     if (!sim_quiet) {
6193         sim_printf ("%s: buffering file in memory\n", sim_dname (dptr));
6194         }
6195     uptr->hwmark = (uint32)sim_fread (uptr->filebuf,    /* read file */
6196         SZ_D (dptr), cap, uptr->fileref);
6197     uptr->flags = uptr->flags | UNIT_BUF;               /* set buffered */
6198     }
6199 uptr->flags = uptr->flags | UNIT_ATT;
6200 uptr->pos = 0;
6201 return SCPE_OK;
6202 }
6203 
6204 t_stat attach_err (UNIT *uptr, t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
6205 {
6206 FREE (uptr->filename);
6207 uptr->filename = NULL;
6208 return stat;
6209 }
6210 
6211 /* Detach command */
6212 
6213 t_stat detach_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6214 {
6215 char gbuf[CBUFSIZE];
6216 DEVICE *dptr;
6217 UNIT *uptr;
6218 
6219 GET_SWITCHES (cptr);                                    /* get switches */
6220 if ((NULL == cptr) || (*cptr == 0)) //-V560             /* must be more */
6221     return SCPE_2FARG;
6222 cptr = get_glyph (cptr, gbuf, 0);                       /* get next glyph */
6223 if (*cptr != 0)                                         /* now eol? */
6224     return SCPE_2MARG;
6225 if (strcmp (gbuf, "ALL") == 0)
6226     return (detach_all (0, FALSE));
6227 dptr = find_unit (gbuf, &uptr);                         /* locate unit */
6228 if (dptr == NULL)                                       /* found dev? */
6229     return SCPE_NXDEV;
6230 if (uptr == NULL)                                       /* valid unit? */
6231     return SCPE_NXUN;
6232 return scp_detach_unit (dptr, uptr);                    /* detach */
6233 }
6234 
6235 /* Detach devices start..end
6236 
6237    Inputs:
6238         start   =       number of starting device
6239         shutdown =      TRUE if simulator shutting down
6240    Outputs:
6241         status  =       error status
6242 
6243    Note that during shutdown, detach routines for non-attachable devices
6244    will be called.  These routines can implement simulator shutdown.  Error
6245    returns during shutdown are ignored.
6246 */
6247 
6248 t_stat detach_all (int32 start, t_bool shutdown)
     /* [previous][next][first][last][top][bottom][index][help] */
6249 {
6250 uint32 i, j;
6251 DEVICE *dptr;
6252 UNIT *uptr;
6253 t_stat r;
6254 
6255 if ((start < 0) || (start > 1))
6256     return SCPE_IERR;
6257 if (shutdown)
6258     sim_switches = sim_switches | SIM_SW_SHUT;          /* flag shutdown */
6259 for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
6260     for (j = 0; j < dptr->numunits; j++) {              /* loop thru units */
6261         uptr = (dptr->units) + j;
6262         if ((uptr->flags & UNIT_ATT) ||                 /* attached? */
6263             (shutdown && dptr->detach &&                /* shutdown, spec rtn, */
6264             !(uptr->flags & UNIT_ATTABLE))) {           /* !attachable? */
6265             r = scp_detach_unit (dptr, uptr);           /* detach unit */
6266 
6267             if ((r != SCPE_OK) && !shutdown)            /* error and not shutting down? */
6268                 return r;                               /* bail out now with error status */
6269             }
6270         }
6271     }
6272 return SCPE_OK;
6273 }
6274 
6275 /* Call device-specific or file-oriented detach unit routine */
6276 
6277 t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6278 {
6279 if (dptr->detach != NULL)                               /* device routine? */
6280     return dptr->detach (uptr);
6281 return detach_unit (uptr);                              /* no, standard */
6282 }
6283 
6284 /* Detach unit from file */
6285 
6286 t_stat detach_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6287 {
6288 DEVICE *dptr;
6289 
6290 if (uptr == NULL)
6291     return SCPE_IERR;
6292 if (!(uptr->flags & UNIT_ATTABLE))                      /* attachable? */
6293     return SCPE_NOATT;
6294 if (!(uptr->flags & UNIT_ATT)) {                        /* not attached? */
6295     if (sim_switches & SIM_SW_REST)                     /* restoring? */
6296         return SCPE_OK;                                 /* allow detach */
6297     else
6298         return SCPE_NOTATT;                             /* complain */
6299     }
6300 if ((dptr = find_dev_from_unit (uptr)) == NULL)
6301     return SCPE_OK;
6302 if (uptr->flags & UNIT_BUF) {
6303     uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr;
6304     if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) {
6305         if (!sim_quiet) {
6306             sim_printf ("%s: writing buffer to file\n", sim_dname (dptr));
6307             }
6308         rewind (uptr->fileref);
6309         sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref);
6310         if (ferror (uptr->fileref))
6311             sim_printf ("%s: I/O error - %s (Error %d)",
6312                         sim_dname (dptr), xstrerror_l(errno), errno);
6313         }
6314     if (uptr->flags & UNIT_MUSTBUF) {                   /* dyn alloc? */
6315         FREE (uptr->filebuf);                           /* free buf */
6316         uptr->filebuf = NULL;
6317         }
6318     uptr->flags = uptr->flags & ~UNIT_BUF;
6319     }
6320 uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO);
6321 FREE (uptr->filename);
6322 uptr->filename = NULL;
6323 if (fclose (uptr->fileref) == EOF)
6324     return SCPE_IOERR;
6325 return SCPE_OK;
6326 }
6327 
6328 /* Get device display name */
6329 
6330 const char *sim_dname (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6331 {
6332 return (dptr ? (dptr->lname? dptr->lname: dptr->name) : "");
6333 }
6334 
6335 /* Get unit display name */
6336 
6337 const char *sim_uname (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6338 {
6339 DEVICE *d = find_dev_from_unit(uptr);
6340 static char uname[CBUFSIZE];
6341 
6342 if (!d)
6343     return "";
6344 if (d->numunits == 1)
6345     return sim_dname (d);
6346 (void)sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
6347 return uname;
6348 }
6349 
6350 /* Run, go, boot, cont, step, next commands */
6351 
6352 t_stat run_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6353 {
6354 char gbuf[CBUFSIZE] = "";
6355 CONST char *tptr;
6356 uint32 i, j;
6357 int32 sim_next = 0;
6358 int32 unitno;
6359 t_value pcv, orig_pcv;
6360 t_stat r;
6361 DEVICE *dptr;
6362 UNIT *uptr;
6363 
6364 GET_SWITCHES (cptr);                                    /* get switches */
6365 sim_step = 0;
6366 if ((flag == RU_RUN) || (flag == RU_GO)) {              /* run or go */
6367     orig_pcv = get_rval (sim_PC, 0);                    /* get current PC value */
6368     if (*cptr != 0) {                                   /* argument? */
6369         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6370         if (MATCH_CMD (gbuf, "UNTIL") != 0) {
6371             if (sim_dflt_dev && sim_vm_parse_addr)      /* address parser? */
6372                 pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr);
6373             else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */
6374             if ((tptr == gbuf) || (*tptr != 0) ||       /* error? */
6375                 (pcv > width_mask[sim_PC->width]))
6376                 return SCPE_ARG;
6377             put_rval (sim_PC, 0, pcv);                  /* Save in PC */
6378             }
6379         }
6380     if ((flag == RU_RUN) &&                             /* run? */
6381         ((r = sim_run_boot_prep (flag)) != SCPE_OK)) {  /* reset sim */
6382         put_rval (sim_PC, 0, orig_pcv);                 /* restore original PC */
6383         return r;
6384         }
6385     if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) { //-V600 /* should be end */
6386         int32 saved_switches = sim_switches;
6387 
6388         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6389             cptr = get_glyph (cptr, gbuf, 0);           /* get next glyph */
6390         if (MATCH_CMD (gbuf, "UNTIL") != 0)
6391             return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\n",
6392                                              (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr);
6393         sim_switches = 0;
6394         GET_SWITCHES (cptr);
6395         if ((*cptr == '\'') || (*cptr == '"')) {        /* Expect UNTIL condition */
6396             r = expect_cmd (1, cptr);
6397             if (r != SCPE_OK)
6398                 return r;
6399             }
6400         else {                                          /* BREAK UNTIL condition */
6401             if (sim_switches == 0)
6402                 sim_switches = sim_brk_dflt;
6403             sim_switches |= BRK_TYP_TEMP;               /* make this a one-shot breakpoint */
6404             sim_brk_types |= BRK_TYP_TEMP;
6405             r = ssh_break (NULL, cptr, SSH_ST);
6406             if (r != SCPE_OK)
6407                 return sim_messagef (r, "Unable to establish breakpoint at: %s\n", cptr);
6408             }
6409         sim_switches = saved_switches;
6410         }
6411     }
6412 
6413 else if ((flag == RU_STEP) ||
6414          ((flag == RU_NEXT) && !sim_vm_is_subroutine_call)) { /* step */
6415     static t_bool not_implemented_message = FALSE;
6416 
6417     if ((!not_implemented_message) && (flag == RU_NEXT)) {
6418         not_implemented_message = TRUE;
6419         flag = RU_STEP;
6420         }
6421     if (*cptr != 0) {                                   /* argument? */
6422         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6423         if (*cptr != 0)                                 /* should be end */
6424             return SCPE_2MARG;
6425         sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6426         if ((r != SCPE_OK) || (sim_step <= 0))          /* error? */
6427             return SCPE_ARG;
6428         }
6429     else sim_step = 1;
6430     if ((flag == RU_STEP) && (sim_switches & SWMASK ('T')))
6431         sim_step = (int32)((sim_timer_inst_per_sec ()*sim_step)/1000000.0);
6432     }
6433 else if (flag == RU_NEXT) {                             /* next */
6434     t_addr *addrs;
6435 
6436     if (*cptr != 0) {                                   /* argument? */
6437         cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
6438         if (*cptr != 0)                                 /* should be end */
6439             return SCPE_2MARG;
6440         sim_next = (int32) get_uint (gbuf, 10, INT_MAX, &r);
6441         if ((r != SCPE_OK) || (sim_next <= 0))          /* error? */
6442             return SCPE_ARG;
6443         }
6444     else sim_next = 1;
6445     if (sim_vm_is_subroutine_call(&addrs)) {
6446         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6447         for (i=0; addrs[i]; i++)
6448             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6449         }
6450     else
6451         sim_step = 1;
6452     }
6453 else if (flag == RU_BOOT) {                             /* boot */
6454     if (*cptr == 0)                                     /* must be more */
6455         return SCPE_2FARG;
6456     cptr = get_glyph (cptr, gbuf, 0);                   /* get next glyph */
6457     if (*cptr != 0)                                     /* should be end */
6458         return SCPE_2MARG;
6459     dptr = find_unit (gbuf, &uptr);                     /* locate unit */
6460     if (dptr == NULL)                                   /* found dev? */
6461         return SCPE_NXDEV;
6462     if (uptr == NULL)                                   /* valid unit? */
6463         return SCPE_NXUN;
6464     if (dptr->boot == NULL)                             /* can it boot? */
6465         return SCPE_NOFNC;
6466     if (uptr->flags & UNIT_DIS)                         /* disabled? */
6467         return SCPE_UDIS;
6468     if ((uptr->flags & UNIT_ATTABLE) &&                 /* if attable, att? */
6469         !(uptr->flags & UNIT_ATT))
6470         return SCPE_UNATT;
6471     unitno = (int32) (uptr - dptr->units);              /* recover unit# */
6472     if ((r = sim_run_boot_prep (flag)) != SCPE_OK)      /* reset sim */
6473         return r;
6474     if ((r = dptr->boot (unitno, dptr)) != SCPE_OK)     /* boot device */
6475         return r;
6476     }
6477 
6478 else
6479     if (flag != RU_CONT)                                /* must be cont */
6480         return SCPE_IERR;
6481     else                                                /* CONTINUE command */
6482         if (*cptr != 0)                                 /* should be end (no arguments allowed) */
6483             return sim_messagef (SCPE_2MARG, "CONTINUE command takes no arguments\n");
6484 
6485 if (sim_switches & SIM_SW_HIDE)                         /* Setup only for Remote Console Mode */
6486     return SCPE_OK;
6487 
6488 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* reposition all */
6489     for (j = 0; j < dptr->numunits; j++) {              /* seq devices */
6490         uptr = dptr->units + j;
6491         if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ))
6492             sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
6493         }
6494     }
6495 stop_cpu = 0;
6496 sim_is_running = 1;                                     /* flag running */
6497 if (sim_ttrun () != SCPE_OK) {                          /* set console mode */
6498     sim_is_running = 0;                                 /* flag idle */
6499     sim_ttcmd ();
6500     return SCPE_TTYERR;
6501     }
6502 if ((r = sim_check_console (30)) != SCPE_OK) {          /* check console, error? */
6503     sim_is_running = 0;                                 /* flag idle */
6504     sim_ttcmd ();
6505     return r;
6506     }
6507 #if !defined(IS_WINDOWS)
6508 # if defined(SIGINT)
6509 if (signal (SIGINT, int_handler) == SIG_ERR) {          /* set WRU */
6510     sim_is_running = 0;                                 /* flag idle */
6511     sim_ttcmd ();
6512     return SCPE_SIGERR;
6513     }
6514 # endif
6515 #endif
6516 #if !defined(IS_WINDOWS)
6517 # if defined(SIGHUP)
6518 if (signal (SIGHUP, int_handler) == SIG_ERR) {          /* set WRU */
6519     sim_is_running = 0;                                 /* flag idle */
6520     sim_ttcmd ();
6521     return SCPE_SIGERR;
6522     }
6523 # endif
6524 #endif
6525 #if !defined(IS_WINDOWS)
6526 # if defined(SIGTERM)
6527 if (signal (SIGTERM, int_handler) == SIG_ERR) {         /* set WRU */
6528     sim_is_running = 0;                                 /* flag idle */
6529     sim_ttcmd ();
6530     return SCPE_SIGERR;
6531     }
6532 # endif
6533 #endif
6534 if (sim_step)                                           /* set step timer */
6535     sim_activate (&sim_step_unit, sim_step);
6536 (void)fflush(stdout);                                   /* flush stdout */
6537 if (sim_log)                                            /* flush log if enabled */
6538     (void)fflush (sim_log);
6539 sim_rtcn_init_all ();                                   /* re-init clocks */
6540 sim_start_timer_services ();                            /* enable wall clock timing */
6541 
6542 do {
6543     t_addr *addrs;
6544 
6545     while (1) {
6546         r = sim_instr();
6547         if (r != SCPE_REMOTE)
6548             break;
6549         sim_remote_process_command ();                  /* Process the command and resume processing */
6550         }
6551     if ((flag != RU_NEXT) ||                            /* done if not doing NEXT */
6552         (--sim_next <=0))
6553         break;
6554     if (sim_step == 0) {                                /* doing a NEXT? */
6555         t_addr val;
6556         BRKTAB *bp;
6557 
6558         if (SCPE_BARE_STATUS(r) >= SCPE_BASE)           /* done if an error occurred */
6559             break;
6560         if (sim_vm_pc_value)                            /* done if didn't stop at a dynamic breakpoint */
6561             val = (t_addr)(*sim_vm_pc_value)();
6562         else
6563             val = (t_addr)get_rval (sim_PC, 0);
6564         if ((!(bp = sim_brk_fnd (val))) || (!(bp->typ & BRK_TYP_DYN_STEPOVER)))
6565             break;
6566         sim_brk_clrall (BRK_TYP_DYN_STEPOVER);          /* cancel any step/over subroutine breakpoints */
6567         }
6568     else {
6569         if (r != SCPE_STEP)                             /* done if step didn't complete with step expired */
6570             break;
6571         }
6572     /* setup another next/step */
6573     sim_step = 0;
6574     if (sim_vm_is_subroutine_call(&addrs)) {
6575         sim_brk_types |= BRK_TYP_DYN_STEPOVER;
6576         for (i=0; addrs[i]; i++)
6577             sim_brk_set (addrs[i], BRK_TYP_DYN_STEPOVER, 0, NULL);
6578         }
6579     else
6580         sim_step = 1;
6581     if (sim_step)                                       /* set step timer */
6582         sim_activate (&sim_step_unit, sim_step);
6583     } while (1);
6584 
6585 sim_is_running = 0;                                     /* flag idle */
6586 sim_stop_timer_services ();                             /* disable wall clock timing */
6587 sim_ttcmd ();                                           /* restore console */
6588 sim_brk_clrall (BRK_TYP_DYN_STEPOVER);                  /* cancel any step/over subroutine breakpoints */
6589 signal (SIGINT, SIG_DFL);                               /* cancel WRU */
6590 #if defined(SIGHUP)
6591 signal (SIGHUP, SIG_DFL);                               /* cancel WRU */
6592 #endif
6593 signal (SIGTERM, SIG_DFL);                              /* cancel WRU */
6594 if (sim_log)                                            /* flush console log */
6595     (void)fflush (sim_log);
6596 if (sim_deb)                                            /* flush debug log */
6597     sim_debug_flush ();
6598 for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {     /* flush attached files */
6599     for (j = 0; j < dptr->numunits; j++) {              /* if not buffered in mem */
6600         uptr = dptr->units + j;
6601         if (uptr->flags & UNIT_ATT) {                   /* attached, */
6602             if (uptr->io_flush)                         /* unit specific flush routine */
6603                 uptr->io_flush (uptr);                  /* call it */
6604             else {
6605                 if (!(uptr->flags & UNIT_BUF) &&        /* not buffered, */
6606                     (uptr->fileref) &&                  /* real file, */
6607                     !(uptr->dynflags & UNIT_NO_FIO) &&  /* is FILE *, */
6608                     !(uptr->flags & UNIT_RO))           /* not read only? */
6609                     (void)fflush (uptr->fileref);
6610                 }
6611             }
6612         }
6613     }
6614 sim_cancel (&sim_step_unit);                            /* cancel step timer */
6615 UPDATE_SIM_TIME;                                        /* update sim time */
6616 return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
6617 }
6618 
6619 /* run command message handler */
6620 
6621 void
6622 run_cmd_message (const char *unechoed_cmdline, t_stat r)
     /* [previous][next][first][last][top][bottom][index][help] */
6623 {
6624 if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT))
6625     sim_printf("%s> %s\n", do_position(), unechoed_cmdline);
6626 #if defined(WIN_STDIO)
6627 (void)fflush(stderr);
6628 (void)fflush(stdout);
6629 #endif /* if defined(WIN_STDIO) */
6630 fprint_stopped (stdout, r);                         /* print msg */
6631 if (sim_log && (sim_log != stdout))                 /* log if enabled */
6632     fprint_stopped (sim_log, r);
6633 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))/* debug if enabled */
6634     fprint_stopped (sim_deb, r);
6635 #if defined(WIN_STDIO)
6636 (void)fflush(stderr);
6637 (void)fflush(stdout);
6638 #endif /* if defined(WIN_STDIO) */
6639 }
6640 
6641 /* Common setup for RUN or BOOT */
6642 
6643 t_stat sim_run_boot_prep (int32 flag)
     /* [previous][next][first][last][top][bottom][index][help] */
6644 {
6645 UNIT *uptr;
6646 t_stat r;
6647 
6648 sim_interval = 0;                                       /* reset queue */
6649 sim_time = sim_rtime = 0;
6650 noqueue_time = 0;
6651 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
6652     sim_clock_queue = uptr->next;
6653     uptr->next = NULL;
6654     }
6655 r = reset_all (0);
6656 if ((r == SCPE_OK) && (flag == RU_RUN)) {
6657     if ((run_cmd_did_reset) && (0 == (sim_switches & SWMASK ('Q')))) {
6658         sim_printf ("Resetting all devices...  This may not have been your intention.\n");
6659         sim_printf ("The GO and CONTINUE commands do not reset devices.\n");
6660         }
6661     run_cmd_did_reset = TRUE;
6662     }
6663 return r;
6664 }
6665 
6666 /* Print stopped message
6667  * For VM stops, if a VM-specific "sim_vm_fprint_stopped" pointer is defined,
6668  * call the indicated routine to print additional information after the message
6669  * and before the PC value is printed.  If the routine returns FALSE, skip
6670  * printing the PC and its related instruction.
6671  */
6672 
6673 void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6674 {
6675 int32 i;
6676 t_stat r = 0;
6677 t_addr k;
6678 t_value pcval;
6679 
6680 fputc ('\n', st);                                       /* start on a new line */
6681 
6682 if (v >= SCPE_BASE)                                     /* SCP error? */
6683     fputs (sim_error_text (v), st);                     /* print it from the SCP list */
6684 else {                                                  /* VM error */
6685     fputs (sim_stop_messages [v], st);                  /* print the VM-specific message */
6686 
6687     if ((sim_vm_fprint_stopped != NULL) &&              /* if a VM-specific stop handler is defined */
6688         (!sim_vm_fprint_stopped (st, v)))               /*   call it; if it returned FALSE, */
6689         return;                                         /*     we're done */
6690     }
6691 
6692 (void)fprintf (st, ", %s: ", pc->name);                       /* print the name of the PC register */
6693 
6694 pcval = get_rval (pc, 0);
6695 if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr)       /* if reg wants VM-specific printer */
6696     sim_vm_fprint_addr (st, dptr, (t_addr) pcval);      /*   call it to print the PC address */
6697 else fprint_val (st, pcval, pc->radix, pc->width,       /* otherwise, print as a numeric value */
6698     pc->flags & REG_FMT);                               /*   with the radix and formatting specified */
6699 if ((dptr != NULL) && (dptr->examine != NULL)) {
6700     for (i = 0; i < sim_emax; i++)
6701         sim_eval[i] = 0;
6702     for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) {
6703         if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK)
6704             break;
6705         }
6706     if ((r == SCPE_OK) || (i > 0)) {
6707         (void)fprintf (st, " (");
6708         if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0)
6709             fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO);
6710         (void)fprintf (st, ")");
6711         }
6712     }
6713 (void)fprintf (st, "\n");
6714 return;
6715 }
6716 
6717 void fprint_stopped (FILE *st, t_stat v)
     /* [previous][next][first][last][top][bottom][index][help] */
6718 {
6719 #if defined(WIN_STDIO)
6720 (void)fflush(stderr);
6721 (void)fflush(stdout);
6722 #endif /* if defined(WIN_STDIO) */
6723 fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev);
6724 return;
6725 }
6726 
6727 /* Unit service for step timeout, originally scheduled by STEP n command
6728    Return step timeout SCP code, will cause simulation to stop */
6729 
6730 t_stat step_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6731 {
6732 return SCPE_STEP;
6733 }
6734 
6735 /* Unit service to facilitate expect matching to stop simulation.
6736    Return expect SCP code, will cause simulation to stop */
6737 
6738 t_stat expect_svc (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6739 {
6740 return SCPE_EXPECT | (sim_do_echo ? 0 : SCPE_NOMESSAGE);
6741 }
6742 
6743 /* Signal handler for ^C signal - set stop simulation flag */
6744 
6745 void int_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
6746 {
6747 stop_cpu = 1;
6748 return;
6749 }
6750 
6751 /* Examine/deposit commands */
6752 
6753 t_stat exdep_cmd (int32 flag, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
6754 {
6755 char gbuf[CBUFSIZE];
6756 CONST char *gptr;
6757 CONST char *tptr = NULL;
6758 int32 opt;
6759 t_addr low, high;
6760 t_stat reason = SCPE_IERR;
6761 DEVICE *tdptr;
6762 REG *lowr, *highr;
6763 FILE *ofile;
6764 
6765 opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT;               /* options for all */
6766 if (flag == EX_E)                                       /* extra for EX */
6767     opt = opt | CMD_OPT_OF;
6768 cptr = get_sim_opt (opt, cptr, &reason);                /* get cmd options */
6769 if (NULL == cptr)                                       /* error? */
6770     return reason;
6771 if (*cptr == 0)                                         /* must be more */
6772     return SCPE_2FARG;
6773 if (sim_dfunit == NULL)                                 /* got a unit? */
6774     return SCPE_NXUN;
6775 cptr = get_glyph (cptr, gbuf, 0);                       /* get list */
6776 if ((flag == EX_D) && (*cptr == 0))                     /* deposit needs more */
6777 
6778     return SCPE_2FARG;
6779 ofile = sim_ofile? sim_ofile: stdout;                   /* no ofile? use stdout */
6780 
6781 for (gptr = gbuf, reason = SCPE_OK;
6782     (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) {
6783     tdptr = sim_dfdev;                                  /* working dptr */
6784     if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) {
6785         tptr = gptr + strlen ("STATE");
6786         if (*tptr && (*tptr++ != ','))
6787             return SCPE_ARG;
6788         if ((lowr = sim_dfdev->registers) == NULL)
6789             return SCPE_NXREG;
6790         for (highr = lowr; highr->name != NULL; highr++) ;
6791         sim_switches = sim_switches | SIM_SW_HIDE;
6792         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6793             lowr, --highr, 0, 0);
6794         continue;
6795         }
6796 
6797     /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
6798     if ((lowr = find_reg (gptr, &tptr, tdptr)) ||       /* local reg or */
6799         (!(sim_opt_out & CMD_OPT_DFT) &&                /* no dflt, global? */
6800         (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) {
6801         low = high = 0;
6802         if ((*tptr == '-') || (*tptr == ':')) {
6803             highr = find_reg (tptr + 1, &tptr, tdptr);
6804             if (highr == NULL)
6805                 return SCPE_NXREG;
6806             }
6807         else {
6808             highr = lowr;
6809             if (*tptr == '[') {
6810                 if (lowr->depth <= 1)
6811                     return SCPE_ARG;
6812                 tptr = get_range (NULL, tptr + 1, &low, &high,
6813                     10, lowr->depth - 1, ']');
6814                 if (tptr == NULL)
6815                     return SCPE_ARG;
6816                 }
6817             }
6818         if (*tptr && (*tptr++ != ','))
6819             return SCPE_ARG;
6820         reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr,
6821             lowr, highr, (uint32) low, (uint32) high);
6822         continue;
6823         }
6824 
6825     tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix,
6826         (((sim_dfunit->capac == 0) || (flag == EX_E))? 0:
6827         sim_dfunit->capac - sim_dfdev->aincr), 0);
6828     if (tptr == NULL)
6829         return SCPE_ARG;
6830     if (*tptr && (*tptr++ != ','))
6831         return SCPE_ARG;
6832     reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high,
6833         sim_dfdev, sim_dfunit);
6834     }                                                   /* end for */
6835 if (sim_ofile)                                          /* close output file */
6836     fclose (sim_ofile);
6837 return reason;
6838 }
6839 
6840 /* Loop controllers for examine/deposit
6841 
6842    exdep_reg_loop       examine/deposit range of registers
6843    exdep_addr_loop      examine/deposit range of addresses
6844 */
6845 
6846 t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, CONST char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6847     REG *lowr, REG *highr, uint32 lows, uint32 highs)
6848 {
6849 t_stat reason;
6850 uint32 idx, val_start=lows;
6851 t_value val, last_val;
6852 REG *rptr;
6853 
6854 if ((lowr == NULL) || (highr == NULL))
6855     return SCPE_IERR;
6856 if (lowr > highr)
6857     return SCPE_ARG;
6858 for (rptr = lowr; rptr <= highr; rptr++) {
6859     if ((sim_switches & SIM_SW_HIDE) &&
6860         (rptr->flags & REG_HIDDEN))
6861         continue;
6862     val = last_val = 0;
6863     for (idx = lows; idx <= highs; idx++) {
6864         if (idx >= rptr->depth)
6865             return SCPE_SUB;
6866         val = get_rval (rptr, idx);
6867         if (schptr && !test_search (&val, schptr))
6868             continue;
6869         if (flag == EX_E) {
6870             if ((idx > lows) && (val == last_val))
6871                 continue;
6872             if (idx > val_start+1) {
6873                 if (idx-1 == val_start+1) {
6874                     reason = ex_reg (ofile, val, flag, rptr, idx-1);
6875                     if (reason != SCPE_OK)
6876                         return reason;
6877                     if (sim_log && (ofile == stdout))
6878                         ex_reg (sim_log, val, flag, rptr, idx-1);
6879                     }
6880                 else {
6881                     if (val_start+1 != idx-1) {
6882                         (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6883                         if (sim_log && (ofile == stdout))
6884                             (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, idx-1);
6885                         }
6886                     else {
6887                         (void)Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6888                         if (sim_log && (ofile == stdout))
6889                             (void)Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6890                         }
6891                     }
6892                 }
6893             sim_last_val = last_val = val;
6894             val_start = idx;
6895             reason = ex_reg (ofile, val, flag, rptr, idx);
6896             if (reason != SCPE_OK)
6897                 return reason;
6898             if (sim_log && (ofile == stdout))
6899                 ex_reg (sim_log, val, flag, rptr, idx);
6900             }
6901         if (flag != EX_E) {
6902             reason = dep_reg (flag, cptr, rptr, idx);
6903             if (reason != SCPE_OK)
6904                 return reason;
6905             }
6906         }
6907     if ((flag == EX_E) && (val_start != highs)) {
6908         if (highs == val_start+1) {
6909             reason = ex_reg (ofile, val, flag, rptr, highs);
6910             if (reason != SCPE_OK)
6911                 return reason;
6912             if (sim_log && (ofile == stdout))
6913                 ex_reg (sim_log, val, flag, rptr, highs);
6914             }
6915         else {
6916             if (val_start+1 != highs) {
6917                 (void)Fprintf (ofile, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6918                 if (sim_log && (ofile == stdout))
6919                     (void)Fprintf (sim_log, "%s[%d]-%s[%d]: same as above\n", rptr->name, val_start+1, rptr->name, highs);
6920                 }
6921             else {
6922                 (void)Fprintf (ofile, "%s[%d]: same as above\n", rptr->name, val_start+1);
6923                 if (sim_log && (ofile == stdout))
6924                     (void)Fprintf (sim_log, "%s[%d]: same as above\n", rptr->name, val_start+1);
6925                 }
6926             }
6927         }
6928     }
6929 return SCPE_OK;
6930 }
6931 
6932 t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
6933     t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr)
6934 {
6935 t_addr i, mask;
6936 t_stat reason;
6937 
6938 if (uptr->flags & UNIT_DIS)                             /* disabled? */
6939     return SCPE_UDIS;
6940 mask = (t_addr) width_mask[dptr->awidth];
6941 if ((low > mask) || (high > mask) || (low > high))
6942     return SCPE_ARG;
6943 for (i = low; i <= high; ) {                            /* all paths must incr!! */
6944     reason = get_aval (i, dptr, uptr);                  /* get data */
6945     if (reason != SCPE_OK)                              /* return if error */
6946         return reason;
6947     if (schptr && !test_search (sim_eval, schptr))
6948         i = i + dptr->aincr;                            /* sch fails, incr */
6949     else {                                              /* no sch or success */
6950         if (flag != EX_D) {                             /* ex, ie, or id? */
6951             reason = ex_addr (ofile, flag, i, dptr, uptr);
6952             if (reason > SCPE_OK)
6953                 return reason;
6954             if (sim_log && (ofile == stdout))
6955                 ex_addr (sim_log, flag, i, dptr, uptr);
6956             }
6957         else reason = 1 - dptr->aincr;                  /* no, dflt incr */
6958         if (flag != EX_E) {                             /* ie, id, or d? */
6959             reason = dep_addr (flag, cptr, i, dptr, uptr, reason);
6960             if (reason > SCPE_OK)
6961                 return reason;
6962             }
6963         i = i + (1 - reason);                           /* incr */
6964         }
6965     }
6966 return SCPE_OK;
6967 }
6968 
6969 /* Examine register routine
6970 
6971    Inputs:
6972         ofile   =       output stream
6973         val     =       current register value
6974         flag    =       type of ex/mod command (ex, iex, idep)
6975         rptr    =       pointer to register descriptor
6976         idx     =       index
6977    Outputs:
6978         return  =       error status
6979 */
6980 
6981 t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
6982 {
6983 int32 rdx;
6984 
6985 if (rptr == NULL)
6986     return SCPE_IERR;
6987 if (rptr->depth > 1)
6988     (void)Fprintf (ofile, "%s[%d]:\t", rptr->name, idx);
6989 else
6990     (void)Fprintf (ofile, "%s:\t", rptr->name);
6991 if (!(flag & EX_E))
6992     return SCPE_OK;
6993 GET_RADIX (rdx, rptr->radix);
6994 if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr && sim_dflt_dev)
6995     sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val);
6996 else if (!(rptr->flags & REG_VMFLAGS) ||
6997     (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, &val,
6998                  NULL, sim_switches | SIM_SW_REG) > 0)) {
6999         fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT);
7000         if (rptr->fields) {
7001             (void)Fprintf (ofile, "\t");
7002             fprint_fields (ofile, val, val, rptr->fields);
7003             }
7004         }
7005 if (flag & EX_I)
7006     (void)Fprintf (ofile, "\t");
7007 else
7008     (void)Fprintf (ofile, "\n");
7009 return SCPE_OK;
7010 }
7011 
7012 /* Get register value
7013 
7014    Inputs:
7015         rptr    =       pointer to register descriptor
7016         idx     =       index
7017    Outputs:
7018         return  =       register value
7019 */
7020 
7021 t_value get_rval (REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7022 {
7023 size_t sz;
7024 t_value val;
7025 uint32 *ptr;
7026 
7027 sz = SZ_R (rptr);
7028 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7029     idx = idx + rptr->qptr;
7030     if (idx >= rptr->depth) idx = idx - rptr->depth;
7031     }
7032 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7033     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7034     if (sz <= sizeof (uint32))
7035         val = *ptr;
7036     else val = *((t_uint64 *) ptr); //-V1032
7037     }
7038 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7039     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7040     if (sz <= sizeof (uint32))
7041         val = *ptr;
7042     else val = *((t_uint64 *) ptr);
7043     }
7044 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7045     (sz == sizeof (uint8)))
7046     val = *(((uint8 *) rptr->loc) + idx);
7047 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7048     (sz == sizeof (uint16)))
7049     val = *(((uint16 *) rptr->loc) + idx);
7050 else if (sz <= sizeof (uint32))
7051      val = *(((uint32 *) rptr->loc) + idx);
7052 else val = *(((t_uint64 *) rptr->loc) + idx);
7053 val = (val >> rptr->offset) & width_mask[rptr->width];
7054 return val;
7055 }
7056 
7057 /* Deposit register routine
7058 
7059    Inputs:
7060         flag    =       type of deposit (normal/interactive)
7061         cptr    =       pointer to input string
7062         rptr    =       pointer to register descriptor
7063         idx     =       index
7064    Outputs:
7065         return  =       error status
7066 */
7067 
7068 t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
     /* [previous][next][first][last][top][bottom][index][help] */
7069 {
7070 t_stat r;
7071 t_value val, mask;
7072 int32 rdx;
7073 CONST char *tptr;
7074 char gbuf[CBUFSIZE];
7075 
7076 if ((cptr == NULL) || (rptr == NULL))
7077     return SCPE_IERR;
7078 if (rptr->flags & REG_RO)
7079     return SCPE_RO;
7080 if (flag & EX_I) {
7081     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7082     if (sim_log)
7083         (void)fprintf (sim_log, "%s\n", cptr? cptr: "");
7084     if (cptr == NULL)                                   /* force exit */
7085         return 1;
7086     if (*cptr == 0)                                     /* success */
7087         return SCPE_OK;
7088     }
7089 mask = width_mask[rptr->width];
7090 GET_RADIX (rdx, rptr->radix);
7091 if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr && sim_dflt_dev) {    /* address form? */
7092     val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
7093     if ((tptr == cptr) || (*tptr != 0) || (val > mask))
7094         return SCPE_ARG;
7095     }
7096 else
7097     if (!(rptr->flags & REG_VMFLAGS) ||                 /* don't use sym? */
7098         (parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
7099                     &val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
7100     val = get_uint (cptr, rdx, mask, &r);
7101     if (r != SCPE_OK)
7102         return SCPE_ARG;
7103     }
7104 if ((rptr->flags & REG_NZ) && (val == 0))
7105     return SCPE_ARG;
7106 put_rval (rptr, idx, val);
7107 return SCPE_OK;
7108 }
7109 
7110 /* Put register value
7111 
7112    Inputs:
7113         rptr    =       pointer to register descriptor
7114         idx     =       index
7115         val     =       new value
7116         mask    =       mask
7117    Outputs:
7118         none
7119 */
7120 
7121 void put_rval (REG *rptr, uint32 idx, t_value val)
     /* [previous][next][first][last][top][bottom][index][help] */
7122 {
7123 size_t sz;
7124 t_value mask;
7125 uint32 *ptr;
7126 
7127 #define PUT_RVAL(sz,rp,id,v,m)            \
7128     *(((sz *) rp->loc) + id) =            \
7129         (sz)((*(((sz *) rp->loc) + id) &  \
7130             ~((m) << (rp)->offset)) | ((v) << (rp)->offset))
7131 
7132 if (rptr == sim_PC)
7133     sim_brk_npc (0);
7134 sz = SZ_R (rptr);
7135 mask = width_mask[rptr->width];
7136 if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
7137     idx = idx + rptr->qptr;
7138     if (idx >= rptr->depth)
7139         idx = idx - rptr->depth;
7140     }
7141 if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
7142     ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
7143     if (sz <= sizeof (uint32))
7144         *ptr = (*ptr &
7145         ~(((uint32) mask) << rptr->offset)) |
7146         (((uint32) val) << rptr->offset);
7147     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr) //-V1032
7148         & ~(mask << rptr->offset)) | (val << rptr->offset);
7149     }
7150 else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
7151     ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
7152     if (sz <= sizeof (uint32))
7153         *((uint32 *) ptr) = (*((uint32 *) ptr) &
7154         ~(((uint32) mask) << rptr->offset)) |
7155         (((uint32) val) << rptr->offset);
7156     else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
7157         & ~(mask << rptr->offset)) | (val << rptr->offset);
7158     }
7159 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7160     (sz == sizeof (uint8)))
7161     PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
7162 else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
7163     (sz == sizeof (uint16)))
7164     PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
7165 else if (sz <= sizeof (uint32))
7166     PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
7167 else PUT_RVAL (t_uint64, rptr, idx, val, mask);
7168 return;
7169 }
7170 
7171 /* Examine address routine
7172 
7173    Inputs: (sim_eval is an implicit argument)
7174         ofile   =       output stream
7175         flag    =       type of ex/mod command (ex, iex, idep)
7176         addr    =       address to examine
7177         dptr    =       pointer to device
7178         uptr    =       pointer to unit
7179    Outputs:
7180         return  =       if > 0, error status
7181                         if <= 0,-number of extra addr units retired
7182 */
7183 
7184 t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7185 {
7186 t_stat reason;
7187 int32 rdx;
7188 
7189 if (sim_vm_fprint_addr)
7190     sim_vm_fprint_addr (ofile, dptr, addr);
7191 else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT);
7192 (void)Fprintf (ofile, ":\t");
7193 if (!(flag & EX_E))
7194     return (1 - dptr->aincr);
7195 
7196 GET_RADIX (rdx, dptr->dradix);
7197 if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) {
7198     fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO);
7199     reason = 1 - dptr->aincr;
7200     }
7201 if (flag & EX_I)
7202     (void)Fprintf (ofile, "\t");
7203 else
7204     (void)Fprintf (ofile, "\n");
7205 return reason;
7206 }
7207 
7208 /* Get address routine
7209 
7210    Inputs:
7211         flag    =       type of ex/mod command (ex, iex, idep)
7212         addr    =       address to examine
7213         dptr    =       pointer to device
7214         uptr    =       pointer to unit
7215    Outputs: (sim_eval is an implicit output)
7216         return  =       error status
7217 */
7218 
7219 t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7220 {
7221 int32 i;
7222 t_value mask;
7223 t_addr j, loc;
7224 size_t sz;
7225 t_stat reason = SCPE_OK;
7226 
7227 if ((dptr == NULL) || (uptr == NULL))
7228     return SCPE_IERR;
7229 mask = width_mask[dptr->dwidth];
7230 for (i = 0; i < sim_emax; i++)
7231     sim_eval[i] = 0;
7232 for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) {
7233     if (dptr->examine != NULL) {
7234         reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches);
7235         if (reason != SCPE_OK)
7236             break;
7237         }
7238     else {
7239         if (!(uptr->flags & UNIT_ATT))
7240             return SCPE_UNATT;
7241         if (uptr->dynflags & UNIT_NO_FIO)
7242             return SCPE_NOFNC;
7243         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) {
7244             reason = SCPE_NXM;
7245             break;
7246             }
7247         sz = SZ_D (dptr);
7248         loc = j / dptr->aincr;
7249         if (uptr->flags & UNIT_BUF) {
7250             SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc);
7251             }
7252         else {
7253             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7254             sim_fread (&sim_eval[i], sz, 1, uptr->fileref);
7255             if ((feof (uptr->fileref)) &&
7256                !(uptr->flags & UNIT_FIX)) {
7257                 reason = SCPE_EOF;
7258                 break;
7259                 }
7260             else if (ferror (uptr->fileref)) {
7261                 clearerr (uptr->fileref);
7262                 reason = SCPE_IOERR;
7263                 break;
7264                 }
7265             }
7266         }
7267     sim_last_val = sim_eval[i] = sim_eval[i] & mask;
7268     }
7269 if ((reason != SCPE_OK) && (i == 0))
7270     return reason;
7271 return SCPE_OK;
7272 }
7273 
7274 /* Deposit address routine
7275 
7276    Inputs:
7277         flag    =       type of deposit (normal/interactive)
7278         cptr    =       pointer to input string
7279         addr    =       address to examine
7280         dptr    =       pointer to device
7281         uptr    =       pointer to unit
7282         dfltinc =       value to return on cr input
7283    Outputs:
7284         return  =       if > 0, error status
7285                         if <= 0, -number of extra address units retired
7286 */
7287 
7288 t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
7289     UNIT *uptr, int32 dfltinc)
7290 {
7291 int32 i, count, rdx;
7292 t_addr j, loc;
7293 t_stat r, reason;
7294 t_value mask;
7295 size_t sz;
7296 char gbuf[CBUFSIZE];
7297 
7298 if (dptr == NULL)
7299     return SCPE_IERR;
7300 if (flag & EX_I) {
7301     cptr = read_line (gbuf, sizeof(gbuf), stdin);
7302     if (sim_log)
7303         (void)fprintf (sim_log, "%s\n", cptr? cptr: "");
7304     if (cptr == NULL)                                   /* force exit */
7305         return 1;
7306     if (*cptr == 0)                                     /* success */
7307         return dfltinc;
7308     }
7309 if (uptr->flags & UNIT_RO)                              /* read only? */
7310     return SCPE_RO;
7311 mask = width_mask[dptr->dwidth];
7312 
7313 GET_RADIX (rdx, dptr->dradix);
7314 if ((reason = parse_sym ((CONST char *)cptr, addr, uptr, sim_eval, sim_switches)) > 0) {
7315     sim_eval[0] = get_uint (cptr, rdx, mask, &reason);
7316     if (reason != SCPE_OK)
7317         return reason;
7318     reason = dfltinc;
7319     }
7320 count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr;
7321 
7322 for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) {
7323     sim_eval[i] = sim_eval[i] & mask;
7324     if (dptr->deposit != NULL) {
7325         r = dptr->deposit (sim_eval[i], j, uptr, sim_switches);
7326         if (r != SCPE_OK)
7327             return r;
7328         }
7329     else {
7330         if (!(uptr->flags & UNIT_ATT))
7331             return SCPE_UNATT;
7332         if (uptr->dynflags & UNIT_NO_FIO)
7333             return SCPE_NOFNC;
7334         if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac))
7335             return SCPE_NXM;
7336         sz = SZ_D (dptr);
7337         loc = j / dptr->aincr;
7338         if (uptr->flags & UNIT_BUF) {
7339             SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc);
7340             if (loc >= uptr->hwmark)
7341                 uptr->hwmark = (uint32) loc + 1;
7342             }
7343         else {
7344             sim_fseek (uptr->fileref, (t_addr)(sz * loc), SEEK_SET);
7345             sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref);
7346             if (ferror (uptr->fileref)) {
7347                 clearerr (uptr->fileref);
7348                 return SCPE_IOERR;
7349                 }
7350             }
7351         }
7352     }
7353 return reason;
7354 }
7355 
7356 /* Evaluate command */
7357 
7358 t_stat eval_cmd (int32 flg, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7359 {
7360 if (!sim_dflt_dev)
7361   return SCPE_ARG;
7362 DEVICE *dptr = sim_dflt_dev;
7363 int32 i, rdx, a, lim;
7364 t_stat r;
7365 
7366 GET_SWITCHES (cptr);
7367 GET_RADIX (rdx, dptr->dradix);
7368 for (i = 0; i < sim_emax; i++)
7369 sim_eval[i] = 0;
7370 if (*cptr == 0)
7371     return SCPE_2FARG;
7372 if ((r = parse_sym ((CONST char *)cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) {
7373     sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r);
7374     if (r != SCPE_OK)
7375         return r;
7376     }
7377 lim = 1 - r;
7378 for (i = a = 0; a < lim; ) {
7379     sim_printf ("%d:\t", a);
7380     if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7381         r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7382     if (sim_log) {
7383         if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0)
7384             r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO);
7385         }
7386     sim_printf ("\n");
7387     if (r < 0)
7388         a = a + 1 - r;
7389     else a = a + dptr->aincr;
7390     i = a / dptr->aincr;
7391     }
7392 return SCPE_OK;
7393 }
7394 
7395 /* String processing routines
7396 
7397    read_line            read line
7398 
7399    Inputs:
7400         cptr    =       pointer to buffer
7401         size    =       maximum size
7402         stream  =       pointer to input stream
7403    Outputs:
7404         optr    =       pointer to first non-blank character
7405                         NULL if EOF
7406 */
7407 
7408 char *read_line (char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7409 {
7410 return read_line_p (NULL, cptr, size, stream);
7411 }
7412 
7413 /* read_line_p          read line with prompt
7414 
7415    Inputs:
7416         prompt  =       pointer to prompt string
7417         cptr    =       pointer to buffer
7418         size    =       maximum size
7419         stream  =       pointer to input stream
7420    Outputs:
7421         optr    =       pointer to first non-blank character
7422                         NULL if EOF
7423 */
7424 
7425 char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
     /* [previous][next][first][last][top][bottom][index][help] */
7426 {
7427 char *tptr;
7428 
7429 if (prompt) {                                           /* interactive? */
7430 #if defined(HAVE_LINEHISTORY)
7431         char *tmpc = linenoise (prompt);                /* get cmd line */
7432         if (tmpc == NULL)                               /* bad result? */
7433             cptr = NULL;
7434         else {
7435             strncpy (cptr, tmpc, size-1);               /* copy result */
7436             linenoiseHistoryAdd (tmpc);                 /* add to history */
7437             FREE (tmpc);                                /* free temp */
7438             }
7439         }
7440 #else
7441         (void)fflush (stdout);                          /* flush output */
7442         (void)printf ("%s", prompt);                    /* display prompt */
7443         (void)fflush (stdout);                          /* flush output */
7444         cptr = fgets (cptr, size, stream);              /* get cmd line */
7445         }
7446 #endif /* if defined(HAVE_LINEHISTORY) */
7447 else cptr = fgets (cptr, size, stream);                 /* get cmd line */
7448 
7449 if (cptr == NULL) {
7450     clearerr (stream);                                  /* clear error */
7451     return NULL;                                        /* ignore EOF */
7452     }
7453 for (tptr = cptr; tptr < (cptr + size); tptr++) {       /* remove cr or nl */
7454     if ((*tptr == '\n') || (*tptr == '\r') ||
7455         (tptr == (cptr + size - 1))) {                  /* str max length? */
7456         *tptr = 0;                                      /* terminate */
7457         break;
7458         }
7459     }
7460 if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3))              /* Skip/ignore UTF8_BOM */
7461     memmove (cptr, cptr + 3, strlen (cptr + 3));
7462 while (sim_isspace (*cptr))                             /* trim leading spc */
7463     cptr++;
7464 if ((*cptr == ';') || (*cptr == '#')) {                 /* ignore comment */
7465     if (sim_do_echo)                                    /* echo comments if -v */
7466         sim_printf("%s> %s\n", do_position(), cptr);
7467     *cptr = 0;
7468     }
7469 
7470 return cptr;
7471 }
7472 
7473 /* get_glyph            get next glyph (force upper case)
7474    get_glyph_nc         get next glyph (no conversion)
7475    get_glyph_quoted     get next glyph (potentially enclosed in quotes, no conversion)
7476    get_glyph_cmd        get command glyph (force upper case, extract leading !)
7477    get_glyph_gen        get next glyph (general case)
7478 
7479    Inputs:
7480         iptr        =   pointer to input string
7481         optr        =   pointer to output string
7482         mchar       =   optional end of glyph character
7483         uc          =   TRUE for convert to upper case (_gen only)
7484         quote       =   TRUE to allow quote enclosing values (_gen only)
7485         escape_char =   optional escape character within quoted strings (_gen only)
7486 
7487    Outputs
7488         result      =   pointer to next character in input string
7489 */
7490 
7491 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] */
7492 {
7493 t_bool quoting = FALSE;
7494 t_bool escaping = FALSE;
7495 char quote_char = 0;
7496 
7497 while ((*iptr != 0) &&
7498        ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) {
7499     if (quote) {
7500         if (quoting) {
7501             if (!escaping) {
7502                 if (*iptr == escape_char)
7503                     escaping = TRUE;
7504                 else
7505                     if (*iptr == quote_char)
7506                         quoting = FALSE;
7507                 }
7508             else
7509                 escaping = FALSE;
7510             }
7511         else {
7512             if ((*iptr == '"') || (*iptr == '\'')) {
7513                 quoting = TRUE;
7514                 quote_char = *iptr;
7515                 }
7516             }
7517         }
7518     if (sim_islower (*iptr) && uc)
7519         *optr = (char)toupper (*iptr);
7520     else *optr = *iptr;
7521     iptr++; optr++;
7522     }
7523 if (mchar && (*iptr == mchar))              /* skip input terminator */
7524     iptr++;
7525 *optr = 0;                                  /* terminate result string */
7526 while (sim_isspace (*iptr))                 /* absorb additional input spaces */
7527     iptr++;
7528 return iptr;
7529 }
7530 
7531 CONST char *get_glyph (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7532 {
7533 return (CONST char *)get_glyph_gen (iptr, optr, mchar, TRUE, FALSE, 0);
7534 }
7535 
7536 CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7537 {
7538 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, FALSE, 0);
7539 }
7540 
7541 CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar)
     /* [previous][next][first][last][top][bottom][index][help] */
7542 {
7543 return (CONST char *)get_glyph_gen (iptr, optr, mchar, FALSE, TRUE, '\\');
7544 }
7545 
7546 CONST char *get_glyph_cmd (const char *iptr, char *optr)
     /* [previous][next][first][last][top][bottom][index][help] */
7547 {
7548 /* Tolerate "!subprocess" vs. requiring "! subprocess" */
7549 if ((iptr[0] == '!') && (!sim_isspace(iptr[1]))) {
7550     strcpy (optr, "!");                     /* return ! as command glyph */
7551     return (CONST char *)(iptr + 1);        /* and skip over the leading ! */
7552     }
7553 return (CONST char *)get_glyph_gen (iptr, optr, 0, TRUE, FALSE, 0);
7554 }
7555 
7556 /* Trim trailing spaces from a string
7557 
7558     Inputs:
7559         cptr    =       pointer to string
7560     Outputs:
7561         cptr    =       pointer to string
7562 */
7563 
7564 char *sim_trim_endspc (char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7565 {
7566 char *tptr;
7567 
7568 tptr = cptr + strlen (cptr);
7569 while ((--tptr >= cptr) && sim_isspace (*tptr))
7570     *tptr = 0;
7571 return cptr;
7572 }
7573 
7574 int sim_isspace (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7575 {
7576 return (c & 0x80) ? 0 : isspace (c);
7577 }
7578 
7579 int sim_islower (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7580 {
7581 return (c & 0x80) ? 0 : islower (c);
7582 }
7583 
7584 int sim_isalpha (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7585 {
7586 return (c & 0x80) ? 0 : isalpha (c);
7587 }
7588 
7589 int sim_isprint (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7590 {
7591 return (c & 0x80) ? 0 : isprint (c);
7592 }
7593 
7594 int sim_isdigit (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7595 {
7596 return (c & 0x80) ? 0 : isdigit (c);
7597 }
7598 
7599 int sim_isgraph (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7600 {
7601 return (c & 0x80) ? 0 : isgraph (c);
7602 }
7603 
7604 int sim_isalnum (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
7605 {
7606 return (c & 0x80) ? 0 : isalnum (c);
7607 }
7608 
7609 /* get_uint             unsigned number
7610 
7611    Inputs:
7612         cptr    =       pointer to input string
7613         radix   =       input radix
7614         max     =       maximum acceptable value
7615         *status =       pointer to error status
7616    Outputs:
7617         val     =       value
7618 */
7619 
7620 t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status)
     /* [previous][next][first][last][top][bottom][index][help] */
7621 {
7622 t_value val;
7623 CONST char *tptr;
7624 
7625 *status = SCPE_OK;
7626 val = strtotv ((CONST char *)cptr, &tptr, radix);
7627 if ((cptr == tptr) || (val > max))
7628     *status = SCPE_ARG;
7629 else {
7630     while (sim_isspace (*tptr)) tptr++;
7631     if (*tptr != 0)
7632         *status = SCPE_ARG;
7633     }
7634 return val;
7635 }
7636 
7637 /* get_range            range specification
7638 
7639    Inputs:
7640         dptr    =       pointer to device (NULL if none)
7641         cptr    =       pointer to input string
7642         *lo     =       pointer to low result
7643         *hi     =       pointer to high result
7644         aradix  =       radix
7645         max     =       default high value
7646         term    =       terminating character, 0 if none
7647    Outputs:
7648         tptr    =       input pointer after processing
7649                         NULL if error
7650 */
7651 
7652 CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
     /* [previous][next][first][last][top][bottom][index][help] */
7653     uint32 rdx, t_addr max, char term)
7654 {
7655 CONST char *tptr;
7656 
7657 if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) {    /* ALL? */
7658     tptr = cptr + strlen ("ALL");
7659     *lo = 0;
7660     *hi = max;
7661     }
7662 else {
7663     if ((strncmp (cptr, ".", strlen (".")) == 0) &&             /* .? */
7664         ((cptr[1] == '\0') ||
7665          (cptr[1] == '-')  ||
7666          (cptr[1] == ':')  ||
7667          (cptr[1] == '/'))) {
7668         tptr = cptr + strlen (".");
7669         *lo = *hi = sim_last_addr;
7670         }
7671     else {
7672         if (strncmp (cptr, "$", strlen ("$")) == 0) {           /* $? */
7673             tptr = cptr + strlen ("$");
7674             *hi = *lo = (t_addr)sim_last_val;
7675             }
7676         else {
7677             if (dptr && sim_vm_parse_addr)                      /* get low */
7678                 *lo = sim_vm_parse_addr (dptr, cptr, &tptr);
7679             else
7680                 *lo = (t_addr) strtotv (cptr, &tptr, rdx);
7681             if (cptr == tptr)                                   /* error? */
7682                     return NULL;
7683             }
7684         }
7685     if ((*tptr == '-') || (*tptr == ':')) {             /* range? */
7686         cptr = tptr + 1;
7687         if (dptr && sim_vm_parse_addr)                  /* get high */
7688             *hi = sim_vm_parse_addr (dptr, cptr, &tptr);
7689         else *hi = (t_addr) strtotv (cptr, &tptr, rdx);
7690         if (cptr == tptr)
7691             return NULL;
7692         if (*lo > *hi)
7693             return NULL;
7694         }
7695     else if (*tptr == '/') {                            /* relative? */
7696         cptr = tptr + 1;
7697         *hi = (t_addr) strtotv (cptr, &tptr, rdx);      /* get high */
7698         if ((cptr == tptr) || (*hi == 0))
7699             return NULL;
7700         *hi = *lo + *hi - 1;
7701         }
7702     else *hi = *lo;
7703     }
7704 sim_last_addr = *hi;
7705 if (term && (*tptr++ != term))
7706     return NULL;
7707 return tptr;
7708 }
7709 
7710 /* sim_decode_quoted_string
7711 
7712    Inputs:
7713         iptr        =   pointer to input string
7714         optr        =   pointer to output buffer
7715                         the output buffer must be allocated by the caller
7716                         and to avoid overrunat it must be at least as big
7717                         as the input string.
7718 
7719    Outputs
7720         result      =   status of decode SCPE_OK when good, SCPE_ARG otherwise
7721         osize       =   size of the data in the optr buffer
7722 
7723    The input string must be quoted.  Quotes may be either single or
7724    double but the opening anc closing quote characters must match.
7725    Within quotes C style character escapes are allowed.
7726 */
7727 
7728 t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize)
     /* [previous][next][first][last][top][bottom][index][help] */
7729 {
7730 char quote_char;
7731 uint8 *ostart = optr;
7732 
7733 *osize = 0;
7734 if ((strlen(iptr) == 1) ||
7735     (iptr[0] != iptr[strlen(iptr)-1]) ||
7736     ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\'')))
7737     return SCPE_ARG;            /* String must be quote delimited */
7738 quote_char = *iptr++;           /* Save quote character */
7739 while (iptr[1]) {               /* Skip trailing quote */
7740     if (*iptr != '\\') {
7741         if (*iptr == quote_char)
7742             return SCPE_ARG;    /* Embedded quotes must be escaped */
7743         *(optr++) = (uint8)(*(iptr++));
7744         continue;
7745         }
7746     ++iptr; /* Skip backslash */
7747     switch (*iptr) {
7748         case 'r':   /* ASCII Carriage Return character (Decimal value 13) */
7749             *(optr++) = 13; ++iptr;
7750             break;
7751         case 'n':   /* ASCII Linefeed character (Decimal value 10) */
7752             *(optr++) = 10; ++iptr;
7753             break;
7754         case 'f':   /* ASCII Formfeed character (Decimal value 12) */
7755             *(optr++) = 12; ++iptr;
7756             break;
7757         case 't':   /* ASCII Horizontal Tab character (Decimal value 9) */
7758             *(optr++) = 9; ++iptr;
7759             break;
7760         case 'v':   /* ASCII Vertical Tab character (Decimal value 11) */
7761             *(optr++) = 11; ++iptr;
7762             break;
7763         case 'b':   /* ASCII Backspace character (Decimal value 8) */
7764             *(optr++) = 8; ++iptr;
7765             break;
7766         case '\\':   /* ASCII Backslash character (Decimal value 92) */
7767             *(optr++) = 92; ++iptr;
7768             break;
7769         case 'e':   /* ASCII Escape character (Decimal value 27) */
7770             *(optr++) = 27; ++iptr;
7771             break;
7772         case '\'':   /* ASCII Single Quote character (Decimal value 39) */
7773             *(optr++) = 39; ++iptr;
7774             break;
7775         case '"':   /* ASCII Double Quote character (Decimal value 34) */
7776             *(optr++) = 34; ++iptr;
7777             break;
7778         case '?':   /* ASCII Question Mark character (Decimal value 63) */
7779             *(optr++) = 63; ++iptr;
7780             break;
7781         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
7782             *optr = *(iptr++) - '0';
7783             if ((*iptr >= '0') && (*iptr <= '7'))
7784                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7785             if ((*iptr >= '0') && (*iptr <= '7'))
7786                 *optr = ((*optr)<<3) + (*(iptr++) - '0');
7787             ++optr;
7788             break;
7789         case 'x':
7790             if (1) {
7791                 static const char *hex_digits = "0123456789ABCDEF";
7792                 const char *c;
7793 
7794                 ++iptr;
7795                 *optr = 0;
7796                 c = strchr (hex_digits, toupper(*iptr));
7797                 if (c) {
7798                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7799                     ++iptr;
7800                     }
7801                 c = strchr (hex_digits, toupper(*iptr));
7802                 if (c) {
7803                     *optr = ((*optr)<<4) + (uint8)(c-hex_digits);
7804                     ++iptr;
7805                     }
7806                 ++optr;
7807                 }
7808             break;
7809         default:
7810             return SCPE_ARG;    /* Invalid escape */
7811         }
7812     }
7813 *optr = '\0';
7814 *osize = (uint32)(optr-ostart);
7815 return SCPE_OK;
7816 }
7817 
7818 /* sim_encode_quoted_string
7819 
7820    Inputs:
7821         iptr        =   pointer to input buffer
7822         size        =   number of bytes of data in the buffer
7823 
7824    Outputs
7825         optr        =   pointer to output buffer
7826                         the output buffer must be freed by the caller
7827 
7828    The input data will be encoded into a simply printable form.
7829 */
7830 
7831 char *sim_encode_quoted_string (const uint8 *iptr, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7832 {
7833 size_t i;
7834 t_bool double_quote_found = FALSE;
7835 t_bool single_quote_found = FALSE;
7836 char quote = '"';
7837 char *tptr, *optr;
7838 
7839 optr = (char *)malloc (4*size + 3);
7840 if (optr == NULL)
7841     return NULL;
7842 tptr = optr;
7843 for (i=0; i<size; i++)
7844     switch ((char)iptr[i]) {
7845         case '"':
7846             double_quote_found = TRUE;
7847             break;
7848         case '\'':
7849             single_quote_found = TRUE;
7850             break;
7851         }
7852 if (double_quote_found && (!single_quote_found))
7853     quote = '\'';
7854 *tptr++ = quote;
7855 while (size--) {
7856     switch (*iptr) {
7857         case '\r':
7858             *tptr++ = '\\'; *tptr++ = 'r'; break;
7859         case '\n':
7860             *tptr++ = '\\'; *tptr++ = 'n'; break;
7861         case '\f':
7862             *tptr++ = '\\'; *tptr++ = 'f'; break;
7863         case '\t':
7864             *tptr++ = '\\'; *tptr++ = 't'; break;
7865         case '\v':
7866             *tptr++ = '\\'; *tptr++ = 'v'; break;
7867         case '\b':
7868             *tptr++ = '\\'; *tptr++ = 'b'; break;
7869         case '\\':
7870             *tptr++ = '\\'; *tptr++ = '\\'; break;
7871         case '"':
7872         case '\'':
7873             if (quote == *iptr)
7874                 *tptr++ = '\\';
7875         /*FALLTHRU*/ /* fall through */ /* fallthrough */
7876         default:
7877             if (sim_isprint (*iptr))
7878                 *tptr++ = *iptr;
7879             else {
7880                 (void)sprintf (tptr, "\\%03o", *iptr);
7881                 tptr += 4;
7882                 }
7883             break;
7884         }
7885     ++iptr;
7886     }
7887 *tptr++ = quote;
7888 *tptr++ = '\0';
7889 return optr;
7890 }
7891 
7892 void fprint_buffer_string (FILE *st, const uint8 *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
7893 {
7894 char *string;
7895 
7896 string = sim_encode_quoted_string (buf, size);
7897 (void)fprintf (st, "%s", string);
7898 FREE (string);
7899 }
7900 
7901 /* Find_device          find device matching input string
7902 
7903    Inputs:
7904         cptr    =       pointer to input string
7905    Outputs:
7906         result  =       pointer to device
7907 */
7908 
7909 DEVICE *find_dev (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7910 {
7911 int32 i;
7912 DEVICE *dptr;
7913 
7914 if (cptr == NULL)
7915     return NULL;
7916 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
7917     if ((strcmp (cptr, dptr->name) == 0) ||
7918         (dptr->lname &&
7919         (strcmp (cptr, dptr->lname) == 0)))
7920         return dptr;
7921     }
7922 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
7923     if ((strcmp (cptr, dptr->name) == 0) ||
7924         (dptr->lname &&
7925         (strcmp (cptr, dptr->lname) == 0)))
7926         return dptr;
7927     }
7928 return NULL;
7929 }
7930 
7931 /* Find_unit            find unit matching input string
7932 
7933    Inputs:
7934         cptr    =       pointer to input string
7935         uptr    =       pointer to unit pointer
7936    Outputs:
7937         result  =       pointer to device (null if no dev)
7938         *iptr   =       pointer to unit (null if nx unit)
7939 
7940 */
7941 
7942 DEVICE *find_unit (const char *cptr, UNIT **uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7943 {
7944 uint32 i, u;
7945 const char *nptr;
7946 const char *tptr;
7947 t_stat r;
7948 DEVICE *dptr;
7949 
7950 if (uptr == NULL)                                       /* arg error? */
7951     return NULL;
7952 *uptr = NULL;
7953 if ((dptr = find_dev (cptr))) {                         /* exact match? */
7954     if (qdisable (dptr))                                /* disabled? */
7955         return NULL;
7956     *uptr = dptr->units;                                /* unit 0 */
7957     return dptr;
7958     }
7959 
7960 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {     /* base + unit#? */
7961     if (qdisable (dptr))                                /* device disabled? */
7962         continue;
7963     if (dptr->numunits && /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/ /* any units? */
7964         (((nptr = dptr->name) &&
7965           (strncmp (cptr, nptr, strlen (nptr)) == 0)) || /* LINTED E_EQUALITY_NOT_ASSIGNMENT*/
7966          ((nptr = dptr->lname) &&
7967           (strncmp (cptr, nptr, strlen (nptr)) == 0)))) {
7968         tptr = cptr + strlen (nptr);
7969         if (sim_isdigit (*tptr)) {
7970             if (qdisable (dptr))                        /* disabled? */
7971                 return NULL;
7972             u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r);
7973             if (r != SCPE_OK)                           /* error? */
7974                 *uptr = NULL;
7975             else
7976                 *uptr = dptr->units + u;
7977             return dptr;
7978             }
7979         }
7980     for (u = 0; u < dptr->numunits; u++) {
7981         if (0 == strcmp (cptr, sim_uname (&dptr->units[u]))) {
7982             *uptr = &dptr->units[u];
7983             return dptr;
7984             }
7985         }
7986     }
7987 return NULL;
7988 }
7989 
7990 /* sim_register_internal_device   Add device to internal device list
7991 
7992    Inputs:
7993         dptr    =       pointer to device
7994 */
7995 
7996 t_stat sim_register_internal_device (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
7997 {
7998 uint32 i;
7999 
8000 for (i = 0; (sim_devices[i] != NULL); i++)
8001     if (sim_devices[i] == dptr)
8002         return SCPE_OK;
8003 for (i = 0; i < sim_internal_device_count; i++)
8004     if (sim_internal_devices[i] == dptr)
8005         return SCPE_OK;
8006 ++sim_internal_device_count;
8007 sim_internal_devices = (DEVICE **)realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
8008 if (!sim_internal_devices)
8009   {
8010     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8011                    __func__, __FILE__, __LINE__);
8012 #if defined(USE_BACKTRACE)
8013 # if defined(SIGUSR2)
8014     (void)raise(SIGUSR2);
8015     /*NOTREACHED*/ /* unreachable */
8016 # endif /* if defined(SIGUSR2) */
8017 #endif /* if defined(USE_BACKTRACE) */
8018     abort();
8019   }
8020 sim_internal_devices[sim_internal_device_count-1] = dptr;
8021 sim_internal_devices[sim_internal_device_count] = NULL;
8022 return SCPE_OK;
8023 }
8024 
8025 /* Find_dev_from_unit   find device for unit
8026 
8027    Inputs:
8028         uptr    =       pointer to unit
8029    Outputs:
8030         result  =       pointer to device
8031 */
8032 
8033 DEVICE *find_dev_from_unit (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8034 {
8035 DEVICE *dptr;
8036 uint32 i, j;
8037 
8038 if (uptr == NULL)
8039     return NULL;
8040 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
8041     for (j = 0; j < dptr->numunits; j++) {
8042         if (uptr == (dptr->units + j))
8043             return dptr;
8044         }
8045     }
8046 for (i = 0; i<sim_internal_device_count; i++) {
8047     dptr = sim_internal_devices[i];
8048     for (j = 0; j < dptr->numunits; j++) {
8049         if (uptr == (dptr->units + j))
8050             return dptr;
8051         }
8052     }
8053 return NULL;
8054 }
8055 
8056 /* Test for disabled device */
8057 
8058 t_bool qdisable (DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8059 {
8060 return (dptr->flags & DEV_DIS? TRUE: FALSE);
8061 }
8062 
8063 /* find_reg_glob        find globally unique register
8064 
8065    Inputs:
8066         cptr    =       pointer to input string
8067         optr    =       pointer to output pointer (can be null)
8068         gdptr   =       pointer to global device
8069    Outputs:
8070         result  =       pointer to register, NULL if error
8071         *optr   =       pointer to next character in input string
8072         *gdptr  =       pointer to device where found
8073 */
8074 
8075 REG *find_reg_glob (CONST char *cptr, CONST char **optr, DEVICE **gdptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8076 {
8077 int32 i;
8078 DEVICE *dptr;
8079 REG *rptr, *srptr = NULL;
8080 
8081 *gdptr = NULL;
8082 for (i = 0; (dptr = sim_devices[i]) != 0; i++) {        /* all dev */
8083     if (dptr->flags & DEV_DIS)                          /* skip disabled */
8084         continue;
8085     if ((rptr = find_reg (cptr, optr, dptr))) {         /* found? */
8086         if (srptr)                                      /* ambig? err */
8087             return NULL;
8088         srptr = rptr;                                   /* save reg */
8089         *gdptr = dptr;                                  /* save unit */
8090         }
8091     }
8092 return srptr;
8093 }
8094 
8095 /* find_reg             find register matching input string
8096 
8097    Inputs:
8098         cptr    =       pointer to input string
8099         optr    =       pointer to output pointer (can be null)
8100         dptr    =       pointer to device
8101    Outputs:
8102         result  =       pointer to register, NULL if error
8103         *optr   =       pointer to next character in input string
8104 */
8105 
8106 REG *find_reg (CONST char *cptr, CONST char **optr, DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8107 {
8108 CONST char *tptr;
8109 REG *rptr;
8110 size_t slnt;
8111 
8112 if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL))
8113     return NULL;
8114 tptr = cptr;
8115 do {
8116     tptr++;
8117     } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.'));
8118 slnt = tptr - cptr;
8119 for (rptr = dptr->registers; rptr->name != NULL; rptr++) {
8120     if ((slnt == strlen (rptr->name)) &&
8121         (strncmp (cptr, rptr->name, slnt) == 0)) {
8122         if (optr != NULL)
8123             *optr = tptr;
8124         return rptr;
8125         }
8126     }
8127 return NULL;
8128 }
8129 
8130 /* get_switches         get switches from input string
8131 
8132    Inputs:
8133         cptr    =       pointer to input string
8134    Outputs:
8135         sw      =       switch bit mask
8136                         0 if no switches, -1 if error
8137 */
8138 
8139 int32 get_switches (const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8140 {
8141 int32 sw;
8142 
8143 if (*cptr != '-')
8144     return 0;
8145 sw = 0;
8146 for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) {
8147     if (sim_isalpha (*cptr) == 0)
8148         return -1;
8149     sw = sw | SWMASK (toupper (*cptr));
8150     }
8151 return sw;
8152 }
8153 
8154 /* get_sim_sw           accumulate sim_switches
8155 
8156    Inputs:
8157         cptr    =       pointer to input string
8158    Outputs:
8159         ptr     =       pointer to first non-string glyph
8160                         NULL if error
8161 */
8162 
8163 CONST char *get_sim_sw (CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8164 {
8165 int32 lsw;
8166 char gbuf[CBUFSIZE];
8167 
8168 while (*cptr == '-') {                                  /* while switches */
8169     cptr = get_glyph (cptr, gbuf, 0);                   /* get switch glyph */
8170     lsw = get_switches (gbuf);                          /* parse */
8171     if (lsw <= 0)                                       /* invalid? */
8172         return NULL;
8173     sim_switches = sim_switches | lsw;                  /* accumulate */
8174     }
8175 return cptr;
8176 }
8177 
8178 /* get_sim_opt          get simulator command options
8179 
8180    Inputs:
8181         opt     =       command options
8182         cptr    =       pointer to input string
8183    Outputs:
8184         ptr     =       pointer to next glyph, NULL if error
8185         *stat   =       error status
8186 */
8187 
8188 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st)
     /* [previous][next][first][last][top][bottom][index][help] */
8189 {
8190 int32 t;
8191 char gbuf[CBUFSIZE];
8192 CONST char *svptr;
8193 DEVICE *tdptr;
8194 UNIT *tuptr;
8195 
8196 sim_switches = 0;                                       /* no switches */
8197 sim_ofile = NULL;                                       /* no output file */
8198 sim_schrptr = NULL;                                     /* no search */
8199 sim_schaptr = NULL;                                     /* no search */
8200 sim_stabr.logic = sim_staba.logic = SCH_OR;             /* default search params */
8201 sim_stabr.boolop = sim_staba.boolop = SCH_GE;
8202 sim_stabr.count = 1;
8203 sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask));
8204 if (!sim_stabr.mask)
8205   {
8206     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8207                    __func__, __FILE__, __LINE__);
8208 #if defined(USE_BACKTRACE)
8209 # if defined(SIGUSR2)
8210     (void)raise(SIGUSR2);
8211     /*NOTREACHED*/ /* unreachable */
8212 # endif /* if defined(SIGUSR2) */
8213 #endif /* if defined(USE_BACKTRACE) */
8214     abort();
8215   }
8216 (void)memset (sim_stabr.mask, 0, sim_emax * sizeof(*sim_stabr.mask));
8217 sim_stabr.comp = (t_value *)realloc (sim_stabr.comp, sim_emax * sizeof(*sim_stabr.comp));
8218 if (!sim_stabr.comp)
8219   {
8220     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8221                    __func__, __FILE__, __LINE__);
8222 #if defined(USE_BACKTRACE)
8223 # if defined(SIGUSR2)
8224     (void)raise(SIGUSR2);
8225     /*NOTREACHED*/ /* unreachable */
8226 # endif /* if defined(SIGUSR2) */
8227 #endif /* if defined(USE_BACKTRACE) */
8228     abort();
8229   }
8230 (void)memset (sim_stabr.comp, 0, sim_emax * sizeof(*sim_stabr.comp));
8231 sim_staba.count = sim_emax;
8232 sim_staba.mask = (t_value *)realloc (sim_staba.mask, sim_emax * sizeof(*sim_staba.mask));
8233 if (!sim_staba.mask)
8234   {
8235     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8236                    __func__, __FILE__, __LINE__);
8237 #if defined(USE_BACKTRACE)
8238 # if defined(SIGUSR2)
8239     (void)raise(SIGUSR2);
8240     /*NOTREACHED*/ /* unreachable */
8241 # endif /* if defined(SIGUSR2) */
8242 #endif /* if defined(USE_BACKTRACE) */
8243     abort();
8244   }
8245 (void)memset (sim_staba.mask, 0, sim_emax * sizeof(*sim_staba.mask));
8246 sim_staba.comp = (t_value *)realloc (sim_staba.comp, sim_emax * sizeof(*sim_staba.comp));
8247 if (!sim_staba.comp)
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_staba.comp, 0, sim_emax * sizeof(*sim_staba.comp));
8260 if (! sim_dflt_dev)
8261   return NULL;
8262 sim_dfdev = sim_dflt_dev;
8263 sim_dfunit = sim_dfdev->units;
8264 sim_opt_out = 0;                                        /* no options yet */
8265 *st = SCPE_OK;
8266 while (*cptr) {                                         /* loop through modifiers */
8267     svptr = cptr;                                       /* save current position */
8268     if ((opt & CMD_OPT_OF) && (*cptr == '@')) {         /* output file spec? */
8269         if (sim_ofile) {                                /* already got one? */
8270             fclose (sim_ofile);                         /* one per customer */
8271             *st = SCPE_ARG;
8272             return NULL;
8273             }
8274         cptr = get_glyph (cptr + 1, gbuf, 0);
8275         sim_ofile = sim_fopen (gbuf, "a");              /* open for append */
8276         if (sim_ofile == NULL) {                        /* open failed? */
8277             *st = SCPE_OPENERR;
8278             return NULL;
8279             }
8280         sim_opt_out |= CMD_OPT_OF;                      /* got output file */
8281         continue;
8282         }
8283     cptr = get_glyph (cptr, gbuf, 0);
8284     if ((t = get_switches (gbuf)) != 0) {               /* try for switches */
8285         if (t < 0) {                                    /* err if bad switch */
8286             *st = SCPE_INVSW;
8287             return NULL;
8288             }
8289         sim_switches = sim_switches | t;                /* or in new switches */
8290         }
8291     else if ((opt & CMD_OPT_SCH) &&                     /* if allowed, */
8292         get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) { /* try for search */
8293         sim_schrptr = &sim_stabr;                       /* set search */
8294         sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);/* populate memory version of the same expression */
8295         sim_opt_out |= CMD_OPT_SCH;                     /* got search */
8296         }
8297     else if ((opt & CMD_OPT_DFT) &&                     /* default allowed? */
8298         ((sim_opt_out & CMD_OPT_DFT) == 0) &&           /* none yet? */
8299         (tdptr = find_unit (gbuf, &tuptr)) &&           /* try for default */
8300         (tuptr != NULL)) {
8301         sim_dfdev = tdptr;                              /* set as default */
8302         sim_dfunit = tuptr;
8303         sim_opt_out |= CMD_OPT_DFT;                     /* got default */
8304         }
8305     else return svptr;                                  /* not rec, break out */
8306     }
8307 return cptr;
8308 }
8309 
8310 /* put_switches         put switches into string
8311 
8312    Inputs:
8313         buf     =       pointer to string buffer
8314         bufsize =       size of string buffer
8315         sw      =       switch bit mask
8316    Outputs:
8317         buf     =       buffer with switches converted to text
8318 */
8319 
8320 const char *put_switches (char *buf, size_t bufsize, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
8321 {
8322 char *optr = buf;
8323 int32 bit;
8324 
8325 (void)memset (buf, 0, bufsize);
8326 if ((sw == 0) || (bufsize < 3))
8327     return buf;
8328 --bufsize;                          /* leave room for terminating NUL */
8329 *optr++ = '-';
8330 for (bit=0; bit <= ('Z'-'A'); bit++)
8331     if (sw & (1 << bit))
8332         if ((size_t)(optr - buf) < bufsize)
8333             *optr++ = 'A' + bit;
8334 return buf;
8335 }
8336 
8337 /* Get register search specification
8338 
8339    Inputs:
8340         cptr    =       pointer to input string
8341         radix   =       radix for numbers
8342         schptr =        pointer to search table
8343    Outputs:
8344         return =        NULL if error
8345                         schptr if valid search specification
8346 */
8347 
8348 SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8349 {
8350 int32 c;
8351 size_t logop, cmpop;
8352 t_value logval, cmpval;
8353 const char *sptr;
8354 CONST char *tptr;
8355 const char logstr[] = "|&^", cmpstr[] = "=!><";
8356 /* Using a const instead of a #define. */
8357 const size_t invalid_op = (size_t) -1;
8358 
8359 logval = cmpval = 0;
8360 if (*cptr == 0)                                         /* check for clause */
8361     return NULL;
8362 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8363 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8364     if ((sptr = strchr (logstr, c))) {                  /* check for mask */
8365         logop = sptr - logstr;
8366         logval = strtotv (cptr, &tptr, radix);
8367         if (cptr == tptr)
8368             return NULL;
8369         cptr = tptr;
8370         }
8371     else if ((sptr = strchr (cmpstr, c))) {             /* check for boolop */
8372         cmpop = sptr - cmpstr;
8373         if (*cptr == '=') {
8374             cmpop = cmpop + strlen (cmpstr);
8375             cptr++;
8376             }
8377         cmpval = strtotv (cptr, &tptr, radix);
8378         if (cptr == tptr)
8379             return NULL;
8380         cptr = tptr;
8381         }
8382     else return NULL;
8383     }                                                   /* end for */
8384 if (schptr->count != 1) {
8385     FREE (schptr->mask);
8386     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8387     FREE (schptr->comp);
8388     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8389     }
8390 if (logop != invalid_op) {
8391     schptr->logic = logop;
8392     schptr->mask[0] = logval;
8393     }
8394 if (cmpop != invalid_op) {
8395     schptr->boolop = cmpop;
8396     schptr->comp[0] = cmpval;
8397     }
8398 schptr->count = 1;
8399 return schptr;
8400 }
8401 
8402 /* Get memory search specification
8403 
8404    Inputs:
8405         cptr    =       pointer to input string
8406         radix   =       radix for numbers
8407         schptr =        pointer to search table
8408    Outputs:
8409         return =        NULL if error
8410                         schptr if valid search specification
8411 */
8412 
8413 SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8414 {
8415 int32 c;
8416 size_t logop, cmpop;
8417 t_value *logval, *cmpval;
8418 t_stat reason = SCPE_OK;
8419 CONST char *ocptr = cptr;
8420 const char *sptr;
8421 char gbuf[CBUFSIZE];
8422 const char logstr[] = "|&^", cmpstr[] = "=!><";
8423 /* Using a const instead of a #define. */
8424 const size_t invalid_op = (size_t) -1;
8425 
8426 if (*cptr == 0)                                         /* check for clause */
8427     return NULL;
8428 logval = (t_value *)calloc (sim_emax, sizeof(*logval));
8429 cmpval = (t_value *)calloc (sim_emax, sizeof(*cmpval));
8430 /*LINTED E_EQUALITY_NOT_ASSIGNMENT*/
8431 for (logop = cmpop = invalid_op; (c = *cptr++); ) {     /* loop thru clauses */
8432     if (NULL != (sptr = strchr (logstr, c))) {          /* check for mask */
8433         logop = sptr - logstr;
8434         cptr = get_glyph (cptr, gbuf, 0);
8435         reason = parse_sym (gbuf, 0, sim_dfunit, logval, sim_switches);
8436         if (reason > 0) {
8437             FREE (logval);
8438             FREE (cmpval);
8439             return get_rsearch (ocptr, radix, schptr);
8440             }
8441         }
8442     else if (NULL != (sptr = strchr (cmpstr, c))) {     /* check for boolop */
8443         cmpop = sptr - cmpstr;
8444         if (*cptr == '=') {
8445             cmpop = cmpop + strlen (cmpstr);
8446             cptr++;
8447             }
8448         cptr = get_glyph (cptr, gbuf, 0);
8449         reason = parse_sym (gbuf, 0, sim_dfunit, cmpval, sim_switches);
8450         if (reason > 0) {
8451             FREE (logval);
8452             FREE (cmpval);
8453             return get_rsearch (ocptr, radix, schptr);
8454             }
8455         }
8456     else {
8457         FREE (logval);
8458         FREE (cmpval);
8459         return NULL;
8460         }
8461     }                                                   /* end for */
8462 if (schptr->count != (uint32)(1 - reason)) {
8463     schptr->count = 1 - reason;
8464     FREE (schptr->mask);
8465     schptr->mask = (t_value *)calloc (sim_emax, sizeof(*schptr->mask));
8466     FREE (schptr->comp);
8467     schptr->comp = (t_value *)calloc (sim_emax, sizeof(*schptr->comp));
8468     }
8469 if (logop != invalid_op) {
8470     schptr->logic = logop;
8471     FREE (schptr->mask);
8472     schptr->mask = logval;
8473     }
8474 else {
8475     FREE (logval);
8476     }
8477 if (cmpop != invalid_op) {
8478     schptr->boolop = cmpop;
8479     FREE (schptr->comp);
8480     schptr->comp = cmpval;
8481     }
8482 else {
8483     FREE (cmpval);
8484     }
8485 return schptr;
8486 }
8487 
8488 /* Test value against search specification
8489 
8490    Inputs:
8491         val    =        value list to test
8492         schptr =        pointer to search table
8493    Outputs:
8494         return =        1 if value passes search criteria, 0 if not
8495 */
8496 
8497 int32 test_search (t_value *values, SCHTAB *schptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8498 {
8499 t_value *val = NULL;
8500 int32 i, updown;
8501 int32 ret = 0;
8502 
8503 if (schptr == NULL)
8504     return ret;
8505 
8506 val = (t_value *)malloc (schptr->count * sizeof (*values));
8507 if (!val)
8508   {
8509     (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
8510                   __func__, __FILE__, __LINE__);
8511 #if defined(USE_BACKTRACE)
8512 # if defined(SIGUSR2)
8513     (void)raise(SIGUSR2);
8514     /*NOTREACHED*/ /* unreachable */
8515 # endif /* if defined(SIGUSR2) */
8516 #endif /* if defined(USE_BACKTRACE) */
8517     abort();
8518   }
8519 for (i=0; i<(int32)schptr->count; i++) {
8520     val[i] = values[i];
8521     switch (schptr->logic) {                            /* case on logical */
8522 
8523         case SCH_OR:
8524             val[i] = val[i] | schptr->mask[i];
8525             break;
8526 
8527         case SCH_AND:
8528             val[i] = val[i] & schptr->mask[i];
8529             break;
8530 
8531         case SCH_XOR:
8532             val[i] = val[i] ^ schptr->mask[i];
8533             break;
8534             }
8535     }
8536 
8537 ret = 1;
8538 if (1) {    /* Little Endian VM */
8539     updown = -1;
8540     i=schptr->count-1;
8541     }
8542 else {      /* Big Endian VM */
8543     updown = 1;
8544     i=0;
8545     }
8546 for (; (i>=0) && (i<(int32)schptr->count) && ret; i += updown) {
8547     switch (schptr->boolop) {                           /* case on comparison */
8548 
8549         case SCH_E: case SCH_EE:
8550             if (val[i] != schptr->comp[i])
8551                 ret = 0;
8552             break;
8553 
8554         case SCH_N: case SCH_NE:
8555             if (val[i] == schptr->comp[i])
8556                 ret = 0;
8557             break;
8558 
8559         case SCH_G:
8560             if (val[i] <= schptr->comp[i])
8561                 ret = 0;
8562             break;
8563 
8564         case SCH_GE:
8565             if (val[i] < schptr->comp[i])
8566                 ret = 0;
8567             break;
8568 
8569         case SCH_L:
8570             if (val[i] >= schptr->comp[i])
8571                 ret = 0;
8572             break;
8573 
8574         case SCH_LE:
8575             if (val[i] > schptr->comp[i])
8576                 ret = 0;
8577             break;
8578         }
8579     }
8580 FREE (val);
8581 return ret;
8582 }
8583 
8584 /* Radix independent input/output package
8585 
8586    strtotv - general radix input routine
8587 
8588    Inputs:
8589         inptr   =       string to convert
8590         endptr  =       pointer to first unconverted character
8591         radix   =       radix for input
8592    Outputs:
8593         value   =       converted value
8594 
8595    On an error, the endptr will equal the inptr.
8596 */
8597 
8598 t_value strtotv (CONST char *inptr, CONST char **endptr, uint32 radix)
     /* [previous][next][first][last][top][bottom][index][help] */
8599 {
8600 int32 nodigit;
8601 t_value val;
8602 uint32 c, digit;
8603 
8604 *endptr = inptr;                                        /* assume fails */
8605 if ((radix < 2) || (radix > 36))
8606     return 0;
8607 while (sim_isspace (*inptr))                            /* bypass white space */
8608     inptr++;
8609 val = 0;
8610 nodigit = 1;
8611 for (c = *inptr; sim_isalnum(c); c = *++inptr) {        /* loop through char */
8612     if (sim_islower (c))
8613         c = toupper (c);
8614     if (sim_isdigit (c))                                /* digit? */
8615         digit = c - (uint32) '0';
8616     else if (radix <= 10)                               /* stop if not expected */
8617         break;
8618     else digit = c + 10 - (uint32) 'A';                 /* convert letter */
8619     if (digit >= radix)                                 /* valid in radix? */
8620         return 0;
8621     val = (val * radix) + digit;                        /* add to value */
8622     nodigit = 0;
8623     }
8624 if (nodigit)                                            /* no digits? */
8625     return 0;
8626 *endptr = inptr;                                        /* result pointer */
8627 return val;
8628 }
8629 
8630 /* fprint_val - general radix printing routine
8631 
8632    Inputs:
8633         stream  =       stream designator
8634         val     =       value to print
8635         radix   =       radix to print
8636         width   =       width to print
8637         format  =       leading zeroes format
8638    Outputs:
8639         status  =       error status
8640         if stream is NULL, returns length of output that would
8641         have been generated.
8642 */
8643 
8644 t_stat sprint_val (char *buffer, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8645                    size_t width, uint32 format)
8646 {
8647 #define MAX_WIDTH ((CHAR_BIT * sizeof (t_value) * 4 + 3) / 3)
8648 t_value owtest, wtest;
8649 size_t d;
8650 size_t digit;
8651 size_t ndigits;
8652 size_t commas = 0;
8653 char dbuf[MAX_WIDTH + 1];
8654 
8655 for (d = 0; d < MAX_WIDTH; d++)
8656     dbuf[d] = (format == PV_RZRO)? '0': ' ';
8657 dbuf[MAX_WIDTH] = 0;
8658 d = MAX_WIDTH;
8659 do {
8660     d = d - 1;
8661     digit = val % radix;
8662     val = val / radix;
8663     dbuf[d] = (char)((digit <= 9)? '0' + digit: 'A' + (digit - 10));
8664     } while ((d > 0) && (val != 0));
8665 
8666 switch (format) {
8667     case PV_LEFT:
8668         break;
8669     case PV_RZRO:
8670         wtest = owtest = radix;
8671         ndigits = 1;
8672         while ((wtest < width_mask[width]) && (wtest >= owtest)) {
8673             owtest = wtest;
8674             wtest = wtest * radix;
8675             ndigits = ndigits + 1;
8676             }
8677         if ((MAX_WIDTH - (ndigits + commas)) < d)
8678             d = MAX_WIDTH - (ndigits + commas);
8679         break;
8680     }
8681 if (NULL == buffer)                   /* Potentially unsafe wraparound if */
8682     return ((t_stat) strlen(dbuf+d)); /*  sizeof(t_stat) < sizeof(size_t) */
8683 *buffer = '\0';
8684 if (width < strlen(dbuf+d))
8685     return SCPE_IOERR;
8686 strcpy(buffer, dbuf+d);
8687 return SCPE_OK;
8688 }
8689 
8690 t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
     /* [previous][next][first][last][top][bottom][index][help] */
8691     uint32 width, uint32 format)
8692 {
8693 char dbuf[MAX_WIDTH + 1];
8694 
8695 if (!stream)
8696     return sprint_val (NULL, val, radix, width, format);
8697 if (width > MAX_WIDTH)
8698     width = MAX_WIDTH;
8699 sprint_val (dbuf, val, radix, width, format);
8700 if (Fprintf (stream, "%s", dbuf) < 0)
8701     return SCPE_IOERR;
8702 return SCPE_OK;
8703 }
8704 
8705 const char *sim_fmt_secs (double seconds)
     /* [previous][next][first][last][top][bottom][index][help] */
8706 {
8707 static char buf[60];
8708 char frac[16] = "";
8709 const char *sign = "";
8710 double val = seconds;
8711 double days, hours, mins, secs, msecs, usecs;
8712 
8713 if (val == 0.0)
8714     return "";
8715 if (val < 0.0) {
8716     sign = "-";
8717     val = -val;
8718     }
8719 days = floor (val / (24.0*60.0*60.0));
8720 val -= (days * 24.0*60.0*60.0);
8721 hours = floor (val / (60.0*60.0));
8722 val -= (hours * 60.0 * 60.0);
8723 mins = floor (val / 60.0);
8724 val -= (mins * 60.0);
8725 secs = floor (val);
8726 val -= secs;
8727 val *= 1000.0;
8728 msecs = floor (val);
8729 val -= msecs;
8730 val *= 1000.0;
8731 usecs = floor (val+0.5);
8732 if (usecs == 1000.0) {
8733     usecs = 0.0;
8734     msecs += 1;
8735     }
8736 if ((msecs > 0.0) || (usecs > 0.0)) {
8737     (void)sprintf (frac, ".%03.0f%03.0f", msecs, usecs);
8738     while (frac[strlen (frac) - 1] == '0') //-V557
8739         frac[strlen (frac) - 1] = '\0'; //-V557
8740     if (strlen (frac) == 1)
8741         frac[0] = '\0';
8742     }
8743 if (days > 0)
8744     (void)sprintf (buf, "%s%.0f day%s %02.0f:%02.0f:%02.0f%s hour%s",
8745                    sign, days, (days != 1) ? "s" : "", hours, mins,
8746                    secs, frac, (days == 1) ? "s" : "");
8747 else
8748     if (hours > 0)
8749         (void)sprintf (buf, "%s%.0f:%02.0f:%02.0f%s hour",
8750                        sign, hours, mins, secs, frac);
8751     else
8752         if (mins > 0)
8753             (void)sprintf (buf, "%s%.0f:%02.0f%s minute",
8754                            sign, mins, secs, frac);
8755         else
8756             if (secs > 0)
8757                 (void)sprintf (buf, "%s%.0f%s second",
8758                                sign, secs, frac);
8759             else
8760                 if (msecs > 0) {
8761                     if (usecs > 0)
8762                         (void)sprintf (buf, "%s%.0f.%s msec",
8763                                        sign, msecs, frac+4);
8764                     else
8765                         (void)sprintf (buf, "%s%.0f msec",
8766                                        sign, msecs);
8767                     }
8768                 else
8769                     (void)sprintf (buf, "%s%.0f usec",
8770                                    sign, usecs);
8771 if (0 != strncmp ("1 ", buf, 2))
8772     strcpy (&buf[strlen (buf)], "s");
8773 return buf;
8774 }
8775 
8776 /*
8777  * Event queue package
8778  *
8779  *      sim_activate            add entry to event queue
8780  *      sim_activate_abs        add entry to event queue even if event already scheduled
8781  *      sim_activate_after      add entry to event queue after a specified amount of wall time
8782  *      sim_cancel              remove entry from event queue
8783  *      sim_process_event       process entries on event queue
8784  *      sim_is_active           see if entry is on event queue
8785  *      sim_activate_time       return time until activation
8786  *      sim_atime               return absolute time for an entry
8787  *      sim_gtime               return global time
8788  *      sim_qcount              return event queue entry count
8789  */
8790 
8791 t_stat sim_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
8792 {
8793 UNIT *uptr;
8794 t_stat reason;
8795 #if defined(TESTING)
8796 cpu_state_t * cpup = _cpup;
8797 #endif
8798 
8799 if (stop_cpu)                                           /* stop CPU? */
8800   {
8801 #if defined(WIN_STDIO)
8802     (void)fflush(stdout);
8803     (void)fflush(stderr);
8804 #endif /* if defined(WIN_STDIO) */
8805     return SCPE_STOP;
8806   }
8807 UPDATE_SIM_TIME;                                        /* update sim time */
8808 
8809 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8810     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8811     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8812                "Queue Empty New Interval = %d\n",
8813                sim_interval);
8814     return SCPE_OK;
8815     }
8816 sim_processing_event = TRUE;
8817 do {
8818     uptr = sim_clock_queue;                             /* get first */
8819     sim_clock_queue = uptr->next;                       /* remove first */
8820     uptr->next = NULL;                                  /* hygiene */
8821     sim_interval -= uptr->time;
8822     uptr->time = 0;
8823     if (sim_clock_queue != QUEUE_LIST_END)
8824         sim_interval = sim_clock_queue->time;
8825     else
8826         sim_interval = noqueue_time = NOQUEUE_WAIT;
8827     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8828                "Processing Event for %s\n", sim_uname (uptr));
8829     if (uptr->action != NULL)
8830         reason = uptr->action (uptr);
8831     else
8832         reason = SCPE_OK;
8833     } while ((reason == SCPE_OK) &&
8834              (sim_interval <= 0) &&
8835              (sim_clock_queue != QUEUE_LIST_END) &&
8836              (!stop_cpu));
8837 
8838 if (sim_clock_queue == QUEUE_LIST_END) {                /* queue empty? */
8839     sim_interval = noqueue_time = NOQUEUE_WAIT;         /* flag queue empty */
8840     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8841                "Processing Queue Complete New Interval = %d\n",
8842                sim_interval);
8843     }
8844 else
8845     sim_debug (SIM_DBG_EVENT, sim_dflt_dev,
8846                "Processing Queue Complete New Interval = %d(%s)\n",
8847                sim_interval, sim_uname(sim_clock_queue));
8848 
8849 if ((reason == SCPE_OK) && stop_cpu)
8850   {
8851 #if defined(WIN_STDIO)
8852     (void)fflush(stdout);
8853     (void)fflush(stderr);
8854 #endif /* if defined(WIN_STDIO) */
8855     reason = SCPE_STOP;
8856   }
8857 sim_processing_event = FALSE;
8858 return reason;
8859 }
8860 
8861 /* sim_activate - activate (queue) event
8862 
8863    Inputs:
8864         uptr    =       pointer to unit
8865         event_time =    relative timeout
8866    Outputs:
8867         reason  =       result (SCPE_OK if ok)
8868 */
8869 
8870 t_stat sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8871 {
8872 if (uptr->dynflags & UNIT_TMR_UNIT)
8873     return sim_timer_activate (uptr, event_time);
8874 return _sim_activate (uptr, event_time);
8875 }
8876 
8877 t_stat _sim_activate (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8878 {
8879 UNIT *cptr, *prvptr;
8880 int32 accum;
8881 #if defined(TESTING)
8882 cpu_state_t * cpup = _cpup;
8883 #endif
8884 
8885 if (sim_is_active (uptr))                               /* already active? */
8886     return SCPE_OK;
8887 UPDATE_SIM_TIME;                                        /* update sim time */
8888 
8889 sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\n", sim_uname (uptr), event_time);
8890 
8891 prvptr = NULL;
8892 accum = 0;
8893 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8894     if (event_time < (accum + cptr->time))
8895         break;
8896     accum = accum + cptr->time;
8897     prvptr = cptr;
8898     }
8899 if (prvptr == NULL) {                                   /* insert at head */
8900     cptr = uptr->next = sim_clock_queue;
8901     sim_clock_queue = uptr;
8902     }
8903 else {
8904     cptr = uptr->next = prvptr->next;                   /* insert at prvptr */
8905     prvptr->next = uptr;
8906     }
8907 uptr->time = event_time - accum;
8908 if (cptr != QUEUE_LIST_END)
8909     cptr->time = cptr->time - uptr->time;
8910 sim_interval = sim_clock_queue->time;
8911 return SCPE_OK;
8912 }
8913 
8914 /* sim_activate_abs - activate (queue) event even if event already scheduled
8915 
8916    Inputs:
8917         uptr    =       pointer to unit
8918         event_time =    relative timeout
8919    Outputs:
8920         reason  =       result (SCPE_OK if ok)
8921 */
8922 
8923 t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
     /* [previous][next][first][last][top][bottom][index][help] */
8924 {
8925 sim_cancel (uptr);
8926 return _sim_activate (uptr, event_time);
8927 }
8928 
8929 /* sim_activate_after - activate (queue) event
8930 
8931    Inputs:
8932         uptr    =       pointer to unit
8933         usec_delay =    relative timeout (in microseconds)
8934    Outputs:
8935         reason  =       result (SCPE_OK if ok)
8936 */
8937 
8938 t_stat sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
8939 {
8940 return _sim_activate_after (uptr, usec_delay);
8941 }
8942 
8943 t_stat _sim_activate_after (UNIT *uptr, uint32 usec_delay)
     /* [previous][next][first][last][top][bottom][index][help] */
8944 {
8945 if (sim_is_active (uptr))                               /* already active? */
8946     return SCPE_OK;
8947 return sim_timer_activate_after (uptr, usec_delay);
8948 }
8949 
8950 /* sim_cancel - cancel (dequeue) event
8951 
8952    Inputs:
8953         uptr    =       pointer to unit
8954    Outputs:
8955         reason  =       result (SCPE_OK if ok)
8956 
8957 */
8958 
8959 t_stat sim_cancel (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
8960 {
8961 UNIT *cptr, *nptr;
8962 #if defined(TESTING)
8963 cpu_state_t * cpup = _cpup;
8964 #endif
8965 
8966 if (sim_clock_queue == QUEUE_LIST_END)
8967     return SCPE_OK;
8968 if (!sim_is_active (uptr))
8969     return SCPE_OK;
8970 UPDATE_SIM_TIME;                                        /* update sim time */
8971 sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\n", sim_uname(uptr));
8972 nptr = QUEUE_LIST_END;
8973 
8974 if (sim_clock_queue == uptr) {
8975     nptr = sim_clock_queue = uptr->next;
8976     uptr->next = NULL;                                  /* hygiene */
8977     }
8978 else {
8979     for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
8980         if (cptr->next == uptr) {
8981             nptr = cptr->next = uptr->next;
8982             uptr->next = NULL;                          /* hygiene */
8983             break;                                      /* end queue scan */
8984             }
8985         }
8986     }
8987 if (nptr != QUEUE_LIST_END)
8988     nptr->time += (uptr->next) ? 0 : uptr->time;
8989 if (!uptr->next)
8990     uptr->time = 0;
8991 if (sim_clock_queue != QUEUE_LIST_END)
8992     sim_interval = sim_clock_queue->time;
8993 else sim_interval = noqueue_time = NOQUEUE_WAIT;
8994 if (uptr->next) {
8995     sim_printf ("\rCancel failed for '%s'!\r\n", sim_uname(uptr));
8996     if (sim_deb)
8997         fclose(sim_deb);
8998     (void)fprintf (stderr, "\rFATAL: Bugcheck! Aborting at %s[%s:%d]\r\n",
8999                    __func__, __FILE__, __LINE__);
9000     abort ();
9001     }
9002 return SCPE_OK;
9003 }
9004 
9005 /* sim_is_active - test for entry in queue
9006 
9007    Inputs:
9008         uptr    =       pointer to unit
9009    Outputs:
9010         result =        TRUE if unit is busy, FALSE inactive
9011 */
9012 
9013 t_bool sim_is_active (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9014 {
9015 if (uptr->next == NULL)
9016   return FALSE;
9017 else
9018 return TRUE;
9019 }
9020 
9021 /* sim_activate_time - return activation time
9022 
9023    Inputs:
9024         uptr    =       pointer to unit
9025    Outputs:
9026         result =        absolute activation time + 1, 0 if inactive
9027 */
9028 
9029 int32 sim_activate_time (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9030 {
9031 UNIT *cptr;
9032 int32 accum = 0;
9033 
9034 for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
9035     if (cptr == sim_clock_queue) {
9036         if (sim_interval > 0)
9037             accum = accum + sim_interval;
9038         }
9039     else
9040         accum = accum + cptr->time;
9041     if (cptr == uptr)
9042         return accum + 1;
9043     }
9044 return 0;
9045 }
9046 
9047 /* sim_gtime - return global time
9048 
9049    Inputs: none
9050    Outputs:
9051         time    =       global time
9052 */
9053 
9054 double sim_gtime (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9055 {
9056 return sim_time;
9057 }
9058 
9059 /* sim_qcount - return queue entry count
9060 
9061    Inputs: none
9062    Outputs:
9063         count   =       number of entries on the queue
9064 */
9065 
9066 int32 sim_qcount (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9067 {
9068 int32 cnt;
9069 UNIT *uptr;
9070 
9071 cnt = 0;
9072 for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
9073     cnt++;
9074 return cnt;
9075 }
9076 
9077 /* Breakpoint package.  This module replaces the VM-implemented one
9078    instruction breakpoint capability.
9079 
9080    Breakpoints are stored in table sim_brk_tab, which is ordered by address for
9081    efficient binary searching.  A breakpoint consists of a six entry structure:
9082 
9083         addr                    address of the breakpoint
9084         type                    types of breakpoints set on the address
9085                                 a bit mask representing letters A-Z
9086         cnt                     number of iterations before breakp is taken
9087         action                  pointer command string to be executed
9088                                 when break is taken
9089         next                    list of other breakpoints with the same addr specifier
9090         time_fired              array of when this breakpoint was fired for each class
9091 
9092    sim_brk_summ is a summary of the types of breakpoints that are currently set (it
9093    is the bitwise OR of all the type fields).  A simulator need only check for
9094    a breakpoint of type X if bit SWMASK('X') is set in sim_brk_summ.
9095 
9096    The package contains the following public routines:
9097 
9098         sim_brk_init            initialize
9099         sim_brk_set             set breakpoint
9100         sim_brk_clr             clear breakpoint
9101         sim_brk_clrall          clear all breakpoints
9102         sim_brk_show            show breakpoint
9103         sim_brk_showall         show all breakpoints
9104         sim_brk_test            test for breakpoint
9105         sim_brk_npc             PC has been changed
9106         sim_brk_getact          get next action
9107         sim_brk_clract          clear pending actions
9108 
9109    Initialize breakpoint system.
9110 */
9111 
9112 t_stat sim_brk_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9113 {
9114 int32 i;
9115 
9116 for (i=0; i<sim_brk_lnt; i++) {
9117     BRKTAB *bp;
9118     if (sim_brk_tab)
9119       {
9120         bp = sim_brk_tab[i];
9121 
9122         while (bp)
9123           {
9124             BRKTAB *bpt = bp->next;
9125 
9126             FREE (bp->act);
9127             FREE (bp);
9128             bp = bpt;
9129           }
9130       }
9131 }
9132 if (sim_brk_tab != NULL)
9133     (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9134 sim_brk_lnt = SIM_BRK_INILNT;
9135 sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*));
9136 if (sim_brk_tab == NULL)
9137     return SCPE_MEM;
9138 (void)memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*));
9139 sim_brk_ent = sim_brk_ins = 0;
9140 sim_brk_clract ();
9141 sim_brk_npc (0);
9142 return SCPE_OK;
9143 }
9144 
9145 /* Search for a breakpoint in the sorted breakpoint table */
9146 
9147 BRKTAB *sim_brk_fnd (t_addr loc)
     /* [previous][next][first][last][top][bottom][index][help] */
9148 {
9149 int32 lo, hi, p;
9150 BRKTAB *bp;
9151 
9152 if (sim_brk_ent == 0) {                                 /* table empty? */
9153     sim_brk_ins = 0;                                    /* insrt at head */
9154     return NULL;                                        /* sch fails */
9155     }
9156 lo = 0;                                                 /* initial bounds */
9157 hi = sim_brk_ent - 1;
9158 do {
9159     p = (lo + hi) >> 1;                                 /* probe */
9160     bp = sim_brk_tab[p];                                /* table addr */
9161     if (loc == bp->addr) {                              /* match? */
9162         sim_brk_ins = p;
9163         return bp;
9164         }
9165     else if (loc < bp->addr)                            /* go down? p is upper */
9166         hi = p - 1;
9167     else lo = p + 1;                                    /* go up? p is lower */
9168     } while (lo <= hi);
9169 if (loc < bp->addr)                                     /* insrt before or */
9170     sim_brk_ins = p;
9171 else sim_brk_ins = p + 1;                               /* after last sch */
9172 return NULL;
9173 }
9174 
9175 BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ, uint32 spc)
     /* [previous][next][first][last][top][bottom][index][help] */
9176 {
9177 BRKTAB *bp = sim_brk_fnd (loc);
9178 
9179 while (bp) {
9180     if (any_typ ? ((bp->typ & btyp) && (bp->time_fired[spc] != sim_gtime())) :
9181                   (bp->typ == btyp))
9182         return bp;
9183     bp = bp->next;
9184     }
9185 return bp;
9186 }
9187 
9188 /* Insert a breakpoint */
9189 
9190 BRKTAB *sim_brk_new (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9191 {
9192 int32 i, t;
9193 BRKTAB *bp, **newp;
9194 
9195 if (sim_brk_ins < 0)
9196     return NULL;
9197 if (sim_brk_ent >= sim_brk_lnt) {                       /* out of space? */
9198     t = sim_brk_lnt + SIM_BRK_INILNT;                   /* new size */
9199     newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*));    /* new table */
9200     if (newp == NULL)                                   /* can't extend */
9201         return NULL;
9202     memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));/* copy table */
9203     (void)memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));/* zero new entries */
9204     FREE (sim_brk_tab);                                 /* free old table */
9205     sim_brk_tab = newp;                                 /* new base, lnt */
9206     sim_brk_lnt = t;
9207     }
9208 if ((sim_brk_ins == sim_brk_ent) ||
9209     ((sim_brk_ins != sim_brk_ent) && //-V728
9210      (sim_brk_tab[sim_brk_ins]->addr != loc))) {        /* need to open a hole? */
9211     for (i = sim_brk_ent; i > sim_brk_ins; --i)
9212         sim_brk_tab[i] = sim_brk_tab[i - 1];
9213     sim_brk_tab[sim_brk_ins] = NULL;
9214     }
9215 bp = (BRKTAB *)calloc (1, sizeof (*bp));
9216 if (!bp)
9217   {
9218     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9219                    __func__, __FILE__, __LINE__);
9220 #if defined(USE_BACKTRACE)
9221 # if defined(SIGUSR2)
9222     (void)raise(SIGUSR2);
9223     /*NOTREACHED*/ /* unreachable */
9224 # endif /* if defined(SIGUSR2) */
9225 #endif /* if defined(USE_BACKTRACE) */
9226     abort();
9227   }
9228 bp->next = sim_brk_tab[sim_brk_ins];
9229 sim_brk_tab[sim_brk_ins] = bp;
9230 if (bp->next == NULL)
9231     sim_brk_ent += 1;
9232 bp->addr = loc;
9233 bp->typ = btyp;
9234 bp->cnt = 0;
9235 bp->act = NULL;
9236 for (i = 0; i < SIM_BKPT_N_SPC; i++)
9237     bp->time_fired[i] = -1.0;
9238 return bp;
9239 }
9240 
9241 /* Set a breakpoint of type sw */
9242 
9243 t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, CONST char *act)
     /* [previous][next][first][last][top][bottom][index][help] */
9244 {
9245 BRKTAB *bp;
9246 
9247 if ((sw == 0) || (sw == BRK_TYP_DYN_STEPOVER))
9248     sw |= sim_brk_dflt;
9249 if (~sim_brk_types & sw) {
9250     char gbuf[CBUFSIZE];
9251 
9252     return sim_messagef (SCPE_NOFNC, "Unknown breakpoint type; %s\n", put_switches(gbuf, sizeof(gbuf), sw & ~sim_brk_types));
9253     }
9254 if ((sw & BRK_TYP_DYN_ALL) && act)                      /* can't specify an action with a dynamic breakpoint */
9255     return SCPE_ARG;
9256 bp = sim_brk_fnd (loc);                                 /* loc present? */
9257 if (!bp)                                                /* no, allocate */
9258     bp = sim_brk_new (loc, sw);
9259 else {
9260     while (bp && (bp->typ != (uint32)sw))
9261         bp = bp->next;
9262     if (!bp)
9263         bp = sim_brk_new (loc, sw);
9264     }
9265 if (!bp)                                                /* still no? mem err */
9266     return SCPE_MEM;
9267 bp->cnt = ncnt;                                         /* set count */
9268 if ((!(sw & BRK_TYP_DYN_ALL)) &&                        /* Not Dynamic and */
9269     (bp->act != NULL) && (act != NULL)) {               /* replace old action? */
9270     FREE (bp->act);                                     /* deallocate */
9271     bp->act = NULL;                                     /* now no action */
9272     }
9273 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9274     char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char)); /* alloc buf */
9275     if (newp == NULL)                                   /* mem err? */
9276         return SCPE_MEM;
9277     strncpy (newp, act, CBUFSIZE);                      /* copy action */
9278     bp->act = newp;                                     /* set pointer */
9279     }
9280 sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP);
9281 return SCPE_OK;
9282 }
9283 
9284 /* Clear a breakpoint */
9285 
9286 t_stat sim_brk_clr (t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9287 {
9288 BRKTAB *bpl = NULL;
9289 BRKTAB *bp = sim_brk_fnd (loc);
9290 int32 i;
9291 
9292 if (!bp)                                                /* not there? ok */
9293     return SCPE_OK;
9294 if (sw == 0)
9295     sw = SIM_BRK_ALLTYP;
9296 
9297 #if !defined(__clang_analyzer__)
9298 while (bp) {
9299     if (bp->typ == (bp->typ & sw)) {
9300         FREE (bp->act);                                 /* deallocate action */
9301         if (bp == sim_brk_tab[sim_brk_ins])
9302             bpl = sim_brk_tab[sim_brk_ins] = bp->next;
9303         else
9304           {
9305             if (bpl)
9306               bpl->next = bp->next;
9307           }
9308         FREE (bp);
9309         bp = bpl;
9310         }
9311     else {
9312         bpl = bp;
9313         bp = bp->next;
9314         }
9315     }
9316 #endif /* if !defined(__clang_analyzer__) */
9317 if (sim_brk_tab[sim_brk_ins] == NULL) {                 /* erased entry */
9318     sim_brk_ent = sim_brk_ent - 1;                      /* decrement count */
9319     for (i = sim_brk_ins; i < sim_brk_ent; i++)         /* shuffle remaining entries */
9320         sim_brk_tab[i] = sim_brk_tab[i+1];
9321     }
9322 sim_brk_summ = 0;                                       /* recalc summary */
9323 for (i = 0; i < sim_brk_ent; i++) {
9324     bp = sim_brk_tab[i];
9325     while (bp) {
9326         sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP);
9327         bp = bp->next;
9328         }
9329     }
9330 return SCPE_OK;
9331 }
9332 
9333 /* Clear all breakpoints */
9334 
9335 t_stat sim_brk_clrall (int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9336 {
9337 int32 i;
9338 
9339 if (sw == 0)
9340     sw = SIM_BRK_ALLTYP;
9341 for (i = 0; i < sim_brk_ent;) {
9342     t_addr loc = sim_brk_tab[i]->addr;
9343     sim_brk_clr (loc, sw);
9344     if ((i < sim_brk_ent) &&
9345         (loc == sim_brk_tab[i]->addr))
9346         ++i;
9347     }
9348 return SCPE_OK;
9349 }
9350 
9351 /* Show a breakpoint */
9352 
9353 t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9354 {
9355 BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE, 0);
9356 DEVICE *dptr;
9357 uint32 i, any;
9358 
9359 if ((sw == 0) || (sw == SWMASK ('C'))) {
9360     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); }
9361 if (!bp || (!(bp->typ & sw))) {
9362     return SCPE_OK; }
9363 dptr = sim_dflt_dev;
9364 if (dptr == NULL) {
9365     return SCPE_OK; }
9366 if (sw & SWMASK ('C')) {
9367     if (st != NULL) {
9368         (void)fprintf (st, "SET BREAK "); }
9369 } else {
9370     if (sim_vm_fprint_addr) {
9371         sim_vm_fprint_addr
9372             (st, dptr, loc);
9373     } else {
9374         fprint_val
9375             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9376     if (st != NULL) {
9377         (void)fprintf (st, ":\t"); }
9378     }
9379 for (i = any = 0; i < 26; i++) {
9380     if ((bp->typ >> i) & 1) {
9381         if ((sw & SWMASK ('C')) == 0) {
9382             if (any) {
9383                 if (st != NULL) {
9384                     (void)fprintf (st, ", "); } }
9385             if (st != NULL) {
9386                 fputc (i + 'A', st); }
9387             }
9388         } else {
9389             if (st != NULL) {
9390                 (void)fprintf (st, "-%c", i + 'A'); }
9391         any = 1;
9392         }
9393     }
9394 if (sw & SWMASK ('C')) {
9395     if (st != NULL) {
9396         (void)fprintf (st, " "); }
9397     if (sim_vm_fprint_addr) {
9398         if (st != NULL) {
9399             sim_vm_fprint_addr (st, dptr, loc); }
9400     } else {
9401         fprint_val
9402             (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); }
9403     }
9404 if (bp->cnt > 0) {
9405     if (st != NULL) {
9406         (void)fprintf (st, "[%d]", bp->cnt); } }
9407 if (bp->act != NULL) {
9408     if (st != NULL) {
9409         (void)fprintf (st, "; %s", bp->act); } }
9410 (void)fprintf (st, "\n");
9411 return SCPE_OK;
9412 }
9413 
9414 /* Show all breakpoints */
9415 
9416 t_stat sim_brk_showall (FILE *st, uint32 sw)
     /* [previous][next][first][last][top][bottom][index][help] */
9417 {
9418 int32 bit, mask, types;
9419 BRKTAB **bpt;
9420 
9421 if ((sw == 0) || (sw == SWMASK ('C')))
9422     sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0);
9423 for (types=bit=0; bit <= ('Z'-'A'); bit++)
9424     if (sim_brk_types & (1 << bit))
9425         ++types;
9426 if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) {
9427     (void)fprintf (st, "Supported Breakpoint Types:");
9428     for (bit=0; bit <= ('Z'-'A'); bit++)
9429         if (sim_brk_types & (1 << bit))
9430             (void)fprintf (st, " -%c", 'A' + bit);
9431     (void)fprintf (st, "\n");
9432     }
9433 if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) {
9434     mask = (sw & sim_brk_types);
9435     (void)fprintf (st, "Displaying Breakpoint Types:");
9436     for (bit=0; bit <= ('Z'-'A'); bit++)
9437         if (mask & (1 << bit))
9438             (void)fprintf (st, " -%c", 'A' + bit);
9439     (void)fprintf (st, "\n");
9440     }
9441 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9442     BRKTAB *prev = NULL;
9443     BRKTAB *cur = *bpt;
9444     BRKTAB *next;
9445     /* First reverse the list */
9446     while (cur) {
9447         next = cur->next;
9448         cur->next = prev;
9449         prev = cur;
9450         cur = next;
9451         }
9452     /* save reversed list in the head pointer so lookups work */
9453     *bpt = prev;
9454     /* Walk the reversed list and print it in the order it was defined in */
9455     cur = prev;
9456     while (cur) {
9457         if (cur->typ & sw)
9458             sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0));
9459         cur = cur->next;
9460         }
9461     /* reversing the list again */
9462     cur = prev;
9463     prev = NULL;
9464     while (cur) {
9465         next = cur->next;
9466         cur->next = prev;
9467         prev = cur;
9468         cur = next;
9469         }
9470     /* restore original list */
9471     *bpt = prev;
9472     }
9473 return SCPE_OK;
9474 }
9475 
9476 /* Test for breakpoint */
9477 
9478 uint32 sim_brk_test (t_addr loc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9479 {
9480 BRKTAB *bp;
9481 uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1);
9482 
9483 if (sim_brk_summ & BRK_TYP_DYN_ALL)
9484     btyp |= BRK_TYP_DYN_ALL;
9485 
9486 if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE, spc))) {     /* in table, and type match? */
9487     double s_gtime = sim_gtime ();                      /* get time now */
9488 
9489     if (bp->time_fired[spc] == s_gtime)                 /* already taken?  */
9490         return 0;
9491     bp->time_fired[spc] = s_gtime;                      /* remember match time */
9492     if (--bp->cnt > 0)                                  /* count > 0? */
9493         return 0;
9494     bp->cnt = 0;                                        /* reset count */
9495     sim_brk_setact (bp->act);                           /* set up actions */
9496     sim_brk_match_type = btyp & bp->typ;                /* set return value */
9497     if (bp->typ & BRK_TYP_TEMP)
9498         sim_brk_clr (loc, bp->typ);                     /* delete one-shot breakpoint */
9499     sim_brk_match_addr = loc;
9500     return sim_brk_match_type;
9501     }
9502 return 0;
9503 }
9504 
9505 /* Get next pending action, if any */
9506 
9507 CONST char *sim_brk_getact (char *buf, int32 size)
     /* [previous][next][first][last][top][bottom][index][help] */
9508 {
9509 char *ep;
9510 size_t lnt;
9511 
9512 if (sim_brk_act[sim_do_depth] == NULL)                  /* any action? */
9513     return NULL;
9514 while (sim_isspace (*sim_brk_act[sim_do_depth]))        /* skip spaces */
9515     sim_brk_act[sim_do_depth]++;
9516 if (*sim_brk_act[sim_do_depth] == 0) {                  /* now empty? */
9517     return sim_brk_clract ();
9518     }
9519 if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) {   /* cmd delimiter? */
9520     lnt = ep - sim_brk_act[sim_do_depth];               /* cmd length */
9521     memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1);   /* copy with ; */
9522     buf[lnt] = 0;                                       /* erase ; */
9523     sim_brk_act[sim_do_depth] += lnt + 1;               /* adv ptr */
9524     }
9525 else {
9526     strncpy (buf, sim_brk_act[sim_do_depth], size);     /* copy action */
9527     sim_brk_clract ();                                  /* no more */
9528     }
9529 return buf;
9530 }
9531 
9532 /* Clear pending actions */
9533 
9534 char *sim_brk_clract (void)
     /* [previous][next][first][last][top][bottom][index][help] */
9535 {
9536 FREE (sim_brk_act_buf[sim_do_depth]);
9537 return sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth] = NULL;
9538 }
9539 
9540 /* Set up pending actions */
9541 
9542 void sim_brk_setact (const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
9543 {
9544 if (action) {
9545     sim_brk_act_buf[sim_do_depth] = (char *)realloc (sim_brk_act_buf[sim_do_depth], strlen (action) + 1);
9546     if (!sim_brk_act_buf[sim_do_depth])
9547       {
9548         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9549                        __func__, __FILE__, __LINE__);
9550 #if defined(USE_BACKTRACE)
9551 # if defined(SIGUSR2)
9552         (void)raise(SIGUSR2);
9553         /*NOTREACHED*/ /* unreachable */
9554 # endif /* if defined(SIGUSR2) */
9555 #endif /* if defined(USE_BACKTRACE) */
9556         abort();
9557       }
9558     strcpy (sim_brk_act_buf[sim_do_depth], action);
9559     sim_brk_act[sim_do_depth] = sim_brk_act_buf[sim_do_depth];
9560     }
9561 else
9562     sim_brk_clract ();
9563 }
9564 
9565 /* New PC */
9566 
9567 void sim_brk_npc (uint32 cnt)
     /* [previous][next][first][last][top][bottom][index][help] */
9568 {
9569 uint32 spc;
9570 BRKTAB **bpt, *bp;
9571 
9572 if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC))
9573     cnt = SIM_BKPT_N_SPC;
9574 for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9575     for (bp = *bpt; bp; bp = bp->next) {
9576         for (spc = 0; spc < cnt; spc++)
9577             bp->time_fired[spc] = -1.0;
9578         }
9579     }
9580 }
9581 
9582 /* Clear breakpoint space */
9583 
9584 void sim_brk_clrspc (uint32 spc, uint32 btyp)
     /* [previous][next][first][last][top][bottom][index][help] */
9585 {
9586 BRKTAB **bpt, *bp;
9587 
9588 if (spc < SIM_BKPT_N_SPC) {
9589     for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) {
9590         for (bp = *bpt; bp; bp = bp->next) {
9591             if (bp->typ & btyp)
9592                 bp->time_fired[spc] = -1.0;
9593             }
9594         }
9595     }
9596 }
9597 
9598 const char *sim_brk_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
9599 {
9600 static char msg[256];
9601 char addr[65] = "";
9602 char buf[32];
9603 
9604 msg[0] = '\0';
9605 if (sim_dflt_dev) {
9606   if (sim_vm_sprint_addr)
9607     sim_vm_sprint_addr (addr, sim_dflt_dev, (t_value)sim_brk_match_addr);
9608   else sprint_val (addr, (t_value)sim_brk_match_addr, sim_dflt_dev->aradix, sim_dflt_dev->awidth, PV_LEFT);
9609 }
9610 if (sim_brk_type_desc) {
9611     BRKTYPTAB *brk = sim_brk_type_desc;
9612 
9613     while (2 == strlen (put_switches (buf, sizeof(buf), brk->btyp))) {
9614         if (brk->btyp == sim_brk_match_type) {
9615             (void)sprintf (msg, "%s: %s", brk->desc, addr);
9616             break;
9617             }
9618         brk++;
9619         }
9620     }
9621 if (!msg[0])
9622     (void)sprintf (msg, "%s Breakpoint at: %s\n",
9623                    put_switches (buf, sizeof(buf), sim_brk_match_type), addr);
9624 
9625 return msg;
9626 }
9627 
9628 /* Expect package.  This code provides a mechanism to stop and control simulator
9629    execution based on traffic coming out of simulated ports and as well as a means
9630    to inject data into those ports.  It can conceptually viewed as a string
9631    breakpoint package.
9632 
9633    Expect rules are stored in tables associated with each port which can use this
9634    facility.  An expect rule consists of a five entry structure:
9635 
9636         match                   the expect match string
9637         size                    the number of bytes in the match string
9638         match_pattern           the expect match string in display format
9639         cnt                     number of iterations before match is declared
9640         action                  command string to be executed when match occurs
9641 
9642    All active expect rules are contained in an expect match context structure.
9643 
9644         rules                   the match rules
9645         size                    the count of match rules
9646         buf                     the buffer of output data which has been produced
9647         buf_ins                 the buffer insertion point for the next output data
9648         buf_size                the buffer size
9649 
9650    The package contains the following public routines:
9651 
9652         sim_set_expect          expect command parser and initializer
9653         sim_set_noexpect        noexpect command parser
9654         sim_exp_set             set or add an expect rule
9655         sim_exp_clr             clear or delete an expect rule
9656         sim_exp_clrall          clear all expect rules
9657         sim_exp_show            show an expect rule
9658         sim_exp_showall         show all expect rules
9659         sim_exp_check           test for rule match
9660 */
9661 
9662 /* Set expect */
9663 
9664 t_stat sim_set_expect (EXPECT *exp, CONST char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9665 {
9666 char gbuf[CBUFSIZE];
9667 CONST char *tptr;
9668 CONST char *c1ptr;
9669 t_bool after_set = FALSE;
9670 uint32 after;
9671 int32 cnt = 0;
9672 t_stat r;
9673 
9674 if (exp == NULL)
9675     return sim_messagef (SCPE_ARG, "Null exp!\n");
9676 after = exp->after;
9677 
9678 if ((cptr == NULL) || (*cptr == 0))
9679     return SCPE_2FARG;
9680 if (*cptr == '[') {
9681     cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
9682     if ((cptr == c1ptr) || (*c1ptr != ']'))
9683         return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n");
9684     cptr = c1ptr + 1;
9685     while (sim_isspace(*cptr))
9686         ++cptr;
9687     }
9688 tptr = get_glyph (cptr, gbuf, ',');
9689 if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
9690     after = (uint32)get_uint (&gbuf[10], 10, 2000000000, &r);
9691     if (r != SCPE_OK)
9692         return sim_messagef (SCPE_ARG, "Invalid Halt After Value\n");
9693     after_set = TRUE;
9694     cptr = tptr;
9695     }
9696 if ((*cptr != '"') && (*cptr != '\''))
9697     return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
9698 cptr = get_glyph_quoted (cptr, gbuf, 0);
9699 
9700 return sim_exp_set (exp, gbuf, cnt, (after_set ? after : exp->after), sim_switches, cptr);
9701 }
9702 
9703 /* Clear expect */
9704 
9705 t_stat sim_set_noexpect (EXPECT *exp, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
9706 {
9707 char gbuf[CBUFSIZE];
9708 
9709 if (NULL == cptr || !*cptr)
9710     return sim_exp_clrall (exp);                    /* clear all rules */
9711 if ((*cptr != '"') && (*cptr != '\''))
9712     return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
9713 cptr = get_glyph_quoted (cptr, gbuf, 0);
9714 if (*cptr != '\0')
9715     return SCPE_2MARG;                              /* No more arguments */
9716 return sim_exp_clr (exp, gbuf);                     /* clear one rule */
9717 }
9718 
9719 /* Search for an expect rule in an expect context */
9720 
9721 CONST EXPTAB *sim_exp_fnd (CONST EXPECT *exp, const char *match, size_t start_rule)
     /* [previous][next][first][last][top][bottom][index][help] */
9722 {
9723 size_t i;
9724 
9725 if (NULL == exp->rules)
9726     return NULL;
9727 for (i=start_rule; i<exp->size; i++)
9728     if (!strcmp (exp->rules[i].match_pattern, match))
9729         return &exp->rules[i];
9730 return NULL;
9731 }
9732 
9733 /* Clear (delete) an expect rule */
9734 
9735 t_stat sim_exp_clr_tab (EXPECT *exp, EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9736 {
9737 size_t i;
9738 
9739 if (NULL == ep)                                         /* not there? ok */
9740     return SCPE_OK;
9741 FREE (ep->match);                                       /* deallocate match string */
9742 FREE (ep->match_pattern);                               /* deallocate the display format match string */
9743 FREE (ep->act);                                         /* deallocate action */
9744 exp->size -= 1;                                         /* decrement count */
9745 #if !defined(__clang_analyzer__)
9746 for (i=ep-exp->rules; i<exp->size; i++)                 /* shuffle up remaining rules */
9747     exp->rules[i] = exp->rules[i+1];
9748 if (exp->size == 0) {                                   /* No rules left? */
9749     FREE (exp->rules);
9750     exp->rules = NULL;
9751     }
9752 #endif /* if !defined(__clang_analyzer__) */
9753 return SCPE_OK;
9754 }
9755 
9756 t_stat sim_exp_clr (EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9757 {
9758 EXPTAB *ep = (EXPTAB *)sim_exp_fnd (exp, match, 0);
9759 
9760 while (ep) {
9761     sim_exp_clr_tab (exp, ep);
9762     ep = (EXPTAB *)sim_exp_fnd (exp, match, ep - exp->rules);
9763     }
9764 return SCPE_OK;
9765 }
9766 
9767 /* Clear all expect rules */
9768 
9769 t_stat sim_exp_clrall (EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
9770 {
9771 int32 i;
9772 
9773 for (i=0; i<exp->size; i++) {
9774     FREE (exp->rules[i].match);                         /* deallocate match string */
9775     FREE (exp->rules[i].match_pattern);                 /* deallocate display format match string */
9776     FREE (exp->rules[i].act);                           /* deallocate action */
9777     }
9778 FREE (exp->rules);
9779 exp->rules = NULL;
9780 exp->size = 0;
9781 FREE (exp->buf);
9782 exp->buf = NULL;
9783 exp->buf_size = 0;
9784 exp->buf_ins = 0;
9785 return SCPE_OK;
9786 }
9787 
9788 /* Set/Add an expect rule */
9789 
9790 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] */
9791 {
9792 EXPTAB *ep;
9793 uint8 *match_buf;
9794 uint32 match_size;
9795 size_t i;
9796 
9797 /* Validate the match string */
9798 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9799 if (!match_buf)
9800     return SCPE_MEM;
9801 if (switches & EXP_TYP_REGEX) {
9802     FREE (match_buf);
9803     return sim_messagef (SCPE_ARG, "RegEx support not available\n");
9804     }
9805 else {
9806     if (switches & EXP_TYP_REGEX_I) {
9807         FREE (match_buf);
9808         return sim_messagef (SCPE_ARG, "Case independent matching is only valid for RegEx expect rules\n");
9809         }
9810     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9811     if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
9812         FREE (match_buf);
9813         return sim_messagef (SCPE_ARG, "Invalid quoted string\n");
9814         }
9815     }
9816 FREE (match_buf);
9817 for (i=0; i<exp->size; i++) {                           /* Make sure this rule won't be occluded */
9818     if ((0 == strcmp (match, exp->rules[i].match_pattern)) &&
9819         (exp->rules[i].switches & EXP_TYP_PERSIST))
9820         return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\n");
9821     }
9822 if (after && exp->size)
9823     return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n");
9824 exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
9825 if (!exp->rules)
9826   {
9827     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9828                    __func__, __FILE__, __LINE__);
9829 #if defined(USE_BACKTRACE)
9830 # if defined(SIGUSR2)
9831     (void)raise(SIGUSR2);
9832     /*NOTREACHED*/ /* unreachable */
9833 # endif /* if defined(SIGUSR2) */
9834 #endif /* if defined(USE_BACKTRACE) */
9835     abort();
9836   }
9837 ep = &exp->rules[exp->size];
9838 exp->size += 1;
9839 exp->after = after;                                     /* set halt after value */
9840 (void)memset (ep, 0, sizeof(*ep));
9841 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9842 if (ep->match_pattern)
9843     strcpy (ep->match_pattern, match);
9844 ep->cnt = cnt;                                          /* set proceed count */
9845 ep->switches = switches;                                /* set switches */
9846 match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
9847 if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
9848     sim_exp_clr_tab (exp, ep);                          /* clear it */
9849     FREE (match_buf);                                   /* release allocation */
9850     return SCPE_MEM;
9851     }
9852 if (switches & EXP_TYP_REGEX) {
9853     FREE (match_buf);
9854     match_buf = NULL;
9855     }
9856 else {
9857     sim_data_trace(exp->dptr, exp->dptr->units, (const uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit);
9858     sim_decode_quoted_string (match, match_buf, &match_size);
9859     ep->match = match_buf;
9860     ep->size = match_size;
9861     }
9862 ep->match_pattern = (char *)malloc (strlen (match) + 1);
9863 if (!ep->match_pattern)
9864   {
9865     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
9866                    __func__, __FILE__, __LINE__);
9867 #if defined(USE_BACKTRACE)
9868 # if defined(SIGUSR2)
9869     (void)raise(SIGUSR2);
9870     /*NOTREACHED*/ /* unreachable */
9871 # endif /* if defined(SIGUSR2) */
9872 #endif /* if defined(USE_BACKTRACE) */
9873     abort();
9874   }
9875 strcpy (ep->match_pattern, match);
9876 if (ep->act) {                                          /* replace old action? */
9877     FREE (ep->act);                                     /* deallocate */
9878     ep->act = NULL;                                     /* now no action */
9879     }
9880 if (act) while (sim_isspace(*act)) ++act;                   /* skip leading spaces in action string */
9881 if ((act != NULL) && (*act != 0)) {                     /* new action? */
9882     char *newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */
9883     if (newp == NULL)                                   /* mem err? */
9884         return SCPE_MEM;
9885     strcpy (newp, act);                                 /* copy action */
9886     ep->act = newp;                                     /* set pointer */
9887     }
9888 /* Make sure that the production buffer is large enough to detect a match for all rules including a NUL termination byte */
9889 for (i=0; i<exp->size; i++) {
9890     size_t compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size;
9891     if (compare_size >= exp->buf_size) {
9892         exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2); /* Extra byte to null terminate regex compares */
9893         exp->buf_size = compare_size + 1;
9894         }
9895     }
9896 return SCPE_OK;
9897 }
9898 
9899 /* Show an expect rule */
9900 
9901 t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep)
     /* [previous][next][first][last][top][bottom][index][help] */
9902 {
9903 if (!ep)
9904     return SCPE_OK;
9905 (void)fprintf (st, "EXPECT");
9906 if (ep->switches & EXP_TYP_PERSIST)
9907     (void)fprintf (st, " -p");
9908 if (ep->switches & EXP_TYP_CLEARALL)
9909     (void)fprintf (st, " -c");
9910 if (ep->switches & EXP_TYP_REGEX)
9911     (void)fprintf (st, " -r");
9912 if (ep->switches & EXP_TYP_REGEX_I)
9913     (void)fprintf (st, " -i");
9914 (void)fprintf (st, " %s", ep->match_pattern);
9915 if (ep->cnt > 0)
9916     (void)fprintf (st, " [%d]", ep->cnt);
9917 if (ep->act)
9918     (void)fprintf (st, " %s", ep->act);
9919 (void)fprintf (st, "\n");
9920 return SCPE_OK;
9921 }
9922 
9923 t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
9924 {
9925 CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0);
9926 
9927 if (exp->buf_size) {
9928     char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
9929 
9930     (void)fprintf (st, "Match Buffer Size: %lld\n",
9931                    (long long)exp->buf_size);
9932     (void)fprintf (st, "Buffer Insert Offset: %lld\n",
9933                    (long long)exp->buf_ins);
9934     (void)fprintf (st, "Buffer Contents: %s\n",
9935                    bstr);
9936     FREE (bstr);
9937     }
9938 if (exp->after)
9939     (void)fprintf (st, "Halt After: %lld instructions\n",
9940                    (long long)exp->after);
9941 if (exp->dptr && exp->dbit)
9942     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\n",
9943                    sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "",
9944                    exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : "");
9945 (void)fprintf (st, "Match Rules:\n");
9946 if (!*match)
9947     return sim_exp_showall (st, exp);
9948 if (!ep) {
9949     (void)fprintf (st, "No Rules match '%s'\n", match);
9950     return SCPE_ARG;
9951     }
9952 do {
9953     sim_exp_show_tab (st, exp, ep);
9954     ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules));
9955     } while (ep);
9956 return SCPE_OK;
9957 }
9958 
9959 /* Show all expect rules */
9960 
9961 t_stat sim_exp_showall (FILE *st, const EXPECT *exp)
     /* [previous][next][first][last][top][bottom][index][help] */
9962 {
9963 size_t i;
9964 
9965 for (i=0; i < exp->size; i++)
9966     sim_exp_show_tab (st, exp, &exp->rules[i]);
9967 return SCPE_OK;
9968 }
9969 
9970 /* Test for expect match */
9971 
9972 t_stat sim_exp_check (EXPECT *exp, uint8 data)
     /* [previous][next][first][last][top][bottom][index][help] */
9973 {
9974 size_t i;
9975 EXPTAB *ep = NULL;
9976 char *tstr = NULL;
9977 #if defined(TESTING)
9978 cpu_state_t * cpup = _cpup;
9979 #endif
9980 
9981 if ((!exp) || (!exp->rules))                            /* Anything to check? */
9982     return SCPE_OK;
9983 
9984 exp->buf[exp->buf_ins++] = data;                        /* Save new data */
9985 exp->buf[exp->buf_ins] = '\0';                          /* Nul terminate for RegEx match */
9986 
9987 for (i=0; i < exp->size; i++) {
9988     ep = &exp->rules[i];
9989     if (ep == NULL)
9990         break;
9991     if (ep->switches & EXP_TYP_REGEX) {
9992         }
9993     else {
9994         if (exp->buf_ins < ep->size) {                          /* Match stradle end of buffer */
9995             /*
9996              * First compare the newly deposited data at the beginning
9997              * of buffer with the end of the match string
9998              */
9999             if (exp->buf_ins > 0) {
10000                 if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10001                     char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins);
10002                     char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins);
10003 
10004                     sim_debug (exp->dbit, exp->dptr, "Checking String[0:%lld]: %s\n",
10005                                (long long)exp->buf_ins, estr);
10006                     sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
10007                     FREE (estr);
10008                     FREE (mstr);
10009                     }
10010                 if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins))
10011                     continue;
10012                 }
10013             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10014                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins);
10015                 char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins);
10016 
10017                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\n",
10018                            (long long)exp->buf_size-(ep->size-exp->buf_ins),
10019                            (long long)ep->size-exp->buf_ins, estr);
10020                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
10021                 FREE (estr);
10022                 FREE (mstr);
10023                 }
10024             if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins))
10025                 continue;
10026             break;
10027             }
10028         else {
10029             if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) {
10030                 char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size);
10031                 char *mstr = sim_encode_quoted_string (ep->match, ep->size);
10032 
10033                 sim_debug (exp->dbit, exp->dptr, "Checking String[%lld:%lld]: %s\n",
10034                            (long long)exp->buf_ins-ep->size,
10035                            (long long)ep->size, estr);
10036                 sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr);
10037                 FREE (estr);
10038                 FREE (mstr);
10039                 }
10040             if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size))
10041                 continue;
10042             break;
10043             }
10044         }
10045     }
10046 if (exp->buf_ins == exp->buf_size) {                    /* At end of match buffer? */
10047         exp->buf_ins = 0;                               /* wrap around to beginning */
10048         sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\n");
10049     }
10050 if ((ep != NULL) && (i != exp->size)) {                 /* Found? */
10051     sim_debug (exp->dbit, exp->dptr, "Matched expect pattern!\n");
10052     if (ep->cnt > 0) {
10053         ep->cnt -= 1;
10054         sim_debug (exp->dbit, exp->dptr, "Waiting for %lld more match%s before stopping\n",
10055                    (long long)ep->cnt, (ep->cnt == 1) ? "" : "es");
10056         }
10057     else {
10058         uint32 after   = exp->after;
10059         int32 switches = ep->switches;
10060         if (ep->act && *ep->act) {
10061             sim_debug (exp->dbit, exp->dptr, "Initiating actions: %s\n", ep->act);
10062             }
10063         else {
10064             sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\n");
10065             }
10066         sim_brk_setact (ep->act);                       /* set up actions */
10067         if (ep->switches & EXP_TYP_CLEARALL)            /* Clear-all expect rule? */
10068             sim_exp_clrall (exp);                       /* delete all rules */
10069         else {
10070             if (!(ep->switches & EXP_TYP_PERSIST))      /* One shot expect rule? */
10071                 sim_exp_clr_tab (exp, ep);              /* delete it */
10072             }
10073         sim_activate (&sim_expect_unit,                 /* schedule simulation stop when indicated */
10074                       (switches & EXP_TYP_TIME) ?
10075                             (uint32)((sim_timer_inst_per_sec ()*exp->after)/1000000.0) :
10076                              after);
10077         }
10078     /* Matched data is no longer available for future matching */
10079     exp->buf_ins = 0;
10080     }
10081 if (tstr)  //-V547
10082   FREE (tstr);
10083 return SCPE_OK;
10084 }
10085 
10086 /* Queue input data for sending */
10087 
10088 t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
     /* [previous][next][first][last][top][bottom][index][help] */
10089 {
10090 if (snd->extoff != 0) {
10091     if (snd->insoff > snd->extoff)
10092         memmove(snd->buffer, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10093     snd->insoff -= snd->extoff;
10094     snd->extoff  = 0;
10095     }
10096 if (snd->insoff+size > snd->bufsize) {
10097     snd->bufsize = snd->insoff+size;
10098     snd->buffer  = (uint8 *)realloc(snd->buffer, snd->bufsize);
10099     if (!snd->buffer)
10100       {
10101         (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
10102                        __func__, __FILE__, __LINE__);
10103 #if defined(USE_BACKTRACE)
10104 # if defined(SIGUSR2)
10105         (void)raise(SIGUSR2);
10106         /*NOTREACHED*/ /* unreachable */
10107 # endif /* if defined(SIGUSR2) */
10108 #endif /* if defined(USE_BACKTRACE) */
10109         abort();
10110       }
10111     }
10112 memcpy(snd->buffer+snd->insoff, data, size);
10113 snd->insoff += size;
10114 if (delay)
10115     snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay;
10116 if (after)
10117     snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after;
10118 if (snd->after == 0)
10119     snd->after = snd->delay;
10120 snd->next_time = sim_gtime() + snd->after;
10121 return SCPE_OK;
10122 }
10123 
10124 /* Cancel Queued input data */
10125 t_stat sim_send_clear (SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10126 {
10127 snd->insoff = 0;
10128 snd->extoff = 0;
10129 return SCPE_OK;
10130 }
10131 
10132 /* Display console Queued input data status */
10133 
10134 t_stat sim_show_send_input (FILE *st, const SEND *snd)
     /* [previous][next][first][last][top][bottom][index][help] */
10135 {
10136 if (snd->extoff < snd->insoff) {
10137     (void)fprintf (st, "%lld bytes of pending input Data:\n    ",
10138                    (long long)snd->insoff-snd->extoff);
10139     fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff);
10140     (void)fprintf (st, "\n");
10141     }
10142 else
10143     (void)fprintf (st, "No Pending Input Data\n");
10144 if ((snd->next_time - sim_gtime()) > 0) {
10145     if ((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0))
10146         (void)fprintf (st, "Minimum of %d instructions (%d microseconds) before sending first character\n",
10147                        (int)(snd->next_time - sim_gtime()),
10148         (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0)));
10149     else
10150         (void)fprintf (st, "Minimum of %d instructions before sending first character\n",
10151                        (int)(snd->next_time - sim_gtime()));
10152     }
10153 if (snd->delay > (sim_timer_inst_per_sec()/1000000.0))
10154     (void)fprintf (st, "Minimum of %d instructions (%d microseconds) between characters\n",
10155                    (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
10156 else
10157     (void)fprintf (st, "Minimum of %d instructions between characters\n",
10158                    (int)snd->delay);
10159 if (snd->dptr && snd->dbit)
10160     (void)fprintf (st, "Debugging via: SET %s DEBUG%s%s\n",
10161                    sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "",
10162                    snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
10163 return SCPE_OK;
10164 }
10165 
10166 /* Poll for Queued input data */
10167 
10168 t_bool sim_send_poll_data (SEND *snd, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10169 {
10170 #if defined(TESTING)
10171 cpu_state_t * cpup = _cpup;
10172 #endif
10173 if ((NULL != snd) && (snd->extoff < snd->insoff)) {     /* pending input characters available? */
10174     if (sim_gtime() < snd->next_time) {                 /* too soon? */
10175         *stat = SCPE_OK;
10176         sim_debug (snd->dbit, snd->dptr, "Too soon to inject next byte\n");
10177         }
10178     else {
10179         char dstr[8] = "";
10180         *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;/* get one */
10181         snd->next_time = sim_gtime() + snd->delay;
10182         if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' '))
10183             (void)sprintf (dstr, " '%c'", *stat & 0xFF);
10184         sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\n", *stat & 0xFF, dstr);
10185         }
10186     return TRUE;
10187     }
10188 return FALSE;
10189 }
10190 
10191 /* Message Text */
10192 
10193 const char *sim_error_text (t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10194 {
10195 static char msgbuf[64];
10196 
10197 stat &= ~(SCPE_KFLAG|SCPE_BREAK|SCPE_NOMESSAGE);        /* remove any flags */
10198 if (stat == SCPE_OK)
10199     return "No Error";
10200 if ((stat >= SCPE_BASE) && (stat <= SCPE_MAX_ERR))
10201     return scp_errors[stat-SCPE_BASE].message;
10202 (void)sprintf(msgbuf, "Error %d", stat);
10203 return msgbuf;
10204 }
10205 
10206 t_stat sim_string_to_stat (const char *cptr, t_stat *stat)
     /* [previous][next][first][last][top][bottom][index][help] */
10207 {
10208 char gbuf[CBUFSIZE];
10209 size_t cond;
10210 
10211 *stat = SCPE_ARG;
10212 cptr = get_glyph (cptr, gbuf, 0);
10213 if (0 == memcmp("SCPE_", gbuf, 5))
10214     memmove (gbuf, gbuf + 5, 1 + strlen (gbuf + 5));  /* skip leading SCPE_ */
10215 for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
10216     if (0 == strcmp(scp_errors[cond].code, gbuf)) {
10217         cond += SCPE_BASE;
10218         break;
10219         }
10220 if (0 == strcmp(gbuf, "OK"))
10221     cond = SCPE_OK;
10222 if (cond == (SCPE_MAX_ERR-SCPE_BASE)) {       /* not found? */
10223     unsigned long numeric_cond = strtol(gbuf, NULL, 0);
10224     if (0 == numeric_cond)                    /* try explicit number */
10225         return SCPE_ARG;
10226     cond = (t_stat) numeric_cond;
10227     }
10228 if (cond > SCPE_MAX_ERR)
10229     return SCPE_ARG;
10230 *stat = cond;
10231 return SCPE_OK;
10232 }
10233 
10234 /* Debug printout routines, from Dave Hittner */
10235 
10236 const char* debug_bstates = "01_^";
10237 char debug_line_prefix[256];
10238 int32 debug_unterm  = 0;
10239 
10240 /* Finds debug phrase matching bitmask from from device DEBTAB table */
10241 
10242 static const char *get_dbg_verb (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10243 {
10244 static const char *debtab_none    = "DEBTAB_ISNULL";
10245 static const char *debtab_nomatch = "DEBTAB_NOMATCH";
10246 const char *some_match = NULL;
10247 int32 offset = 0;
10248 
10249 if (dptr->debflags == 0)
10250     return debtab_none;
10251 
10252 dbits &= dptr->dctrl;                           /* Look for just the bits that matched */
10253 
10254 /* Find matching words for bitmask */
10255 
10256 while ((offset < 32) && dptr->debflags[offset].name) {
10257     if (dptr->debflags[offset].mask == dbits)   /* All Bits Match */
10258         return dptr->debflags[offset].name;
10259     if (dptr->debflags[offset].mask & dbits)
10260         some_match = dptr->debflags[offset].name;
10261     offset++;
10262     }
10263 return some_match ? some_match : debtab_nomatch;
10264 }
10265 
10266 /* Prints standard debug prefix unless previous call unterminated */
10267 
10268 static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
10269 {
10270 const char* debug_type = get_dbg_verb (dbits, dptr);
10271 char tim_t[32] = "";
10272 char tim_a[32] = "";
10273 char  pc_s[64] = "";
10274 struct timespec time_now;
10275 
10276 if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) {
10277     clock_gettime(CLOCK_REALTIME, &time_now);
10278     if (sim_deb_switches & SWMASK ('R'))
10279         sim_timespec_diff (&time_now, &time_now, &sim_deb_basetime);
10280     if (sim_deb_switches & SWMASK ('T')) {
10281         time_t tnow = (time_t)time_now.tv_sec;
10282         struct tm *now = gmtime(&tnow);
10283         (void)sprintf(tim_t, "%02d:%02d:%02d.%03ld ",
10284                       (int)now->tm_hour,
10285                       (int)now->tm_min,
10286                       (int)now->tm_sec,
10287                       (long)(time_now.tv_nsec / 1000000));
10288         }
10289     if (sim_deb_switches & SWMASK ('A')) {
10290         (void)sprintf(tim_t, "%d.%03ld ",
10291                       (int)(time_now.tv_sec),
10292                       (long)(time_now.tv_nsec / 1000000));
10293         }
10294     }
10295 if (sim_deb_switches & SWMASK ('P')) {
10296     t_value val;
10297 
10298     if (sim_vm_pc_value)
10299         val = (*sim_vm_pc_value)();
10300     else
10301         val = get_rval (sim_PC, 0);
10302     (void)sprintf(pc_s, "-%s:", sim_PC->name);
10303     sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT);
10304     }
10305 (void)sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ",
10306               tim_t, tim_a, sim_gtime(), pc_s,
10307               "", dptr->name, debug_type);
10308 return debug_line_prefix;
10309 }
10310 
10311 void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs)
     /* [previous][next][first][last][top][bottom][index][help] */
10312 {
10313 int32 i, fields, offset;
10314 uint32 value, beforevalue, mask;
10315 
10316 for (fields=offset=0; bitdefs[fields].name; ++fields) {
10317     if (bitdefs[fields].offset == 0xffffffff)       /* fixup uninitialized offsets */
10318         bitdefs[fields].offset = offset;
10319     offset += bitdefs[fields].width;
10320     }
10321 for (i = fields-1; i >= 0; i--) {                   /* print xlation, transition */
10322     if (bitdefs[i].name[0] == '\0')
10323         continue;
10324     if ((bitdefs[i].width == 1) && (bitdefs[i].valuenames == NULL)) {
10325         int off = ((after >> bitdefs[i].offset) & 1) + (((before ^ after) >> bitdefs[i].offset) & 1) * 2;
10326         (void)Fprintf(stream, "%s%c ", bitdefs[i].name, debug_bstates[off]);
10327         }
10328     else {
10329         const char *delta = "";
10330         mask = 0xFFFFFFFF >> (32-bitdefs[i].width);
10331         value = (uint32)((after >> bitdefs[i].offset) & mask);
10332         beforevalue = (uint32)((before >> bitdefs[i].offset) & mask);
10333         if (value < beforevalue)
10334             delta = "_";
10335         if (value > beforevalue)
10336             delta = "^";
10337         if (bitdefs[i].valuenames)
10338             (void)Fprintf(stream, "%s=%s%s ", bitdefs[i].name, delta, bitdefs[i].valuenames[value]);
10339         else
10340             if (bitdefs[i].format) {
10341                 (void)Fprintf(stream, "%s=%s", bitdefs[i].name, delta);
10342                 (void)Fprintf(stream, bitdefs[i].format, value);
10343                 (void)Fprintf(stream, " ");
10344                 }
10345             else
10346                 (void)Fprintf(stream, "%s=%s0x%X ", bitdefs[i].name, delta, value);
10347         }
10348     }
10349 }
10350 
10351 /* Prints state of a register: bit translation + state (0,1,_,^)
10352    indicating the state and transition of the bit and bitfields. States:
10353    0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */
10354 
10355 void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header,
     /* [previous][next][first][last][top][bottom][index][help] */
10356     BITFIELD* bitdefs, uint32 before, uint32 after, int terminate)
10357 {
10358 if (sim_deb && dptr && (dptr->dctrl & dbits)) {
10359     if (!debug_unterm)
10360         (void)fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr));         /* print prefix if required */
10361     if (header)
10362         (void)fprintf(sim_deb, "%s: ", header);
10363     fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs); /* print xlation, transition */
10364     if (terminate)
10365         (void)fprintf(sim_deb, "\r\n");
10366     debug_unterm = terminate ? 0 : 1;                   /* set unterm for next */
10367     }
10368 }
10369 void sim_debug_bits(uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
     /* [previous][next][first][last][top][bottom][index][help] */
10370     uint32 before, uint32 after, int terminate)
10371 {
10372 sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate);
10373 }
10374 
10375 /* Print message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10376 void sim_printf (const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10377 {
10378 char stackbuf[STACKBUFSIZE];
10379 int32 bufsize = sizeof(stackbuf);
10380 char *buf = stackbuf;
10381 int32 len;
10382 va_list arglist;
10383 
10384 while (1) {                                         /* format passed string, args */
10385     va_start (arglist, fmt);
10386     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10387     va_end (arglist);
10388 
10389 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10390 
10391     if ((len < 0) || (len >= bufsize-1)) {
10392         if (buf != stackbuf)
10393             FREE (buf);
10394         if (bufsize >= (INT_MAX / 2))
10395             return;                                 /* too big */
10396         bufsize = bufsize * 2;
10397         if (bufsize < len + 2)
10398             bufsize = len + 2;
10399         buf = (char *) malloc (bufsize);
10400         if (buf == NULL)                            /* out of memory */
10401             return;
10402         buf[bufsize-1] = '\0';
10403         continue;
10404         }
10405     break;
10406     }
10407 
10408 if (sim_is_running) {
10409     char *c, *remnant = buf;
10410     while ((c = strchr(remnant, '\n'))) {
10411         if ((c != buf) && (*(c - 1) != '\r'))
10412             (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10413         else
10414             (void)printf("%.*s\n", (int)(c-remnant), remnant);
10415         remnant = c + 1;
10416         }
10417     (void)printf("%s", remnant);
10418     }
10419 else
10420     (void)printf("%s", buf);
10421 if (sim_log && (sim_log != stdout))
10422     (void)fprintf (sim_log, "%s", buf);
10423 if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
10424     (void)fprintf (sim_deb, "%s", buf);
10425 
10426 if (buf != stackbuf)
10427     FREE (buf);
10428 }
10429 
10430 /* Print command result message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
10431 t_stat sim_messagef (t_stat stat, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10432 {
10433 char stackbuf[STACKBUFSIZE];
10434 size_t bufsize = sizeof(stackbuf);
10435 char *buf = stackbuf;
10436 size_t len;
10437 va_list arglist;
10438 t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
10439 
10440 while (1) {                                         /* format passed string, args */
10441     va_start (arglist, fmt);
10442     len = vsnprintf (buf, bufsize-1, fmt, arglist);
10443     va_end (arglist);
10444 
10445 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10446 
10447     if (len >= bufsize - 1) {
10448         if (buf != stackbuf)
10449             FREE (buf);
10450         bufsize = bufsize * 2;
10451         if (bufsize < len + 2)
10452             bufsize = len + 2;
10453         buf = (char *) malloc (bufsize);
10454         if (buf == NULL)                            /* out of memory */
10455             return SCPE_MEM;
10456         buf[bufsize-1] = '\0';
10457         continue;
10458         }
10459     break;
10460     }
10461 
10462 if (sim_do_ocptr[sim_do_depth]) {
10463     if (!sim_do_echo && !sim_quiet && !inhibit_message)
10464         sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
10465     else {
10466         if (sim_deb)                        /* Always put context in debug output */
10467             (void)fprintf (sim_deb, "%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
10468         }
10469     }
10470 if (sim_is_running && !inhibit_message) {
10471     char *c, *remnant = buf;
10472     while ((c = strchr(remnant, '\n'))) {
10473         if ((c != buf) && (*(c - 1) != '\r'))
10474             (void)printf("%.*s\r\n", (int)(c-remnant), remnant);
10475         else
10476             (void)printf("%.*s\n", (int)(c-remnant), remnant);
10477         remnant = c + 1;
10478         }
10479     (void)printf("%s", remnant);
10480     }
10481 else {
10482     if (!inhibit_message)
10483         (void)printf("%s", buf);
10484     }
10485 if (sim_log && (sim_log != stdout) && !inhibit_message)
10486     (void)fprintf (sim_log, "%s", buf);
10487 if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))/* Always display messages in debug output */
10488     (void)fprintf (sim_deb, "%s", buf);
10489 
10490 if (buf != stackbuf)
10491     FREE (buf);
10492 return stat | SCPE_NOMESSAGE;
10493 }
10494 
10495 /* Inline debugging - will print debug message if debug file is
10496    set and the bitmask matches the current device debug options.
10497    Extra returns are added for un*x systems, since the output
10498    device is set into 'raw' mode when the cpu is booted,
10499    and the extra returns don't hurt any other systems.
10500    Callers should be calling sim_debug() which is a macro
10501    defined in scp.h which evaluates the action condition before
10502    incurring call overhead. */
10503 void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10504 {
10505 DEVICE *dptr = (DEVICE *)vdptr;
10506 if (sim_deb && dptr && (dbits == 0 || (dptr->dctrl & dbits))) {
10507     char stackbuf[STACKBUFSIZE];
10508     int32 bufsize = sizeof(stackbuf);
10509     char *buf = stackbuf;
10510     va_list arglist;
10511     int32 i, j, len;
10512     const char* debug_prefix = sim_debug_prefix(dbits, dptr);   /* prefix to print if required */
10513 
10514     buf[bufsize-1] = '\0';
10515     while (1) {                                         /* format passed string, args */
10516         va_start (arglist, fmt);
10517         len = vsnprintf (buf, bufsize-1, fmt, arglist);
10518         va_end (arglist);
10519 
10520 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
10521 
10522         if ((len < 0) || (len >= bufsize-1)) {
10523             if (buf != stackbuf)
10524                 FREE (buf);
10525             if (bufsize >= (INT_MAX / 2))
10526                 return;                                 /* too big */
10527             bufsize = bufsize * 2;
10528             if (bufsize < len + 2)
10529                 bufsize = len + 2;
10530             buf = (char *) malloc (bufsize);
10531             if (buf == NULL)                            /* out of memory */
10532                 return;
10533             buf[bufsize-1] = '\0';
10534             continue;
10535             }
10536         break;
10537         }
10538 
10539 /* Output the formatted data expanding newlines where they exist */
10540 
10541     for (i = j = 0; i < len; ++i) {
10542         if ('\n' == buf[i]) {
10543             if (i >= j) {
10544                 if ((i != j) || (i == 0)) {
10545                     if (debug_unterm)
10546                         (void)fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
10547                     else                                /* print prefix when required */
10548                         (void)fprintf (sim_deb, "%s%.*s\r\n", debug_prefix, i-j, &buf[j]);
10549                     }
10550                 debug_unterm = 0;
10551                 }
10552             j = i + 1;
10553             }
10554         }
10555     if (i > j) {
10556         if (debug_unterm)
10557             (void)fprintf (sim_deb, "%.*s", i-j, &buf[j]);
10558         else                                        /* print prefix when required */
10559             (void)fprintf (sim_deb, "%s%.*s", debug_prefix, i-j, &buf[j]);
10560         }
10561 
10562 /* Set unterminated flag for next time */
10563 
10564     debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm;
10565     if (buf != stackbuf)
10566         FREE (buf);
10567     }
10568 return;
10569 }
10570 
10571 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] */
10572 {
10573 #if defined(TESTING)
10574 cpu_state_t * cpup = _cpup;
10575 #endif
10576 if (sim_deb && (dptr->dctrl & reason)) {
10577     sim_debug (reason, dptr, "%s %s %slen: %08X\n", sim_uname(uptr), txt, position, (unsigned int)len);
10578     if (data && len) {
10579         size_t i, same, group, sidx, oidx, ridx, eidx, soff;
10580         char outbuf[80], strbuf[28], rad50buf[36], ebcdicbuf[32];
10581         static char hex[] = "0123456789ABCDEF";
10582         static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";
10583         static unsigned char ebcdic2ascii[] = {
10584             0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,
10585             0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,
10586             0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,
10587             0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,
10588             0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,
10589             0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,
10590             0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,
10591             0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,
10592             0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
10593             0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,
10594             0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
10595             0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,
10596             0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
10597             0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,
10598             0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
10599             0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
10600             0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
10601             0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
10602             0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
10603             0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
10604             0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
10605             0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
10606             0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
10607             0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
10608             0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
10609             0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
10610             0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
10611             0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
10612             0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
10613             0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
10614             0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
10615             0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,
10616             };
10617 
10618         for (i=same=0; i<len; i += 16) {
10619             if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) {
10620                 ++same;
10621                 continue;
10622                 }
10623             if (same > 0) {
10624                 sim_debug (reason, dptr, "%04lx thru %04lx same as above\n",
10625                            (unsigned long int)(i - (16*same)),
10626                            (unsigned long int)(i - 1));
10627                 same = 0;
10628                 }
10629             group = (((len - i) > 16) ? 16 : (len - i));
10630             strcpy (ebcdicbuf, (sim_deb_switches & SWMASK ('E')) ? " EBCDIC:" : "");
10631             eidx = strlen(ebcdicbuf);
10632             strcpy (rad50buf, (sim_deb_switches & SWMASK ('D')) ? " RAD50:" : "");
10633             ridx = strlen(rad50buf);
10634             strcpy (strbuf, (sim_deb_switches & (SWMASK ('E') | SWMASK ('D'))) ? "ASCII:" : "");
10635             soff = strlen(strbuf);
10636             for (sidx=oidx=0; sidx<group; ++sidx) {
10637                 outbuf[oidx++] = ' ';
10638                 outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf];
10639                 outbuf[oidx++] = hex[data[i+sidx]&0xf];
10640                 if (sim_isprint (data[i+sidx]))
10641                     strbuf[soff+sidx] = data[i+sidx];
10642                 else
10643                     strbuf[soff+sidx] = '.';
10644                 if (ridx && ((sidx&1) == 0)) {
10645                     uint16 word = data[i+sidx] + (((uint16)data[i+sidx+1]) << 8);
10646 
10647                     if (word >= 64000) {
10648                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10649                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10650                         rad50buf[ridx++] = '|'; /* Invalid RAD-50 character */
10651                         }
10652                     else {
10653                         rad50buf[ridx++] = rad50[word/1600];
10654                         rad50buf[ridx++] = rad50[(word/40)%40];
10655                         rad50buf[ridx++] = rad50[word%40];
10656                         }
10657                     }
10658                 if (eidx) {
10659                     if (sim_isprint (ebcdic2ascii[data[i+sidx]]))
10660                         ebcdicbuf[eidx++] = ebcdic2ascii[data[i+sidx]];
10661                     else
10662                         ebcdicbuf[eidx++] = '.';
10663                     }
10664                 }
10665             outbuf[oidx] = '\0';
10666             strbuf[soff+sidx] = '\0';
10667             ebcdicbuf[eidx] = '\0';
10668             rad50buf[ridx] = '\0';
10669             sim_debug (reason, dptr, "%04lx%-48s %s%s%s\n",
10670                     (unsigned long int)i, outbuf, strbuf, ebcdicbuf, rad50buf);
10671             }
10672         if (same > 0) {
10673             sim_debug (reason, dptr, "%04lx thru %04lx same as above\n",
10674                     (unsigned long int)(i-(16*same)),
10675                     (unsigned long int)(len-1));
10676             }
10677         }
10678     }
10679 }
10680 
10681 int Fprintf (FILE *f, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
10682 {
10683 int ret = 0;
10684 va_list args;
10685 
10686 va_start (args, fmt);
10687     ret = vfprintf (f, fmt, args);
10688 va_end (args);
10689 return ret;
10690 }
10691 
10692 /* Hierarchical help presentation
10693  *
10694  * Device help can be presented hierarchically by calling
10695  *
10696  * t_stat scp_help (FILE *st, DEVICE *dptr,
10697  *                  UNIT *uptr, int flag, const char *help, char *cptr)
10698  *
10699  * or one of its three cousins from the device HELP routine.
10700  *
10701  * *help is the pointer to the structured help text to be displayed.
10702  *
10703  * The format and usage, and some helper macros can be found in scp_help.h
10704  * If you don't use the macros, it is not necessary to #include "scp_help.h".
10705  *
10706  * Actually, if you don't specify a DEVICE pointer and don't include
10707  * other device references, it can be used for non-device help.
10708  */
10709 
10710 #define blankch(x) ((x) == ' ' || (x) == '\t')
10711 
10712 typedef struct topic {
10713     size_t         level;
10714     char          *title;
10715     char          *label;
10716     struct topic  *parent;
10717     struct topic **children;
10718     uint32         kids;
10719     char          *text;
10720     size_t         len;
10721     uint32         flags;
10722     size_t         kidwid;
10723 #define HLP_MAGIC_TOPIC  1
10724     } TOPIC;
10725 
10726 static volatile struct {
10727     const char *error;
10728     const char *prox;
10729     size_t block;
10730     size_t line;
10731     } help_where = { "", NULL, 0, 0 };
10732 jmp_buf help_env;
10733 
10734 #define FAIL(why,text,here)        \
10735   {                                \
10736     help_where.error = #text;      \
10737     help_where.prox = here;        \
10738     longjmp ( help_env, (why) );   \
10739     /*LINTED E_STMT_NOT_REACHED*/  \
10740   }
10741 
10742 /*
10743  * Add to topic text.
10744  * Expands text buffer as necessary.
10745  */
10746 
10747 static void appendText (TOPIC *topic, const char *text, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
10748 {
10749 char *newt;
10750 
10751 if (!len)
10752     return;
10753 
10754 newt = (char *)realloc (topic->text, topic->len + len +1);
10755 if (!newt) {
10756 #if !defined(SUNLINT)
10757     FAIL (SCPE_MEM, No memory, NULL);
10758 #endif /* if !defined(SUNLINT) */
10759     }
10760 topic->text = newt;
10761 memcpy (newt + topic->len, text, len);
10762 topic->len +=len;
10763 newt[topic->len] = '\0';
10764 return;
10765 }
10766 
10767 /* Release memory held by a topic and its children.
10768  */
10769 static void cleanHelp (TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
10770 {
10771 TOPIC *child;
10772 size_t i;
10773 
10774 FREE (topic->title);
10775 FREE (topic->text);
10776 FREE (topic->label);
10777 for (i = 0; i < topic->kids; i++) {
10778     child = topic->children[i];
10779     cleanHelp (child);
10780     FREE (child);
10781     }
10782 FREE (topic->children);
10783 return;
10784 }
10785 
10786 /* Build a help tree from a string.
10787  * Handles substitutions, formatting.
10788  */
10789 static TOPIC *buildHelp (TOPIC *topic, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
10790                          UNIT *uptr, const char *htext, va_list ap)
10791 {
10792 char *end;
10793 size_t n, ilvl;
10794 #define VSMAX 100
10795 char *vstrings[VSMAX];
10796 size_t vsnum = 0;
10797 char * astrings[VSMAX+1];
10798 size_t asnum = 0;
10799 char *const *hblock;
10800 const char *ep;
10801 t_bool excluded = FALSE;
10802 
10803 /* variable arguments consumed table.
10804  * The scheme used allows arguments to be accessed in random
10805  * order, but for portability, all arguments must be char *.
10806  * If you try to violate this, there ARE machines that WILL break.
10807  */
10808 
10809 (void)memset (vstrings, 0, sizeof (vstrings));
10810 (void)memset (astrings, 0, sizeof (astrings));
10811 astrings[asnum++] = (char *) htext;
10812 
10813 for (hblock = astrings; (htext = *hblock) != NULL; hblock++) {
10814     help_where.block = hblock - astrings;
10815     help_where.line = 0;
10816     while (*htext) {
10817         const char *start;
10818 
10819         help_where.line++;
10820         if (sim_isspace (*htext) || *htext == '+') {/* Topic text, indented topic text */
10821             if (excluded) {                     /* Excluded topic text */
10822                 while (*htext && *htext != '\n')
10823                     htext++;
10824                 if (*htext)
10825                     ++htext;
10826                 continue;
10827                 }
10828             ilvl = 1;
10829             appendText (topic, "    ", 4);      /* Basic indentation */
10830             if (*htext == '+') {                /* More for each + */
10831                 while (*htext == '+') {
10832                     ilvl++;
10833                     appendText (topic, "    ", 4);
10834                     htext++;
10835                     }
10836                 }
10837             while (*htext && *htext != '\n' && sim_isspace (*htext))
10838                 htext++;
10839             if (!*htext)                        /* Empty after removing leading spaces */
10840                 break;
10841             start = htext;
10842             while (*htext) {                    /* Process line for substitutions */
10843                 if (*htext == '%') {
10844                     appendText (topic, start, htext - start); /* Flush up to escape */
10845                     switch (*++htext) {         /* Evaluate escape */
10846                         case 'U':
10847                             if (dptr) {
10848                                 char buf[129];
10849                                 n = uptr? uptr - dptr->units: 0;
10850                                 (void)sprintf (buf, "%s%u", dptr->name, (int)n);
10851                                 appendText (topic, buf, strlen (buf));
10852                                 }
10853                             break;
10854                         case 'D':
10855                             if (dptr != NULL)
10856                                 appendText (topic, dptr->name, strlen (dptr->name));
10857                             break;
10858                         case 'S':
10859                             appendText (topic, sim_name, strlen (sim_name));
10860                             break;
10861                         case '%':
10862                             appendText (topic, "%", 1);
10863                             break;
10864                         case '+':
10865                             appendText (topic, "+", 1);
10866                             break;
10867                         default:                    /* Check for vararg # */
10868                             if (sim_isdigit (*htext)) {
10869                                 n = 0;
10870                                 while (sim_isdigit (*htext))
10871                                     n += (n * 10) + (*htext++ - '0');
10872                                 if (( *htext != 'H' && *htext != 's') ||
10873                                     n == 0 || n >= VSMAX) {
10874 #if !defined(SUNLINT)
10875                                     FAIL (SCPE_ARG, Invalid escape, htext);
10876 #endif /* if !defined(SUNLINT) */
10877                                     }
10878                                 while (n > vsnum)   /* Get arg pointer if not cached */
10879                                     vstrings[vsnum++] = va_arg (ap, char *);
10880                                 start = vstrings[n-1]; /* Insert selected string */
10881                                 if (*htext == 'H') {   /* Append as more input */
10882                                     if (asnum >= VSMAX) {
10883 #if !defined(SUNLINT)
10884                                         FAIL (SCPE_ARG, Too many blocks, htext);
10885 #endif /* if !defined(SUNLINT) */
10886                                         }
10887                                     astrings[asnum++] = (char *)start;
10888                                     break;
10889                                     }
10890                                 ep = start;
10891                                 while (*ep) {
10892                                     if (*ep == '\n') {
10893                                         ep++;       /* Segment to \n */
10894                                         appendText (topic, start, ep - start);
10895                                         if (*ep) {  /* More past \n, indent */
10896                                             size_t i;
10897                                             for (i = 0; i < ilvl; i++)
10898                                                 appendText (topic, "    ", 4);
10899                                             }
10900                                         start = ep;
10901                                         }
10902                                     else
10903                                         ep++;
10904                                     }
10905                                 appendText (topic, start, ep-start);
10906                                 break;
10907                                 }
10908 #if !defined(SUNLINT)
10909                             FAIL (SCPE_ARG, Invalid escape, htext);
10910 #endif /* if !defined(SUNLINT) */
10911                         } /* switch (escape) */
10912                     start = ++htext;
10913                     continue;                   /* Current line */
10914                     } /* if (escape) */
10915                 if (*htext == '\n') {           /* End of line, append last segment */
10916                     htext++;
10917                     appendText (topic, start, htext - start);
10918                     break;                      /* To next line */
10919                     }
10920                 htext++;                        /* Regular character */
10921                 }
10922             continue;
10923             } /* topic text line */
10924         if (sim_isdigit (*htext)) {             /* Topic heading */
10925             TOPIC **children;
10926             TOPIC *newt;
10927             char nbuf[100];
10928 
10929             n = 0;
10930             start = htext;
10931             while (sim_isdigit (*htext))
10932                 n += (n * 10) + (*htext++ - '0');
10933             if ((htext == start) || !n) {
10934 #if !defined(SUNLINT)
10935                 FAIL (SCPE_ARG, Invalid topic heading, htext);
10936 #endif /* if !defined(SUNLINT) */
10937                 }
10938             if (n <= topic->level) {            /* Find level for new topic */
10939                 while (n <= topic->level)
10940                     topic = topic->parent;
10941                 }
10942             else {
10943                 if (n > topic->level + 1) {     /* Skipping down more than 1 */
10944 #if !defined(SUNLINT)
10945                     FAIL (SCPE_ARG, Level not contiguous, htext); /* E.g. 1 3, not reasonable */
10946 #endif /* if !defined(SUNLINT) */
10947                     }
10948                 }
10949             while (*htext && (*htext != '\n') && sim_isspace (*htext))
10950                 htext++;
10951             if (!*htext || (*htext == '\n')) {  /* Name missing */
10952 #if !defined(SUNLINT)
10953                 FAIL (SCPE_ARG, Missing topic name, htext);
10954 #endif /* if !defined(SUNLINT) */
10955                 }
10956             start = htext;
10957             while (*htext && (*htext != '\n'))
10958                 htext++;
10959             if (start == htext) {               /* Name NULL */
10960 #if !defined(SUNLINT)
10961                 FAIL (SCPE_ARG, Null topic name, htext);
10962 #endif /* if !defined(SUNLINT) */
10963                 }
10964             excluded = FALSE;
10965             if (*start == '?') {                /* Conditional topic? */
10966                 size_t n = 0;
10967                 start++;
10968                 while (sim_isdigit (*start))    /* Get param # */
10969                     n += (n * 10) + (*start++ - '0');
10970                 if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) {
10971 #if !defined(SUNLINT)
10972                     FAIL (SCPE_ARG, Invalid parameter number, start);
10973 #endif /* if !defined(SUNLINT) */
10974                     }
10975                 while (n > vsnum)               /* Get arg pointer if not cached */
10976                     vstrings[vsnum++] = va_arg (ap, char *);
10977                 end = vstrings[n-1];            /* Check for True */
10978                 if (!end || !(toupper (*end) == 'T' || *end == '1')) {
10979                     excluded = TRUE;            /* False, skip topic this time */
10980                     if (*htext)
10981                         htext++;
10982                     continue;
10983                     }
10984                 }
10985             newt = (TOPIC *) calloc (sizeof (TOPIC), 1);
10986             if (!newt) {
10987 #if !defined(SUNLINT)
10988                 FAIL (SCPE_MEM, No memory, NULL);
10989 #endif /* if !defined(SUNLINT) */
10990                 }
10991             newt->title = (char *) malloc ((htext - start)+1);
10992             if (!newt->title) {
10993                 FREE (newt);
10994 #if !defined(SUNLINT)
10995                 FAIL (SCPE_MEM, No memory, NULL);
10996 #endif /* if !defined(SUNLINT) */
10997                 }
10998             memcpy (newt->title, start, htext - start);
10999             newt->title[htext - start] = '\0';
11000             if (*htext)
11001                 htext++;
11002 
11003             if (newt->title[0] == '$')
11004                 newt->flags |= HLP_MAGIC_TOPIC;
11005 
11006             children = (TOPIC **) realloc (topic->children,
11007                                            (topic->kids +1) * sizeof (TOPIC *));
11008             if (NULL == children) {
11009                 FREE (newt->title);
11010                 FREE (newt);
11011 #if !defined(SUNLINT)
11012                 FAIL (SCPE_MEM, No memory, NULL);
11013 #endif /* if !defined(SUNLINT) */
11014                 }
11015             topic->children = children;
11016             topic->children[topic->kids++] = newt;
11017             newt->level = n;
11018             newt->parent = topic;
11019             n = strlen (newt->title);
11020             if (n > topic->kidwid)
11021                 topic->kidwid = n;
11022             (void)sprintf (nbuf, ".%u", topic->kids);
11023             n = strlen (topic->label) + strlen (nbuf) + 1;
11024             newt->label = (char *) malloc (n);
11025             if (NULL == newt->label) {
11026                 FREE (newt->title);
11027                 topic->children[topic->kids -1] = NULL;
11028                 FREE (newt);
11029 #if !defined(SUNLINT)
11030                 FAIL (SCPE_MEM, No memory, NULL);
11031 #endif /* if !defined(SUNLINT) */
11032                 }
11033             (void)sprintf (newt->label, "%s%s", topic->label, nbuf);
11034             topic = newt;
11035             continue;
11036             } /* digits introducing a topic */
11037         if (*htext == ';') {                    /* Comment */
11038             while (*htext && *htext != '\n')
11039                 htext++;
11040             continue;
11041             }
11042 #if !defined(SUNLINT)
11043         FAIL (SCPE_ARG, Unknown line type, htext);     /* Unknown line */
11044 #endif /* if !defined(SUNLINT) */
11045         } /* htext not at end */
11046     (void)memset (vstrings, 0, VSMAX * sizeof (char *));
11047     vsnum = 0;
11048     } /* all strings */
11049 
11050 return topic;
11051 }
11052 
11053 /*
11054  * Create prompt string - top thru current topic
11055  * Add prompt at end.
11056  */
11057 static char *helpPrompt ( TOPIC *topic, const char *pstring, t_bool oneword )
     /* [previous][next][first][last][top][bottom][index][help] */
11058 {
11059 char *prefix;
11060 char *newp, *newt;
11061 
11062 if (topic->level == 0) {
11063     prefix = (char *) calloc (2,1);
11064     if (!prefix) {
11065 #if !defined(SUNLINT)
11066         FAIL (SCPE_MEM, No memory, NULL);
11067 #endif /* if !defined(SUNLINT) */
11068         }
11069     prefix[0] = '\n';
11070     }
11071 else
11072     prefix = helpPrompt (topic->parent, "", oneword);
11073 
11074 newp = (char *) malloc (strlen (prefix) + 1 + strlen (topic->title) + 1 +
11075                         strlen (pstring) +1);
11076 if (!newp) {
11077     FREE (prefix);
11078 #if !defined(SUNLINT)
11079     FAIL (SCPE_MEM, No memory, NULL);
11080 #endif /* if !defined(SUNLINT) */
11081     }
11082 strcpy (newp, prefix);
11083 if (topic->children) {
11084     if (topic->level != 0)
11085         strcat (newp, " ");
11086     newt = (topic->flags & HLP_MAGIC_TOPIC)?
11087             topic->title+1: topic->title;
11088     if (oneword) {
11089         char *np = newp + strlen (newp);
11090         while (*newt) {
11091             *np++ = blankch (*newt)? '_' : *newt;
11092             newt++;
11093             }
11094         *np = '\0';
11095         }
11096     else
11097         strcat (newp, newt);
11098     if (*pstring && *pstring != '?')
11099         strcat (newp, " ");
11100     }
11101 strcat (newp, pstring);
11102 FREE (prefix);
11103 return newp;
11104 }
11105 
11106 static void displayMagicTopic (FILE *st, DEVICE *dptr, TOPIC *topic)
     /* [previous][next][first][last][top][bottom][index][help] */
11107 {
11108 char tbuf[CBUFSIZE];
11109 size_t i, skiplines;
11110 #if defined(_WIN32)
11111 FILE *tmp;
11112 char *tmpnam;
11113 
11114 do {
11115     int fd;
11116     tmpnam = _tempnam (NULL, "simh");
11117     fd = _open (tmpnam, _O_CREAT | _O_RDWR | _O_EXCL, _S_IREAD | _S_IWRITE);
11118     if (fd != -1) {
11119         tmp = _fdopen (fd, "w+");
11120         break;
11121         }
11122     } while (1);
11123 #else
11124 FILE *tmp = tmpfile();
11125 #endif /* if defined(_WIN32) */
11126 
11127 if (!tmp) {
11128     (void)fprintf (st, "Unable to create temporary file: %s (Error %d)\n",
11129                    xstrerror_l(errno), errno);
11130     return;
11131     }
11132 
11133 if (topic->title)
11134     (void)fprintf (st, "%s\n", topic->title+1);
11135 
11136 skiplines = 0;
11137 if (topic->title) {
11138   if (!strcmp (topic->title+1, "Registers")) {
11139       fprint_reg_help (tmp, dptr) ;
11140       skiplines = 1;
11141       }
11142   else
11143       if (!strcmp (topic->title+1, "Set commands")) {
11144           fprint_set_help (tmp, dptr);
11145           skiplines = 3;
11146           }
11147       else
11148           if (!strcmp (topic->title+1, "Show commands")) {
11149               fprint_show_help (tmp, dptr);
11150               skiplines = 3;
11151               }
11152   }
11153 rewind (tmp);
11154 if (errno) {
11155     (void)fprintf (st, "rewind: error %d\r\n", errno);
11156 }
11157 
11158 /* Discard leading blank lines/redundant titles */
11159 
11160 for (i =0; i < skiplines; i++)
11161     if (fgets (tbuf, sizeof (tbuf), tmp)) {};
11162 
11163 while (fgets (tbuf, sizeof (tbuf), tmp)) {
11164     if (tbuf[0] != '\n')
11165         fputs ("    ", st);
11166     fputs (tbuf, st);
11167     }
11168 fclose (tmp);
11169 #if defined(_WIN32)
11170 remove (tmpnam);
11171 FREE (tmpnam);
11172 #endif /* if defined(_WIN32) */
11173 return;
11174 }
11175 /* Flatten and display help for those who say they prefer it. */
11176 
11177 static t_stat displayFlatHelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11178                                UNIT *uptr, int32 flag,
11179                                TOPIC *topic, va_list ap )
11180 {
11181 size_t i;
11182 
11183 if (topic->flags & HLP_MAGIC_TOPIC) {
11184     (void)fprintf (st, "\n%s ", topic->label);
11185     displayMagicTopic (st, dptr, topic);
11186     }
11187 else
11188     (void)fprintf (st, "\n%s %s\n", topic->label, topic->title);
11189 
11190 /*
11191  * Topic text (for magic topics, follows for explanations)
11192  * It's possible/reasonable for a magic topic to have no text.
11193  */
11194 
11195 if (topic->text)
11196     fputs (topic->text, st);
11197 
11198 for (i = 0; i < topic->kids; i++)
11199     displayFlatHelp (st, dptr, uptr, flag, topic->children[i], ap);
11200 
11201 return SCPE_OK;
11202 }
11203 
11204 #define HLP_MATCH_AMBIGUOUS (~0u)
11205 #define HLP_MATCH_WILDCARD  (~1U)
11206 #define HLP_MATCH_NONE      0
11207 static size_t matchHelpTopicName (TOPIC *topic, const char *token)
     /* [previous][next][first][last][top][bottom][index][help] */
11208 {
11209 size_t i, match;
11210 char cbuf[CBUFSIZE], *cptr;
11211 
11212 if (!strcmp (token, "*"))
11213     return HLP_MATCH_WILDCARD;
11214 
11215 match = 0;
11216 for (i = 0; i < topic->kids; i++) {
11217     strcpy (cbuf,topic->children[i]->title +
11218             ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11219     cptr = cbuf;
11220     while (*cptr) {
11221         if (blankch (*cptr)) {
11222             *cptr++ = '_';
11223             }
11224         else {
11225             *cptr = (char)toupper (*cptr);
11226             cptr++;
11227             }
11228         }
11229     if (!strcmp (cbuf, token))      /* Exact Match */
11230         return i+1;
11231     if (!strncmp (cbuf, token, strlen (token))) {
11232         if (match)
11233             return HLP_MATCH_AMBIGUOUS;
11234         match = i+1;
11235         }
11236     }
11237 return match;
11238 }
11239 
11240 /* Main help routine */
11241 
11242 t_stat scp_vhelp (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11243                   UNIT *uptr, int32 flag,
11244                   const char *help, const char *cptr, va_list ap)
11245 {
11246 TOPIC top;
11247 TOPIC *topic = &top;
11248 int failed;
11249 size_t match;
11250 size_t i;
11251 const char *p;
11252 t_bool flat_help = FALSE;
11253 char cbuf [CBUFSIZE], gbuf[CBUFSIZE];
11254 
11255 static const char attach_help[] = { " ATTACH" };
11256 static const char  brief_help[] = { "%s help.  Type <CR> to exit, HELP for navigation help.\n" };
11257 static const char onecmd_help[] = { "%s help.\n" };
11258 static const char   help_help[] = {
11259     /****|***********************80 column width guide********************************/
11260     "    To see more HELP information, type the listed subtopic name.  To move\n"
11261     "    up a level, just type <CR>.  To review the current subtopic, type \"?\".\n"
11262     "    To view all subtopics, type \"*\".  To exit type \"EXIT\", \"^C\", or \"^D\".\n\n"
11263     };
11264 
11265 (void)memset (&top, 0, sizeof(top));
11266 top.parent = &top;
11267 if ((failed = setjmp (help_env)) != 0) {
11268     (void)fprintf (stderr, "\nHELP was unable to process HELP for this device.\n"
11269                            "Error in block %u line %u: %s\n"
11270                            "%s%*.*s%s\n",
11271                    (int)help_where.block, (int)help_where.line, help_where.error,
11272                    help_where.prox ? "Near '" : "",
11273                    help_where.prox ? 15 : 0, help_where.prox ? 15 : 0,
11274                    help_where.prox ? help_where.prox : "",
11275                    help_where.prox ? "'" : "");
11276     cleanHelp (&top);
11277     return failed;
11278     }
11279 
11280 /* Compile string into navigation tree */
11281 
11282 /* Root */
11283 
11284 if (dptr) {
11285     p = dptr->name;
11286     flat_help = (dptr->flags & DEV_FLATHELP) != 0;
11287     }
11288 else
11289     p = sim_name;
11290 top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1);
11291 if (!top.title)
11292   {
11293     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11294                    __func__, __FILE__, __LINE__);
11295 #if defined(USE_BACKTRACE)
11296 # if defined(SIGUSR2)
11297     (void)raise(SIGUSR2);
11298     /*NOTREACHED*/ /* unreachable */
11299 # endif /* if defined(SIGUSR2) */
11300 #endif /* if defined(USE_BACKTRACE) */
11301     abort();
11302   }
11303 for (i = 0; p[i]; i++ )
11304     top.title[i] = (char)toupper (p[i]);
11305 top.title[i] = '\0';
11306 if (flag & SCP_HELP_ATTACH)
11307     strcpy (top.title+i, attach_help);
11308 
11309 top.label = (char *) malloc (sizeof ("1"));
11310 if (!top.label)
11311   {
11312     (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
11313                    __func__, __FILE__, __LINE__);
11314 #if defined(USE_BACKTRACE)
11315 # if defined(SIGUSR2)
11316     (void)raise(SIGUSR2);
11317     /*NOTREACHED*/ /* unreachable */
11318 # endif /* if defined(SIGUSR2) */
11319 #endif /* if defined(USE_BACKTRACE) */
11320     abort();
11321   }
11322 strcpy (top.label, "1");
11323 
11324 flat_help = flat_help || !sim_ttisatty() || (flag & SCP_HELP_FLAT);
11325 
11326 if (flat_help) {
11327     flag |= SCP_HELP_FLAT;
11328     if (sim_ttisatty())
11329         (void)fprintf (st, "%s help.\nThis help is also available in hierarchical form.\n", top.title);
11330     else
11331         (void)fprintf (st, "%s help.\n", top.title);
11332     }
11333 else
11334     (void)fprintf (st, ((flag & SCP_HELP_ONECMD)? onecmd_help: brief_help), top.title);
11335 
11336 /* Add text and subtopics */
11337 
11338 (void) buildHelp (&top, dptr, uptr, help, ap);
11339 
11340 /* Go to initial topic if provided */
11341 
11342 while (cptr && *cptr) {
11343     cptr = get_glyph (cptr, gbuf, 0);
11344     if (!gbuf[0])
11345         break;
11346     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11347         (void)fprintf (st, "\n");
11348         fputs (help_help, st);
11349         break;
11350         }
11351     match =  matchHelpTopicName (topic, gbuf);
11352     if (match == HLP_MATCH_WILDCARD) {
11353         if (dptr)
11354             displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11355         cleanHelp (&top);
11356         return SCPE_OK;
11357         }
11358     if (match == HLP_MATCH_AMBIGUOUS) {
11359         (void)fprintf (st, "\n%s is ambiguous in %s\n", gbuf, topic->title);
11360         break;
11361         }
11362     if (match == HLP_MATCH_NONE) {
11363         (void)fprintf (st, "\n%s is not available in %s\n", gbuf, topic->title);
11364         break;
11365         }
11366     topic = topic->children[match-1];
11367     }
11368 cptr = NULL;
11369 
11370 if (flat_help) {
11371     displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11372     cleanHelp (&top);
11373     return SCPE_OK;
11374     }
11375 
11376 /* Interactive loop displaying help */
11377 
11378 while (TRUE) {
11379     char *pstring;
11380     const char *prompt[2] = {"? ", "Subtopic? "};
11381 
11382     /* Some magic topic names for help from data structures */
11383 
11384     if (topic->flags & HLP_MAGIC_TOPIC) {
11385         fputc ('\n', st);
11386         displayMagicTopic (st, dptr, topic);
11387         }
11388     else
11389         (void)fprintf (st, "\n%s\n", topic->title);
11390 
11391     /* Topic text (for magic topics, follows for explanations)
11392      * It's possible/reasonable for a magic topic to have no text.
11393      */
11394 
11395     if (topic->text)
11396         fputs (topic->text, st);
11397 
11398     if (topic->kids) {
11399         size_t w = 0;
11400         char *p;
11401         char tbuf[CBUFSIZE];
11402 
11403         (void)fprintf (st, "\n    Additional information available:\n\n");
11404         for (i = 0; i < topic->kids; i++) {
11405             strcpy (tbuf, topic->children[i]->title +
11406                     ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0));
11407             for (p = tbuf; *p; p++) {
11408                 if (blankch (*p))
11409                     *p = '_';
11410                 }
11411             w += 4 + topic->kidwid;
11412             if (w > 80) {
11413                 w = 4 + topic->kidwid;
11414                 fputc ('\n', st);
11415                 }
11416             (void)fprintf (st, "    %-*s", (int32_t)topic->kidwid, tbuf);
11417             }
11418         (void)fprintf (st, "\n\n");
11419         if (flag & SCP_HELP_ONECMD) {
11420             pstring = helpPrompt (topic, "", TRUE);
11421             (void)fprintf (st, "To view additional topics, type HELP %s topicname\n", pstring+1);
11422             FREE (pstring);
11423             break;
11424             }
11425         }
11426 
11427     if (!sim_ttisatty() || (flag & SCP_HELP_ONECMD))
11428         break;
11429 
11430   reprompt:
11431     if (NULL == cptr || !*cptr) {
11432         if (topic->kids == 0)
11433             topic = topic->parent;
11434         pstring = helpPrompt (topic, prompt[topic->kids != 0], FALSE);
11435 
11436         cptr = read_line_p (pstring+1, cbuf, sizeof (cbuf), stdin);
11437         FREE (pstring);
11438         if ((cptr != NULL) &&                   /* Got something? */
11439             ((0 == strcmp (cptr, "\x04")) ||    /* was it a bare ^D? */
11440              (0 == strcmp (cptr, "\x1A"))))     /* was it a bare ^Z? */
11441             cptr = NULL;                        /* These are EOF synonyms */
11442         }
11443 
11444     if (NULL == cptr)                           /* EOF, exit help */
11445         break;
11446 
11447     cptr = get_glyph (cptr, gbuf, 0);
11448     if (!strcmp (gbuf, "*")) {              /* Wildcard */
11449         displayFlatHelp (st, dptr, uptr, flag, topic, ap);
11450         gbuf[0] = '\0';                     /* Displayed all subtopics, go up */
11451         }
11452     if (!gbuf[0]) {                         /* Blank, up a level */
11453         if (topic->level == 0)
11454             break;
11455         topic = topic->parent;
11456         continue;
11457         }
11458     if (!strcmp (gbuf, "?"))                /* ?, repaint current topic */
11459         continue;
11460     if (!strcmp (gbuf, "HELP")) {           /* HELP (about help) */
11461         fputs (help_help, st);
11462         goto reprompt;
11463         }
11464     if (!strcmp (gbuf, "EXIT") || !strcmp (gbuf, "QUIT"))   /* EXIT (help) */
11465         break;
11466 
11467     /* String - look for that topic */
11468 
11469     if (!topic->kids) {
11470         (void)fprintf (st, "No additional help at this level.\n");
11471         cptr = NULL;
11472         goto reprompt;
11473         }
11474     match = matchHelpTopicName (topic, gbuf);
11475     if (match == HLP_MATCH_AMBIGUOUS) {
11476         (void)fprintf (st, "%s is ambiguous, please type more of the topic name\n", gbuf);
11477         cptr = NULL;
11478         goto reprompt;
11479         }
11480 
11481     if (match == HLP_MATCH_NONE) {
11482         (void)fprintf (st, "Help for %s is not available\n", gbuf);
11483         cptr = NULL;
11484         goto reprompt;
11485         }
11486     /* Found, display subtopic */
11487 
11488     topic = topic->children[match-1];
11489     }
11490 
11491 /* Free structures and return */
11492 
11493 cleanHelp (&top);
11494 
11495 return SCPE_OK;
11496 }
11497 
11498 /* variable argument list shell - most commonly used */
11499 
11500 t_stat scp_help (FILE *st, DEVICE *dptr,
     /* [previous][next][first][last][top][bottom][index][help] */
11501                  UNIT *uptr, int32 flag,
11502                  const char *help, const char *cptr, ...)
11503 {
11504 t_stat r;
11505 va_list ap;
11506 
11507 va_start (ap, cptr);
11508 r = scp_vhelp (st, dptr, uptr, flag, help, cptr, ap);
11509 va_end (ap);
11510 
11511 return r;
11512 }
11513 
11514 #if defined(_MSC_VER)
11515 # pragma warning(pop)
11516 #endif

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