home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 2 / RISC_DISC_2.iso / pd_share / utilities / cli / pgp2 / src / c / system < prev    next >
Encoding:
Text File  |  1995-03-14  |  40.0 KB  |  1,859 lines

  1. /*
  2.  * system.c
  3.  *
  4.  * Routines specific for non-MSDOS implementations of pgp.
  5.  * 
  6.  * (c) Copyright 1990-1994 by Philip Zimmermann.  All rights reserved.
  7.  * The author assumes no liability for damages resulting from the use
  8.  * of this software, even if the damage results from defects in this
  9.  * software.  No warranty is expressed or implied.
  10.  *
  11.  * Note that while most PGP source modules bear Philip Zimmermann's
  12.  * copyright notice, many of them have been revised or entirely written
  13.  * by contributors who frequently failed to put their names in their
  14.  * code.  Code that has been incorporated into PGP from other authors
  15.  * was either originally published in the public domain or is used with
  16.  * permission from the various authors.
  17.  *
  18.  * PGP is available for free to the public under certain restrictions.
  19.  * See the PGP User's Guide (included in the release package) for
  20.  * important information about licensing, patent restrictions on
  21.  * certain algorithms, trademarks, copyrights, and export controls.
  22.  *
  23.  *    Modified 24-Jun-92 HAJK
  24.  *    Adapt for VAX/VMS.
  25.  *
  26.  *    Modified: 11-Nov-92 HAJK
  27.  *    Add FDL Support Routines. 
  28.  *
  29.  *    Modified: 31-Jan-93 HAJK
  30.  *    Misc. updates for terminal handling.
  31.  *    Add VMS command stuff.
  32.  *    Add fileparse routine.
  33.  */
  34. #include <stdio.h>
  35. #include "exitpgp.h"
  36. #include "system.h"
  37. #include "usuals.h"
  38.  
  39. /*===========================================================================*/
  40. /*
  41.  * UNIX
  42.  */
  43.  
  44. #ifdef UNIX
  45. /*
  46.  * Define USE_SELECT to use the select() system call to check if
  47.  * keyboard input is available. Define USE_NBIO to use non-blocking
  48.  * read(). If you don't define anything the FIONREAD ioctl() command
  49.  * will be used.
  50.  *
  51.  * Define NOTERMIO if you don't have the termios stuff
  52.  */
  53. #include <sys/types.h>
  54. #include <fcntl.h>
  55.  
  56. #ifndef    NOTERMIO
  57. #ifndef SVR2
  58. #include <termios.h>
  59. #else
  60. #include <termio.h>
  61. #endif /* not SVR2 */
  62. #else
  63. #include <sgtty.h>
  64. #endif
  65.  
  66. #ifdef    USE_SELECT
  67. #include <sys/time.h>
  68. #ifdef _IBMR2
  69. #include <sys/select.h>
  70. #endif /* _IBMR2 */
  71. #else
  72. #ifndef USE_NBIO
  73. #ifndef sun
  74. #include <sys/ioctl.h>        /* for FIONREAD */
  75. #else /* including both ioctl.h and termios.h gives a lot of warnings on sun */
  76. #include <sys/filio.h>
  77. #endif /* sun */
  78. #ifndef FIONREAD
  79. #define    FIONREAD    TIOCINQ
  80. #endif
  81. #endif
  82. #endif
  83. #include <signal.h>
  84.  
  85. static void setsigs(void);
  86. static void rmsigs(void);
  87. static void sig1(int);
  88. static void sig2(int);
  89. void breakHandler(int);
  90. static int ttyfd= -1;
  91. #ifndef SVR2
  92. static void (*savesig)(int);
  93. #else
  94. static int (*savesig)(int);
  95. #endif
  96.  
  97. void ttycbreak(void);
  98. void ttynorm(void);
  99.  
  100. #ifndef NEED_KBHIT
  101. #undef USE_NBIO
  102. #endif
  103.  
  104. #ifndef NOTERMIO
  105. #ifndef SVR2
  106. static struct termios itio, tio;
  107. #else
  108. static struct termio itio, tio;
  109. #endif /* not SVR2 */
  110. #else
  111. static struct sgttyb isg, sg;
  112. #endif
  113.  
  114. #ifdef USE_NBIO
  115. static int kbuf= -1;    /* buffer to store char read by kbhit() */
  116. static int fflags;
  117. #endif
  118.  
  119. static int gottio = 0;
  120.  
  121. void ttycbreak(void)
  122. {
  123.     if (ttyfd == -1) {
  124.         if ((ttyfd = open("/dev/tty", O_RDWR)) < 0) {
  125.             fprintf(stderr, "cannot open tty, using stdin\n");
  126.             ttyfd = 0;
  127.         }
  128.     }
  129. #ifndef NOTERMIO
  130. #ifndef SVR2
  131.     if (tcgetattr(ttyfd, &tio) < 0)
  132. #else
  133.     if (ioctl(ttyfd, TCGETA, &tio) < 0)
  134. #endif  /* not SVR2 */
  135.     {
  136.         fprintf (stderr, "\nUnable to get terminal characteristics: ");
  137.         perror("ioctl");
  138.         exitPGP(1);
  139.     }
  140.     itio = tio;
  141.     setsigs();
  142.     gottio = 1;
  143. #ifdef USE_NBIO
  144.     tio.c_cc[VMIN] = 0;
  145. #else
  146.     tio.c_cc[VMIN] = 1;
  147. #endif
  148.     tio.c_cc[VTIME] = 0;
  149.     tio.c_lflag &= ~(ECHO|ICANON);
  150. #ifndef SVR2
  151. #ifdef ultrix
  152.     /* Ultrix is broken and flushes the output as well! */
  153.     tcsetattr (ttyfd, TCSANOW, &tio);
  154. #else
  155.     tcsetattr (ttyfd, TCSAFLUSH, &tio);
  156. #endif
  157. #else
  158.     ioctl(ttyfd, TCSETAF, &tio);
  159. #endif /* not SVR2 */
  160. #else
  161.     if (ioctl(ttyfd, TIOCGETP, &sg) < 0) {
  162.         fprintf (stderr, "\nUnable to get terminal characteristics: ");
  163.         perror("ioctl");
  164.         exitPGP(1);
  165.     }
  166.     isg = sg;
  167.     setsigs();
  168.     gottio = 1;
  169. #ifdef CBREAK
  170.     sg.sg_flags |= CBREAK;
  171. #else
  172.     sg.sg_flags |= RAW;
  173. #endif
  174.     sg.sg_flags &= ~ECHO;
  175.     ioctl(ttyfd, TIOCSETP, &sg);
  176. #endif    /* !NOTERMIO */
  177. #ifdef USE_NBIO
  178. #ifndef O_NDELAY
  179. #define    O_NDELAY    O_NONBLOCK
  180. #endif
  181.     if ((fflags = fcntl(ttyfd, F_GETFL, 0)) != -1)
  182.         fcntl(ttyfd, F_SETFL, fflags|O_NDELAY);
  183. #endif
  184. }
  185.  
  186.  
  187. void ttynorm(void)
  188. {    gottio = 0;
  189. #ifdef USE_NBIO
  190.     if (fcntl(ttyfd, F_SETFL, fflags) == -1)
  191.         perror("fcntl");
  192. #endif
  193. #ifndef NOTERMIO
  194. #ifndef SVR2
  195. #ifdef ultrix
  196.     /* Ultrix is broken and flushes the output as well! */
  197.     tcsetattr (ttyfd, TCSANOW, &itio);
  198. #else
  199.     tcsetattr (ttyfd, TCSAFLUSH, &itio);
  200. #endif
  201. #else
  202.     ioctl(ttyfd, TCSETAF, &itio);
  203. #endif /* not SVR2 */
  204. #else
  205.     ioctl(ttyfd, TIOCSETP, &isg);
  206. #endif
  207.     rmsigs();
  208. }
  209.  
  210. static void sig1 (int sig)
  211. {
  212. #ifndef NOTERMIO
  213. #ifndef SVR2
  214.     tcsetattr (ttyfd, TCSANOW, &itio);
  215. #else
  216.     ioctl(ttyfd, TCSETAW, &itio);
  217. #endif /* not SVR2 */
  218. #else
  219.     ioctl(ttyfd, TIOCSETP, &isg);
  220. #endif
  221.     signal (sig, SIG_DFL);
  222.     if (sig == SIGINT)
  223.         breakHandler(SIGINT);
  224.     kill (getpid(), sig);
  225. }
  226.  
  227. static void sig2 (int sig)
  228. {
  229.     if (gottio)
  230.         ttycbreak();
  231.     else
  232.         setsigs();
  233. }
  234.  
  235. static void setsigs(void)
  236. {
  237.     savesig = signal (SIGINT, sig1);
  238. #ifdef    SIGTSTP
  239.     signal (SIGCONT, sig2);
  240.     signal (SIGTSTP, sig1);
  241. #endif
  242. }
  243.  
  244. static void rmsigs(void)
  245. {    signal (SIGINT, savesig);
  246. #ifdef    SIGTSTP
  247.     signal (SIGCONT, SIG_DFL);
  248.     signal (SIGTSTP, SIG_DFL);
  249. #endif
  250. }
  251.  
  252. #ifdef NEED_KBHIT
  253. #ifndef CRUDE
  254. int kbhit(void)
  255. /* Return TRUE if there is a key to be read */
  256. {
  257. #ifdef USE_SELECT        /* use select() system call */
  258.     struct timeval t;
  259.     fd_set n;
  260.     int r;
  261.  
  262.     timerclear(&t);
  263.     FD_ZERO(&n);
  264.     FD_SET(ttyfd, &n);
  265.     r = select(32, &n, NULL, NULL, &t);
  266.     if (r == -1) {
  267.         perror("select");
  268.         exitPGP(1);
  269.     }
  270.     return r > 0;
  271. #else
  272. #ifdef    USE_NBIO        /* use non-blocking read() */
  273.     unsigned char ch;
  274.     if (kbuf >= 0) 
  275.         return(1);
  276.     if (read(ttyfd, &ch, 1) == 1) {
  277.         kbuf = ch;
  278.         return(1);
  279.     }
  280.     return(0);
  281. #else
  282.     long lf;
  283.     if (ioctl(ttyfd, FIONREAD, &lf) == -1) {
  284.         perror("ioctl: FIONREAD");
  285.         exitPGP(1);
  286.     }
  287.     return(lf);
  288. #endif
  289. #endif
  290. }
  291. #endif    /* !CRUDE */
  292. #endif
  293.  
  294. int getch(void)
  295. {
  296.     char c;
  297. #ifdef USE_NBIO
  298.     while (!kbhit());    /* kbhit() does the reading */
  299.     c = kbuf;
  300.     kbuf = -1;
  301. #else
  302.     read(ttyfd, &c, 1);
  303. #endif
  304.     return(c);
  305. }
  306.  
  307. #if defined(_BSD) && !defined(__STDC__)
  308.  
  309. VOID *memset(s, c, n)
  310. VOID *s;
  311. register int c, n;
  312. {
  313.     register char *p = s;
  314.     ++n;
  315.     while (--n)
  316.         *p++ = c;
  317.     return(s);
  318. }
  319. int memcmp(s1, s2, n)
  320. register unsigned char *s1, *s2;
  321. register int n;
  322. {
  323.     if (!n)
  324.         return(0);
  325.     while (--n && *s1 == *s2) {
  326.         ++s1;
  327.         ++s2;
  328.     }
  329.     return(*s1 - *s2);
  330. }
  331. VOID *memcpy(s1, s2, n)
  332. register char *s1, *s2;
  333. register int n;
  334. {
  335.     char *p = s1;
  336.     ++n;
  337.     while (--n)
  338.         *s1++ = *s2++;
  339.     return(p);
  340. }
  341. #endif /* _BSD */
  342.  
  343. #if (defined(MACH) || defined(SVR2) || defined(_BSD)) && !defined(NEXT) \
  344. && !defined(AUX) && !defined(__MACHTEN__) || (defined(sun) && defined(i386))
  345. int remove(name)
  346. char *name;
  347. {
  348.     return unlink(name);
  349. }
  350. #endif
  351.  
  352. #if defined(SVR2) && !defined(AUX)
  353. int rename(old, new)
  354. register char *old, *new;
  355. {
  356.     unlink(new);
  357.     if (link(old, new) < 0)
  358.         return -1;
  359.     if (unlink(old) < 0) {
  360.         unlink(new);
  361.         return -1;
  362.     }
  363.     return 0;
  364. }
  365. #endif /* SVR2 */
  366.  
  367. /* not all unices have clock() */
  368. long
  369. Clock()    /* not a replacement for clock(), just for random number generation */
  370. {
  371. #if defined(_BSD) || (defined(sun) && !defined(SOLARIS)) || \
  372. defined(MACH) || defined(linux)
  373. #include <sys/time.h>
  374. #include <sys/resource.h>
  375.     struct rusage ru;
  376.  
  377.     getrusage(RUSAGE_SELF, &ru);
  378.     return ru.ru_utime.tv_sec + ru.ru_utime.tv_usec +
  379.         ru.ru_stime.tv_sec + ru.ru_stime.tv_usec +
  380.         ru.ru_minflt + ru.ru_majflt +
  381.         ru.ru_inblock + ru.ru_oublock +
  382.         ru.ru_maxrss + ru.ru_nvcsw + ru.ru_nivcsw;
  383.  
  384. #else    /* no getrusage() */
  385. #include <sys/times.h>
  386.     struct tms tms;
  387.  
  388.     times(&tms);
  389.     return(tms.tms_utime + tms.tms_stime);
  390. #endif
  391. }
  392. #endif /* UNIX */
  393.  
  394.  
  395. /*===========================================================================*/
  396. /*
  397.  * VMS
  398.  */
  399.  
  400. #ifdef VMS            /* kbhit()/getch() equivalent */
  401.  
  402. /*
  403.  * This code defines an equivalent version of kbhit() and getch() for
  404.  * use under VAX/VMS, together with an exit handler to reset terminal
  405.  * characteristics.
  406.  *
  407.  * This code assumes that kbhit() has been invoked to test that there
  408.  * are characters in the typeahead buffer before getch() is invoked to
  409.  * get the answer.
  410.  */
  411.  
  412. #include <signal.h>
  413. #include <string.h>
  414. #include <file.h>
  415. #include <ctype.h>
  416. #include "pgp.h"
  417. #include "mpilib.h"
  418. #include "mpiio.h"
  419. #include "fileio.h"
  420. extern byte textbuf[DISKBUFSIZE];   /*    Defined in FILEIO.C */
  421.  
  422. /*      
  423. **  VMS Private Macros
  424. */      
  425. #include <descrip.h>
  426. #include <devdef>
  427. #include <iodef.h>
  428. #include <ttdef.h>
  429. #include <tt2def.h>
  430. #include <dcdef.h>
  431. #include <climsgdef.h>
  432. #include <rms.h>
  433. #include <hlpdef.h>
  434.  
  435. #define MAX_CMDSIZ    256  /*  Maximum command size */
  436. #define MAX_FILENM    255 /* Mamimum file name size */
  437.  
  438. #define FDL$M_FDL_STRING    2        /* Use string for fdl text */
  439. #define FDLSIZE            4096    /* Maximum possible file size */
  440.  
  441. #ifdef _USEDCL_
  442.  
  443. /*
  444.  * Declare some external procedure prototypes (saves me confusion!)
  445.  */
  446. extern int lib$get_input(
  447.         struct dsc$descriptor *resultant,
  448.         struct dsc$descriptor *prompt, 
  449.         unsigned short *resultant_length);
  450. extern int lib$put_output(
  451.         struct dsc$descriptor *output);
  452. extern int lib$sig_to_ret();
  453. /*      
  454. **  The CLI routines are documented in the system routines manual.
  455. */      
  456. extern int cli$dcl_parse(
  457.         struct dsc$descriptor *command,
  458.         char cmd_table[],
  459.         int (*get_command)(
  460.         struct dsc$descriptor *resultant,
  461.         struct dsc$descriptor *prompt, 
  462.         unsigned short *resultant_length),
  463.         int (*get_parameter)(
  464.         struct dsc$descriptor *resultant,
  465.         struct dsc$descriptor *prompt, 
  466.         unsigned short *resultant_length),
  467.         struct dsc$descriptor *prompt);
  468. extern int cli$present( struct dsc$descriptor *object);
  469. extern int cli$_get_value(
  470.         struct dsc$descriptor *object,
  471.         struct dsc$decsriptor *value,
  472.         unsigned short *value_len);
  473. /*
  474.  * Static Data
  475.  */
  476. static $DESCRIPTOR (cmdprmt_d, "DROPSAFE> ");  /*  Prompt string */
  477.  
  478. #endif /* _USEDCL_ */
  479.  
  480. static volatile short    _kbhitChan_ = 0;
  481.  
  482. static volatile struct IOSB {
  483.     unsigned short sts;
  484.     unsigned short byteCount;
  485.     unsigned short terminator;
  486.     unsigned short terminatorSize;
  487.     } iosb;
  488.  
  489. static $DESCRIPTOR (kbdev_desc, "SYS$COMMAND:");
  490.  
  491. static volatile struct {
  492.     char Class;
  493.     char Type;
  494.     unsigned short BufferSize;
  495.     unsigned int Mode;
  496.     int ExtChar;
  497.   } CharBuf, OldCharBuf;
  498.  
  499. static $DESCRIPTOR (out_file_descr, "SYS$DISK:[]"); /* Default Output
  500.                                File Descr */
  501.  
  502. static int flags = FDL$M_FDL_STRING;
  503.  
  504. /*
  505.  * **-kbhit_handler-This exit handler restores the terminal characteristics
  506.  *
  507.  * Description:
  508.  *
  509.  * This procedure is invoked to return the the terminal to normality (depends
  510.  * on what you think is normal!). Anyway, it gets called to restore
  511.  * characteristics either through ttynorm or via an exit handler.
  512.  */
  513. static void kbhit_handler(int *sts)
  514. {
  515.   ttynorm();
  516.   (void) sys$dassgn (
  517.       _kbhitChan_);
  518.   _kbhitChan_ = 0;
  519. }
  520.  
  521. /*
  522.  * Data Structures For Linking Up Exit Handler 
  523.  */
  524. unsigned int exsts;
  525.  
  526. static struct {
  527.     int link;
  528.     VOID *rtn;
  529.     int argcnt;
  530.     int *stsaddr;
  531.    } exhblk = { 0, &(kbhit_handler), 1, &(exsts)};
  532. /*
  533.  * **-kbhit_Getchn-Get Channel
  534.  *
  535.  * Functional Description:
  536.  *
  537.  * Private routine to get a terminal channel and save the terminal
  538.  * characteristics.
  539.  *
  540.  * Arguments:
  541.  *
  542.  *  None.
  543.  *
  544.  * Returns:
  545.  *
  546.  *  If 0, channel already assigned. If odd, then assign was successful
  547.  * otherwise returns VMS error status.
  548.  *
  549.  * Implicit Inputs:
  550.  *
  551.  * _kbhitChan_    Channel assigned to the terminal (if any).
  552.  *
  553.  * Implicit Outputs:
  554.  *
  555.  *  OldCharBuf    Initial terminal characteristics.
  556.  *  _kbhitChan_    Channel assigned to the terminal.
  557.  *
  558.  * Side Effects:
  559.  *
  560.  *  Establishes an exit handler to restore characteristics and deassign
  561.  * terminal channel.
  562.  */
  563. static int kbhit_Getchn()
  564. {
  565.     int sts = 0;
  566.  
  567.     if (_kbhitChan_ == 0) {
  568.     if ((sts = sys$assign (
  569.                &kbdev_desc,
  570.                &_kbhitChan_,
  571.                0,
  572.                0)) & 1) {
  573.         if ((sts = sys$qiow (
  574.                    0,
  575.                    _kbhitChan_,
  576.                    IO$_SENSEMODE,
  577.                    &iosb,
  578.                    0,
  579.                    0,
  580.                    &OldCharBuf,
  581.                    12,
  582.                    0,
  583.                    0,
  584.                    0,
  585.                    0)) & 01) sts = iosb.sts;
  586.         if (sts & 01) {
  587.           if (!(OldCharBuf.Class & DC$_TERM)) {
  588.         fprintf(stderr,"\nNot running on a terminal");
  589.         exitPGP(1);
  590.           }
  591.           (void) sys$dclexh (&exhblk);
  592.         }
  593.     }
  594.     }
  595.     return(sts);
  596. }
  597. /*      
  598.  * **-ttynorm-Restore initial terminal characteristics
  599.  *
  600.  * Functional Description:
  601.  *
  602.  * This procedure is invoked to restore the initial terminal characteristics.
  603.  */
  604. void ttynorm()
  605. /*
  606.  * Arguments:
  607.  *
  608.  *  None.
  609.  *
  610.  * Implicit Inputs:
  611.  *
  612.  *  OldCharBuf    Initial terminal characteristics.
  613.  *  _kbhitChan_    Channel assigned to the terminal.
  614.  *
  615.  * Implicit Outputs:
  616.  *
  617.  *  None.
  618.  */      
  619. {
  620.   int sts;
  621.  
  622.   if (_kbhitChan_ != 0) {
  623.       CharBuf.Mode = OldCharBuf.Mode;
  624.       CharBuf.ExtChar = OldCharBuf.ExtChar;
  625.     /*
  626.       CharBuf.Mode &= ~TT$M_NOECHO;
  627.       CharBuf.ExtChar &= ~TT2$M_PASTHRU;
  628.     */
  629.       if ((sts = sys$qiow (
  630.                    0,
  631.                    _kbhitChan_,
  632.                    IO$_SETMODE,
  633.                    &iosb,
  634.                    0,
  635.                    0,
  636.                    &OldCharBuf,
  637.                    12,
  638.                    0,
  639.                    0,
  640.                    0,
  641.                    0)) & 01) sts = iosb.sts;
  642.       if (!(sts & 01)) {
  643.         fprintf(stderr,"\nFailed to reset terminal characteristics!");
  644.         (void) lib$signal(sts);
  645.       }
  646.    }
  647.    return;
  648. }
  649. /*
  650.  * **-kbhit-Find out if a key has been pressed
  651.  *
  652.  * Description:
  653.  *
  654.  * Make the terminal noecho and sense the characters coming in by looking at
  655.  * the typeahead count. Note that the character remains in the typeahead buffer
  656.  * untill either read, or that the user types a Control-X when not in 'passall'
  657.  * mode.
  658.  */
  659. int kbhit()
  660. /*
  661.  * Arguments:
  662.  *
  663.  *  None.
  664.  *
  665.  * Returns:
  666.  *
  667.  *  TRUE  if there is a character in the typeahead buffer.
  668.  *  FALSE if there is no character in the typeahead buffer.
  669.  */
  670.  
  671.  
  672. {
  673.   int sts;
  674.  
  675.   struct {
  676.     unsigned short TypAhdCnt;
  677.     char FirstChar;
  678.     char Reserved[5];
  679.   } TypCharBuf;
  680.  
  681.   /*
  682.   **  Get typeahead count
  683.   */
  684.   if ((sts = sys$qiow (
  685.                0,
  686.                _kbhitChan_,
  687.                IO$_SENSEMODE | IO$M_TYPEAHDCNT,
  688.                &iosb,
  689.                0,
  690.                0,
  691.                &TypCharBuf,
  692.                8,
  693.                0,
  694.                0,
  695.                0,
  696.                0)) & 01) sts = iosb.sts;
  697.   if (sts & 01) return(TypCharBuf.TypAhdCnt>0);
  698.   (void) lib$signal(sts);
  699.   exitPGP(1);
  700. }
  701.  
  702. static int NoTerm[2] = { 0, 0};  /*  TT Terminator Mask (Nothing) */
  703.  
  704. /*
  705.  * **-getch-Get a character and return it
  706.  *
  707.  * Description:
  708.  *
  709.  * Get a character from the keyboard and return it. Unlike Unix, the character
  710.  * will be explicitly echoed unless ttycbreak() has been called first. If the
  711.  * character is in the typeahead, that will be read first.
  712.  */
  713. int getch()
  714. /*
  715.  * Arguments:
  716.  *
  717.  *  None.
  718.  *
  719.  * Returns:
  720.  *
  721.  *  Character Read.
  722.  */
  723. {
  724.   unsigned int sts;
  725.   volatile char CharBuf;
  726.  
  727.   if (((sts = kbhit_Getchn()) & 01) || sts == 0) {
  728.       if ((sts = sys$qiow (
  729.                   0,
  730.                   _kbhitChan_,
  731.                   IO$_READVBLK,
  732.                   &iosb,
  733.                   0,
  734.                   0,
  735.                   &CharBuf,
  736.                   1,
  737.                   0,
  738.                   &NoTerm,
  739.                   0,
  740.                   0)) & 01) sts = iosb.sts;
  741.   }
  742.   if (sts & 01) return ((int) CharBuf);
  743.   fprintf(stderr,"\nFailed to get character");
  744.   (void) lib$signal(sts);
  745. }
  746. /*
  747.  * **-putch-Put Character To 'Console' Device
  748.  *
  749.  * This procedure is a companion to getch, outputing a character to the
  750.  * terminal with a minimum of fuss (no VAXCRTLK, no RMS!). This routine
  751.  * simply gets a channel (if there isn't one already and uses QIO to
  752.  * output.
  753.  *
  754.  */
  755. int putch(int chr)
  756. /*
  757.  * Arguments:
  758.  *  chr        Character to output.
  759.  *
  760.  * Returns:
  761.  *
  762.  *  Status return from Getchn and qio.
  763.  *
  764.  * Side Effects
  765.  *
  766.  * May assign a channel to the terminal.
  767.  */
  768. {
  769.   unsigned int sts;
  770.  
  771.   if (((sts = kbhit_Getchn()) & 01) || sts == 0) {
  772.       if ((sts = sys$qiow (
  773.                   0,
  774.                   _kbhitChan_,
  775.                   IO$_WRITEVBLK,
  776.                   &iosb,
  777.                   0,
  778.                   0,
  779.                   &chr,
  780.                   1,
  781.                   0,
  782.                   0,
  783.                   0,
  784.                   0)) & 01) sts = iosb.sts;
  785.   }
  786.   if (sts & 01) return (sts);
  787.   fprintf(stderr,"\nFailed to put character");
  788.   (void) lib$signal(sts);
  789. }
  790. /*
  791.  * **-ttycbreak-Set Unix-like Cbreak mode
  792.  *
  793.  * Functional Description:
  794.  *
  795.  * This code must be invoked to produce the Unix-like cbreak operation which
  796.  * disables echo, allows control character input.
  797.  */
  798. void ttycbreak ()
  799. /*
  800.  * Arguments:
  801.  *
  802.  *  None.
  803.  *
  804.  * Returns:
  805.  *
  806.  *  None.
  807.  *
  808.  * Side Effects
  809.  *
  810.  * May assign a channel to the terminal.
  811.  */
  812. {
  813.     struct {
  814.     unsigned short TypAhdCnt;
  815.     char FirstChar;
  816.     char Reserved[5];
  817.     } TypCharBuf;
  818.     char buf[80];
  819.     int sts;
  820.  
  821.     if (((sts = kbhit_Getchn()) & 01) || sts == 0) {
  822. /*
  823.  * Flush any typeahead before we change characteristics
  824.  */
  825.     if ((sts = sys$qiow (
  826.                    0,
  827.                    _kbhitChan_,
  828.                    IO$_SENSEMODE | IO$M_TYPEAHDCNT,
  829.                    &iosb,
  830.                    0,
  831.                    0,
  832.                    &TypCharBuf,
  833.                    8,
  834.                    0,
  835.                    0,
  836.                    0,
  837.                    0)) & 01) sts = iosb.sts;
  838.     if (sts) {
  839.         if (TypCharBuf.TypAhdCnt>0) {
  840.         if ((sts = sys$qiow (
  841.                 0,
  842.                _kbhitChan_,
  843.                IO$_READVBLK | IO$M_NOECHO | IO$M_TIMED,
  844.                &iosb,
  845.                0,
  846.                0,
  847.                &buf,
  848.                (TypCharBuf.TypAhdCnt >= 80 ? 80 :
  849.                 TypCharBuf.TypAhdCnt),
  850.                1,
  851.                &NoTerm,
  852.                0,
  853.                0)) & 01) sts = iosb.sts;
  854.                
  855.         if (sts)
  856.             TypCharBuf.TypAhdCnt -= iosb.byteCount;
  857.         }
  858.     }
  859.     if (!(sts & 01)) TypCharBuf.TypAhdCnt = 0;
  860. /*
  861.  * Modify characteristics
  862.  */
  863.     CharBuf = OldCharBuf;
  864.     CharBuf.Mode = (OldCharBuf.Mode | TT$M_NOECHO) & ~TT$M_NOTYPEAHD;
  865.     CharBuf.ExtChar = OldCharBuf.ExtChar | TT2$M_PASTHRU;
  866.     if ((sts = sys$qiow (
  867.                0,
  868.                _kbhitChan_,
  869.                IO$_SETMODE,
  870.                &iosb,
  871.                0,
  872.                0,
  873.                &CharBuf,
  874.                12,
  875.                    0,
  876.                0,
  877.                0,
  878.                0)) & 01) sts = iosb.sts;
  879.     if (!(sts & 01)) {
  880.       fprintf(stderr,
  881.           "\nttybreak()- Failed to set terminal characteristics!");
  882.       (void) lib$signal(sts);
  883.       exitPGP(1);
  884.     }
  885.     }
  886. }
  887.  
  888.  
  889. #ifdef _USEDCL_
  890.  
  891. /*
  892.  * **-vms_getcmd-Get VMS Style Foreign Command
  893.  *
  894.  * Functional Description:
  895.  *
  896.  *  Get command from VAX/VMS foreign command line interface and parse
  897.  * according to DCL rules. If the command line is ok, it can then be
  898.  * parsed according to the rules in the DCL command language table.
  899.  *
  900.  */
  901. int vms_GetCmd( char *cmdtbl)
  902. /*
  903.  * Arguments:
  904.  *
  905.  *  cmdtbl    Pointer to command table to parse.
  906.  *
  907.  * Returns:
  908.  *
  909.  *  ...TBS...
  910.  *
  911.  * Implicit Inputs:
  912.  *
  913.  *  Command language table defined in DROPDCL.CLD
  914.  */
  915. {
  916.     int sts;
  917.     char cmdbuf[MAX_CMDSIZ];
  918.     unsigned short cmdsiz;
  919.     struct dsc$descriptor cmdbuf_d = {0,0,0,0};
  920.     struct dsc$descriptor infile_d = {0,0,0,0};
  921.     char filenm[MAX_FILENM];
  922.     unsigned short filenmsiz;
  923.     unsigned short verb_size;
  924.  
  925.     /*      
  926.     **  DCL Parse Expects A Command Verb Prefixing The Argumnents
  927.     **    fake it!
  928.     */      
  929.     verb_size = cmdprmt_d.dsc$w_length - 2;  /*  Loose '> ' characters */
  930.     cmdbuf_d.dsc$w_length = MAX_CMDSIZ-verb_size-1;
  931.     cmdbuf_d.dsc$a_pointer = strncpy(cmdbuf,cmdprmt_d.dsc$a_pointer,verb_size)
  932.       +    verb_size+1;
  933.     cmdbuf[verb_size++]=' ';
  934.     if ((sts = lib$get_foreign (  /*  Recover command line from DCL */
  935.                &cmdbuf_d, 
  936.                0, 
  937.                &cmdsiz, 
  938.                0)) & 01) {
  939.     cmdbuf_d.dsc$a_pointer = cmdbuf;
  940.     cmdbuf_d.dsc$w_length = cmdsiz + verb_size;
  941.     VAXC$ESTABLISH(lib$sig_to_ret);   /*  Force unhandled exceptions
  942.                           to return */
  943.         sts = cli$dcl_parse(  /*  Parse Command Line */
  944.             &cmdbuf_d,
  945.             cmdtbl,            
  946.             lib$get_input,
  947.             lib$get_input,
  948.             &cmdprmt_d);
  949.     }
  950.     return(sts);
  951. }
  952. /*
  953.  * **-vms_TstOpt-Test for command qualifier present
  954.  *
  955.  * Functional Description:
  956.  *
  957.  * This procedure is invoked to test whether an option is present. It is
  958.  * really just a jacket routine for the system routine CLI$PRESENT
  959.  * converting the argument and result into 'C' speak.
  960.  *
  961.  */
  962. vms_TstOpt(char opt)
  963. /*
  964.  * Arguments:
  965.  *
  966.  *  opt        Character label of qualifier to test for.
  967.  *
  968.  * Returns:
  969.  *
  970.  *  +1    Option present.
  971.  *  0    Option absent.
  972.  *  -1    Option negated.
  973.  *
  974.  * Implicit Inputs:
  975.  *
  976.  * Uses DCL command line context established by vms_GetOpt.
  977.  */
  978. {
  979.     int sts;
  980.     char buf;
  981.     struct dsc$descriptor option_d = { 1, 0, 0, &buf};
  982.  
  983.     buf = _toupper(opt);
  984.     VAXC$ESTABLISH(lib$sig_to_ret);   /*  Force unhandled exceptions
  985.                       to return */
  986.     switch (sts=cli$present(&option_d))
  987.     {
  988.  
  989.     case CLI$_PRESENT :
  990.         return(1);
  991.     case CLI$_ABSENT:
  992.         return(0);
  993.     case CLI$_NEGATED:
  994.         return(-1);
  995.         default:
  996.         return(0);
  997.     }    
  998. }
  999. /*
  1000.  * **-vms_GetVal-Get Qualifier Value.
  1001.  *
  1002.  * Functional Description:
  1003.  *
  1004.  * This procedure is invoked to return the value associated with a
  1005.  * qualifier that exists (See TstOpt).
  1006.  */
  1007. vms_GetVal( char opt, char *resval, unsigned short maxsiz)
  1008. /*
  1009.  * Arguments:
  1010.  *
  1011.  *  opt        Character label of qualifier to test for.
  1012.  *  resval  Pointer to resulting value string.
  1013.  *  maxsiz  Maximum size of string.
  1014.  *
  1015.  * Returns:
  1016.  *
  1017.  *  ...TBS...
  1018.  *
  1019.  * Implicit Inputs:
  1020.  *
  1021.  * Uses DCL command line context established by vms_GetOpt.
  1022.  */
  1023. {
  1024.     int sts;
  1025.     char buf;
  1026.     struct dsc$descriptor option_d = { 1, 0, 0, &buf};
  1027.     struct dsc$descriptor value_d = {maxsiz-1, 0, 0, resval };
  1028.     unsigned short valsiz;
  1029.  
  1030.     VAXC$ESTABLISH(lib$sig_to_ret);   /*  Force unhandled exceptions
  1031.                       to return */
  1032.     buf = _toupper(opt);
  1033.     if ((sts = cli$get_value( 
  1034.         &option_d,
  1035.         &value_d,
  1036.         &valsiz)) & 01) resval[valsiz] = '\0';
  1037.     return(sts);
  1038. }
  1039. /*
  1040.  * **-vms_GetArg-Get Argument Value.
  1041.  *
  1042.  * Functional Description:
  1043.  *
  1044.  * This procedure is invoked to return the value associated with an
  1045.  * argument.
  1046.  */
  1047. vms_GetArg( unsigned short arg, char *resval, unsigned short maxsiz)
  1048. /*
  1049.  * Arguments:
  1050.  *
  1051.  *  arg        Argument Number (1-9)
  1052.  *  resval  Pointer to resulting value string.
  1053.  *  maxsiz  Maximum size of string.
  1054.  *
  1055.  * Returns:
  1056.  *
  1057.  *  ...TBS...
  1058.  *
  1059.  * Implicit Inputs:
  1060.  *
  1061.  * Uses DCL command line context established by vms_GetOpt.
  1062.  */
  1063. {
  1064.     int sts;
  1065.     char buf[2] = "P";
  1066.     struct dsc$descriptor option_d = { 2, 0, 0, buf};
  1067.     struct dsc$descriptor value_d = {maxsiz-1, 0, 0, resval };
  1068.     unsigned short valsiz;
  1069.  
  1070.     VAXC$ESTABLISH(lib$sig_to_ret);   /*  Force unhandled exceptions
  1071.                       to return */
  1072.     buf[1] = arg + '0';
  1073.     if ((sts = cli$present(&option_d)) & 01) {
  1074.     if ((sts = cli$get_value( 
  1075.         &option_d,
  1076.         &value_d,
  1077.         &valsiz)) & 01) resval[valsiz] = '\0';
  1078.     } else return(0);
  1079.     return(sts);
  1080. }
  1081.  
  1082.  
  1083.  
  1084. /*
  1085.  * **-do_help-Invoke VMS Help Processor
  1086.  *
  1087.  * Functional Description:
  1088.  *
  1089.  * This procedure is invoked to display a suitable help message to the caller
  1090.  * using the standard VMS help library.
  1091.  *
  1092.  */
  1093. do_help(char *helptext, char *helplib)
  1094. /*
  1095.  * Arguments:
  1096.  *
  1097.  *  helptext    Text of help request.
  1098.  *  helplib    Help library.
  1099.  *
  1100.  * Returns:
  1101.  *
  1102.  * As for kbhit_Getchn and lbr$output_help.
  1103.  *
  1104.  * Side Effects:
  1105.  *
  1106.  * A channel may be opened to the terminal. A library is opened.
  1107.  */
  1108. {
  1109.     int sts;
  1110.     int helpflags;
  1111.     struct dsc$descriptor helptext_d = { strlen(helptext), 0, 0, helptext};
  1112.     struct dsc$descriptor helplib_d = { strlen(helplib), 0, 0, helplib};
  1113.  
  1114.     VAXC$ESTABLISH(lib$sig_to_ret);   /*  Force unhandled
  1115.                       exceptions to return */
  1116.     if (((sts = kbhit_Getchn()) & 01) || sts == 0) {
  1117.     helpflags = HLP$M_PROMPT|HLP$M_SYSTEM|HLP$M_GROUP|HLP$M_PROCESS;    
  1118.     sts = lbr$output_help(
  1119.             lib$put_output,
  1120.             &OldCharBuf.BufferSize,
  1121.             &helptext_d,
  1122.             &helplib_d,
  1123.             &helpflags,
  1124.             lib$get_input);
  1125.     }
  1126.     return(sts);
  1127. }
  1128. #endif /* _USEDCL_ */
  1129. unsigned long    vms_clock_bits[2];    /* VMS Hardware Clock */
  1130. const long    vms_ticks_per_update = 100000L; /* Clock update int. */
  1131.  
  1132. /*
  1133.  * FDL Stuff For Getting & Setting File Characteristics
  1134.  * This code was derived (loosely!) from the module LZVIO.C in the public 
  1135.  * domain LZW compress routine as found on the DECUS VAX SIG tapes (no author
  1136.  * given, so no credits!) 
  1137.  */
  1138.  
  1139. /*
  1140.  * **-fdl_generate-Generate An FDL
  1141.  *
  1142.  * Description:
  1143.  *
  1144.  * This procedure takes the name of an existing file as input and creates
  1145.  * an fdl. The FDL is retuned by pointer and length. The FDL space should be
  1146.  * released after use with a call to free();
  1147.  */
  1148. int fdl_generate(char *in_file, char **fdl, short *len)
  1149. /*
  1150.  * Arguments:
  1151.  *
  1152.  *    in_file        char*   Filename of file to examine (Zero terminated).
  1153.  *
  1154.  *    fdl        char*   Pointer to FDL that was created.
  1155.  *
  1156.  *    len        short   Length of FDL created.
  1157.  *
  1158.  * Status Returns:
  1159.  *
  1160.  * VMS style. lower bit set means success.
  1161.  */
  1162. {
  1163.  
  1164.     struct dsc$descriptor fdl_descr = { 0,
  1165.                 DSC$K_DTYPE_T,
  1166.                 DSC$K_CLASS_D,
  1167.                 0};
  1168.     struct FAB fab, *fab_addr;
  1169.     struct RAB rab, *rab_addr;
  1170.     struct NAM nam;
  1171.     struct XABFHC xab;
  1172.     int sts;
  1173.     int badblk;
  1174.  
  1175. /*
  1176.  * Build FDL Descriptor
  1177.  */
  1178.     if (!(sts = str$get1_dx(&FDLSIZE,&fdl_descr)) & 01) return(0);
  1179. /*
  1180.  * Build RMS Data Structures
  1181.  */
  1182.     fab = cc$rms_fab;
  1183.     fab_addr = &fab;
  1184.     nam = cc$rms_nam;
  1185.     rab = cc$rms_rab;
  1186.     rab_addr = &rab;
  1187.     xab = cc$rms_xabfhc;
  1188.     fab.fab$l_nam = &nam;
  1189.     fab.fab$l_xab = &xab;
  1190.     fab.fab$l_fna = in_file;
  1191.     fab.fab$b_fns = strlen(in_file);
  1192.     rab.rab$l_fab = &fab;
  1193.     fab.fab$b_fac = FAB$M_GET | FAB$M_BIO; /* This open block mode only */
  1194. /*
  1195.  * Attempt to Open File
  1196.  */
  1197.     if (!((sts = sys$open(&fab)) & 01)) {
  1198.     if (verbose) {
  1199.         fprintf(stderr,"\n(SYSTEM) Failed to $OPEN %s\n",in_file);
  1200.         (void) lib$signal(fab.fab$l_sts,fab.fab$l_stv);
  1201.     }
  1202.     return(sts);
  1203.     }
  1204.     if (fab.fab$l_dev & DEV$M_REC) {
  1205.     fprintf(stderr,"\n(SYSTEM) Attempt to read from output only device\n");
  1206.     sts = 0;
  1207.     } else {
  1208.     rab.rab$l_rop = RAB$M_BIO;
  1209.     if (!((sts = sys$connect(&rab)) & 01)) {
  1210.         if (verbose) {
  1211.         fprintf(stderr,"\n(SYSTEM) Failed to $CONNECT %s\n",in_file);
  1212.         (void) lib$signal(fab.fab$l_sts,fab.fab$l_stv);
  1213.         }
  1214.     } else {
  1215.         if (!((sts = fdl$generate(
  1216.             &flags,
  1217.             &fab_addr,
  1218.             &rab_addr,
  1219.             NULL,NULL,
  1220.             &fdl_descr,
  1221.             &badblk,
  1222.             len)) & 01)) {
  1223.         if (verbose)
  1224.           fprintf(stderr,"\n(SYSTEM) Failed to generate FDL\n",
  1225.               in_file);
  1226.         free(fdl);
  1227.         } else {
  1228.         if (!(*fdl = malloc(*len))) return(0);
  1229.         memcpy(*fdl,fdl_descr.dsc$a_pointer,*len);
  1230.         }
  1231.         (void) str$free1_dx(&fdl_descr);
  1232.     }
  1233.         sys$close(&fab);
  1234.     }
  1235.     return(sts);        
  1236. }
  1237.  
  1238. /*      
  1239.  * **-fdl_close-Closes files created by fdl_generate
  1240.  *  
  1241.  * Description:
  1242.  *
  1243.  * This procedure is invoked to close the file and release the data structures
  1244.  * allocated by fdl$parse.
  1245.  */
  1246. void fdl_close(void* rab)
  1247. /*
  1248.  * Arguments:
  1249.  *
  1250.  *    rab    VOID *    Pointer to RAB (voided to avoid problems for caller).
  1251.  *
  1252.  * Returns:
  1253.  *
  1254.  *    None.
  1255.  */
  1256. {
  1257.     struct FAB *fab;
  1258.  
  1259.     fab = ((struct RAB *) rab)->rab$l_fab;
  1260.     if (fab) {  /*  Close file if not already closed */
  1261.     if (fab->fab$w_ifi) sys$close(fab);
  1262.     }
  1263.     fdl$release( NULL, &rab);      
  1264. }
  1265.  
  1266. /*
  1267.  * **-fdl_create-Create A File Using the recorded FDL (hope we get it right!)
  1268.  *
  1269.  * Description:
  1270.  *
  1271.  * This procedure accepts an FDL and uses it create a file. Unfortunately
  1272.  * there is no way we can easily patch into the back of the VAX C I/O
  1273.  * subsystem.
  1274.  */
  1275. VOID * fdl_create( char *fdl, short len, char *outfile, char *preserved_name)
  1276. /*
  1277.  * Arguments:
  1278.  *
  1279.  *    fdl    char*    FDL string descriptor.
  1280.  *
  1281.  *    len    short    Returned string length.
  1282.  *
  1283.  *    outfile    char*    Output filename.
  1284.  *
  1285.  *    preserved_name char*    Name from FDL.
  1286.  *
  1287.  * Returns:
  1288.  *
  1289.  *     0 in case of error, or otherwise the RAB pointer.
  1290.  */
  1291. {
  1292.     VOID *sts;
  1293.     int sts2;
  1294.     struct FAB *fab;
  1295.     struct RAB *rab;
  1296.     struct NAM nam;
  1297.     int badblk;
  1298.     char *resnam;
  1299.  
  1300.     struct dsc$descriptor fdl_descr = {
  1301.                 len,
  1302.                 DSC$K_DTYPE_T,
  1303.                 DSC$K_CLASS_S,
  1304.                 fdl
  1305.                 };
  1306.  
  1307.     sts = NULL;
  1308. /*
  1309.  * Initialize RMS NAM Block
  1310.  */
  1311.     nam = cc$rms_nam;
  1312.     nam.nam$b_rss = NAM$C_MAXRSSLCL;
  1313.     nam.nam$b_ess = NAM$C_MAXRSSLCL;
  1314.     if (!(resnam = nam.nam$l_esa = malloc(NAM$C_MAXRSSLCL+1))) {
  1315.     fprintf(stderr,"\n(FDL_CREATE) Out of memory!\n");
  1316.     return(NULL);
  1317.     }
  1318. /*
  1319.  * Parse FDL
  1320.  */
  1321.     if (!((sts2 = fdl$parse( &fdl_descr,
  1322.                 &fab,
  1323.                 &rab,
  1324.                 &flags)) & 01)) {
  1325.     fprintf(stderr,"\nCreating (fdl$parse)\n");
  1326.     (void) lib$signal(sts2);
  1327.     } else {
  1328. /*
  1329.  * Extract & Return Name of FDL Supplied Filename
  1330.  */
  1331.     memcpy (preserved_name,fab->fab$l_fna,fab->fab$b_fns);
  1332.     preserved_name[fab->fab$b_fns] = '\0';
  1333. /*
  1334.  * Set Name Of Temporary File
  1335.  */
  1336.     fab->fab$l_fna = outfile;
  1337.     fab->fab$b_fns = strlen(outfile);
  1338. /*
  1339.  * Connect NAM Block
  1340.  */
  1341.     fab->fab$l_nam = &nam;
  1342.     fab->fab$l_fop |= FAB$M_NAM | FAB$M_CIF;
  1343.     fab->fab$b_fac |= FAB$M_BIO | FAB$M_PUT;
  1344. /*
  1345.  * Create File
  1346.  */
  1347.     if (!(sys$create(fab) & 01)) {
  1348.         fprintf(stderr,"\nCreating (RMS)\n");
  1349.         (void) lib$signal(fab->fab$l_sts,fab->fab$l_stv);
  1350.         fdl_close(rab);
  1351.     } else {
  1352.         if (verbose) {
  1353.         resnam[nam.nam$b_esl+1] = '\0';
  1354.         fprintf(stderr,"\nCreated %s successfully\n",resnam);
  1355.         }
  1356.         rab->rab$l_rop = RAB$M_BIO;
  1357.         if (!(sys$connect(rab) & 01)) {
  1358.         fprintf(stderr,"\nConnecting (RMS)\n");
  1359.         (void) lib$signal(rab->rab$l_sts,rab->rab$l_stv);
  1360.         fdl_close(rab);
  1361.         } else sts = rab;
  1362.     }
  1363.     fab->fab$l_nam = 0; /* I allocated NAM block,
  1364.                    so I must deallocate it! */
  1365.     }
  1366.     free(resnam);
  1367.     return(sts);        
  1368. }
  1369.  
  1370. /*
  1371.  * **-fdl_copyfile2bin-Copies the input file to a 'binary' output file
  1372.  *
  1373.  * Description:
  1374.  *
  1375.  * This procedure is invoked to copy from an opened file f to a file opened
  1376.  * directly through RMS. This allows us to make a block copy into one of the
  1377.  * many esoteric RMS file types thus preserving characteristics without blowing
  1378.  * up the C RTL. This code is based directly on copyfile from FILEIO.C.
  1379.  *
  1380.  * Calling Sequence:
  1381.  */
  1382. int fdl_copyfile2bin( FILE *f, VOID *rab, word32 longcount)
  1383. /*
  1384.  * Arguments:
  1385.  *
  1386.  *    f        FILE*    Pointer to input file
  1387.  *
  1388.  *    rab        RAB*    Pointer to output file RAB
  1389.  * 
  1390.  *    longcount   word32    Size of file
  1391.  *
  1392.  * Returns:
  1393.  *
  1394.  *    0   If we were successful.
  1395.  *    -1  We had an error on the input file (VAXCRTL).
  1396.  *    +1  We had an error on the output file (direct RMS).
  1397.  */
  1398. {
  1399.     int status = 0;
  1400.     word32 count;
  1401.     ((struct RAB *) rab)->rab$l_rbf = &textbuf;
  1402.     ((struct RAB *) rab)->rab$l_bkt = 0;
  1403.     do { /*  Read and write longcount bytes */
  1404.     if (longcount < (word32) DISKBUFSIZE)
  1405.         count = longcount;
  1406.     else
  1407.         count = DISKBUFSIZE;
  1408.     count = fread(textbuf,1,count,f);
  1409.     if (count > 0) {
  1410. /*      
  1411.  *  No byte order conversion required, source and target system are both
  1412.  *  VMS so have the same byte ordering.
  1413.  */      
  1414.         ((struct RAB *) rab)->rab$w_rsz = (unsigned short) count;
  1415.         if (!(sys$write (
  1416.                rab, 
  1417.                NULL, 
  1418.                NULL) & 01)) {
  1419.           lib$signal(((struct RAB *) rab)->rab$l_sts,
  1420.                  ((struct RAB *) rab)->rab$l_stv);
  1421.           status = 1;
  1422.           break;
  1423.         }
  1424.         longcount -= count;
  1425.     }
  1426.     } while (count==DISKBUFSIZE);
  1427.     burn(textbuf);
  1428.     return(status);
  1429. }
  1430. /*
  1431.  * **-vms_fileparse-Parse A VMS File Specification
  1432.  *
  1433.  * Functional Description:
  1434.  *
  1435.  * This procedure is invoked to parse a VMS file specification using default 
  1436.  * and related specifications to fill in any missing components. This works a 
  1437.  * little like DCL's F$PARSE function with the syntax check only specified
  1438.  * (that is we don't check the device or the directory). The related file
  1439.  * spec is really for when we want to use the name of an input file (w/o the
  1440.  * directory) to supply the name of an output file.
  1441.  *
  1442.  * Note that we correctly handle the situation where the output buffer overlays
  1443.  * the input filespec by testing for the case and then handling it by copying
  1444.  * the primary input specification to a temporary buffer before parsing.
  1445.  */
  1446. int vms_fileparse( char *outbuf, char *filespec, char *defspec, char *relspec)
  1447. /*
  1448.  * Arguments:
  1449.  *
  1450.  *  outbuf    Returned file specification.
  1451.  *  filespec    Primary file specification (optional).
  1452.  *  defspec    Default file specification (optional).
  1453.  *  relspec    Related file specification (optional).
  1454.  *
  1455.  * Returns:
  1456.  *
  1457.  *  As for SYS$PARSE.
  1458.  *
  1459.  * Implicit Inputs:
  1460.  *
  1461.  *  None.
  1462.  *
  1463.  * Implicit Outputs:
  1464.  *
  1465.  *  None.
  1466.  *
  1467.  * Side Effects:
  1468.  *
  1469.  *  ...TBS...
  1470.  */
  1471. {
  1472.     struct FAB fab = cc$rms_fab;
  1473.     struct NAM nam = cc$rms_nam;
  1474.     struct NAM rlnam = cc$rms_nam;
  1475.     int sts = 1;
  1476.     int len;
  1477.     char tmpbuf[NAM$C_MAXRSSLCL];
  1478.     char expfnam2[NAM$C_MAXRSSLCL];
  1479.  
  1480.     if (outbuf != NULL) {
  1481.     outbuf[0] = '\0';
  1482.     fab.fab$l_fop != FAB$M_NAM;  /*  Enable RMS NAM block processing */
  1483.     nam.nam$b_nop |= NAM$M_PWD | NAM$M_SYNCHK;
  1484.     /*      
  1485.     **  Handle Related Spec (If reqd).
  1486.     */      
  1487.     if (relspec != NULL) {
  1488.         if ((len = strlen(relspec)) > 0) {
  1489.         fab.fab$l_nam = &rlnam;
  1490.         fab.fab$b_fns = len;
  1491.         fab.fab$l_fna = relspec;
  1492.         rlnam.nam$b_ess = NAM$C_MAXRSSLCL;
  1493.         rlnam.nam$l_esa = expfnam2;
  1494.         rlnam.nam$b_nop |= NAM$M_PWD | NAM$M_SYNCHK;
  1495.         if ((sts = sys$parse (
  1496.                 &fab, 
  1497.                 0, 
  1498.                 0)) & 01) {
  1499.             rlnam.nam$l_rsa = rlnam.nam$l_esa;
  1500.             rlnam.nam$b_rsl = rlnam.nam$b_esl;
  1501.             nam.nam$l_rlf = &rlnam;
  1502.             fab.fab$l_fop |= FAB$M_OFP;
  1503.         }
  1504.         }
  1505.     }
  1506.     if (sts) {
  1507.         fab.fab$l_nam = &nam;
  1508.         nam.nam$l_esa = outbuf;
  1509.         nam.nam$b_ess = NAM$C_MAXRSSLCL;
  1510.         /*      
  1511.         **  Process Default Specification:
  1512.         */      
  1513.         if (defspec != NULL) {
  1514.         if ((len = strlen(defspec)) > 0) {
  1515.             fab.fab$l_dna = defspec;
  1516.             fab.fab$b_dns = len;
  1517.         }
  1518.         }
  1519.         /*      
  1520.         **  Process Main File Specification:
  1521.         */      
  1522.         fab.fab$l_fna = NULL;
  1523.         fab.fab$b_fns = 0;
  1524.         if (filespec != NULL) {
  1525.         if ((len = strlen(filespec)) > 0) {
  1526.             fab.fab$b_fns = len;
  1527.             if (filespec == outbuf)
  1528.             fab.fab$l_fna = memcpy(tmpbuf,filespec,len);
  1529.             else
  1530.             fab.fab$l_fna = filespec;
  1531.         }
  1532.         }
  1533.         if ((sts = sys$parse(
  1534.                &fab, 
  1535.                0, 
  1536.                0)) && 01) outbuf[nam.nam$b_esl] = '\0';
  1537.     }
  1538.     }
  1539.     return (sts);
  1540. }
  1541. #endif /* VMS */
  1542.  
  1543.  
  1544. /*
  1545.  * ------------------------- Amiga specific routines -------------------------
  1546.  */
  1547.  
  1548. #ifdef AMIGA
  1549.  
  1550. #include <time.h>
  1551. #include <dos/var.h>
  1552. #include <exec/memory.h>
  1553. #include <exec/ports.h>
  1554. #include <exec/types.h>
  1555. #include <libraries/dosextens.h>
  1556. #include <libraries/reqtools.h>
  1557. #include <proto/dos.h> 
  1558. #include <proto/exec.h>
  1559. #include <proto/reqtools.h>
  1560. #include "pgp.h"
  1561.  
  1562. /*
  1563.  * This getenv will use the WB2.0 calls if you have the 2.0
  1564.  * rom. If not, it resorts to looking in the ENV: directory.
  1565.  */
  1566.  
  1567. char *getenv(const char *name)
  1568. {
  1569.         FILE *fp;
  1570.         char *ptr;
  1571.         static char value[256];
  1572.         static char buf[256];
  1573.  
  1574.         /*
  1575.          * 2.0 style?
  1576.          */
  1577.         if (DOSBase->dl_lib.lib_Version >= 36) {
  1578.                 if (GetVar((char *) name, value, 256, 0L) == -1)
  1579.                         return NULL;
  1580.         }
  1581.         else {
  1582.                 if (strlen(name) > 252)
  1583.                         return NULL;
  1584.                 strcpy(buf, "ENV:");
  1585.                 strcpy(&buf[4], name);
  1586.                 if (!(fp = fopen(buf, "r")))
  1587.                         return NULL;
  1588.                 for (ptr = value; (*ptr = getc(fp)) != EOF
  1589.                      && *ptr != '\n'
  1590.                      && ++ptr < &value[256];) ;
  1591.                 fclose(fp);
  1592.                 *ptr = 0;
  1593.         }
  1594.         return value;
  1595. }
  1596.  
  1597.  
  1598. extern FILE *pgpout;
  1599. char *requesterdesc;
  1600.  
  1601. /*
  1602.  * AmigaRequestString() is a trick to make PGP more usable from scripts.
  1603.  * The problem is, that most scripts don't allow user interaction over
  1604.  * the standard input. The same problem occurs when working in filter mode.
  1605.  *
  1606.  * This routine will be called by PGP's getstring() whenever user input
  1607.  * is requested but the standard input is not interactive. Because the
  1608.  * routine can't know what string to ask for, I added the Amiga-specific
  1609.  * variable requesterdesc, which holds the last string printed to pgpout
  1610.  * before getstring was called.
  1611.  *
  1612.  * This solution is not pretty, but it works.
  1613.  *                                                      Peter Simons
  1614.  */
  1615.  
  1616. int AmigaRequestString(char *buffer, int maxlen, int echo)
  1617. {
  1618.         struct ReqToolsBase *ReqToolsBase;
  1619.         struct TagItem ti[] = {
  1620.                 {RTGS_Invisible, FALSE},
  1621.                 {RTGS_TextFmt, 0L},
  1622.                 {RTGS_Flags, GSREQF_CENTERTEXT},
  1623.                 {TAG_DONE, 0L}
  1624.         };
  1625.         int len = 0;
  1626.         char name[64];
  1627.  
  1628.         if (!maxlen)
  1629.                 return 0;
  1630.         if (!echo)
  1631.                 ti[0].ti_Data = TRUE;
  1632.         ti[1].ti_Data = (ULONG) (requesterdesc) ? ((*requesterdesc == '\n') ? requesterdesc+1 : requesterdesc) : "Please enter required string";
  1633.                                 /* This one is tricky, too. Because of the format of the
  1634.                                  * LANG() module we have a prefacing return before most
  1635.                                  * strings, which will make our beautiful requester look
  1636.                                  * a bit stupid. This way, we get rid of it. :-)
  1637.                                  */
  1638.         sprintf(name, "PGPAmiga %s", rel_version);
  1639.  
  1640.         if (ReqToolsBase = (struct ReqToolsBase *) OpenLibrary(REQTOOLSNAME, 38L))
  1641.         {
  1642.                 *buffer = '\0';
  1643.                 if (rtGetStringA(buffer, maxlen, name, NULL, ti))
  1644.                         len = strlen(buffer);
  1645.                 CloseLibrary((struct Library *) ReqToolsBase);
  1646.         }
  1647.         else
  1648.         {  fprintf(stderr,"Could not open ReqTools.library!  Try using PGP "
  1649.                    "without -f.\n");
  1650.            exitPGP(7);   /* Error exit */
  1651.         }
  1652.         requesterdesc=NULL;   /* Program will re-set it before next getstring() call */
  1653.         return len;
  1654. }
  1655.  
  1656. sendpacket(struct MsgPort *rec,LONG action,LONG arg1) 
  1657. {
  1658.   struct StandardPacket *pkt;
  1659.   struct MsgPort *rp;
  1660.   LONG res1 = 0L;
  1661.  
  1662.   if (rp = (struct MsgPort *)CreatePort(NULL,0L)) {
  1663.     if (pkt = (struct StandardPacket *)\
  1664.      AllocMem(sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR)) {
  1665.        pkt->sp_Msg.mn_Node.ln_Name = (BYTE *)&pkt->sp_Pkt;
  1666.        pkt->sp_Pkt.dp_Link = &pkt->sp_Msg;
  1667.        pkt->sp_Pkt.dp_Port = rp;
  1668.        pkt->sp_Pkt.dp_Type = action;
  1669.        pkt->sp_Pkt.dp_Arg1 = arg1;
  1670.        PutMsg(rec,&pkt->sp_Msg);
  1671.        WaitPort(rp);
  1672.        GetMsg(rp);
  1673.        res1 = pkt->sp_Pkt.dp_Res1;
  1674.        FreeMem((UBYTE*)pkt,sizeof(struct StandardPacket));
  1675.      }
  1676.      DeletePort(rp);
  1677.     }
  1678.     return(res1);
  1679.  
  1680. }
  1681.  
  1682. void ttycbreak()
  1683. {
  1684.   struct MsgPort *ch;
  1685.  
  1686.   ch = ((struct FileHandle *)BADDR(Input()))->fh_Type;
  1687.   sendpacket(ch,ACTION_SCREEN_MODE,-1L);
  1688. }
  1689.  
  1690. void ttynorm()
  1691. {
  1692.   struct MsgPort *ch;
  1693.  
  1694.   ch = ((struct FileHandle *)BADDR(Input()))->fh_Type;
  1695.   sendpacket(ch,ACTION_SCREEN_MODE,0L);
  1696. }
  1697.  
  1698. int getch(void)
  1699. {
  1700.   char buf;
  1701.  
  1702.   Read(Input(),&buf,1);
  1703.   return((int)buf);
  1704. }
  1705.  
  1706. int kbhit() 
  1707. {
  1708.   if(WaitForChar(Input(), 1)) return 1;
  1709.   return 0;
  1710. }
  1711.  
  1712. #ifdef __SASC
  1713.  
  1714. /*
  1715.  * SAS/C CTRL-C handler
  1716.  */
  1717.  
  1718. void __regargs _CXBRK(void)
  1719. {
  1720.   struct MsgPort *ch;
  1721.  
  1722.   /* it might happen we catch a ^C while in cbreak mode.
  1723.    * so always set the screen to the normal mode.
  1724.   */
  1725.  
  1726.   ch = ((struct FileHandle *)BADDR(Input()))->fh_Type;
  1727.   sendpacket(ch, ACTION_SCREEN_MODE, 0L);
  1728.  
  1729.  
  1730.   fprintf(pgpout, "\n*** Program Aborted.\n");
  1731.   exitPGP(6); /* INTERRUPT */
  1732. }
  1733. #endif    /* __SASC */
  1734.  
  1735. #endif /* AMIGA */
  1736.  
  1737.  
  1738. /*===========================================================================*/
  1739. /*
  1740.  * other stuff for non-MSDOS systems
  1741.  */
  1742.  
  1743. #ifdef ATARI
  1744. #include <osbind.h>        /* use GEMDOS functions for I/O */
  1745.  
  1746. int kbhit(void)
  1747. {
  1748.     return Cconis();    /* ret == 0 : no char available */
  1749. }
  1750.  
  1751. int getch(void)
  1752. {
  1753.     return (Cnecin() & 0x000000FF);    /* ASCII-Code in Bits 0..7   */
  1754. }                    /* Scan-Codes in Bits 16..23 */
  1755. #endif /* ATARI */
  1756.  
  1757. #if !defined(MSDOS) && !defined(ATARI)
  1758. #include <ctype.h>
  1759. #include "charset.h"
  1760. char *strlwr(char *s)
  1761. {    /*
  1762.     **        Turns string s into lower case.
  1763.     */
  1764.     int c;
  1765.     char *p = s;
  1766.     while (c = *p)
  1767.         *p++ = to_lower(c);
  1768.     return(s);
  1769. }
  1770. #endif /* !MSDOS && !ATARI */
  1771.  
  1772.  
  1773. #ifdef strstr
  1774. #undef strstr
  1775. /* Not implemented on some systems - return first instance of s2 in s1 */
  1776. char *mystrstr (char *s1, char *s2)
  1777. {    int i;
  1778.     char *strchr();
  1779.  
  1780.     if (!s2 || !*s2)
  1781.         return s1;
  1782.     for ( ; ; )
  1783.     {    if (!(s1 = strchr (s1, *s2)))
  1784.             return s1;
  1785.         for (i=1; s2[i] && (s1[i]==s2[i]); ++i)
  1786.             ;
  1787.         if (!s2[i])
  1788.             return s1;
  1789.         ++s1;
  1790.     }
  1791. }
  1792. #endif /* strstr */
  1793.  
  1794.  
  1795. #ifdef fopen
  1796. #undef fopen
  1797.  
  1798. #ifdef ATARI
  1799. #define F_BUF_SIZE 8192  /* seems to be a good value ... */
  1800.  
  1801. FILE *myfopen(const char *filename, const char *mode)
  1802. /* Open streams with larger buffer to increase disk I/O speed. */
  1803. /* Adjust F_BUF_SIZE to change buffer size.                    */
  1804. {
  1805.     FILE *f;
  1806.  
  1807.     if ( (f = fopen(filename, mode)) != NULL )
  1808.         if (setvbuf(f, NULL, _IOFBF, F_BUF_SIZE)) /* no memory? */
  1809.         {
  1810.             fclose(f);                 /* then close it again */
  1811.             f = fopen(filename, mode); /* and try again in normal mode */
  1812.         }
  1813.     return(f);                         /* return either handle or NULL */
  1814. }
  1815.     
  1816. #else /* ATARI */
  1817.  
  1818. /* Remove "b" from 2nd arg */
  1819. FILE *myfopen(char *filename, char *type)
  1820. {    char buf[10];
  1821.  
  1822.     buf[0] = *type++;
  1823.     if (*type=='b')
  1824.         ++type;
  1825.     strcpy(buf+1,type);
  1826.     return fopen(filename, buf);
  1827. }
  1828. #endif /* not ATARI */
  1829. #endif /* fopen */
  1830.  
  1831.  
  1832. #ifndef MSDOS
  1833. #ifdef OS2
  1834.  
  1835. static int chr = -1;
  1836.  
  1837. int kbhit(void)
  1838. {
  1839.     if (chr == -1)
  1840.           chr = _read_kbd(0, 0, 0);
  1841.     return (chr != -1);
  1842. }
  1843.  
  1844. int getch(void)
  1845. {
  1846.     int c;
  1847.  
  1848.     if (chr >= 0) {
  1849.         c = chr;
  1850.         chr = -1;
  1851.     } else
  1852.           c = _read_kbd(0, 1, 0);
  1853.  
  1854.     return c;
  1855. }
  1856.  
  1857. #endif /* OS2 */
  1858. #endif /* MSDOS */
  1859.