home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols100 / vol181 / rtfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-13  |  11.9 KB  |  560 lines

  1. /*
  2.     RT-11 Adapter Package for CP/M
  3.  
  4.     Rev. 1.0 -- July 1980
  5.  
  6.     Rev. 1.1 -- March 1981 consisting of adding a valid system date
  7.             word to all files placed on the RT-11 disk and
  8.             putting the volume ID on a disk when the directory
  9.             is initialized.  This will keep RT-11 versions
  10.             later than V02C from choking.
  11.  
  12.     copyright (c) 1980, William C. Colley, III
  13.  
  14. This group of functions implements enough of RT-11 to allow the rest of
  15. the package to work.  The functions are built and named as per the
  16. RT-11 Software Support Manual for version 2C of RT-11.
  17. */
  18.  
  19. #include "B:RT11.H"
  20.  
  21. #include "B:STDIO.H"
  22.  
  23. #include "B:PORTAB.H"
  24.  
  25. #include "B:CTYPE.H"
  26.  
  27. /*
  28. Routine to look up an RT-11 file.  The routine accepts a file name as an
  29. array of int and returns 0 if the file was not found, 1 otherwise.
  30. The length of the file can be extracted thru dir_pointer, and the
  31. starting block of the file appears in file_start.
  32. */
  33.  
  34. lookup(file_name)
  35. int *file_name;
  36. {
  37.     usrcom();
  38.     return dleet(file_name);
  39. }
  40.  
  41. /*
  42. Routine to rename an RT-11 file.  Pass the old and new names.  The routine
  43. returns 0 if the file doesn't exist, 1 otherwise.
  44. */
  45.  
  46. rename(old_file,new_file)
  47. int *old_file, *new_file;
  48. {
  49.     char i;
  50.     usrcom();
  51.     if (!dleet(old_file)) return 0;
  52.     for (i = 0; i < 3; i++) _putword(dir_pointer,i+1,new_file[i]);
  53.     *dir_pointer = 0;
  54.     *(dir_pointer + 1) = TENTAT;
  55.     clocom(new_file);
  56.     return 1;
  57. }
  58.  
  59. /*
  60. Routine to delete an RT-11 file.  Pass the routine the file name as an
  61. array of int.  If the file does not exist, the routine returns 0, else
  62. it returns 1.
  63. */
  64.  
  65. delete(file_name)
  66. int *file_name;
  67. {
  68.     usrcom();
  69.     if (!dleet(file_name)) return 0;
  70.     *dir_pointer = 0;
  71.     *(dir_pointer + 1) = EMPTY;
  72.     consol(0);
  73.     segrw(WRITE,current_segment);
  74.     return 1;
  75. }
  76.  
  77. /*
  78. Routine to build a tentative entry in the directory.  Routine requires
  79. a file name in an array of int, and the size of the file required.  The
  80. routine returns 0 if the entry is not possible, or the first block of
  81. the file if it is.  If the entry fails, the appropriate diagnostic is printed.
  82. */
  83.  
  84. enter(file_name,size)
  85. int *file_name, size;
  86. {
  87.     char *save_pntr, i;
  88.     unsigned ret_value;
  89.     usrcom();
  90.     do
  91.     {
  92. retry:        consol(0);
  93.         while (entry(EMPTY))
  94.         {
  95.             if (size <= _getword(dir_pointer,4))
  96.             {
  97.                 save_pntr = dir_pointer;
  98.                 ret_value = file_start;
  99.                 while (entry(EMPTY)) incr1();
  100.                 if (dir_pointer > &directory.entries[1000] -
  101.                     directory.extra_bytes)
  102.                 {
  103.                     ret_value = current_segment;
  104.                     if (extend())
  105.                     {
  106.                         blkchk(ret_value);
  107.                         goto retry;
  108.                     }
  109.                     puts("\nError -- directory full\n");
  110.                     return 0;
  111.                 }
  112.                 dir_pointer = save_pntr;
  113.                 _expand(dir_pointer);
  114.                 *dir_pointer = 0;
  115.                 dir_pointer+=1;
  116.                 *dir_pointer = TENTAT;
  117.                 dir_pointer+=1;
  118.                 for (i = 0; i < 3; i++)
  119.                 {
  120.                     _putword(dir_pointer,i,file_name[i]);
  121.                 }
  122.                 _putword(dir_pointer,3,size);
  123.                 _putword(dir_pointer,5,sysdate);
  124.                 incr1();
  125.                 _putword(dir_pointer,3,
  126.                     _getword(dir_pointer,3) - size);
  127.                 segrw(WRITE,current_segment);
  128.                 return ret_value;
  129.             }
  130.             incr1();
  131.         }
  132.     }
  133.     while (nxblk());
  134.     puts("\nError -- no large enough gaps\n");
  135.     return 0;
  136. }
  137.  
  138. /*
  139. Routine to extend an RT-11 directory by splitting a directory segment.
  140. The routine returns 0 if no directory segment is available, 1 otherwise.
  141. */
  142.  
  143. extend()
  144. {
  145.     struct dirseg temp_seg;
  146.     int t, newseg;
  147.     emt_375(BIOSREAD,0,2,&temp_seg);
  148.     if (temp_seg.highest_segment >= temp_seg.total_segments) return 0;
  149.     newseg = temp_seg.highest_segment;
  150.     temp_seg.highest_segment++;
  151.     emt_375(WRITE,0,2,&temp_seg);
  152.     MOVMEM(&directory,&temp_seg,1024);
  153.     blkchk(current_segment);
  154.     for (t = (1024 - 10) / (14 + directory.extra_bytes);
  155.         t > 0; t--) incr1();
  156.     *dir_pointer = 0;
  157.     *(dir_pointer + 1) = EMPTY;
  158.     temp_seg.next_segment = directory.next_segment;
  159.     directory.next_segment = newseg;
  160.     segrw(WRITE,current_segment);
  161.     temp_seg.first_block = file_start;
  162.     MOVMEM(&temp_seg,&directory,10);
  163.     MOVMEM(temp_seg.entries + (dir_pointer - directory.entries),
  164.         directory.entries, directory.entries + 1024 - dir_pointer);
  165.     segrw(WRITE,newseg);
  166.     current_segment = newseg;
  167.     blkchk(newseg);
  168.     return 1;
  169. }
  170.  
  171. /*
  172. Routine to close an RT-11 file.  The file name comes over in radix 50 in
  173. the array file_name.  The routine returns 0 if no file by that name was
  174. around to close, 1 otherwise.
  175. */
  176.  
  177. klose(file_name)
  178. int *file_name;
  179. {
  180.     char i;
  181.     blkchk(1);
  182.     do
  183.     {
  184.         while(entry(TENTAT))
  185.         {
  186.             for (i = 0; i < 3; i++)
  187.             {
  188.                 if (_getword(dir_pointer,i+1) !=
  189.                     file_name[i]) break;
  190.             }
  191.             if (i == 3)
  192.             {
  193.                 clocom(file_name);
  194.                 return 1;
  195.             }
  196.             incr1();
  197.         }
  198.     }
  199.     while (nxblk());
  200.     return 0;
  201. }
  202.     
  203. /*
  204. Routine that continues close and rename operations.
  205. */
  206.  
  207. clocom(file_name)
  208. int *file_name;
  209. {
  210.     char *tdptr;
  211.     int tseg;
  212.     tdptr = dir_pointer;
  213.     tseg = current_segment;
  214.     if (dleet(file_name))
  215.     {
  216.         *dir_pointer = 0;
  217.         *(dir_pointer + 1) = EMPTY;
  218.         if (tseg != current_segment)
  219.         {
  220.             consol(0);
  221.             segrw(WRITE,current_segment);
  222.         }
  223.     }
  224.     blkchk(tseg);
  225.     dir_pointer = tdptr;
  226.     *tdptr = 0;
  227.     tdptr+=1;
  228.     *tdptr = PERM;
  229.     consol(0);
  230.     segrw(WRITE,current_segment);
  231. }    
  232.  
  233. /*
  234. Routine to get an RT-11 file name from the console.  The name is packed
  235. into the int array file_name in radix 50.  The routine returns 0
  236. if the file name is not legal, 1 otherwise.
  237. */
  238.  
  239. getfd(file_name)
  240. int *file_name;
  241. {
  242.     char c, i, j, name[20], *pntr;
  243.     pntr = gets(name);
  244.     file_name[0] = file_name[1] = file_name[2] = 0;
  245.     for (i = 0; i < 2; i++)
  246.     {
  247.         for (j = 0; j < 3; j++)
  248.         {
  249.             c = *pntr;
  250.             if (c == '.' || c == '\0') c = ' ';
  251.             else pntr++;
  252.             if ((c = ator50(c)) == 255) return 0;
  253.             file_name[i] = file_name[i] * 050 + c;
  254.         }
  255.     }
  256.     if (*pntr == '.') pntr++;
  257.     for (i = 0; i < 3; i++)
  258.     {
  259.         c = *pntr;
  260.         if (c == '\0') c = ' ';
  261.         else pntr++;
  262.         if ((c = ator50(c)) == 255) return 0;
  263.         file_name[2] = file_name[2] * 050 + c;
  264.     }
  265.     return 1;
  266. }
  267.  
  268. /*
  269. Routine to set up an RT-11 file I/O operation.
  270. */
  271.  
  272. usrcom()
  273. {
  274.     current_segment = 0;
  275.     blkchk(1);
  276. }
  277.  
  278. /*
  279. Routine to scan the directory for a file of a specified name.  The routine
  280. is passed the file name in radix 50 as an array of int.  The routine returns
  281. 0 if the file is not found, 1 otherwise.
  282. */
  283.  
  284. dleet(file_name)
  285. int *file_name;
  286. {
  287.     char i;
  288.     blkchk(1);
  289.     do
  290.     {
  291.         while(entry(PERM))
  292.         {
  293.             for (i = 0; i < 3; i++)
  294.             {
  295.                 if (_getword(dir_pointer,i+1) !=
  296.                     file_name[i]) break;
  297.             }
  298.             if (i == 3) return 1;
  299.             incr1();
  300.         }
  301.     }
  302.     while (nxblk());
  303.     return 0;
  304. }
  305.  
  306. /*
  307. Routine to get the next directory segment into core.  The routine returns
  308. 0 if no next segment exists, 1 otherwise.
  309. */
  310.  
  311. nxblk()
  312. {
  313.     if (directory.next_segment == 0) return 0;
  314.     blkchk(directory.next_segment);
  315.     return 1;
  316. }
  317.  
  318. /*
  319. Routine to find out if the requested directory segment is in core.  If it
  320. isn't, the segment is read in.
  321. */
  322.  
  323. blkchk(segment)
  324. int segment;
  325. {
  326.     if (segment != current_segment)
  327.     {
  328.         current_segment = segment;
  329.         segrw(BIOSREAD,segment);
  330.     }
  331.     dir_pointer = directory.entries;
  332.     file_start = directory.first_block;
  333. }
  334.  
  335. /*
  336. Function to read/write a directory segment.  Parameters passed are the
  337. directory segment desired, and a read/write flag as per emt_375.
  338. */
  339.  
  340. segrw(read_write,segment)
  341. int segment;
  342. char read_write;
  343. {
  344.     emt_375(read_write,segment * 2 + 4,2,&directory);
  345. }
  346.     
  347. /*
  348. Routine to find a specified file type in a directory segment.
  349. The routine starts from the current value of dir_pointer, and
  350. returns either 0 if the type isn't found or 1 if it is.
  351. */
  352.  
  353. entry(type)
  354. char type;
  355. {
  356.     char t;
  357.     while (1)
  358.     {
  359.         if ((t = *(dir_pointer + 1)) == type) return 1;
  360.         if (t == ENDSEG) return 0;
  361.         incr1();
  362.     }
  363. }
  364.  
  365. /*
  366. Routine to increment the directory pointer to the next entry in the
  367. directory.
  368. */
  369.  
  370. incr1()
  371. {
  372.     file_start += _getword(dir_pointer,4);
  373.     dir_pointer += 14 + directory.extra_bytes;
  374. }
  375.  
  376. /*
  377. Routine to compress the stray tentatives and empties out of a directory
  378. segment.  The file name file_name gives a tentative file that is to be
  379. exempt from the compression (i. e., there is only one active channel).
  380. If no files are to be exempt, pass 0 for file_name.
  381. */
  382.  
  383. consol(file_name)
  384. int *file_name;
  385. {
  386.     char i, *next;
  387.     dir_pointer = directory.entries;
  388.     while (entry(TENTAT))
  389.     {
  390.         if (file_name != 0)
  391.         {
  392.             for (i = 0; i < 3; i++)
  393.             {
  394.                 if (_getword(dir_pointer,i+1) !=
  395.                     file_name[i]) break;
  396.             }
  397.         }
  398.         else i = 0;
  399.         if (i != 3)
  400.         {
  401.             *dir_pointer = 0;
  402.             *(dir_pointer + 1) = EMPTY;
  403.         }
  404.         incr1();
  405.     }
  406.     dir_pointer = directory.entries;
  407.     while (entry(EMPTY))
  408.     {
  409.         next = dir_pointer + 14 + directory.extra_bytes;
  410.         if (*(next + 1) == EMPTY)
  411.         {
  412.             _putword(dir_pointer,4,_getword(next,4) +
  413.                 _getword(dir_pointer,4));
  414.             _squeez(next);
  415.             continue;
  416.         }
  417.         if (_getword(dir_pointer,4) == 0)
  418.         {
  419.             if (*(dir_pointer - 13 -
  420.                 directory.extra_bytes) == PERM)
  421.             {
  422.                 _squeez(dir_pointer);
  423.                 continue;
  424.             }
  425.         }
  426.         incr1();
  427.     }
  428.     blkchk(current_segment);
  429. }
  430.  
  431. /*
  432. This routine emulates the block read/write EMT call (#375).  You pass the
  433. routine a starting block number, a block count, and an appropriate core
  434. buffer.  The routine reads or writes the blocks and returns.  A read is
  435. done if the read/write flag has value BIOSREAD, and a write is done if the
  436. read/write flag is WRITE.  Each block is 512 bytes.
  437. */
  438.  
  439. emt_375(read_write,start_block,block_count,core_buffer)
  440. int start_block, block_count;
  441. char read_write, *core_buffer;
  442. {
  443.     char i;
  444.     while (--block_count >= 0)
  445.     {
  446.         for (i = 0; i < 4; i++)
  447.         {
  448.             BIOS(SEL_DSK,1);
  449.             BDOS(SET_DMA,core_buffer);
  450.             _find(start_block,i);
  451.             BIOS(read_write,0);
  452.             BDOS(SET_DMA,DMA_ADDR);
  453.             BIOS(SEL_DSK,0);
  454.             core_buffer += 128;
  455.         }
  456.     start_block++;
  457.     }
  458. }
  459.  
  460. /*
  461. Internal function to map an RT-11 block number and sector number inside the
  462. block into a physical sector number.  The sectors within a block are numbered
  463. from 0 to 3.
  464. */
  465.  
  466. _find(block,sector)
  467. int block;
  468. char sector;
  469. {
  470.     int r, s, t;
  471.     r = (block - 6) * 2 + (sector >> 1);
  472.     sector &= 001;
  473.     t = (r + 12) / 13;
  474.     r = (r + 12) % 13;
  475.     s = t * 6 + r * 4 + (r > 6 ? 1 : 0);
  476.     if (sector) s += (r == 6 ? 3 : 2);
  477.     t++;
  478.     BIOS(SET_TRK,t);
  479.     BIOS(SET_SEC,s % 26 + 1);
  480. }
  481.  
  482. /*
  483. Internal routine to extract a word from a core buffer that is an array of
  484. char.  The array is passed, as is the word number desired.  The function
  485. returns the word.
  486.  
  487. +++++ Modified C.D. 10/2/84 for DRC under CP/M-86.
  488.  
  489. */
  490.  
  491. _getword(buffer,word_number)
  492. unsigned word_number;
  493. int *buffer;
  494. {
  495.     buffer+=word_number;
  496.     return *buffer;
  497. }
  498.  
  499. /*
  500. Internal routine to place a word into the core buffer that is an array of char.
  501. The array is passed, as is the word number desired, and the word itself.
  502.  
  503. +++++ Modified CD 10/2/84 for DRC under CP/M-86 
  504. */
  505.  
  506. _putword(buffer,word_number,word)
  507. unsigned word_number, word;
  508. int *buffer;
  509. {
  510.     buffer+=word_number;
  511.     *buffer = word;
  512. }
  513.  
  514. /*
  515. Internal routine to compress an entry out of a directory segment.
  516. The address of the entry is passed.
  517. */
  518.  
  519. _squeez(entry)
  520. char *entry;
  521. {
  522.     char *next;
  523.     next = entry + 14 + directory.extra_bytes;
  524.     MOVMEM(next,entry,&directory.entries[1014] - next);
  525. }        
  526.  
  527. /*
  528. Internal routine to splice an entry into a directory segment.
  529. The address of the desired entry is passed.
  530. */
  531.  
  532. _expand(entry)
  533. char *entry;
  534. {
  535.     char *next;
  536.     next = entry + 14 + directory.extra_bytes;
  537.     MOVMEM(entry,next,&directory.entries[1014] - next);
  538. }
  539.  
  540. /*
  541. Routine to map a character into its radix 50 representation.  The function
  542. returns the rad 50 version or 255 if no rad 50 version exists.
  543. */
  544.  
  545. ator50(ascii)
  546. char ascii;
  547. {
  548.     switch(ascii)
  549.     {
  550.         case ' ':    return 0;
  551.         case '$':    return 033;
  552.         case '.':    return 034;
  553.     }
  554.     ascii = toupper(ascii);
  555.     if ((ascii -= '0') <= 9) return ascii + 036;
  556.     if ((ascii -= ('A' - '0')) <= ('Z' - 'A')) return ascii + 1;
  557.     return 255;
  558. }
  559.  
  560.