home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol140 / exorcopy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1984-04-29  |  10.7 KB  |  462 lines

  1. /*
  2.     **********************************************
  3.      *                         *
  4.      * EXORCOPY.C    MOTOROLA MDOS TO CP/M DATA   *
  5.      *        EXCHANGE UTILITY          *
  6.      **********************************************
  7.  
  8.     (c) Copyright Chris Undery
  9.     1st November 1982
  10.     11 Margaret St, Newtown 2042 N.S.W
  11.     SYDNEY, AUSTRALIA
  12.  
  13.  
  14. DESCRIPTION
  15. -----------
  16.  
  17.     This program provides MDOS  directory access and
  18.     file transfer functions for CP/M based systems. 
  19.     EXORCOPY assumes a 3740 MDOS diskette in drive B:
  20.  
  21.     If the program is invoked, and no parameter is passed
  22.     from the command line, then just the directory of
  23.     the MDOS diskette will be displayed.
  24.  
  25.     The second form of invokation allows, a valid MDOS
  26.     name in parameter position 1, and either the word
  27.     "TYPE" or a cpm file name. If the former invokation
  28.     is used, the contents of the named MDOS file will be
  29.     be listed on the console. If the latter form is used
  30.     then the MDOS file will be transferred to the cpm
  31.     file name specified.
  32.  
  33.     For detailed information about the MDOS file structure
  34.     refer to MOTOROLA publication ...
  35.     'M68MDOS3 EXORdisk II/III OPERATING SYSTEM USERS GUIDE'
  36.     DECEMBER 1978, MOTOROLA INC. 
  37.     CHAPTER 24
  38.  
  39. */
  40.  
  41. #include bdscio.h
  42. #define CLEAR_SCREEN 0x1a        /* screen clear character */
  43. #define LEADIN_1 0x1b            /* ESC leadin character for adm */
  44. #define LEADIN_2 '='            /* Leadin for cursor addressing */
  45. #define LEADIN_3 NULL            /* Screen clr prefix not used */
  46. #define OFFSET ' '            /* Coordinate graphic offset */
  47. #define SEL_DSK 14                  /* bdos function number */ 
  48. #define SET_DMA 26
  49. #define SET_TRK 10                  /* bios index number */
  50. #define SET_SEC 11
  51. #define READ    13
  52. #define WRITE 14
  53. #define DUMMY 0
  54. #define FLAG char
  55. #define WRITE_PROTECTED 0x8000
  56. #define DELETE_PROTECTED 0x4000
  57. #define SYSTEM_FILE 0x2000
  58. #define CONTIGUOUS 0x1000        /* non segmented allocation */
  59. #define NON_COMPRESSED 0x0800        /* no space compression used */
  60. #define MEMORY_IMAGE 2            /* loadable file */
  61. #define BINARY_RECORD 3
  62. #define ASCII_RECORD 5
  63. #define ASCII_CONVERTED 7
  64. #define VACANT 0            /* first file name char zero */
  65. #define DELETED 0xff            /* first file name char all ones */
  66.  
  67. char track;                /* current track */
  68. char sector;                /* current sector */
  69. unsigned psn;                /* MDOS physical sector number */
  70. int attributes;                /* file attributes */
  71. unsigned cluster;            /* current cluster */
  72. unsigned num_contig;            /* number of contigous clusters */
  73. char buffer[1000];            /* MDOS cluster buffer */
  74. char directory[128*21];            /* MDOS directory image */ 
  75. char volume_id[20];            /* MDOS volume name */
  76. char version_no[10];
  77. char revision_no[10];
  78. char date[10];
  79. char user_name[30];
  80. char mdos_name[20];            /* MDOS search key file name */
  81. char cpm_name[20];            /* destination cpm file name */
  82. char obuf[BUFSIZ];            /* cpm file buffer */
  83. char file_end;                /* true when at end of file */
  84. unsigned segtable[64];            /* Segment descriptor table */
  85. unsigned num_segments;            /* number of segments in file */
  86. char typeing;                /* true if to console else file */
  87. char numsecs;                /* no of logical sectors in file */
  88.  
  89.  
  90. /*
  91.  * If no arguments are passed from the command line
  92.  * exorcopy will display the directory of the mdos diskette
  93.  * in drive B:  else the passed parameter is used a search
  94.  * key to extract and copy file to specified cp/m file.
  95.  */
  96.  
  97. main(argc,argv)
  98. char **argv;
  99. {
  100.     puts("\nEXORCOPY vers A.0 (c) Chris Undery 1982\n");
  101.     if (argc == 1) show_directory();
  102.     else {
  103.        if (argc != 3) {
  104.           puts("\nUSAGE: Mdos.primary.name (AS assumed) <type, or cp/m name>");
  105.           exit();
  106.        }
  107.        strcpy(mdos_name,argv[1]);    /* move file names */
  108.        strcpy(cpm_name,argv[2]);
  109.        spaceout();            /* left justify mdos name */
  110.        if (!lookup()) {
  111.           printf("\n%s not found",mdos_name);
  112.           exit();
  113.        }
  114.        get_rib();    /* load retrieval info block for the file */
  115.        if (index(cpm_name,"TYPE") >= 0 ) {
  116.           typeing = 1;
  117.        }
  118.        else {
  119.          typeing = 0;
  120.          if (fcreat(cpm_name,obuf) == ERROR) {
  121.             puts("Cannot create %s\n",cpm_name);
  122.             exit();
  123.          }
  124.        }
  125.            file_copy(); /* now copy while steering via the segtable */
  126.     }
  127. }
  128.  
  129. /*
  130.  * Scan directory, and display list of files on the diskette
  131.  */
  132.  
  133. show_directory()
  134. {
  135.     int i,j,k;
  136.     char done, c,count;
  137.  
  138.     count = 0;
  139.     read_volume_id();        /* get volume id */    
  140.     read_directory();
  141.     printf("\nDirectory: %s Vsn %s.%s Date %s User.name %s",volume_id,version_no,revision_no,date,user_name);
  142.     i = 0;done = 0;
  143.     puts("\n\n");
  144.     while (!done) {
  145.        c = directory[i];        /* dont show empties and deleted */
  146.        if (c == ' ' || c == NULL || c == 0xff ) ;
  147.        else {
  148.           k = i;            /* transfer pointer */
  149.           j = 0;            /* clear display pointer */
  150.           while (j++ < 8) putchar(directory[k++]);
  151.           putchar('.');
  152.           while (j++ < 11) putchar(directory[k++]);
  153.           if (count++ < 4) puts(" | ");
  154.           else {
  155.         puts("\n");
  156.         count = 0;
  157.           }
  158.        }
  159.        i += 16;            /* next directory entry */
  160.        if (i == 128 * 20) done = 1; /* at end of driectory */
  161.     }
  162. }
  163.  
  164. /*
  165.  * Read the mdos identification sector and extract
  166.  * volume id generation date and all the usual system
  167.  * garbage
  168.  */
  169.  
  170. read_volume_id()
  171. {
  172.     char vbuf[130];            /* volume sector */
  173.  
  174.     rdsec(1,1,0,vbuf);        /* read it */
  175.     movmem(&vbuf[0],&volume_id,8);
  176.     volume_id[8] = NULL;
  177.     movmem(&vbuf[8],&version_no,2);
  178.     version_no[2] = NULL;
  179.     movmem(&vbuf[0xa],&revision_no,2);
  180.     revision_no[2] = NULL;
  181.     movmem(&vbuf[0xc],&date,6);
  182.     date[6] = NULL;
  183.     movmem(&vbuf[0x12],&user_name,0x14);
  184.     user_name[0x14] = NULL;
  185. }
  186.  
  187. /*
  188.  * Search for name in mdos directory. When found read the directory
  189.  * attributes , psn etc 
  190.  */
  191.  
  192. lookup()
  193. {
  194.     int i,k;
  195.     char hi,lo, found, name[20];
  196.  
  197.     i = found = 0;
  198.     read_directory();    /* get dir info */
  199.     while (!found) {
  200.        movmem(&directory[i],&name[0],10);
  201.        name[10] = NULL;
  202.        if (strcmp(name,mdos_name) == 0 ) found = 1;
  203.        else {
  204.          i += 16;
  205.          if (i >= 128 * 20) return FALSE;
  206.        }
  207.     }
  208.     lo = directory[i+0xa];    /* get physical sect of file start */
  209.     psn = lo; psn = psn << 8;
  210.     hi = directory[i+0xb];/* get lsb of sector address */
  211.     psn += hi;
  212.     attributes = directory[i+0xc];
  213.     attributes = (attributes << 8);
  214.     attributes += directory[i+0xd];
  215.     return TRUE;    
  216. }
  217.  
  218. /*
  219.  * Space out the desired file name to match the
  220.  * left justified format of the mdos directory entry
  221.  */
  222.  
  223. spaceout()
  224. {
  225.     while (strlen(mdos_name) < 8) strcat(mdos_name," ");
  226.     strcat(mdos_name,"SA");
  227. }
  228.  
  229. /*
  230.  * Load the retrieval information block into the segment table
  231.  * this allows us to read segmented files
  232.  */
  233.  
  234. get_rib()
  235. {
  236.     psn_decode(psn);    /* get track and sector address */
  237.     rdsec(sector,1,track,&segtable[0]);    /* read RIB of file */
  238. }
  239.  
  240. /*
  241.  * File copy procedure. 
  242.  * NOTE: MDOS uses reverse byte sex to 8080 style cpu's.
  243.  */
  244.  
  245. file_copy()
  246. {
  247.     
  248.     unsigned sdw;        /* segment descriptor word */
  249.     int k, sector_count, segnum;
  250.         
  251.     k = segnum = sector_count = 0;
  252.     file_end = FALSE;
  253.     while (!(byteflip(segtable[segnum]) & 0x8000)) { 
  254.        sdw = byteflip(segtable[segnum++]);
  255.        cluster = (sdw & 0x3ff);    /* extract starting cluster no */
  256.        num_contig = (sdw & 0x7c00); /* extract num contiguous */
  257.        num_contig = (num_contig >> 10); /* shift her */
  258.        num_contig++;
  259.        while (num_contig--) {    /* read all clusters in this segment */
  260.           cluster_read(cluster++,segnum);
  261.           if (file_end) goto fin;
  262.        }
  263.     }
  264. fin:    if (!typeing ) {
  265.        putc(CPMEOF,obuf);
  266.       fflush(obuf);
  267.       fclose(obuf);
  268.     }
  269. }    
  270.  
  271. /*
  272.  * Byte flip a word to make it compatible with 8080 cpu
  273.  * (INTEL bought some idiosyncracies when they bought the
  274.  *  achitectural plans for the 8008!)
  275.  */
  276.  
  277. byteflip(word)
  278. unsigned word;
  279. {
  280.     char bogor, bogee;
  281.     unsigned boig;
  282.  
  283.     boig = word;
  284.     bogor = boig & 0xff;
  285.     word = word >> 8;
  286.     bogee = word & 0xff;
  287.     boig = bogor;
  288.     boig = boig << 8;
  289.     boig += bogee;
  290.     return boig;
  291. }
  292.  
  293. /*
  294.  * Read cluster number (clust). If seg == 1 then it is assumed that
  295.  * we are at logical sector 0 , which contains the RIB, therefor
  296.  * must increment to next bogorgical sector to get to the good stuff
  297.  */
  298.  
  299. cluster_read(clust,seg)
  300. int clust,seg;
  301. {
  302.     char count;
  303.     char *address;
  304.     int bytes;
  305.     char c;
  306.  
  307.     address = &buffer;
  308.     count = 0;
  309.     psn_decode(clustran(clust));
  310.     if (seg == 1) sector++;        /* skip past RIB bbogorck */
  311.     while (count++ < 4) {        /* a cluster is 512 bytes bogorng */
  312.        if (sector == 27) {
  313.           track++;
  314.           sector = 1;
  315.        }
  316.        rdsec(sector++,1,track,address);
  317.        address += 128;
  318.     }
  319.     bytes = 0;
  320.     while (bytes < 512) {
  321.        c = buffer[bytes++];
  322.        if (c & 0x80) {    /* check for compressed spaces */
  323.           c &= 0x7f;
  324.           while (c--) if (typeing) putchar(' '); else putc(' ',obuf);
  325.        }
  326.        else {
  327.           if (c == NULL) {
  328.         file_end =TRUE;
  329.         return TRUE;
  330.           }
  331.           if (typeing) putchar(c); else putc(c,obuf);
  332.           if (c == 0x0d) 
  333.         if (typeing) putchar(0x0a); else putc(0x0a,obuf);
  334.        }
  335.     }  
  336. }
  337.  
  338. /*
  339.  * PSN decode: Called with psn return with gbogorbal variables
  340.  * track and sector set to decode values.
  341.  * valid range of psn 0..2000, (2001 & 2002 are ignored)
  342.  */
  343.  
  344. psn_decode(psn)
  345. unsigned psn;
  346. {
  347.     psn++;
  348.     track = psn / 26;
  349.     sector = psn - (track * 26);
  350. }
  351.  
  352.  
  353. /*
  354.  * Translate MDOS cluster address into PHYSICAL SECTOR NUMBER 
  355.  * where cluster is a group of 4 contiguous 128 byte sectors
  356.  * and a physical sector is sector number beginning at 0 and
  357.  * 2000.
  358.  */
  359.  
  360. clustran(cluster_number)
  361. int cluster_number;
  362. {
  363.     return (cluster_number * 4);
  364. }
  365.  
  366. /*
  367.  * Read MDOS directory into the directory buffer
  368.  * This is rather slow, as the bios access functions
  369.  * of bds c are clumsy due to excessive indirection.
  370.  */
  371.  
  372. read_directory()
  373. {
  374.     char sect, *dma_buffer;
  375.     
  376.     dma_buffer = &directory[0];
  377.     sect = 4;
  378.     while (sect <= 24) {
  379.       rdsec(sect++,1,0,dma_buffer);
  380.       dma_buffer += 128;
  381.     }
  382. }
  383.  
  384. /* 
  385.  * Sector read primitive
  386.  *
  387.  */
  388.  
  389. rdsec(secnum,drive,track,memadr)
  390. int secnum,drive,track;
  391. char *memadr;    
  392. {
  393.  
  394.     disk_action(secnum,drive,track,memadr,1,'r');
  395. }
  396.  
  397. /*
  398.  * Write sector primitive operation
  399.  *
  400.  */
  401.  
  402. wrsec(secnum,drive,track,memadr)
  403. int secnum,drive,track;
  404. char *memadr;
  405. {
  406.     disk_action(secnum,drive,track,memadr,1,'w');
  407. }
  408.  
  409. /*
  410.  * Basic disk io interface function.
  411.  * is passed operation code, track, sector, count and buffer
  412.  *
  413.  */
  414.  
  415. disk_action(secnum,drive,track,buffer,count,operation)
  416. char secnum,drive,track;
  417. unsigned buffer,count;
  418. char operation;
  419.  
  420.     { 
  421.     char bios();
  422.  
  423.      if (drive > 3 || drive < 0) {
  424.             printf("Disk drive %c does not exist\n",drive+'A');
  425.       exit();
  426.     }
  427.         bdos(SEL_DSK,drive); 
  428.         while( count-- ) { 
  429.           bdos(SET_DMA,buffer); 
  430.           bios(SET_TRK,track); 
  431.           bios(SET_SEC,secnum);
  432.       switch(operation) {
  433.         case 'r':
  434.           if (bios(READ,DUMMY)) error(READ);
  435.           break;
  436.         case 'w':
  437.           if (bios(WRITE,DUMMY)) error(WRITE);
  438.           break;
  439.         default :
  440.           error(0);
  441.           } 
  442.           buffer += 128;
  443.       if (secnum++ > 26 ) {
  444.         secnum = 1;
  445.         if (track++ > 77) return(0);
  446.           }
  447.           } 
  448.         } 
  449.  
  450. /*
  451.  * Will never get here, but its nice coding
  452.  */
  453.  
  454. error(id)
  455. char id;
  456. {
  457.     puts("\nFunction 'disk action' just screwed up!!!!");
  458.     exit();
  459. }    
  460.  
  461. /* end of EXORCOPY.C */
  462.