home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / gkermit68k.tar.gz / gkermit68.tar / gkermit68 / gunixio.c < prev    next >
C/C++ Source or Header  |  2002-03-12  |  33KB  |  1,349 lines

  1. /* G U N I X I O  --  UNIX i/o module for gkermit */
  2.  
  3. /*
  4.   UNIX i/o functions for gkermit.
  5.  
  6.   Author:
  7.     Frank da Cruz
  8.     The Kermit Project
  9.     Columbia University
  10.     612 West 115th Street
  11.     New York NY 10025-7799  USA
  12.     http://www.columbia.edu/kermit/
  13.     kermit@columbia.edu
  14.  
  15.   Copyright (C) 1999,
  16.   The Trustees of Columbia University in the City of New York.
  17.  
  18.   This program is free software; you can redistribute it and/or modify
  19.   it under the terms of the GNU General Public License as published by
  20.   the Free Software Foundation; either version 2 of the License, or
  21.   (at your option) any later version.
  22.  
  23.   This program is distributed in the hope that it will be useful,
  24.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.   GNU General Public License for more details.
  27.  
  28.   You should have received a copy of the GNU General Public License
  29.   along with this program; if not, write to the Free Software
  30.   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  31. */
  32.  
  33. /*
  34.  CONTENTS...
  35.  
  36.  Console Output:
  37.    tmsg   - Type a message
  38.    tmsgl  - Type a line
  39.  
  40.  Communication Device:
  41.    ttopen - Open
  42.    ttpkt  - Put in packet mode
  43.    ttres  - Restore normal mode
  44.    ttinl  - Input a raw packet
  45.    ttol   - Send a packet
  46.    ttchk  - Check if input ready
  47.    ttflui - Flush input buffer
  48.  
  49.  File:
  50.    zchki  - See if file can be opened for input
  51.    zopeni - Open input file
  52.    zopeno - Open output file
  53.    zclosi - Close input file
  54.    zcloso - Close output file
  55.    zrtol  - Remote-to-Local filename conversion
  56.    zltor  - Local-to-Remote filename conversion
  57.    zgetc  - Get character from input file
  58. */
  59.  
  60. #include <stdio.h>            /* Standard input/output */
  61.  
  62. #ifdef POSIX
  63. #include <termios.h>            /* Terminal modes */
  64. #else
  65. #ifdef SYSV
  66. #include <termio.h>
  67. #else
  68. #include <sgtty.h>
  69. #endif /* SYSV */
  70. #endif /* POSIX */
  71.  
  72. #include <ctype.h>            /* Character types */
  73. #ifndef CPM68K
  74. #include <sys/types.h>            /* Needed e.g. by <stat.h> */
  75. #endif
  76. #include <signal.h>            /* Interrupts */
  77. #include <setjmp.h>            /* Longjumps */
  78. #ifndef CPM68K
  79. #include <sys/stat.h>            /* File exist, file size */
  80. #endif
  81. #include <errno.h>            /* Error symbols */
  82. #include "gkermit.h"            /* gkermit definitions */
  83.  
  84. /* All versions of HP-UX need Xon/Xoff */
  85.  
  86. #ifdef hpux                /* HP-UX Pre-7.00 */
  87. #ifndef __hpux
  88. #define __hpux
  89. #endif /* __hpux */
  90. #endif /* hpux */
  91.  
  92. #ifdef __hpux                /* HP-UX 7.00 and later */
  93. #ifndef SETXONXOFF
  94. #define SETXONXOFF
  95. #endif /* SETXONXOFF */
  96. #endif /*  __hpux */
  97.  
  98. #ifdef NOXONXOFF            /* -DNOXONXOFF overrides */
  99. #ifdef SETXONXOFF
  100. #undef SETXONXOFF
  101. #endif /* SETXONXOFF */
  102. #endif /* NOXONXOFF */
  103.  
  104. #ifndef TINBUFSIZ            /* read() inpbut buffer */
  105. #ifdef USE_GETCHAR
  106. #define TINBUFSIZ 0            /* getchar() has its own */
  107. #else
  108. #ifdef SMALL
  109. #define TINBUFSIZ 240
  110. #else
  111. #define TINBUFSIZ 4080
  112. #endif /* SMALL */
  113. #endif /* USE_GETCHAR */
  114. #endif /* TINBUFSIZ */
  115.  
  116. #ifndef DUMBIO
  117. #ifndef USE_GETCHAR
  118. #ifndef NOFCNTL_H            /* For nonblocking buffered read() */
  119. #ifdef SYS_FCNTL_H
  120. #include <sys/fcntl.h>
  121. #else
  122. #include <fcntl.h>
  123. #ifndef O_NDELAY
  124. #ifdef O_NONBLOCK
  125. #define O_NDELAY O_NONBLOCK
  126. #endif /* O_NONBLOCK */
  127. #endif /* O_NDELAY */
  128. #endif /* SYS_FCNTL_H */
  129. #endif /* NOFCNTL_H */
  130. #endif /* USE_GETCHAR */
  131. #endif /* DUMBIO */
  132.  
  133. #ifdef O_NDELAY                /* For System V R3 and earlier */
  134. #ifndef EWOULDBLOCK
  135. #ifdef EAGAIN
  136. #define EWOULDBLOCK EAGAIN
  137. #endif /* EAGAIN */
  138. #endif /* EWOULDBLOCK */
  139. #endif /* O_NDELAY */
  140.  
  141. #ifndef DUMBIO                /* To force single-char read/write */
  142. #ifndef USE_GETCHAR
  143. #ifndef O_NDELAY
  144. #define DUMBIO
  145. #endif /* O_NDELAY */
  146. #endif /* USE_GETCHAR */
  147. #endif /* DUMBIO */
  148.  
  149. #ifdef CPM68K
  150.  
  151. /* extracted from <osif.h> (including it in full results in name clashes) */
  152. #define __OSIF(fn,arg) __BDOS((fn),(LONG)(arg))    /* CPM68K does it this way  */
  153. #define EXIT        0    /* Exit to BDOS             */
  154. #define CONIN        1    /* direct echoing con input */
  155. #define CONOUT        2    /* Direct console output    */
  156. #define LSTOUT        5    /* Direct list device output*/
  157. #define CONIO        6    /* Direct console I/O       */
  158. #define C_WRITESTR    9    /* Console string output    */
  159. #define CONBUF        10    /* Read console buffer      */
  160. #define C_STAT        11    /* Get console status       */
  161. #define S_BDOSVER    12    /* Get System BDOS Ver Num  */
  162. /* end of extract from <osif.h> */
  163.  
  164. #define SCOUNT    163000        /* sleep time constant for a 33MHz 68020 */
  165. #define ACOUNT    10000        /* alarm time constant */
  166. static int atime;
  167. static long acount;
  168.  
  169. extern int text;        /* 0=binary, 1=text */
  170.  
  171. #endif /* CPM68K */
  172.  
  173. /* Header file deficiencies section... */
  174.  
  175. #ifndef R_OK
  176. #define R_OK 4
  177. #endif /* R_OK */
  178.  
  179. #ifndef W_OK
  180. #define W_OK 2
  181. #endif /* W_OK */
  182.  
  183. #ifndef _IFMT
  184. #ifdef S_IFMT
  185. #define _IFMT S_IFMT
  186. #else
  187. #define _IFMT 0170000
  188. #endif /* S_IFMT */
  189. #endif /* _IFMT */
  190.  
  191. #ifndef S_ISREG
  192. #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  193. #endif /* S_ISREG */
  194.  
  195. /* External variables */
  196.  
  197. extern int literal;            /* Literal filenames */
  198. extern int quiet;            /* No messages */
  199. extern int keep;            /* Keep incomplete files */
  200. extern int streamok;            /* OK to offer streaming */
  201. extern int nomodes;            /* Don't get/set tty modes */
  202. extern int xonxoff;            /* Set Xon/Xoff */
  203. extern int noxonxoff;            /* Don't set Xon/Xoff */
  204. extern FILE * db;            /* Debug log file */
  205.  
  206. /* Exported variables */
  207.  
  208. FILE *ifp, *ofp;            /* Input and output file pointers */
  209. char zinbuf[MAXRECORD+1];        /* File input buffer */
  210. int zincnt = 0;                /* count */
  211. char * zinptr = NULL;            /* and pointer. */
  212.  
  213. /* Private global variables */
  214.  
  215. static int havemodes = 0;        /* Have obtained terminal modes */
  216. static int ttflags = -1;        /* Terminal flags */
  217. static int nonblock = 0;        /* Nonblocking i/o enabled */
  218. static char tinbuf[TINBUFSIZ+16];    /* Communications input buffer */
  219. static char * tinptr = NULL;        /* Pointer to current item */
  220. static int tincnt = 0;            /* Buffer count */
  221. static int tlast = 0;            /* Last item in buffer */
  222. static int xparity = 0;            /* Parity in use, 0 = none */
  223. static int raw = 0;            /* Terminal rawmode flag */
  224. static char work[MAXPATHLEN+1];        /* Filename conversion buffer */
  225.  
  226. /* Terminal mode structs */
  227.  
  228. #ifdef POSIX                /* POSIX */
  229. static struct termios ttold, ttraw;
  230. #else
  231. #ifdef SYSV                /* System V */
  232. static struct termio ttold = {0};
  233. static struct termio ttraw = {0};
  234. #else
  235. #ifdef BSD                /* 4.2 BSD or UNIX V7 */
  236. static struct sgttyb ttold, ttraw;
  237. #endif /* BSD */
  238. #endif /* SYSV */
  239. #endif /* POSIX */
  240.  
  241. static jmp_buf jbuf;            /* Longjump buffer for timeouts */
  242.  
  243. /* Functions... */
  244.  
  245. SIGTYP
  246. doexit(x) int x; {            /* Exit routine */
  247.     if (x)                /* If failure */
  248.       ttflui();                /* flush pending junk we won't read */
  249.     ttres();                /* Reset the communication device */
  250. #ifdef F_SETFL
  251.     if (ttflags > -1)            /* Restore its flags */
  252.       fcntl(0,F_SETFL,ttflags);
  253. #endif /* F_SETFL */
  254.     if (debug) {
  255.     fprintf(db,"exit %d\n",x);
  256.     fclose(db);
  257.     }
  258.     exit(x);
  259. }
  260.  
  261. VOID
  262. sysinit() {                /* To be run first thing */
  263. #ifdef F_SETFL
  264.     ttflags = fcntl(0,F_GETFL,0);    /* Get and save stdin flags */
  265. #endif /* F_SETFL */
  266. #ifdef SIGINT
  267.     signal(SIGINT,SIG_IGN);        /* Ignore interrupts */
  268. #endif /* SIGINT */
  269. #ifdef SIGTSTP
  270.     signal(SIGTSTP,SIG_IGN);
  271. #endif /* SIGTSTP */
  272. #ifdef SIGQUIT
  273.     signal(SIGQUIT,SIG_IGN);
  274. #endif /* SIGQUIT */
  275.     signal(SIGHUP,doexit);        /* Go here on hangup */
  276. }
  277.  
  278. /* Console Functions */
  279.  
  280. #ifdef COMMENT                /* (not used) */
  281. VOID
  282. tmsg(s) char *s; {            /* tmsg() */
  283.     if (!quiet)
  284.       fprintf(stderr,"%s",s);        /* Type message on the screen. */
  285. }
  286. #endif /* COMMENT */
  287.  
  288. VOID
  289. tmsgl(s) char *s; {            /* tmsgl() */
  290.     if (!quiet) {
  291.     if (raw)
  292.       fprintf(stderr,"%s\r\n",s);    /* Type message with CRLF */
  293.     else
  294.       fprintf(stderr,"%s\n",s);
  295.     }
  296. }
  297.  
  298. /* Debugging functions */
  299.  
  300. VOID
  301. logerr(s) char * s; {            /* Log text and errno */
  302.     if (s == (char *)NULL) s = "";
  303.     if (!debug) return;
  304.     if (db) fprintf(db,"%s: errno = %d\n",s,errno);
  305. }
  306.  
  307. /* Parity function */
  308.  
  309. char
  310. #ifdef __STDC__
  311. dopar(char ch)
  312. #else
  313. dopar(ch) char ch;
  314. #endif /* __STDC__ */
  315. {                    /* Do parity */
  316.     unsigned int a;
  317.     if (!xparity) return(ch); else ch &= 0177;
  318.     switch (xparity) {
  319.       case 'm':  return(ch | 128);    /* Mark */
  320.       case 's':  return(ch & 127);    /* Space */
  321.       case 'o':                /* Odd (fall thru) */
  322.       case 'e':                /* Even */
  323.     a = (ch & 15) ^ ((ch >> 4) & 15);
  324.     a = (a & 3) ^ ((a >> 2) & 3);
  325.     a = (a & 1) ^ ((a >> 1) & 1);
  326.     if (xparity == 'o') a = 1 - a;    /* Switch sense for odd */
  327.     return(ch | (a << 7));
  328.       default: return(ch);
  329.     }
  330. }
  331.  
  332. /* Communication functions */
  333.  
  334. int
  335. ttopen(ttname) char *ttname; {        /* "Open" the communication device */
  336.     if (debug) {            /* Vital statistics for debug log */
  337. #ifdef __STDC__
  338.     fprintf(db,"ttopen __STDC__\n");
  339. #endif /* __STDC__ */
  340. #ifdef SIG_V
  341.     fprintf(db,"ttopen SIG_V\n");
  342. #else
  343. #ifdef SIG_I
  344.     fprintf(db,"ttopen SIG_I\n");
  345. #endif /* SIG_I */
  346. #endif /* SIG_V */
  347. #ifdef USE_GETCHAR
  348.     fprintf(db,"ttopen getchar/putchar\n");
  349. #ifdef BUFSIZ
  350.     fprintf(db,"ttopen BUFSIZ = %d\n", BUFSIZ);
  351. #endif /* BUFSIZ */
  352. #else
  353. #ifdef DUMBIO
  354.     fprintf(db,"ttopen single-byte read/write\n");
  355. #else
  356.     fprintf(db,"ttopen nonblocking read/write\n");
  357. #endif /* DUMBIO */
  358. #endif /* USE_GETCHAR */
  359.     fprintf(db,"ttopen TINBUFSIZ = %d\n", TINBUFSIZ);
  360. #ifdef __hpux
  361.     fprintf(db,"ttopen __hpux\n");
  362. #endif /* __hpux */
  363. #ifdef pdp11
  364.     fprintf(db,"ttopen pdp11\n");
  365. #endif /* pdp11 */
  366. #ifdef SETXONXOFF
  367.     fprintf(db,"ttopen SETXONXOFF\n");
  368. #endif /* SETXONXOFF */
  369.     fprintf(db,"ttopen xonxoff = %d\n",xonxoff);
  370.     fprintf(db,"ttopen noxonxoff = %d\n",noxonxoff);
  371.     fprintf(db,"ttopen ttflags %d\n",ttflags);
  372.     fprintf(db,"ttopen nomodes %d\n",nomodes);
  373.     }
  374.     if (nomodes) {            /* If external protocol */
  375. #ifdef SIGINT                /* exit on interrupts */
  376.     signal(SIGINT,doexit);
  377. #endif /* SIGINT */
  378. #ifdef SIGTSTP
  379.     signal(SIGTSTP,doexit);
  380. #endif /* SIGTSTP */
  381. #ifdef SIGQUIT
  382.     signal(SIGQUIT,doexit);
  383. #endif /* SIGQUIT */
  384.     return(0);
  385.     }
  386.  
  387. #ifndef DUMBIO
  388. #ifndef USE_GETCHAR
  389. #ifdef O_NDELAY
  390. #ifdef F_SETFL
  391.     if (ttflags != -1) {        /* Set nonbocking i/o on stdin */
  392.     errno = 0;
  393.     if (fcntl(0, F_SETFL,ttflags|O_NDELAY) == -1)
  394.       logerr("ttopen fcntl(0,F_SETFL,O_NDELAY)");
  395.     else
  396.       nonblock = 1;
  397.     }
  398. #endif /* F_SETFL */
  399. #endif /* O_NDELAY */
  400. #endif /* USE_GETCHAR */
  401. #endif /* DUMBIO */
  402.     if (!nonblock)            /* No streaming without */
  403.       streamok = -1;            /* nonblocking reads */
  404.  
  405.     if (debug)
  406.       fprintf(db,"ttopen nonblock = %d\n", nonblock);
  407. #ifdef POSIX
  408.     tcgetattr(0,&ttold);        /* Get stdin device attributes */
  409.     tcgetattr(0,&ttraw);
  410. #else
  411. #ifdef SYSV
  412.     ioctl(0,TCGETA,&ttold);
  413.     ioctl(0,TCGETA,&ttraw);
  414. #else
  415. #ifdef BSD
  416.     gtty(0,&ttold);
  417.     gtty(0,&ttraw);
  418. #endif /* BSD */
  419. #endif /* SYSV */
  420. #endif /* POSIX */
  421.     havemodes++;
  422.     return(0);
  423. }
  424.  
  425. int
  426. ttpkt(parity) int parity; {        /* Put comm device in packet mode */
  427. #ifdef BSD
  428.     int x;
  429. #endif /* BSD */
  430.     xparity = parity;            /* Make local copy of parity */
  431.     if (nomodes)
  432.       return(0);
  433.  
  434. #ifdef SVORPOSIX            /* System V or POSIX section... */
  435.     ttraw.c_iflag |= IGNPAR;
  436.     ttraw.c_lflag &= ~(ICANON|ECHO);
  437.     ttraw.c_lflag &= ~ISIG;
  438.     ttraw.c_lflag |= NOFLSH;
  439. #ifdef SETXONXOFF
  440.     if (!noxonxoff) {
  441.     ttraw.c_iflag |= (IXON|IXOFF);
  442.     if (debug) fprintf(db,"ttpkt SVORPOSIX Xon/Xoff\n");
  443.     }
  444. #else
  445.     if (xonxoff) {
  446.     if (debug) fprintf(db,"ttpkt SVORPOSIX Xon/Xoff\n");
  447.     ttraw.c_iflag |= (IXON|IXOFF);
  448.     }
  449. #endif /* SETXONXOFF */
  450. #ifdef IEXTEN
  451.     ttraw.c_lflag &= ~IEXTEN;
  452. #endif /* IEXTEN */
  453. #ifdef POSIX
  454.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
  455. #else
  456.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
  457. #endif /* POSIX */
  458.     ttraw.c_oflag &= ~OPOST;
  459.     ttraw.c_cflag &= ~(CSIZE);
  460.     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
  461.     ttraw.c_cflag &= ~(PARENB);
  462.  
  463. #ifndef VEOF
  464.     ttraw.c_cc[4] = 1;
  465. #else
  466. #ifdef VMIN
  467.     ttraw.c_cc[VMIN] = 1;
  468. #endif /* VMIN */
  469. #endif /* VEOF */
  470.  
  471. #ifndef VEOL
  472.     ttraw.c_cc[5] = 0;
  473. #else
  474. #ifdef VTIME
  475.     ttraw.c_cc[VTIME] = 0;
  476. #endif /* VTIME */
  477. #endif /* VEOL */
  478.  
  479. #ifdef VINTR
  480.     ttraw.c_cc[VINTR] = 0;
  481. #endif /* VINTR */
  482.  
  483. #ifdef POSIX
  484.     if (tcsetattr(0,TCSADRAIN,&ttraw) < 0)
  485.       return(-1);
  486. #else
  487.     if (ioctl(0,TCSETAW,&ttraw) < 0)
  488.       return(-1);
  489. #ifdef SYSV
  490. #endif /* SYSV */
  491. #endif /* POSIX */
  492.  
  493. #else  /* Not SVORPOSIX */
  494.  
  495. #ifdef BSD
  496.     ttraw.sg_flags |= RAW;        /* BSD/V7 raw (binary) mode */
  497. #ifdef SETXONXOFF
  498.     if (!noxonxoff) {
  499.     ttraw.sg_flags |= TANDEM;
  500.     if (debug) fprintf(db,"ttpkt BSD Xon/Xoff\n");
  501.     }
  502. #else
  503.     if (xonxoff) {
  504. #ifdef CPM68K
  505.     if (debug) fprintf(db,"ttpkt CPM68K can't do Xon/Xoff!\n");
  506. #else
  507.     ttraw.sg_flags |= TANDEM;
  508.     if (debug) fprintf(db,"ttpkt BSD Xon/Xoff\n");
  509. #endif /* CPM68K */
  510.     }
  511. #endif /* SETXONXOFF */
  512.     ttraw.sg_flags &= ~(ECHO|CRMOD);    /* No echo, etc */
  513.     if (stty(0,&ttraw) < 0) return(-1); /* Set modes */
  514. #else
  515.     system("stty raw -echo");
  516. #endif /* BSD */
  517. #endif /* SVORPOSIX */
  518.     raw = 1;                /* Flag we're now in raw mode */
  519.     return(0);
  520. }
  521.  
  522. int
  523. ttres() {                /* Reset terminal */
  524.     int x = 0;
  525.     if (havemodes) {            /* Restore old modes */
  526. #ifdef POSIX
  527.     x = tcsetattr(0,TCSADRAIN,&ttold);
  528. #else
  529. #ifdef SYSV
  530.     sleep(1);            /* Let output finish */
  531.     x = ioctl(0,TCSETAW,&ttold);
  532. #else
  533. #ifdef BSD
  534.     sleep(1);            /* Let output finish */
  535.     x = stty(0,&ttold);
  536. #else
  537.     x = system("stty -raw echo");
  538. #endif /* BSD */
  539. #endif /* SYSV */
  540. #endif /* POSIX */
  541.     }
  542.     write(1,"\015\012",2);
  543.     raw = 0;
  544.     return(x);
  545. }
  546.  
  547. int
  548. ttchk() {                /* Check if input ready */
  549.     int x = 0;
  550.     if (nonblock) {            /* Try to read */
  551.     errno = 0;
  552.     x = read(0,&tinbuf[tlast],TINBUFSIZ-tlast);
  553. #ifdef EXTRADEBUG
  554.     fprintf(db,"ttchk read %d errno = %d\n",x,errno);
  555. #endif /* EXTRADEBUG */
  556. #ifdef EWOULDBLOCK
  557.     if (x < 0 && errno == EWOULDBLOCK) /* Nothing to read */
  558.       x = 0;
  559. #endif /* EWOULDBLOCK */
  560.     if (x < 0)            /* Fatal i/o error */
  561.       return(-1);
  562.     }
  563.     tincnt += x;            /* Buffer bookkeeping */
  564.     tlast  += x;
  565.     return(x + tincnt);            /* How much is waiting to be read */
  566. }
  567.  
  568. int
  569. ttflui() {                /* Flush comm device input buffer */
  570. #ifdef BSD
  571.     long n = 1;                /* Specify read queue */
  572. #endif /* BSD */
  573.     int x;
  574.     tincnt = 0;                /* Our own buffer */
  575.     tlast = 0;
  576.     tinptr = tinbuf;
  577.     errno = 0;
  578. #ifdef POSIX
  579.     x = tcflush(0,TCIFLUSH);        /* kernel/driver buffers */
  580. #else
  581. #ifdef SYSV
  582.     x = ioctl(0,TCFLSH,0);
  583. #else
  584. #ifdef BSD
  585. #ifndef CPM68K
  586.     x = ioctl(0,TIOCFLUSH,&n);
  587. #endif /* CPM68K */
  588. #endif /* BSD */
  589. #endif /* SYSV */
  590. #endif /* POSIX */
  591.     if (debug) fprintf(db,"ttflui = %d, errno = %d\n",x,errno);
  592.     return(x);
  593. }
  594.  
  595. SIGTYP
  596. timerh(dummy) int dummy; {        /* Timeout handler */
  597.     longjmp(jbuf,1);
  598.     SIGRETURN;
  599. }
  600.  
  601. /*
  602.  ttinl() - Read a raw packet.
  603.  
  604.  Call with:
  605.    dest - where to put it
  606.    maxl - maximum length
  607.    timo - timeout (seconds, 0 = none)
  608.    eol  - packet terminator
  609.    turn - half-duplex line turnaround character to wait for, 0 = none
  610.  
  611.  Returns length obtained, or -1 if error or timeout, -2 on disconnection.
  612. */
  613. #ifndef DEBUGWRAP
  614. #define DEBUGWRAP 48
  615. #endif /* DEBUGWRAP */
  616.  
  617. int
  618. #ifdef __STDC__
  619. ttinl(char * dest, int maxl, int timo, char eol, char soh, int turn)
  620. #else
  621. ttinl(dest,maxl,timo,eol,soh,turn) int maxl, timo, turn; char eol, soh, *dest;
  622. #endif /* __STDC__ */
  623. {
  624.     int n = 0, x = 0, flag = 0, rc = 0, ccn = 0; /* Local variables */
  625.     char c = NUL;
  626.     int havelen = 0, pktlen = 0, lplen = 0;
  627.  
  628. #ifdef USE_GETCHAR
  629.     if (debug) fprintf(db,"ttinl getchar timo = %d\n",timo);
  630. #else
  631.     if (debug) fprintf(db,"ttinl read timo = %d\n",timo);
  632. #endif /* USE_GETCHAR */
  633.     *dest = NUL;            /* Clear destination buffer */
  634.     if (timo) {
  635.     signal(SIGALRM,timerh);        /* Enable timer interrupt */
  636.     alarm(timo);            /* Set it. */
  637.     }
  638.     if (setjmp(jbuf)) {            /* Timer went off? */
  639.     if (debug) fprintf(db,"ttinl timeout\n");
  640.         rc = -1;            /* Yes, set this return code. */
  641.     } else {                /* Otherwise... */
  642.     while (1) {            /* Read until we have a packet */
  643. #ifdef DUMBIO
  644. #ifdef CPM68K
  645.         /* use direct console I/O in order to implement a
  646.          * timeout counter
  647.          */
  648.         if (timo) {
  649.             if (__OSIF(CONIO, 0xfe) == 0) {
  650.             /* no char ready, decrement timeout counter */
  651.             tttimo();
  652.             continue;
  653.         }
  654.         }
  655.         c = (char)__OSIF(CONIO, 0xff);    /* blocking read */
  656. #else
  657.         x = read(0,&c,1);        /* Dumb blocking read byte loop */
  658.         if (x < 0) {
  659.         logerr("ttinl XX read 1");
  660.         rc = -2;
  661.         }
  662. #endif CPM68K
  663. #else
  664. #ifdef USE_GETCHAR
  665.         errno = 0;
  666.         x = getchar();        /* Buffered read with getchar() */
  667.         if (x == EOF) {
  668.         if (errno == EINTR)
  669.           continue;
  670.         logerr("ttinl getchar");
  671.         rc = -2;
  672.         }
  673.         c = x;
  674. #else  /* USE_GETCHAR */
  675. #ifdef O_NDELAY
  676.         if (nonblock) {        /* Buffered nonblocking read() */
  677.         int x;
  678.         if (tincnt < 1) {    /* Need to fill our buffer */
  679.             errno = 0;
  680.             tincnt = read(0,tinbuf,TINBUFSIZ);
  681.             if (tincnt > -1) tlast = tincnt;
  682.             if (debug)
  683.               fprintf(db,"ttinl nonblock tincnt=%d errno=%d\n",
  684.                   tincnt,errno);
  685.             if (tincnt == 0 || errno == EWOULDBLOCK) {
  686. #ifdef F_SETFL
  687.             /* Go back to blocking and wait for 1 char */
  688.             if (ttflags != -1) {
  689.                 errno = 0;
  690.                 x = fcntl(0, F_SETFL, ttflags  & ~O_NDELAY);
  691.                 if (x == -1 || errno)
  692.                   logerr("ttinl fcntl O_NDELAY off");
  693.                 errno = 0;
  694.                 tincnt = read(0,tinbuf,1);
  695.                 if (tincnt < 1 || errno)
  696.                   logerr("ttinl BL read");
  697.                 errno = 0;
  698.                 fcntl(0, F_SETFL, ttflags | O_NDELAY);
  699.                 if (x == -1 || errno)
  700.                   logerr("ttinl fcntl O_NDELAY on");
  701.             }
  702.             if (tincnt == 0) { /* Check results */
  703.                 continue;
  704.             }
  705.             if (tincnt < 0) { /* I/O error */
  706.                 rc = -2;
  707.                 goto xttinl;
  708.             }
  709.             if (debug)
  710.               fprintf(db,"ttinl blocking read %d\n",tincnt);
  711. #else
  712.             /* No other form of sleeping is portable */
  713.             sleep(1);
  714.             continue;
  715. #endif /* F_SETFL */
  716.             } else if (tincnt < 0) {
  717.             rc = -2;
  718.             goto xttinl;
  719.             }
  720.             tinptr = tinbuf;
  721.         }
  722.         c = *tinptr++;
  723.         tincnt--;
  724.         } else {
  725. #endif /* O_NDELAY */
  726.         x = read(0,&c,1);    /* Dumb read byte loop */
  727.         if (x < 0) {
  728.             logerr("ttinl XX read 1");
  729.             rc = -2;
  730.         }
  731. #ifdef O_NDELAY
  732.         }
  733. #endif /* O_NDELAY */
  734. #endif /* USE_GETCHAR */
  735. #endif /* DUMBIO */
  736.         if (rc < 0)
  737.           break;
  738.         if (xparity)        /* Strip parity */
  739.           c &= 0x7f;
  740. #ifdef COMMENT
  741.         /* Only uncomment in emergencies */
  742.         if (debug)
  743.           fprintf(db,"ttinl char=%c flag=%d tincnt=%d\n",c,flag,tincnt);
  744. #endif /* COMMENT */
  745.         if (c == '\03') {        /* Got ^C, count it. */
  746.             if (++ccn > 2) {    /* If more than 2, let them out */
  747.             fprintf(stderr,"^C...");
  748.             ttres();
  749.             if (debug) fprintf(db,"ttinl interrupted\n");
  750.             dest[n = 0] = NUL;
  751.             rc = -9;
  752.             goto xttinl;
  753.         }
  754.         } else            /* Not ^C so reset counter*/
  755.           ccn = 0;
  756.  
  757.         if (!flag && (c != soh))    /* Look for SOH */
  758.           continue;            /* Skip stuff between packets */
  759.         flag = 1;            /* Have SOH */
  760.  
  761.         if (n >= maxl) {
  762.         if (debug) fprintf(db,"ttinl overflow\n");
  763.         rc = -2;
  764.         goto xttinl;
  765.         }
  766.         dest[n++] = c;        /* Store the character */
  767. #ifdef USE_EOL
  768.         /* Use EOL to determine end of packet */
  769.         if (c == eol) {
  770.         dest[n] = NUL;
  771.         break;
  772.         }
  773. #else
  774.         /* Use length field for framing */
  775.         if (!havelen) {
  776.         if (n == 2) {
  777.             pktlen = xunchar(dest[1] & 0x7f);
  778.             if (pktlen > 1) {
  779.             if (debug) fprintf(db,"ttinl length = %d\n",pktlen);
  780.             havelen = 1;
  781.             }
  782.         } else if (n == 5 && pktlen == 0) {
  783.             lplen = xunchar(dest[4] & 0x7f);
  784.         } else if (n == 6 && pktlen == 0) {
  785.             pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
  786.             if (debug) fprintf(db,"ttinl length = %d\n",pktlen);
  787.             havelen = 1;
  788.         }
  789.         }
  790.         if (havelen && (n > pktlen+1)) {
  791.         if (turn && c != turn)    /* Wait for turnaround char */
  792.           continue;
  793.         dest[n] = NUL;        /* Null-terminate whatever we got */
  794.         break;
  795.         }
  796. #endif /* USE_EOL */
  797.     }
  798.     }
  799.   xttinl:                /* Common exit point */
  800.     if (timo) {
  801.     alarm(0);            /* Turn off the alarm */
  802.     signal(SIGALRM,SIG_IGN);    /* and associated interrupt */
  803.     }
  804.     if (debug && n > 0) {        /* Log packet */
  805. #ifndef FULLPACKETS
  806.     if (n > DEBUGWRAP) {        /* Truncate if it would wrap */
  807.         dest[n] = NUL;        /* in case of interruption */
  808.         c = dest[DEBUGWRAP];
  809.         dest[DEBUGWRAP] = NUL;
  810.         fprintf(db,"PKT<-[^A%s...](%d) rc=%d\n",&dest[1],n,rc);
  811.         dest[DEBUGWRAP] = c;
  812.  
  813.     } else
  814. #endif /* FULLPACKETS */
  815.         fprintf(db,"PKT<-[^A%s](%d) rc=%d\n",&dest[1],n,rc);
  816.     }
  817.     if (rc == -9)            /* Interrupted by user */
  818.       doexit(1);
  819.     else if (rc > -1)
  820.       rc = n;
  821.     return(rc);                /* Return length, or failure. */
  822. }
  823.  
  824. int
  825. ttol(s,len) int len; char *s; {        /* Output string s of given length  */
  826.     register int i = 0, n = 0, m = 0;
  827.     int partial = 0;
  828.  
  829.     n = len;
  830.     if (n < 0) {
  831.     if (debug) fprintf(db,"ttol len = %d\n",n);
  832.     return(-1);
  833.     }
  834.     if (xparity) {            /* Add parity if requested */
  835.     for (i = 0; i < n; i++)
  836.       s[i] = dopar(s[i]);
  837.     }
  838.     if (debug) {            /* Log the packet if requested */
  839.     char c;
  840. #ifndef FULLPACKETS
  841.     if (n > DEBUGWRAP) {
  842.         c = s[DEBUGWRAP];
  843.         s[DEBUGWRAP] = NUL;
  844.         fprintf(db,"PKT->[^A%s...](%d)\n",&s[1],n);
  845.         s[DEBUGWRAP] = c;
  846.     } else {
  847. #endif /* FULLPACKETS */
  848.         c = s[n-1];
  849.         s[n-1] = NUL;
  850.         fprintf(db,"PKT->[^A%s](%d)\n",&s[1],n);
  851.         s[n-1] = c;
  852. #ifndef FULLPACKETS
  853.     }
  854. #endif /* FULLPACKETS */
  855.     }
  856. #ifdef USE_GETCHAR
  857.     {                    /* Send the packet with putchar() */
  858.     register CHAR c; register int i;
  859.     for (i = 0; i < n; i++) {
  860.         c = *s++;
  861.         if (putchar(c) == EOF) {
  862.         logerr("ttol putchar");
  863.         return(-1);
  864.         }
  865.     }
  866.     }
  867.     fflush(stdout);            /* Push it out */
  868.     return(n);
  869. #else
  870.     while (n > 0) {            /* Send the packet with write() */
  871.     i = write(1,&s[m],n);        /* Allowing for partial results */
  872.     if (i < 0) {
  873. #ifdef EWOULDBLOCK
  874.         if (errno == EWOULDBLOCK)    /* and even no results at all.. */
  875.           continue;
  876. #endif
  877.         logerr("ttol write");
  878.         return(-1);
  879.     }
  880.     if (i == n)
  881.       break;
  882.     partial++;
  883.     m += i;
  884.     if (debug) fprintf(db,"ttol partial write %d (%d/%d)\n",i,m,len);
  885.     n -= i;
  886.     }
  887.     if (partial) {
  888.     m += i;
  889.     if (debug) fprintf(db,"ttol partial write %d (%d/%d)\n",i,m,len);
  890.     if (m != len) {
  891.         if (debug) fprintf(db,"ttol foulup %d != %d\n",m,len);
  892.         return(-1);
  893.     }
  894.     }
  895.     return(len);
  896. #endif /* USE_GETCHAR */
  897. }
  898.  
  899. /* File Functions */
  900.  
  901. char ofile[MAXPATHLEN];            /* Output filename */
  902. long filelength = -1L;
  903.  
  904. long
  905. zchki(fn) char * fn; {            /* Check if file is readable */
  906. #ifdef CPM68K
  907.     int fd;
  908.     long fsize, _filesz();
  909.  
  910.     /* CP/M-68K doesn't have stat().
  911.      * Instead, we have to open the file and then use _filesz().
  912.      */
  913.     if (fn == (char *)NULL)
  914.     return(-1);
  915.     errno = 0;
  916.     if (text)
  917.     fd = open(fn,0);        /* text mode */
  918.     else
  919.     fd = openb(fn,0);        /* binary mode */
  920.     if (fd == -1) {
  921.     if (debug)
  922.       fprintf(db,"zchki open %s errno = %d\n",fn,errno);
  923.     return(-1);
  924.     }
  925.     fsize = _filesz(fd);
  926.     close(fd);
  927.     if (debug)
  928.       fprintf(db,"zchki fsize = %ld\n",fsize);    /* GH */
  929.     return(fsize);
  930. #else    /* CPM68K */
  931.     struct stat buf;
  932.     if (!fn) return(-1);
  933.     if (stat(fn,&buf) < 0)
  934.       return(-1);
  935.     errno = 0;
  936.     if (access(fn,R_OK) < 0) {
  937.     if (debug)
  938.       fprintf(db,"zchki access %s errno = %d\n",fn,errno);
  939.     return(-1);
  940.     }
  941.     if (!S_ISREG(buf.st_mode)) {
  942.     if (debug)
  943.       fprintf(db,"zchki %s is a directory",fn);
  944.     return(-2);
  945.     }
  946.     return(buf.st_size);
  947. #endif    /* CPM68K */
  948. }
  949.  
  950. int
  951. zchko(fn) char *fn; {            /* Check write access */
  952.     int i, x;
  953.     char * s;
  954.  
  955.     if (fn == (char *)NULL)        /* Defend against empty name */
  956.       fn = "";
  957.     if (!*fn)
  958.       return(-1);
  959.     if (!strcmp(fn,"/dev/null"))    /* Null device is OK. */
  960.       return(0);
  961.     if ((x = zchki(fn)) == -2)        /* An existing directory? */
  962.       return(-1);
  963.     s = fn;
  964.     if (x < 0) {            /* If file does not exist */
  965.     strncpy(work,fn,MAXPATHLEN);
  966.     work[MAXPATHLEN] = NUL;
  967.     s = work;
  968.     for (i = (int)strlen(s); i > 0; i--) { /* Strip filename from right */
  969.         if (s[i-1] == '/') {    /* and check its directory */
  970.         s[i-1] = NUL;
  971.         break;
  972.         }
  973.     }
  974.     if (i == 0)
  975.       s = ".";
  976.     }
  977.     errno = 0;
  978. #ifdef CPM68K
  979.     /* checking for write access to '.' is meaningless */
  980.     if (*s == '.') {
  981.     x = 0;
  982.     } else {
  983.         x = access(s,W_OK);        /* Check access of path. */
  984.     }
  985. #else
  986.     x = access(s,W_OK);            /* Check access of path. */
  987. #endif
  988.     if (debug) fprintf(db,"zchko(%s) x = %d errno = %d\n",s,x,errno);
  989.     return((x < 0) ? -1 : 0);           /* and return. */
  990. }
  991.  
  992. int
  993. zopeni(name) char *name; {        /* Open existing file for input */
  994. #ifdef CPM68K
  995.     if (text)
  996.     ifp = fopen(name,"r");        /* open in text mode */
  997.     else
  998.     ifp = fopenb(name,"r");        /* open in binary mode */
  999. #else
  1000.     ifp = fopen(name,"r");
  1001. #endif
  1002.     if (debug) fprintf(db,"zopeni %s: %d\n",name, ifp ? 0 : errno);
  1003.     filelength = zchki(name);
  1004.     if (filelength < 0)
  1005.       return((int)filelength);
  1006.     zincnt = 0;
  1007.     zinptr = zinbuf;
  1008.     return((ifp == NULL) ? -1 : 0);
  1009. }
  1010.  
  1011. int
  1012. zopeno(name) char *name; {        /* Open new file for output */
  1013.     errno = 0;
  1014. #ifdef CPM68K
  1015.     if (text)
  1016.     ofp = fopen(name,"w");        /* text mode */
  1017.     else
  1018.     ofp = fopenb(name,"w");        /* binary mode */
  1019. #else
  1020.     ofp = fopen(name,"w");
  1021. #endif
  1022.     if (debug) fprintf(db,"zopeno %s: %d\n",name, ofp ? 0 : errno);
  1023.     if (ofp) {
  1024.     strncpy(ofile,name,MAXPATHLEN);
  1025.     ofile[MAXPATHLEN-1] = NUL;
  1026.     return(0);
  1027.     } else
  1028.       return(-1);
  1029. }
  1030.  
  1031. VOID                    /* Local to remote file name */
  1032. zltor(lclnam,pktnam,maxlen) char *lclnam, *pktnam; int maxlen; {
  1033.     char *p, *np = NULL, *cp, *pp, c;
  1034.     char *dotp = NULL;
  1035.     char *dirp = NULL;
  1036.     int n = 0;
  1037.  
  1038.     if (debug)
  1039.       fprintf(db,"zltor %s: maxlen = %d, literal = %d\n",
  1040.           lclnam,maxlen,literal);
  1041.     if (literal) {
  1042.     p = lclnam;
  1043.     dirp = p;
  1044.     while (*p) {
  1045.         if (*p == '/') dirp = p+1;
  1046.         p++;
  1047.     }
  1048.     strncpy(pktnam,dirp,maxlen);
  1049.     } else {
  1050.     for (p = lclnam; *p; p++) {    /* Point to name part */
  1051.         if (*p == '/')
  1052.           np = p;
  1053.     }
  1054.     if (np) {
  1055.         np++;
  1056.         if (!*np) np = lclnam;
  1057.     } else
  1058.       np = lclnam;
  1059.  
  1060.     if (debug)
  1061.       fprintf(db,"zltor np %s\n",np);
  1062.  
  1063.     pp = work;            /* Output buffer */
  1064.     for (cp = np, n = 0; *cp && n < maxlen; cp++,n++) {
  1065.         c = *cp;
  1066.         if (islower(c))        /* Uppercase letters */
  1067.           *pp++ = toupper(c);    /* Change tilde to hyphen */
  1068.         else if (c == '~')
  1069.           *pp++ = '-';
  1070.         else if (c == '#')        /* Change number sign to 'X' */
  1071.           *pp++ = 'X';
  1072.         else if (c == '*' || c == '?') /* Change wildcard chars to 'X' */
  1073.           *pp++ = 'X';
  1074.         else if (c == ' ')        /* Change space to underscore */
  1075.           *pp++ = '_';
  1076.         else if (c < ' ')        /* Change space and controls to 'X' */
  1077.           *pp++ = 'X';
  1078.         else if (c == '.') {    /* Change dot to underscore */
  1079.         dotp = pp;        /* Remember where we last did this */
  1080.         *pp++ = '_';
  1081.         } else {
  1082.         if (c == '/')
  1083.           dirp = pp;
  1084.         *pp++ = c;
  1085.         }
  1086.     }
  1087.     *pp = NUL;            /* Tie it off. */
  1088.     if (dotp > dirp) *dotp = '.';    /* Restore last dot in file name */
  1089.     cp = pktnam;            /* If nothing before dot, */
  1090.     if (*work == '.') *cp++ = 'X';    /* insert 'X' */
  1091.     strncpy(cp,work,maxlen);
  1092.     cp[maxlen-1] = NUL;
  1093.     }
  1094.     if (debug)
  1095.       fprintf(db,"zltor result: %s\n",pktnam);
  1096. }
  1097.  
  1098. int
  1099. zbackup(fn) char * fn; {        /* Back up existing file */
  1100. #ifndef CPM68K
  1101.     struct stat buf;
  1102. #endif
  1103.     int i, j, k, x, state, flag;
  1104.     char *p, newname[MAXPATHLEN+12];
  1105.  
  1106.     if (fn == (char *)NULL)        /* Watch out for null pointers. */
  1107.       return(-1);
  1108.     if (!*fn)                /* And empty names. */
  1109.       return(-1);
  1110. #ifdef CPM68K
  1111.     /* CP/M-68K doesn't have stat(), use access() instead */
  1112.     if (access(fn,0) < 0)
  1113.     return(0);
  1114. #else
  1115.     if (stat(fn,&buf) < 0)        /* If file doesn't exist */
  1116.       return(0);            /* no need to back it up. */
  1117. #endif
  1118.  
  1119.     i = strlen(fn);            /* Get length */
  1120.     if (i > MAXPATHLEN)            /* Guard buffer */
  1121.       i = MAXPATHLEN;
  1122.     if (debug)
  1123.       fprintf(db,"zbackup A %s: %d\n", fn, i);
  1124.  
  1125.     strncpy(work,fn,MAXPATHLEN);    /* Make pokeable copy of name */
  1126.     work[MAXPATHLEN] = NUL;
  1127.     p = work;                /* Strip any backup prefix */
  1128.  
  1129.     i--;
  1130.     for (flag = state = 0; (!flag && (i > 0)); i--) {
  1131.     switch (state) {
  1132.       case 0:            /* State 0 - final char */
  1133.         if (p[i] == '~')        /* Is tilde */
  1134.           state = 1;        /* Switch to next state */
  1135.         else            /* Otherwise */
  1136.           flag = 1;            /* Quit - no backup suffix. */
  1137.         break;
  1138.       case 1:            /* State 1 - digits */
  1139.         if (p[i] == '~'  && p[i-1] == '.') { /* Have suffix */
  1140.         p[i-1] = NUL;        /* Trim it */
  1141.         flag = 1;        /* done */
  1142.         } else if (p[i] >= '0' && p[i] <= '9') { /* In number part */
  1143.         continue;        /* Keep going */
  1144.         } else {            /* Something else */
  1145.         flag = 1;        /* Not a backup suffix - quit. */
  1146.         }
  1147.         break;
  1148.     }
  1149.     }
  1150.     if (debug)
  1151.       fprintf(db,"zbackup B %s\n", p);
  1152.     if (!p[0])
  1153.       p = fn;
  1154.     j = strlen(p);
  1155.     strncpy(newname,p,MAXPATHLEN);
  1156.     for (i = 1; i < 1000; i++) {    /* Search from 1 to 999 */
  1157.     if (i < 10)            /* Length of numeric part of suffix */
  1158.       k = 1;
  1159.     else if (i < 100)
  1160.       k = 2;
  1161.     else
  1162.       k = 3;
  1163.     x = j;                /* Where to write suffix */
  1164.     if ((x + k + 3) > MAXPATHLEN)
  1165.       x = MAXPATHLEN - k - 3;
  1166.     sprintf(&newname[x],".~%d~",i); /* Make a backup name */
  1167. #ifdef CPM68K
  1168.     if (access(newname,0) < 0) {
  1169. #else
  1170.     if (stat(newname,&buf) < 0) {    /* If it doesn't exist */
  1171. #endif
  1172.         errno = 0;
  1173. #ifdef CPM68K
  1174.     /* CP/M-68K doesn' have link(), use rename() instead */
  1175.         if (rename(fn,newname) < 0) {
  1176.         if (debug)
  1177.           fprintf(db,"zbackup failed: rename(%s,%s): %d\n",fn,newname,errno);
  1178.         return(-1);
  1179.  
  1180. #else
  1181.         if (link(fn,newname) <  0) { /* Rename old file to backup name */
  1182.         if (debug)
  1183.           fprintf(db,"zbackup failed: link(%s): %d\n",newname,errno);
  1184.         return(-1);
  1185.         } else if (unlink(fn) < 0) {
  1186.         if (debug)
  1187.           fprintf(db,"zbackup failed: unlink(%s): %d\n",fn,errno);
  1188.         return(-1);
  1189. #endif
  1190.         } else {
  1191.         if (debug)
  1192.           fprintf(db,"zbackup %s: OK\n",newname);
  1193.         return(0);
  1194.         }
  1195.     }
  1196.     }
  1197.     if (debug)
  1198.       fprintf(db,"zbackup failed: all numbers used\n");
  1199.     return(-1);
  1200. }
  1201.  
  1202. int                    /* Remote to local filename */
  1203. zrtol(pktnam,lclnam,warn,maxlen) char *pktnam, *lclnam; int warn, maxlen; {
  1204.     int acase = 0, flag = 0, n = 0;
  1205.     char * p;
  1206.  
  1207.     if (debug)
  1208.       fprintf(db, "zrtol pktnam=%s\n", pktnam);    /* GH */
  1209.     if (literal) {
  1210.     strncpy(lclnam,pktnam,maxlen);
  1211.     } else {
  1212.     for (p = lclnam; *pktnam != '\0' && n < maxlen; pktnam++) {
  1213.         if (*pktnam > SP) flag = 1;    /* Strip leading blanks and controls */
  1214.         if (flag == 0 && *pktnam < '!')
  1215.           continue;
  1216.         if (isupper(*pktnam))    /* Check for mixed case */
  1217.           acase |= 1;
  1218.         else if (islower(*pktnam))
  1219.           acase |= 2;
  1220.         *p++ = *pktnam;
  1221.         n++;
  1222.     }
  1223.     *p-- = NUL;            /* Terminate */
  1224.     while (*p < '!' && p > lclnam)    /* Strip trailing blanks & controls */
  1225.       *p-- = '\0';
  1226.  
  1227.     if (!*lclnam) {            /* Nothing left? */
  1228.         strncpy(lclnam,"NONAME",maxlen); /* do this... */
  1229.     } else if (acase == 1) {    /* All uppercase? */
  1230.         p = lclnam;            /* So convert all letters to lower */
  1231.         while (*p) {
  1232.         if (isupper(*p))
  1233.           *p = tolower(*p);
  1234.         p++;
  1235.         }
  1236.     }
  1237.     }
  1238.     if (warn) {
  1239.     if (zbackup(lclnam) < 0)
  1240.       return(-1);
  1241.     }
  1242.     return(0);
  1243. }
  1244.  
  1245. int
  1246. zclosi() {                /* Close input file */
  1247.     int rc;
  1248.     rc = (fclose(ifp) == EOF) ? -1 : 0;
  1249.     ifp = NULL;
  1250.     return(rc);
  1251. }
  1252.  
  1253. int
  1254. zcloso(cx) int cx; {            /* Close output file */
  1255.     int rc;
  1256.     rc = (fclose(ofp) == EOF) ? -1 : 0;
  1257.     if (debug) fprintf(db,"zcloso(%s) cx = %d keep = %d\n", ofile, cx, keep);
  1258.     if (cx && !keep ) unlink(ofile);    /* Delete if incomplete */
  1259.     ofp = NULL;
  1260.     return(rc);
  1261. }
  1262.  
  1263. int
  1264. zfillbuf(text) int text; {        /* Refill input file buffer */
  1265.     if (zincnt < 1) {            /* Nothing in buffer - must refill */
  1266.     if (text) {            /* Text mode needs LF/CRLF handling */
  1267.         int c;            /* Current character */
  1268.         for (zincnt = 0;        /* Read a line */
  1269.          zincnt < MAXRECORD - 1 && (c = getc(ifp)) != EOF && c != '\n';
  1270.          zincnt++
  1271.          ) {
  1272.         zinbuf[zincnt] = c;
  1273.         }
  1274.         if (c == '\n') {        /* Have newline. */
  1275.         zinbuf[zincnt++] = '\r'; /* Substitute CRLF */
  1276.         zinbuf[zincnt++] = c;
  1277.         }
  1278.     } else {            /* Binary - just read raw buffers */
  1279.         zincnt = fread(zinbuf, sizeof(char), MAXRECORD, ifp);
  1280.     }
  1281.     zinbuf[zincnt] = NUL;        /* Terminate. */
  1282.     if (zincnt == 0)        /* Check for EOF */
  1283.       return(-1);
  1284.     zinptr = zinbuf;        /* Not EOF - reset pointer */
  1285.     }
  1286. #ifdef EXTRADEBUG                /* Voluminous debugging */
  1287.     if (debug) fprintf(db,"zfillbuf (%s) zincnt = %d\n",
  1288.                text ? "text" : "binary",
  1289.                zincnt
  1290.                );
  1291. #endif /* EXTRADEBUG */
  1292.     zincnt--;                /* Return first byte. */
  1293.     return(*zinptr++ & 0xff);
  1294. }
  1295. #ifdef CPM68K
  1296. /*
  1297.  * a crude sleep()
  1298.  */
  1299. sleep(sec) int sec;
  1300. {
  1301.     int i, a, b, c;
  1302.     long j;
  1303.  
  1304.     a = 101;
  1305.     b = 101;
  1306.     for (i = 0; i < sec; i++) {
  1307.         for (j = 0; j < SCOUNT; j++) {
  1308.             c = a * b;    /* compiles to 'muls' */
  1309.             b = c / a;    /* compiles to 'divs' */
  1310.         }
  1311.     }
  1312.     return(0);
  1313. }
  1314. /*
  1315.  * CP/M-68K has no timers so doesn't support a real alarm()
  1316.  * function. This just sets the timeout for tttimo()
  1317.  */
  1318. alarm(sec) int sec;
  1319. {
  1320.     atime = sec;
  1321.     acount = ACOUNT;
  1322.     return(0);
  1323. }
  1324. /*
  1325.  * timer for ttinl()
  1326.  */
  1327. tttimo()
  1328. {
  1329.     int a, b, c;
  1330.  
  1331.     if (atime == 0) {
  1332.     return(0);        /* no alarm set */
  1333.     }
  1334.     a = 101;
  1335.     b = 101;
  1336.     c = a * b;            /* compiles to 'muls' */
  1337.     b = c / a;            /* compiles to 'divs' */
  1338.     if (--acount == 0) {
  1339.         if (--atime == 0) {
  1340.         timerh(0);        /* timeout */
  1341.     }
  1342.     acount = ACOUNT;    /* reload timer */
  1343.     }
  1344.     return(0);
  1345. }
  1346.  
  1347. #endif /* CPM68K */
  1348.  
  1349.