home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / BEEHIVE / COMMS / YAM.ARC / YAM7.C < prev    next >
Text File  |  1990-09-20  |  18KB  |  833 lines

  1. /*
  2. >>:yam7.c 30-Jun-83 (diff 08-11-81)
  3.  * Logfile sprinf fixed to write correct length record
  4.  * closerx fixed so as not to pad a file abnormal due to write errors
  5.  * File open and close stuff and more ...
  6.  * This file assumes operation on a CP/M system
  7.  */
  8.  
  9. #include "yam.h"
  10.  
  11. /* dpb dph blocks from CP/M Interface Guide Sect 6.5 */
  12.  
  13. struct dpb {    /* CP/M Version 2 Disk Parameter Block */
  14.     unsigned dpb_spt;    /* sectors per track */
  15.     char dpb_bsh;        /* block shift factor */
  16.     char dpb_blm;
  17.     char dpb_exm;        /* Extent Mask */
  18.     unsigned dpb_dsm;    /* Highest block number on this disk */
  19.     unsigned dpb_drm;    /* total number of directory entries -1 */
  20.     unsigned dpb_al;    /* bit field corresponding to direc blocks */
  21.     unsigned dpb_cks;    /* size of the directory check vector */
  22.     unsigned dpb_off;    /* number of reserved tracks on this disk */
  23. };
  24.  
  25. char *call();
  26.  
  27. struct dph {    /* CP/M Version 2 Disk Parameter Header */
  28.     char **dph_xlt;        /* logical to physical xlat vector */
  29.     int dph_ooo;
  30.     char *dph_dirbuf;    /* 128 byte scratchpad for directory use */
  31.     struct dpb *dph_dpb;    /* disk param block for this type of disk */
  32.     char **dph_csv;        /* scratch area for detecting changed disks */
  33.     char *dph_alv;        /* pointer to bit vector alloc map for disk */
  34. };
  35.  
  36. struct fcb {    /* CP/M Version 2 fcb AS SEEN BY THE USER */
  37.     char    dr;        /* drive number */
  38.     char    fname[8];    /* fname[1] used by TAG2 */
  39.     char    ftype[3];    /* ftype[1] 8th bit set for $SYS */
  40.     char    ex;        /* file extent normally 0 */
  41.     char    s1;        /* reserved for bdos's benefit */
  42.     char    s2;        /* likewise, =0 on call to open,make,search */
  43.     char    rc;        /* record count for extent[ex]  0...128 */
  44.     char    dmap[16];
  45.     char    cr;        /* current record, initialized to 0 by usr */
  46.     unsigned recn;        /* highest record number */
  47.     char    recovf;        /* overflow of above */
  48. };
  49.  
  50. /* following are BIOS calls */
  51. #define CONST 2            /* bios console char ready */
  52. #define CONIN 3            /* bios cons char input */
  53. #define CONOUT 4        /* bios cons char output */
  54.  
  55. /* following are BDOS calls */
  56. #define BDOS 5            /* address used to call bdos */
  57. #define SELDSK 14        /* bdos select disk 0=default disk */
  58. #define SRCH 17         /* bdos search for file pattern*/
  59. #define SRCHNXT 18        /* search for next occurrence */
  60. #define GETDEFDISK 25        /* get current disk  (0-15) */
  61. #define SETDMA 26        /* set address for read, write, etc. */
  62. #define GETALLOCP 27        /* get address of allocation vector */
  63. #define SETATTRIB 30        /* update file attributes */
  64. #define GETDPBP 31        /* get DPB address for disk */
  65. #define SETGETUSER 32        /* set or get user number */
  66. #define COMPFILSIZ 35        /* compute file size into recn and recovf */
  67. #define UFNSIZE 15        /* a:foobar12.urk\0 is 15 chars */
  68.  
  69. openrx(name)
  70. char *name;
  71. {
  72.  
  73. #ifdef RESTRICTED
  74.     char *s;
  75.     if(s=cisubstr(name, ".com"))    /* upload .com files as .obj */
  76.         strcpy(s, ".OBJ");
  77.     if(cisubstr(name, "$$$"))
  78.         return ERROR;        /* don't allow upload of $$$.sub */
  79.     for(s=name; *s; )
  80.         if(*s++ > 'z')
  81.             return ERROR;    /* no garbage names please */
  82. #endif
  83.     unspace(name);
  84.     lprintf("'%s' ", name);        /* show the name right away */
  85.     if(!Creamfile && fopen(name, fout) != ERROR) {
  86.         fclose(fout);
  87.         printf("Exists ", name);
  88. #ifdef XMODEM
  89.         return ERROR;
  90. #else
  91.         printf("Replace it (y/n)??");
  92.         if(tolower(getchar())!= 'y')
  93.             return ERROR;
  94. #endif
  95.     }
  96.     if(fcreat(name, fout)==ERROR){
  97.         printf("Can't create %s\n", name);
  98.         return ERROR;
  99.     }
  100.     Rfile= TRUE;
  101.     strcpy(Rname, name);
  102.     Dumping= !Squelch;
  103.     lprintf("Created%s\n", Dumping? "" : " recording OFF");
  104.     return OK;
  105. }
  106.  
  107. closerx(pad)
  108. {
  109.     if(Rfile) {
  110.         if(!Quiet)
  111.             lpstat("Closing %s", Rname);
  112. #ifdef BDSC
  113.         if(pad && (fout._nleft != ERROR))
  114.         /* only if requested, and file not error aborted */
  115.             do
  116.                 putc(CPMEOF, fout);
  117.                 while(fout._nleft % SECSIZ);
  118. #endif
  119.         fflush(fout);
  120.         fclose(fout);
  121.         Rfile=FALSE;
  122. #ifdef LOGFILE
  123.         logfile(Rname, pad?'*':'R');    /* record file xmsn */
  124. #endif
  125.     }
  126. }
  127.  
  128. opentx(name)
  129. char *name;
  130. {
  131.     int printf();
  132. #ifdef XMODEM
  133.     int lprintf();
  134. #endif
  135.     struct fcb *fp, *fcbaddr();
  136.     int (*fnx)();
  137. #ifndef CDOS
  138.     unsigned spm, dminutes;
  139.     struct fcb fstat;
  140.     spm= Baudrate/23;
  141. #endif
  142. #ifdef XMODEM
  143.     fnx=Batch? lprintf : printf;
  144. #else
  145.     fnx=printf;
  146. #endif
  147.     (*fnx)("'%s' ", name);
  148.     unspace(name);
  149.  
  150.  
  151.     if(fopen(name, fin)==ERROR){
  152.         printf("Can't open %s\n", name);
  153.         return ERROR;
  154.     }
  155. #ifdef RESTRICTED
  156.     if(cisubstr(name, ".bad")
  157.      || (fp=fcbaddr(fin._fd))==ERROR
  158.      || (fp->fname[1] & 0200)    /* tag2 */
  159.      || (fp->ftype[1] & 0200)    /* $SYS */
  160.      ) {
  161.         fclose(fin); printf("\n'%s' Not for Distribution\n", name);
  162.         return ERROR;
  163.     }
  164. #endif
  165.     Tfile= TRUE;
  166.     strcpy(Tname, name);
  167. #ifndef CDOS
  168.     setfcb( &fstat, name);
  169.     bdos(COMPFILSIZ, &fstat);
  170.     dminutes= 1+((10*(1+fstat.recn))/spm)+(fstat.recn/20);
  171.     (*fnx)("Open %u Sectors %u.%u Minutes\n",
  172.       fstat.recn, dminutes/10, dminutes%10);
  173. #else
  174.     (*fnx)("Open\n");
  175. #endif
  176.     return OK;
  177. }
  178.  
  179. /* closetx(status) call with status != 0 if incomplete file xmsn */
  180. closetx(status)
  181. {
  182.     if(Tfile) {
  183.         fclose(fin);
  184.         if(!Quiet)
  185.             lpstat("%s closed", Tname);
  186. #ifdef LOGFILE
  187.         if(!status)
  188.             logfile(Tname, 's');        /* record file xmsn */
  189. #endif
  190.         Tfile=FALSE;
  191.     }
  192. }
  193. /* search the phone file for name */
  194. getphone(name, buffer)
  195. char *name, *buffer;
  196. {
  197.     closetx(TRUE);
  198.  
  199.     if(fopen(PHONES, fin)==ERROR) {
  200.         printf("Cannot open %s\n", PHONES);
  201.         return ERROR;
  202.     } else {
  203.         while(fgets(buffer, fin))
  204.             if(cmdeq(buffer, name)) {
  205.                 fclose(fin);
  206.                 return OK;
  207.             }
  208.     }
  209.     printf("Can't find data for %s\n", name);
  210.     fclose(fin);
  211.     return ERROR;
  212. }
  213.  
  214. /* change default disk and optionally, user number */
  215. chdir(p)
  216. char *p;
  217. {
  218.     unsigned newuser;
  219.  
  220.     if(Rfile||Tfile) {
  221.         printf("Must close files first\n");
  222.         return ERROR;
  223.     }
  224.     newuser=user; *p=toupper(*p);
  225.     if(index(*p, DISKS)) {
  226.         defdisk= *p - 'A';
  227.         bdos(SELDSK, defdisk);
  228. #ifdef CDOS
  229.         return OK;
  230. #else
  231.         printdfr();
  232.         if(!isdigit(p[1]))
  233.             return;
  234.         if((newuser=atoi(p+1)) <= MAXUSER) {
  235.             bdos(SETGETUSER, newuser);
  236.             user=newuser;
  237.             return OK;
  238.         }
  239. #endif
  240.     }
  241.     printf("Disk %c and/or User %d Illegal\n", *p, newuser);
  242.     return ERROR;
  243. }
  244.  
  245. /* fetch default disk and user number */
  246. initdd()
  247. {
  248.     Secpblk=SECPBLK;
  249.     defdisk= bdos(GETDEFDISK,0);
  250. #ifdef CDOS
  251.     user=0;
  252. #else
  253.     user=bdos(SETGETUSER, 0377);
  254. #endif
  255. }
  256.  
  257. dolist(argc, argp)
  258. char **argp;
  259.  
  260. {
  261.     int listfile();
  262. #ifdef XMODEM
  263.     printf("^S pauses, ^K skips to next file, ^X terminates\n");
  264. #endif
  265.     expand(listfile, argc, argp);
  266.     putch('\n');
  267. }
  268.  
  269. listfile(name)
  270. char *name;
  271.  
  272. {
  273.     char *p;
  274.     int c,d;
  275.  
  276. #ifdef XMODEM
  277.     printf("\nListing '%s'\n\022", name);
  278. #endif
  279.     closetx(TRUE);
  280.     if(opentx(name)==ERROR)
  281.         return ERROR;
  282. #ifdef USQ
  283.     if((c=getw(fin))==RECOGNIZE)
  284.         c=unsqueeze();
  285.     else if(c != ERROR) {
  286.         putcty(c); putcty(c>>8);    /* pdp-11 sequence */
  287. #else
  288.     else {
  289. #endif
  290.         while((c=getc(fin))!=EOF && c != CPMEOF) {
  291.             if( !(c=putcty(c)))
  292.                 continue;
  293.             if(c==003 || c==CAN || c==013) {
  294.                 break;
  295.             }
  296.         }
  297.     }
  298.     if(c != CPMEOF)
  299.         putchar('\n');
  300.     /* record complete xmsn iff terminated by (CPM)EOF */
  301.     closetx(c != CPMEOF);
  302. #ifdef XMODEM
  303.     sendline(024);    /* squelch in case user downloading */
  304. #endif        
  305.     /* cancel rest of files if ^C or ^X */
  306.     if(c==003 || c==CAN)
  307.         return ERROR;
  308.     else
  309.         return OK;
  310. }
  311.  
  312. /* fill buf with count chars padding with ^Z for CPM */
  313. filbuf(buf, count)
  314. char *buf;
  315. {
  316.     register c, m;
  317.     m=count;
  318.     while((c=getc(fin))!=EOF) {
  319.         *buf++ =c;
  320.         if(--m == 0)
  321.             break;
  322.     }
  323.     if(m==count)
  324.         return 0;
  325.     else
  326.         while(--m>=0)
  327.             *buf++ = 032;
  328.     return count;
  329. }
  330.  
  331. dodir(argc, argp)
  332. char **argp;
  333. {
  334.     int pdirent();
  335.     cfast=0;        /* counter for 4 across format */
  336.     expand(pdirent, argc, argp);
  337. #ifndef CDOS
  338.     putch('\n');
  339.     printdfr();
  340. #endif
  341. }
  342.  
  343. pdirent(name)
  344. {
  345.     printf("%-14s%c", name, (++cfast%DIRCOLS)?' ':'\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/8)));
  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.     printf("%-14s", ufn);
  378.     unspace(ufn);
  379.     setfcb( &fstat, ufn);
  380.     bdos(COMPFILSIZ, &fstat);
  381.     Numsecs += fstat.recn;
  382.     Numblks += (fstat.recn+Secpblk)/Secpblk;
  383.     printf("%4u%c",fstat.recn, (++cfast%DIRCOLS)?' ':'\n');
  384.     return fstat.recn;
  385. }
  386. #endif
  387.  
  388. expand(fnx, argc, argp)
  389. int (*fnx)();
  390. char **argp;
  391. {
  392.     char name[PATHLEN], *s;
  393.     Numfiles=0;
  394.  
  395.     if(argc<=0)
  396.         return e1xpand(fnx, "*.*");
  397.     else
  398.         while(--argc>=0) {
  399.             /* change b: to b:*.*  */
  400.             strcpy(name, *argp++);
  401.             if((s=index(':', name)) && *++s == 0)
  402.                 strcpy(s, "*.*");
  403.             if(e1xpand(fnx, name)==ERROR)
  404.                 return ERROR;
  405.         }
  406.     return OK;
  407. }
  408.  
  409. /*
  410.  * e1xpand expands ambiguous pathname afnp
  411.  * calling fnx for each.
  412.  * Modified from: Parameter list builder by Richard Greenlaw
  413.  *                251 Colony Ct. Gahanna, Ohio 43230
  414.  */
  415. e1xpand(fnx, afnp)
  416. int (*fnx)();
  417. char *afnp;    /* possible ambiguous file name*/
  418. {
  419.     struct fcb sfcb, *pfcb;
  420.     FLAG first;
  421.     char *p, *q, i, byteaddr;
  422.     int filecount, m;
  423.     char tbuf[SECSIZ];
  424.     struct {
  425.         char xYxx[UFNSIZE];        /* unambiguous file name */
  426.     } *fp;
  427.     int strcmp();
  428.  
  429.  
  430.     /* build CPM fcb   */
  431.     unspace(afnp);
  432.     if(setfcb(&sfcb, afnp) == ERROR) {
  433.         printf("%s is bad pattern\n", afnp);
  434.         return ERROR;
  435.     }
  436.  
  437.     if(Wrapped || (bufend-bufcq)<2048) {
  438.         dumprxbuff();        /* I need the space for building the pathlist */
  439.         clearbuff();        /* so the printer won't try to list dir's */
  440.         bufmark=bufst;
  441.     } else
  442.         bufmark=bufcq;
  443.  
  444.     /* Search disk directory for all ufns which match afn*/
  445.     for(fp=bufmark,filecount=0,first=TRUE;; fp++,filecount++) {
  446. tryanother:
  447.         bdos(SETDMA, tbuf);
  448.         /* seems CP/M outta know whether to use SRCH or SRCHNXT !! */
  449.         byteaddr=bdos(first? SRCH:SRCHNXT, &sfcb); first=FALSE;
  450.         if(byteaddr==255)
  451.             break;
  452.         /* calculate pointer to filename fcb returned by bdos */
  453.         pfcb = (tbuf + 32 * (byteaddr % 4));
  454. #ifdef RESTRICTED
  455.         /* check for $SYS or tag bit on 2nd byte of filename (TAG2) */
  456.         if((pfcb->fname[1]&0200) ||(pfcb->ftype[1]&0200))
  457.             goto tryanother;
  458. #else
  459.         /* check for $SYS with Sysfil flag */
  460.         if((pfcb->ftype[1]&0200) && !Sysfil)
  461.             goto tryanother;
  462. #endif
  463.  
  464.         Numfiles++;
  465.         p = fp;
  466.         if(fp>bufend) {    /* Note: assumes some slop after bufend! */
  467.             printf("Out of Memory for pathname expansion\n");
  468.             return ERROR;
  469.         }
  470.         if(*(afnp+1) == ':') {
  471.             /* Drive spec.*/
  472.             *p++ = *afnp;
  473.             *p++ = ':';
  474.         }
  475.  
  476.         /*Copy filename from directory*/
  477.         q = pfcb;
  478.         for(i =8; i; --i)
  479.             *p++ = (0177& *++q);
  480.         *p++ = '.' ;
  481.  
  482.         /*Copy file extent*/
  483.         for(i = 3; i; --i)
  484.             *p++ = (0177& *++q);
  485.         *p = '\0' ;
  486.  
  487.     }
  488.     if(filecount==0) {
  489.         printf("'%s' NOT FOUND\n", afnp);
  490.         return ERROR;
  491.     }
  492.  
  493.     qsort(bufmark, filecount, UFNSIZE, strcmp);
  494.  
  495.     for(fp=bufmark; --filecount>=0;) {
  496.         p=fp++;
  497.         /* execute desired function with real pathname */
  498.         if((*fnx)(p)==ERROR)
  499.             return ERROR;
  500.     }
  501.     return OK;
  502. }
  503.  
  504. /*
  505.  * cisubstr(string, token) searches for lower case token in string s
  506.  * returns pointer to token within string if found, NULL otherwise
  507.  */
  508. char *cisubstr(s, t)
  509. char *s,*t;
  510. {
  511.     char *ss,*tt;
  512.     /* search for first char of token */
  513.     for(ss=s; *s; s++)
  514.         if(tolower(*s)==*t)
  515.             /* compare token with substring */
  516.             for(ss=s,tt=t; ;) {
  517.                 if(*tt==0)
  518.                     return s;
  519.                 if(tolower(*ss++) != *tt++)
  520.                     break;
  521.             }
  522.     return NULL;
  523. }
  524.  
  525. /* copy string s onto itself deleting spaces "hello there" > "hellothere" */
  526. unspace(s)
  527. char *s;
  528. {
  529.     char *p;
  530.     for(p=s; *s; s++)
  531.         if(*s != ' ')
  532.             *p++ = *s;
  533.     *p++ =0;
  534. }
  535.  
  536. #ifdef LOGFILE
  537. /*
  538.  * logfile keeps a record of files transmitted.
  539.  * Mode is 's' for send file, 'r' for receive file, 't' for type file
  540.  * Lifted from xcmodem by J. Wierda, R. Hart, and W. Earnest
  541. */
  542.  
  543. #define RPB 4    /* log records per buffer */
  544. #define LRL 32    /* logical rec length LRL*RPB == SECSIZ */
  545.  
  546. logfile(name, mode)
  547. char *name;
  548. char mode;
  549. {
  550.     struct fcb *fcbaddr(), *fp;
  551.     int fd, rnum, bnum, thedisk;
  552.     char *i, *lrec, lbuf[SECSIZ+2];
  553.     char date_str[6], time_str[6];
  554.  
  555.     /* find out what disk was used */
  556.  
  557.     thedisk = defdisk + 'a';
  558.     if(i = index(':', name)) {
  559.         thedisk = *name;
  560.         name = ++i;
  561.     }
  562.     bdos(SETGETUSER, 0);    /* get it from user 0 */
  563.     fd = open(LOGFILE,2);
  564.     if(fd == ERROR) {    /* if file absent, create and initialize it */
  565.         fd = creat(LOGFILE);
  566.         if(fd == ERROR)
  567.             return;
  568.         else {
  569.             rnum=1;
  570.             fp = fcbaddr(fd);
  571.             fp->fname[1] |= 0200;    /* set TAG2 bit */
  572.             fp->ftype[1] |= 0200;    /* set SYS bit */
  573.             bdos(SETATTRIB, fp);    /* and update attributes */
  574.         }
  575.     }
  576.     else {
  577.         read(fd, lbuf, 1);
  578.         rnum = atoi(lbuf)+1;
  579.     }
  580.     setmem(lbuf, SECSIZ, 0);
  581.     sprintf(lbuf, "%d\r\n", rnum);
  582.     seek(fd,0,0);
  583.     write(fd, lbuf, 1);        /* update last record number */
  584.     bnum = rnum/RPB;
  585.     rnum = (rnum%RPB)*LRL;
  586.     seek(fd, bnum, 0);
  587.     if(rnum == 0)
  588.         setmem(lbuf, SECSIZ, 0);
  589.     else
  590.         read(fd, lbuf, 1);
  591.     if (time(time_str)){
  592.         sprintf(time_str,"fill");
  593.     }
  594.     if (date(date_str)){
  595.         sprintf(date_str,"");
  596.     }
  597.     sprintf(&lbuf[rnum], "\r\n%c    %c%02d    %-12s    %5s    %5s",
  598.      mode, thedisk, user, name, time_str, date_str);
  599.     seek(fd, bnum, 0);
  600.     write(fd,lbuf,1);
  601.     close(fd);
  602.     bdos(SETGETUSER, user);
  603. }
  604.  
  605. #ifdef LOGCLOCK
  606.  
  607. #include "clock.h"
  608.  
  609. /* Real time system clock functions
  610.  
  611.    Extracted from DATEDEMO.C
  612.  
  613.    By Bill Bolton,
  614.    Software Tools,
  615.    P.O. Box 80,
  616.    Newport Beach,
  617.    NSW, 2106,
  618.    AUSTRALIA
  619.  
  620.    Source Address TCY-396
  621.    Phone (+61 2) 997-1018
  622.  
  623.    Version 1.1 for Godbout Systsem Support 1 clock 19/1/82
  624.  
  625.     char    date_str[5];    /* string (character array) for date */
  626.     char    time_str[5];    /* string for time */
  627.     date(srt) will fill a string with date formatted as follows:
  628.  
  629.     "11/5" (in Eurodate format)
  630. */
  631.  
  632. date(str)
  633.  
  634. char    *str;        /* pointer to date string */
  635.  
  636. {
  637.     int    month[1];    /* month of the year, range 1 to 12 */
  638.     int    mday[1];    /* day of the current month, range 0 to 31 */
  639.  
  640.     if (get_date(month,mday)){
  641.         return(-1);
  642.     } 
  643.     sprintf(str,"%d/%d",*mday,*month);
  644.     return(0);
  645. }
  646.  
  647. /* get_date(month,mday) provides the basic data for formatting
  648.    a date string, fetched from the clock board and converted to a useable
  649.    set of values */
  650.  
  651. int get_date(month,mday)
  652.  
  653. int    *month;        /* pointer to current month */
  654. int    *mday;        /* pointer to day of the month */
  655.  
  656. {
  657.     if (inp(CDATA) == 0XFF )      /* no clock board present */
  658.         return(-1);
  659.     *month = ((read_digit(MONTH10) & 1) * 10) + read_digit(MONTH1);
  660.     *mday = ((read_digit(DAY10) & 3) * 10) + read_digit(DAY1);
  661.     outp(CLKCMD,0);
  662.     return(0);
  663. }
  664.  
  665.  
  666. int read_digit(address)
  667.  
  668. int    address;
  669.  
  670. {
  671.     int    instruct;
  672.  
  673.     instruct = address + CREAD;
  674.     outp(CLKCMD,instruct);
  675.     return (inp(CDATA));
  676. }
  677.  
  678. /* time(str,format) fills a string with the time of day in the 
  679.    following format :
  680.  
  681.         18:00
  682. */
  683.  
  684. time(str)
  685.  
  686. char    *str;        /* string to fill with time */
  687.  
  688. {
  689.     int    t[4];
  690.  
  691.     if (read_clock(t)){
  692.         return(-1);
  693.     } 
  694.     sprintf(str,"%d%d:%d%d",t[0],t[1],t[2],t[3]);
  695.     return(0);
  696. }
  697.  
  698. /* read_clock(t) fills an array with the time of day digits read from
  699.    the clock board
  700. */
  701.  
  702. int read_clock(t)
  703.  
  704. int    *t;        /* array to store clock digits */
  705.  
  706. {
  707.     int    ptr;    /* pointer into digit array */
  708.  
  709.     if (inp(CDATA) == 0XFF )    /* no clock board present */
  710.         return(-1);
  711.     t[0] = (read_digit(HOUR10) & 3);
  712.     t[1] = read_digit(HOUR1);
  713.     t[2] = (read_digit(MIN10) & 7);
  714.     t[3] = read_digit(MIN1);
  715.     outp(CLKCMD,0);
  716.     return(0);
  717. }
  718.  
  719. #else /* LOGCLOCK */
  720.  
  721. time(str)
  722. char *str;
  723.  
  724. {
  725.     return(-1);
  726. }
  727.  
  728. date(str)
  729. char *str;
  730.  
  731. {
  732.     return(-1);
  733. }
  734.  
  735. #endif /* LOGCLOCK */
  736.  
  737. #endif /* LOGFILE */
  738.  
  739.  
  740. docrck(argc, argp)
  741. char **argp;
  742. {
  743.     int crckfile();
  744.  
  745.     expand(crckfile, argc, argp);
  746. }
  747.  
  748. /* Accumulate and print a "crck" for a file */
  749. crckfile(name)
  750. char *name;
  751. {
  752.     unsigned crck();
  753.     char crbuf[SECSIZ]; int fd,st;
  754.  
  755.     printf("%14s ", name); unspace(name);
  756.     if((fd=open(name, 0))==ERROR)
  757.         return ERROR;
  758.  
  759.     oldcrc=0;
  760.     while((st=read(fd, crbuf, 1)) ==1)
  761.             oldcrc=crck(crbuf, SECSIZ, oldcrc);
  762.     close(fd);
  763.     if(st != 0)
  764.         printf("READ ERROR\n");
  765.     else
  766.         printf("CRCK= %04x\n", oldcrc);
  767.     return OK;
  768. }
  769.  
  770. /* print number of free blocks on default disk */
  771. printdfr()
  772. {
  773.     struct dpb *dp;
  774.  
  775.     dp=call(BDOS, 0, 0, GETDPBP, defdisk);
  776.     Secpblk= 1 << dp->dpb_bsh;
  777.     printf("%u kb Free on %c\n", getfree(defdisk), defdisk+'A');
  778. }
  779.  
  780. /* return total free kilobytes of disk */
  781. unsigned getfree(disk)
  782. {
  783.     struct dpb *dp;
  784.     /* unsigned */ char v, c, *s;
  785.     unsigned total, count;
  786.  
  787.     bdos(SELDSK, disk);
  788.     dp=call(BDOS, 0, 0, GETDPBP, disk);
  789.     s=call(BDOS, 0, 0, GETALLOCP, disk);
  790.     total=0;
  791.     count=dp->dpb_dsm+1;
  792.     for(;;) {
  793.         v= *s++;
  794.         for(c=0200; c; c>>=1) {
  795.             if((v & c)==0)
  796.                 ++total;
  797.             if(--count ==0) {
  798.                 bdos(SELDSK, defdisk);
  799.                 return total << dp->dpb_bsh-3;
  800.             }
  801.         }
  802.     }
  803. }
  804.  
  805. doerase(argc, argp)
  806. char **argp;
  807. {
  808.     int erasefile();
  809.     expand(erasefile, argc, argp);
  810. #ifndef CDOS
  811.     printdfr();
  812. #endif
  813. }
  814.  
  815. erasefile(ufn)
  816. char *ufn;
  817. {
  818.     register c;
  819.     unspace(ufn);
  820.     printf("Erase %s (y/n/q)? ",ufn);
  821.     c=getchar();
  822.     putchar('\n');
  823.     if(tolower(c)=='y')
  824.         unlink(ufn);
  825.     else if(tolower(c)=='n')
  826.         return FALSE;
  827.     else
  828.         return ERROR;
  829.     return FALSE;
  830. }
  831.  
  832. /* end of YAM7.C */
  833.