home *** CD-ROM | disk | FTP | other *** search
- /*
- bfile.c
-
- % block file functions
-
- OWL 1.1
- Copyright (c) 1988, by Oakland Group, Inc.
- ALL RIGHTS RESERVED.
-
- Revision History:
- -----------------
- 02/02/89 jdc added bfile_Clear() and added fflush() in bfile_Read()
- 02/02/89 jdc fixed bfile_Close() bug
- 4/16/89 jmd replaced iarray with jarray
- 04/21/89 jdc changed bfile_Gets to _bfile_gets
- 07/01/89 jdc fixed free block chain
- 07/22/89 jdc removed block size check for exsisting files
- added more error checking and comment field
- 07/27/89 jdc renamed macros
- 08/02/89 jdc put if else instead of continue for bfile_Open
- 08/04/89 jdc fixed multiple bfile_GetFreeB bug
- 08/09/89 jdc added block padding
- 8/09/89 jdc changed oslist_GetSym to oslist_Get
- 8/13/89 jdc changed format
- 8/21/89 jmd changed r+b to rb
- 8/25/89 jdc changed error handling
- */
-
- #include "oakhead.h"
- #include "jadecl.h"
-
- #include "symldecl.h"
- #include "bfdecl.h"
-
- OSTATIC boolean bfile_pad(_arg1(bfile_type));
-
- static char dirname[] = "___dirname\n";
-
- #define BFILE_DIRNAME dirname
- #define BFDIR_DATASIZE 2*sizeof(int)
- #define BFILE_PADCHAR " "
-
- #define DIR_START 5
- #define BF_PSIZE 5*sizeof(int)+sizeof(long)
- #define BF_PINTS 5*sizeof(int)
-
- #define fopen_read(path) fopen(path, "r+b")
- #define fopen_write(path) fopen(path, "w+b")
-
- /* -------------------------------------------------------------------------- */
-
- bfile_type bfile_Open(pathname, block_size, comment)
- char *pathname;
- unsigned block_size;
- char *comment;
- /*
- Opens a bfile, existing or not, handles directory creation, etc.
-
- format:
- comment\n
- bfile->block_size in bytes
- bfile->freeb start of free blocks chain
-
- blocks of data \n!BLOCK\n.data_size.next_block.data_chars
-
- the first block is always the beginning of the directory
- in the form start_block.data_type. name\n...
-
- Returns:
-
- bfile_type if ok
-
- NULL if it can't open, file isn't a bfile or not enough memory for
- the directory.
- */
- {
- bfile_type bfile;
- char buf[100];
- int data[2], len;
- FILE *fp;
-
- if (comment == NULL) {
- comment = "BLOCKFILE\n";
- }
-
- if ((bfile = (bfile_type)omalloc(OA_BFILE, sizeof(struct bfile_struct)
- + strlen(pathname) + 1)) == NULL) {
- return(NULL);
- }
- bfile->path = (char*)bfile + sizeof(struct bfile_struct);
- strcpy(bfile->path, pathname);
-
- bfile->block_size = block_size;
- bfile->current_name = OSLIST_BADNAME;
- bfile->freeb = BFILE_NOMORE;
- bfile->dir = oslist_Open(DIR_START, BFDIR_DATASIZE);
- bfile->push = NULL;
- bfile->pindex = -1;
-
- if ((fp = bfile->stream = fopen_read(pathname)) == NULL) {
-
- len = ((len = strlen(comment)) > COMM_LEN ) ? COMM_LEN : len;
- strncpy(buf, comment, len);
- memset(buf+len, ' ', COMM_LEN - len);
- buf[COMM_LEN - 1] = '\n';
- buf[COMM_LEN] = '\0';
-
- if ((fp = bfile->stream = fopen_write(pathname)) == NULL)
- goto QUIT1;
-
- rewind(fp);
- fprintf(fp, "%s% 5d% 5d\n\n!% 5d% 5d %5d\n",
- buf, bfile->block_size, bfile->freeb, 0, 0, BFILE_NOMORE);
-
- if (ferror(fp)) goto QUIT;
- }
- else {
- rewind(fp);
- fread(buf, 1, (int)(FHEAD_LEN + THEAD_LEN), fp);
- sscanf(buf + COMM_LEN, "%5d%5d\n", &bfile->block_size, &bfile->freeb);
-
- if (ferror(fp) || *(buf + COMM_LEN + (int)BHEAD_LEN + 1) != '!') {
-
- goto QUIT;
- }
-
- bfile_Find(bfile, BFILE_DIRNAME, 0);
- while (_bfile_gets(bfile, buf, 99, '\0') != 0) {
-
- sscanf(buf, "%5d%5d ", &data[0], &data[1]);
- bfile_PutDir(bfile, buf + 11, data);
- }
- }
- return(bfile);
-
- QUIT:
- fclose(fp);
- QUIT1:
- bfile_CloseDir(bfile);
- ofree(OA_BFILE, bfile);
- return(NULL);
- }
- /* -------------------------------------------------------------------------- */
-
- boolean bfile_Find(bfile, name, type)
- bfile_type bfile;
- char *name;
- int type;
- /*
- sets the current file block chain.
- if the chain doesn't exist then it is created.
- "type" is a label for possible reference use and is ignored by bfile code
-
- returns: TRUE or FALSE
- */
- {
- int *data_p, data[2];
- char headbuf[BHEAD_LEN + 1];
-
- bfile->new_find = TRUE;
-
- if (name == BFILE_DIRNAME) {
- /* the directory starts at block 0 */
-
- bfile->current_name = BFILE_DIR;
- bfile->current_block = 0;
- }
- else if ((bfile->current_name = bfile_FindDir(bfile, name)) == OSLIST_BADNAME) {
- /* create new block chain */
-
- bfile->curblock_size = 0;
- bfile->current_block = bfile_GetFreeB(bfile);
- bfile->curnext_block = BFILE_NOMORE;
- data[0] = bfile->current_block;
- data[1] = type;
-
- if ((bfile->current_name = bfile_PutDir(bfile, name, data))
- == OSLIST_BADNAME) {
-
- return(FALSE);
- }
-
- /* write something to the new block (so it can't be gotten as free) */
- bfwseek(bfile);
- fprintf(bfile->stream, "\n!% 5d% 5d% 5d\n",
- bfile->current_block,
- bfile->curblock_size,
- bfile->curnext_block);
-
- if (ferror(bfile->stream)) {
- return(FALSE);
- }
-
- bfile_WriteDir(bfile);
- return(TRUE);
- }
- else {
- data_p = bfile_GetDirData(bfile_GetDirName(bfile, bfile->current_name));
- bfile->current_block = data_p[0];
- }
- bfrseek(bfile);
-
- headbuf[(int)BHEAD_LEN] = '\0';
- fread(headbuf, 1, (int)BHEAD_LEN, bfile->stream);
- sscanf(headbuf, "%5d%5d\n", &(bfile->curblock_size), &(bfile->curnext_block));
-
- if (ferror(bfile->stream)) {
- return(FALSE);
- }
-
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- boolean bfile_Write(bfile, data, len)
- bfile_type bfile;
- char *data;
- unsigned int len;
- /*
- saves "len" bytes of "data" into the current block chain (bfile_Find).
- assumes that the last bfile_ call was bfile_Find() or bfile_Write().
-
- returns: TRUE or FALSE
- */
- {
- unsigned int work_size, new_size;
- int block;
-
- if (bfile->current_block == OSLIST_BADNAME)
- return(FALSE);
-
- if (bfile->curnext_block != BFILE_NOMORE) {
- bfile_PutFreeB(bfile, bfile->curnext_block);
- bfile->curnext_block = BFILE_NOMORE;
- }
- if (bfile->new_find) {
- bfile->curblock_size = 0;
- bfile->new_find = FALSE;
- bfile_pad(bfile);
- }
-
- while (len > 0) {
-
- if (bfile->curblock_size == bfile->block_size) {
- block = bfile_GetFreeB(bfile);
-
- bfwseek(bfile);
- fprintf(bfile->stream, "\n!% 5d% 5d% 5d\n",
- bfile->current_block, bfile->curblock_size, block);
-
- if (ferror(bfile->stream)) return(FALSE);
-
- bfile->current_block = block;
- bfile->curblock_size = 0;
- bfile_pad(bfile);
- }
- if (len > bfile->block_size - bfile->curblock_size) {
- work_size = bfile->block_size - bfile->curblock_size;
- }
- else {
- work_size = len;
- }
- new_size = bfile->curblock_size + work_size;
- bfwseek(bfile);
-
- fprintf(bfile->stream, "\n!% 5d% 5d% 5d\n",
- bfile->current_block, new_size, BFILE_NOMORE);
-
- fseek(bfile->stream, (long)(bfile->curblock_size), SEEK_CUR);
- fwrite(data, 1, work_size, bfile->stream);
-
- if (ferror(bfile->stream)) return(FALSE);
-
- len -= work_size;
- data += work_size;
- bfile->curblock_size = new_size;
- }
- return(TRUE);
- }
-
- static boolean bfile_pad(bfile)
- bfile_type bfile;
- {
- long fptr;
- unsigned int i, bsize;
-
- fptr = ftell(bfile->stream);
-
- bfrseek(bfile);
- fseek(bfile->stream, BHEAD_LEN, SEEK_CUR);
-
- if (ferror(bfile->stream)) return(FALSE);
-
- for (i = 0, bsize = bfile->block_size; i < bsize; i++) {
- fwrite(BFILE_PADCHAR, 1, 1, bfile->stream);
- }
-
- if (ferror(bfile->stream)) return(FALSE);
-
- fseek(bfile->stream, fptr, SEEK_SET);
-
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- unsigned int _bfile_gets(bfile, buf, buf_len, end_char)
- bfile_type bfile;
- char *buf;
- unsigned int buf_len;
- char end_char;
- /*
- fills "buf" with data up to "buf_len",
- and replaces the '\n' with "end_char".
-
- returns: the number of bytes read.
- */
- {
- char *b;
- unsigned int len;
-
- if (buf_len != 0) { /* even if no read the buf must be delimited */
- *buf = end_char;
- }
- for (b = buf, len = 0; bfile_Read(bfile, b, 1) == 1; b++) {
-
- len++;
- if (*b == '\n') {
- *b = end_char;
- break;
- }
- else if (len == buf_len) {
- break;
- }
- }
- return(len);
- }
- /* -------------------------------------------------------------------------- */
-
- unsigned int bfile_Read(bfile, buf, buf_len)
- bfile_type bfile;
- char *buf;
- unsigned int buf_len;
- /*
- fills "buf" with data up to "buf_len".
- assumes that the last bfile_ call was bfile_Find(), bfile_Read(),
- or bfile_Gets().
-
- returns: the number of bytes read.
- */
- {
- char *b;
- unsigned int size, work_size, tot_size;
- char headbuf[BHEAD_LEN + 1];
-
- if (bfile->current_block == OSLIST_BADNAME) {
- return(0);
- }
-
- headbuf[(int)BHEAD_LEN] = '\0';
-
- for (b = buf, tot_size = 0; tot_size < buf_len;) {
-
- work_size = bfile->curblock_size;
-
- if ((size = buf_len - tot_size) < work_size) {
- size = fread(b, 1, size, bfile->stream);
- tot_size += size;
- bfile->curblock_size -= size;
- break;
- }
- work_size = fread(b, 1, work_size, bfile->stream);
- tot_size += work_size;
- b += work_size;
- if (bfile->curnext_block == BFILE_NOMORE) {
- /* end of read */
-
- bfile->current_block = OSLIST_BADNAME;
- break;
- }
- /* go to next block */
- bfile->current_block = bfile->curnext_block;
-
- bfrseek(bfile);
- fread(headbuf, 1, (int)BHEAD_LEN, bfile->stream);
- sscanf(headbuf, "%5d%5d\n", &(bfile->curblock_size), &(bfile->curnext_block));
-
- if (ferror(bfile->stream)) return(0);
- }
- return(tot_size);
- }
- /* -------------------------------------------------------------------------- */
-
- void bfile_Close(bfile)
- bfile_type bfile;
- /*
- Closes a bfile.
- */
- {
- bfile_CloseDir(bfile);
- if (bfile->push != NULL) {
- xa_Close(bfile->push);
- }
- if (bfile->stream != NULL) {
- fclose(bfile->stream);
- }
- ofree(OA_BFILE, bfile);
- }
- /* -------------------------------------------------------------------------- */
-
- boolean bfile_Push(bfile)
- bfile_type bfile;
- {
- char *mem;
-
- if (bfile->push == NULL) {
- bfile->push = xa_Open(1);
- }
- if ((mem = (char *)omalloc(OA_BFPUSH, BF_PSIZE)) == NULL) {
- return(FALSE);
- }
- /* careful */
- *((long *)mem) = ftell(bfile->stream);
- memcpy(mem + sizeof(long), &(bfile->current_name), BF_PINTS);
-
- bfile->pindex++;
- xa_Put(bfile->push, bfile->pindex, (VOID *) mem);
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- boolean bfile_Pop(bfile)
- bfile_type bfile;
- {
- char *mem;
-
- if (bfile->push == NULL ||
- (mem = (char *) xa_Get(bfile->push, bfile->pindex)) == NULL) {
- return(FALSE);
- }
- /* careful */
- fseek(bfile->stream, *((long *)mem), SEEK_SET);
-
- memcpy(&(bfile->current_name), mem + sizeof(long), BF_PINTS);
- ofree(OA_BFPUSH, (VOID *)mem);
- xa_Put(bfile->push, bfile->pindex, NULL);
- bfile->pindex--;
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
- /********************* INTERNAL ROUTINES **************************/
-
- void bfile_PutFreeB(bfile, block)
- bfile_type bfile;
- int block;
- {
- unsigned int size;
- int old_block, next_block;
- char headbuf[BHEAD_LEN + 1];
-
- if (bfile->freeb == BFILE_NOMORE) {
-
- bfile->freeb = block;
- }
- else {
- headbuf[(int)BHEAD_LEN] = '\0';
-
- old_block = bfile->current_block;
- next_block = block;
- while (next_block != BFILE_NOMORE) {
- bfile->current_block = next_block;
- bfrseek(bfile);
- fread(headbuf, 1, (int)BHEAD_LEN, bfile->stream);
- sscanf(headbuf, "%5d%5d\n", &size, &next_block);
- }
- bfwseek(bfile);
- fprintf(bfile->stream, "\n!% 5d% 5d% 5d\n",
- bfile->current_block, size, bfile->freeb);
- bfile->freeb = block;
- bfile->current_block = old_block;
- }
- /* rewrite file header (freeb) */
- fseek(bfile->stream, (long)COMM_LEN, SEEK_SET);
- fprintf(bfile->stream, "% 5d% 5d\n", bfile->block_size, bfile->freeb);
- }
- /* -------------------------------------------------------------------------- */
-
- int bfile_GetFreeB(bfile)
- bfile_type bfile;
- {
- long fptr;
- unsigned int size;
- int block, ret;
- char headbuf[BHEAD_LEN + 1];
-
- if (bfile->freeb == BFILE_NOMORE) {
-
- fseek(bfile->stream, 0L, SEEK_END);
- fptr = ftell(bfile->stream) - FHEAD_LEN - 1;
- ret = (int)(fptr / ((long)(bfile->block_size) + BHEAD_LEN + THEAD_LEN)) + 1;
- }
- else {
- headbuf[(int)BHEAD_LEN] = '\0';
-
- block = bfile->current_block;
- ret = bfile->current_block = bfile->freeb;
-
- /* get the new free block */
- bfrseek(bfile);
- fread(headbuf, 1, (int)BHEAD_LEN, bfile->stream);
- sscanf(headbuf, "%5d%5d\n", &size, &(bfile->freeb));
-
- /* destroy the free block's chain */
- bfrseek(bfile);
- fprintf(bfile->stream, "% 5d% 5d\n", 0, BFILE_NOMORE);
-
- /* rewrite file header (freeb) */
- fseek(bfile->stream, (long)COMM_LEN, SEEK_SET);
- fprintf(bfile->stream, "% 5d% 5d\n", bfile->block_size, bfile->freeb);
-
- bfile->current_block = block;
- }
-
- return(ret);
- }
- /* -------------------------------------------------------------------------- */
-
- void bfile_WriteDir(bfile)
- bfile_type bfile;
- /*
- Rewrites a bfile's directory.
- */
- {
- char buf[100], *sym;
- int i, *data;
-
- bfile_Push(bfile);
- bfile_Find(bfile, BFILE_DIRNAME, 0);
-
- for (i = 0; i < bfile_GetDirSize(bfile); i++) {
- sym = bfile_GetDirName(bfile, bfile_DirAlphaHandle(bfile, i));
- data = bfile_GetDirData(sym);
-
- sprintf(buf, "% 5d% 5d %s\n", data[0], data[1], sym);
- bfile_Write(bfile, buf, strlen(buf));
- }
- bfile_Pop(bfile);
- }
- /* -------------------------------------------------------------------------- */