home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c185 / 2.ddi / OWLSRC.EXE / CSCAPE / SOURCE / BFILE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-11  |  13.3 KB  |  549 lines

  1. /*
  2.     bfile.c    
  3.  
  4.     % block file functions
  5.  
  6.     OWL 1.1
  7.     Copyright (c) 1988, by Oakland Group, Inc.
  8.     ALL RIGHTS RESERVED.
  9.  
  10.     Revision History:
  11.     -----------------
  12.     02/02/89 jdc    added bfile_Clear() and added fflush() in bfile_Read()
  13.     02/02/89 jdc    fixed bfile_Close() bug
  14.      4/16/89 jmd    replaced iarray with jarray
  15.     04/21/89 jdc    changed bfile_Gets to _bfile_gets
  16.     07/01/89 jdc    fixed free block chain
  17.     07/22/89 jdc    removed block size check for exsisting files
  18.                     added more error checking and comment field
  19.     07/27/89 jdc    renamed macros
  20.     08/02/89 jdc    put if else instead of continue for bfile_Open
  21.     08/04/89 jdc    fixed multiple bfile_GetFreeB bug
  22.     08/09/89 jdc    added block padding
  23.      8/09/89 jdc    changed oslist_GetSym to oslist_Get
  24.      8/13/89 jdc    changed format
  25.      8/21/89 jmd    changed r+b to rb
  26.      8/25/89 jdc    changed error handling
  27. */
  28.  
  29. #include "oakhead.h"
  30. #include "jadecl.h"
  31.  
  32. #include "symldecl.h"
  33. #include "bfdecl.h"
  34.  
  35. OSTATIC boolean bfile_pad(_arg1(bfile_type));
  36.  
  37. static char dirname[] = "___dirname\n";
  38.  
  39. #define BFILE_DIRNAME     dirname
  40. #define BFDIR_DATASIZE    2*sizeof(int)
  41. #define BFILE_PADCHAR    " "
  42.  
  43. #define DIR_START     5
  44. #define BF_PSIZE     5*sizeof(int)+sizeof(long)
  45. #define BF_PINTS     5*sizeof(int)
  46.  
  47. #define fopen_read(path)    fopen(path, "r+b")
  48. #define    fopen_write(path)    fopen(path, "w+b")
  49.  
  50. /* -------------------------------------------------------------------------- */
  51.  
  52. bfile_type bfile_Open(pathname, block_size, comment)
  53.     char         *pathname;
  54.     unsigned    block_size;
  55.     char        *comment;
  56. /*
  57.     Opens a bfile, existing or not, handles directory creation, etc.  
  58.  
  59.     format:
  60.         comment\n
  61.         bfile->block_size        in bytes
  62.         bfile->freeb            start of free blocks chain
  63.  
  64.         blocks of data             \n!BLOCK\n.data_size.next_block.data_chars
  65.  
  66.         the first block is always the beginning of the directory
  67.         in the form                start_block.data_type. name\n...
  68.  
  69.     Returns:
  70.  
  71.     bfile_type if ok
  72.  
  73.     NULL if it can't open, file isn't a bfile or not enough memory for 
  74.         the directory.
  75. */
  76. {
  77.     bfile_type    bfile;
  78.     char buf[100];
  79.     int    data[2], len;
  80.     FILE *fp;
  81.         
  82.     if (comment == NULL) {
  83.         comment = "BLOCKFILE\n";
  84.     }
  85.  
  86.     if ((bfile = (bfile_type)omalloc(OA_BFILE, sizeof(struct bfile_struct)
  87.         + strlen(pathname) + 1)) == NULL) {
  88.         return(NULL);
  89.     }
  90.     bfile->path = (char*)bfile + sizeof(struct bfile_struct);
  91.     strcpy(bfile->path, pathname);
  92.  
  93.     bfile->block_size = block_size;
  94.     bfile->current_name = OSLIST_BADNAME;
  95.     bfile->freeb = BFILE_NOMORE;
  96.     bfile->dir = oslist_Open(DIR_START, BFDIR_DATASIZE);
  97.     bfile->push = NULL;
  98.     bfile->pindex = -1;
  99.  
  100.     if ((fp = bfile->stream = fopen_read(pathname)) == NULL) {
  101.  
  102.         len = ((len = strlen(comment)) > COMM_LEN ) ? COMM_LEN : len;
  103.         strncpy(buf, comment, len);
  104.         memset(buf+len, ' ', COMM_LEN - len);
  105.         buf[COMM_LEN - 1] = '\n';
  106.         buf[COMM_LEN] = '\0';
  107.         
  108.         if ((fp = bfile->stream = fopen_write(pathname)) == NULL)
  109.             goto QUIT1;
  110.  
  111.         rewind(fp);
  112.         fprintf(fp, "%s% 5d% 5d\n\n!% 5d% 5d %5d\n", 
  113.             buf, bfile->block_size, bfile->freeb, 0, 0, BFILE_NOMORE);
  114.  
  115.         if (ferror(fp)) goto QUIT;
  116.     }
  117.     else {
  118.         rewind(fp);
  119.         fread(buf, 1, (int)(FHEAD_LEN + THEAD_LEN), fp);
  120.         sscanf(buf + COMM_LEN, "%5d%5d\n", &bfile->block_size, &bfile->freeb);
  121.  
  122.         if (ferror(fp) || *(buf + COMM_LEN + (int)BHEAD_LEN + 1) != '!') {
  123.  
  124.              goto QUIT;
  125.         }
  126.  
  127.         bfile_Find(bfile, BFILE_DIRNAME, 0);
  128.         while (_bfile_gets(bfile, buf, 99, '\0') != 0) {
  129.  
  130.             sscanf(buf, "%5d%5d ", &data[0], &data[1]);
  131.             bfile_PutDir(bfile, buf + 11, data);
  132.         }
  133.     }
  134.     return(bfile);
  135.  
  136. QUIT:
  137.     fclose(fp);
  138. QUIT1:
  139.     bfile_CloseDir(bfile);
  140.     ofree(OA_BFILE, bfile);
  141.     return(NULL);
  142. }
  143. /* -------------------------------------------------------------------------- */
  144.  
  145. boolean bfile_Find(bfile, name, type)
  146.     bfile_type    bfile;
  147.     char        *name;
  148.     int            type;
  149. /* 
  150.     sets the current file block chain.
  151.     if the chain doesn't exist then it is created.
  152.     "type" is a label for possible reference use and is ignored by bfile code
  153.  
  154.     returns:  TRUE or FALSE
  155. */
  156. {
  157.     int *data_p, data[2];
  158.     char headbuf[BHEAD_LEN + 1];
  159.     
  160.     bfile->new_find = TRUE;
  161.  
  162.     if (name == BFILE_DIRNAME) {
  163.         /* the directory starts at block 0 */
  164.  
  165.         bfile->current_name = BFILE_DIR;
  166.         bfile->current_block = 0;
  167.     }
  168.     else if ((bfile->current_name = bfile_FindDir(bfile, name)) == OSLIST_BADNAME) {
  169.         /* create new block chain */
  170.  
  171.         bfile->curblock_size = 0;
  172.         bfile->current_block = bfile_GetFreeB(bfile);
  173.         bfile->curnext_block = BFILE_NOMORE;
  174.         data[0] = bfile->current_block;
  175.         data[1] = type;
  176.  
  177.         if ((bfile->current_name = bfile_PutDir(bfile, name, data)) 
  178.             == OSLIST_BADNAME) {
  179.  
  180.             return(FALSE);
  181.         }    
  182.  
  183.         /* write something to the new block (so it can't be gotten as free) */
  184.         bfwseek(bfile);
  185.         fprintf(bfile->stream, "\n!% 5d% 5d% 5d\n", 
  186.             bfile->current_block, 
  187.             bfile->curblock_size, 
  188.             bfile->curnext_block);
  189.  
  190.         if (ferror(bfile->stream)) {
  191.             return(FALSE);
  192.         }
  193.  
  194.         bfile_WriteDir(bfile);
  195.         return(TRUE);
  196.     }
  197.     else {
  198.         data_p = bfile_GetDirData(bfile_GetDirName(bfile, bfile->current_name));
  199.         bfile->current_block = data_p[0];
  200.     }
  201.     bfrseek(bfile);
  202.  
  203.     headbuf[(int)BHEAD_LEN] = '\0';
  204.     fread(headbuf, 1, (int)BHEAD_LEN, bfile->stream);
  205.     sscanf(headbuf, "%5d%5d\n", &(bfile->curblock_size), &(bfile->curnext_block));
  206.  
  207.     if (ferror(bfile->stream)) {
  208.         return(FALSE);
  209.     }
  210.  
  211.     return(TRUE);
  212. }
  213. /* -------------------------------------------------------------------------- */
  214.  
  215. boolean bfile_Write(bfile, data, len)
  216.     bfile_type    bfile;
  217.     char        *data;
  218.     unsigned int len;
  219. /* 
  220.     saves "len" bytes of "data" into the current block chain (bfile_Find).
  221.     assumes that the last bfile_ call was bfile_Find() or bfile_Write().
  222.  
  223.     returns:  TRUE or FALSE
  224. */
  225. {
  226.     unsigned int work_size, new_size;
  227.     int block;
  228.  
  229.     if (bfile->current_block == OSLIST_BADNAME)
  230.         return(FALSE);
  231.     
  232.     if (bfile->curnext_block != BFILE_NOMORE) {
  233.         bfile_PutFreeB(bfile, bfile->curnext_block);
  234.         bfile->curnext_block = BFILE_NOMORE;
  235.     }
  236.     if (bfile->new_find) {
  237.         bfile->curblock_size = 0;
  238.         bfile->new_find = FALSE;
  239.         bfile_pad(bfile);
  240.     }
  241.  
  242.     while (len > 0) {
  243.  
  244.         if (bfile->curblock_size == bfile->block_size) {
  245.             block = bfile_GetFreeB(bfile);
  246.     
  247.             bfwseek(bfile);
  248.             fprintf(bfile->stream, "\n!% 5d% 5d% 5d\n", 
  249.                 bfile->current_block, bfile->curblock_size, block);
  250.  
  251.             if (ferror(bfile->stream)) return(FALSE);
  252.  
  253.             bfile->current_block = block;
  254.             bfile->curblock_size = 0;
  255.             bfile_pad(bfile);
  256.         }        
  257.         if (len > bfile->block_size - bfile->curblock_size) {
  258.             work_size = bfile->block_size - bfile->curblock_size;
  259.         }
  260.         else {
  261.             work_size = len;
  262.         }
  263.         new_size = bfile->curblock_size + work_size;
  264.         bfwseek(bfile);
  265.  
  266.         fprintf(bfile->stream, "\n!% 5d% 5d% 5d\n", 
  267.             bfile->current_block, new_size, BFILE_NOMORE);
  268.  
  269.         fseek(bfile->stream, (long)(bfile->curblock_size), SEEK_CUR);
  270.         fwrite(data, 1, work_size, bfile->stream);
  271.  
  272.         if (ferror(bfile->stream)) return(FALSE);
  273.  
  274.         len -= work_size;
  275.         data += work_size;
  276.         bfile->curblock_size = new_size;
  277.     }
  278.     return(TRUE);
  279. }
  280.  
  281. static boolean bfile_pad(bfile)
  282.     bfile_type bfile;
  283. {
  284.     long fptr;
  285.     unsigned int i, bsize;
  286.  
  287.     fptr = ftell(bfile->stream);    
  288.  
  289.     bfrseek(bfile);
  290.     fseek(bfile->stream, BHEAD_LEN, SEEK_CUR);
  291.  
  292.     if (ferror(bfile->stream)) return(FALSE);
  293.  
  294.     for (i = 0, bsize = bfile->block_size; i < bsize; i++) {
  295.         fwrite(BFILE_PADCHAR, 1, 1, bfile->stream);
  296.     }
  297.  
  298.     if (ferror(bfile->stream)) return(FALSE);
  299.  
  300.     fseek(bfile->stream, fptr, SEEK_SET);
  301.  
  302.     return(TRUE);
  303. }
  304. /* -------------------------------------------------------------------------- */
  305.  
  306. unsigned int _bfile_gets(bfile, buf, buf_len, end_char)
  307.     bfile_type bfile;
  308.     char *buf;
  309.     unsigned int buf_len;
  310.     char end_char;
  311. /*
  312.     fills "buf" with data up to "buf_len", 
  313.     and replaces the '\n' with "end_char".
  314.  
  315.     returns: the number of bytes read.
  316. */
  317. {
  318.     char *b;
  319.     unsigned int len;
  320.     
  321.     if (buf_len != 0) {        /* even if no read the buf must be delimited */
  322.         *buf = end_char;
  323.     }
  324.     for (b = buf, len = 0; bfile_Read(bfile, b, 1) == 1; b++) {
  325.     
  326.         len++;
  327.         if (*b == '\n') {
  328.             *b = end_char;
  329.             break;
  330.         }
  331.         else if (len == buf_len) {
  332.             break;
  333.         }
  334.     }    
  335.     return(len);
  336. }
  337. /* -------------------------------------------------------------------------- */
  338.  
  339. unsigned int bfile_Read(bfile, buf, buf_len)
  340.     bfile_type    bfile;
  341.     char        *buf;
  342.     unsigned int buf_len;
  343. /*
  344.     fills "buf" with data up to "buf_len".
  345.     assumes that the last bfile_ call was bfile_Find(), bfile_Read(),
  346.     or bfile_Gets().
  347.  
  348.     returns: the number of bytes read.
  349. */
  350. {
  351.     char *b;
  352.     unsigned int size, work_size, tot_size;
  353.     char headbuf[BHEAD_LEN + 1];
  354.     
  355.     if (bfile->current_block == OSLIST_BADNAME) {
  356.         return(0);
  357.     }
  358.  
  359.     headbuf[(int)BHEAD_LEN] = '\0';
  360.  
  361.     for (b = buf, tot_size = 0; tot_size < buf_len;) {
  362.  
  363.         work_size = bfile->curblock_size;
  364.  
  365.         if ((size = buf_len - tot_size) < work_size) {
  366.             size = fread(b, 1, size, bfile->stream);
  367.             tot_size += size;
  368.             bfile->curblock_size -= size;
  369.             break;
  370.         }                
  371.         work_size = fread(b, 1, work_size, bfile->stream);
  372.         tot_size += work_size;
  373.         b += work_size;
  374.         if (bfile->curnext_block == BFILE_NOMORE) {
  375.             /* end of read */
  376.  
  377.             bfile->current_block = OSLIST_BADNAME;
  378.             break;
  379.         }
  380.         /* go to next block */
  381.         bfile->current_block = bfile->curnext_block;
  382.  
  383.         bfrseek(bfile);
  384.         fread(headbuf, 1, (int)BHEAD_LEN, bfile->stream);
  385.         sscanf(headbuf, "%5d%5d\n", &(bfile->curblock_size), &(bfile->curnext_block));
  386.  
  387.         if (ferror(bfile->stream)) return(0);
  388.     }
  389.     return(tot_size);
  390. }
  391. /* -------------------------------------------------------------------------- */
  392.  
  393. void bfile_Close(bfile)
  394.     bfile_type    bfile;
  395. /* 
  396.     Closes a bfile.
  397. */
  398. {
  399.     bfile_CloseDir(bfile);
  400.     if (bfile->push != NULL) {
  401.         xa_Close(bfile->push);
  402.     }
  403.     if (bfile->stream != NULL) {
  404.         fclose(bfile->stream);
  405.     }
  406.     ofree(OA_BFILE, bfile);
  407. }
  408. /* -------------------------------------------------------------------------- */
  409.  
  410. boolean bfile_Push(bfile)
  411.     bfile_type bfile;
  412. {
  413.     char *mem;
  414.  
  415.     if (bfile->push == NULL) {
  416.         bfile->push = xa_Open(1);
  417.     }
  418.     if ((mem = (char *)omalloc(OA_BFPUSH, BF_PSIZE)) == NULL) {
  419.         return(FALSE);
  420.     }
  421.     /* careful */
  422.     *((long *)mem) = ftell(bfile->stream);
  423.     memcpy(mem + sizeof(long), &(bfile->current_name), BF_PINTS);
  424.  
  425.     bfile->pindex++;
  426.     xa_Put(bfile->push, bfile->pindex, (VOID *) mem);
  427.     return(TRUE);
  428. }
  429. /* -------------------------------------------------------------------------- */
  430.  
  431. boolean bfile_Pop(bfile)
  432.     bfile_type bfile;
  433. {
  434.     char *mem;
  435.  
  436.     if (bfile->push == NULL || 
  437.         (mem = (char *) xa_Get(bfile->push, bfile->pindex)) == NULL) {
  438.         return(FALSE);
  439.     }
  440.     /* careful */
  441.     fseek(bfile->stream, *((long *)mem), SEEK_SET);
  442.  
  443.     memcpy(&(bfile->current_name), mem + sizeof(long), BF_PINTS);
  444.     ofree(OA_BFPUSH, (VOID *)mem);
  445.     xa_Put(bfile->push, bfile->pindex, NULL);
  446.     bfile->pindex--;
  447.     return(TRUE);
  448. }
  449. /* -------------------------------------------------------------------------- */
  450. /********************* INTERNAL ROUTINES **************************/
  451.  
  452. void bfile_PutFreeB(bfile, block)
  453.     bfile_type    bfile;
  454.     int block;
  455. {
  456.     unsigned int size;
  457.     int old_block, next_block;
  458.     char headbuf[BHEAD_LEN + 1];
  459.     
  460.     if (bfile->freeb == BFILE_NOMORE) {
  461.  
  462.         bfile->freeb = block;
  463.     }
  464.     else {
  465.         headbuf[(int)BHEAD_LEN] = '\0';
  466.  
  467.         old_block = bfile->current_block;
  468.         next_block = block;
  469.         while (next_block != BFILE_NOMORE) {
  470.             bfile->current_block = next_block;
  471.             bfrseek(bfile);
  472.             fread(headbuf, 1, (int)BHEAD_LEN, bfile->stream);
  473.             sscanf(headbuf, "%5d%5d\n", &size, &next_block);
  474.         }
  475.         bfwseek(bfile);
  476.         fprintf(bfile->stream, "\n!% 5d% 5d% 5d\n", 
  477.             bfile->current_block, size, bfile->freeb);
  478.         bfile->freeb = block;
  479.         bfile->current_block = old_block;
  480.     }
  481.     /* rewrite file header (freeb) */
  482.     fseek(bfile->stream, (long)COMM_LEN, SEEK_SET);
  483.     fprintf(bfile->stream, "% 5d% 5d\n", bfile->block_size, bfile->freeb);
  484. }
  485. /* -------------------------------------------------------------------------- */
  486.  
  487. int bfile_GetFreeB(bfile)
  488.     bfile_type    bfile;
  489. {
  490.     long fptr;
  491.     unsigned int size;
  492.     int block, ret;
  493.     char headbuf[BHEAD_LEN + 1];
  494.     
  495.     if (bfile->freeb == BFILE_NOMORE) {
  496.  
  497.         fseek(bfile->stream, 0L, SEEK_END);
  498.         fptr = ftell(bfile->stream) - FHEAD_LEN - 1;
  499.         ret = (int)(fptr / ((long)(bfile->block_size) + BHEAD_LEN + THEAD_LEN)) + 1;
  500.     }
  501.     else {
  502.         headbuf[(int)BHEAD_LEN] = '\0';
  503.  
  504.         block = bfile->current_block;
  505.         ret = bfile->current_block = bfile->freeb;
  506.  
  507.         /* get the new free block */
  508.         bfrseek(bfile);
  509.         fread(headbuf, 1, (int)BHEAD_LEN, bfile->stream);
  510.         sscanf(headbuf, "%5d%5d\n", &size, &(bfile->freeb));
  511.  
  512.         /* destroy the free block's chain */
  513.         bfrseek(bfile);
  514.         fprintf(bfile->stream, "% 5d% 5d\n", 0, BFILE_NOMORE);
  515.  
  516.         /* rewrite file header (freeb) */
  517.         fseek(bfile->stream, (long)COMM_LEN, SEEK_SET);
  518.         fprintf(bfile->stream, "% 5d% 5d\n", bfile->block_size, bfile->freeb);
  519.  
  520.         bfile->current_block = block;
  521.     }
  522.  
  523.     return(ret);
  524. }
  525. /* -------------------------------------------------------------------------- */
  526.  
  527. void bfile_WriteDir(bfile)
  528.     bfile_type    bfile;
  529. /* 
  530.     Rewrites a bfile's directory.
  531. */
  532. {
  533.     char buf[100], *sym;
  534.     int i, *data;
  535.  
  536.     bfile_Push(bfile);
  537.     bfile_Find(bfile, BFILE_DIRNAME, 0);
  538.  
  539.     for (i = 0; i < bfile_GetDirSize(bfile); i++) {
  540.         sym = bfile_GetDirName(bfile, bfile_DirAlphaHandle(bfile, i));
  541.         data = bfile_GetDirData(sym);
  542.  
  543.         sprintf(buf, "% 5d% 5d %s\n", data[0], data[1], sym);
  544.         bfile_Write(bfile, buf, strlen(buf));
  545.     }
  546.     bfile_Pop(bfile);
  547. }
  548. /* -------------------------------------------------------------------------- */
  549.