home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / sinclairqla.zip / qlksbr.c < prev    next >
C/C++ Source or Header  |  1987-05-08  |  16KB  |  586 lines

  1. /*
  2.     SBR_C - QL-Kermit general subroutines
  3.  
  4.     Extracts from ck*.c files, (C) Columbia University
  5. */
  6.  
  7.  
  8. /* Include files */
  9.  
  10. #include "ram1_ker_h"                            /* Kermit definitions */
  11.  
  12. #include "flp1_fcntl_h"                          /* File opening modes */
  13. #include "flp1_ctype_h"                          /* Character test macros */
  14.  
  15.  
  16. /* External variables */
  17.  
  18. extern int state;                                /* Current switcher state */
  19. extern int ttychid;                              /* QDOS channel ID of comms line */
  20. extern int tvalue;                               /* Receive timeout (frames) */
  21. extern int debug;                                /* Debugging level */
  22. extern int serno;                                /* Serial port in use */
  23. extern int parity;                               /* Parity setting */
  24. extern int speed;                                /* Baud rate */
  25. extern int ttyfd;                                /* FD of communication line */
  26. extern int trans;                                /* File name translation */
  27. extern int tlevel;                               /* TAKE file nesting level */
  28.  
  29. extern int _oserr;                               /* QDOS error code */
  30. extern int oserr;                                /* Copy of above */
  31.  
  32. extern bool timer;                               /* Timer enabled flag */
  33. extern bool cxseen,czseen;                       /* Transfer interrupt flags */
  34. extern bool local;                               /* Operation mode flag */
  35. extern bool keep;                                /* Incomplete file flag */
  36.  
  37. extern char *newfilnam;                          /* Transfer file name */
  38. extern char *errdata;                            /* Data for E packet */
  39. extern char *suffix;                             /* Outgoing file suffix */
  40.  
  41. extern char ttyname[];                           /* Name of communication line */
  42.  
  43. extern int fp;                                   /* Transfer file */
  44.  
  45. extern FILE *tfile[MAXTAKE];                     /* TAKE file stack */
  46.  
  47.  
  48. /* External functions */
  49.  
  50. char *strchr();                                  /* Find first character */
  51. char *strrchr();                                 /* Find last character */
  52.  
  53.  
  54. /* Local variables */
  55.  
  56. static char buf[BLKSIZ];                         /* Transfer file buffer */
  57. static int bufp;                                 /* Index into above */
  58. static int n;                                    /* Character count */
  59.  
  60.  
  61. /* DELCH - Special QL console character delete */
  62.  
  63. delch()
  64. {
  65.     sd_pcol(fgetchid(stdout),1);
  66.     putchar(' ');
  67.     sd_pcol(fgetchid(stdout),1);
  68. }
  69.  
  70.  
  71. /* TREAD - Read a character from line, with timeout */
  72.  
  73. int tread()
  74. {
  75.     unsigned char t;
  76.     int e;
  77.     int w = 0;
  78.  
  79.     do
  80.     {
  81.          if (!io_pend(ttychid,1))                /* Check for pending input */
  82.          {
  83.               io_fbyte(ttychid,0,&t);            /* If a byte available, */
  84.               if (parity!=PYNONE) t &= 0177;     /* remove parity */
  85.               return((int) t);                   /* and return immediately */
  86.          }
  87.          w++;                                    /* otherwise continue */
  88.     } while ((e = chkint())>=0 &&
  89.              (w<tvalue || !timer));              /* until timeout or interrupt */
  90.     if (e==INTE) return(e);                      /* ^E interrupt */
  91.     if (debon) printf("Receiver timeout\n");
  92.     return(BAD);                                 /* Timeout */
  93. }
  94.  
  95.  
  96. /* CHKINT - Check for console interrupts */
  97.  
  98. int chkint()
  99. {
  100.     unsigned char ch;
  101.  
  102.     if (!io_pend(fgetchid(stdin),0))
  103.     {
  104.          io_fbyte(fgetchid(stdin),0,&ch);         /* If a key pressed, read it */
  105.          switch (ch)
  106.          {
  107.  
  108. case 'B'-'@':                                    /* CTRL-B */
  109. case 'Z'-'@':                                    /* CTRL-Z */
  110.               if (state==S_DATA || state==R_DATA)
  111.               {
  112.                    intrpt("Batch aborted");
  113.                    czseen = TRUE;
  114.               }
  115.               endcase;
  116.  
  117. case 'F'-'@':                                    /* CTRL-F */
  118. case 'X'-'@':                                    /* CTRL-X */
  119.               if (state==S_DATA || state==R_DATA)
  120.               {
  121.                    intrpt("File aborted");
  122.                    cxseen = TRUE;
  123.               }
  124.               endcase;
  125.  
  126. case 'E'-'@': return(INTE);                      /* CTRL-E */
  127.  
  128. case 'T'-'@': intrpt("Forced timeout");          /* ENTER */
  129.               return(BAD);
  130.  
  131.          }
  132.     }
  133.     return(0);
  134. }
  135.  
  136.  
  137. /* FLUSHINPUT - Dump all pending input to clear stacked up NAKs */
  138.  
  139. flushinput()
  140. {
  141.     char dump;
  142.  
  143.     if (debon) printf("Flushing input on %s\n",ttyname);
  144.     while (io_pend(ttychid,1)==0) io_fbyte(ttychid,0,&dump);
  145.     if (debon) printf("Input flushed\n");
  146. }
  147.  
  148.  
  149. /* ERROR - Print an error message */
  150.  
  151. error(fmt,a1,a2,a3,a4,a5)
  152. char *fmt;
  153. {
  154.     printf("ERROR: ");
  155.     printf(fmt,a1,a2,a3,a4,a5);
  156.     printf("\n");
  157. }
  158.  
  159.  
  160. /* PRERRPKT - Print contents of error packet received from remote host */
  161.  
  162. prerrpkt(msg)
  163. char *msg;
  164. {
  165.     printf("REMOTE ERROR: %s\n",msg);
  166. }
  167.  
  168.  
  169. /* INTRPT - Print a transfer interruption message */
  170.  
  171. intrpt(msg)
  172. char *msg;
  173. {
  174.     printf("INTERRUPT: %s\n",msg);
  175. }
  176.  
  177.  
  178. /* STNAME - return a printable state name */
  179.  
  180. char *stname(st)
  181. int st;
  182. {
  183.     switch(st)
  184.     {
  185.  
  186. case ABORT:   return("ABORT");
  187. case COMP:    return("COMPLETE");
  188. case IDLE:    return("IDLE");
  189. case R_INIT:  return("REC_INIT");
  190. case R_FILE:  return("REC_FILE");
  191. case R_DATA:  return("REC_DATA");
  192. case S_INIT:  return("SEND_INIT");
  193. case S_FILE:  return("SEND_FILE");
  194. case S_DATA:  return("SEND_DATA");
  195. case S_EOF:   return("SEND_EOF");
  196. case S_BRK:   return("SEND_EOT");
  197. case S_COMD:  return("SEND_SERVER_CMD");
  198. case G_INIT:  return("SEND_SERVER_INIT");
  199. case K_ERR:   return("SEND_ERROR");
  200. default:      return("UNKNOWN");
  201.  
  202.     }
  203. }
  204.  
  205.  
  206. /* RTLIM - Retry limit exceeded */
  207.  
  208. int rtlim()
  209. {
  210.     strcpy(errdata,"Retry limit exceeded");
  211.     error(errdata);
  212.     return(K_ERR);
  213. }
  214.  
  215.  
  216. /* INTERRUPT - CTRL-E pressed to cause error abort */
  217.  
  218. int interrupt()
  219. {
  220.     strcpy(errdata,"CTRL-E interrupt");
  221.     intrpt("Transaction aborted");
  222.     return(K_ERR);
  223. }
  224.  
  225.  
  226. /* ERRSTR - give a description for a QDOS error */
  227.  
  228. char *errstr(code)
  229. int code;
  230. {
  231.     switch (-code)
  232.     {
  233.  
  234. case 0:  return("No error");
  235. case 1:  return("Not complete");
  236. case 2:  return("Invalid job");
  237. case 3:  return("Out of memory");
  238. case 4:  return("Out of range");
  239. case 5:  return("Buffer full");
  240. case 6:  return("Channel not found");
  241. case 7:  return("Not found");
  242. case 8:  return("Already exists");
  243. case 9:  return("In use");
  244. case 10: return("End of file");
  245. case 11: return("Drive full");
  246. case 12: return("Bad name");
  247. case 13: return("Transmit error");
  248. case 14: return("Format failed");
  249. case 15: return("Bad parameter");
  250. case 16: return("Bad medium");
  251. case 17: return("Error in expression");
  252. case 18: return("Overflow");
  253. case 19: return("Not implemented");
  254. case 20: return("Read only");
  255. case 21: return("Bad line");
  256. default: return("Unknown error");
  257.  
  258.     }
  259. }
  260.  
  261.  
  262. /* QDOSERR - An error from QDOS encountered */
  263.  
  264. int qdoserr()
  265. {
  266.     strcpy(errdata,errstr(oserr));
  267.     printf("QDOS: %s\n",errdata);
  268.     return(K_ERR);
  269. }
  270.  
  271.  
  272. /* CLOSEF - Close transfer file if open */
  273.  
  274. closef()
  275. {
  276.     if (fp>=0) close(fp);                        /* File open? */
  277.     fp = -1;
  278. }
  279.  
  280.  
  281. /* TFGET - Get a character from transfer file (from K&R - MCC library
  282.    getchar() gives EOF if the file contains more than one $FF byte
  283.    in succession!)
  284. */
  285.  
  286. int tfget()
  287. {
  288.     if (n==0)                                    /* Buffer empty? */
  289.     {
  290.          n = read(fp,buf,BLKSIZ);                /* Read data */
  291.          bufp = 0;                               /* and restore pointer */
  292.     }
  293.  
  294.     return((--n>=0) ? buf[bufp++]&0377 : EOF);   /* Return data or EOF indication */
  295. }
  296.  
  297.  
  298. /* DEVOPEN - open transfer file, using appropriate device if necessary */
  299.  
  300. int devopen(name,dev,mode)
  301. char *name,*dev;
  302. int mode;
  303. {
  304.     strcpy(newfilnam,name);                      /* Name for first try */
  305.     if ((fp = open(newfilnam,mode))<0)
  306.     {
  307.          oserr = _oserr;
  308.          if (debon) printf("Open %s failed\n",newfilnam);
  309.          if (oserr==ERR_NF)                      /* Maybe device name left off */
  310.          {
  311.               strcpy(newfilnam,dev);             /* Add device name */
  312.               strcat(newfilnam,name);            /* to given name */
  313.               if ((fp = open(newfilnam,mode))<0)
  314.               {
  315.                    oserr = _oserr;
  316.                    if (debon) printf("Open %s failed\n",newfilnam);
  317.               }
  318.          }
  319.     }
  320.  
  321.     n = bufp = 0;                                /* Initialise read pointers */
  322.     return(fp);
  323. }
  324.  
  325.  
  326. /* CLS - clear a window */
  327.  
  328. cls(chan)
  329. char *chan;
  330. {
  331.     struct REGS in,out;
  332.  
  333.     in.D0 = 0x20;                                /* SD.CLEAR */
  334.     in.D3 = -1;                                  /* Timeout */
  335.     in.A0 = chan;                                /* Channel */
  336.  
  337.     QDOS3(&in,&out);
  338. }
  339.  
  340.  
  341. /* SETBAUD - Set the communication line baud rate */
  342.  
  343. setbaud(speed)
  344. int speed;
  345. {
  346.     struct REGS in,out;
  347.  
  348.     in.D0 = 0x12;                                /* MT.BAUD */
  349.     in.D1 = (short) speed;                       /* Baud rate */
  350.  
  351.     if (QDOS1(&in,&out)==0) return(speed);
  352.     else return(-1);
  353. }
  354.  
  355.  
  356. /* WAIT - Delay for d seconds, or until a key pressed */
  357.  
  358. wait(d)
  359. int d;
  360. {
  361.     int i;
  362.  
  363.     for (i = 0; i<d && (io_pend(fgetchid(stdin),0)!=0); i++) mt_susjb(1*50);
  364. }
  365.  
  366.  
  367. /* MT_SUSJB - Sleep this job for w frames (1/50s) */
  368.  
  369. mt_susjb(w)
  370. int w;
  371. {
  372.     struct REGS in,out;
  373.  
  374.     in.D0 = 0x08;                                /* MT.SUSJB */
  375.     in.D1 = -1;                                  /* Current job */
  376.     in.D3 = (short) w;                           /* Timeout */
  377.     in.A1 = 0;                                   /* No flag byte */
  378.  
  379.     QDOS1(&in,&out);
  380. }
  381.  
  382.  
  383. /* PTYPE - return a string for parity type p */
  384.  
  385. char *ptype(p)
  386. int p;
  387. {
  388.     switch(p)
  389.     {
  390.  
  391. case PYNONE: return("none");
  392. case PYEVEN: return("even");
  393. case PYODD:  return("odd");
  394. case PYMARK: return("mark");
  395. case PYSPC:  return("space");
  396. default:     return("UNKNOWN");
  397.  
  398.     }
  399. }
  400.  
  401.  
  402. /* MKTTNAM - build a name to open the serial port with */
  403.  
  404. int mkttnam(line,pty)
  405. int line,pty;
  406. {
  407.      int i;
  408.  
  409.      strcpy(ttyname,"ser");                      /* First part of name */
  410.      i = strlen(ttyname);
  411.  
  412.      ttyname[i++] = line+'0';                    /* Port number */
  413.  
  414.      switch (pty)                                /* Parity setting */
  415.      {
  416. case PYEVEN: ttyname[i++] = 'e'; endcase;
  417. case PYODD:  ttyname[i++] = 'o'; endcase;
  418. case PYMARK: ttyname[i++] = 'm'; endcase;
  419. case PYSPC:  ttyname[i++] = 's'; endcase;
  420.      }
  421.  
  422.      ttyname[i++] = 'h';                         /* Use handshake */
  423.      ttyname[i++] = 'r';                         /* Raw data */
  424.      ttyname[i] = '\0';                          /* Terminate the string */
  425.      return(i);                                  /* and return the length */
  426. }
  427.  
  428.  
  429. /* NEWTTY - re-open a serial port with the current settings */
  430.  
  431. int newtty()
  432. {
  433.     if (ttyfd>0)
  434.     {
  435.          close(ttyfd);                           /* Close old line if open */
  436.          if (debon) printf("Closed %s\n",ttyname);
  437.          ttyfd = -1;
  438.     }
  439.  
  440.     ttyname[0] = '\0';                           /* and clear out name */
  441.     local = FALSE;                               /* and status */
  442.  
  443.     if (serno>0)                                 /* New line to be opened? */
  444.     {
  445.          mkttnam(serno,parity);                  /* Make new name */
  446.          ttyfd = open(ttyname,O_RDWR);           /* Open line */
  447.          if (ttyfd<0)                            /* Open failed? */
  448.          {
  449.               oserr = _oserr;                    /* Save QDOS error code */
  450.               error("Cannot open %s",ttyname);   /* Print error messages */
  451.               qdoserr();
  452.               speed = -1;                        /* Unset line parameters */
  453.               return(-2);
  454.          }
  455.          local = TRUE;                           /* Set local/remote status */
  456.          ttychid = (int) getchid(ttyfd);         /* Reset channel ID */
  457.          if (debon) printf("Opened %s\n",ttyname);
  458.     }
  459.     else speed = -1;                             /* Remote mode, unset speed */
  460.  
  461.     return(0);
  462. }
  463.  
  464.  
  465. /* DISCARD - delete an incomplete file, if appropriate flag set */
  466.  
  467. discard(fn)
  468. char *fn;
  469. {
  470.     if (!keep)
  471.     {
  472.          unlink(fn);
  473.          printf("Discarded %s\n",fn);
  474.     }
  475. }
  476.  
  477.  
  478. /* CHKQUOTE - Check for a valid quote character */
  479.  
  480. bool chkquote(c)
  481. char c;
  482. {
  483.     return((c>' ' && c<'@') || (c>'a' && c<DEL));
  484. }
  485.  
  486.  
  487. /* NAMEPATCH - change our job name from "C-PROG" to something sensible */
  488.  
  489. namepatch()
  490. {
  491.     char *p;                                     /* Destination pointer */
  492.     char *s = "Kermit";                          /* New job name */
  493.     struct REGS in,out;
  494.  
  495.     in.D0 = 0;                                   /* MT.INF */
  496.     QDOS1(&in,&out);                             /* Get our job ID */
  497.  
  498.     in.D0 = 2;                                   /* MT.JINF */
  499.     in.D1 = out.D1;                              /* Job ID */
  500.     in.D2 = 0;                                   /* Parent ID */
  501.     QDOS1(&in,&out);                             /* Get our base address */
  502.  
  503.     p = out.A0+8;                                /* Point to job name length */
  504.     if (*((short *) p)==6)                       /* Check it */
  505.     {
  506.          p += 2;
  507.          while (*s!='\0') *p++ = *s++;           /* and copy in new one */
  508.     }
  509. }
  510.  
  511.  
  512. /* RTOL - convert a filename from Kermit- to QL-format:  (a) change '.'s
  513.    to '_'s, (b) make letters lower case
  514. */
  515.  
  516. rtol(new,old)
  517. char new[],old[];
  518. {
  519.     int i;
  520.     char c;
  521.  
  522.     if (trans==FNUNTR) strcpy(new,old);          /* Literal mode , don't convert */
  523.     else
  524.     {
  525.          for (i = 0; (c = old[i])!='\0'; i++)
  526.          {
  527.               if (c=='.') new[i] = '_';
  528.               else if (isupper(c)) new[i] = tolower(c);
  529.               else new[i] = c;
  530.          }
  531.          new[i] = '\0';
  532.     }
  533.  
  534.     if (debon) printf("rtol: converted %s to %s\n",old,new);
  535.  
  536. }
  537.  
  538.  
  539. /* LTOR - convert a filename from QL- to Kermit-format:  (a) remove first
  540.    component (device name), (b) change last '_' to '.', (c) make letters
  541.    upper case.  We know that old[] has at least 2 components here (the QL
  542.    device name and the file name).
  543. */
  544.  
  545. ltor(new,old)
  546. char new[],old[];
  547. {
  548.     int l,s,j;
  549.     char c;
  550.     char wrk[30];
  551.  
  552.     if (trans==FNUNTR) strcpy(new,old);          /* Literal mode, don't convert */
  553.     else
  554.     {
  555.          strcpy(wrk,old);                        /* Take local copy of name */
  556.          if (strlen(suffix)>0)                   /* Suffix to be added? */
  557.          {
  558.               strcat(wrk,"_");                   /* Yes, add seperator */
  559.               strcat(wrk,suffix);                /* then the suffix */
  560.          }
  561.  
  562.          s = (int) (strchr(wrk,'_')-wrk+1);      /* Find start of 2nd component */
  563.          l = (int) (strrchr(wrk,'_')-wrk);       /* and last underscore */
  564.  
  565.          for (j = 0; (c = wrk[s])!='\0'; s++,j++)
  566.          {
  567.               if (s==l) new[j] = '.';
  568.               else if (islower(c)) new[j] = toupper(c);
  569.               else new[j] = c;
  570.          }
  571.          new[j] = '\0';
  572.     }
  573.  
  574.     if (debon) printf("ltor: converted %s to %s\n",old,new);
  575.  
  576. }
  577.  
  578.  
  579. /* TCLOSE - close the current TAKE file */
  580.  
  581. tclose()
  582. {
  583.     fclose(tfile[tlevel--]);
  584.     if (debon) printf("TAKE file level %d closed\n",tlevel+1);
  585. }
  586.