481 lines
9.7 KiB
C
481 lines
9.7 KiB
C
|
|
/*
|
|
* parse library stdio and malloc utility classes.
|
|
*/
|
|
|
|
/*
|
|
* Version 2.05
|
|
*
|
|
* Author: Graeme W. Gill
|
|
* Date: 2002/10/24
|
|
*
|
|
* Copyright 2002, Graeme W. Gill
|
|
* All rights reserved.
|
|
*
|
|
* This material is licensed with an "MIT" free use license:-
|
|
* see the License4.txt file in this directory for licensing details.
|
|
*
|
|
* These are kept in a separate file to allow them to be
|
|
* selectively ommitted from the cgats library.
|
|
*
|
|
*/
|
|
|
|
|
|
#define _PARSSTD_C_
|
|
|
|
#ifndef COMBINED_STD
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#ifdef __sun
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "pars.h"
|
|
|
|
#endif /* !COMBINED_STD */
|
|
|
|
#if defined(SEPARATE_STD) || defined(COMBINED_STD)
|
|
|
|
/* ----------------------------------------------- */
|
|
/* Standard Heap allocator cgatsAlloc compatible class */
|
|
/* Just call the standard system function */
|
|
|
|
#ifdef CGATS_DEBUG_MALLOC
|
|
|
|
/* Make sure that inline malloc #defines are turned off for this file */
|
|
#undef was_debug_malloc
|
|
#ifdef malloc
|
|
#undef malloc
|
|
#undef calloc
|
|
#undef realloc
|
|
#undef free
|
|
#define was_debug_malloc
|
|
#endif /* dmalloc */
|
|
|
|
static void *cgatsAllocStd_dmalloc(
|
|
struct _cgatsAlloc *pp,
|
|
size_t size,
|
|
char *file,
|
|
int line
|
|
) {
|
|
void *rv = malloc(size);
|
|
return rv;
|
|
}
|
|
|
|
static void *cgatsAllocStd_dcalloc(
|
|
struct _cgatsAlloc *pp,
|
|
size_t num,
|
|
size_t size,
|
|
char *file,
|
|
int line
|
|
) {
|
|
void *rv = calloc(num, size);
|
|
return rv;
|
|
}
|
|
|
|
static void *cgatsAllocStd_drealloc(
|
|
struct _cgatsAlloc *pp,
|
|
void *ptr,
|
|
size_t size,
|
|
char *file,
|
|
int line
|
|
) {
|
|
void *rv = realloc(ptr, size);
|
|
return rv;
|
|
}
|
|
|
|
|
|
static void cgatsAllocStd_dfree(
|
|
struct _cgatsAlloc *pp,
|
|
void *ptr,
|
|
char *file,
|
|
int line
|
|
) {
|
|
free(ptr);
|
|
}
|
|
|
|
/* we're done with the AllocStd object */
|
|
static void cgatsAllocStd_delete(
|
|
cgatsAlloc *pp
|
|
) {
|
|
cgatsAllocStd *p = (cgatsAllocStd *)pp;
|
|
|
|
free(p);
|
|
}
|
|
|
|
/* Create cgatsAllocStd */
|
|
cgatsAlloc *new_cgatsAllocStd() {
|
|
cgatsAllocStd *p;
|
|
if ((p = (cgatsAllocStd *) calloc(1,sizeof(cgatsAllocStd))) == NULL)
|
|
return NULL;
|
|
p->dmalloc = cgatsAllocStd_dmalloc;
|
|
p->dcalloc = cgatsAllocStd_dcalloc;
|
|
p->drealloc = cgatsAllocStd_drealloc;
|
|
p->dfree = cgatsAllocStd_dfree;
|
|
p->del = cgatsAllocStd_delete;
|
|
|
|
return (cgatsAlloc *)p;
|
|
}
|
|
|
|
#ifdef was_debug_malloc
|
|
#undef was_debug_malloc
|
|
#define malloc( p, size ) dmalloc( p, size, __FILE__, __LINE__ )
|
|
#define calloc( p, num, size ) dcalloc( p, num, size, __FILE__, __LINE__ )
|
|
#define realloc( p, ptr, size ) drealloc( p, ptr, size, __FILE__, __LINE__ )
|
|
#define free( p, ptr ) dfree( p, ptr , __FILE__, __LINE__ )
|
|
#endif /* was_debug_malloc */
|
|
|
|
#else /* !CGATS_DEBUG_MALLOC */
|
|
|
|
static void *cgatsAllocStd_malloc(
|
|
struct _cgatsAlloc *pp,
|
|
size_t size
|
|
) {
|
|
void *rv = malloc(size);
|
|
return rv;
|
|
}
|
|
|
|
static void *cgatsAllocStd_calloc(
|
|
struct _cgatsAlloc *pp,
|
|
size_t num,
|
|
size_t size
|
|
) {
|
|
void *rv = calloc(num, size);
|
|
return rv;
|
|
}
|
|
|
|
static void *cgatsAllocStd_realloc(
|
|
struct _cgatsAlloc *pp,
|
|
void *ptr,
|
|
size_t size
|
|
) {
|
|
void *rv = realloc(ptr, size);
|
|
return rv;
|
|
}
|
|
|
|
|
|
static void cgatsAllocStd_free(
|
|
struct _cgatsAlloc *pp,
|
|
void *ptr
|
|
) {
|
|
free(ptr);
|
|
}
|
|
|
|
/* we're done with the AllocStd object */
|
|
static void cgatsAllocStd_delete(
|
|
cgatsAlloc *pp
|
|
) {
|
|
cgatsAllocStd *p = (cgatsAllocStd *)pp;
|
|
|
|
free(p);
|
|
}
|
|
|
|
/* Create cgatsAllocStd */
|
|
cgatsAlloc *new_cgatsAllocStd() {
|
|
cgatsAllocStd *p;
|
|
if ((p = (cgatsAllocStd *) calloc(1,sizeof(cgatsAllocStd))) == NULL)
|
|
return NULL;
|
|
p->malloc = cgatsAllocStd_malloc;
|
|
p->calloc = cgatsAllocStd_calloc;
|
|
p->realloc = cgatsAllocStd_realloc;
|
|
p->free = cgatsAllocStd_free;
|
|
p->del = cgatsAllocStd_delete;
|
|
|
|
return (cgatsAlloc *)p;
|
|
}
|
|
|
|
#endif /* !CGATS_DEBUG_MALLOC */
|
|
|
|
/* ------------------------------------------------- */
|
|
/* Standard Stream file I/O cgatsFile compatible class */
|
|
|
|
/* Get the size of the file (Only valid for reading file. */
|
|
static size_t cgatsFileStd_get_size(cgatsFile *pp) {
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
|
|
return p->size;
|
|
}
|
|
|
|
/* Set current position to offset. Return 0 on success, nz on failure. */
|
|
static int cgatsFileStd_seek(
|
|
cgatsFile *pp,
|
|
unsigned int offset
|
|
) {
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
|
|
return fseek(p->fp, offset, SEEK_SET);
|
|
}
|
|
|
|
/* Read count items of size length. Return number of items successfully read. */
|
|
static size_t cgatsFileStd_read(
|
|
cgatsFile *pp,
|
|
void *buffer,
|
|
size_t size,
|
|
size_t count
|
|
) {
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
|
|
return fread(buffer, size, count, p->fp);
|
|
}
|
|
|
|
/* Read a character */
|
|
static int cgatsFileStd_getch(
|
|
cgatsFile *pp
|
|
) {
|
|
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
|
|
return fgetc(p->fp);
|
|
}
|
|
|
|
/* write count items of size length. Return number of items successfully written. */
|
|
static size_t cgatsFileStd_write(
|
|
cgatsFile *pp,
|
|
void *buffer,
|
|
size_t size,
|
|
size_t count
|
|
) {
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
|
|
return fwrite(buffer, size, count, p->fp);
|
|
}
|
|
|
|
/* do a printf */
|
|
static int cgatsFileStd_printf(
|
|
cgatsFile *pp,
|
|
const char *format,
|
|
...
|
|
) {
|
|
int rv;
|
|
va_list args;
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
|
|
va_start(args, format);
|
|
rv = vfprintf(p->fp, format, args);
|
|
va_end(args);
|
|
return rv;
|
|
}
|
|
|
|
/* flush all write data out to secondary storage. Return nz on failure. */
|
|
static int cgatsFileStd_flush(
|
|
cgatsFile *pp
|
|
) {
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
|
|
return fflush(p->fp);
|
|
}
|
|
|
|
/* Return the memory buffer. Error if not cgatsFileMem */
|
|
static int cgatsFileStd_get_buf(
|
|
cgatsFile *pp,
|
|
unsigned char **buf,
|
|
size_t *len
|
|
) {
|
|
return 1;
|
|
}
|
|
|
|
/* return the filename */
|
|
static char *cgatsFileStd_fname(
|
|
cgatsFile *pp
|
|
) {
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
|
|
if (p->filename != NULL)
|
|
return p->filename;
|
|
else
|
|
return "**Unknown**";
|
|
}
|
|
|
|
|
|
/* we're done with the file object, return nz on failure */
|
|
static int cgatsFileStd_delete(
|
|
cgatsFile *pp
|
|
) {
|
|
int rv = 0;
|
|
cgatsFileStd *p = (cgatsFileStd *)pp;
|
|
cgatsAlloc *al = p->al;
|
|
int del_al = p->del_al;
|
|
|
|
if (p->doclose != 0) {
|
|
if (fclose(p->fp) != 0)
|
|
rv = 2;
|
|
}
|
|
|
|
if (p->filename != NULL)
|
|
al->free(al, p->filename);
|
|
|
|
al->free(al, p); /* Free object */
|
|
if (del_al) /* We are responsible for deleting allocator */
|
|
al->del(al);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* Create cgatsFile given a (binary) FILE* */
|
|
cgatsFile *new_cgatsFileStd_fp(
|
|
FILE *fp
|
|
) {
|
|
return new_cgatsFileStd_fp_a(fp, NULL);
|
|
}
|
|
|
|
/* Create cgatsFile given a (binary) FILE* and allocator */
|
|
cgatsFile *new_cgatsFileStd_fp_a(
|
|
FILE *fp,
|
|
cgatsAlloc *al /* heap allocator, NULL for default */
|
|
) {
|
|
cgatsFileStd *p;
|
|
int del_al = 0;
|
|
struct stat sbuf = { 0 };
|
|
|
|
if (al == NULL) { /* None provided, create default */
|
|
if ((al = new_cgatsAllocStd()) == NULL)
|
|
return NULL;
|
|
del_al = 1; /* We need to delete it */
|
|
}
|
|
|
|
if ((p = (cgatsFileStd *) al->calloc(al, 1, sizeof(cgatsFileStd))) == NULL) {
|
|
if (del_al)
|
|
al->del(al);
|
|
return NULL;
|
|
}
|
|
p->al = al; /* Heap allocator */
|
|
p->del_al = del_al; /* Flag noting whether we delete it */
|
|
p->get_size = cgatsFileStd_get_size;
|
|
p->seek = cgatsFileStd_seek;
|
|
p->read = cgatsFileStd_read;
|
|
p->getch = cgatsFileStd_getch;
|
|
p->write = cgatsFileStd_write;
|
|
p->gprintf = cgatsFileStd_printf;
|
|
p->flush = cgatsFileStd_flush;
|
|
p->get_buf = cgatsFileStd_get_buf;
|
|
p->fname = cgatsFileStd_fname;
|
|
p->del = cgatsFileStd_delete;
|
|
|
|
if (fstat(fileno(fp), &sbuf) == 0) {
|
|
p->size = sbuf.st_size;
|
|
} else {
|
|
p->size = 0;
|
|
}
|
|
|
|
p->fp = fp;
|
|
p->doclose = 0;
|
|
|
|
return (cgatsFile *)p;
|
|
}
|
|
|
|
/* Create cgatsFile given a file name */
|
|
cgatsFile *new_cgatsFileStd_name(
|
|
const char *name,
|
|
const char *mode
|
|
) {
|
|
return new_cgatsFileStd_name_a(name, mode, NULL);
|
|
}
|
|
|
|
/* Create given a file name and allocator */
|
|
cgatsFile *new_cgatsFileStd_name_a(
|
|
const char *name,
|
|
const char *mode,
|
|
cgatsAlloc *al /* heap allocator, NULL for default */
|
|
) {
|
|
FILE *fp;
|
|
cgatsFile *p;
|
|
char nmode[50];
|
|
|
|
strcpy(nmode, mode);
|
|
#if !defined(O_CREAT) && !defined(_O_CREAT)
|
|
# error "Need to #include fcntl.h!"
|
|
#endif
|
|
#if defined(O_BINARY) || defined(_O_BINARY)
|
|
strcat(nmode, "b");
|
|
#endif
|
|
|
|
if ((fp = fopen(name, nmode)) == NULL)
|
|
return NULL;
|
|
|
|
p = new_cgatsFileStd_fp_a(fp, al);
|
|
|
|
if (p != NULL) {
|
|
cgatsFileStd *pp = (cgatsFileStd *)p;
|
|
pp->doclose = 1;
|
|
|
|
pp->filename = pp->al->malloc(pp->al, strlen(name) + 1);
|
|
strcpy(pp->filename, name);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
/* Create a memory image file access class with the std allocator */
|
|
/* Don't free the buffer on delete */
|
|
cgatsFile *new_cgatsFileMem(
|
|
void *base, /* Pointer to base of memory buffer */
|
|
size_t length /* Number of bytes in buffer */
|
|
) {
|
|
cgatsFile *p;
|
|
cgatsAlloc *al; /* memory allocator */
|
|
|
|
if ((al = new_cgatsAllocStd()) == NULL)
|
|
return NULL;
|
|
|
|
if ((p = new_cgatsFileMem_a(base, length, al)) == NULL) {
|
|
al->del(al);
|
|
return NULL;
|
|
}
|
|
|
|
((cgatsFileMem *)p)->del_al = 1; /* Get cgatsFileMem->del to cleanup al */
|
|
return p;
|
|
}
|
|
|
|
/* Create a memory image file access class with the std allocator */
|
|
/* Free buffer on delete */
|
|
cgatsFile *new_cgatsFileMem_d(
|
|
void *base, /* Pointer to base of memory buffer */
|
|
size_t length /* Number of bytes in buffer */
|
|
) {
|
|
cgatsFile *p;
|
|
cgatsAlloc *al; /* memory allocator */
|
|
|
|
if ((al = new_cgatsAllocStd()) == NULL)
|
|
return NULL;
|
|
|
|
if ((p = new_cgatsFileMem_a(base, length, al)) == NULL) {
|
|
al->del(al);
|
|
return NULL;
|
|
}
|
|
|
|
((cgatsFileMem *)p)->del_al = 1; /* Get cgatsFileMem->del to cleanup al */
|
|
((cgatsFileMem *)p)->del_buf = 1; /* Get cgatsFileMem->del to cleanup buffer */
|
|
return p;
|
|
}
|
|
|
|
/* ------------------------------------------------- */
|
|
|
|
/* Create an empty parse object, default standard allocator */
|
|
parse *
|
|
new_parse(cgatsFile *fp) {
|
|
parse *p;
|
|
cgatsAlloc *al; /* memory allocator */
|
|
|
|
if ((al = new_cgatsAllocStd()) == NULL)
|
|
return NULL;
|
|
|
|
if ((p = new_parse_al(al, fp)) == NULL) {
|
|
al->del(al);
|
|
return NULL;
|
|
}
|
|
|
|
p->del_al = 1; /* Get parse->del to cleanup allocator */
|
|
return p;
|
|
}
|
|
|
|
|
|
#endif /* defined(SEPARATE_STD) || defined(COMBINED_STD) */
|