home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / c / crcbbs.arc / CRCPC0C.C < prev    next >
Text File  |  1985-10-22  |  17KB  |  751 lines

  1. #include    "crcpchdr.h"
  2.  
  3. /* Adaptation of standard newline() and spout(); open() used inst.of. sopen() */
  4.  
  5. int newline()
  6. {
  7. spout("\r\n",0,1);
  8. return quit;
  9. }
  10.  
  11. spout(line,arg1,arg2)
  12. char *line;
  13. int arg1, arg2;
  14. {
  15. static int linectr;
  16. char yesno[5], c;
  17.  
  18. if (arg1==0) linectr = 0;
  19. if (line[0]=='\0') return;
  20. linectr += mputs(line);
  21. if (utlength) {
  22.     if (linectr>=utlength) {
  23.         c=*disp_reply("More?",yesno,sizeof(yesno));
  24.         if (stpchr("NnQq",*yesno)!=NULL) quit = TRUE;
  25.         linectr = 0;
  26.         }
  27.     }
  28. else linectr = 0;
  29. }
  30.  
  31. /* Chop off the last node level in a DOS pathname  */
  32. up_node(innode)
  33. char *innode;
  34. {
  35. int l;
  36.     
  37. if (l=strlen(innode)) {
  38.     while(--l) if (innode[l]==ESCSYM) {
  39.         innode[l] = '\0';        /* Zap it */
  40.         break;
  41.         }
  42.     }
  43. }
  44.  
  45. ubeep(times)
  46. int times;
  47. {
  48. while(times--) {
  49.     if (sys_test) pch(BEEP);
  50.     else mcharout(BEEP);
  51.     }
  52. }
  53.  
  54. int int14h(port,function,value,reg)
  55. int port;
  56. char function;
  57. char value;
  58. int reg;
  59. {
  60. rmodem.x.dx = port;
  61. rmodem.h.ah = function;
  62. rmodem.h.al = value;
  63. rmodem.x.cx = reg;
  64. int86(com_inttype,&rmodem,&rmodem);
  65. return rmodem.x.ax;
  66. }
  67.  
  68. minprdy() { return(int14h(port_used,TEST_COM,NA,NA)); }
  69. purgeline() { int14h(port_used,FLUSH_COM,NA,NA); }
  70.  
  71. int mcharinp()
  72. {
  73. while(!minprdy() && rdsr());     /* Do nothing until ready or hangup */
  74. if (!rdsr()) return 0;        /* Leave if hangup */
  75. return(int14h(port_used,READ_COM,NA,NA) & 0xFF);
  76. }
  77.  
  78. mcharout(c)
  79. char c;
  80. {
  81. if (!rdsr()) return;
  82. int14h(port_used,WRITE_COM,c,NA);
  83. }
  84.  
  85. prmodm(string)        /* SPECIAL OUTPUT RTN, FOR 1200B - DTR ALWAYS ON */
  86. bhar *string;
  87. {            /* Partly my slop, but DREAD I have to do it ! */
  88. while (*string) {
  89.     mcharout(*string++);
  90.     }
  91. }
  92.  
  93. rdsr() { return(int14h(port_used,STATS_COM,NA,NA)&B7); }  /* Use RLSD */
  94.  
  95. drop_carrier()            /* Should work on most modems.  General */
  96. {                /* Drop DTR & RTS for BRKTIM "for" loops */
  97. int c, i;
  98. c = int14h(port_used,READ_UART,NA,MCR); /* Read the MCR register */
  99. int14h(port_used,WRITE_UART,c&(B2|B3|B4|B5|B6|B7),MCR); /* Off DTR & RTS */
  100. for (i=0;i<BRKTIM;i++) ;        /* Keep "OFF" for duration */
  101. int14h(port_used,WRITE_UART,c,MCR);     /* Restore DTR & RTS */
  102. }
  103.  
  104. reset_h1200b() 
  105. {
  106. int c, i;
  107. c = int14h(port_used,READ_UART,NA,MCR);     /* Read the MCR register */
  108. int14h(port_used,WRITE_UART,c | B2,MCR);    /* Set OUT1 on H1200b = "OFF" */
  109. for (i=0;i<BRKTIM;i++) ;            /* Keep "OFF" for duration */
  110. int14h(port_used,WRITE_UART,c,MCR);         /* Switch modem back on */
  111. }
  112.  
  113. int hs1200b()
  114. {
  115. return(!(int14h(port_used,READ_UART,NA,HSR)&B0)); /* TRUE iff (xFF).B0 FALSE */
  116. }
  117.  
  118. waitterm()
  119. {
  120. while(dsr() && int14h(port_used,CHECK_OQ,NA,NA)); /* Wait for output queue */
  121. }
  122.  
  123. /*  hangup: tell the modem (if modem is in answer mode) to hangup the phone. */
  124. /* We wait until the output buffer is empty, however */
  125. hangup()
  126. {
  127. waitterm();        /* wait till all characters in queue are sent */
  128. drop_carrier();        /* Reset DTR, RTS on MODEM */
  129. }
  130.  
  131. /* 
  132.     (int)    parsetok(s, argcptr, argv)
  133.         char *s;        /* Input string to be parsed in place */
  134.         int *argcptr;        /* Pointer to input/output integer */
  135.         char *argv[];        /* String token array */
  136.  
  137.     This function parses the input string (in place by placing \0's
  138.     after 'tokens' in string) and returning token addresses in 'argv'
  139.     array.  Must set '*argcptr' to maximum size of string array 'argv[]'.
  140.     '*argcptr' will be set to number of tokens actually parsed at exit,
  141.     in addition, NULL (0) will be written to first invalid token ptr.
  142.     Note therefore that size of array must be one larger than maximum
  143.     number of tokens allowed (as defined by '*argcptr' at start).
  144.  
  145.     returns:    0    parse went well, *argcptr = # tokens
  146.                !0    error, probably too may tokens in string
  147.  
  148. */
  149.  
  150. int parsetok(s,argcptr,argv)
  151. char s[];
  152. int *argcptr;
  153. char *argv[];
  154. {
  155. int maxarg;
  156.  
  157. if ((maxarg=(*argcptr)-1)<0) return -1;        /* Must provide n+1 pointers */
  158. *argcptr = 0;
  159. while (isspace(*s)) s++;
  160. while (*s != '\0' && *argcptr < maxarg) {
  161.     argv[(*argcptr)++] = s;
  162.     while (*s != '\0' && isspace(*s) == 0) s++;
  163.     if (*s == '\0') break;
  164.     *s++ = '\0';
  165.     while (isspace(*s)) s++;
  166.     }
  167. argv[*argcptr] = NULL;        /* End list with NULL */
  168. return(*s != '\0');        /* Did we quit other than because of end ? */
  169. }
  170.  
  171. char *input_pw(len)
  172. int len;
  173. {
  174. char *string;
  175. int what_it_used_to_be;
  176.  
  177. what_it_used_to_be = silence ;
  178. silence = TRUE;
  179. string = rtrim(stpblk(uppercase(lineinput(len))));
  180. silence = what_it_used_to_be;
  181. return(string);
  182. }
  183.  
  184. long timesec(hh,mm,ss)
  185. int hh,mm,ss;
  186. {
  187. return((long)hh*(long)SECPERHR+(long)mm*(long)SECPERMIN+(long)ss);
  188. }
  189.  
  190. /* TIME DIFF: Returns time (in seconds) difference between mm1/dd1/yy1 & -2 */
  191. /* I.E. TIME1 is start time, TIME2 is end time.             */
  192. long time_diff(hh1,mm1,ss1,hh2,mm2,ss2)
  193. int hh1,mm1,ss1,hh2,mm2,ss2;
  194. {
  195. long diff, timesec();
  196. diff = timesec(hh2,mm2,ss2)-timesec(hh1,mm1,ss1);
  197. if (diff<0) diff+=((long)HRS_IN_DAY*(long)SECPERHR); /* NOTE: Only ONE day grace given! */
  198. return(diff);
  199. }
  200.  
  201.  
  202. /* WAIT_SEC(nsec):  This routine waits at least (nsec) seconds before returning
  203.     (timing loop)  */
  204. wait_sec(nsec)
  205. int nsec;
  206. {
  207. int hh1,mm1,ss1,ms1;
  208. int hh2,mm2,ss2,ms2;
  209. systime(&hh1,&mm1,&ss1,&ms1);
  210. do systime(&hh2,&mm2,&ss2,&ms2);
  211.    while(time_diff(hh1,mm1,ss1,hh2,mm2,ss2)<=nsec);
  212. }
  213.  
  214. char *elapsed_time(diff)
  215. long diff;
  216. {
  217. static char eltime[25];
  218. char workstr[25];
  219. long hh,mm,ss;
  220.  
  221. if (diff<0) diff+=(long)HRS_IN_DAY*(long)SECPERHR; /* NOTE: Only ONE day grace given! */
  222.  
  223. hh = diff / (long)(SECPERHR);
  224. mm = (diff-(hh*(long)(SECPERHR))) / (long)(SECPERMIN);
  225. ss = diff - hh*(long)(SECPERHR) - mm*(long)(SECPERMIN);
  226. workstr[0] = '\0';
  227. eltime[0]  = '\0';
  228. if (hh>0L) {
  229.     sprintf(eltime,"%ld hr",hh);
  230.     strcat(workstr,eltime);
  231.     }
  232. if (mm>0L) {
  233.     sprintf(eltime," %ld min",mm);
  234.     strcat(workstr,eltime);
  235.     }
  236. if ((hh==0L && mm==0L) || ss>0L) {
  237.     sprintf(eltime," %ld sec",ss);
  238.     strcat(workstr,eltime);
  239.     }
  240. strcpy(eltime,workstr);
  241. return(stpblk(eltime));
  242. }
  243.  
  244. char *date()
  245. {
  246. static char datestr[12];
  247. int mo,dy,yr;
  248. sysdate(&mo,&dy,&yr);
  249. sprintf(datestr,"%02d/%02d/%02d",mo,dy,yr-BASEYEAR);
  250. return(datestr);
  251. }
  252.  
  253. char *time()
  254. {
  255. static char timestr[9];
  256. int hh,mm,ss,ms;
  257. systime(&hh,&mm,&ss,&ms);
  258. sprintf(timestr,"%d:%02d%c",hh>12?hh-12:hh,mm,hh>11?'p':'a');
  259. return(timestr);
  260. }
  261.  
  262. int abbrev(s,w,l)
  263. char s[], w[];
  264. int l;
  265. {
  266. int i,wl;
  267.  
  268. for (i=0,wl=strlen(w);i<wl;i++) {
  269.     if (s[i]!=w[i]) return 0;
  270.     }
  271. return (i>=l);    
  272. }
  273.  
  274. dupchar(n,c)
  275. int n;
  276. char c;
  277. {
  278. while(n-->0) pch(c);
  279. }
  280.  
  281. /* 
  282.     find_option:    Returns TRUE if character OP found in string OPTS.
  283.             Performs upper case conversion if necessary on OP.
  284. */
  285. int find_option(opts,op)
  286. char *opts, op;
  287. {
  288. if (stpchr(opts,op)!=NULL) return(TRUE);
  289. else return(stpchr(opts,toupper(op))!=NULL);
  290. }
  291.  
  292. /* 
  293.     strip_options:    We write to the 20 character array OPTS the
  294.             option string we find in the first token position
  295.             of ARGS.  If the first token does not begin with
  296.             a '-', then OPTS gets zapped and we return the 
  297.             left justified ARGS string.
  298.         If args are found, they are left in OPTS -- WITHOUT the
  299.         negative sign.  Use routine 'FIND_OPTION' to test for 
  300.         presence of options.
  301. */
  302. char *strip_options(args,opts)
  303. char *args, opts[];
  304. {
  305. char *op, *ap;
  306. opts[0] = '\0';
  307. if (args==NULL||!*args) return(args);    /* Should never be null, but ... */
  308. op = stpblk(args);        /* Start of arg list should be option(s) */
  309. ap = stptok(op,opts,20," ");    /* Break out options, if present */
  310.  
  311. if (op[0]=='-') return(stpblk(ap));    /* Return, pointing to args */
  312. else {     
  313.     opts[0]='\0';        /* No arguments, not recognized first token */
  314.     return(op);        /* Return left trimmed argument pointer */
  315.     }
  316. }
  317.  
  318. char yesno()
  319. {
  320. char c;
  321. c = *lineinput(4);
  322. c = toupper(c);
  323. return(c);
  324. }
  325.  
  326. char *itos(val)
  327. int val;
  328. {
  329. static char buf[10];
  330. sprintf(buf,"%d",val);
  331. return(buf);
  332. }
  333.  
  334. char *ftos(fval)
  335. float fval;
  336. {
  337. static char floatbuf[20];
  338. sprintf(floatbuf,"%f",fval);
  339. return(floatbuf);
  340. }
  341.  
  342. nothing_done() { printf("Nothing done\r\n"); }
  343.  
  344. char *uppercase(s)
  345. char s[];
  346. {
  347. int i;
  348. for(i=0;s[i];i++) s[i]=toupper(s[i]);
  349. return(s);
  350. }
  351.  
  352. char *rtrim(s)
  353. char s[];
  354. {
  355.         int i;
  356.         i = strlen(s);              /* Find end of string */
  357.     if (i) {
  358.             while(s[--i]==' ' && i>=0);  /* Back up over spaces until start */
  359.         s[++i] = '\0';     /* Put null where last space was */
  360.         }
  361. return(s);
  362. }
  363.  
  364. char *lineinput(maxl)
  365. int maxl;
  366. {                
  367. char *string;   
  368. static char conbuff[STR_SIZE];
  369.         output = TRUE;
  370.         if (maxl>STR_SIZE) conbuff[0] = STR_SIZE;
  371.         else conbuff[0] = maxl;         /* inform it of its own limits */
  372.         string = mgets(conbuff);
  373.         cr();
  374.         return (string);
  375. }
  376.  
  377. char *disp_reply(outstr,instr,maxlen)
  378. char outstr[], instr[];
  379. int maxlen;
  380. {
  381. printf(outstr);
  382. strcpy(instr,rtrim(ltrim(lineinput(maxlen))));
  383. return(instr);
  384. }
  385.  
  386. int sysdir(dirname,rootname)
  387. char *dirname, *rootname;
  388. {
  389. static char curdir[DIRSIZE];
  390. static char curroot[ROOTSIZE];
  391. int rc;
  392.                 /* Attempt to normalize (standardize) dir */
  393. uppercase(dirname);
  394. if (*dirname==ESCSYM) dirname++;
  395. zaphesc(dirname);
  396. if (!strcmp(curdir,dirname) && !strcmp(curroot,rootname)) return(0); 
  397. if ((rc=dos_dir_int(dirname,DOS_CHDIR,rootname))==0) {
  398.         strcpy(curdir,dirname);
  399.         strcpy(curroot,rootname);
  400.         }
  401. return(rc);
  402. }
  403.  
  404. int typefile(filename,opts)
  405. char *filename;
  406. char *opts;
  407. {
  408.     FILE *fp ;
  409.     int quiet;
  410.  
  411.     quiet = find_option(opts,'q');
  412.     if (!dsr()) return;
  413.     if (*filename=='\0') return(1);
  414.     else if ((fp=fopen(filename,"r")) == NULL) {
  415.         printf("FILE '%s' NOT FOUND.\r\n",filename);
  416.         return(2);
  417.         }
  418.     else {
  419.         if (beginner && !quiet) ctlsctlk();
  420.         fileterm(fp,opts);    /* type out the file onto the terminal */
  421.         fclose(fp);
  422.         return(0);
  423.         }
  424. }
  425.  
  426. cls() { if (*utcls) printf(utcls); }
  427.     /* Print user clear screen sequence */
  428.  
  429. fileterm(fp,opts)    /* Type a disk file onto the local terminal */
  430. FILE *fp;
  431. char *opts;
  432. {
  433.     char *cp, c;
  434.     char file_buff[LINESIZE+1];
  435.     int page, lc;    
  436.  
  437.     output = TRUE;
  438.     quit = FALSE;
  439.     page = find_option(opts,'p');
  440.     if (find_option(opts,'t')) page = FALSE;    /* Text override */
  441.     lc = 0;
  442.         /* Don't force users off while they are reading a file */
  443.     noforcenow = TRUE;
  444.     
  445.     while(fgets(file_buff,termwidth,fp)!=NULL && !quit && dsr()) {
  446.         if ((cp=stpchr(file_buff,CTLZ))!=NULL) {
  447.             *cp = '\0';
  448.             lc += mputs(file_buff);
  449.             break;
  450.             }
  451.         else lc += mputs(file_buff);
  452.         if (utlength && lc>=utlength && page) {
  453.             if (beginner) printf("<ENTER> for more, Q to abort: ");
  454.             else printf("More? ");
  455.             quit |= ((c=yesno())=='Q' || c=='N');
  456.             lc = 0;
  457.             if (!quit) cls();
  458.             }
  459.         }
  460.  
  461.     noforcenow = FALSE;
  462. }
  463.  
  464. ctlsctlk() { mputs("\r\nUse CTL-S or S to pause, CTL-K or K to abort.\r\n"); }
  465.  
  466. char *skptok(str)
  467. char *str;
  468. {
  469. char *ans;
  470.  
  471. ans = stpbrk(str," \r");
  472. return(ans==NULL?"":stpblk(ans));
  473. }
  474.  
  475. long stol(s)
  476. char *s;
  477. {
  478.     long n;
  479.     n = 0;
  480.     s = stpblk(s);
  481.     while(*s >= '0' && *s <= '9') n=10*n+*s++-'0';
  482.     return(n);
  483. }
  484.  
  485. int stoi(s)
  486. char *s;
  487. {
  488. return((int)stol(s));
  489. }
  490.  
  491. iputs(s) char *s; { int i; while(*s++) pch(' '); }
  492.  
  493. esc() { printf("\\\r\n"); }
  494.  
  495. bs() { pch(BS); pch(' '); pch(BS); }
  496.    /* Should be smart or dumb: need flag */
  497. cr() { mputs("\r\n"); }
  498.  
  499. warn_omem() { printf("Out of memory!\r\n"); }
  500.  
  501. pch(c) char c; { bdos(OUTMODE,c); }
  502.  
  503. int badfile(filename) 
  504. char *filename;
  505. printf("Can't open file %s\r\n",uppercase(filename));
  506. return(4);
  507. }
  508.  
  509. /* Zap Hanging ESCape symbol - so can be sloppy about path specifications */
  510. char *zaphesc(str)
  511. char *str;
  512. {
  513. int i;
  514.  
  515. if (i=strlen(str)) {
  516.     if (str[--i]==ESCSYM) {
  517.         if (i==0 || str[i-1]==DRVSYM) ;
  518.         else str[i] = '\0';
  519.         }
  520.     }
  521. return str;
  522. }
  523.  
  524. /* Preliminery subroutines for directory handling functions */
  525. /* NOTE: Caller to PREFIX_DIR MUST TAKE CARE OF OWN OUTPUT BUFFER ! */
  526. char *prefix_dir(buffer,dirname,rootname)
  527. char buffer[], *dirname, *rootname;
  528. {
  529. strcpy(buffer,rootname);
  530. if (!buffer[0] || dirname[0]) {
  531.     if (!strcmp(dirname,"..")) {    /* Back up one node if possible */
  532.         up_node(buffer);
  533.         return(buffer);
  534.         }
  535.     else if (!strcmp(dirname,".")) return(buffer);
  536.             /* Make sure is ESCSYM between root & dir */
  537.     if (buffer[0] && buffer[strlen(buffer)-1]==ESCSYM) ;
  538.     else strcat(buffer,ESCSTR);
  539.     if (*dirname==ESCSYM) dirname++; /* strip leading ESCSYM from dir */
  540.     strcat(buffer,dirname);
  541.     }
  542. zaphesc(buffer);        /* Zap hanging esc sym if possible */
  543. return(buffer);
  544. }
  545.  
  546. int dos_dir_int(dirname,function,rootname)
  547. char dirname[], rootname[];
  548. int function;
  549. {
  550. char buffer[2*(DIRSIZE+1)];
  551. return(bdos(function,prefix_dir(buffer,dirname,rootname)));    
  552. }
  553.  
  554. badnum(s)
  555. char *s;
  556. {
  557. printf("Number expected but read '%s'\r\n",s);
  558. }
  559.  
  560.  
  561. /* 
  562.     mputs: General output driver.   Returns number of physical lines taken
  563. */
  564. int mputs(s)
  565. char *s;       
  566. {
  567.     char c,f;
  568.     int wait_flg;
  569.     int i,j;
  570.  
  571.     for (j=0,i=1,wait_flg=FALSE;*s && dsr() && !quit;++s) {
  572.         do {
  573.             if (bdos(KBHIT)) {
  574.                 c = bdos(CONSINP);
  575.                 c = toupper(c);
  576.                 switch(c) {
  577.                     case NULL: 
  578.                         local_function(bdos(CONSINP));
  579.                         i = 0;
  580.                         break;
  581.                     case 'O':
  582.                     case CTL_O: output = FALSE;
  583.                             i = 0;
  584.                             j++;
  585.                             printf("\r\n");
  586.                             break;
  587.                     case 'P':
  588.                     case CTL_P: output = TRUE;
  589.                             break;
  590. /*                    case 'S':
  591.                     case CTL_S: wait_flg = TRUE;
  592.                             break;
  593.                     case 'Q':
  594.                     case CTL_Q: wait_flg = FALSE;
  595.                             output = TRUE;
  596.                             break;
  597. */                    case 'K':
  598.                     case CTL_K: quit = TRUE;
  599.                             i = 0;
  600.                             j++;
  601.                             printf("\r\n");
  602.                             break;
  603.                     default: wait_flg = FALSE;
  604.                          }
  605.                 }
  606.             } while(wait_flg && dsr());    /* End WHILE */
  607.         if (output && !quit) {
  608.             bdos(OUTMODE,*s);
  609.     /* Do our best to anticipate horizontal cursor movement in 'i' */
  610.             if (i && *s=='\b') i--;
  611.             else if (*s=='\n') j++;
  612.             else if (*s=='\r') i=0;
  613.             else if (*s=='\t') i=i+9-i%8; /* assume tabs are *8 */
  614.             else i++;
  615.             }
  616.         if (utwidth && i>utwidth) {  /* Insert auto-CRLF on line wrap */
  617.             printf("\r\n");
  618.             i = 0;
  619.             j++;
  620.             }
  621.         }  /* End FOR  */
  622. return(j);
  623. }
  624.  
  625. char *mgets(string)
  626. char string[];
  627. {
  628. char c;
  629. int i;                /* Index to STRING (current buffer). Starts=2 */
  630. int k;                /* Index to LASTBUF for CTL_B function */
  631. static char lastbuf[LSTCSIZE];
  632. unsigned loops, secs, mins;
  633. long remaining;
  634. long cnct_seconds();
  635.  
  636. i=2;  k=0;
  637. quit = FALSE;
  638. output = TRUE;
  639. if (!beingforced) {
  640.     remaining=((long)maxconnect*(long)SECPERMIN)-cnct_seconds();
  641.     if (remaining>0L && remaining<=(long)WARN_TIME && !noforcenow) {
  642.         printf("\r\nNOTE: Please finish up now; only %s left\r\n",elapsed_time(remaining));
  643.         }
  644.     else if (remaining<=0L && !noforcenow) {
  645.         ubeep(1);
  646.         printf("\r\nMaximum visiting time has been exceeded.\r\n");
  647.         printf("Please limit your sessions to %d minutes\r\n",maxconnect);
  648.         if (!no_account) printf("Leave feedback if you need an extension\r\n");
  649.         ubeep(1);
  650.         beingforced = TRUE;
  651.         goto putnil;
  652.         }
  653.     if (string[0]>1) do {
  654.     tryagain:
  655.         for (mins=0;mins<MAXINPUTTIME;++mins) {
  656.             if (!notimeout && mins==MAXINPUTTIME-1) {
  657.                 ubeep(2);
  658.                 printf("\r\n** One minute until input timeout -> forced hangup **\r\n");
  659.                 ubeep(2);
  660.                 }
  661.             for (secs=0;secs<SECSPERMIN;++secs) {
  662.                 for (loops=0;loops<LOOPSPERSEC;++loops) {
  663.                     if (!dsr()) goto abortinp;
  664.                     if (bdos(KBHIT)) goto got_chr;
  665.                     }
  666.                 }
  667.             }
  668.         if (notimeout) goto tryagain;
  669.         printf("\r\n*USER INPUT TIMEOUT*\r\n");
  670.         hangup();
  671.     
  672.     abortinp:    i = 2 ;
  673.             break;            /* Timeout */
  674.     
  675.     got_chr:
  676.         c = bdos(CONSINP);
  677.     chkc:    switch(c) {
  678.             case NULL: local_function(bdos(CONSINP));
  679.                 break;
  680.             case CTL_A:            /* Instant recall of last line */
  681.                 if (lastbuf[k] && string[0] > strlen(lastbuf+k)+i) {
  682.                     strcpy(string+i,lastbuf+k);
  683.                     i += strlen(lastbuf+k);
  684.                     if (silence) iputs(lastbuf+k);
  685.                     else mputs(lastbuf+k);    /* Echo it */
  686.                     }
  687.                 else ubeep(1);
  688.                 k = 0;            /* Reset lastbuf pointer */
  689.                 break;        
  690.             case CTL_B:            /* One char at a time recall */
  691.                 c = lastbuf[k];
  692.                 if (c) {
  693.                     k++;
  694.                     goto chkc;    /* I hope this is cool w/C */
  695.                     }
  696.                 else {
  697.                     ubeep(1);
  698.                     k = 0;        /* Reset lastbuf ptr for nxtme */
  699.                     }
  700.                 break;
  701.             case CTL_C:
  702.                 string[1]=0;
  703.                 string[2]='\0';
  704.                  c = '\r';
  705.                 break;
  706.             case BEEP:
  707.                 ubeep(1);
  708.                 break;
  709.             case '\b':
  710.                 if (i>2) { 
  711.                     if (string[i-1]=='\n') ubeep(1);
  712.                     else {
  713.                         bs();
  714.                         if (string[--i]<=CTLZ) bs();
  715.                         }
  716.                     }
  717.                 else ubeep(1);
  718.                 break;
  719.             case CTL_U:
  720.             case ESC:  esc(); i=2; break;
  721.             case CTL_R:
  722.                 string[i] = '\0';
  723.                 esc();
  724.                 if (silence) iputs(string+2);
  725.                 else mputs(string+2);
  726.                 break;
  727.             case '\r': bdos(OUTMODE,c); break;
  728.             default:
  729.                 if (i>string[0]) ubeep(1);
  730.                 else {
  731.                     if (c<=CTLZ && c!='\n') { 
  732.                         bdos(OUTMODE,'^'); 
  733.                         bdos(OUTMODE,c+'A'-1); 
  734.                         }
  735.                     else if (duplex==HALF) ;
  736.                     else if (silence) bdos(OUTMODE,' ');
  737.                     else bdos(OUTMODE,c);    
  738.                     string[i++] = c;
  739.                     }
  740.             }    /* End SWITCH */
  741.         } while(c!='\r');
  742.     } /* End !beingforced */
  743. putnil:
  744. string[i] = '\0';
  745. string[1] = i-2;
  746. stptok(string+2,lastbuf,sizeof(lastbuf),"");
  747. return(string+2);
  748. }
  749. 
  750.