home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / varia / pgp / pgpamiga / source / system.c < prev    next >
C/C++ Source or Header  |  1993-12-23  |  44KB  |  1,784 lines

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