Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1162 lines
26 KiB

/*** doclib.c - standard DH library routines
* cl /c /Zep /D LINT_ARGS doclib.c
*/
#include <stdio.h>
#include <fcntl.h>
#include "dh.h"
#include "dhint.h"
#ifdef XENIX
#define O_BINARY 0 /* null or in constant */
#endif
/* external functions */
extern int fprintf();
extern char *getenv();
extern char *malloc();
extern int free();
extern int open();
extern int close();
extern int read();
extern int write();
extern long _lseek();
extern int exit();
extern char *strcat();
extern char *strchr();
extern int strcmp();
extern char *strcpy();
extern char *_strdup();
extern int strlen();
extern char *strncpy();
/*
** Globals
*/
static Folder foldertab[NFOLDERS];
static Document doctab[NDOCS];
static char *dhpath = NULL;
/*
** Forward functions
*/
static int mkfold(char *,struct Folder *);
static unsigned int setnipe(void);
static int pathsrch(char *,struct Folder *);
static char *pathcat(char * *,char *);
static unsigned int setsize(unsigned int );
static struct Folder *fhtofp(int );
static int readindex(struct Folder *,int ,struct Index *);
static int writeindex(struct Folder *,int ,struct Index *);
static int getextent(struct Folder *,int ,int );
static int addextent(struct Folder *,int );
static void flushextent(struct Folder *);
static void clearextent(struct Folder *);
static struct Document *dhtodp(int );
static char *nlnl(char *);
/*global*/ int getfolder(char *,int );
/*global*/ void putfolder(int );
/*global*/ char *getname(int );
/*global*/ int getdoc(int ,int ,int );
/*global*/ int scanfolder(int ,int );
/*global*/ int putdoc(int );
/*global*/ int deldoc(int ,int );
/*global*/ int gettext(int ,int );
/*global*/ char *gethdr(int );
/*global*/ int getbdy(int ,int );
/*global*/ int puttext(int ,int );
/*global*/ int putbody(int ,int );
/*global*/ int puthdr(int ,char *);
/*global*/ int getid(int );
char *(*dh_alloc) (int) = malloc;
void (*dh_free) (char *) = free;
/*** getfolder - prepare a DH folder for manipulation
*
* folderhand = getfolder(foldername, function);
*
* get a folder handle for the folder foldername
* function can take one of the following values:
* FLD_CREATE create a new folder
* FLD_SPEC open existing folder
*/
Fhandle getfolder(name, func)
char *name;
int func;
{
int rv;
char *cname;
int fd;
Folder *fp;
/* find first free slot */
for (fp = foldertab; fp < &foldertab[NFOLDERS]; fp += 1) {
if (fp->f_flags == 0)
break;
}
switch(func) {
case FLD_SPEC: /* open a specific folder */
if ( pathsrch(name, fp) == ERROR )
return ERROR;
break;
case FLD_CREATE: /* create a new subfolder */
if ( mkfold(name, fp) == ERROR )
return ERROR;
break;
default: /* bad action */
return ERROR;
}
/* ok, set it up */
fp->f_flags |= F_BUSY;
return (Fhandle)(fp - foldertab);
}
/*** mkfold - create a new folder
*
* mkfold creates a new, empty folder. The difficult part
* is determining the path name of the new folder. The path
* name is determined by the following rules:
* 1. If the name passed to mkfold contains a PATHSEP then
* the name passed is the path name used.
* 2. Otherwise, the name is generated by concatenating the
* first element of DHPATH with the passed name.
*
* Folders are created with mode 666 (modified by the creator's
* umask).
*
* Entry: name = name of new folder (see above)
* fp = pointer to folder slot to fill
*
* Return: OK or ERROR
*/
static int mkfold(name, fp)
char *name;
Folder *fp;
{
char *work;
int len;
if ( strchr(name, PATHSEP) != NULL ) {
fp->f_name = _strdup(name);
} else {
if ( dhpath == NULL && (dhpath = getenv("DHPATH")) == NULL ) {
fprintf(stderr, "DHPATH not set.\n");
return ERROR;
}
if ( (work = strchr(dhpath, PATHBRK)) == NULL )
len = strlen(dhpath);
else
len = work - dhpath;
/* allocate space; one byte for null terminator, one for PATHSEP */
fp->f_name = (*dh_alloc)(len + strlen(name) + 2);
/* build the canonical name */
work = fp->f_name + len;
if ( len ) {
strncpy(fp->f_name, dhpath, len);
*work++ = PATHSEP;
}
strcpy(work, name);
}
if ( (fp->f_fd = open(fp->f_name, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0666)) < 0 ) {
fprintf(stderr, "Can't create folder '%s'.\n", fp->f_name);
(*dh_free) (fp->f_name);
return ERROR;
}
fp->f_control.c_magic = MAGIC;
fp->f_control.c_numdoc = 0;
fp->f_control.c_nipe = setnipe();
fp->f_extsize = setsize(fp->f_control.c_nipe);
write(fp->f_fd, &fp->f_control, sizeof(Control));
fp->f_extent = (Extent *)(*dh_alloc)(fp->f_extsize);
clearextent(fp);
fp->f_extpos = sizeof(Control);
fp->f_extnum = 0;
write(fp->f_fd, fp->f_extent, fp->f_extsize);
fp->f_flags = 0;
return OK;
}
/*** setnipe - compute how many index entries to use per extent
*
* setnipe decides how many index entries per extent should be used
* when we create a new folder. Currently, it always simply returns
* a fixed, per-system value.
*
*/
static unsigned setnipe()
{
return DEFAULT_NIPE;
}
/*** pathsrch - search along DHPATH for a folder
*
* pathsrch tries to locate a folder, using DHPATH if necessary.
* If the name that is passed contains a PATHSEP, that is the name
* used. Otherwise, the folder is searched for in each directory
* specified in DHPATH.
*
* Entry: name = name of folder (see above)
* fp = pointer to folder slot to fill
*
* Return: ERROR or OK
*/
static int pathsrch(name, fp)
char *name;
Folder *fp;
{
char *path;
if ( strchr(name, PATHSEP) != NULL ) {
fp->f_name = _strdup(name);
if ( (fp->f_fd = open(fp->f_name, O_RDWR|O_BINARY)) < 0 ) {
(*dh_free) (fp->f_name);
return ERROR;
}
} else {
fp->f_fd = -1;
if ( dhpath == NULL && (dhpath = getenv("DHPATH")) == NULL ) {
fprintf(stderr, "DHPATH not set.\n");
return ERROR;
}
path = dhpath;
while ( (fp->f_name = pathcat(&path, name)) != NULL ) {
if ( (fp->f_fd = open(fp->f_name, O_RDWR|O_BINARY)) >= 0 )
break;
(*dh_free) (fp->f_name);
}
if ( fp->f_fd < 0 )
return ERROR;
}
read(fp->f_fd, &fp->f_control, sizeof(Control));
if ( fp->f_control.c_magic != MAGIC ) {
close(fp->f_fd);
(*dh_free) (fp->f_name);
return ERROR;
}
fp->f_extnum = -1;
fp->f_extent = NULL;
fp->f_extsize = setsize(fp->f_control.c_nipe);
fp->f_extpos = 0;
fp->f_flags = 0;
return OK;
}
/*** pathcat - help contruct paths for pathsrc
* WE NEED BETTER HEADER HERE!
*/
static char *pathcat(pathpp, name)
char **pathpp;
char *name;
{
int len;
char *end, *work, *rv;
if ( **pathpp == '\0' )
return NULL;
if ( (end = strchr(*pathpp, PATHBRK)) != NULL )
len = end - *pathpp;
else
len = strlen(*pathpp);
/* allocate space; one byte for null terminator, one for PATHSEP */
rv = (*dh_alloc)(len + strlen(name) + 2);
/* build the canonical name */
work = &rv[len];
if ( len ) {
strncpy(rv, *pathpp, len);
*work++ = PATHSEP;
}
strcpy(work, name);
/* adjust the path pointer for next time */
*pathpp += len;
if ( **pathpp == PATHBRK )
*pathpp += 1;
return rv;
}
/*** setsize - return size of extent, based on nipe, static sizes.
*
* setsize subtracts the size of one index entry from the size of Extent,
* which yields the TRUE size of the static part of an extent. It then
* adds the number of index entries per extent (nipe) for this folder
* times the size of and index entry. This yields the true size of
* an extent for a particular folder.
*
*/
static unsigned setsize(nipe)
unsigned nipe;
{
unsigned size;
size = sizeof(Extent) - sizeof(Index);
size += nipe * sizeof(Index);
return size;
}
/*** putfolder - close a folder
*
* Put_folder indicates that this folder is no longer going
* to be manipulated. Thus, we can now deallocate any resources
* associated with that folder. Currently, those resources are
* the alloc'ed string for the canonical name, and possibly
* an open stream, if the FLD_FIRST or FLD_NEXT operations of
* get_folder have been used.
*
* Entry: fh = Fhandle of folder to close
* Return: none
*/
void putfolder(fh)
Fhandle fh;
{
Folder *fp;
if ((fp = fhtofp(fh)) == NULL)
return;
if ( fp->f_flags & F_CDIRTY ) {
_lseek(fp->f_fd, 0L, 0);
write(fp->f_fd, &fp->f_control, sizeof(Control));
fp->f_flags &= ~F_CDIRTY;
}
if ( fp->f_flags & F_EDIRTY )
flushextent(fp);
close(fp->f_fd);
(*dh_free) (fp->f_name);
if ( fp->f_extent != NULL )
(*dh_free) ((char *) (fp->f_extent));
fp->f_flags = 0;
return;
}
/*** getname - get a DH name for a folder
*
* Getname gets the name of an open folder. The name of a folder
* is the canonical name (see mkcname, above) of the folder, with
* the dhroot portion cut off. In other words, we could form
* the dh name of a folder by concatenating the name of the parent
* folder and the name of the folder itself.
*
* we deduce the DH name of a folder by examining the canonical
* name in the foldertab entry. We pass back a pointer into the
* canonical name, with the pointer pointing just past the
* dhroot part.
*
*/
char *getname(fh)
Fhandle fh;
{
Folder *fp;
if ( (fp = fhtofp(fh)) == NULL )
return NULL;
return _strdup(fp->f_name);
}
/*** fhtofp - convert folder handle to folder pointer
*
* Outside this module, the only reference to an active folder is
* its 'folder handle.' This routine converts this handle to
* a pointer to the appropriate entry in the foldertab.
*
* Entry: fh = folder handle to convert
* Return: NULL if fh is not a valid folder handle
* pointer to Folder if fh is valid
*/
static Folder *fhtofp(fh)
Fhandle fh;
{
Folder *rv;
if ((fh < 0) || (fh >= NFOLDERS))
return NULL;
rv = &foldertab[fh];
if ( (rv->f_flags & F_BUSY) == 0)
return NULL;
return rv;
}
/*** index - create/manage the DH folder index
*
* DH folders contain both the data for the header and body,
* and an index that allows programs to locate that data easily.
* The index contains one entry for each document. Index
* entries are grouped together in 'extents'. Each extent contains
* a number of index entries, and pointers to the previous and
* subsequent extents. The ends of this doubly linked list marked
* by null pointers.
*
* A header block at the beginning of the file contains relevant
* information such as how many extents are allocated, how many
* documents there are, etc.
*/
/*** readindex - read the index for a specific document
*
* The index entry for a specific document is read from the
* appropriate extent into the passed data area.
* We first get the appropriate extent into memory, and then
* copy the index from the extent.
*
* Entry: fp = pointer to folder that document is in
* docid = Id of document to read index for
* ip = pointer to place to read index into
*
* Return: ERROR if unsuccessful
* OK if successful
*/
static int readindex(fp, docid, ip)
Folder *fp;
Docid docid;
Index *ip;
{
int fd;
int extent, offset;
long pos;
/* quick check, does doc exist? */
if ( docid > fp->f_control.c_numdoc )
return ERROR;
/* read down the extent chain forward pointers */
getextent(fp, (docid-1)/fp->f_control.c_nipe, 0);
*ip = fp->f_extent->e_index[(docid - 1) % fp->f_control.c_nipe];
return OK;
}
/*** writeindex - write the index for a specific document
*
* The index entry for a specific document is written to the
* appropriate extent from the passed data area.
* We first get the appropriate extent into memory, and then
* copy the index into the extent. The altered extent is then
* marked dirty, so that it will eventually be flushed to disk.
*
* Entry: fp = pointer to folder that document is in
* docid = Id of document to write index for
* ip = pointer to place to read index from
*
* Return: ERROR if unsuccessful
* OK if successful
*/
static int writeindex(fp, docid, ip)
Folder *fp;
Docid docid;
Index *ip;
{
/* quick check, does doc exist? */
if ( docid > fp->f_control.c_numdoc )
return ERROR;
getextent(fp, (docid-1)/fp->f_control.c_nipe, 1);
fp->f_extent->e_index[(docid - 1) % fp->f_control.c_nipe] = *ip;
fp->f_flags |= F_EDIRTY;
return OK;
}
/*** getextent - get a specified extent into memory
*
* The specified extent is read into memory.
* If the current extent is dirty, it must be flushed to disk.
* Then, the correct extent is located and read into memory.
* If the extent doesn't exist yet, but the flag is non-zero
* then the extent is created. New extents are created only
* if they would fall immediately after the last extent in the
* existing chain of extents.
*
* Entry: fp = pointer to folder that extent is part of
* number = extent to be read
* flag = 0 means don't create a new extent
* flag = 1 means do create a new extent if needed
*
* Return: OK if successful
* FAILURE if unsuccessful
*/
static int getextent(fp, number, flag)
Folder *fp;
int number;
int flag;
{
long pos;
int n;
if (fp->f_extent == NULL ) {
fp->f_extent = (Extent *)(*dh_alloc)(fp->f_extsize);
fp->f_extnum = -1;
fp->f_extpos = 0;
}
if ( fp->f_extnum == number )
return OK;
if ( fp->f_flags & F_EDIRTY )
flushextent(fp);
/* read down the links the right number of times */
if ( (fp->f_extnum > number) || (fp->f_extnum == -1) ) {
/* start at beginning */
pos = sizeof(Control);
fp->f_extnum = -1;
} else {
/* start from where we are */
pos = fp->f_extent->e_link;
}
for (; fp->f_extnum != number; pos = fp->f_extent->e_link) {
if ( pos == 0L )
break;
_lseek(fp->f_fd, pos, 0);
read(fp->f_fd, fp->f_extent, fp->f_extsize);
fp->f_extnum += 1;
fp->f_extpos = pos;
}
if ( fp->f_extnum == number )
return OK;
if ( (number - fp->f_extnum) > 1 ) {
fprintf(stderr, "extent chain too short.\n");
fprintf(stderr, "extnum %d number %d\n", fp->f_extnum, number);
exit(1);
}
if ( (number - fp->f_extnum) == 1 && flag != 0 ) {
return addextent(fp, number);
}
}
/*** addextent - add a new extent to the chain
*
* A new, empty extent is added to the current chain.
* First, we get the last extent into memory. Then, we seek to the
* end of the, set the link of the last extent to that position, and
* create the new extent in memory. We flush the new extent, and
* return.
*
* Entry: fp = pointer to folder to create extent for
* number = number of extent to create.
* Return: OK if ok, ERROR otherwise
*/
static int addextent(fp, number)
Folder *fp;
int number;
{
long pos;
if ( getextent(fp, number - 1, 0) != OK )
return ERROR;
if ( fp->f_extent->e_link != 0 ) {
fprintf(stderr, "Warning: trying to add extent that exists.\n");
}
pos = _lseek(fp->f_fd, 0L, 2); /* end of file */
fp->f_extent->e_link = pos;
flushextent(fp);
fp->f_extpos = pos;
fp->f_extnum = number;
fp->f_flags |= F_EDIRTY;
clearextent(fp);
flushextent(fp);
return OK;
}
static void flushextent(fp)
Folder *fp;
{
_lseek(fp->f_fd, fp->f_extpos, 0);
write(fp->f_fd, fp->f_extent, fp->f_extsize);
fp->f_flags &= ~F_EDIRTY;
}
static void clearextent(fp)
Folder *fp;
{
register int i;
register Index *ip;
for (ip = fp->f_extent->e_index;
ip < &(fp->f_extent->e_index[fp->f_control.c_nipe]);
ip += 1) {
ip->i_hpos = ip->i_bpos = 0;
ip->i_hlen = ip->i_blen = 0;
ip->i_flags = 0;
}
fp->f_extent->e_link = 0;
}
/*** getdoc - get a document
*
* get a document handle for the document indicated by flags [and docid].
* flags can take one of the following values:
* DOC_SPEC document specified by 'docid' in 'folder'
* DOC_CREATE create new document in 'folder'
*
* Entry: fh = Fhandle to parent folder of document
* func = desired action
* docid = document id, if needed
* Return: ERROR if failed, Dhandle to document if successful
*/
Dhandle getdoc(fh, func, docid)
Fhandle fh;
int func;
Docid docid;
{
Folder *fp;
Document *dp;
FILE *file;
struct extent *ep;
int extent, offset;
if ( (fp = fhtofp(fh)) == NULL )
return ERROR;
/* find empty document slot */
for (dp = doctab; dp < &doctab[NDOCS]; dp += 1) {
if (dp->d_flags == 0)
break;
}
if (dp >= &doctab[NDOCS])
return ERROR;
/* do function specific work */
switch (func) {
case DOC_SPEC: /* find a specific document */
/* quick check, does doc exist? */
if ( docid > fp->f_control.c_numdoc )
return ERROR;
if ( readindex(fp, docid, &dp->d_index) == ERROR )
return ERROR;
/* make sure the document exists */
if ( (dp->d_index.i_flags & (I_EXISTS|I_DELETED)) != I_EXISTS )
return ERROR;
/* ok, init the document struct and return */
dp->d_docid = docid;
dp->d_flags = 0;
break;
case DOC_CREATE: /* make a new document */
/* get a new document id */
fp->f_control.c_numdoc += 1;
dp->d_docid = fp->f_control.c_numdoc;
fp->f_flags |= F_CDIRTY;
/* set up an empty document */
dp->d_index.i_flags = I_EXISTS;
dp->d_index.i_hlen = 0;
dp->d_index.i_blen = 0;
dp->d_index.i_hpos = 0;
dp->d_index.i_bpos = 0;
dp->d_flags |= D_IDIRTY;
break;
default: /* Bad function */
return ERROR;
}
/* do work common to all funcs */
dp->d_flags |= D_BUSY;
dp->d_fp = fp;
return (Dhandle)(dp - doctab);
}
/*** scanfolder - scan the existing documents
*
* return the document id for the specified document
* flags can take one of the following values:
* DOC_FIRST first document in 'folder'
* DOC_NEXT next document in 'folder'
* DOC_LAST upper bound on last docid
*
* Entry: fh = Fhandle to parent folder of document
* func = desired action
* docid = document id, if needed
* Return: ERROR if failed, docid of document if successful
*/
Docid scanfolder(fh, func)
Fhandle fh;
int func;
{
Folder *fp;
int i, flags;
if ( (fp = fhtofp(fh)) == NULL )
return ERROR;
/* do function specific work */
switch (func) {
case DOC_FIRST: /* find the first document */
fp->f_sdocid = 1;
/* fall thru */
case DOC_NEXT: /* find the next document */
while ( 1 ) {
if ( fp->f_sdocid > fp->f_control.c_numdoc )
return ERROR;
if ( getextent(fp,
(fp->f_sdocid - 1)/fp->f_control.c_nipe,0) != OK)
return ERROR;
i = (int)(fp->f_sdocid - 1) % fp->f_control.c_nipe;
flags = fp->f_extent->e_index[i].i_flags;
if ( (flags & (I_EXISTS|I_DELETED)) == I_EXISTS )
return fp->f_sdocid;
fp->f_sdocid += 1;
}
case DOC_LAST: /* upper bound on last doc */
return fp->f_control.c_numdoc;
default: /* Bad function */
return ERROR;
}
}
/*** putdoc - close a document
*
* Put_doc indicates that the document is no longer going to
* be manipulated. Thus, we can free all the resources that
* are allocated for that document.
*
* Entry: dh = Dhandle to document to close
* Return: none unless there's an error, in which case ERROR
*/
putdoc(dh)
Dhandle dh;
{
Document *dp;
if ((dp = dhtodp(dh)) == NULL)
return ERROR;
if ( dp->d_flags & D_IDIRTY)
writeindex(dp->d_fp, dp->d_docid, &(dp->d_index));
dp->d_fp->f_cnt -= 1;
dp->d_flags = 0;
return 0;
}
/*** deldoc - make a document go away
*
* Entry: fh = handle of folder to delete document from
* docid = number of document to delete
*
* Return: ERROR if document never existed, or already deleted
*
* BUGBUG - deleted an open document will result in chaos
*/
deldoc(fh, docid)
Fhandle fh;
int docid;
{
Index index;
Folder *fp;
if ( (fp = fhtofp(fh)) == NULL )
return ERROR;
readindex(fp, docid, &index);
if ( index.i_flags & I_DELETED )
return ERROR;
index.i_flags |= I_DELETED;
writeindex(fp, docid, &index);
return OK;
}
/*** gettext - write document to stream
*
* The entire document, header and all, is written to the
* passed stream in presentation format.
*
* Entry: dh = handle of document to write to stream
* stream = stream to write document onto
*
* Return: ERROR or none
*/
gettext(dh, file)
Dhandle dh;
int file;
{
Document *dp;
char *cp;
if ((dp = dhtodp(dh)) == NULL)
return ERROR;
/* write out header */
if ( (cp = gethdr(dh)) == NULL )
return ERROR;
write(file, cp, strlen(cp));
(*dh_free) (cp);
write(file, "\n", 1);
/* write out body */
getbdy(dh, file);
return 0;
}
/*** gethdr(dh) - get header block
*
* We return a pointer to on allocated piece of memory that
* contains the header for the document. The memory is allocated
* from the heap. Because the memory pointer is returned to the
* user, we must assume that we transfer ownership to the caller.
* Thus, he is responsible for freeing the memory when he no longer
* needs it.
*
* Entry: dh = handle of relevant document
*
* Return: pointer to block of memory if successful
* NULL if unsuccessful
*/
char *gethdr(dh)
Dhandle dh;
{
Document *dp;
char *cp;
int size;
if ( (dp = dhtodp(dh)) == NULL)
return NULL;
size = (int)dp->d_index.i_hlen;
cp = (*dh_alloc)(size + 1);
_lseek(dp->d_fp->f_fd, dp->d_index.i_hpos, 0);
read(dp->d_fp->f_fd, cp, size);
cp[size] = '\0';
return cp;
}
/*** getbdy - write the body of the document to the passed file handle
*
* The body of the relevant document is written onto the passed
* file handle.
*
* Entry: dh = handle of document
* file = file handle to write body onto
*/
getbdy(dh, file)
Dhandle dh;
int file;
{
Document *dp;
long pos, length;
int fd;
char *bufp;
int cnt;
if ( (dp = dhtodp(dh)) == NULL )
return ERROR;
if ( (bufp = (*dh_alloc)(BUFFERSIZE)) == NULL )
return ERROR;
length = dp->d_index.i_blen;
pos = dp->d_index.i_bpos;
fd = dp->d_fp->f_fd;
_lseek(fd, pos, 0L);
while ( length > 0 ) {
if ( length > BUFFERSIZE )
cnt = BUFFERSIZE;
else
cnt = (int)length;
cnt = read(fd, bufp, cnt);
write(file, bufp, cnt);
length -= (long)cnt;
}
(*dh_free) (bufp);
return OK;
}
/*** puttext - replace contents of a document
*
* The entire document is replaced by the document read from
* the stream, assumed to be a document is presentation format
*
* Entry: dh = handle of document to replace
* file = file handle to read new document content from
*
* Return: ERROR or none
*/
int puttext(dh, file)
Dhandle dh;
int file;
{
Document *dp;
char *bufp;
char *wp;
char *hp;
int cnt;
int nllast = 0;
int fd;
if ( (dp = dhtodp(dh)) == NULL )
return ERROR;
if ( (bufp = (*dh_alloc)(BUFFERSIZE+1)) == NULL )
return ERROR;
fd = dp->d_fp->f_fd;
dp->d_index.i_hpos = _lseek(fd, 0L, 2);
dp->d_index.i_hlen = 0;
/* read in header */
while ( 1 ) {
if ( (cnt = read(file, bufp, BUFFERSIZE)) == 0 )
break;
if ( nllast && *bufp == '\n' ) {
wp = bufp + 1;
break;
}
bufp[cnt] = '\0';
if ( (wp = nlnl(bufp)) != NULL ) {
/* found end of header */
wp += 1;
write(fd, bufp, wp - bufp);
dp->d_index.i_hlen += (long)(wp - bufp);
wp += 1;
break;
}
if ( bufp[cnt - 1] == '\n' )
nllast = 1;
write(fd, bufp, cnt);
dp->d_index.i_hlen += (long)cnt;
}
/*
* wp = NULL iff there is no body
* wp = ptr to start of body in buffer iff there is a body
* bufp = ptr to buffer
* cnt = amount of data in buffer
*/
if ( wp == NULL ) {
fprintf(stdout, "no body\n"); /* Should this be stderr??? */
dp->d_index.i_bpos = 0;
dp->d_index.i_blen = 0;
} else {
dp->d_index.i_bpos = dp->d_index.i_hpos + dp->d_index.i_hlen;
dp->d_index.i_blen = (long)(cnt - (wp - bufp));
write(fd, wp, cnt - (wp - bufp));
}
/*
* write remainder of file into body
*/
while ( (cnt = read(file, bufp, BUFFERSIZE)) > 0 ) {
dp->d_index.i_blen += (long)cnt;
write(fd, bufp, cnt);
}
dp->d_flags |= D_IDIRTY;
(*dh_free) (bufp);
}
/*** putbody - replace the body of a document
*
* The body of the specified document is replaced with the
* body read from the specified file descriptor.
*
* Entry: dh = handle of document to replace
* ifd = file handle to read body from
*
* Return: ERROR if some difficulty arises
*/
putbody(dh, ifd)
Dhandle dh;
int ifd;
{
Document *dp;
int fd;
int cnt;
char *bufp;
if ( (dp = dhtodp(dh)) == NULL )
return ERROR;
if ( (bufp = (*dh_alloc)(BUFFERSIZE)) == NULL )
return ERROR;
fd = dp->d_fp->f_fd;
dp->d_index.i_bpos = _lseek(fd, 0L, 2);
dp->d_index.i_blen = 0;
while ( (cnt = read(ifd, bufp, BUFFERSIZE)) > 0 ) {
dp->d_index.i_blen += (long)cnt;
write(fd, bufp, cnt);
}
dp->d_flags |= D_IDIRTY;
(*dh_free) (bufp);
return OK;
}
/*** puthdr - set new header block
*
* The document specified by dh gets a new header,
* which is specified by the memory block that bp points to.
* All storage, including the list nodes, must be allocated
* from the heap, as it will be freed from the heap at
* put_doc time.
*
* Note that we replace a header IN PLACE if we can.
*
* entry:
* dh = handle of document which will recieve the new header
* lp = pointer to new header field/value list
*
* return: ERROR if some problem
*/
puthdr(dh, bp)
Dhandle dh;
char *bp;
{
Document *dp;
long l = (long) strlen (bp);
if ( (dp = dhtodp(dh)) == NULL )
return ERROR;
if (l <= dp->d_index.i_hlen)
_lseek (dp->d_fp->f_fd, dp->d_index.i_hpos, 0);
else
dp->d_index.i_hpos = _lseek(dp->d_fp->f_fd, 0L, 2);
dp->d_index.i_hlen = l;
write(dp->d_fp->f_fd, bp, dp->d_index.i_hlen);
dp->d_flags |= D_IDIRTY;
return OK;
}
/*** getid - get the name of a document
*
* The name of the document is its 'document id', really
* just a number. This number is computed based on information
* in the doclist and returned.
*
* entry:
* dh = handle of document in question
*
* Return: id of document
*/
Docid getid(dh)
Dhandle dh;
{
Document *dp;
if ((dp = dhtodp(dh)) == NULL)
return ERROR;
return dp->d_docid;
}
/*** dhtodp - convert document handle to pointer to document list structure
*
* Dhtodp checks to make sure that dh is a valid handle, and if it is, returns
* the internal document structure that it corresponds to. If not, NULL will
* be returned, indicating an error.
*
* entry:
* dh - document handle to test and dereference
*
* return:
* pointer to docstrc of interest, or null if error
*
* globals: doclist
*
*/
static Document *dhtodp(dh)
Dhandle dh;
{
/* handle ok? */
if ( ((doctab[dh].d_flags & D_BUSY) == 0) || (dh >= NDOCS) || (dh < 0))
return NULL;
return &doctab[dh];
}
static char *nlnl(cp)
char *cp;
{
while ( (cp = strchr(cp, '\n')) != NULL ) {
if ( cp[1] == '\n' )
return cp;
cp += 1;
}
return NULL;
}
/*** getbodylen - return length of the body of a document
*
* The document specified by dh is examined and the length is returned.
*
* entry:
* dh = handle of document to be sized.
*
* return: ERROR (cast to LONG) if bogus doc handle
*/
long getbodylen (dh)
Dhandle dh;
{
Document *dp;
if ( (dp = dhtodp(dh)) == NULL )
return (long) ERROR;
return dp->d_index.i_blen;
}