home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol158 / yam7.c < prev    next >
Encoding:
C/C++ Source or Header  |  1984-04-29  |  20.9 KB  |  1,030 lines

  1. /*
  2. >>:yam7.c 12-16-83 for CI C86 under cp/m-86
  3.  * File open and close stuff and more ...
  4.  * This file assumes operation on a CP/M system
  5.  */
  6.  
  7. #define EXTERN extern
  8. #include "yamc86.h"
  9. /* dpb dph blocks from CP/M Interface Guide Sect 6.5 */
  10.  
  11. struct dpb {            /* CP/M Version 2 Disk Parameter Block */
  12.     unsigned dpb_spt;    /* sectors per track */
  13.     unsigned char dpb_bsh;        /* block shift factor */
  14.     unsigned char dpb_blm;
  15.     unsigned char dpb_exm;        /* Extent Mask */
  16.     unsigned dpb_dsm;    /* Highest block number on this disk */
  17.     unsigned dpb_drm;    /* total number of directory entries -1 */
  18.     unsigned dpb_al;    /* bit field corresponding to direc blocks */
  19.     unsigned dpb_cks;    /* size of the directory check vector */
  20.     unsigned dpb_off;    /* number of reserved tracks on this disk */
  21. };
  22.  
  23.  
  24.  
  25. struct dph {            /* CP/M Version 2 Disk Parameter Header */
  26.     char **dph_xlt;        /* logical to physical xlat vector */
  27.     int dph_ooo;
  28.     char *dph_dirbuf;    /* 128 byte scratchpad for directory use */
  29.     struct dpb *dph_dpb;    /* disk param block for this type of disk */
  30.     char **dph_csv;        /* scratch area for detecting changed disks */
  31.     char *dph_alv;        /* pointer to bit vector alloc map for disk */
  32. };
  33.  
  34. struct fcb {            /* CP/M Version 2 fcb AS SEEN BY THE USER */
  35.     char    dr;        /* drive number */
  36.     unsigned char fname[8];    /* fname[1] used by TAG2 */
  37.     unsigned char ftype[3];    /* ftype[1] 8th bit set for $SYS */
  38.     unsigned char ex;    /* file extent normally 0 */
  39.     unsigned char s1;    /* reserved for bdos's benefit */
  40.     unsigned char s2;    /* likewise, =0 on call to open,make,search */
  41.     unsigned char rc;    /* record count for extent[ex]  0...128 */
  42.     unsigned char dmap[16];
  43.     unsigned char cr;    /* current record, initialized to 0 by usr */
  44.     unsigned recn;        /* highest record number */
  45.     unsigned char recovf;    /* overflow of above */
  46. };
  47.  
  48. /* following are BDOS calls */
  49. #define GETVRSN 12        /* cpm bdos version number */
  50. #define SELDSK 14        /* bdos select disk 0=default disk */
  51. #define SRCH 17         /* bdos search for file pattern*/
  52. #define SRCHNXT 18        /* search for next occurrence */
  53. #define GETDEFDISK 25        /* get current disk  (0-15) */
  54. #define SETDMA 26        /* set address for read, write, etc. */
  55. #define GETALLOCP 27        /* get address of allocation vector */
  56. #define SETATTRIB 30        /* update file attributes */
  57. #define GETDPBP 31        /* get DPB address for disk */
  58. #define SETGETUSER 32        /* set or get user number */
  59. #define COMPFILSIZ 35        /* compute file size into recn and recovf */
  60. #define GETSPACE 46        /* 3.0 call to return sectors free on disk */
  61.  
  62. #define UFNSIZE 15        /* a:foobar12.urk\0 is 15 chars */
  63.  
  64. openrx(name)
  65. char *name;
  66. {
  67.  
  68.     unsigned char option;
  69. #ifdef RESTRICTED
  70.     char *s;
  71.     if(s=cisubstr(name, ".cmd"))    /* upload .cmd files as .obj */
  72.         strcpy(s, ".OBJ");
  73.     if(cisubstr(name, "$$$"))
  74.         return ERROR;        /* don't allow upload of $$$.sub */
  75.     for(s=name; *s; )
  76.         if(*s++ > 'z')
  77.             return ERROR;    /* no garbage names please */
  78. #endif
  79.     option='y'; unspace(name);
  80.     lprintf("'%s' ", name);        /* show the name right away */
  81.     if(!Creamfile && ((fout=fopen(name,"r")) != NULL)) {
  82.         fclose(fout);
  83. #ifdef XMODEM
  84.         printf("Can't upload '%s': file exists\n", name);
  85.         return ERROR;
  86. #else
  87.         printf("Exists ", name);
  88.         printf("Replace/Append/Quit (r/a/q)??");
  89.         if(!index(option=getopt(), "ary"))
  90.             return ERROR;
  91.         putchar('\n');
  92. #endif
  93.     }
  94.     if((option=='a'?(fout=fopen(name,BAPPEND)):(fout=fopen(name,BWRITE)))==NULL){
  95.         printf(" Can't create %s\n", name);
  96.         return ERROR;
  97.     }
  98.     Rfile= TRUE;
  99.     strcpy(Rname, name);
  100.     Dumping= !Squelch;
  101.     lprintf(" Open: Capture O%s\n", Dumping? "n" : "FF");
  102. #ifdef STATLINE
  103.     lpstat("Receiving %s", Rname);
  104. #endif
  105.     return OK;
  106. }
  107.  
  108. getopt()
  109. {
  110.     int c;
  111.     c = tolower(getcty());
  112.     putcty(c);
  113.     return c;
  114. }
  115.  
  116. closerx(pad)
  117. {
  118.     if(Rfile) {
  119. #ifdef BDSC
  120.         if(pad)
  121.             do
  122.                 putc(CPMEOF, fout);
  123.                 while(fout._nleft % SECSIZ);
  124. #endif
  125.         fflush(fout); fclose(fout);
  126.         Rfile=FALSE;
  127. #ifdef LOGRX
  128.         logfile(LOGRX, Rname, pad?'*':'R');    /* record file xmsn */
  129. #endif
  130.     }
  131. }
  132.  
  133. opentx(name)
  134. char *name;
  135. {
  136.     int printf();
  137. #ifdef XMODEM
  138.     int lprintf();
  139. #endif
  140. /*    struct fcb *fp, *fcbaddr(); */
  141.     char *fcbp;
  142.     int (*fnx)();
  143. #ifndef CDOS
  144.     unsigned spm, dminutes;
  145.     struct fcb fstat;
  146.     spm= Baudrate/23;
  147. #endif
  148. #ifdef XMODEM
  149.     fnx=Batch? lprintf : printf;
  150. #else
  151.     fnx=printf;
  152. #endif
  153.     (*fnx)("'%s' ", name);
  154.     unspace(name);
  155.  
  156.  
  157.     if((fin=fopen(name,BREAD))==NULL){
  158.         printf("Can't open %s\n", name);
  159.         return ERROR;
  160.     }
  161. /*
  162.  *    DOWLOADING CHECKING NOT IMPLEMENTED IN YAMC86
  163.  *
  164.  *#ifdef RESTRICTED
  165.  *    if(cisubstr(name, ".bad")
  166.  *     || (fp=fcbaddr(fin._fd))==ERROR
  167.  *     || (fp->fname[1] & 0200) */    /* tag2 */
  168. /*     || (fp->ftype[1] & 0200) */    /* $SYS */
  169. /*     ) {
  170.  *         fclose(fin); printf("\n'%s' Not for Distribution\n", name);
  171.  *        return ERROR;
  172.  *    }
  173.  *#endif
  174.  */
  175.     Tfile= TRUE;
  176.     strcpy(Tname, name);
  177. #ifndef CDOS
  178.     setfcb( &fstat, name);
  179.     bdos(COMPFILSIZ, &fstat);
  180.     dminutes= 1+((10*(1+fstat.recn))/spm)+(fstat.recn/20);
  181.     (*fnx)("Open %u Sectors %dk %u.%u Minutes\n",
  182.       fstat.recn, fstat.recn>>3, dminutes/10, dminutes%10);
  183. #ifdef STATLINE
  184.     if (!UsePutchar)
  185.         lpstat("%s %u Sectors %dk %u.%u Min",
  186.           Tname, fstat.recn, fstat.recn>>3, dminutes/10, dminutes%10);
  187. #endif
  188. #else
  189.     (*fnx)("Open\n");
  190. #endif
  191.     return OK;
  192. }
  193.  
  194. /* closetx(status) call with status != 0 if incomplete file xmsn */
  195. closetx(status)
  196. {
  197.     if(Tfile) {
  198.         fclose(fin);
  199. #ifdef LOGTX
  200.         if(!status)
  201.             logfile(LOGTX, Tname, 's');    /* record file xmsn */
  202. #endif
  203.         Tfile=FALSE;
  204.     }
  205. }
  206.  
  207. #ifdef PHONES
  208. /* search the phone file for name */
  209. getphone(name, buffer)
  210. char *name, *buffer;
  211. {
  212.     closetx(TRUE);
  213.  
  214.     if((fin=fopen(PHONES,"r"))==NULL) {
  215.         printf("Cannot open %s\n", PHONES);
  216.         return ERROR;
  217.     } else {
  218.         while(fgets(buffer, 100, fin))
  219.             if(cmdeq(buffer, name)) {
  220.                 fclose(fin);
  221.                 return OK;
  222.             }
  223.     }
  224.     printf("Can't find data for %s\n", name);
  225.     fclose(fin);
  226.     return ERROR;
  227. }
  228. #endif
  229.  
  230. /* channge default disk and optionally, user number */
  231. chdir(p)
  232. char *p;
  233. {
  234.     unsigned newuser;
  235.  
  236.     if(Rfile||Tfile) {
  237.         printf("Must close files first");
  238.         return ERROR;
  239.     }
  240.     newuser=user; *p=toupper(*p);
  241.     if(index(*p, DISKS)) {
  242.         defdisk= *p - 'A';
  243.         bdos(SELDSK, defdisk);
  244. #ifdef CDOS
  245.         return OK;
  246. #else
  247.         printdfr();
  248.         if(!isdigit(p[1]))
  249.             return;
  250.         if((newuser=atoi(p+1)) <= MAXUSER) {
  251.             bdos(SETGETUSER, newuser);
  252.             user=newuser;
  253.             return OK;
  254.         }
  255. #endif
  256.     }
  257.     printf("Disk %c and/or User %d Illegal\n", *p, newuser);
  258.     return ERROR;
  259. }
  260.  
  261. /* fetch default disk and user number */
  262. initdd()
  263. {
  264.     defdisk= bdos(GETDEFDISK,0);
  265. #ifdef CDOS
  266.     Secpblk=SECPBLK;
  267.     user=0;
  268. #else
  269.     user=bdos(SETGETUSER, 0377);
  270.     printdfr();
  271. #endif
  272.     Phone[0] = 0;            /* initialize Phone to blank line */
  273. #ifdef XMODEM
  274.     bdos(SETGETUSER, LOGUSER);    /* read user's name to Phone */
  275.     if((fin=fopen(LASTCALR,"r"))!=NULL) {
  276.         fgets(Phone, 100, fin);
  277.         fclose(fin);
  278.     }
  279.     bdos(SETGETUSER, user);
  280. #endif
  281. }
  282.  
  283. /*
  284.  * Z19 gets to use it's 25th line. pstat starts at 48th char
  285.  * note that a call to lpstat will erase what pstat displays
  286.  */
  287. /*VARARGS*/
  288. pstat(a,b,c)
  289. char *a, *b, *c;
  290. {
  291.     char pbuf[40];
  292. #ifdef Z19
  293.     lputs("\033x1\033j\033Y8P");
  294. #endif
  295.     sprintf(pbuf, a,b,c);
  296.     lputs(pbuf);
  297. #ifdef Z19
  298.     lputs("\033K\033k");
  299. #else
  300.     lprintf("\n");
  301. #endif
  302. }
  303.  
  304. /*
  305.  * Z19 gets to use it's 25th line. lpstat starts at col 1
  306.  * Rest of line is erased
  307.  */
  308. /*VARARGS*/
  309. lpstat(a,b,c,d,e,f,g)
  310. char *a, *b, *c, *d, *e, *f, *g;
  311. {
  312. #ifdef Z19
  313.     lputs("\033x1\033j\033Y8 ");
  314. #endif
  315.     lprintf(a,b,c,d,e,f,g);
  316. #ifdef Z19
  317.     lputs("\033K\033k");
  318. #else
  319.     lprintf("\n");
  320. #endif
  321. }
  322.  
  323. dolist(argc, argp)
  324. char **argp;
  325. {
  326.     int listfile();
  327. #ifdef XMODEM
  328.     printf("^S pauses, ^K skips to next file, ^X terminates\n");
  329. #endif
  330.     expand(listfile, argc, argp);
  331. }
  332.  
  333. dodir(argc, argp)
  334. char **argp;
  335. {
  336.     int pdirent();
  337.     cfast=0;        /* counter for 4 across format */
  338.     expand(pdirent, argc, argp);
  339. #ifndef CDOS
  340.     printdfr();
  341. #endif
  342. }
  343. pdirent(name)
  344. {
  345.     printf("%-14s%c", name, (++cfast&03)?' ':'\n');
  346. }
  347. #ifndef CDOS
  348. /* docomp does a directory listing showing sectors for each matched file
  349.  * and computes total transmission time of matched files in batch mode
  350.  * time is sum of:
  351.  *     number of files * open/close time (assumed 5 seconds)
  352.  *    time to xmit and ACK each sector assuming no path delay or error
  353.  *    disk i/o time at each end, not dependent on baud rate
  354.  */
  355. docomp(argc,argp)
  356. char **argp;
  357. {
  358.     unsigned compsecs();
  359.     unsigned spm;    /* sectors per minute-baud */
  360.     unsigned dminutes;    /* tenths of minutes */
  361.     cfast=Numsecs=Numblks=0;
  362.     expand(compsecs, argc, argp);
  363.     /* (Baudrate*60)/(10 bits each char * 136 chars) */
  364.     spm= Baudrate/23;
  365.     dminutes= Numfiles+((10*(Numfiles+Numsecs))/spm)+(Numsecs/20);
  366.     printf("\n%u Files %u Blocks %u K\n",
  367.       Numfiles, Numblks, (Numblks*(Secpblk>>3)));
  368.     printf("%u Sectors %u.%u Minutes Xmsn Time at %u Baud\n",
  369.       Numsecs, dminutes/10, dminutes%10, Baudrate);
  370.  
  371. }
  372. /* add file length (in CP/M 128 byte records) to Numsecs */
  373. unsigned compsecs(ufn)
  374. char *ufn;
  375. {
  376.     struct fcb fstat;
  377.     char *fcbp;
  378.     printf("%-14s", ufn);
  379.     unspace(ufn);
  380.     setfcb( &fstat, ufn);
  381.     bdos(COMPFILSIZ, &fstat);
  382.     Numsecs += fstat.recn;
  383.     Numblks += (fstat.recn+Secpblk-1)/Secpblk;
  384.     if(CIREADY)
  385.         return ERROR;
  386.     printf("%4u%c",fstat.recn, (++cfast&03)?' ':'\n');
  387.     return fstat.recn;
  388. }
  389. #endif
  390.  
  391. expand(fnx, argc, argp)
  392. int (*fnx)();
  393. char **argp;
  394. {
  395.     char name[PATHLEN], *s;
  396.     Numfiles=0;
  397.  
  398.     if(argc<=0)
  399.         return e1xpand(fnx, "????????.???");
  400.     else
  401.         while(--argc>=0) {
  402.             /* change b: to b:*.*     */
  403.             strcpy(name, *argp++);
  404.             if((s=index(':', name)) && *++s == 0)
  405.                 strcpy(s, "????????.???");
  406.             if(e1xpand(fnx, name)==ERROR)
  407.                 return ERROR;
  408.         }
  409.     return OK;
  410. }
  411.  
  412. /*
  413.  * e1xpand expands ambiguous pathname afnp
  414.  * calling fnx for each.
  415.  * Modified from: Parameter list builder by Richard Greenlaw
  416.  *                251 Colony Ct. Gahanna, Ohio 43230
  417.  */
  418. e1xpand(fnx, afnp)
  419. int (*fnx)();
  420. char *afnp;    /* possible ambiguous file name*/
  421. {
  422.     struct fcb sfcb, *pfcb;
  423.     int bdoscmd;
  424.     char *p, *q;
  425.     int i, byteaddr;
  426.     int filecount, m;
  427.     char tbuf[SECSIZ];
  428.     struct {
  429.         char xYxx[UFNSIZE];        /* unambiguous file name */
  430.     } *fp;
  431.     int strcmp();
  432.     char *fcbp;
  433.  
  434.     /* build CPM fcb   */
  435.     unspace(afnp);
  436.     if(setfcb(&sfcb,afnp) == NULL) {
  437.         printf("%s is bad pattern\n", afnp);
  438.         return ERROR;
  439.     }
  440.     snarfbuf();    /* get some buffer */
  441.     /* Search disk directory for all ufns which match afn*/
  442.     for(fp=bufmark,filecount=0,bdoscmd=SRCH;; fp++,filecount++) {
  443. tryanother:
  444.         bdos(SETDMA, tbuf);
  445.         /* seems CP/M outta know whether to use SRCH or SRCHNXT !! */
  446.         byteaddr=bdos(bdoscmd, &sfcb); bdoscmd=SRCHNXT;
  447.         if(byteaddr==255)
  448.             break;
  449.         /* calculate pointer to filename fcb returned by bdos */
  450.         pfcb = (tbuf + 32 * (byteaddr % 4));
  451. /*
  452.  *#ifdef RESTRICTED
  453.  */
  454.     /* check for $SYS or tag bit on 2nd byte of filename (TAG2) */
  455. /*        if((pfcb->fname[1]&0200) ||(pfcb->ftype[1]&0200))
  456.  *            goto tryanother;
  457.  *#endif
  458.  */
  459.         Numfiles++;
  460.         p = fp;
  461.         if(fp>bufend) {    /* Note: assumes some slop after bufend! */
  462.             printf("Out of Memory\n");
  463.             return ERROR;
  464.         }
  465.         if(*(afnp+1) == ':') {
  466.             /* Drive spec.*/
  467.             *p++ = *afnp;
  468.             *p++ = ':';
  469.         }
  470.  
  471.         /*Copy filename from directory*/
  472.         q = pfcb;
  473.         for(i =8; i; --i)
  474.             *p++ = (0177& *++q);
  475.         *p++ = '.' ;
  476.  
  477.         /*Copy file extent*/
  478.         for(i = 3; i; --i)
  479.             *p++ = (0177& *++q);
  480.         *p = '\0' ;
  481.  
  482.     }
  483.     if(filecount==0) {
  484.         printf("'%s' NOT FOUND\n", afnp);
  485.         return ERROR;
  486.     }
  487.  
  488.     qsort(bufmark, filecount, UFNSIZE, strcmp);
  489.  
  490.     for(fp=bufmark; --filecount>=0;) {
  491.         p=fp++;
  492.         /* execute desired function with real pathname */
  493.         if((*fnx)(p)==ERROR)
  494.             return ERROR;
  495.     }
  496.     return OK;
  497. }
  498.  
  499. /*
  500.  * snarfbuf "guarantees" that bufmark points to at least SNARFBUNCH bytes
  501.  * of "unused" space in the big circular buffer
  502.  */
  503. snarfbuf()
  504. {
  505.     if(Wrapped || (bufend-bufcq)<SNARFBUNCH) {
  506.         dumprxbuff();
  507.         clearbuff();    /* so the printer won't try to list dir's */
  508.         bufmark=bufst;
  509.     } else
  510.         bufmark=bufcq;
  511. }
  512.  
  513. /*
  514.  * cisubstr(string, token) searches for lower case token in string s
  515.  * returns pointer to token within string if found, NULL otherwise
  516.  * ignore parity in strings s
  517.  */
  518. char *cisubstr(s, t)
  519. char *s,*t;
  520. {
  521.     char *ss,*tt;
  522.     /* search for first char of token */
  523.     for(ss=s; *s; s++)
  524.         if(tolower(*s & 0177)==*t)
  525.             /* compare token with substring */
  526.             for(ss=s,tt=t; ;) {
  527.                 if(*tt==0)
  528.                     return s;
  529.                 if(tolower(*ss++ & 0177) != *tt++)
  530.                     break;
  531.             }
  532.     return NULL;
  533. }
  534. #ifdef XMODEM
  535.  
  536. /*
  537.  * lprintf is like regular printf but uses direct output to console
  538.  * This prevents status printouts from disrupting file transfers, etc.
  539.  */
  540.  
  541. lprintf(a,b,c,d,e,f)
  542. char *a, *b, *c, *d, *e, *f;
  543. {
  544.     char lbuf[CMDLEN], *s;
  545.     /* format data into lbuf */
  546.     sprintf(lbuf, a,b,c,d,e,f);
  547.     /* now send lbuf to console directly */
  548.     for(s=lbuf; *s; ) {
  549.         if(*s=='\n') {
  550.             while(!COREADY)        /* expand \n to \r\n */
  551.                 ;
  552.             TTYOUT('\r');
  553.         }
  554.         while(!COREADY)
  555.             ;
  556.         TTYOUT(*s++);
  557.     }
  558. }
  559. #endif
  560.  
  561. /* copy string s onto itself deleting spaces "hello there" > "hellothere" */
  562. unspace(s)
  563. char *s;
  564. {
  565.     char *p;
  566.     for(p=s; *s; s++)
  567.         if(*s != ' ')
  568.             *p++ = *s;
  569.     *p++ =0;
  570. }
  571.  
  572. #ifdef LOGFILE
  573. /*
  574.  * logfile keeps a record of files transmitted.
  575.  */
  576. logfile(log, name, mode)
  577. char *log, *name;
  578. unsigned char mode;
  579. {
  580.     int thedisk;
  581.     char *i;
  582.  
  583.     /* find out what disk was used */
  584.     thedisk=defdisk + 'a';
  585.     if(i=index(':', name)) {
  586.         thedisk = *name;
  587.         name= ++i;
  588.     }
  589.     if(i=index('\t', Phone))    /* keep just the system name */
  590.         *i = 0;
  591. #ifdef XMODEM
  592.     if(i=index('\r', Phone))    /* keep just user's name */
  593.         *i = 0;
  594.     if(i=index('\n', Phone))    /* keep just user's name */
  595.         *i = 0;
  596. #endif
  597.  
  598.     bdos(SETGETUSER, LOGUSER);    /* get it from user 0 */
  599.     if(fin=fopen(log,"a")!=NULL) {
  600.         fprintf(fin, "%c %5u    %c%02d:%-14s %s\n",
  601.          mode, Baudrate, thedisk, user, name, Phone);
  602.         putc(CPMEOF, fin); fflush(fin); fclose(fin);
  603.     }
  604.     bdos(SETGETUSER, user);
  605. }
  606. #endif
  607.  
  608. #ifdef BIGYAM
  609. crcfile(name)
  610. char *name;
  611. {
  612.     unspace(name);
  613.     oldcrc = 0; wcj = 0;
  614.     if ((Utility.ufbuf=fopen(name,BREAD))==NULL)
  615.         return ERROR;
  616.     while ((firstch=getc(Utility.ufbuf))!=EOF) {
  617.         ++wcj;
  618.         oldcrc = updcrc(firstch, oldcrc);
  619.     }
  620.     oldcrc=updcrc(0,updcrc(0,oldcrc));
  621.     fclose(Utility.ufbuf);
  622.     if(CIREADY)
  623.         return ERROR;
  624.     printf("%04x %7u %s\n", oldcrc, wcj, name);
  625.     return OK;
  626. }
  627.  
  628. docrc(argc, argp)
  629. char **argp;
  630. {
  631.     expand(crcfile, argc, argp);
  632. }
  633.  
  634. docrck(argc, argp)
  635. char **argp;
  636. {
  637.     int crckfile();
  638.  
  639.     expand(crckfile, argc, argp);
  640. }
  641.  
  642. /* Accumulate and print a "crck" for a file */
  643. crckfile(name)
  644. char *name;
  645. {
  646.     unsigned crck();
  647.     char crbuf[SECSIZ]; int fd, st, nsec;
  648.  
  649.     unspace(name);
  650.     if((fd=open(name,BREAD))==ERROR)
  651.         return ERROR;
  652.  
  653.     nsec=oldcrc=0;
  654.     while((st=read(fd, crbuf, 128)) ==128) {
  655.             ++nsec;
  656.             oldcrc=crck(crbuf, SECSIZ, oldcrc);
  657.     }
  658.     close(fd);
  659.     if(CIREADY)
  660.         return ERROR;
  661.     if(st != 0)
  662.         printf("READ ERROR");
  663.     else
  664.         printf("%04x %4d ", oldcrc, nsec);
  665.     printf(" %s\n", name);
  666.     return OK;
  667. }
  668. #endif
  669.  
  670. /* print number of free blocks on default disk */
  671. printdfr()
  672. {
  673.     unsigned dseg, dpbbx, dpbes;
  674.     struct dpb dpbloc;
  675.     struct dpb *dp;
  676.  
  677.     struct regval {    int ax, bx, cx, dx, si, di, ds, es;};
  678.  
  679.     struct regval srv,rrv;
  680.  
  681.     srv.cx = GETDPBP;
  682.     sysint(224,&srv,&rrv);
  683.     dpbbx = rrv.bx;
  684.     dpbes = rrv.es;
  685.     segread(&rrv);
  686.     dseg = rrv.cx;
  687.     dp = &dpbloc;
  688.     movblock(dpbbx,dpbes,dp,dseg,15); /* move a copy of dpb local */
  689.     Secpblk= 1 << dp->dpb_bsh;
  690.     printf("%u kb Free on %c  ", getfree(defdisk), defdisk+'A');
  691. }
  692.  
  693. /* return total free kilobytes of disk */
  694. unsigned getfree(disk)
  695. int disk;
  696. {
  697.     struct dpb dpbloc;    /* local structure */
  698.     struct dpb *dp;
  699.     unsigned char v, *s;
  700.     int c;
  701.     unsigned char vec[512];
  702.     unsigned total, count, dseg, dpbbx, dpbes, alvbx, alves;
  703.     
  704.     struct regval {    int ax, bx, cx, dx, si, di, ds, es;};
  705.  
  706.     struct regval srv,rrv;
  707.  
  708.     bdos(SELDSK, disk);
  709.     srv.cx = GETVRSN;
  710.     sysint(224,&srv,&rrv);
  711.     if(((rrv.bx)&0x00FF) >= 0x30) {        /* if version >= 3.0 */
  712.         return(getfre3(disk) >> 3);
  713.     } else                    /* if not */
  714.         {
  715.         srv.cx = GETDPBP;
  716.         sysint(224,&srv,&rrv);
  717.         dpbbx = rrv.bx;
  718.         dpbes = rrv.es;
  719.         segread(&rrv);
  720.         dseg = rrv.cx;
  721.         dp = &dpbloc;
  722.         movblock(dpbbx,dpbes,dp,dseg,15); /* move a copy of dpb local */
  723.         srv.cx = GETALLOCP;
  724.         sysint(224,&srv,&rrv);
  725.         alvbx = rrv.bx;
  726.         alves = rrv.es;
  727.         movblock(alvbx,alves,vec,dseg,512); /* make local copy of allocation vec */
  728.         total=0;
  729.         s = vec;
  730.         count=dp->dpb_dsm+1;
  731.         for(;;) {
  732.             v= *s++;
  733.             for(c=0200; c; c>>=1) {
  734.                 if((v & c)==0)
  735.                     ++total;
  736.                 if(--count ==0) {
  737.                     bdos(SELDSK, defdisk);
  738.                     return(total << ((dp->dpb_bsh)-3));
  739.                 }
  740.             }
  741.         }
  742.     }
  743. }
  744.  
  745.  
  746. /*  Get free sectors left on disk
  747.  *  Uses 3.0 BDOS #46 call
  748.  */
  749.  
  750. long getfre3(disk)
  751. {
  752.     long lspace = 0;
  753.  
  754.     bdos(SETDMA,0x0080);        /* c86 always resets dma address
  755.                        b4 read/write, so ok to set here */
  756.     movmem(&lspace,0x0080,4);    /* zero out dma area */
  757.     bdos(GETSPACE,disk);        /* get free sectors on disk */
  758.     movmem(0x0080,&lspace,4);    /* move answer from dma area */
  759.     return(lspace);
  760. }
  761.  
  762. doerase(argc, argp)
  763. char **argp;
  764. {
  765.     int erasefile();
  766.     expand(erasefile, argc, argp);
  767. #ifndef CDOS
  768.     printdfr();
  769. #endif
  770. }
  771.  
  772. erasefile(ufn)
  773. char *ufn;
  774. {
  775.     unspace(ufn);
  776.     printf("Erase %s (y/n/q)? ",ufn);
  777.  
  778.     switch(getopt()) {
  779.     case 'y':
  780.         unlink(ufn);
  781.     case 'n':
  782.         putchar('\n');
  783.         return FALSE;
  784.     }
  785.     return ERROR;
  786. }
  787.  
  788. #ifdef BIGYAM
  789.  
  790. /*
  791.  * Sum bytes in file mod 2^16 discard CR and CPMEOF+junk
  792.  */
  793. sumfile(name)
  794. char *name;
  795. {
  796.     unsigned nbytes;
  797.  
  798.     oldcrc = 0; nbytes = 0;
  799.     unspace(name);
  800.     if ((Utility.ufbuf=fopen(name,BREAD))==NULL) {
  801.         fprintf(stderr, "Can't open %s\n", name);
  802.         return ERROR;
  803.     }
  804.     for (; (cfast=getc(Utility.ufbuf))!=EOF && cfast!=032; ) {
  805.         if (cfast=='\r')
  806.             continue;
  807.         ++nbytes;
  808.         if (oldcrc&01)
  809.             oldcrc = (oldcrc>>1) + 0x8000;
  810.         else
  811.             oldcrc >>= 1;
  812.         oldcrc += cfast;
  813.     }
  814.     fclose(Utility.ufbuf);
  815.     if(CIREADY)
  816.         return ERROR;
  817.     printf("%5u%7u %s\n", oldcrc, nbytes, name);
  818.     return OK;
  819. }
  820. dosum(argc, argp)
  821. char **argp;
  822. {
  823.     int sumfile();
  824.     expand(sumfile, argc, argp);
  825. }
  826.  
  827.  
  828. /*
  829.  * count lines words bytes and carriage returns in file
  830.  */
  831. wcfile(name)
  832. char *name;
  833. {
  834.     unsigned lines, words, ncr;
  835.  
  836.     unspace(name);
  837.     if ((Utility.ufbuf=fopen(name,BREAD))==NULL)
  838.         return ERROR;
  839.     lines = words = firstch = ncr = 0; checksum = 0;
  840.     for (;;) {
  841.         cfast = getc(Utility.ufbuf);
  842.         if (cfast == EOF || cfast == 032)
  843.             break;
  844.         ++firstch;
  845.         if (cfast>040 && cfast<0177) {
  846.             if (!checksum) {
  847.                 ++words; ++checksum;
  848.             }
  849.             continue;
  850.         }
  851.         if (cfast=='\n')
  852.             ++lines;
  853.         else if (cfast=='\r')
  854.             ++ncr;
  855.         else if (cfast!=' ' && cfast!='\t')
  856.             continue;
  857.         checksum = 0;
  858.     }
  859.     fclose(Utility.ufbuf);
  860.     if(CIREADY)
  861.         return ERROR;
  862.     printf("%7u%7u%7u%7u %s\n", lines,words, firstch-ncr, firstch, name);
  863.     return OK;
  864. }
  865. dowc(argc, argp)
  866. char **argp;
  867. {
  868.     expand(wcfile, argc, argp);
  869. }
  870.  
  871. dodumph() {}    /* requres non BDS-C features */
  872.  
  873. #endif
  874.  
  875. /*
  876.  * Perform various operating systetm dependent initializations that should
  877.  *  be performed but once.
  878.  */
  879. onceonly()
  880. {
  881.     unsigned core;
  882.     core = coreleft()-12000;
  883.     if(core < 5000) {    /* check for enough memory */
  884.         printf("urk"); exit();                
  885.     }                            
  886.     bufst = alloc(core);
  887.     bufend = bufst + core;
  888.     T1pause=290*CLKMHZ;    /* calibration for deciseconds in readline() */
  889. }
  890.  
  891. /*
  892.  * init resets all variables to their "standard" values (whatever that
  893.  *  is ...).  Init is called at the beginning of yam and when the "init"
  894.  *  command is given.
  895.  */
  896. init()
  897. {
  898. #ifdef USERINIT
  899.     userinit();    /* allows extra user externs' to be initialized */
  900. #endif
  901.     initdd();        /* fetch default disk and user number */
  902.     Dport=DPORT; Sport=SPORT;
  903. #ifndef DEFBAUD
  904.     readbaud();
  905. #else
  906.     Baudrate=DEFBAUD;
  907. #endif
  908. #ifdef INITBAUD
  909.     setbaud(Baudrate);
  910. #endif
  911.     Mstatus=0;    
  912.     Onetrip=Exitchar=Rfile=Tfile=Pflag=FALSE;
  913.     Cis02=Twxmode=Image=Waitbunch=Exoneof=Hdx=Zeof=Squelch=FALSE;
  914.     Txgo=TRUE;
  915.     Parity= NORMAL;
  916.     Originate= TRUE;
  917.     Txeoln= EOL_NOTHING;
  918.     Tpause=1500*CLKMHZ; Throttle=22*CLKMHZ;
  919.     Waitnum=1;
  920.     GOchar= '\n';
  921.     clearbuff();
  922. }
  923.  
  924. /* pause n 1/10s of a sec */
  925.  
  926. sleep(n)
  927. int n;
  928. {
  929.     int i,j;
  930.     for(i=0; i<n; i++) for(j=0;j<(LOOPS);j++);
  931. }
  932.  
  933. #ifdef C86        
  934.  
  935. gets(buffer)
  936. char buffer[];
  937. {
  938.     register char *cp;
  939.     register int i = 0;
  940.   /* open con: as non-binary read for buffered input */
  941.      fclose(stdin);
  942.     fopen("CON:","r");
  943.     cp = buffer;
  944.     while ((i = getchar()) != EOF && i != '\n')
  945.         *cp++ = i;
  946.     *cp = 0;
  947.     if (i == EOF && cp == buffer) {
  948.         fclose(stdin);
  949.         fopen("CON:",BREAD);
  950.         return NULL;
  951.     }
  952.   /* reopen con: as binary read for character by character input */
  953.     fclose(stdin);
  954.     fopen("CON:",BREAD);
  955.     return buffer;
  956. }
  957.  
  958. #endif
  959.  
  960. /*    make a cp/m file control block
  961. */
  962.  
  963. setfcb(fcb,filename)
  964. struct fcb *fcb;
  965. unsigned char *filename;
  966. {
  967.   int u;
  968.  
  969.   setmem(fcb,36,0);
  970.   if(filename[1]==':'){
  971.     u=toupper(*filename);
  972.     if(u>='A' && u<='P')fcb->dr=u-('A'-1);    /* set drive number */
  973.     else goto error;
  974.     filename+=2;
  975.   }
  976.   setmem(fcb->fname,11,' ');            /* space fill fn and ft */
  977.   if(_setfcb(fcb->fname,8,&filename)||_setfcb(fcb->ftype,3,&filename))
  978.     goto error;
  979.   return(1);            /* all ok */
  980.  
  981. error:
  982. err01:
  983.   return 0;
  984. }
  985.  
  986. /*    a service routine for setfcb
  987. */
  988.  
  989. _setfcb(outstr,outlen,filename)
  990. unsigned char *outstr,**filename;
  991. int outlen;
  992. {
  993.   unsigned char *cp;
  994.   int u;
  995.  
  996.   for(cp=*filename;*cp;){        /* do file name */
  997.     u=toupper(*cp++)&0x7f;
  998.     if(u=='.')break;            /* that part done */
  999.     if(u<0x21)return 1;            /* some protection */
  1000.     if(u=='*'){
  1001.       while(outlen){
  1002.          *outstr++='?';
  1003.          --outlen;
  1004.       }
  1005.    }
  1006.     if(outlen){
  1007.       --outlen;
  1008.       *outstr++=u;
  1009.     }
  1010.   }
  1011.   *filename=cp;
  1012.   return 0;
  1013. }
  1014.  
  1015. /* direct bios call through bdos */
  1016.  
  1017. bios(func,arg1,arg2)
  1018. int func,arg1,arg2;
  1019. {
  1020. unsigned char params[5];
  1021.  
  1022.     params[0] = func&0xFF;        /* bios function number */
  1023.     params[1] = arg1&0x00FF;    /* register CL        */
  1024.     params[2] = arg1&0xFF00;    /* register CH        */
  1025.     params[3] = arg2&0x00FF;    /* register DL        */
  1026.     params[4] = arg2&0xFF00;    /* register DH        */
  1027.  
  1028.     return(bdos(50,params));
  1029. }
  1030.