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 / UTILITYS / PCSWP05.ARC / PCSWP05.C < prev    next >
Text File  |  1991-03-10  |  28KB  |  1,053 lines

  1. /*************************************************
  2.  
  3.  PCSWP
  4.  Eugene Nolan
  5.  2/10/89
  6.  c/o DHN* RCPM 215-623-4040
  7.  
  8.  This utility allows you access to IBM PC 320/360k floppies
  9.  if:
  10.   1 - Your systems has a means of accessing DS/DD 5.25
  11.       with 512 byte sectors and 8 or 9 physical sectors/track.
  12.       This means that your system must support 4k or 4.5k bytes
  13.       per track on your floppy. It must also alternate heads
  14.       when it overflows the current track.
  15.  
  16.  It:
  17.   1 - Allows you to spec the drive the DOS disk is on
  18.   2 - Get a directory listing of the DOS disk
  19.   3 - Copy a single file at a time to the DOS disk (no wildcards) from
  20.        a specified CPM drive/user
  21.   4 - Sweep the DOS disk
  22.       A - Foreward or backwards
  23.       B - View a file ( if file is not ASCII, sorry )
  24.       C - Delete a DOS file
  25.       D - Tag a DOS file for later mass copy
  26.       E - Untag a previously tagged file
  27.       F - Copy all tagged files to a designated CPM drive/user
  28.   5 - During file copies from/to the DOS disk, you will be asked
  29.        whether to proceed on not if the destination file exists
  30.  
  31.  Limitations:
  32.   1 -    Only  320k and 360k format supported.
  33.   2 -    File names with 05 in dos directory as first character
  34.     of name may display funny, as no conversion to the true
  35.     E5h will be made.
  36.   3 -   For file copys from/to the DOS disk, no data verification is done
  37.   4 -   No autologin of DOS disk, if you change the disk, tell the
  38.         program by re-specifying the drive the DOS disk is on
  39.   5 -   Checks are made to verify the DOS disk is a DOS disk of the supported
  40.         formats, but given the right circumstances, it is possible to trick
  41.         the program (possible but unlikely).
  42.  
  43.  
  44.  Many commercial systems have a utility that will allow you to
  45.  define this format. For those of you who wish to roll your own
  46.  DPB, the values are:
  47.  
  48. DPBF:    ;DISK PARAMETER BLOCK for IBM 360k
  49.     DW    36        ;SECTORS PER TRACK ( 32 if 320k disk)
  50.     DB    3        ;BLOCK SHIFT FACTOR
  51.     DB    7        ;BLOCK MASK
  52.     DB    0        ;EXTENT MASK
  53.     DW    359        ;DISK SIZE-1 (319 if 320k disk)
  54.     DW    63        ;DIRECTORY MAX (Not applicable)
  55.     DB    128+64        ;ALLOC 0    ditto
  56.     DB    0        ;ALLOC 1    ditto
  57.     DW    8        ;CKS        ditto
  58.     DW    0        ;TRACK OFFSET    ditto
  59.  
  60.  
  61.  General Notes:
  62.  
  63.   This program is written in Small C 2.11. In doing so it makes use
  64.   of some of Small C's internal data bases (namely _fcbptr) and it's
  65.   method of allocating storage for global variables. In doing so, it
  66.   will probably not compile correctly with ANY commercial compiler.
  67.  
  68.   Also note again, if you change the 'DOS' disk, TELL THE PROGRAM by
  69.   using the SELECT DOS DISK function from the main menu.
  70.  
  71.   And please do not get in the habit of Control-C'ing out of it,
  72.   Small C lets you do it, but there may be side effects, use the
  73.   exit from the main menu. ( Only applies if you have been able to
  74.   succesfully select a DOS disk).
  75.  
  76.   The program in it's current version is somewhat slow in it's write's
  77.   to the DOS floppy. This is because, for the time being, the BIOS
  78.   calls to 'write sector' are initiated with a 'write to directory' code,
  79.   which flushes each 128 byte CPM sector individually, regardless of
  80.   any allocation management code in the BIOS.
  81.  
  82. ***************************************************************/
  83.  
  84. #define    VER 0        /* current version of this code */
  85. #define REV 5        /* current revision level */
  86.  
  87. /* Psuedo 'c' structure for dos directory entry, DO NOT change order */
  88. char    dfilen[11],    /* dos file name from directory */
  89.     dattri,        /* dos attribute */
  90.     dresrv[10],    /* dos reserved */
  91.     dhms[2],    /* dos hour/min/sec */
  92.     dmdy[2];    /* dos month/day/year */
  93. int    ddclus,        /* dos root cluster */
  94.     dfllsb,        /* dos file length LSB */
  95.     dflmsb;        /* dos file length MSB */
  96.  
  97. char    cfilen[15],    /* cpm file name for build fcb */
  98.     cldat[1024],    /* cluster data stored here */
  99.     taghld[224],    /* Holds tags of files on DOS write functions */
  100.     cpmdsk,        /* CPM drive to copy to */
  101.     *dirent;    /* pointer to current dir entry in dir[] on DOS disk */
  102.  
  103. int    cclust,        /* current cluster being processed */
  104.     newclu,        /* next cluster to allocate on write */
  105.     clupnt,        /* address for newclu */
  106.     user,        /* CPM user to copy to */
  107.     empdsk,        /* ==112 if no usable files on dos disk */
  108.     swppnt;        /* pointer into dir[] for sweep function */
  109.  
  110. #define    SETUSR    32    /* CPM BDOS call for set user # */
  111. #define SETDRV  14    /* ditto for set default drive */
  112. #define GETDRV    25    /* ditto for get default drive */
  113.  
  114. char    *pfat0,        /* pointer to DOS fat0 */
  115.     *pfat1,        /* pointer to dos fat1 */
  116.     fat0[1024],    /* hold MS-DOS FAT 0 (if 360k) */
  117.     fat[1024],    /* Holds MS-DOS FAT 1 (if 320k,else fat0&1 if 320) */
  118.     dir[3584];    /* Holds MS-DOS Directory */
  119. char    filenam[16];    /* Filename we are copying to CPM */
  120. int    seldsk,        /* Disk MS-DOS is on, A=0,B=1 */
  121.     biodpb,        /* ==0 if BIOS said bad disk selected */
  122.     track,        /* CPM track on MS-DOS disk */
  123.     sector,        /* CPM sector on MS-DOS disk */
  124.     fsize,        /* DOS file size in K */
  125.     swpsiz,        /* size of all files tagged in K */
  126.     dirsiz,        /* total k of all files on disk */
  127.     fillsb,        /* current count of bytes to write LSB */
  128.     filmsb,        /* current count of files to write MSB */
  129.     dsmax,        /* max sector to read based upon 320/360k */
  130.     fatsiz;        /* size of fat based upon 320/360k */
  131.  
  132. int    disp;        /* ==1 if display directory */
  133.  
  134. char    *fatpnt,    /* pointer to fat[] */
  135.     *dirpnt,    /* pointer to dir[] */
  136.     *dma,        /* pointer to set dma address to */
  137.     *jnkpnt;    /* used in file size calc and FAT verification */
  138.  
  139. int    maxsec,        /* =32 for 320k, =36 for 360k */
  140.     maxclu,        /* =315 for 320k, = 355 for 360k */
  141.     cpmspt,        /* Seldsk returns the DPB's CPMSPT here */
  142.     sptcpm;        /* used for verifying DOS format matches CPM */
  143.  
  144. extern    _fcbptr[10];    /* Small C pointers to FCB's it builds */
  145.  
  146. #define    STDIN    0    /* Small C's channel number for console input */
  147.  
  148. /**************
  149.  
  150.  Start here
  151.  
  152. ***************/
  153.  
  154. main() 
  155. {
  156.  
  157.  int i,flag;
  158.  char d;
  159.  
  160. #asm
  161.     lhld    1        ; get address of warm boot in BIOS
  162.     mvi    l,1bh
  163.     shld    dtosel+1    ; store address of BIOS SELDSK jump
  164.     mvi    l,1eh
  165.     shld    ttosel+1    ; store address of BIOS SETTRK
  166.     mvi    l,21h
  167.     shld    stosel+1    ; store address of BIOS SETSEC
  168.     mvi    l,24h
  169.     shld    dmasel+1    ; store address of BIOS SETDMA
  170.     mvi    l,27h
  171.     shld    readsc+1    ; store address of BIOS READSC
  172.     mvi    l,2ah
  173.     shld    writsc+1    ; store address of BIOS WRITSC
  174. #endasm
  175.  
  176.  seldsk=255;            /* flag no disk selected yet */
  177.  printf("\n\n ****  PCSWP %d.%d  ****\n\n",VER,REV);
  178.  printf("       Gene Nolan\n\n");
  179.  flag=1;
  180.  while(flag) {
  181.  i=menu(); /* display menu and get selection */
  182.  switch (i)
  183.     {
  184.     case 1:        /* select disk for DOS files */
  185.         printf("\nEnter drive DOS disk is on (A,B,,,) : ");
  186.         d=getchar(); d=toupper(d);
  187.         if ((d>='A')&&(d<='P'))
  188.          { seldsk=d-65; rdwrdr(0);     /* convert to 0-15 and read
  189.                            FAT's and directory */
  190.            if(!biodpb) { seldsk=255;
  191.                  printf("\n\n ** BIOS rejected drive");
  192.                  force();
  193.                  }
  194.            if(!((sptcpm==32)||(sptcpm==36))) { /* BIOS DPB CPMSPT */
  195.             seldsk=255;
  196.             printf("\n\n *** Disk DPB definition not correct,");
  197.             printf(" Need SPT=32 or 36, ABORTED ***\n");
  198.             force();
  199.             }
  200.                    if(seldsk!=255) {
  201.             if(sptcpm!=maxsec) { /* check disk DPB is correct */
  202.               seldsk=255;
  203.               printf("\n\n ** DPB CPMSPT(%d) != DOS SPT(%d), aborted\n",
  204.                  sptcpm,maxsec); force(); }
  205.               else {
  206.                printf(" *** 3");
  207.                        if(maxsec==32) putchar('2'); else putchar('6');
  208.                        printf("0 K disk found ***\n");
  209.                }
  210.                      }
  211.           }
  212.           else { printf("\n\n ** A->P only!"); force(); }
  213.         break;
  214.  
  215.     case 2:    disdir(); break;        /* DOS disk directory */
  216.     case 3: dosswp(); break;        /* sweep function */
  217.     case 4: cpmdos(); break;        /* Copy CPM file to DOS disk */
  218.     case 5: flag=0; break;            /* done */
  219.     default:
  220.         }
  221.   }
  222. }
  223.  
  224. /* ********** */
  225.  
  226. menu()                /* display menu */
  227. {
  228.  printf("\n\n");
  229.  printf(" 1 = Select drive with DOS files on (A,B,C,,,)\n");
  230.  printf(" 2 = DOS disk directory\n");
  231.  printf(" 3 = Sweep DOS disk\n");
  232.  printf(" 4 = Copy to DOS\n");
  233.  printf(" 5 = Quit\n");
  234.  printf("\nChoice = ");
  235.  return((getchar()-48)&255);
  236. }        
  237.  
  238. /* ************* */
  239.  
  240. rdwrdr(rdwr) int rdwr;        /* read/write FAT's/DIR from dos disk */
  241. {
  242.  int i,defdrv,tdsk;
  243.  defdrv=_bdos(GETDRV,0);    /* get CPM BDOS default drive */
  244.  seldk();            /* select disk given by seldsk */
  245.  sptcpm=cpmspt;            /* save what seldsk returned from DPB */
  246.  if(!biodpb) return(1);        /* BIOS returned a 0, bad drive selected */
  247.  if(rdwr) { printf("\n\n Writing"); suwrdr(); /* set up for FAT/DIR write */
  248.   }
  249.   else {
  250.    printf("\n\n Reading"); if(surdwr()) return;    /* set up for FAT/DIR read */
  251.    }
  252.  printf(" DOS FAT's and directory\n");
  253.  
  254.  dma=pfat0;            /* start dma to/from memory here */
  255.  for(i=4;i<dsmax;i++)        /* read 'CPM' sectors from disk */
  256.   {
  257.   track=i/maxsec; sector=i%maxsec;/* track=int(cpmsec/X) sector=mod(cpmsec,X) */
  258.   setdma(); settrk(); setsec(); /* BIOS calls */
  259.   if(rdwr) wsectr();        /* read or write? */
  260.    else rsectr();
  261.   dma+=128;
  262.   }
  263.  
  264.  tdsk=seldsk;            /* restore CPM BDOS default drive */
  265.  seldsk=defdrv;
  266.  seldk();
  267.  seldsk=tdsk;
  268.  
  269.  if(rdwr) { dma=dir+12;        /* restore our tags if was a write */
  270.   for(i=0;i<112;i++) {
  271.    *dma=taghld[i*2]; *(dma+1)=taghld[i*2+1];
  272.    dma+=32;
  273.    }
  274.   }
  275.  
  276.  if(!rdwr) {            /* if reading, verify the 2 FAT's we just read
  277.                    match */
  278.   dma=pfat0; jnkpnt=pfat1;
  279.   for(i=0;i<fatsiz;i++) {
  280.    if(!(((*dma++)&&255)==((*jnkpnt++)&&255))) {
  281.     printf("\n\n FAT's do not match!!! Select aborted\n"); force(); seldsk=255;
  282.     i=fatsiz;
  283.     }
  284.    }
  285.   }
  286.  disp=0; disdir(); disp=1;    /* recalc file numbers */
  287.  return(0);            /* no errors */
  288. }
  289.  
  290. /* ************** */
  291.  
  292. surdwr() {            /* set up for read of directory
  293.                    read first 128 bytes of FAT0 to determine
  294.                    disk size working with */
  295.  int i;
  296.  dma=fat0;            /* start dma to memory here */
  297.  track=0; sector=4;
  298.  setdma(); settrk(); setsec(); rsectr(); /* BIOS calls */
  299.  maxsec=0; i=*dma&255;
  300.  if(i==255) {            /* 320k disk */
  301.         maxsec=32; maxclu=315; pfat0=fat; pfat1=fat+512; dsmax=40; 
  302.         fatsiz=512; }
  303.  if(i==253) {            /* 360k disk */
  304.          maxsec=36; maxclu=355; pfat0=fat0; pfat1=fat; dsmax=48;
  305.         fatsiz=1024; }
  306.  if(maxsec==0) {
  307.          printf("\n\n *** Not 320k or 360k DOS disk, aborted ***\n");
  308.               force(); seldsk=255; return(1); }
  309.  return(0);
  310. }
  311.  
  312. /* *************** */
  313.  
  314. suwrdr() {    /* set up for write directory */
  315.  int i;
  316.  dma=dir+12;
  317.   for(i=0;i<112;i++) {
  318.    taghld[i*2]=*dma; taghld[i*2+1]=*(dma+1);    /* keep old tags */
  319.    *dma=0; *(dma+1)=0; dma+=32; }        /* clear all file */
  320.                         /* numbers from reserved */
  321.                         /* bytes (used by SWP)*/
  322. #asm
  323.     lhld    fatsiz        ; get size of FAT table
  324.     push    h
  325.     pop    b
  326.     lhld    pfat1        ; get pointer to working copy
  327.     xchg
  328.     lhld    pfat0        ; get pointer to FAT0
  329. fatcpy:    ldax    d        ; copy FAT1 to FAT0
  330.     mov    m,a
  331.     inx    h
  332.     inx    d
  333.     dcx    b
  334.     mov    a,b
  335.     ora    c
  336.     jnz    fatcpy
  337. #endasm
  338. }
  339.  
  340. /* **************** */
  341.  
  342. disdir() {    /* display directory at dir[] */
  343.  int i,j,k;
  344.  char *dmap;
  345.  if(seldsk==255) { nodos(); return; }    /* no DOS disk selected, abort */
  346.  k=0; printf("\n\n");
  347.  dirsiz=0;            /* total file sizes */
  348.  for(i=0;i<112;i++) {        /* possible 112 files */
  349.   dma=dir+i*32;            /* dma=dos directory entry */
  350.   jnkpnt=dma+28;        /* point to file size area */
  351.   switch(*dma&255) {
  352.     case   0:
  353.     case  46:
  354.     case 229: *(dma+13)=255; break;    /* not used ,sub dir, or erased */
  355.  
  356.     default:  if ((*(dma+11)&24)==0) {    /* not sub dir or vol label */
  357.            *(dma+13)=k+1;        /* store file number in reserv*/
  358.            fsizek(); dirsiz=dirsiz+fsize; /* total size of tagged */
  359.            if(disp) {
  360.             for(j=0;j<8;j++) putchar(*dma++); putchar('.');
  361.               for(j=0;j<3;j++) putchar(*dma++);
  362.               printf(" %4dk ",fsize);
  363.               }
  364.            k=k+1; if(disp) {
  365.                  if(!(k%4)) putchar('\n');
  366.                  if(!(k%88)) { printf("* MORE *"); getchar();
  367.                     putchar("\n"); }
  368.                  }
  369.            }
  370.            else *(dma+13)=255;
  371.    }
  372.  }
  373.  if(disp) printf("\n\n   Total %d files, %dk\n",k,dirsiz);
  374. }
  375.  
  376. /* ************* */
  377.  
  378. seldk() {            /* use bios to select disk given by seldsk */
  379. #asm
  380.     lhld    seldsk
  381.     push    h
  382.     pop    b
  383. dtosel:    call    0        ; filled in above with bios entry
  384.     shld    biodpb        ; save DPB pointer so can check for errors */
  385.     mov    a,l
  386.     ora    h
  387.     jz    dselng
  388.     lxi    d,0ah
  389.     dad    d
  390.     mov    e,m
  391.     inx    h
  392.     mov    d,m
  393.     xchg
  394.     mov    e,m
  395.     mvi    d,0
  396.     xchg
  397.     shld    cpmspt
  398. dselng:
  399. #endasm
  400. }
  401.  
  402. /* ************ */
  403.  
  404. settrk() {            /* use bios to set disk track given by track */
  405. #asm
  406.     lhld    track
  407.     push    h
  408.     pop    b
  409. ttosel:    call    0        ; filled in above
  410. #endasm
  411. }
  412.  
  413. /* ************ */
  414.  
  415. setsec() {            /* use bios to set sector given by sector */
  416. #asm
  417.     lhld    sector
  418.     push    h
  419.     pop    b
  420. stosel:    call    0        ; filled in above
  421. #endasm
  422. }
  423.  
  424. /* ************ */
  425.  
  426. setdma() {            /* use bios to set dma address */
  427. #asm
  428.     lhld    dma
  429.     push    h
  430.     pop    b
  431. dmasel:    call    0        ; filled in above */
  432. #endasm
  433. }
  434.  
  435. /* ************ */
  436.  
  437. rsectr() {            /* use bios call to read track/sector to dma */
  438. #asm
  439. readsc:    call    0        ; filled in above */
  440. #endasm
  441. }
  442.  
  443. /* ********** */
  444.  
  445. wsectr() {            /* use BIOS call to write trk/sec to dma */
  446. #asm
  447.     mvi    c,1
  448. writsc:    call    0
  449. #endasm
  450. }
  451.  
  452. /* ****************** */
  453.  
  454. dosswp() {        /* sweep the dos directory */
  455.  int i,inc,lim,lim1;
  456.  char b;
  457.  if(seldsk==255) { nodos(); return; }        /* no DOS disk selected,abort */
  458.  swpmnu();                    /* display sweep menu */
  459.  dma=dir+12;                    /* use a reserved for tags */
  460.  for(i=0;i<112;i++) { *dma=0; dma=dma+32; }    /* clear all tags */
  461.  b=0;
  462.  swpsiz=0;                    /* current K of tagged files */
  463.  swppnt=0;                    /* directory entry being
  464.                            processed */
  465.  inc=1; lim=112; lim1=0; dma=dir;        /* move foreward in directory
  466.                            if hit file #112, wrap to
  467.                            file 0 */
  468.  
  469.  jnkpnt=dma+28;            /* point to file size in dos dir */
  470.  while(b!='X') {
  471.   dma=dir+swppnt*32;            /* point to current entry */
  472.   shofil(inc,lim,lim1);            /* show file and tag */
  473.   b=getchar();                /* get function */
  474.   b=toupper(b);
  475.   inc=1; lim=113; lim1=0;        /* default to move foreward */
  476.   jnkpnt=dma+28;            /* point to file size in dos dir */
  477.   fsizek();                /* get this files size */
  478.   switch(b) {
  479.     case 'T':             /* tag file, up size of tagged files */
  480.           if(*(dma+12)!=1) { *(dma+12)=1; swpsiz=swpsiz+fsize; }
  481.              break;
  482.  
  483.     case 'U':             /* untag, if was tagged, subtract
  484.                        size from size of tagged */
  485.           if(*(dma+12)) { swpsiz=swpsiz-fsize; }
  486.           *(dma+12)=0; break;
  487.  
  488.     case 'B': inc=-1; lim=-1; lim1=111; break; /* move backward in directory
  489.                               if hit file #=-1, wrap to
  490.                               file # 112 */
  491.  /* back up */
  492.     case 'M': mascop(); swpsiz=0; break;    /* copy tagged files to CPM */
  493.     case 'V': viewfl(); break;        /* View the file */
  494.     case 'D': printf(" ARE YOU SURE? "); b=getchar(0); b=toupper(b);
  495.           if((b&255)=='Y') {
  496.             if(*(dma+12)) swpsiz=swpsiz-fsize;
  497.             deldos();
  498.             }
  499.           break;
  500.     case '?': swpmnu(); break;        /* display menu */
  501.     }
  502.  if(b!=13) putchar('\n');    /* if not just CR, put out a CR */
  503.  
  504.  if(!((b=='?')||(b=='M')||(b=='V'))) /* if not help or mass copy, to next fil */
  505.   { swppnt=swppnt+inc; if(swppnt==lim) swppnt=lim1; }
  506.  }
  507. }
  508.  
  509. /* ************** */
  510.  
  511. swpmnu() {                        /* display sweep menu */
  512.  printf("\n\n  T  - Tag file      U - Untag file\n");
  513.  printf  ("  M  - Mass copy     B - Backwards\n");
  514.  printf  ("  V  - View file     X - Exit sweep\n");
  515.  printf  ("  ?  - This          D - Delete file\n");
  516.  printf     ("  CR or other advances\n\n");
  517. }
  518.  
  519. /* *************** */
  520.  
  521. deldos() {            /* erase the file pointed to by dma */
  522.  int d;
  523.  movdir();
  524.  cclust=ddclus;
  525.  *dma=229;
  526.  while(cclust!=-1) {
  527.   ddclus=cclust; nextcl(); d=cclust; cclust=ddclus; newclu=0;
  528.   tagclu(); cclust=d;
  529.   }
  530.   rdwrdr(1);
  531. }
  532.  
  533. /* *************** */
  534.  
  535. shofil(inc,lim,lim1) int inc,lim,lim1; { /* display next filename for/back */
  536.  int i,k;
  537.  char b,*cpnt;
  538.  i=1;
  539.  empdsk=0;                /* assume disk not empty */
  540.  while(i) {
  541.   if(((*(dma+11))&24)==0) {        /* ==10h = volume label,==8 = subdir */
  542.    b=*dma;                /* get first byte directory entry */
  543.    switch (b&255) {
  544.     case 0:        /* empty, subdir, or erased = skip file */
  545.     case 46:
  546.     case 229: swppnt=swppnt+inc; if (swppnt==lim) swppnt=lim1;
  547.          empdsk=empdsk+1; break;
  548.     default: i=0;    /* good file, display name and tag */
  549.     }
  550.    }
  551.    else { swppnt=swppnt+inc; if (swppnt==lim) swppnt=lim1; empdsk=empdsk+1; }
  552.  
  553.   dma=dir+swppnt*32;
  554.   if(empdsk==113) i=0;            /* if no files, done */
  555.  
  556.  }
  557.  if(empdsk==113)  printf(" NO FILES\n ");
  558.   else {
  559.    cpnt=dma; printf(" %2d. %c: ",(*(dma+13)&255),seldsk+65);
  560.    for(i=0;i<8;i++) putchar(*cpnt++); putchar('.');
  561.    for(i=0;i<3;i++) putchar(*cpnt++);
  562.    jnkpnt=dma+28;            /* point to file size in dos dir */
  563.    printf("  %4dk :",fsizek());
  564.    cpnt++; if(*cpnt==1) putchar('*'); else putchar(' '); /* check for tagged */
  565.    if(swpsiz)   printf(" > %dk ",swpsiz);    /* if any tagged, show size */
  566.    }
  567. }
  568.  
  569. /* ***************** */
  570.  
  571. mascop() {            /* copy all tagged files */
  572.  int i;
  573.  i=0;
  574.  if(empdsk==113) { printf(" no files! \n"); return; }
  575.  
  576.  printf(" Dest Drv(A,B,,) = ");        /* ask for destination drive */
  577.  cpmdsk=getchar(); cpmdsk=toupper(cpmdsk);
  578.  i=cpmdsk&255;
  579.  if((i<65)||(i>81)) { printf("\n\n ** drive A-P only"); force(); return; }
  580.  
  581.  if(askusr()) return;        /* get destination user */
  582.  for(i=0;i<112;i++) {        /* check tags for all files in directory */
  583.   dma=dir+i*32;
  584.   if (*(dma+12)==1) {        /* ==1= tagged */
  585.    *(dma+12)=0;            /* untag it */
  586.    cfdos();            /* copy this file to CPM */
  587.    }
  588.  }
  589. }
  590.  
  591. /* ***************** */
  592.  
  593. cfdos() {                    /* copy from dos to cpm */
  594.  int *cfd;
  595.  char b;
  596.  movdir();                    /* build psuedo structure */
  597.  cfilen[0]=cpmdsk;                 /* put in destination disk */
  598.  cfilen[1]=':';
  599.  strncpy(&cfilen[2],dfilen,8); cfilen[10]='.';    /* move filename over */
  600.  strncpy(&cfilen[11],&dfilen[8],3);
  601.  printf(" Copying to %c%d:%s",cfilen[0],user,&cfilen[2]);
  602.  fillsb=dfllsb; filmsb=dflmsb;            /* copy filesize to working */
  603.  cfd=fopen(cfilen,"r");
  604.  if(cfd) {
  605.   fclose(cfd);
  606.   printf(" exists, delete(Y/N) "); b=getchar(); b=toupper(b);
  607.   if((b&255)!='Y') { printf(" aborted\n"); return; }
  608.   }
  609.  cfd=fopen(cfilen,"w");                /* open file for writing */
  610.  if(!cfd) { printf("\n\n ** could not open, no copy"); force(); return; }
  611.  cclust=ddclus;                    /* get root cluster */
  612.  while(cclust!=-1) {                /* while not last cluster */
  613.    rdwrcl(0);                    /* read cluster */
  614. #asm
  615.     lxi    h,fillsb    ; filmsb::lsb=filmsb:lsb-400h
  616.     mvi    c,0
  617.     mov    a,m
  618.     ora    a
  619.     sbb    c
  620.     mov    m,a
  621.     inx    h
  622.     mov    a,m
  623.     sbi    4
  624.     mov    m,a
  625.     inx    h
  626.     mov    a,m
  627.     sbb    c
  628.     mov    m,a
  629.     inx    h
  630.     mov    a,m
  631.     sbb    c
  632.     mov    m,a
  633. #endasm
  634.  if(filmsb<0) {            /* less than 1024 left */
  635.   fillsb+=1024; jnkpnt=cldat+fillsb; *(jnkpnt+1)=26; /* put in EOF(1Ah) */
  636.   fwrite(cldat,1,fillsb,cfd);                 /* write to CPM */
  637.   }
  638.   else fwrite(cldat,1,1024,cfd);    /* read cluster,write to cpm */
  639.    nextcl();                    /* get next cluster number */
  640.  }
  641.  if(ferror(cfd)) { printf("\n\n ** Error writing file "); force(); }
  642.  fclose(cfd); putchar('\n');
  643. }
  644.  
  645. /* ******* */
  646.  
  647. viewfl() {                    /* view DOS file */
  648.  int i,j,vsize,lcnt;
  649.  movdir();                    /* build psuedo structure */
  650.  lcnt=1;
  651.  fillsb=dfllsb; filmsb=dflmsb;            /* copy filesize to working */
  652.  cclust=ddclus;                    /* get root cluster */
  653.  printf("\n\n *** Ctrl-C aborts\n");
  654.  while(cclust!=-1) {                /* while not last cluster */
  655.    rdwrcl(0);                    /* read cluster */
  656. #asm
  657.     lxi    h,fillsb    ; filmsb:lsb=filmsb:lsb-400h
  658.     mvi    c,0
  659.     mov    a,m
  660.     ora    a
  661.     sbb    c
  662.     mov    m,a
  663.     inx    h
  664.     mov    a,m
  665.     sbi    4
  666.     mov    m,a
  667.     inx    h
  668.     mov    a,m
  669.     sbb    c
  670.     mov    m,a
  671.     inx    h
  672.     mov    a,m
  673.     sbb    c
  674.     mov    m,a
  675. #endasm
  676.  if(filmsb<0) vsize=fillsb+1024;    /* less than 1024 */
  677.   else vsize=1024;
  678.   jnkpnt=cldat;
  679.   for(i=0;i<vsize;i++) {        /* display data from buffer */
  680.    switch(*jnkpnt&255) {
  681.      case 10: lcnt+=1;            /* LF */
  682.      default : _bdos(2,(*jnkpnt)&255);    /* display character */
  683.      }
  684.    jnkpnt++;
  685.    if(!(lcnt%23)) {            /* pause if mod(lcnt,23)=0 */
  686.      printf(" * MORE *"); while(!(j=_bdos(6,255))); lcnt=1; _bdos(2,13);
  687.      printf("         "); _bdos(2,13);
  688.      }
  689.    if(j==3) { cclust=-1; i=vsize; } /* Ctrl-C, abort */
  690.    }
  691.    if(j!=3) nextcl();        /* not aborted, get next cluster */
  692.  }
  693.  putchar('\n');
  694. }
  695.  
  696. /* ********************* */
  697.  
  698. movdir() {    /* move from mem @dma to dfilen */
  699.  dirent=dfilen;            /* point to psuedo structure */
  700. #asm
  701.     lhld    dma        ;source pointer
  702.     xchg
  703.     lhld    dirent        ;destination pointer
  704.     mvi    c,20h        ;32 bytes
  705. md1:    ldax    d        ;move em'
  706.     mov    m,a
  707.     inx    h
  708.     inx    d
  709.     dcr    c
  710.     jnz    md1
  711. #endasm
  712. }
  713.  
  714.  
  715. /* **************** */
  716.  
  717. nextcl() {    /* get next cluster from fat given current cluster */
  718.  int i;
  719.  i=cclust%2;            /* get odd/even cluster number */
  720.  cclust=(cclust*24)/16;        /* cluster*1.5=next cluster */
  721. #asm
  722.     lhld    pfat1
  723. ;    lxi    h,fat    ;get pointer to start of fat[]
  724.     xchg
  725.     lhld    cclust    ;get current cluster number
  726.     dad    d    ;index fat
  727.     xchg
  728.     ldax    d    ;get data from fat to cclust
  729.     mov    l,a
  730.     inx    d
  731.     ldax    d
  732.     mov    h,a
  733.     shld    cclust
  734. #endasm
  735.  if (i) {        /* last cluster # odd? */
  736. #asm
  737.     lhld    cclust    ;yes, take upper 12 bits from fat
  738.     mvi    e,4
  739. shclus:    ora    a
  740.     mov    a,h
  741.     rar
  742.     mov    h,a
  743.     mov    a,l
  744.     rar
  745.     mov    l,a
  746.     dcr    e
  747.     jnz    shclus
  748.     shld    cclust
  749. #endasm
  750.   }
  751.   else cclust=cclust&4095;    /* no, take lower 12 bits */
  752.  if (cclust>4087) cclust=-1;    /* if last cluster, set=-1 */
  753. }
  754.  
  755. /* ************** */
  756.  
  757. rdwrcl(rdwr) int rdwr; { /* rd/wr whole cluster given by cclust to cldat[] */
  758.  int i,cpmsec,defdrv,d;
  759.  defdrv=_bdos(GETDRV,0);
  760.  cpmsec=(((cclust-2)*2)+(dsmax/4))*4;    /* calc absolute 128 byte sector */
  761.  dma=cldat;            /* put data here */
  762.  seldk();            /* select dos disk */
  763.  for(i=0;i<8;i++) {        /* read 8 128 byte sectors=1 cluster */
  764.   /* printf(" dma=%x, cpmsec=%d\n",dma,cpmsec); */
  765.   track=cpmsec/maxsec; sector=cpmsec%maxsec;
  766.   setdma(); settrk(); setsec(); 
  767.   if(rdwr) wsectr();
  768.    else rsectr();
  769.   cpmsec+=1;
  770.   dma+=128;
  771.  }
  772.  d=seldsk;            /* restore BDOS defualt disk */
  773.  seldsk=defdrv;
  774.  seldk();
  775.  seldsk=d;
  776. }
  777.  
  778. /* ********** */
  779.  
  780. fsizek() {            /* calc file size in K */
  781. #asm
  782.     lhld    jnkpnt        ;get address of 2 word file size
  783.     inx    h
  784.     mov    e,m        ; point to second byte
  785.     inx    h
  786.     mov    d,m
  787.     inx    h
  788.     mov    l,m        ; l/d/e has high 3 bytes of file size
  789.     mvi    c,2
  790. fsizshf:
  791.     ora    a        ; shift l/d/e 2 bits right
  792.     mov    a,l
  793.     rar
  794.     mov    l,a
  795.     mov    a,d
  796.     rar
  797.     mov    d,a
  798.     mov    a,e
  799.     rar
  800.     mov    e,a
  801.     dcr    c
  802.     jnz    fsizshf
  803.     xchg            ; hl now has byte count/400h
  804.     inx    h
  805.     shld    fsize
  806. #endasm
  807. }
  808.  
  809. /* *********** */
  810.  
  811. cpmdos() {            /* copy CPM file to DOS disk */
  812.  int *cfd,i;
  813.  char b;
  814.  if(seldsk==255) { nodos(); return; }
  815.  if((fredir()==112)||(gnewcl()>maxclu)) { printf("\n\n ** No Room on DOS");
  816.                     force(); return; }
  817.  putchar('\n');
  818.  if(askusr()) return;            /* if bad dest user, abort */
  819.  printf("File name <D:>NAME.EXT = ");    /* ask for file to copy */
  820.  _gets(cfilen,15,STDIN,0);        /* read response, 0 terminated */
  821.  cfd=fopen(cfilen,"r");            /* try to open */
  822.  if(!cfd) { printf("\n\n ** Not found"); force(); return; }
  823.  dma=_fcbptr[3]+1;            /* point to SMC's FCB */
  824.  for(i=0;i<11;i++) *dma=(*dma++)&127;    /* strip high bit */
  825.  for(i=0;i<112;i++) { dma=dir+i*32;    /* see if file exists on DOS disk */
  826.   if(!(*(dma+13)==255)) {        /* look at our 'file number' field
  827.                        to see if we found valid name here */
  828.    if(!(strncmp(dma,_fcbptr[3]+1,11))) { i=112; 
  829.     printf(" exists, overwrite(Y/N) "); b=getchar(); b=toupper(b);
  830.     if((b&255)=='Y') { deldos(); fredir(); gnewcl(); }
  831.      else { fclose(cfd); printf(" aborted\n"); return; }
  832.     }
  833.    }
  834.   }
  835.  
  836.  strncpy(dfilen,_fcbptr[3]+1,11);    /* copy from Small C's internal FCB
  837.                        to psuedo structure file name */
  838.  dfllsb=dflmsb=0;            /* filesize=0 */
  839.  ddclus=cclust=newclu;            /* base cluster=current cluster=
  840.                        unused cluster */
  841.  while(newclu!=4095) {            /* ==4095= CPM EOF found */
  842.   fsize=fread(cldat,1,1024,cfd);    /* read from CPM */
  843.   sumsiz(); rdwrcl(1);            /* sum amount read */
  844.   if(fsize==1024) {            /* if 1k read */
  845.    if(gnewcl()>maxclu) {        /* get a new cluster */ 
  846.     printf(" \n\n *** DOS DISK FULL, Copied file BAD **\n\n"); force();
  847.     newclu=4095;
  848.     }
  849.     else { tagclu(); cclust=newclu; }    /* current cluster=new one */
  850.    }
  851.    else {
  852.     newclu=4095;            /* CPM EOF, tag last cluster with FFF */
  853.     tagclu();
  854.     }
  855.  }
  856.  i=ferror(cfd);
  857.  fclose(cfd);
  858.  
  859.  if(i) {
  860.   printf("\n\n ** Error reading file, Copied file BAD, disk select aborted");
  861.   force();
  862.   seldsk=255;
  863.   }
  864.   else {            /* good file copy */
  865.     dattri=32;        /* Mark archive (not changed) */
  866. #asm
  867.     lhld    dirpnt        ; copy psuedo structure to dir[] area */
  868.     lxi    d,dfilen
  869.     mvi    c,20h        ; 32 bytes
  870. ctodir:    ldax    d
  871.     mov    m,a
  872.     inx    h
  873.     inx    d
  874.     dcr    c
  875.     jnz    ctodir
  876.     lhld    dirpnt        ; Take away CPM's attribute bits
  877.     mvi    c,0bh
  878. nfattr:    mov    a,m
  879.     ani    7fh
  880.     mov    m,a
  881.     inx    h
  882.     dcr    c
  883.     jnz    nfattr
  884. #endasm
  885.    rdwrdr(1);                        /* write FATS & DIR */
  886.    }
  887. }
  888.  
  889. /* ****** */
  890.  
  891. askusr() {
  892.  printf(" User = "); scanf("%d",&user);
  893.  if((user<0)||(user>15)) { printf("\n\n ** User 0-15 only"); force() ;
  894.   return(1);
  895.   }
  896.  _bdos(SETUSR,user);
  897.  return(0);
  898. }
  899.  
  900. /* ********* */
  901.  
  902. sumsiz() {            /* sum up file size in double precision */
  903. int j;
  904. #asm
  905.     lhld    fsize        ; current amount read (0-1024)
  906.     xchg
  907.     lhld    dfllsb        ; sum with previous total
  908.     dad    d
  909.     shld    dfllsb
  910.     lda    dflmsb
  911.     aci    0
  912.     sta    dflmsb
  913. #endasm
  914. }
  915.  
  916.  
  917. /* *********** */
  918.  
  919. writcl() {
  920. printf("writ cclust= %d",cclust);
  921. }
  922.  
  923. /* ******** */
  924.  
  925. tagclu() {            /* point cclust at newclu */
  926.    jnkpnt=(cclust*24)/16;    /* offset from fat[0] =cluster # * 1.5 */
  927. #asm
  928. ;    lxi    d,fat
  929.     lhld    pfat1
  930.     xchg
  931.     lhld    jnkpnt
  932.     dad    d
  933.     lda    cclust
  934.     ani    1
  935.     jnz    clhigh
  936.     lda    newclu
  937.     mov    m,a
  938.     inx    h
  939.     mov    a,m
  940.     ani    0f0h
  941.     mov    c,a
  942.     lda    newclu+1
  943.     ora    c
  944.     mov    m,a
  945.     jmp    dsclu
  946. clhigh:
  947.     xchg
  948.     lhld    newclu
  949.     xchg
  950.     mvi    c,4
  951. shclu:    ora    a
  952.     mov    a,e
  953.     ral
  954.     mov    e,a
  955.     mov    a,d
  956.     ral
  957.     mov    d,a
  958.     dcr    c
  959.     jnz    shclu
  960.     mov    a,m
  961.     ani    0fh
  962.     ora    e
  963.     mov    m,a
  964.     inx    h
  965.     mov    m,d
  966. dsclu:
  967. #endasm
  968. }
  969. /* ****** */
  970.  
  971. fredir() {            /* find a free directory entry */
  972.  int i;
  973.  char b;
  974.  dirpnt=dir;            /* start looking at first entry */
  975.  i=0; b=1;
  976.  while((b&255)&&(i<112)) {    /* while this entry used */
  977.   b=*dirpnt;            /* get status */
  978.   switch (b&255) {
  979.    case 0:            /* not used */
  980.    case 229: b=0; break;    /* erased */
  981.    default : dirpnt=dirpnt+32; b=*dirpnt; i+=1;    /* look at next entry */
  982.    }
  983.   }
  984.  return(i);
  985. }
  986.  
  987. /* ****** */
  988.  
  989. gnewcl() {            /* get an unallocated cluster */
  990.  newclu=2; jnkpnt=1;        /* start looking at cluster 2 */
  991.  while((jnkpnt==1)&&(newclu<=maxclu)) {
  992.   clupnt=(newclu*24)/16;    /* offset from fat[0]=cluster*1.5 */
  993. #asm
  994. ;    lxi    d,fat
  995.     lhld    pfat1
  996.     xchg
  997.     lhld    clupnt
  998.     lda    newclu
  999.     dad    d
  1000.     ani    1
  1001.     jnz    newhgh
  1002.     mov    a,m
  1003.     ora    a
  1004.     jnz    notfre
  1005.     inx    h
  1006.     mov    a,m
  1007.     ora    a
  1008.     jnz    notfre
  1009.     dcx    h
  1010.     mvi    m,0ffh
  1011.     inx    h
  1012.     mov    a,m
  1013.     ani    0f0h
  1014.     ori    0fh
  1015.     mov    m,a
  1016.     jmp    isfre
  1017. newhgh:    mov    a,m
  1018.     ani    0f0h
  1019.     jnz    notfre
  1020.     inx    h
  1021.     mov    a,m
  1022.     ora    a
  1023.     jnz    notfre
  1024.     dcx    h
  1025.     mov    a,m
  1026.     ani    0fh
  1027.     ori    0f0h
  1028.     mov    m,a
  1029.     inx    h
  1030.     mvi    m,0ffh
  1031. isfre:    lxi    h,0
  1032.     shld    jnkpnt
  1033. notfre:
  1034. #endasm
  1035.   if(jnkpnt) newclu+=1;        /* last one used, check next one */
  1036.  }
  1037.  return(newclu);
  1038. }
  1039.  
  1040. /* ******** */
  1041.  
  1042. force() {        /* error occured, make operator hit a key */
  1043. int i;
  1044. printf("  *** hit any key *** \n");
  1045. i=getchar();
  1046. }
  1047.  
  1048. /* ******* */
  1049.  
  1050. nodos() {            /* say no DOS disk selected */
  1051. printf("\n\n ** NO DOS DISK SELECTED"); force();
  1052. }
  1053.