home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / os2 / pgp263.arj / PGP263I.SRC / PGP263II.ZIP / src / system.c < prev    next >
C/C++ Source or Header  |  1996-01-06  |  46KB  |  2,005 lines

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