home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / CSAPE32.ARJ / SOURCE / OWLSCR / BFILE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-25  |  14.2 KB  |  560 lines

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