root/src/dps8/dps8_prt.c

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

DEFINITIONS

This source file includes following definitions.
  1. prt_init
  2. prt_reset
  3. gc
  4. parseID
  5. buffered_write
  6. openPrtFile
  7. eoj
  8. print_buf
  9. loadImageBuffer
  10. readStatusRegister
  11. loadVFCImage
  12. print_cmd
  13. prt_cmd_202
  14. prt_cmd_300
  15. prt_cmd_300a
  16. prt_cmd_400
  17. prt_iom_cmd
  18. prt_show_nunits
  19. prt_set_nunits
  20. prt_show_device_name
  21. prt_set_device_model
  22. prt_show_device_model
  23. prt_set_device_name
  24. prt_show_path
  25. prt_set_path
  26. burst_printer
  27. signal_prt_ready
  28. prt_set_ready
  29. prt_set_config
  30. prt_show_config

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * SPDX-License-Identifier: Multics
   5  * scspell-id: cb56e6b9-f62e-11ec-8a20-80ee73e9b8e7
   6  *
   7  * ---------------------------------------------------------------------------
   8  *
   9  * Copyright (c) 2007-2013 Michael Mondy
  10  * Copyright (c) 2012-2016 Harry Reed
  11  * Copyright (c) 2013-2016 Charles Anthony
  12  * Copyright (c) 2020-2021 Dean Anderson
  13  * Copyright (c) 2021-2025 The DPS8M Development Team
  14  *
  15  * This software is made available under the terms of the ICU License.
  16  * See the LICENSE.md file at the top-level directory of this distribution.
  17  *
  18  * ---------------------------------------------------------------------------
  19  *
  20  * This source file may contain code comments that adapt, include, and/or
  21  * incorporate Multics program code and/or documentation distributed under
  22  * the Multics License.  In the event of any discrepancy between code
  23  * comments herein and the original Multics materials, the original Multics
  24  * materials should be considered authoritative unless otherwise noted.
  25  * For more details and historical background, see the LICENSE.md file at
  26  * the top-level directory of this distribution.
  27  *
  28  * ---------------------------------------------------------------------------
  29  */
  30 
  31 #include <stdio.h>
  32 #include <ctype.h>
  33 #include <unistd.h>
  34 #include <stdlib.h>
  35 #include <sys/stat.h>
  36 
  37 #include "dps8.h"
  38 #include "dps8_iom.h"
  39 #include "dps8_prt.h"
  40 #include "dps8_sys.h"
  41 #include "dps8_cable.h"
  42 #include "dps8_cpu.h"
  43 #include "dps8_faults.h"
  44 #include "dps8_scu.h"
  45 #include "dps8_utils.h"
  46 
  47 #if defined(__MINGW64__) || defined(__MINGW32__)
  48 # include "bsd_random.h"
  49 # define random  bsd_random
  50 # define srandom bsd_srandom
  51 #endif /* if defined(__MINGW64__) || defined(__MINGW32__) */
  52 
  53 #if defined(FREE)
  54 # undef FREE
  55 #endif /* if defined(FREE) */
  56 #define FREE(p)   \
  57   do              \
  58     {             \
  59       free ((p)); \
  60       (p) = NULL; \
  61     }             \
  62   while (0)
  63 
  64 #include "utfile.h"
  65 #include "safemove.h"
  66 
  67 #if defined(NO_LOCALE)
  68 # define xstrerror_l strerror
  69 #endif
  70 
  71 #define DBG_CTR 1
  72 
  73 //-- // XXX We use this where we assume there is only one unit
  74 //-- #define ASSUME0 0
  75 //--
  76 
  77 // printer_types.incl.pl1
  78 //
  79 // dcl  models (13) fixed bin /* table of printer model numbers */
  80 //     (202, 300, 301, 302, 303, 304, 401, 402, 901, 1000, 1200, 1201, 1600);
  81 //
  82 // dcl  types (13) fixed bin /* table of corresponding printer types */
  83 //    (  1,   2,   2,   2,   3,   3,   4,   4,   4,    4,    4,    4,    4);
  84 //
  85 // dcl  WRITE (4) bit (6) /* printer write edited commands */
  86 //     ("011000"b, "011000"b, "011100"b, "011100"b);
  87 //
  88 // dcl  WRITE_NE_SLEW (4) bit (6) /* printer write non-edited commands */
  89 //     ("001001"b, "001001"b, "001101"b, "001101"b);
  90 //
  91 // dcl  LOAD_IMAGE (4) bit (6) /* printer load image buffer commands */
  92 //     ("000000"b, "001100"b, "000001"b, "000001"b);
  93 //
  94 // dcl  LOAD_VFC (4) bit (6) /* printer load VFC image commands */
  95 //     ("000000"b, "000000"b, "000000"b, "000101"b);
  96 //
  97 // dcl  READ_STATUS (4) bit (6) /* printer read detailed status command */
  98 //     ("000000"b, "000000"b, "000000"b, "000011"b);
  99 
 100 // AN87 only defines commands for
 101 //   PRT203/303, PRU1200/1600
 102 // and
 103 //   PRT202/300
 104 
 105 #define N_PRT_UNITS 1 // default
 106 
 107 static t_stat prt_reset (DEVICE * dptr);
 108 static t_stat prt_show_nunits (FILE *st, UNIT *uptr, int val, const void *desc);
 109 static t_stat prt_set_nunits (UNIT * uptr, int32 value, const char * cptr, void * desc);
 110 static t_stat prt_show_device_name (FILE *st, UNIT *uptr, int val, const void *desc);
 111 static t_stat prt_set_device_name (UNIT * uptr, int32 value, const char * cptr, void * desc);
 112 static t_stat prt_set_config (UNUSED UNIT *  uptr, UNUSED int32 value,
 113                               const char * cptr, UNUSED void * desc);
 114 static t_stat prt_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
 115                                UNUSED int  val, UNUSED const void * desc);
 116 static t_stat prt_show_path (UNUSED FILE * st, UNIT * uptr,
 117                                        UNUSED int val, UNUSED const void * desc);
 118 static t_stat prt_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
 119                                     const UNUSED char * cptr, UNUSED void * desc);
 120 static t_stat prt_set_ready (UNIT * uptr, UNUSED int32 value,
 121                              UNUSED const char * cptr,
 122                              UNUSED void * desc);
 123 
 124 static t_stat prt_show_device_model (FILE *st, UNIT *uptr, int val, const void *desc);
 125 static t_stat prt_set_device_model (UNIT * uptr, int32 value, const char * cptr, void * desc);
 126 
 127 #define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
 128                      UNIT_IDLE )
 129 UNIT prt_unit[N_PRT_UNITS_MAX] =
 130   {
 131     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 132     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 133     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 134     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 135     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 136     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 137     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 138     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 139     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 140     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 141     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 142     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 143     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 144     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 145     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 146     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 147     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 148     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 149     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 150     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 151     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 152     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 153     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 154     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 155     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 156     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 157     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 158     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 159     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 160     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 161     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 162     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 163     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 164     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}
 165   };
 166 
 167 #define PRT_UNIT_NUM(uptr) ((uptr) - prt_unit)
 168 
 169 static DEBTAB prt_dt[] =
 170   {
 171     { "NOTIFY", DBG_NOTIFY, NULL },
 172     { "INFO",   DBG_INFO,   NULL },
 173     { "ERR",    DBG_ERR,    NULL },
 174     { "WARN",   DBG_WARN,   NULL },
 175     { "DEBUG",  DBG_DEBUG,  NULL },
 176     { "ALL",    DBG_ALL,    NULL }, /* Don't move as it messes up DBG message */
 177     { NULL,     0,          NULL }
 178   };
 179 
 180 #define UNIT_WATCH UNIT_V_UF
 181 
 182 static MTAB prt_mod[] =
 183   {
 184 #if !defined(SPEED)
 185     { UNIT_WATCH, 1, "WATCH",   "WATCH",   0, 0, NULL, NULL },
 186     { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
 187 #endif /* if !defined(SPEED) */
 188     {
 189       MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR, /* Mask               */
 190       0,                                          /* Match              */
 191       "NUNITS",                                   /* Print string       */
 192       "NUNITS",                                   /* Match string       */
 193       prt_set_nunits,                             /* Validation routine */
 194       prt_show_nunits,                            /* Display routine    */
 195       "Number of PRT units in the system",        /* Value descriptor   */
 196       NULL                                        /* Help               */
 197     },
 198     {
 199       MTAB_XTD | MTAB_VDV  | MTAB_NMO | \
 200                  MTAB_VALR | MTAB_NC,             /* Mask               */
 201       0,                                          /* Match              */
 202       "PATH",                                     /* Print string       */
 203       "PATH",                                     /* Match string       */
 204       prt_set_path,                               /* Validation routine */
 205       prt_show_path,                              /* Display routine    */
 206       "Path to write PRT files",                  /* Value descriptor   */
 207       NULL                                        /* Help               */
 208     },
 209     {
 210       MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,  /* Mask               */
 211       0,                                          /* Match              */
 212       "NAME",                                     /* Print string       */
 213       "NAME",                                     /* Match string       */
 214       prt_set_device_name,                        /* Validation routine */
 215       prt_show_device_name,                       /* Display routine    */
 216       "Select the printer name",                  /* Value descriptor   */
 217       NULL                                        /* Help               */
 218     },
 219 
 220     {
 221       MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,  /* Mask               */
 222       0,                                          /* Match              */
 223       "MODEL",                                    /* Print string       */
 224       "MODEL",                                    /* Match string       */
 225       prt_set_device_model,                       /* Validation routine */
 226       prt_show_device_model,                      /* Display routine    */
 227       "Select the printer model",                 /* Value descriptor   */
 228       NULL                                        /* Help               */
 229     },
 230     {
 231       MTAB_XTD | MTAB_VUN,                        /* Mask               */
 232       0,                                          /* Match              */
 233       (char *) "CONFIG",                          /* Print string       */
 234       (char *) "CONFIG",                          /* Match string       */
 235       prt_set_config,                             /* Validation routine */
 236       prt_show_config,                            /* Display routine    */
 237       NULL,                                       /* Value descriptor   */
 238       NULL,                                       /* Help               */
 239     },
 240     {
 241       MTAB_XTD | MTAB_VUN | MTAB_NMO | MTAB_VALR, /* Mask               */
 242       0,                                          /* Match              */
 243       "READY",                                    /* Print string       */
 244       "READY",                                    /* Match string       */
 245       prt_set_ready,                              /* Validation routine */
 246       NULL,                                       /* Display routine    */
 247       NULL,                                       /* Value descriptor   */
 248       NULL                                        /* Help               */
 249     },
 250     { 0, 0, NULL, NULL, 0, 0, NULL, NULL }
 251   };
 252 
 253 DEVICE prt_dev = {
 254     "PRT",        /* Name                */
 255     prt_unit,     /* Unit                */
 256     NULL,         /* Registers           */
 257     prt_mod,      /* Modifiers           */
 258     N_PRT_UNITS,  /* Number of units     */
 259     10,           /* Address radix       */
 260     24,           /* Address width       */
 261     1,            /* Address increment   */
 262     8,            /* Data radix          */
 263     36,           /* Data width          */
 264     NULL,         /* Examine             */
 265     NULL,         /* Deposit             */
 266     prt_reset,    /* Reset               */
 267     NULL,         /* Boot                */
 268     NULL,         /* Attach              */
 269     NULL,         /* Detach              */
 270     NULL,         /* Context             */
 271     DEV_DEBUG,    /* Flags               */
 272     0,            /* Debug control flags */
 273     prt_dt,       /* Debug flag names    */
 274     NULL,         /* Memory size change  */
 275     NULL,         /* Logical name        */
 276     NULL,         /* Help                */
 277     NULL,         /* Attach help         */
 278     NULL,         /* Attach context      */
 279     NULL,         /* Description         */
 280     NULL          /* End                 */
 281 };
 282 
 283 typedef struct
 284   {
 285     enum prt_mode
 286       {
 287         prtNoMode, prtPrt, prtLdImgBuf, prtRdStatReg, prtLdVFCImg
 288       } ioMode;
 289     int    prtUnitNum;
 290     bool   isBCD;
 291     bool   isEdited;
 292     int    slew;
 293     char   device_name [MAX_DEV_NAME_LEN];
 294     int    prtfile; // fd
 295     char   filename [SIR_MAXPATH];
 296     bool   cachedFF;
 297     bool   split;
 298     int    model;
 299     bool   in_trailing_banner;
 300     bool   secondary_sentinel_seen;
 301     bool   delay_secondary_sentinel_check;
 302     char   history_buf [42];
 303     size_t history_buf_len;
 304   } prt_state_t;
 305 
 306 static prt_state_t prt_state[N_PRT_UNITS_MAX];
 307 
 308 static char prt_path[1025];
 309 
 310 #define N_MODELS 13
 311 
 312 static const char * model_names[N_MODELS] =
 313   {
 314     "202", "300", "301",  "302",  "303",  "304",
 315     "401", "402", "901", "1000", "1200", "1201",
 316     "1600"
 317   };
 318 
 319 #define MODEL_1600 12
 320 
 321 static const int model_type[N_MODELS] =
 322   { 1, 2, 2, 2, 3, 3,
 323     4, 4, 4, 4, 4, 4,
 324     4
 325   };
 326 
 327 #if defined(NO_C_ELLIPSIS)
 328 static const uint8 newlines[128] = {
 329   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 330   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 331   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 332   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 333   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 334   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 335   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 336   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 337   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 338   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 339   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 340   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 341   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 342   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 343   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 344   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'
 345 };
 346 
 347 static const uint8 spaces[128] = {
 348   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 349   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 350   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 351   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 352   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 353   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 354   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 355   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 356   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 357   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 358   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 359   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 360   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 361   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 362   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 363   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
 364 };
 365 #else
 366 static const uint8 newlines[128] = { [0 ... 127] = '\n' };
 367 static const uint8   spaces[128] = { [0 ... 127] = ' ' };
 368 #endif
 369 static const uint8 formfeed[1] = { '\f' };
 370 static const uint8 crlf[4]     = { '\r', '\n', '\r', '\n' };
 371 static const uint8 cr[2]       = { '\r', '\n' };
 372 
 373 /*
 374  * prt_init()
 375  *
 376  */
 377 
 378 // Once-only initialization
 379 
 380 void prt_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 381   {
 382     (void)memset (prt_path, 0, sizeof (prt_path));
 383     (void)memset (prt_state, 0, sizeof (prt_state));
 384     for (int i = 0; i < N_PRT_UNITS_MAX; i ++)
 385       {
 386         prt_state[i].prtfile = -1;
 387         prt_state[i].model = MODEL_1600;
 388       }
 389   }
 390 
 391 static t_stat prt_reset (UNUSED DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 392   {
 393 
 394 
 395 
 396 
 397 
 398 
 399 
 400     return SCPE_OK;
 401   }
 402 
 403 // Given an array of word36 and a 9bit char offset, return the char
 404 
 405 static word9 gc (word36 * b, uint os)
     /* [previous][next][first][last][top][bottom][index][help] */
 406   {
 407     uint wordno = os / 4;
 408     uint charno = os % 4;
 409     return (word9) getbits36_9 (b[wordno], charno * 9);
 410   }
 411 
 412 // Don't know what the longest user id is...
 413 #define LONGEST 128
 414 
 415 // looking for space/space/5 digit number/\037/\005/name/\037
 416 // qno will get 5 chars + null;
 417 
 418 //  040040061060 060060062037 005101156164 150157156171 056123171163 101144155151 156056141037 145061060060 060062013002
 419 // <  10002\037\005Anthony.SysAdmin.a\037e10002\013\002>
 420 //  01234567   8   9
 421 static int parseID (word36 * b, uint tally, char * qno, char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 422   {
 423     if (tally < 3)
 424       return 0;
 425     if (gc (b, 0) != 040)
 426       return 0;
 427     if (gc (b, 1) != 040)
 428       return 0;
 429     uint i;
 430     for (i = 0; i < 5; i ++)
 431       {
 432         word9 ch = gc (b, 2 + i);
 433         if (ch < '0' || ch > '9')
 434           return 0;
 435         qno[i] = (char) ch;
 436       }
 437     qno[5] = 0;
 438     if (gc (b, 7) != 037)
 439       return 0;
 440     //if (gc (b, 8) != 005)
 441       //return 0;
 442     for (i = 0; i < LONGEST; i ++)
 443       {
 444         word9 ch = gc (b, 9 + i);
 445         if (ch == 037)
 446           break;
 447         if (! isprint (ch))
 448           return 0;
 449         name[i] = (char) ch;
 450       }
 451     name[i] = 0;
 452     return -1;
 453   }
 454 
 455 // buffers to hold the last 2 words of the data for each printer for eoj detection
 456 static word36 eoj_history [N_PRT_UNITS_MAX] [2];
 457 static int eoj_history_len [N_PRT_UNITS_MAX] = {0};
 458 
 459 // trailing banner detecting buffered writer
 460 static ssize_t
 461 buffered_write (int prt_unit_num, const void * data, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
 462 {
 463   prt_state_t * st = & prt_state [prt_unit_num];
 464 
 465   size_t total_len = st -> history_buf_len + len;
 466   char * temp_buf  = malloc (total_len);
 467   if (! temp_buf)
 468     {
 469       return -1;
 470     }
 471 
 472   (void)memcpy (temp_buf, st -> history_buf, st -> history_buf_len);
 473   (void)memcpy (temp_buf + st -> history_buf_len, data, len);
 474 
 475   if (st -> delay_secondary_sentinel_check)
 476     {
 477       if (NULL != memchr (data, '\n', len))
 478         st -> delay_secondary_sentinel_check = false;
 479     }
 480 
 481   if (st -> in_trailing_banner && ! st -> secondary_sentinel_seen && ! st -> delay_secondary_sentinel_check)
 482     {
 483       for (int i = 0; i <= (int)total_len - 23; i++)
 484         { /* Bottom of Multics default trailing banner page */
 485           if (temp_buf [i + 0] == '\r'    && // CR
 486               isdigit (temp_buf [i + 13]) && // [0-9]
 487               isdigit (temp_buf [i + 14]) && // [0-9]
 488               isdigit (temp_buf [i + 15]) && // [0-9]
 489               isdigit (temp_buf [i + 16]) && // [0-9]
 490               isdigit (temp_buf [i + 17]) && // [0-9]
 491               temp_buf [i + 18] == ' '    && // space
 492               temp_buf [i + 19] == ' '    && // space
 493               temp_buf [i + 20] == ' '    && // space
 494               temp_buf [i + 21] == ' '    && // space
 495               temp_buf [i + 22] == ' ')      // space
 496             {
 497               st -> secondary_sentinel_seen = true;
 498               break;
 499             }
 500         }
 501     }
 502   else if (! st -> in_trailing_banner)
 503     {
 504       for (int i = 0; i <= (int)total_len - 21; i++)
 505         { /* Top of Multics default trailing banner page */
 506           if (temp_buf [i + 0] == '\r'    && // CR
 507               temp_buf [i + 1] == '\r'    && // CR
 508               temp_buf [i + 2] == '\f'    && // FF
 509               isdigit (temp_buf [i + 16]) && // [0-9]
 510               isdigit (temp_buf [i + 17]) && // [0-9]
 511               isdigit (temp_buf [i + 18]) && // [0-9]
 512               isdigit (temp_buf [i + 19]) && // [0-9]
 513               isdigit (temp_buf [i + 20]))   // [0-9]
 514             {
 515               st -> in_trailing_banner             = true;
 516               st -> delay_secondary_sentinel_check = true;
 517               break;
 518             }
 519         }
 520     }
 521 
 522   if (total_len >= sizeof (st -> history_buf))
 523     {
 524       (void)memcpy (st -> history_buf, temp_buf + total_len - sizeof (st -> history_buf), sizeof (st -> history_buf));
 525       st -> history_buf_len = sizeof (st -> history_buf);
 526     }
 527   else
 528     {
 529       (void)memcpy (st -> history_buf, temp_buf, total_len);
 530       st -> history_buf_len = total_len;
 531     }
 532 
 533   FREE (temp_buf);
 534 
 535   ssize_t n_write = write (st -> prtfile, data, len);
 536 
 537   /*
 538    * if (n_write > 0)
 539    *   (void)fsync (st -> prtfile);
 540    */
 541 
 542   return n_write;
 543 }
 544 
 545 //  0 ok
 546 // -1 unable to open print file
 547 // -2 unable to write to print file
 548 // -3 form feed cached, no i/o done.
 549 
 550 static int openPrtFile (int prt_unit_num, word36 * buffer, uint tally)
     /* [previous][next][first][last][top][bottom][index][help] */
 551   {
 552     if (prt_state [prt_unit_num] . prtfile != -1)
 553       return 0;
 554 
 555     // Reset eoj detection state
 556     eoj_history_len [prt_unit_num]                            = 0;
 557     prt_state [prt_unit_num] . in_trailing_banner             = false;
 558     prt_state [prt_unit_num] . secondary_sentinel_seen        = false;
 559     prt_state [prt_unit_num] . delay_secondary_sentinel_check = false;
 560     prt_state [prt_unit_num] . history_buf_len                = 0;
 561 
 562     // The first (spooled) write is a formfeed; special case it and delay opening until the next line
 563     if (tally == 1 && buffer [0] == 0014013000000llu) //-V536 //-V522
 564       {
 565         prt_state [prt_unit_num] . cachedFF = true;
 566         return -3;
 567       }
 568 
 569     char qno [6], name [LONGEST + 1];
 570     int rc = parseID (buffer, tally, qno, name);
 571     char template [1024 + 129 + LONGEST];
 572     char unit_designator = 'a' + (char) prt_unit_num;
 573     char split_prefix [6];
 574     split_prefix [0] = 0;
 575 
 576     if (prt_state [prt_unit_num] . split) {
 577       (void)sprintf (split_prefix, "prt%c/", unit_designator);
 578     }
 579 
 580     if (rc == 0)
 581       (void)sprintf (template, "%s%sprt%c.spool.XXXXXX.prt.OPEN", prt_path, split_prefix, unit_designator);
 582     else
 583       (void)sprintf (template, "%s%sprt%c.spool.%s.%s.XXXXXX.prt.OPEN", prt_path, split_prefix, unit_designator, qno, name);
 584 
 585     if (prt_path [0] || split_prefix [0])
 586       {
 587         char dir_to_create [sizeof (template)];
 588         (void)snprintf (dir_to_create, sizeof (dir_to_create), "%s%s", prt_path, split_prefix);
 589         size_t l = strlen (dir_to_create);
 590 #if defined(__MINGW64__) || defined(__MINGW32__)
 591         if (l > 1 && (dir_to_create [l - 1] == '/' || dir_to_create [l - 1] == '\\'))
 592 #else
 593         if (l > 1 && dir_to_create [l - 1] == '/')
 594 #endif
 595           dir_to_create [l - 1] = 0;
 596 
 597         if (dir_to_create [0])
 598           {
 599             struct stat st;
 600             if (stat (dir_to_create, & st) == -1)
 601               {
 602                 (void)sir_notice ("Printer output directory '%s' not found; creating it.", dir_to_create);
 603                 if (0 != x_mkdir_p (dir_to_create))
 604                   {
 605                     sir_error ("Unable to create directory '%s': %s (Error %d)", dir_to_create, xstrerror_l (errno), errno);
 606                     return -1;
 607                   }
 608               }
 609           }
 610       }
 611 
 612     prt_state [prt_unit_num] . prtfile = utfile_mkstemps (template, 9);
 613     strcpy (prt_state [prt_unit_num] . filename, template);
 614 
 615     if (prt_state[prt_unit_num].prtfile == -1)
 616       {
 617         sir_error ("Unable to open printer file '%s': %s (Error %d)", template, xstrerror_l (errno), errno);
 618         return -1;
 619       }
 620     if (prt_state[prt_unit_num].cachedFF)
 621       {
 622         ssize_t n_write = buffered_write (prt_unit_num, formfeed, 1);
 623         if (n_write != 1)
 624           {
 625             return -2;
 626           }
 627         prt_state[prt_unit_num].cachedFF = false;
 628       }
 629     return 0;
 630   }
 631 
 632 // eoj is looking for data "\037\014%%%%%\037\005"
 633 // max tally should be 4096 and EOJ window looks back 2 words
 634 #define MAX_WINDOW_WORDS (4096 + 2)
 635 static int eoj (int prt_unit_num, word36 * buffer, uint tally)
     /* [previous][next][first][last][top][bottom][index][help] */
 636 {
 637     if (! prt_state [prt_unit_num] . in_trailing_banner)
 638       return 0;
 639 
 640     if (tally + 2 > MAX_WINDOW_WORDS)
 641       {
 642         sir_warn ("tally %u too large at %s[%s:%d]", tally, __func__, __FILE__, __LINE__);
 643         return 0;
 644       }
 645 
 646     word36 window [MAX_WINDOW_WORDS];
 647     uint window_tally = (uint)eoj_history_len [prt_unit_num];
 648 
 649     if (window_tally > 0)
 650       (void)memcpy (window, eoj_history [prt_unit_num], window_tally * sizeof (word36));
 651 
 652     (void)memcpy (window + window_tally, buffer, tally * sizeof (word36));
 653     window_tally += tally;
 654 
 655     int found = 0;
 656     if (window_tally >= 3)
 657       {
 658         uint num_chars = window_tally * 4;
 659         unsigned char chars [MAX_WINDOW_WORDS * 4];
 660 
 661         for (uint i = 0; i < window_tally; i++)
 662           {
 663             chars [i * 4 + 0] = (unsigned char)getbits36_9 (window [i],  0);
 664             chars [i * 4 + 1] = (unsigned char)getbits36_9 (window [i],  9);
 665             chars [i * 4 + 2] = (unsigned char)getbits36_9 (window [i], 18);
 666             chars [i * 4 + 3] = (unsigned char)getbits36_9 (window [i], 27);
 667           }
 668 
 669         for (uint i = 0; i <= num_chars - 9; i++)
 670           {
 671             if ( chars [i + 0] == 037 &&
 672                  chars [i + 1] == 014 &&
 673                 (chars [i + 2] >= '0' && chars [i + 2] <= '9') &&
 674                 (chars [i + 3] >= '0' && chars [i + 3] <= '9') &&
 675                 (chars [i + 4] >= '0' && chars [i + 4] <= '9') &&
 676                 (chars [i + 5] >= '0' && chars [i + 5] <= '9') &&
 677                 (chars [i + 6] >= '0' && chars [i + 6] <= '9') &&
 678                  chars [i + 7] == 037 &&
 679                  chars [i + 8] == 005)
 680               {
 681                 if (prt_state [prt_unit_num] . secondary_sentinel_seen)
 682                   {
 683                     found = -1;
 684                     break;
 685                   }
 686               }
 687           }
 688       }
 689 
 690     if (found)
 691       {
 692         // got it! reset history for unit
 693         eoj_history_len [prt_unit_num]                         = 0;
 694         prt_state [prt_unit_num] . in_trailing_banner             = false;
 695         prt_state [prt_unit_num] . secondary_sentinel_seen        = false;
 696         prt_state [prt_unit_num] . delay_secondary_sentinel_check = false;
 697         prt_state [prt_unit_num] . history_buf_len                = 0;
 698       }
 699     else
 700       {
 701         // did not get it, save the tail of data into history buffer window
 702         if (window_tally >= 2)
 703           {
 704             eoj_history_len [prt_unit_num] = 2;
 705             (void)memcpy (eoj_history [prt_unit_num], window + window_tally - 2, 2 * sizeof (word36));
 706           }
 707         else if (window_tally == 1)
 708           {
 709             eoj_history_len [prt_unit_num] = 1;
 710             eoj_history [prt_unit_num] [0] = window [0];
 711           }
 712         else
 713           {
 714             eoj_history_len [prt_unit_num] = 0;
 715           }
 716       }
 717 
 718     return found;
 719 }
 720 
 721 // Based on prt_status_table_.alm
 722 //  I think that "substat_entry a,b,c,d"
 723 //    a  character number (6 bit chars; 6/word))
 724 //    b  bit pattern
 725 // so
 726 //   substat_entry       1,000000,,(Normal)
 727 // means "a 0 in char 1" means normal.
 728 //
 729 
 730 
 731 
 732 
 733 
 734 
 735 
 736 
 737 
 738 
 739 
 740 
 741 
 742 
 743 
 744 
 745 
 746 
 747 
 748 
 749 
 750 
 751 
 752 
 753 
 754 
 755 
 756 
 757 
 758 
 759 
 760 
 761 
 762 
 763 
 764 
 765 
 766 
 767 
 768 
 769 
 770 
 771 
 772 
 773 
 774 
 775 
 776 
 777 
 778 
 779 
 780 
 781 
 782 
 783 
 784 
 785 
 786 
 787 
 788 
 789 
 790 
 791 
 792 
 793 
 794 
 795 
 796 
 797 
 798 
 799 
 800 
 801 
 802 
 803 
 804 
 805 
 806 
 807 
 808 
 809 
 810 
 811 
 812 
 813 
 814 
 815 
 816 
 817 
 818 
 819 
 820 
 821 
 822 
 823 
 824 
 825 
 826 // 0 OK
 827 // -1 Can't open print file
 828 // -2 Can't write to print file
 829 
 830 static int print_buf (int prt_unit_num, bool isBCD, bool is_edited, int slew, word36 * buffer, uint tally)
     /* [previous][next][first][last][top][bottom][index][help] */
 831   {
 832 // derived from pr2_conv_$lower_case_table
 833 //
 834 //        0    1    2    3    4    5    6    7
 835 // 000   '0'  '1'  '2'  '3'  '4'  '5'  '6'  '7'
 836 // 010   '8'  '9'  '{'  '#'  '?'  ':'  '>'
 837 // 020   ' '  'a'  'b'  'c'  'd'  'e'  'f'  'g'
 838 // 030   'h'  'i'  '|'  '.'  '}'  '('  '<'  '`'
 839 // 040   '^'  'j'  'k'  'l'  'm'  'm'  'o'  'p'
 840 // 050   'q'  'r'  '_'  '$'  '*'  ')'  ';'  '\''
 841 // 060   '+'  '/'  's'  't'  'u'  'v'  'w'  'x'
 842 // 070   'y'  'z'  '~'  ','  '!'  '='  '"'
 843 
 844     static char * bcd_lc =
 845       "01234567"
 846       "89{#?;>?"
 847       " abcdefg"
 848       "hi|.}(<\\"
 849       "^jklmnop"
 850       "qr_$*);'"
 851       "+/stuvwx"
 852       "yz~,!=\"!"; // '!' is actually the escape character, caught above
 853 
 854 // derived from pr2_conv_$upper_case_table
 855 //
 856 //        0    1    2    3    4    5    6    7
 857 // 000   '0'  '1'  '2'  '3'  '4'  '5'  '6'  '7'
 858 // 010   '8'  '9'  '['  '#'  '@'  ':'  '>'
 859 // 020   ' '  'A'  'B'  'C'  'D'  'E'  'F'  'G'
 860 // 030   'H'  'I'  '&'  '.'  ']'  '('  '<'  '`'
 861 // 040   '^'  'J'  'K'  'L'  'M'  'N'  'O'  'P'
 862 // 050   'Q'  'R'  '-'  '$'  '*'  ')'  ';'  '\''
 863 // 060   '+'  '/'  'S'  'T'  'U'  'V'  'W'  'X'
 864 // 070   'Y'  'Z'  '\\' ','  '%'  '='  '"'
 865     static char * bcd_uc =
 866       "01234567"
 867       "89[#@;>?"  // '?' is actually in the lower case table; pr2_conv_ never generates 017 in upper case mode
 868       " ABCDEFG"
 869       "HI&.](<\\"
 870       "^JKLMNOP"
 871       "QR-$*);'"
 872       "+/STUVWX"
 873       "YZ_,%=\"!"; // '!' is actually the escape character, caught above
 874 
 875 // Used for nonedited; has question mark.
 876     static char * bcd =
 877       "01234567"
 878       "89[#@;> "  // 'POLTS says that 17 is question mark for nonedited
 879       " ABCDEFG"
 880       "HI&.](<\\"
 881       "^JKLMNOP"
 882       "QR-$*);'"
 883       "+/STUVWX"
 884       "YZ_,%=\"!";
 885 
 886     if (prt_state[prt_unit_num].prtfile == -1)
 887       {
 888         int rc = openPrtFile (prt_unit_num, buffer, tally);
 889         if (rc < 0) // Can't open or can't write to print file; or ff cached
 890           {
 891             return rc == -3 ? 0 : rc;
 892           }
 893       }
 894 
 895 
 896 
 897 
 898 
 899 
 900 
 901 
 902 
 903 
 904 
 905 
 906 
 907 
 908 
 909 
 910 
 911 
 912 
 913 
 914 
 915 
 916 
 917 
 918 
 919 
 920 
 921 
 922 
 923 
 924     if (slew == -1)
 925       {
 926         ssize_t n_write = buffered_write (prt_unit_num, formfeed, 1);
 927         if (n_write != 1)
 928           {
 929             return -2;
 930           }
 931       }
 932     else if (slew)
 933       {
 934         for (int i = 0; i < slew; i ++)
 935           {
 936             ssize_t n_write = buffered_write (prt_unit_num, crlf, 2);
 937             if (n_write != 2)
 938               {
 939                 return -2;
 940               }
 941           }
 942       }
 943 // Not needed; always slew back to column 0 when done.
 944 //    else
 945 //      {
 946 //        write (prt_state[prt_unit_num].prtfile, cr, 1);
 947 //      }
 948 
 949     if (tally)
 950       {
 951             if (isBCD)
 952           {
 953             uint nchars = tally * 6;
 954 #define get_BCD_char(i) ((uint8_t) ((buffer[i / 6] >> ((5 - i % 6) * 6)) & 077))
 955 
 956             if (! is_edited)
 957               { // Easy case
 958                 uint8 bytes[nchars];
 959                 for (uint i = 0; i < nchars; i ++)
 960                   {
 961                     bytes[i] = (uint8_t) bcd_uc [get_BCD_char (i)];
 962                   }
 963                 ssize_t n_write = buffered_write (prt_unit_num, bytes, nchars);
 964                 if (n_write != (ssize_t)nchars)
 965                   {
 966                     return -2;
 967                   }
 968               }
 969             else // edited BCD
 970               {
 971                 //bool BCD_case = false; // false is upper case
 972                 // POLTS implies 3 sets
 973                 // 0 - initial set, upper case, no question mark.
 974                 // 1  - first change: lower case, question mark.
 975                 // 2  - second change: upper case, question mark.
 976                 int BCD_cset = 0;
 977                 char * table[3] = { bcd, bcd_lc, bcd_uc };
 978 
 979                 for (uint i = 0; i < nchars; i ++)
 980                   {
 981                     uint8_t ch = get_BCD_char (i);
 982 // Looking at pr2_conv_.alm, it looks like the esc char is 77
 983 //  77 n  if n is
 984 //      0 - 017, slew n lines  (0 is just CR)
 985 //      020 generate slew to top of page,
 986 //      021 generate slew to top of inside page,
 987 //      022 generate slew to top of outside page,
 988 //      041 to 057, generate (n-040) *8 spaces
 989 
 990                     if (ch == 077)
 991                       {
 992                         i ++;
 993                         uint8_t n = get_BCD_char (i);
 994 
 995                         if (n == 077) // pr2_conv_ sez ESC ESC is case shift
 996                           {
 997                             //BCD_case = ! BCD_case;
 998                             switch (BCD_cset)
 999                               {
1000                                 case 0: BCD_cset = 1; break; // default to lower
1001                                 case 1: BCD_cset = 2; break; // lower to upper
1002                                 case 2: BCD_cset = 1; break; // upper to lower
1003                               }
1004                           }
1005                         else if (n >= 041 && n <= 057)
1006                           {
1007                             int nchars = (n - 040) * 8;
1008                             ssize_t n_write = buffered_write (prt_unit_num, spaces, (size_t)nchars);
1009                             if (n_write != nchars)
1010                               {
1011                                 return -2;
1012                               }
1013                           }
1014                         else if (n >= 020 && n <= 022)
1015                           {
1016                             // XXX not distinguishing between top of page, inside page, outside page
1017                             ssize_t n_write = buffered_write (prt_unit_num, formfeed, 1);
1018                             if (n_write != 1)
1019                               {
1020                                 return -2;
1021                               }
1022                           }
1023                         else if (n == 0) // slew 0 lines is just CR
1024                           {
1025                             ssize_t n_write = buffered_write (prt_unit_num, cr, 1);
1026                             if (n_write != 1)
1027                               {
1028                                 return -2;
1029                               }
1030                           }
1031                         else if (n <= 017)
1032                           {
1033                             ssize_t n_write = buffered_write (prt_unit_num, newlines, n);
1034                             if (n_write != n)
1035                               {
1036                                 return -2;
1037                               }
1038                           }
1039 #if defined(TESTING)
1040                         else
1041                           {
1042                             sim_warn ("Printer BCD edited ESC %u. %o ignored\r\n", n, n);
1043                           }
1044 #endif /* if defined(TESTING) */
1045                       }
1046                     else // not escape
1047                       {
1048                         ssize_t n_write = buffered_write (prt_unit_num, table[BCD_cset] + ch, 1);
1049                         if (n_write != 1)
1050                           {
1051                             return -2;
1052                           }
1053                       }
1054                   } // for i to nchars
1055               } // edited BCD
1056           } // BCD
1057         else // ASCII
1058           {
1059             uint nchars = tally * 4;
1060 #define get_ASCII_char(i) ((uint8_t) ((buffer[i / 4] >> ((3 - i % 4) * 9)) & 0377))
1061 
1062             if (! is_edited)
1063               { // Easy case
1064                 uint8 bytes[nchars];
1065                 uint nbytes = 0;
1066                 for (uint i = 0; i < nchars; i ++)
1067                   {
1068                     uint8_t ch = get_ASCII_char (i);
1069                     if (isprint (ch))
1070                       bytes[nbytes ++] = ch;
1071                   }
1072                 ssize_t n_write = buffered_write (prt_unit_num, bytes, nbytes);
1073                 if (n_write != (ssize_t)nbytes)
1074                   {
1075                     return -2;
1076                   }
1077               }
1078             else // edited ASCII
1079               {
1080                 uint col = 0;
1081                 for (uint i = 0; i < tally * 4; i ++)
1082                   {
1083                     uint8_t ch = get_ASCII_char (i);
1084                     if (ch == 037) // insert n spaces
1085                       {
1086                         i ++;
1087                         uint8_t n = get_ASCII_char (i);
1088                         ssize_t n_write = buffered_write (prt_unit_num, spaces, n);
1089                         if (n_write != n)
1090                           {
1091                             return -2;
1092                           }
1093                         col += n;
1094                       }
1095                     else if (ch == 013) // insert n new lines
1096                       {
1097                         i ++;
1098                         uint8_t n = get_ASCII_char (i);
1099                         if (n)
1100                            {
1101                             ssize_t n_write = buffered_write (prt_unit_num, newlines, n);
1102                             if (n_write != n)
1103                               {
1104                                 return -2;
1105                               }
1106                           }
1107                         else // 0 lines; just slew to beginning of line
1108                           {
1109                             ssize_t n_write = buffered_write (prt_unit_num, cr, 1);
1110                             if (n_write != 1)
1111                               {
1112                                 return -2;
1113                               }
1114                           }
1115                         col = 0;
1116                       }
1117                     else if (ch == 014) // slew page
1118                       {
1119                         ssize_t n_write = buffered_write (prt_unit_num, formfeed, 1);
1120                         if (n_write != 1)
1121                           {
1122                             return -2;
1123                           }
1124                         col = 0;
1125                       }
1126                     else if (ch == 011) // horizontal tab
1127                       {
1128                         i ++;
1129                         uint8_t n = get_ASCII_char (i);
1130                         if (col < n)
1131                           {
1132                             ssize_t n_write = buffered_write (prt_unit_num, spaces, n - col);
1133                             if (n_write != n - col)
1134                               {
1135                                 return -2;
1136                               }
1137                             col += n;
1138                           }
1139                       }
1140                     else if (isprint (ch))
1141                       {
1142                         ssize_t n_write = buffered_write (prt_unit_num, & ch, 1);
1143                         if (n_write != 1)
1144                           {
1145                             return -2;
1146                           }
1147                         col ++;
1148                       }
1149                   } // for
1150               } // edited ASCII
1151           } // ASCII
1152       } // tally
1153 
1154 // Slew back to beginning of line
1155     ssize_t n_write = buffered_write (prt_unit_num, cr, 1);
1156     if (n_write != 1)
1157       {
1158         return -2;
1159       }
1160 
1161     if ((! isBCD) && eoj (prt_unit_num, buffer, tally))
1162       {
1163         close (prt_state [prt_unit_num] . prtfile);
1164         prt_state [prt_unit_num] . prtfile = -1;
1165 
1166         int rename_attempts           = 0;
1167         const int MAX_RENAME_ATTEMPTS = 10000;
1168         bool rename_successful        = false;
1169 
1170         char old_open_filename [SIR_MAXPATH];
1171         char new_target_filename [SIR_MAXPATH];
1172 
1173         strcpy (old_open_filename, prt_state [prt_unit_num] . filename);
1174 
1175         char * open_ext_pos = strstr (old_open_filename, ".OPEN");
1176         if (open_ext_pos)
1177           {
1178             strncpy (new_target_filename, old_open_filename, open_ext_pos - old_open_filename);
1179             new_target_filename [open_ext_pos - old_open_filename] = '\0';
1180           }
1181         else
1182           strcpy (new_target_filename, old_open_filename);
1183 
1184         while (rename_attempts < MAX_RENAME_ATTEMPTS)
1185           {
1186             if (safe_rename (old_open_filename, new_target_filename) == 0)
1187               {
1188                 rename_successful = true;
1189                 break;
1190               }
1191 
1192             char new_random_part [7];
1193             const char charset []  = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1194             const int charset_size = sizeof (charset) - 1;
1195 
1196             for (int i = 0; i < 6; ++i)
1197               {
1198                 new_random_part [i] = charset [random () % charset_size];
1199               }
1200 
1201             new_random_part [6] = '\0';
1202 
1203             char * prt_ext_pos = strstr (new_target_filename, ".prt");
1204             if (prt_ext_pos)
1205               {
1206                 char * random_start_pos = prt_ext_pos - 6;
1207                 if (random_start_pos >= new_target_filename)
1208                   (void)memmove (random_start_pos, new_random_part, 6);
1209               }
1210 
1211             rename_attempts++;
1212           }
1213 
1214         if (!rename_successful)
1215           {
1216             sir_error ("Failed to rename '%s': %s (Error %d)", old_open_filename, xstrerror_l (errno), errno);
1217           }
1218       }
1219 
1220     return 0;
1221   }
1222 
1223 static int loadImageBuffer (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1224   {
1225     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1226     // We don't actually have a print chain, so just pretend we loaded the image data
1227     p->stati = 04000; //-V536
1228     return 0;
1229   }
1230 
1231 static int readStatusRegister (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1232   {
1233     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1234 
1235     uint tally = p -> DDCW_TALLY;
1236 
1237     if (tally != 4)
1238       {
1239         sim_warn ("%s: expected tally of 4, is %d\r\n", __func__, tally);
1240       }
1241     if (tally == 0)
1242       {
1243         tally = 4096;
1244       }
1245 
1246 // system_library_tools/source/bound_io_tools_.s.archive/analyze_detail_stat_.pl1  anal_fips_disk_().
1247 
1248     word36 buffer[tally];
1249     (void)memset (buffer, 0, sizeof (buffer));
1250     // word 1 char 1   0: normal
1251     // word 1 char 2   0: device not busy
1252     // word 1 char 3   0: no device attention bit set
1253     // word 1 char 4   0: no device data alert
1254     // word 1 char 5   0: unused
1255     // word 1 char 6   0: no command reject
1256     //buffer[0] = 0;
1257     // word 2 char 1 (7) 0: unused
1258     // word 2 char 2 (9) 0: unused
1259     // word 2 char 3 (10) 0: unused
1260     // word 2 char 4 (11) 0: no MPC attention
1261     // word 2 char 5 (12) 0: no MPC data alert
1262     // word 2 char 6 (13) 0: unused
1263     //buffer[2] = 0;
1264     // word 3 char 1 (14) 0: no MPC command reject
1265     // word 3 char 2 (15) 0: unused
1266     // word 3 char 3 (16) 0: unused
1267     // word 3 char 4 (17) 0: unused
1268     // word 3 char 5 (18) 0: unused
1269     // word 3 char 6 (19) 0: unused
1270     //buffer[3] = 0;
1271     uint wordsProcessed = tally;
1272     iom_indirect_data_service (iom_unit_idx, chan, buffer,
1273                             & wordsProcessed, true);
1274     p->charPos = 0;
1275     p->stati = 04000; //-V536
1276     return 0;
1277   }
1278 
1279 static int loadVFCImage (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1280   {
1281     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1282     // We don't actually have a VFC, so just pretend we loaded the image data
1283     p->stati = 04000; //-V536
1284     return 0;
1285   }
1286 
1287 static iom_cmd_rc_t print_cmd (uint iom_unit_idx, uint chan, int prt_unit_num, bool isBCD, bool is_edited, int slew)
     /* [previous][next][first][last][top][bottom][index][help] */
1288   {
1289 #if defined(TESTING)
1290     cpu_state_t * cpup  = _cpup;
1291 #endif
1292     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1293     p->isRead = false;
1294 
1295 
1296 
1297 
1298 
1299 
1300 
1301 
1302 
1303 
1304 
1305 
1306 
1307 
1308 
1309 
1310 
1311 
1312 
1313 
1314 
1315 
1316 
1317 
1318 
1319 
1320 
1321 
1322 
1323 
1324 
1325 
1326 
1327 
1328 
1329         uint tally = p -> DDCW_TALLY;
1330         sim_debug (DBG_DEBUG, & prt_dev,
1331                    "%s: Tally %d (%o)\r\n", __func__, tally, tally);
1332 
1333         if (tally == 0)
1334           tally = 4096;
1335 
1336         // Copy from core to buffer
1337         word36 buffer[tally];
1338         uint wordsProcessed = 0;
1339         iom_indirect_data_service (iom_unit_idx, chan, buffer,
1340                                 & wordsProcessed, false);
1341         p -> initiate = false;
1342 
1343 
1344 
1345 
1346 
1347 
1348 
1349 
1350 
1351 
1352 
1353 
1354 
1355 
1356 
1357 
1358 
1359 
1360 
1361 
1362         int rc = print_buf (prt_unit_num, isBCD, is_edited, slew, buffer, tally);
1363         if (rc == -1) // Can't open print file
1364           {
1365             p->stati = 04201; // Out of paper
1366             return IOM_CMD_ERROR;
1367           }
1368         if (rc == -2) // Can't write to print file
1369           {
1370             p->stati = 04210; // Check alert
1371             return IOM_CMD_ERROR;
1372           }
1373 
1374 
1375 
1376     p -> tallyResidue = 0;
1377     p -> stati = 04000;
1378     //return IOM_CMD_PROCEED;
1379     return IOM_CMD_RESIDUE;
1380   }
1381 
1382 iom_cmd_rc_t prt_cmd_202 (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1383 #if defined(TESTING)
1384   cpu_state_t * cpup   = _cpup;
1385 #endif
1386   iom_chan_data_t * p  = & iom_chan_data[iomUnitIdx][chan];
1387   uint ctlr_unit_idx   = get_ctlr_idx (iomUnitIdx, chan);
1388   uint devUnitIdx      = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1389   UNIT * unitp         = & prt_unit[devUnitIdx];
1390   int prt_unit_num     = (int) PRT_UNIT_NUM (unitp);
1391   prt_state_t * statep = & prt_state[devUnitIdx];
1392 
1393   // IDCW?
1394   if (IS_IDCW (p)) {
1395     // IDCW
1396     statep->ioMode = prtNoMode;
1397 
1398     switch (p->IDCW_DEV_CMD) {
1399       case 000: // CMD 00 Request status
1400         sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\r\n", __func__);
1401         p->stati = 04000;
1402         break;
1403 
1404       case 010: // CMD 010 -- print nonedited BCD, slew one line
1405         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew One Line\r\n", __func__);
1406         statep->ioMode     = prtPrt;
1407         statep->prtUnitNum = prt_unit_num;
1408         statep->isBCD      = true;
1409         statep->isEdited   = false;
1410         statep->slew       = 1;
1411         p->stati           = 04000;
1412         break;
1413 
1414       case 030: // CMD 030 -- print edited BCD, slew zero lines
1415         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Zero Lines\r\n", __func__);
1416         statep->ioMode     = prtPrt;
1417         statep->prtUnitNum = prt_unit_num;
1418         statep->isBCD      = true;
1419         statep->isEdited   = true;
1420         statep->slew       = 0;
1421         p->stati           = 04000;
1422         break;
1423 
1424       case 040: // CMD 40 Reset status
1425         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\r\n", __func__);
1426         p->stati  = 04000;
1427         p->isRead = false;
1428         break;
1429 
1430       default:
1431         p->stati      = 04501; // cmd reject, invalid opcode
1432         p->chanStatus = chanStatIncorrectDCW;
1433         if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1434           sim_warn ("%s: PRT unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1435         return IOM_CMD_ERROR;
1436     } // switch IDCW_DEV_CMND
1437 
1438     sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\r\n", __func__, p->stati);
1439     return IOM_CMD_PROCEED;
1440   } // if IDCW
1441 
1442   // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
1443   switch (statep->ioMode) {
1444     case prtNoMode:
1445       //sim_printf ("%s: Unexpected IOTx\r\n", __func__);
1446       //sim_warn ("%s: Unexpected IOTx\r\n", __func__);
1447       //return IOM_CMD_ERROR;
1448       break;
1449 
1450     case prtPrt: {
1451         iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1452                 statep->isEdited, statep->slew);
1453         if (rc) //-V547
1454           return rc;
1455       }
1456       break;
1457 
1458     default:
1459       sim_warn ("%s: Unrecognized ioMode %d\r\n", __func__, statep->ioMode);
1460       return IOM_CMD_ERROR;
1461   }
1462 
1463   return IOM_CMD_PROCEED;
1464 }
1465 
1466 iom_cmd_rc_t prt_cmd_300 (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1467 #if defined(TESTING)
1468   cpu_state_t * cpup   = _cpup;
1469 #endif
1470   iom_chan_data_t * p  = & iom_chan_data[iomUnitIdx][chan];
1471   uint ctlr_unit_idx   = get_ctlr_idx (iomUnitIdx, chan);
1472   uint devUnitIdx      = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1473   UNIT * unitp         = & prt_unit[devUnitIdx];
1474   int prt_unit_num     = (int) PRT_UNIT_NUM (unitp);
1475   prt_state_t * statep = & prt_state[devUnitIdx];
1476 
1477   // IDCW?
1478   if (IS_IDCW (p)) {
1479     // IDCW
1480     statep->ioMode = prtNoMode;
1481 
1482     switch (p->IDCW_DEV_CMD) {
1483       case 000: // CMD 00 Request status
1484         sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\r\n", __func__);
1485         p->stati = 04000;
1486         break;
1487 
1488       case 011: // CMD 011 -- print nonedited ASCII, slew one line
1489         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\r\n", __func__);
1490         statep->ioMode     = prtPrt;
1491         statep->prtUnitNum = prt_unit_num;
1492         statep->isBCD      = false;
1493         statep->isEdited   = false;
1494         statep->slew       = 1;
1495         p->stati           = 04000;
1496         break;
1497 
1498       case 014: // CMD 014 -- Load Image Buffer
1499         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\r\n", __func__);
1500         statep->ioMode = prtLdImgBuf;
1501         p->stati       = 04000;
1502         break;
1503 
1504       case 030: // CMD 030 -- print edited ASCII, slew zero lines
1505         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\r\n", __func__);
1506         statep->ioMode     = prtPrt;
1507         statep->prtUnitNum = prt_unit_num;
1508         statep->isBCD      = false;
1509         statep->isEdited   = true;
1510         statep->slew       = 0;
1511         p->stati           = 04000;
1512         break;
1513 
1514       case 040: // CMD 40 Reset status
1515         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\r\n", __func__);
1516         p->stati  = 04000;
1517         p->isRead = false;
1518         break;
1519 
1520       default:
1521         p->stati      = 04501; // cmd reject, invalid opcode
1522         p->chanStatus = chanStatIncorrectDCW;
1523         if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1524           sim_warn ("%s: PRT unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1525         return IOM_CMD_ERROR;
1526     } // switch IDCW_DEV_CMND
1527 
1528     sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\r\n", __func__, p->stati);
1529     return IOM_CMD_PROCEED;
1530   } // if IDCW
1531 
1532   // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
1533   switch (statep->ioMode) {
1534     case prtNoMode:
1535       //sim_printf ("%s: Unexpected IOTx\r\n", __func__);
1536       //sim_warn ("%s: Unexpected IOTx\r\n", __func__);
1537       //return IOM_CMD_ERROR;
1538       break;
1539 
1540     case prtPrt: {
1541         iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1542                 statep->isEdited, statep->slew);
1543         if (rc) //-V547
1544           return rc;
1545       }
1546       break;
1547 
1548     case prtLdImgBuf: {
1549         int rc = loadImageBuffer (iomUnitIdx, chan);
1550         if (rc) //-V547
1551           return IOM_CMD_ERROR;
1552       }
1553       break;
1554 
1555     default:
1556       sim_warn ("%s: Unrecognized ioMode %d\r\n", __func__, statep->ioMode);
1557       return IOM_CMD_ERROR;
1558   }
1559   return IOM_CMD_PROCEED;
1560 }
1561 
1562 iom_cmd_rc_t prt_cmd_300a (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1563 #if defined(TESTING)
1564   cpu_state_t * cpup   = _cpup;
1565 #endif
1566   iom_chan_data_t * p  = & iom_chan_data[iomUnitIdx][chan];
1567   uint ctlr_unit_idx   = get_ctlr_idx (iomUnitIdx, chan);
1568   uint devUnitIdx      = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1569   UNIT * unitp         = & prt_unit[devUnitIdx];
1570   int prt_unit_num     = (int) PRT_UNIT_NUM (unitp);
1571   prt_state_t * statep = & prt_state[devUnitIdx];
1572 
1573   // IDCW?
1574   if (IS_IDCW (p)) {
1575     // IDCW
1576     statep->ioMode = prtNoMode;
1577 
1578     switch (p->IDCW_DEV_CMD) {
1579       case 000: // CMD 00 Request status
1580         sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\r\n", __func__);
1581         p->stati = 04000;
1582         break;
1583 
1584       case 001: // CMD 001 -- Load Image Buffer
1585         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\r\n", __func__);
1586         statep->ioMode = prtLdImgBuf;
1587         p->stati       = 04000;
1588         break;
1589 
1590       case 015: // CMD 015 -- print nonedited ASCII, slew one line
1591         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\r\n", __func__);
1592         statep->ioMode     = prtPrt;
1593         statep->prtUnitNum = prt_unit_num;
1594         statep->isBCD      = false;
1595         statep->isEdited   = false;
1596         statep->slew       = 1;
1597         p->stati           = 04000;
1598         break;
1599 
1600       case 034: // CMD 034 -- print edited ASCII, slew zero lines
1601         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\r\n", __func__);
1602         statep->ioMode     = prtPrt;
1603         statep->prtUnitNum = prt_unit_num;
1604         statep->isBCD      = false;
1605         statep->isEdited   = true;
1606         statep->slew       = 0;
1607         p->stati           = 04000;
1608         break;
1609 
1610       case 040: // CMD 40 Reset status
1611         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\r\n", __func__);
1612         p->stati  = 04000;
1613         p->isRead = false;
1614         break;
1615 
1616       default:
1617         p->stati      = 04501; // cmd reject, invalid opcode
1618         p->chanStatus = chanStatIncorrectDCW;
1619         if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1620           sim_warn ("%s: PRT unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1621         return IOM_CMD_ERROR;
1622     } // switch IDCW_DEV_CMND
1623 
1624     sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\r\n", __func__, p->stati);
1625     return IOM_CMD_PROCEED;
1626   } // if IDCW
1627 
1628   // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
1629   switch (statep->ioMode) {
1630     case prtNoMode:
1631       //sim_printf ("%s: Unexpected IOTx\r\n", __func__);
1632       //sim_warn ("%s: Unexpected IOTx\r\n", __func__);
1633       //return IOM_CMD_ERROR;
1634       break;
1635 
1636     case prtPrt: {
1637         iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1638                 statep->isEdited, statep->slew);
1639         if (rc) //-V547
1640           return rc;
1641       }
1642       break;
1643 
1644     case prtLdImgBuf: {
1645         int rc = loadImageBuffer (iomUnitIdx, chan);
1646         if (rc) //-V547
1647           return IOM_CMD_ERROR;
1648       }
1649       break;
1650 
1651     default:
1652       sim_warn ("%s: Unrecognized ioMode %d\r\n", __func__, statep->ioMode);
1653       return IOM_CMD_ERROR;
1654   }
1655   return IOM_CMD_PROCEED;
1656 }
1657 
1658 iom_cmd_rc_t prt_cmd_400 (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1659 #if defined(TESTING)
1660   cpu_state_t * cpup   = _cpup;
1661 #endif
1662   iom_chan_data_t * p  = & iom_chan_data[iomUnitIdx][chan];
1663   uint ctlr_unit_idx   = get_ctlr_idx (iomUnitIdx, chan);
1664   uint devUnitIdx      = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1665   UNIT * unitp         = & prt_unit[devUnitIdx];
1666   int prt_unit_num     = (int) PRT_UNIT_NUM (unitp);
1667   prt_state_t * statep = & prt_state[devUnitIdx];
1668 
1669   // IDCW?
1670   if (IS_IDCW (p)) {
1671     // IDCW
1672     statep->ioMode = prtNoMode;
1673 
1674     switch (p->IDCW_DEV_CMD) {
1675       case 000: // CMD 00 Request status
1676         sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\r\n", __func__);
1677         p->stati = 04000;
1678         break;
1679 
1680       case 001: // CMD 001 -- Load Image Buffer
1681         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\r\n", __func__);
1682         statep->ioMode = prtLdImgBuf;
1683         p->stati       = 04000;
1684         break;
1685 
1686       case 003: // CMD 003 -- Read Status
1687         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\r\n", __func__);
1688         statep->ioMode = prtRdStatReg;
1689         p->stati       = 04000;
1690         break;
1691 
1692       // load_vfc: entry (pip, pcip, iop, rcode);
1693       //
1694       // dcl 1 vfc_image aligned,                    /* print VFC image */
1695       //    (2 lpi fixed bin (8),                    /* lines per inch */
1696       //     2 image_length fixed bin (8),           /* number of lines represented by image */
1697       //     2 toip,                                 /* top of inside page info */
1698       //       3 line fixed bin (8),                 /* line number */
1699       //       3 pattern bit (9),                    /* VFC pattern */
1700       //     2 boip,                                 /* bottom of inside page info */
1701       //       3 line fixed bin (8),                 /* line number */
1702       //       3 pattern bit (9),                    /* VFC pattern */
1703       //     2 toop,                                 /* top of outside page info */
1704       //       3 line fixed bin (8),                 /* line number */
1705       //       3 pattern bit (9),                    /* VFC pattern */
1706       //     2 boop,                                 /* bottom of outside page info */
1707       //       3 line fixed bin (8),                 /* line number */
1708       //       3 pattern bit (9),                    /* VFC pattern */
1709       //     2 pad bit (18)) unal;                   /* fill out last word */
1710       //
1711       // dcl (toip_pattern init ("113"b3),           /* top of inside page pattern */
1712       //      toop_pattern init ("111"b3),           /* top of outside page pattern */
1713       //      bop_pattern init ("060"b3))            /* bottom of page pattern */
1714       //      bit (9) static options (constant);
1715 
1716       case 005: // CMD 005 -- Load VFC image
1717         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load VFC Image\r\n", __func__);
1718         statep->ioMode = prtLdVFCImg;
1719         p->stati       = 04000;
1720         break;
1721 
1722       case 010: // CMD 010 -- print nonedited BCD, slew zero lines
1723         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Zero Lines\r\n", __func__);
1724         statep->ioMode     = prtPrt;
1725         statep->prtUnitNum = prt_unit_num;
1726         statep->isBCD      = true;
1727         statep->isEdited   = false;
1728         statep->slew       = 0;
1729         p->stati           = 04000;
1730         break;
1731 
1732       case 011: // CMD 011 -- print nonedited BCD, slew one line
1733         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew One Line\r\n", __func__);
1734         statep->ioMode     = prtPrt;
1735         statep->prtUnitNum = prt_unit_num;
1736         statep->isBCD      = true;
1737         statep->isEdited   = false;
1738         statep->slew       = 1;
1739         p->stati           = 04000;
1740         break;
1741 
1742       case 012: // CMD 012 -- print nonedited BCD, slew two lines
1743         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Two Lines\r\n", __func__);
1744         statep->ioMode     = prtPrt;
1745         statep->prtUnitNum = prt_unit_num;
1746         statep->isBCD      = true;
1747         statep->isEdited   = false;
1748         statep->slew       = 2;
1749         p->stati           = 04000;
1750         break;
1751 
1752       case 013: // CMD 013 -- print nonedited BCD, slew top of page
1753         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Top Of Page\r\n", __func__);
1754         statep->ioMode     = prtPrt;
1755         statep->prtUnitNum = prt_unit_num;
1756         statep->isBCD      = true;
1757         statep->isEdited   = false;
1758         statep->slew       = -1;
1759         p->stati           = 04000;
1760         break;
1761 
1762       case 014: // CMD 014 -- print nonedited ASCII, slew zero lines
1763         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Zero Lines\r\n", __func__);
1764         statep->ioMode     = prtPrt;
1765         statep->prtUnitNum = prt_unit_num;
1766         statep->isBCD      = false;
1767         statep->isEdited   = false;
1768         statep->slew       = 0;
1769         p->stati           = 04000;
1770         break;
1771 
1772       case 015: // CMD 015 -- print nonedited ASCII, slew one line
1773         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\r\n", __func__);
1774         statep->ioMode     = prtPrt;
1775         statep->prtUnitNum = prt_unit_num;
1776         statep->isBCD      = false;
1777         statep->isEdited   = false;
1778         statep->slew       = 1;
1779         p->stati           = 04000;
1780         break;
1781 
1782       case 016: // CMD 016 -- print nonedited ASCII, slew two lines
1783         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Two Lines\r\n", __func__);
1784         statep->ioMode     = prtPrt;
1785         statep->prtUnitNum = prt_unit_num;
1786         statep->isBCD      = false;
1787         statep->isEdited   = false;
1788         statep->slew       = 2;
1789         p->stati           = 04000;
1790         break;
1791 
1792       case 017: // CMD 017 -- print nonedited ASCII, slew top of page
1793         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Top Of Page\r\n", __func__);
1794         statep->ioMode     = prtPrt;
1795         statep->prtUnitNum = prt_unit_num;
1796         statep->isBCD      = false;
1797         statep->isEdited   = false;
1798         statep->slew       = -1;
1799         p->stati           = 04000;
1800         break;
1801 
1802       case 030: // CMD 030 -- print edited BCD, slew zero lines
1803         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Zero Lines\r\n", __func__);
1804         statep->ioMode     = prtPrt;
1805         statep->prtUnitNum = prt_unit_num;
1806         statep->isBCD      = true;
1807         statep->isEdited   = true;
1808         statep->slew       = 0;
1809         p->stati           = 04000;
1810         break;
1811 
1812       case 031: // CMD 031 -- print edited BCD, slew one line
1813         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew One Line\r\n", __func__);
1814         statep->ioMode     = prtPrt;
1815         statep->prtUnitNum = prt_unit_num;
1816         statep->isBCD      = true;
1817         statep->isEdited   = true;
1818         statep->slew       = 1;
1819         p->stati           = 04000;
1820         break;
1821 
1822       case 032: // CMD 032 -- print edited BCD, slew two lines
1823         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Two Lines\r\n", __func__);
1824         statep->ioMode     = prtPrt;
1825         statep->prtUnitNum = prt_unit_num;
1826         statep->isBCD      = true;
1827         statep->isEdited   = true;
1828         statep->slew       = 2;
1829         p->stati           = 04000;
1830         break;
1831 
1832       case 033: // CMD 033 -- print edited BCD, slew top of page
1833         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Top Of Page\r\n", __func__);
1834         statep->ioMode     = prtPrt;
1835         statep->prtUnitNum = prt_unit_num;
1836         statep->isBCD      = true;
1837         statep->isEdited   = true;
1838         statep->slew       = -1;
1839         p->stati           = 04000;
1840         break;
1841 
1842       case 034: // CMD 034 -- print edited ASCII, slew zero lines
1843         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\r\n", __func__);
1844         statep->ioMode     = prtPrt;
1845         statep->prtUnitNum = prt_unit_num;
1846         statep->isBCD      = false;
1847         statep->isEdited   = true;
1848         statep->slew       = 0;
1849         p->stati           = 04000;
1850         break;
1851 
1852       case 035: // CMD 035 -- print edited ASCII, slew one line
1853         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew One Line\r\n", __func__);
1854         statep->ioMode     = prtPrt;
1855         statep->prtUnitNum = prt_unit_num;
1856         statep->isBCD      = false;
1857         statep->isEdited   = true;
1858         statep->slew       = 1;
1859         p->stati           = 04000;
1860         break;
1861 
1862       case 036: // CMD 036 -- print edited ASCII, slew two lines
1863         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Two Lines\r\n", __func__);
1864         statep->ioMode     = prtPrt;
1865         statep->prtUnitNum = prt_unit_num;
1866         statep->isBCD      = false;
1867         statep->isEdited   = true;
1868         statep->slew       = 2;
1869         p->stati           = 04000;
1870         break;
1871 
1872       case 037: // CMD 037 -- print edited ASCII, slew top of page
1873         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Top Of Page\r\n", __func__);
1874         statep->ioMode     = prtPrt;
1875         statep->prtUnitNum = prt_unit_num;
1876         statep->isBCD      = false;
1877         statep->isEdited   = true;
1878         statep->slew       = -1;
1879         p->stati           = 04000;
1880         break;
1881 
1882       case 040: // CMD 40 Reset status
1883         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\r\n", __func__);
1884         p->stati  = 04000;
1885         p->isRead = false;
1886         break;
1887 
1888       case 061:  { // CMD 61 Slew one line
1889           sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew One Line\r\n", __func__);
1890           int rc = print_buf (prt_unit_num, false, false, 1, NULL, 0);
1891           if (rc == -1) { // Can't open print file
1892             p->stati = 04201; // Out of paper
1893             return IOM_CMD_ERROR;
1894           }
1895           if (rc == -2) { // Can't write to print file
1896             p->stati = 04210; // Check alert
1897             return IOM_CMD_ERROR;
1898           }
1899           p->stati  = 04000;
1900           p->isRead = false;
1901         }
1902         break;
1903 
1904       case 062: { // CMD 62 Slew two lines
1905           sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew Two Lines\r\n", __func__);
1906           int rc = print_buf (prt_unit_num, false, false, 2, NULL, 0);
1907           if (rc == -1) { // Can't open print file
1908             p->stati = 04201; // Out of paper
1909             return IOM_CMD_ERROR;
1910           }
1911           if (rc == -2) { // Can't write to print file
1912             p->stati = 04210; // Check alert
1913             return IOM_CMD_ERROR;
1914           }
1915           p->stati  = 04000;
1916           p->isRead = false;
1917         }
1918         break;
1919 
1920       case 063: { // CMD 63 Slew to top of page
1921           sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew To Top Of Page\r\n", __func__);
1922           int rc = print_buf (prt_unit_num, false, false, -1, NULL, 0);
1923           if (rc == -1) { // Can't open print file
1924             p->stati = 04201; // Out of paper
1925             return IOM_CMD_ERROR;
1926           }
1927           if (rc == -2) { // Can't write to print file
1928             p->stati = 04210; // Check alert
1929             return IOM_CMD_ERROR;
1930           }
1931           p->stati  = 04000;
1932           p->isRead = false;
1933         }
1934         break;
1935 
1936       case 066: // CMD 66 Reserve device
1937         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reserve Device\r\n", __func__);
1938         p->stati  = 04000;
1939         p->isRead = false;
1940         break;
1941 
1942       case 067: // CMD 67 Release device
1943         sim_debug (DBG_DEBUG, & prt_dev, "%s: Release Device\r\n", __func__);
1944         p->stati  = 04000;
1945         p->isRead = false;
1946         break;
1947 
1948       default:
1949         p->stati      = 04501; // cmd reject, invalid opcode
1950         p->chanStatus = chanStatIncorrectDCW;
1951         if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1952         sim_warn ("%s: PRT unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1953         return IOM_CMD_ERROR;
1954     } // switch IDCW_DEV_CMND
1955 
1956     sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\r\n", __func__, p->stati);
1957     return IOM_CMD_PROCEED;
1958   } // if IDCW
1959 
1960   // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
1961   switch (statep->ioMode) {
1962     case prtNoMode:
1963       //sim_printf ("%s: Unexpected IOTx\r\n", __func__);
1964       //sim_warn ("%s: Unexpected IOTx\r\n", __func__);
1965       //return IOM_CMD_ERROR;
1966       break;
1967 
1968     case prtPrt: {
1969         iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1970                 statep->isEdited, statep->slew);
1971         if (rc) //-V547
1972           return rc;
1973       }
1974       break;
1975 
1976     case prtLdImgBuf: {
1977         int rc = loadImageBuffer (iomUnitIdx, chan);
1978         if (rc) //-V547
1979           return IOM_CMD_ERROR;
1980       }
1981       break;
1982 
1983     case prtRdStatReg: {
1984         int rc = readStatusRegister (iomUnitIdx, chan);
1985         if (rc) //-V547
1986           return IOM_CMD_ERROR;
1987       }
1988       break;
1989 
1990     case prtLdVFCImg: {
1991         int rc = loadVFCImage (iomUnitIdx, chan);
1992         if (rc) //-V547
1993           return IOM_CMD_ERROR;
1994       }
1995       break;
1996 
1997     default:
1998       sim_warn ("%s: Unrecognized ioMode %d\r\n", __func__, statep->ioMode);
1999       return IOM_CMD_ERROR;
2000   }
2001   return IOM_CMD_PROCEED;
2002 }
2003 
2004 iom_cmd_rc_t prt_iom_cmd (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
2005   iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
2006   uint ctlr_unit_idx  = get_ctlr_idx (iomUnitIdx, chan);
2007   uint devUnitIdx     = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
2008   UNIT * unitp        = & prt_unit[devUnitIdx];
2009   int prt_unit_num    = (int) PRT_UNIT_NUM (unitp);
2010 
2011   switch (model_type [prt_state[prt_unit_num].model]) {
2012     case 1: // 202
2013       return prt_cmd_202 (iomUnitIdx, chan);
2014 
2015     case 2: // 300, 301, 302
2016       return prt_cmd_300 (iomUnitIdx, chan);
2017 
2018     case 3: // 303, 304
2019       return prt_cmd_300a (iomUnitIdx, chan);
2020       // switch type 3 cmd
2021 
2022     case 4: // 401, 402, 901, 1000, 1200, 1201, 1600
2023       return prt_cmd_400 (iomUnitIdx, chan);
2024   }
2025   p->stati = 04502; //-V536  // invalid device code
2026   return IOM_CMD_DISCONNECT;
2027 }
2028 
2029 static t_stat prt_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
     /* [previous][next][first][last][top][bottom][index][help] */
2030                                UNUSED const void * desc)
2031   {
2032     sim_printf("Number of PRT units in system is %d\r\n", prt_dev.numunits);
2033     return SCPE_OK;
2034   }
2035 
2036 static t_stat prt_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
2037                               UNUSED void * desc)
2038   {
2039     if (! cptr)
2040       return SCPE_ARG;
2041     int n = atoi (cptr);
2042     if (n < 1 || n > N_PRT_UNITS_MAX)
2043       return SCPE_ARG;
2044     prt_dev.numunits = (uint) n;
2045     return SCPE_OK;
2046   }
2047 
2048 static t_stat prt_show_device_name (UNUSED FILE * st, UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
2049                                     UNUSED int val, UNUSED const void * desc)
2050   {
2051     int n = (int) PRT_UNIT_NUM (uptr);
2052     if (n < 0 || n >= N_PRT_UNITS_MAX)
2053       return SCPE_ARG;
2054     sim_printf("name     : %s", prt_state[n].device_name);
2055     return SCPE_OK;
2056   }
2057 
2058 static t_stat prt_set_device_model (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
2059                                     const UNUSED char * cptr, UNUSED void * desc)
2060   {
2061     int n = (int) PRT_UNIT_NUM (uptr);
2062     if (n < 0 || n >= N_PRT_UNITS_MAX)
2063       return SCPE_ARG;
2064     if (cptr)
2065       {
2066         for (int i = 0; i < N_MODELS; i ++)
2067            {
2068              if (strcmp (cptr, model_names[i]) == 0)
2069                {
2070                  prt_state[n].model = i;
2071                  return SCPE_OK;
2072                }
2073             }
2074         sim_printf ("Model '%s' not known (202 300 301 302 303 304 401 402 901 1000 1200 1201 1600)\r\n", cptr);
2075         return SCPE_ARG;
2076       }
2077     sim_printf ("Specify model from 202 300 301 302 303 304 401 402 901 1000 1200 1201 1600\r\n");
2078     return SCPE_ARG;
2079   }
2080 
2081 static t_stat prt_show_device_model (UNUSED FILE * st, UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
2082                                      UNUSED int val, UNUSED const void * desc)
2083   {
2084     int n = (int) PRT_UNIT_NUM (uptr);
2085     if (n < 0 || n >= N_PRT_UNITS_MAX)
2086       return SCPE_ARG;
2087     sim_printf("model    : %s", model_names[prt_state[n].model]);
2088     return SCPE_OK;
2089   }
2090 
2091 static t_stat prt_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
2092                                    const UNUSED char * cptr, UNUSED void * desc)
2093   {
2094     int n = (int) PRT_UNIT_NUM (uptr);
2095     if (n < 0 || n >= N_PRT_UNITS_MAX)
2096       return SCPE_ARG;
2097     if (cptr)
2098       {
2099         strncpy (prt_state[n].device_name, cptr, MAX_DEV_NAME_LEN - 1);
2100         prt_state[n].device_name[MAX_DEV_NAME_LEN - 1] = 0;
2101       }
2102     else
2103       {
2104         prt_state[n].device_name[0] = 0;
2105       }
2106     return SCPE_OK;
2107   }
2108 
2109 static t_stat prt_show_path (UNUSED FILE * st, UNUSED UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
2110                              UNUSED int val, UNUSED const void * desc)
2111   {
2112     if (prt_path[1] != '\0')
2113       {
2114         sim_printf("Path to PRT files is %s\r\n", prt_path);
2115       }
2116     else
2117       {
2118         char cwd_path [SIR_MAXPATH + 1];
2119         if (getcwd(cwd_path, sizeof(cwd_path)) != NULL)
2120           {
2121             sim_printf("Path to PRT files is %s\r\n", cwd_path);
2122           }
2123         else
2124           {
2125             if (errno)
2126               {
2127                 sim_printf("Path to PRT files is unavailable: %s (Error %d)\r\n",
2128                            xstrerror_l(errno), errno);
2129               }
2130             else
2131               {
2132                 sim_printf("Path to PRT files is undefined\r\n");
2133               }
2134           }
2135       }
2136     return SCPE_OK;
2137   }
2138 
2139 static t_stat prt_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
2140                             const UNUSED char * cptr, UNUSED void * desc)
2141   {
2142     if (! cptr)
2143       return SCPE_ARG;
2144 
2145     size_t len = strlen(cptr);
2146 
2147     if (len >= sizeof(prt_path))
2148       return SCPE_ARG;
2149     strncpy(prt_path, cptr, sizeof(prt_path) - 1);
2150     prt_path[sizeof(prt_path) - 1] = '\0';
2151     if (len > 0)
2152       {
2153         if (prt_path[len - 1] != '/')
2154           {
2155             if (len == sizeof(prt_path) - 1)
2156               return SCPE_ARG;
2157             prt_path[len++] = '/';
2158             prt_path[len] = 0;
2159           }
2160       }
2161     return SCPE_OK;
2162   }
2163 
2164 t_stat burst_printer (UNUSED int32 arg, const char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
2165   {
2166     for (int i = 0; i < N_PRT_UNITS_MAX; i ++)
2167       {
2168         if (strcmp (buf, prt_state [i] . device_name) == 0)
2169           {
2170             if (prt_state [i] . prtfile != -1)
2171               {
2172                 close (prt_state [i] . prtfile);
2173                 eoj_history_len [i]                            = 0;
2174                 prt_state [i] . prtfile                        = -1;
2175                 prt_state [i] . in_trailing_banner             = false;
2176                 prt_state [i] . secondary_sentinel_seen        = false;
2177                 prt_state [i] . delay_secondary_sentinel_check = false;
2178                 prt_state [i] . history_buf_len                = 0;
2179 
2180                 int rename_attempts           = 0;
2181                 const int MAX_RENAME_ATTEMPTS = 10000;
2182                 bool rename_successful        = false;
2183 
2184                 char old_open_filename [SIR_MAXPATH];
2185                 char new_target_filename [SIR_MAXPATH];
2186 
2187                 strcpy (old_open_filename, prt_state [i] . filename);
2188 
2189                 char * open_ext_pos = strstr (old_open_filename, ".OPEN");
2190                 if (open_ext_pos)
2191                   {
2192                     strncpy (new_target_filename, old_open_filename, open_ext_pos - old_open_filename);
2193                     new_target_filename [open_ext_pos - old_open_filename] = '\0';
2194                   }
2195                 else
2196                   strcpy (new_target_filename, old_open_filename);
2197 
2198                 while (rename_attempts < MAX_RENAME_ATTEMPTS)
2199                   {
2200                     if (safe_rename (old_open_filename, new_target_filename) == 0)
2201                       {
2202                         rename_successful = true;
2203                         break;
2204                       }
2205 
2206                     char new_random_part [7];
2207                     const char charset []  = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
2208                     const int charset_size = sizeof (charset) - 1;
2209 
2210                     for (int j = 0; j < 6; ++j)
2211                       {
2212                         new_random_part [j] = charset [random () % charset_size];
2213                       }
2214 
2215                     new_random_part [6] = '\0';
2216 
2217                     char * prt_ext_pos = strstr (new_target_filename, ".prt");
2218                     if (prt_ext_pos)
2219                       {
2220                         char * random_start_pos = prt_ext_pos - 6;
2221                         if (random_start_pos >= new_target_filename)
2222                           (void)memmove (random_start_pos, new_random_part, 6);
2223                       }
2224 
2225                     rename_attempts++;
2226                   }
2227 
2228                 if (!rename_successful)
2229                   {
2230                     sir_error ("Failed to rename '%s': %s (Error %d)", old_open_filename, xstrerror_l (errno), errno);
2231                   }
2232 
2233                 return SCPE_OK;
2234               }
2235 
2236             sim_printf ("burst sees nothing to burst\r\n");
2237             return SCPE_OK;
2238           }
2239       }
2240 
2241     sim_printf ("burst can't find printer named '%s'\r\n", buf);
2242 
2243     return SCPE_ARG;
2244   }
2245 
2246 static t_stat signal_prt_ready (uint prt_unit_idx) {
     /* [previous][next][first][last][top][bottom][index][help] */
2247   // Don't signal if the sim is not running....
2248   if (! sim_is_running)
2249     return SCPE_OK;
2250   uint ctlr_unit_idx = cables->prt_to_urp[prt_unit_idx].ctlr_unit_idx;
2251 
2252 
2253 
2254 
2255 
2256 
2257 
2258 
2259 
2260 
2261 
2262 
2263 
2264 
2265 
2266 
2267 
2268 
2269 
2270 
2271 
2272 
2273 
2274   // Which port should the controller send the interrupt to? All of them...
2275   for (uint ctlr_port_num = 0; ctlr_port_num < MAX_CTLR_PORTS; ctlr_port_num ++) {
2276     struct ctlr_to_iom_s * urp_to_iom = & cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num];
2277     if (urp_to_iom->in_use) {
2278       uint iom_unit_idx = urp_to_iom->iom_unit_idx;
2279       uint chan_num     = urp_to_iom->chan_num;
2280       uint dev_code     = cables->prt_to_urp[prt_unit_idx].dev_code;
2281 
2282       send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0x40, 01 /* disk pack ready */);
2283       return SCPE_OK;
2284     }
2285   }
2286   return SCPE_ARG;
2287 
2288 }
2289 
2290 static t_stat prt_set_ready (UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
2291                              UNUSED const char * cptr,
2292                              UNUSED void * desc)
2293   {
2294 #if defined(TESTING)
2295     cpu_state_t * cpup = _cpup;
2296 #endif
2297     int n = (int) PRT_UNIT_NUM (uptr);
2298     if (n < 0 || n >= N_PRT_UNITS_MAX)
2299       {
2300         sim_debug (DBG_ERR, & prt_dev,
2301                    "Printer set ready: Invalid unit number %ld\r\n", (long) n);
2302         sim_printf ("error: Invalid unit number %ld\r\n", (long) n);
2303         return SCPE_ARG;
2304       }
2305     return signal_prt_ready ((uint) n);
2306   }
2307 
2308 static config_value_list_t cfg_on_off [] =
2309   {
2310     { "off",     0 },
2311     { "on",      1 },
2312     { "disable", 0 },
2313     { "enable",  1 },
2314     { NULL,      0 }
2315   };
2316 
2317 static config_list_t prt_config_list [] =
2318   {
2319     { "split", 0, 1, cfg_on_off },
2320     { NULL,    0, 0, NULL       }
2321   };
2322 
2323 static t_stat prt_set_config (UNUSED UNIT *  uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
2324                               const char * cptr, UNUSED void * desc)
2325   {
2326     int devUnitIdx    = (int) PRT_UNIT_NUM (uptr);
2327     prt_state_t * psp = prt_state + devUnitIdx;
2328     // XXX Minor bug; this code doesn't check for trailing garbage
2329     config_state_t cfg_state = { NULL, NULL };
2330 
2331     for (;;)
2332       {
2333         int64_t v;
2334         int rc = cfg_parse (__func__, cptr, prt_config_list,
2335                            & cfg_state, & v);
2336         if (rc == -1) // done
2337           break;
2338 
2339         if (rc == -2) // error
2340           {
2341             cfg_parse_done (& cfg_state);
2342             return SCPE_ARG;
2343           }
2344         const char * p = prt_config_list[rc].name;
2345 
2346         if (strcmp (p, "split") == 0)
2347           {
2348             psp->split = v != 0;
2349             continue;
2350           }
2351 
2352         sim_warn ("error: prt_set_config: Invalid cfg_parse rc <%ld>\r\n",
2353                   (long) rc);
2354         cfg_parse_done (& cfg_state);
2355         return SCPE_ARG;
2356       } // process statements
2357     cfg_parse_done (& cfg_state);
2358     return SCPE_OK;
2359   }
2360 
2361 static t_stat prt_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
2362                                UNUSED int  val, UNUSED const void * desc)
2363   {
2364     int devUnitIdx    = (int) PRT_UNIT_NUM (uptr);
2365     prt_state_t * psp = prt_state + devUnitIdx;
2366     sim_msg ("split    : %d", psp->split);
2367     return SCPE_OK;
2368   }

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