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