diff --git a/Makefile b/Makefile index f8c1c54..953e094 100755 --- a/Makefile +++ b/Makefile @@ -12,7 +12,8 @@ CC ?= gcc #CC ?= tcc #CC ?= musl-tcc CFLAGS += -O2 -pedantic -g -Wall -Wextra -CPPFLAGS += -DVERSION=$(VERSION) -D_FORTIFY_SOURCE=2 +# CPPFLAGS += -DVERSION=$(VERSION) -D_FORTIFY_SOURCE=2 +CPPFLAGS += -DVERSION=$(VERSION) LDFLAGS += -lm BIN ?= slidescript diff --git a/src/compression.c b/src/compression.c old mode 100755 new mode 100644 diff --git a/src/enc.c b/src/enc.c old mode 100755 new mode 100644 diff --git a/src/eprintf.c b/src/eprintf.c new file mode 100644 index 0000000..03c0153 --- /dev/null +++ b/src/eprintf.c @@ -0,0 +1,259 @@ +/* ------------------------------------------------------------ */ +/* file information */ +/* ------------------------------------------------------------ */ + +// Filename: eprintf.c +// Purpose: TTY and error-message routines +// License: MIT/X. (c) OldCoder (Robert Kiraly) 1987-2021. + +/* ------------------------------------------------------------ */ +/* header files */ +/* ------------------------------------------------------------ */ + +/* The "EPRINTF_P" definition used below suppresses some of the */ +/* prototypes in "x3file.h" locally. This allows us to imple- */ +/* ment variable-length argument lists in a non-standard (but */ +/* generally portable) fashion. */ + +#define EPRINTF_P /* see explanation above */ + +#include +#include +#include + +#include "inc/eprintf.h" + +/* ------------------------------------------------------------ */ +/* functions */ +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC init_tty(NO_PARAM) */ +/* Summary: Initializes the UX3 TTY flags. */ + +/* ------------------------------------------------------------ */ + +/* "init_tty()" sets three global character variables as fol- */ +/* lows: */ +/* */ +/* tty_in -- standard input stream TTY mode */ +/* tty_out -- standard output stream TTY mode */ +/* tty_err -- standard error stream TTY mode */ + +/* TTY modes are determined by the standard library function */ +/* "isatty()". */ + +/* E.g., "init_tty()" sets these three flags true if and only */ +/* if the associated streams are console devices. */ + +/* The global character variable "tty_set" flags the TTY */ +/* initialization status. "tty_set" is true if "init_tty()" */ +/* has been called previously. */ + +/* ------------------------------------------------------------ */ + +V_FUNC init_tty (NO_PARAM) +{ + tty_in = isatty (0); /* standard-input TTY flag */ + tty_out = isatty (1); /* standard-output TTY flag */ + tty_err = isatty (2); /* standard-error TTY flag */ + tty_set = TRUE; /* TTY initialization flag */ +} + +/* ------------------------------------------------------------ */ + +/* "eprintf(s,...)" accepts a "printf()"-style argument list, */ +/* writes the specified message to the standard error stream, */ +/* and flushes the stream. */ + +/* This function may be system-dependent. */ + +/* ------------------------------------------------------------ */ + +V_FUNC eprintf (s,a,b,c,d,e,f,g,h,i,j) +char *s; /* format string */ +int a,b,c,d,e,f,g,h,i,j; /* dummy arguments */ +{ + fflush (stdout); /* flush standard output stream */ + + fprintf (stderr, /* print message to the */ + s,a,b,c,d,e,f,g,h,i,j); /* standard error stream */ + + fflush (stderr); /* flush standard error stream */ +} + +/* ------------------------------------------------------------ */ + +/* "eprintf2(s,...)" accepts a "printf()"-style argument list, */ +/* writes the specified message to the standard error stream, */ +/* and flushes the stream. */ + +/* If the standard output and standard error TTY modes are */ +/* different, "eprintf2()" will write the message to the */ +/* standard output stream as well. TTY modes are determined by */ +/* the standard library function "isatty()". */ + +/* This function may be system-dependent. */ + +/* ------------------------------------------------------------ */ + +V_FUNC eprintf2 (s,a,b,c,d,e,f,g,h,i,j) +char *s; /* format string */ +int a,b,c,d,e,f,g,h,i,j; /* dummy arguments */ +{ + fflush (stdout); /* flush standard output stream */ + + fprintf (stderr, /* print message to the */ + s,a,b,c,d,e,f,g,h,i,j); /* standard error stream */ + + fflush (stderr); /* flush standard error stream */ + if (!tty_set) init_tty(); /* initialize TTY mode flags */ + + if (tty_out == tty_err) /* split the error stream? */ + { /* no */ + return; /* done - exit */ + } + + fprintf (stdout, /* print message to the stan- */ + s,a,b,c,d,e,f,g,h,i,j); /* dard output stream */ + + fflush (stdout); /* flush standard output stream */ +} + +/* ------------------------------------------------------------ */ + +/* "z_msg(t_flag,pf,s,...)" accepts the following arguments: */ +/* */ +/* t_flag -- terminate-caller flag */ +/* pf -- prefix-string pointer */ +/* s, ... -- "printf()"-style argument list */ + +/* "z_msg()" writes the specified "printf()"-style message to */ +/* the standard error stream, appends a newline, and flushes */ +/* the stream. */ + +/* If the standard output and standard error TTY modes are */ +/* different, "z_msg()" will write the message to the standard */ +/* output stream as well. TTY modes are determined by the */ +/* standard library function "isatty()". */ + +/* If the prefix-string pointer "pf" is not NULL, "z_msg()" */ +/* prepends the specified string to the message produced. */ + +/* If the terminate-caller flag "t_flag" is true (nonzero), */ +/* "z_msg()" terminates the caller upon completion. */ + +/* This function may be system-dependent. */ + +/* ------------------------------------------------------------ */ + +MODPRIV V_FUNC z_msg(t_flag,pf,s,a,b,c,d,e,f,g,h,i,j) +int t_flag; /* terminate-caller flag */ +char *pf; /* prefix pointer (or NULL) */ +char *s; /* format string */ +int a,b,c,d,e,f,g,h,i,j; /* dummy arguments */ +{ + if ((pf != NULLCP) && (*pf != CH_EOS)) eprintf2 ("%s",pf); + eprintf2 (s,a,b,c,d,e,f,g,h,i,j); + eprintf2 ("\n"); /* append a newline */ + if (t_flag) exit (ONE); /* terminate the caller */ +} + +/* ------------------------------------------------------------ */ + +/* "x_warn(s,...)" accepts a "printf()"-style argument list */ +/* and writes an warning message based on the argument list to */ +/* the standard error stream. */ + +/* If the standard output and standard error TTY modes are */ +/* different, "x_warn()" will write the message to the standard */ +/* output stream as well. TTY modes are determined by the */ +/* standard library function "isatty()". */ + +/* This function may be system-dependent. */ + +/* ------------------------------------------------------------ */ + +V_FUNC x_warn(s,a,b,c,d,e,f,g,h,i,j) +char *s; /* format string */ +int a,b,c,d,e,f,g,h,i,j; /* dummy arguments */ +{ + z_msg (FALSE, "Warning: ", s,a,b,c,d,e,f,g,h,i,j); +} + +/* ------------------------------------------------------------ */ + +/* "x_error(s,...)" accepts a "printf()"-style argument list, */ +/* writes an error message based on the argument list to the */ +/* standard error stream, and terminates the caller. */ + +/* If the standard output and standard error TTY modes are */ +/* different, "x_error()" will write the message to the */ +/* standard output stream as well. TTY modes are determined by */ +/* the standard library function "isatty()". */ + +/* This function may be system-dependent. */ + +/* ------------------------------------------------------------ */ + +V_FUNC x_error(s,a,b,c,d,e,f,g,h,i,j) +char *s; /* format string */ +int a,b,c,d,e,f,g,h,i,j; /* dummy arguments */ +{ + z_msg (TRUE, "Error: ", s,a,b,c,d,e,f,g,h,i,j); +} + +/* ------------------------------------------------------------ */ + +/* "x_panic(s,...)" accepts a "printf()"-style argument list, */ +/* writes an error message based on the argument list to the */ +/* standard error stream, and terminates the caller. */ + +/* If the standard output and standard error TTY modes are */ +/* different, "x_panic" will write the message to the standard */ +/* output stream as well. TTY modes are determined by the */ +/* standard library function "isatty()". */ + +/* "x_panic" is called primarily to handle internal consistency */ +/* errors. */ + +/* This function may be system-dependent. */ + +/* ------------------------------------------------------------ */ + +V_FUNC x_panic (s,a,b,c,d,e,f,g,h,i,j) +char *s; /* format string */ +int a,b,c,d,e,f,g,h,i,j; /* dummy arguments */ +{ + z_msg (TRUE, "Internal error: ", + s,a,b,c,d,e,f,g,h,i,j); +} + +/* ------------------------------------------------------------ */ + +/* "n_panic(n)" prints an error message of the following form */ +/* and terminates the caller: */ +/* */ +/* Internal error: #123 */ + +/* The integer "n" is used for the "#..." portion of the */ +/* message. */ + +/* "n_panic()" writes the message to the standard error stream. */ + +/* If the standard output and standard error TTY modes are */ +/* different, "n_panic()" will write the message to the stan- */ +/* dard output stream as well. TTY modes are determined by the */ +/* standard library function "isatty()". */ + +/* "n_panic()" is called primarily to handle internal con- */ +/* sistency errors. */ + +/* This function may be system-dependent. */ + +/* ------------------------------------------------------------ */ + +V_FUNC n_panic(n) +REG_VAR int n; /* "panic" number */ +{ + x_panic ("#%d",n,0,0,0,0,0,0,0,0,0); +} diff --git a/src/inc/compression.h b/src/inc/compression.h old mode 100755 new mode 100644 diff --git a/src/inc/config.h b/src/inc/config.h old mode 100755 new mode 100644 diff --git a/src/inc/deps.h b/src/inc/deps.h old mode 100755 new mode 100644 diff --git a/src/inc/enc.h b/src/inc/enc.h old mode 100755 new mode 100644 diff --git a/src/inc/eprintf.h b/src/inc/eprintf.h new file mode 100644 index 0000000..00126d3 --- /dev/null +++ b/src/inc/eprintf.h @@ -0,0 +1,45 @@ +/* ------------------------------------------------------------ */ +/* file information */ +/* ------------------------------------------------------------ */ + +// Filename: eprintf.h +// Purpose: TTY and error-message routines +// License: MIT/X. (c) OldCoder (Robert Kiraly) 1987-2021. + +/* ------------------------------------------------------------ */ +/* header file setup */ +/* ------------------------------------------------------------ */ + +#ifndef _EPRINTF_H /* skip this file if loaded */ +#define _EPRINTF_H 1 /* flag this file */ + +#include "x3basic.h" + +/* ------------------------------------------------------------ */ +/* TTY (console mode) flags */ +/* ------------------------------------------------------------ */ + +UX3_EXT char tty_in; /* standard-input TTY flag */ +UX3_EXT char tty_out; /* standard-output TTY flag */ +UX3_EXT char tty_err; /* standard-error TTY flag */ +UX3_EXT char tty_set; /* TTY initialization flag */ + +/* ------------------------------------------------------------ */ +/* function prototypes */ +/* ------------------------------------------------------------ */ + +V_PROTO init_tty (NO_PARAM); + +#ifndef EPRINTF_P /* see comments in "eprintf.c" */ +/*VARARGS*/ V_PROTO eprintf (argp2 (char *, ...)); +/*VARARGS*/ V_PROTO eprintf2 (argp2 (char *, ...)); +/*VARARGS*/ V_PROTO x_panic (argp2 (char *, ...)); +/*VARARGS*/ V_PROTO x_error (argp2 (char *, ...)); +/*VARARGS*/ V_PROTO x_warn (argp2 (char *, ...)); +#endif /* endif not EPRINTF_P */ + +/* ------------------------------------------------------------ */ +/* wrap it up */ +/* ------------------------------------------------------------ */ + +#endif /* endif _EPRINTF_H */ diff --git a/src/inc/inset.h b/src/inc/inset.h old mode 100755 new mode 100644 diff --git a/src/inc/lexer.h b/src/inc/lexer.h old mode 100755 new mode 100644 diff --git a/src/inc/math.h b/src/inc/math.h old mode 100755 new mode 100644 diff --git a/src/inc/md5.h b/src/inc/md5.h old mode 100755 new mode 100644 diff --git a/src/inc/network.h b/src/inc/network.h old mode 100755 new mode 100644 diff --git a/src/inc/pipe.h b/src/inc/pipe.h old mode 100755 new mode 100644 diff --git a/src/inc/sbyteswap.h b/src/inc/sbyteswap.h old mode 100755 new mode 100644 diff --git a/src/inc/search.h b/src/inc/search.h old mode 100755 new mode 100644 diff --git a/src/inc/tar.h b/src/inc/tar.h old mode 100755 new mode 100644 index 456b665..5d125ee --- a/src/inc/tar.h +++ b/src/inc/tar.h @@ -26,6 +26,12 @@ THE SOFTWARE #ifndef __TAR__ #define __TAR__ +#include "x3mem.h" + +UX3_EXT QLIST QM_TAR [ONE]; // Dynamic-memory QLIST + +extern void tar_free_pool (void); + #ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE #endif diff --git a/src/inc/util.h b/src/inc/util.h old mode 100755 new mode 100644 diff --git a/src/inc/vars.h b/src/inc/vars.h old mode 100755 new mode 100644 diff --git a/src/inc/x3basic.h b/src/inc/x3basic.h new file mode 100644 index 0000000..e69cde9 --- /dev/null +++ b/src/inc/x3basic.h @@ -0,0 +1,275 @@ +/* ------------------------------------------------------------ */ +/* file information */ +/* ------------------------------------------------------------ */ + +// Filename: x3basic.h +// Purpose: UX3 basic definitions +// License: MIT/X. (c) OldCoder (Robert Kiraly) 1987-2021. + +/* ------------------------------------------------------------ */ +/* header file setup */ +/* ------------------------------------------------------------ */ + +#ifndef _X3BASIC_H /* skip this file if loaded */ +#define _X3BASIC_H 1 /* flag this file */ + +/* ------------------------------------------------------------ */ +/* basic definitions */ +/* ------------------------------------------------------------ */ + +#ifndef ZERO +#define ZERO 0 +#endif // Endif ZERO + +#ifndef ONE +#define ONE 1 +#endif // Endif ONE + +#ifndef FALSE +#define FALSE 0 +#endif // Endif FALSE + +#ifndef TRUE +#define TRUE 1 +#endif // Endif TRUE + +#ifndef CH_EOS +#define CH_EOS '\0' +#endif // Endif CH_EOS + +#ifndef x3u_char +#define x3u_char unsigned char +#endif + +#ifndef x3u_int +#define x3u_int unsigned int +#endif + +#ifndef x3u_long +#define x3u_long unsigned long +#endif + +#ifndef MODPRIV // Module-private +#define MODPRIV static +#endif // Endif MODPRIV + +#ifndef MODPUB // Module-public +#define MODPUB +#endif // Endif MODPUB + +#ifndef REG_VAR +#define REG_VAR +#endif // Endif NULL_PTR + +/* ------------------------------------------------------------ */ +/* "erase item" macro functions */ +/* ------------------------------------------------------------ */ + +/* If "dp" is a data pointer (of any type) and "nb" is a short */ +/* or long integer, "b_clr(dp,nb)" clears "nb" bytes to zero, */ +/* starting with the first byte pointed to by "dp". */ + +/* Note: "nb" may use any integer data type, but the value of */ +/* "nb" should fit into an unsigned integer. */ + +#define b_clr(dp,nb) \ + { \ + REG_VAR char *cp = (char *) (dp); \ + REG_VAR u_int x = (u_int) (nb); \ + while (x-- > ZERO) *cp++ = CH_EOS; \ + } + +/* ------------------------------------------------------------ */ + +/* If "a[]" is an array, "a_clr(a)" clears the array (bytewise) */ +/* to zero. "a[]" must be an array and not a pointer. The */ +/* array must have a known fixed size. */ + +#define a_clr(a) b_clr ((char *) (&((a)[0])),sizeof(a)) + +/* ------------------------------------------------------------ */ + +/* If "p" is a pointer to a structure or variable, "p_clr(p)" */ +/* clears the structure or variable. The pointer object must */ +/* have a known fixed size. */ + +#define p_clr(p) b_clr ((char *) (p),sizeof(*p)) + +/* ------------------------------------------------------------ */ + +/* If "x" is a variable (and not an array), "v_clr(x)" clears */ +/* the variable (bytewise) to zero. The variable must have a */ +/* known fixed size. */ + +#define v_clr(x) b_clr ((char *) (&(x)),sizeof(x)) + +/* ------------------------------------------------------------ */ +/* handle "void" data type */ +/* ------------------------------------------------------------ */ + +/* The following five symbols provide a portable interface to */ +/* the "void" data type. These five symbols are translated */ +/* appropriately for systems which don't support the "void" */ +/* type. */ + +/* (a) V_FUNC -- defines a void function */ +/* (b) V_PROTO -- declares a void function */ +/* (c) NO_PARAM -- void function parameter type */ +/* (d) V_CAST -- void typecast */ +/* (e) V_OBJ -- void pointer object */ + +/* ------------------------------------------------------------ */ + +/* V_FUNC may be used to declare a void function in the follow- */ +/* ing context: */ +/* */ +/* V_FUNC function-definition(...) { ... } */ + +/* V_FUNC should not be used in function declarations or */ +/* function prototypes. */ + +/* ------------------------------------------------------------ */ + +/* V_PROTO may be used to declare a void function in the */ +/* following two contexts: */ +/* */ +/* V_PROTO function-declaration(); */ +/* V_PROTO function-prototype(...); */ + +/* V_PROTO should not be used in function definitions. */ + +/* ------------------------------------------------------------ */ + +/* NO_PARAM may be used to declare a void function argument; */ +/* for example, */ +/* */ +/* int foo(NO_PARAM) { ... } */ + +/* NO_PARAM may be used in function declarations, in function */ +/* definitions, and in function prototypes. */ + +/* ------------------------------------------------------------ */ + +/* "V_OBJ *" translates into the appropriate void-pointer data */ +/* type; for example, */ +/* */ +/* V_OBJ *malloc (argp1 (u_int)); */ + +/* ------------------------------------------------------------ */ + +/* V_CAST translates into a "void" typecast; for example, */ +/* */ +/* char *strcpy (argp2(char *,char *)); */ +/* V_CAST strcpy (s,t); */ + +/* ------------------------------------------------------------ */ + +/* if "void" is not supported */ + +#ifdef NO_VOID /* "void" type is not supported */ +#define NO_PARAM /* void parameter type (empty) */ +#define V_CAST /* void typecast (no effect) */ +#define V_FUNC /* void function definition */ +#define V_OBJ char /* void pointer object */ +#define V_PROTO extern /* void function declaration */ +#endif /* endif "void not supported" */ + +/* ------------------------------------------------------------ */ + +/* if "void" is supported */ + +#ifndef NO_VOID /* "void" type is supported */ +#ifdef NO_PROTO /* prototypes are not supported */ +#define NO_PARAM /* void parameter type (empty) */ +#else /* prototypes are supported */ +#define NO_PARAM void /* void parameter type */ +#endif /* endif NO_PARAM */ +#endif /* endif "void is supported" */ + +#ifndef NO_VOID /* "void" type is supported */ +#define V_CAST (void) /* void typecast */ +#define V_FUNC void /* void function definition */ +#define V_OBJ void /* void pointer object */ +#define V_PROTO void /* void function declaration */ +#endif /* endif "void is supported" */ + +/* ------------------------------------------------------------ */ +/* ANSI prototype setup */ +/* ------------------------------------------------------------ */ + +/* The following "argp#(...)" macros may be used in ANSI */ +/* function prototypes. "#" should be replaced with the number */ +/* of function arguments; e.g.: */ +/* */ +/* V_OBJ *malloc (argp1(u_int)); */ +/* char *strcpy (argp2(char *,char *)); */ + +/* The "argp#(...)" macros discard their arguments on systems */ +/* which do not support ANSI prototypes. */ + +/* The "ellipse" construct "..." counts as one argument. */ + +/* ------------------------------------------------------------ */ + +#ifdef NO_PROTO +#define argp0() +#define argp1(a) +#define argp2(a,b) +#define argp3(a,b,c) +#define argp4(a,b,c,d) +#define argp5(a,b,c,d,e) +#define argp6(a,b,c,d,e,f) +#define argp7(a,b,c,d,e,f,g) +#define argp8(a,b,c,d,e,f,g,h) +#define argp9(a,b,c,d,e,f,g,h,i) +#else +#define argp0() NO_PARAM +#define argp1(a) a +#define argp2(a,b) a,b +#define argp3(a,b,c) a,b,c +#define argp4(a,b,c,d) a,b,c,d +#define argp5(a,b,c,d,e) a,b,c,d,e +#define argp6(a,b,c,d,e,f) a,b,c,d,e,f +#define argp7(a,b,c,d,e,f,g) a,b,c,d,e,f,g +#define argp8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h +#define argp9(a,b,c,d,e,f,g,h,i) a,b,c,d,e,f,g,h,i +#endif + +/* ------------------------------------------------------------ */ +/* null pointers of various types */ +/* ------------------------------------------------------------ */ + +/* Note: NULLXP is a null function pointer. */ + +#ifndef NULLXP +#define NULL_PTR ((void *) ZERO) +#define NULLCP ((char *) ZERO) +#define NULLFP ((FILE *) ZERO) +#define NULLVP ((V_OBJ *) ZERO) +#define NULLXP ((int (*)()) ZERO) +#endif // Endif NULLXP + +/* ------------------------------------------------------------ */ +/* resolve global variables */ +/* ------------------------------------------------------------ */ + +#ifdef RES_UX3 /* resolve external variables? */ +#define UX3_EXT /* yes */ +#else /* no */ +#define UX3_EXT extern /* variables are externals */ +#endif + +#ifdef VMS /* VMS host */ +#undef UX3_EXT +#ifdef RES_UX3 /* resolve externals? */ +#define UX3_EXT globaldef +#else /* don't resolve externals */ +#define UX3_EXT globalref +#endif /* endif RES_UX3 */ +#endif /* endif VMS */ + +/* ------------------------------------------------------------ */ +/* wrap it up */ +/* ------------------------------------------------------------ */ + +#endif // Endif _X3BASIC_H diff --git a/src/inc/x3mem.h b/src/inc/x3mem.h new file mode 100644 index 0000000..38bfa8d --- /dev/null +++ b/src/inc/x3mem.h @@ -0,0 +1,333 @@ +/* ------------------------------------------------------------ */ +/* file information */ +/* ------------------------------------------------------------ */ + +// Filename: x3mem.h +// Purpose: Memory management +// License: MIT/X. (c) OldCoder (Robert Kiraly) 1987-2021. + +/* ------------------------------------------------------------ */ +/* header file setup */ +/* ------------------------------------------------------------ */ + +#ifndef _X3MEM_H /* skip this file if loaded */ +#define _X3MEM_H 1 /* flag this file */ + +#include +#include + +#include "x3basic.h" +#include "eprintf.h" + +/* ------------------------------------------------------------ */ +/* basic definitions */ +/* ------------------------------------------------------------ */ + +#ifndef x3u_int +#define x3u_int unsigned int +#endif + +#ifndef x3u_long +#define x3u_long unsigned long +#endif + +#ifndef V_OBJ +#define V_OBJ void +#endif + +/* ------------------------------------------------------------ */ +/* X3MEM package - overview */ +/* ------------------------------------------------------------ */ + +/* The X3MEM package includes the public functions listed be- */ +/* low. For more information, see the functions themselves. */ + +/* ------------------------------------------------------------ */ + +/* QLIST support functions: (*) = macro function */ + +/* 1. chk_qm0() -- checks a "qmalloc()" storage pointer */ +/* 2. chk_qma() -- checks an entire QLIST */ +/* (*) 3. chk_qmp() -- generic version of "chk_qm0()" */ +/* 4. qcalloc() -- allocates and clears memory */ +/* 5. qmalloc() -- allocates memory */ +/* 6. qrealloc() -- re-allocates memory */ +/* 7. qfree() -- frees allocated memory */ +/* 8. qflush() -- frees an entire QLIST */ +/* 9. sys_mem() -- returns amount of free system memory */ +/* (*) 10. xqfree() -- generic version of "qfree()" */ + +/* ------------------------------------------------------------ */ + +/* Simplified QLIST interface layer: */ + +/* 11. sqCalloc() -- similar to "calloc()" */ +/* 12. sqChkHeap() -- checks the entire "sq..." heap */ +/* 13. sqChkPtr() -- checks an "sq..." storage pointer */ +/* 14. sqFlush() -- frees all "sq..." storage */ +/* 15. sqFree() -- frees one "sq..." storage block */ +/* 16. sqMalloc() -- similar to "malloc()" */ +/* 17. sqRealloc() -- similar to "realloc()" */ + +/* ------------------------------------------------------------ */ +/* QLIST pointers - explanation */ +/* ------------------------------------------------------------ */ + +/* The X3MEM functions support multiple dynamic-memory allo- */ +/* cation lists. The "qmalloc()" function, for example, */ +/* allocates memory from a specified allocation list, and the */ +/* "qfree()" function returns memory to the associated list. */ + +/* Multiple-allocation lists provide greater control over */ +/* memory allocation; e.g., the caller can free up one list in */ +/* its entirety without disturbing other lists. */ + +/* Additionally, the use of multiple allocation lists can */ +/* reduce the fragmentation problems which occur on virtual- */ +/* memory systems when free lists have grown large. */ + +/* Allocation lists are specified by QLIST pointers; to create */ +/* a new allocation list, the user simply defines a new (empty) */ +/* QLIST structure. */ + +/* If a program does not require multiple allocation lists, the */ +/* predefined general-purpose list "QM_GEN" may be used. */ + +/* ------------------------------------------------------------ */ +/* QMALLOC structure definitions */ +/* ------------------------------------------------------------ */ + +/* alignment data type */ + +#ifdef QMSA /* stand-alone version */ +#ifndef DEF_ALIGN /* set default alignment type */ +#define DEF_ALIGN unsigned int +#endif +#endif /* endif "QMSA" */ + +#ifdef DEF_ALIGN /* is alignment type defined? */ +typedef DEF_ALIGN QM_ALIGN; /* use specified alignment type */ +#else /* use default alignment type */ +typedef long QM_ALIGN; /* "long-integer" alignment */ +#endif /* endif DEF_ALIGN */ + + /* size of an alignment unit */ +#define QMASIZE (sizeof(QM_ALIGN)) + +/* ------------------------------------------------------------ */ + +/* "size" data type */ + +#define QM_SIZE_T unsigned int + +/* ------------------------------------------------------------ */ + +/* QMALLOC memory block header */ + +union qm_header +{ + QM_ALIGN qm_d; /* align the block header */ + + struct /* begin header proper (qm_h) */ + { + union /* begin multi-use portion */ + { /* see explanation below */ + union qm_header *n0_free; + struct qlist *q0_owner; + } + qm_x; /* end multi-use portion */ + + QM_SIZE_T q0_chk; /* consistency-check value */ + QM_SIZE_T q0_size; /* block size */ + } + qm_h; /* end header proper (qm_h) */ +}; + +typedef union qm_header QM_HDR; /* typedef the block header */ + +/* ------------------------------------------------------------ */ + +/* simplify the structure */ + +#define nxt_free qm_h.qm_x.n0_free +#define qa_size qm_h.q0_size +#define qm_chk qm_h.q0_chk +#define qm_owner qm_h.qm_x.q0_owner + +/* ------------------------------------------------------------ */ + +/* QM_HDR structure */ + +/* The "QM_HDR" structure defines a block of dynamic memory. */ +/* The block is aligned on a "QM_ALIGN" boundary, and begins */ +/* with a header of type "QM_HDR". The rest of the block is */ +/* used for storage. */ + +/* "qa_size" is the total size of the memory block (including */ +/* the header itself) in "QM_ALIGN" alignment units (i.e., */ +/* units of QMASIZE bytes). */ + +/* "nxt_free" and "qm_owner" are context-dependent. See the */ +/* discussion of the QLIST structure below for additional */ +/* information. */ + +/* "qm_chk" is used internally for consistency checking. */ + +/* ------------------------------------------------------------ */ + +/* QLIST structure */ + +struct qlist +{ + QM_HDR *qm_free; /* QLIST free list */ + QM_HDR *qm_sysmem; /* QLIST system-memory list */ + QM_SIZE_T qm_block; /* allocation blocking factor */ + char qm_nofree; /* non-freeable flag */ +}; + +typedef struct qlist QLIST; /* typedef the list header */ + /* null structure pointer */ +#define NULL_QLS ((QLIST *) ZERO) + +/* ------------------------------------------------------------ */ + +/* QLIST free-list */ + +/* The "qm_free" field for a QLIST points to a list of free */ +/* memory blocks associated with the QLIST. Each free block */ +/* begins with a "QM_HDR" block header. The free blocks are */ +/* linked together by the "nxt_free" field in the "QM_HDR" */ +/* header. Blocks are allocated from this list by "qmalloc()" */ +/* and freed onto the list by "qfree()". */ + +/* When "qmalloc()" allocates a block from a free-list, it */ +/* points the "qm_owner" field in the header to the QLIST from */ +/* which the block was obtained. "qfree()" uses this field */ +/* subsequently when the block is freed. */ + +/* The memory blocks in the free list are carved out of a */ +/* lower-level system memory chain, which is discussed in the */ +/* next section. */ + +/* ------------------------------------------------------------ */ + +/* QLIST system-memory list */ + +/* The "qm_sysmem" field for a QLIST points to a list of low- */ +/* level "system memory" blocks associated with the QLIST. */ +/* Each system memory block begins with a "QM_HDR" block head- */ +/* er. The system memory blocks are linked together by the */ +/* "nxt_free" field in the "QM_HDR" header. */ + +/* This linked list contains all of the dynamic storage */ +/* currently associated with a QLIST (on the "qm_free" free */ +/* list or not). The blocks in this list are obtained from the */ +/* operating system. */ + +/* "qmalloc()" carves the storage portion of each system memory */ +/* block up into sub-blocks, writes "QM_HDR" headers onto the */ +/* sub-blocks, and uses these secondary headers to build */ +/* higher-level (qm_free) allocation lists. */ + +/* ------------------------------------------------------------ */ + +/* allocation blocking factor */ + +/* The "malloc"-based version of "qmalloc()" uses the standard */ +/* library routine "malloc()" to allocate dynamic memory at the */ +/* system level. */ + +/* The "stand-alone" version of "qmalloc()" uses an internal */ +/* utility routine to allocate dynamic memory at the system */ +/* level. */ + +/* The "qm_block" field in a QLIST header specifies the minimum */ +/* amount of memory (in bytes) to be requested for the QLIST */ +/* per system-level memory allocation call. */ + +/* If the "qm_block" field is not set, a reasonable default */ +/* value is used. */ + +/* If the host system has virtual memory, setting "qm_block" */ +/* as follows may improve performance: */ +/* */ +/* qm_block <- system memory page size minus total size of all */ +/* system-level storage headers. */ + +/* ------------------------------------------------------------ */ +/* misc. global variables */ +/* ------------------------------------------------------------ */ + +/* "QM_GEN" is intended for use as a general-purpose QLIST. */ + +/* Note: Since "QM_GEN[]" is an array, "QM_GEN" serves both as */ +/* a QLIST pointer and as the QLIST entry itself. */ + +UX3_EXT QLIST QM_GEN [ONE]; /* general-purpose QLIST */ + +/* ------------------------------------------------------------ */ + +/* "qm_retsys" is a flag used by the "qflush()" function. See */ +/* "qflush()" for additional information. */ + +UX3_EXT char qm_retsys; /* "qflush()" flag */ + +/* ------------------------------------------------------------ */ +/* macro functions */ +/* ------------------------------------------------------------ */ + +/* "chk_qmp(xp)" checks the pointer "xp" and terminates the */ +/* caller with an error message if "xp" is not a valid */ +/* "qmalloc()" storage pointer. "xp" may be a pointer of any */ +/* type; "chk_qmp()" typecasts the pointer appropriately. */ + +/* Note: A valid storage pointer becomes invalid if the */ +/* associated storage is freed. */ + +/* "chk_qmp()" is a macro interface to the function "chk_ */ +/* qm0()". See the description of "chk_qm0()" for additional */ +/* information. */ + +/* ------------------------------------------------------------ */ + +#define chk_qmp(xp) chk_qm0 ((V_OBJ *) (xp)) + +/* ------------------------------------------------------------ */ + +/* The macro function "xqfree()" is equivalent to the non-macro */ +/* function "qfree()", with the distinction that "xqfree()" */ +/* typecasts its argument appropriately. See the description */ +/* of "qfree()" for additional information. */ + +/* ------------------------------------------------------------ */ + +#define xqfree(p) qfree ((V_OBJ *) (p)) + +/* ------------------------------------------------------------ */ +/* X3MEM function prototypes */ +/* ------------------------------------------------------------ */ + +V_PROTO chk_qm0 (argp1 (V_OBJ *)); +V_PROTO chk_qma (argp1 (QLIST *)); +V_OBJ *qcalloc (argp3 (QLIST *,x3u_int,x3u_int)); +V_PROTO qflush (argp1 (QLIST *)); +V_PROTO qfree (argp1 (V_OBJ *)); +V_OBJ *qmalloc (argp2 (QLIST *,int)); +V_OBJ *qrealloc (argp2 (V_OBJ *,int)); +long sys_mem (argp0 ()); + +/* ------------------------------------------------------------ */ + +V_OBJ *sqCalloc (argp2 (x3u_int, x3u_int)); +V_PROTO sqChkHeap (argp0 ()); +V_PROTO sqChkPtr (argp2 (V_OBJ *, char *)); +V_PROTO sqFlush (argp0 ()); +V_PROTO sqFree (argp1 (V_OBJ *)); +V_OBJ *sqMalloc (argp1 (x3u_int)); +V_OBJ *sqRealloc (argp2 (V_OBJ *, x3u_int)); + +/* ------------------------------------------------------------ */ +/* wrap it up */ +/* ------------------------------------------------------------ */ + +#endif /* endif _X3MEM_H */ diff --git a/src/inset.c b/src/inset.c old mode 100755 new mode 100644 index 5db67f1..bf1d758 --- a/src/inset.c +++ b/src/inset.c @@ -8,6 +8,7 @@ #include "inc/deps.h" #include "inc/inset.h" #include "inc/lexer.h" +#include "inc/tar.h" #include "inc/vars.h" #include "inc/util.h" @@ -75,6 +76,7 @@ char *parse_bq(char *string) strcat (varbuffer, "\n"); variable_pointer = process_line(varbuffer); + tar_free_pool(); if(variable_pointer == NULL) syn_error("ss:error:backquoted function must return string!"); diff --git a/src/lexer.c b/src/lexer.c old mode 100755 new mode 100644 index 9eddf32..f1f8be4 --- a/src/lexer.c +++ b/src/lexer.c @@ -346,7 +346,6 @@ char *process_line(char *line) return retbuf; } - /* COMPRESSION AND DECOMPRESSION */ else if(strncmp("decompress",tok_srch,10) == 0) { @@ -354,6 +353,7 @@ char *process_line(char *line) struct tar_t *archive = NULL; int fd; + tar_free_pool(); tok_srch = strtok(NULL, "\""); if(tok_srch == NULL) { @@ -430,6 +430,7 @@ char *process_line(char *line) struct tar_t *archive = NULL; int fd; + tar_free_pool(); tok_srch = strtok(NULL, "\""); if(tok_srch == NULL) { diff --git a/src/main.c b/src/main.c old mode 100755 new mode 100644 index f35619a..18b605b --- a/src/main.c +++ b/src/main.c @@ -11,6 +11,7 @@ #include "inc/util.h" #include "inc/lexer.h" #include "inc/pipe.h" +#include "inc/tar.h" #include "inc/vars.h" int main(int argc, char **argv) @@ -62,6 +63,7 @@ int main(int argc, char **argv) pipechk = get_cmd_count(); return_dat = process_line(spipe[0].command); + tar_free_pool(); // Blank line, getting up outta here. if(return_dat == NULL) continue; @@ -74,6 +76,8 @@ int main(int argc, char **argv) set_var(varc, "PIPE", return_dat); // Process functions based on previous pipe return return_dat = process_line(spipe[ii].command); + tar_free_pool(); + // set PIPE var back to NULL after use, keep the struct clean set_var(varc, "\0", "\0"); // Check to see if there's anything to even display diff --git a/src/math.c b/src/math.c old mode 100755 new mode 100644 diff --git a/src/md5.c b/src/md5.c old mode 100755 new mode 100644 diff --git a/src/network.c b/src/network.c old mode 100755 new mode 100644 diff --git a/src/pipe.c b/src/pipe.c old mode 100755 new mode 100644 diff --git a/src/search.c b/src/search.c old mode 100755 new mode 100644 diff --git a/src/tar.c b/src/tar.c old mode 100755 new mode 100644 index 2a7361a..ae7243d --- a/src/tar.c +++ b/src/tar.c @@ -27,12 +27,16 @@ static int iszeroed(char * buf, size_t size); // make directory recursively static int recursive_mkdir(const char * dir, const unsigned int mode); -int tar_read(const int fd, struct tar_t ** archive, const char verbosity){ - if (fd < 0){ +int tar_read (const int fd, + struct tar_t **archive, const char verbosity) +{ + if (fd < 0) + { ERROR("Bad file descriptor"); } - if (!archive || *archive){ + if (!archive || *archive) + { ERROR("Bad archive"); } @@ -42,9 +46,11 @@ int tar_read(const int fd, struct tar_t ** archive, const char verbosity){ struct tar_t ** tar = archive; char update = 1; - for(count = 0; ; count++){ - *tar = malloc(sizeof(struct tar_t)); - if (update && (read_size(fd, (*tar) -> block, 512) != 512)){ + for(count = 0; ; count++) + { + *tar = qmalloc (QM_TAR, sizeof (struct tar_t)); + if (update && (read_size(fd, (*tar) -> block, 512) != 512)) + { V_PRINT(stderr, "Error: Bad read. Stopping"); tar_free(*tar); *tar = NULL; @@ -53,8 +59,10 @@ int tar_read(const int fd, struct tar_t ** archive, const char verbosity){ update = 1; // if current block is all zeros - if (iszeroed((*tar) -> block, 512)){ - if (read_size(fd, (*tar) -> block, 512) != 512){ + if (iszeroed((*tar) -> block, 512)) + { + if (read_size(fd, (*tar) -> block, 512) != 512) + { V_PRINT(stderr, "Error: Bad read. Stopping"); tar_free(*tar); *tar = NULL; @@ -62,12 +70,14 @@ int tar_read(const int fd, struct tar_t ** archive, const char verbosity){ } // check if next block is all zeros as well - if (iszeroed((*tar) -> block, 512)){ + if (iszeroed((*tar) -> block, 512)) + { tar_free(*tar); *tar = NULL; // skip to end of record - if (lseek(fd, RECORDSIZE - (offset % RECORDSIZE), SEEK_CUR) == (off_t) (-1)){ + if (lseek(fd, RECORDSIZE - (offset % RECORDSIZE), SEEK_CUR) == (off_t) (-1)) + { RC_ERROR("Unable to seek file: %s", strerror(rc)); } @@ -82,13 +92,17 @@ int tar_read(const int fd, struct tar_t ** archive, const char verbosity){ // skip over data and unfilled block unsigned int jump = oct2uint((*tar) -> size, 11); - if (jump % 512){ + + if (jump % 512) + { jump += 512 - (jump % 512); } // move file descriptor offset += 512 + jump; - if (lseek(fd, jump, SEEK_CUR) == (off_t) (-1)){ + + if (lseek(fd, jump, SEEK_CUR) == (off_t) (-1)) + { RC_ERROR("Unable to seek file: %s", strerror(rc)); } @@ -99,12 +113,19 @@ int tar_read(const int fd, struct tar_t ** archive, const char verbosity){ return count; } -int tar_write(const int fd, struct tar_t ** archive, const size_t filecount, const char * files[], const char verbosity){ - if (fd < 0){ +int tar_write (const int fd, + struct tar_t ** archive, + const size_t filecount, + const char * files[], + const char verbosity) +{ + if (fd < 0) + { ERROR("Bad file descriptor"); } - if (!archive){ + if (!archive) + { ERROR("Bad archive"); } @@ -113,64 +134,101 @@ int tar_write(const int fd, struct tar_t ** archive, const size_t filecount, con // if there is old data struct tar_t ** tar = archive; - if (*tar){ + + if (*tar) + { // skip to last entry - while (*tar && (*tar) -> next){ + while (*tar && (*tar) -> next) + { tar = &((*tar) -> next); } // get offset past final entry unsigned int jump = 512 + oct2uint((*tar) -> size, 11); - if (jump % 512){ + if (jump % 512) + { jump += 512 - (jump % 512); } // move file descriptor offset = (*tar) -> begin + jump; - if (lseek(fd, offset, SEEK_SET) == (off_t) (-1)){ + if (lseek(fd, offset, SEEK_SET) == (off_t) (-1)) + { RC_ERROR("Unable to seek file: %s", strerror(rc)); } tar = &((*tar) -> next); } // write entries first - if (write_entries(fd, tar, archive, filecount, files, &offset, verbosity) < 0){ + if (write_entries (fd, tar, archive, + filecount, files, &offset, verbosity) < 0) + { WRITE_ERROR("Failed to write entries"); } // write ending data - if (write_end_data(fd, offset, verbosity) < 0){ + if (write_end_data(fd, offset, verbosity) < 0) + { ERROR("Failed to write end data"); } // clear original names from data tar = archive; - while (*tar){ + + while (*tar) + { memset((*tar) -> name, 0, 100); tar = &((*tar) -> next); } + return offset; } -void tar_free(struct tar_t * archive){ - while (archive){ +static void *woof (void *bark) +{ + return (bark); +} + +void tar_free (struct tar_t *archive) +{ + // Silence "gcc" + (void) woof ((void *) archive); + +#ifdef NOTDEF + while (archive) + { struct tar_t * next = archive -> next; free(archive); archive = next; } +#endif } -int tar_ls(FILE * f, struct tar_t * archive, const size_t filecount, const char * files[], const char verbosity){ - if (!verbosity){ +void tar_free_pool (void) +{ + qflush (QM_TAR); +} + +int tar_ls (FILE * f, + struct tar_t * archive, + const size_t filecount, + const char * files[], + const char verbosity) +{ + if (!verbosity) + { return 0; } - if (filecount && !files){ + if (filecount && !files) + { ERROR("Non-zero file count provided, but file list is NULL"); } - while (archive){ - if (ls_entry(f, archive, filecount, files, verbosity) < 0){ + while (archive) + { + if (ls_entry(f, archive, filecount, files, verbosity) < 0) + { return -1; } archive = archive -> next; @@ -179,23 +237,35 @@ int tar_ls(FILE * f, struct tar_t * archive, const size_t filecount, const char return 0; } -int tar_extract(const int fd, struct tar_t * archive, const size_t filecount, const char * files[], const char verbosity){ +int tar_extract (const int fd, + struct tar_t * archive, + const size_t filecount, + const char * files[], + const char verbosity) +{ int ret = 0; // extract entries with given names - if (filecount){ - if (!files){ + if (filecount) + { + if (!files) + { ERROR("Received non-zero file count but got NULL file list"); } - while (archive){ - for(size_t i = 0; i < filecount; i++){ - if (!strncmp(archive -> name, files[i], MAX(strlen(archive -> name), strlen(files[i])))){ - if (lseek(fd, archive -> begin, SEEK_SET) == (off_t) (-1)){ + while (archive) + { + for(size_t i = 0; i < filecount; i++) + { + if (!strncmp(archive -> name, files[i], MAX(strlen(archive -> name), strlen(files[i])))) + { + if (lseek(fd, archive -> begin, SEEK_SET) == (off_t) (-1)) + { RC_ERROR("Unable to seek file: %s", strerror(rc)); } - if (extract_entry(fd, archive, verbosity) < 0){ + if (extract_entry(fd, archive, verbosity) < 0) + { ret = -1; } break; @@ -205,15 +275,19 @@ int tar_extract(const int fd, struct tar_t * archive, const size_t filecount, co } } // extract all - else{ + else + { // move offset to beginning - if (lseek(fd, 0, SEEK_SET) == (off_t) (-1)){ + if (lseek(fd, 0, SEEK_SET) == (off_t) (-1)) + { RC_ERROR("Unable to seek file: %s", strerror(rc)); } // extract each entry - while (archive){ - if (extract_entry(fd, archive, verbosity) < 0){ + while (archive) + { + if (extract_entry(fd, archive, verbosity) < 0) + { ret = -1; } archive = archive -> next; @@ -223,17 +297,24 @@ int tar_extract(const int fd, struct tar_t * archive, const size_t filecount, co return ret; } -int tar_update(const int fd, struct tar_t ** archive, const size_t filecount, const char * files[], const char verbosity){ - if (!filecount){ +int tar_update (const int fd, + struct tar_t ** archive, + const size_t filecount, + const char * files[], + const char verbosity) +{ + if (!filecount) + { return 0; } - if (filecount && !files){ + if (filecount && !files) + { ERROR("Non-zero file count provided, but file list is NULL"); } // buffer for subset of files that need to be updated - char ** newer = calloc(filecount, sizeof(char *)); + char ** newer = qcalloc (QM_TAR, filecount, sizeof(char *)); struct stat st; int count = 0; @@ -241,79 +322,97 @@ int tar_update(const int fd, struct tar_t ** archive, const size_t filecount, co // check each source to see if it was updated struct tar_t * tar = *archive; - for(int i = 0; i < (int)filecount; i++){ + for(int i = 0; i < (int)filecount; i++) + { // make sure original file exists - if (lstat(files[i], &st)){ + if (lstat(files[i], &st)) + { all = 0; RC_ERROR("Could not stat %s: %s", files[i], strerror(rc)); } // find the file in the archive struct tar_t * old = exists(tar, files[i], 1); - newer[count] = calloc(strlen(files[i]) + 1, sizeof(char)); + newer[count] = qcalloc (QM_TAR, + strlen (files [i]) + 1, sizeof (char)); // if there is an older version, check its timestamp - if (old){ - if (st.st_mtime > oct2uint(old -> mtime, 11)){ + if (old) + { + if (st.st_mtime > oct2uint(old -> mtime, 11)) + { strncpy(newer[count++], files[i], strlen(files[i])); V_PRINT(stdout, "%s", files[i]); } } // if there is no older version, just add it - else{ + else + { strncpy(newer[count++], files[i], strlen(files[i])); V_PRINT(stdout, "%s", files[i]); } } // update listed files only - if (tar_write(fd, archive, count, (const char **) newer, verbosity) < 0){ + if (tar_write(fd, archive, count, (const char **) newer, verbosity) < 0) + { ERROR("Unable to update archive"); } // cleanup - for(int i = 0; i < count; i++){ - free(newer[i]); + for(int i = 0; i < count; i++) + { + // free(newer[i]); } - free(newer); + // free(newer); return all?0:-1; } -int tar_remove(const int fd, struct tar_t ** archive, const size_t filecount, const char * files[], const char verbosity){ - if (fd < 0){ +int tar_remove (const int fd, struct tar_t ** archive, const size_t filecount, const char * files[], const char verbosity) +{ + if (fd < 0) + { return -1; } // archive has to exist - if (!archive || !*archive){ + if (!archive || !*archive) + { ERROR("Got bad archive"); } - if (filecount && !files){ + if (filecount && !files) + { ERROR("Non-zero file count provided, but file list is NULL"); } - if (!filecount){ + if (!filecount) + { V_PRINT(stderr, "No entries specified"); return 0; } // get file permissions struct stat st; - if (fstat(fd, &st)){ + if (fstat(fd, &st)) + { RC_ERROR("Unable to stat archive: %s", strerror(rc)); } // reset offset of original file - if (lseek(fd, 0, SEEK_SET) == (off_t) (-1)){ + if (lseek(fd, 0, SEEK_SET) == (off_t) (-1)) + { RC_ERROR("Unable to seek file: %s", strerror(rc)); } // find first file to be removed that does not exist int ret = 0; - for(int i = 0; i < (int)filecount; i++){ - if (!exists(*archive, files[i], 0)){ + + for(int i = 0; i < (int)filecount; i++) + { + if (!exists(*archive, files[i], 0)) + { ERROR("'%s' not found in archive", files[i]); } } @@ -322,46 +421,58 @@ int tar_remove(const int fd, struct tar_t ** archive, const size_t filecount, co unsigned int write_offset = 0; struct tar_t * prev = NULL; struct tar_t * curr = *archive; - while(curr){ + + while(curr) + { // get original size int total = 512; - if ((curr -> type == REGULAR) || (curr -> type == NORMAL) || (curr -> type == CONTIGUOUS)){ + if ((curr -> type == REGULAR) || (curr -> type == NORMAL) || (curr -> type == CONTIGUOUS)) + { total += oct2uint(curr -> size, 11); - if (total % 512){ + if (total % 512) + { total += 512 - (total % 512); } } const int match = check_match(curr, filecount, files); - if (match < 0){ + if (match < 0) + { ERROR("Match failed"); } - else if (!match){ + else if (!match) + { // if the old data is not in the right place, move it - if (write_offset < read_offset){ + if (write_offset < read_offset) + { int got = 0; - while (got < total){ + while (got < total) + { // go to old data - if (lseek(fd, read_offset, SEEK_SET) == (off_t) (-1)){ + if (lseek(fd, read_offset, SEEK_SET) == (off_t) (-1)) + { RC_ERROR("Cannot seek: %s", strerror(rc)); } char buf[512]; // copy chunk out - if (read_size(fd, buf, 512) != 512){// guarenteed 512 octets + if (read_size(fd, buf, 512) != 512) + {// guaranteed 512 octets ERROR("Read error"); } // go to new position - if (lseek(fd, write_offset, SEEK_SET) == (off_t) (-1)){ + if (lseek(fd, write_offset, SEEK_SET) == (off_t) (-1)) + { RC_ERROR("Cannot seek: %s", strerror(rc)); } // write data in - if (write_size(fd, buf, 512) != 512){ + if (write_size(fd, buf, 512) != 512) + { RC_ERROR("Write error: %s", strerror(rc)); } @@ -371,35 +482,43 @@ int tar_remove(const int fd, struct tar_t ** archive, const size_t filecount, co write_offset += 512; } } - else{ + else + { read_offset += total; write_offset += total; // skip past data - if (lseek(fd, read_offset, SEEK_SET) == (off_t) (-1)){ + if (lseek(fd, read_offset, SEEK_SET) == (off_t) (-1)) + { RC_ERROR("Cannot seek: %s", strerror(rc)); } } prev = curr; curr = curr -> next; } - else{// if name matches, skip the data - struct tar_t * tmp = curr; - if (!prev){ + else + {// if name matches, skip the data + // struct tar_t * tmp = curr; + if (!prev) + { *archive = curr -> next; - if (*archive){ + if (*archive) + { (*archive) -> begin = 0; } } - else{ + else + { prev -> next = curr -> next; - if (prev -> next){ + if (prev -> next) + { prev -> next -> begin = curr -> begin; } } + curr = curr -> next; - free(tmp); + // free(tmp); // next read starts after current entry read_offset += total; @@ -407,40 +526,50 @@ int tar_remove(const int fd, struct tar_t ** archive, const size_t filecount, co } // resize file - if (ftruncate(fd, write_offset) < 0){ + if (ftruncate(fd, write_offset) < 0) + { RC_ERROR("Could not truncate file: %s", strerror(rc)); } // add end data - if (write_end_data(fd, write_offset, verbosity) < 0){ + if (write_end_data(fd, write_offset, verbosity) < 0) + { V_PRINT(stderr, "Error: Could not close file"); } return ret; } -int tar_diff(FILE * f, struct tar_t * archive, const char verbosity){ +int tar_diff (FILE * f, struct tar_t * archive, const char verbosity) +{ struct stat st; - while (archive){ + while (archive) + { V_PRINT(f, "%s", archive -> name); // if not found, print error - if (lstat(archive -> name, &st)){ + if (lstat(archive -> name, &st)) + { int rc = errno; fprintf(f, "Could not "); - if (archive -> type == SYMLINK){ + if (archive -> type == SYMLINK) + { fprintf(f, "readlink"); } - else{ + else + { fprintf(f, "stat"); } fprintf(f, " %s: %s", archive -> name, strerror(rc)); } - else{ - if (st.st_mtime != oct2uint(archive -> mtime, 11)){ + else + { + if (st.st_mtime != oct2uint(archive -> mtime, 11)) + { fprintf(f, "%s: Mod time differs", archive -> name); } - if (st.st_size != oct2uint(archive -> size, 11)){ + if (st.st_size != oct2uint(archive -> size, 11)) + { fprintf(f, "%s: Mod time differs", archive -> name); } } @@ -450,7 +579,8 @@ int tar_diff(FILE * f, struct tar_t * archive, const char verbosity){ return 0; } -int print_entry_metadata(FILE * f, struct tar_t * entry){ +int print_entry_metadata(FILE * f, struct tar_t * entry) +{ if (!entry){ return -1; } @@ -740,7 +870,7 @@ int extract_entry(const int fd, struct tar_t * entry, const char verbosity){ ERROR("Attempted to extract entry with empty name"); } - char * path = calloc(len + 1, sizeof(char)); + char * path = qcalloc (QM_TAR, len + 1, sizeof(char)); strncpy(path, entry -> name, len); // remove file from path @@ -749,10 +879,10 @@ int extract_entry(const int fd, struct tar_t * entry, const char verbosity){ if (recursive_mkdir(path, DEFAULT_DIR_MODE) < 0){ V_PRINT(stderr, "Could not make directory %s", path); - free(path); + // free(path); return -1; } - free(path); + // free(path); // create file const unsigned int size = oct2uint(entry -> size, 11); @@ -851,7 +981,7 @@ int write_entries(const int fd, struct tar_t ** archive, struct tar_t ** head, c if ((*tar) -> type == DIRECTORY){ // save parent directory name (source will change) const size_t len = strlen((*tar) -> name); - char * parent = calloc(len + 1, sizeof(char)); + char * parent = qcalloc (QM_TAR, len + 1, sizeof(char)); strncpy(parent, (*tar) -> name, len); // add a '/' character to the end @@ -879,7 +1009,8 @@ int write_entries(const int fd, struct tar_t ** archive, struct tar_t ** head, c // if not special directories . and .. const size_t sublen = strlen(dir -> d_name); if (strncmp(dir -> d_name, ".", sublen) && strncmp(dir -> d_name, "..", sublen)){ - char * path = calloc(len + sublen + 2, sizeof(char)); + char * path = qcalloc (QM_TAR, + len + sublen + 2, sizeof(char)); sprintf(path, "%s/%s", parent, dir -> d_name); // recursively write each subdirectory @@ -892,12 +1023,12 @@ int write_entries(const int fd, struct tar_t ** archive, struct tar_t ** head, c tar = &((*tar) -> next); } - free(path); + // free(path); } } closedir(d); - free(parent); + // free(parent); tar = &((*tar) -> next); } @@ -1064,7 +1195,7 @@ int recursive_mkdir(const char * dir, const unsigned int mode){ return 0; } - char * path = calloc(len + 1, sizeof(char)); + char * path = qcalloc (QM_TAR, len + 1, sizeof(char)); strncpy(path, dir, len); // remove last '/' @@ -1089,6 +1220,6 @@ int recursive_mkdir(const char * dir, const unsigned int mode){ EXIST_ERROR("Could not create directory %s: %s", path, strerror(rc)); } - free(path); + // free(path); return 0; } diff --git a/src/util.c b/src/util.c old mode 100755 new mode 100644 diff --git a/src/vars.c b/src/vars.c old mode 100755 new mode 100644 diff --git a/src/x3basic.c b/src/x3basic.c new file mode 100644 index 0000000..781bdf2 --- /dev/null +++ b/src/x3basic.c @@ -0,0 +1,18 @@ +/* ------------------------------------------------------------ */ +/* file information */ +/* ------------------------------------------------------------ */ + +// Filename: x3basic.c +// Purpose: Resolve UX3 global variables +// License: MIT/X. (c) OldCoder (Robert Kiraly) 1987-2021. + +/* ------------------------------------------------------------ */ +/* header files */ +/* ------------------------------------------------------------ */ + +#define RES_UX3 1 /* resolve UX3 global variables */ + +#include "inc/x3basic.h" +#include "inc/eprintf.h" +#include "inc/x3mem.h" +#include "inc/tar.h" diff --git a/src/x3mem.c b/src/x3mem.c new file mode 100644 index 0000000..5adfecb --- /dev/null +++ b/src/x3mem.c @@ -0,0 +1,1395 @@ +/* ------------------------------------------------------------ */ +/* file information */ +/* ------------------------------------------------------------ */ + +// Filename: x3mem.c +// Purpose: Memory management +// License: MIT/X. (c) OldCoder (Robert Kiraly) 1987-2021. + +/* ------------------------------------------------------------ */ +/* header files */ +/* ------------------------------------------------------------ */ + +#include +#include + +#include "inc/x3mem.h" /* main X3MEM header file */ + +/* ------------------------------------------------------------ */ +/* miscellaneous notes */ +/* ------------------------------------------------------------ */ + +/* 1. X3MEM is aka QMALLOC. */ + +/* 2. Programs should not pass QMALLOC storage pointers to */ +/* MALLOC functions. */ + +/* 3. Programs should not pass MALLOC storage pointers to */ +/* QMALLOC functions. */ + +/* 4. The following actions may slow programs down: */ +/* */ +/* (a) frequent calls to "chk_qma()" or "qflush()" */ +/* (b) frequent calls to the lower-level MALLOC functions */ +/* (c) frequent requests for blocks larger than "qm_block" */ + +/* ------------------------------------------------------------ */ +/* miscellaneous definitions */ +/* ------------------------------------------------------------ */ + +/* convert to alignment units */ + +/* If "x" is a size in bytes, "ALIGNSIZ(x)" returns the minimum */ +/* number of "QM_ALIGN" alignment units which will hold the */ +/* specified number of bytes. */ + +#define ALIGNSIZ(x) ((((x3u_long) (x)) + QMASIZE - ONE) / QMASIZE) + +/* ------------------------------------------------------------ */ + +/* QMALLOC block header size */ + + /* size in bytes */ +#define HDR_BSIZE (sizeof(QM_HDR)) + /* size in alignment units */ +#define HDR_ASIZE ALIGNSIZ(HDR_BSIZE) + +/* ------------------------------------------------------------ */ + +/* null header pointer */ + +#define NULLQH ((QM_HDR *) ZERO) + +/* ------------------------------------------------------------ */ + +/* memory allocation slack */ + +/* When "qmalloc()" allocates a "qm_free" free block which is */ +/* longer than it needs, the unused portion of the block is */ +/* broken off if more than "QM_SLACK" alignment units of usable */ +/* storage will be freed up this way. */ + +#define QM_SLACK (8 / QMASIZE) + +/* ------------------------------------------------------------ */ + +/* return alignment pointer */ + +/* "ALIGN_P(x)" typecasts the pointer (x) to the alignment */ +/* pointer type "QM_ALIGN *". The pointer value should be */ +/* suitably aligned before the conversion is done. */ + +#define ALIGN_P(x) ((QM_ALIGN *) (x)) + +/* ------------------------------------------------------------ */ + +/* address conversion */ + +/* The "addr(x)" macro is used to work around a problem with */ +/* the Intel 80X86 system architecture. */ + +#ifdef M_I86 /* Microsoft C */ +#define addr(x) ((x3u_long) ((char far *) (x))) +#else /* other systems */ +#define addr(x) (x) +#endif /* endif MSC */ + +/* ------------------------------------------------------------ */ + +/* return block size */ + +/* If "x" is a pointer to a "QM_HDR" memory block header, */ +/* "QM_ASIZE(x)" returns the size of the block in "QM_ALIGN" */ +/* units as an unsigned long value. The block size includes */ +/* the size of the header itself. */ + +#define QM_ASIZE(x) ((x3u_long) ((x)->qa_size)) + +/* ------------------------------------------------------------ */ + +/* return next memory position */ + +/* If "x" is a pointer to a "QM_HDR" memory block header, */ +/* "NXT_POS(x)" returns a "QM_ALIGN" pointer to the first */ +/* "QM_ALIGN" memory position after the specified memory */ +/* block. */ + +#define NXT_POS(x) (ALIGN_P(x) + (x)->qa_size) + +/* ------------------------------------------------------------ */ + +/* "qrealloc()" blocking factor */ + +/* To reduce fragmentation, "qrealloc()" reallocates memory in */ +/* blocks of "QM_RAFF" bytes. "QM_RAFF" should be a power of */ +/* two between 2^3 (8) and 2^11 (2048). */ + +#define QM_RAFF 256 + +/* ------------------------------------------------------------ */ +/* consistency-check definitions */ +/* ------------------------------------------------------------ */ + +/* consistency-check codes */ + +#define QM_FREE ((QM_SIZE_T) 0x12345678L) +#define QM_INUSE ((QM_SIZE_T) 0x87654321L) + +/* "QM_HDR" memory block headers normally fall into the follow- */ +/* ing four categories: */ +/* */ +/* (a) headers which are in a QLIST "qm_free" list */ +/* (b) headers which are in the global "sys_free" list */ +/* (c) headers allocated to higher-level users */ +/* (d) headers which are in a QLIST "qm_sysmem" list */ + +/* If a "QM_HDR" block header falls into the first two cate- */ +/* gories here, "qm_chk" contains a consistency check value */ +/* equal to "qa_size" exclusive-or'd with the magic number */ +/* "QM_FREE". */ + +/* If a "QM_HDR" block header falls into the second two cate- */ +/* gories here, "qm_chk" contains a consistency check value */ +/* equal to "qa_size" exclusive-or'd with the magic number */ +/* "QM_INUSE". */ + +/* ------------------------------------------------------------ */ + +/* consistency-check macros */ + +/* These six macros each take a single "QM_HDR" pointer as a */ +/* parameter. */ + +/* "qm_relflg(q)" and "qm_useflg(q)" return the calculated */ +/* values of the "free" and "used" consistency flags, respect- */ +/* ively. */ + +/* "qm_setrel(q)" and "qm_setuse(q)" save the correct values of */ +/* the "free" and "used" consistency flags, respectively. */ + +/* "qm_chkrel(q)" and "qm_chkuse(q)" check the stored values of */ +/* the "free" and "used" consistency flags, respectively. */ + +/* ------------------------------------------------------------ */ + +#define qm_relflg(q) ((q)->qa_size ^ QM_FREE) +#define qm_useflg(q) ((q)->qa_size ^ QM_INUSE) + +#define qm_setrel(q) ((q)->qm_chk = qm_relflg(q)) +#define qm_setuse(q) ((q)->qm_chk = qm_useflg(q)) + +#define qm_chkrel(q) if ((q)->qm_chk != qm_relflg(q)) qm_ce() +#define qm_chkuse(q) if ((q)->qm_chk != qm_useflg(q)) qm_ce() + +/* ------------------------------------------------------------ */ +/* allocation constraints */ +/* ------------------------------------------------------------ */ + +/* default "qm_block" factor */ + +/* The constant "QM_DEFBLK" specifies the default value for */ +/* "qm_block". See the description of "qm_block" in "x3mem.h" */ +/* for additional information. */ + +/* ------------------------------------------------------------ */ + +#ifdef M_I86 /* Microsoft C */ +#define QM_DEFBLK 512 +#endif /* endif MSC */ + +#ifdef QMSA /* stand-alone version */ +#define QM_DEFBLK 512 +#endif /* endif "QMSA" */ + +#ifdef VMS /* VMS host */ +#define QM_DEFBLK 8184 +#endif /* endif VMS */ + +#ifndef QM_DEFBLK /* set default value? */ +#define QM_DEFBLK 2036 /* yes */ +#endif /* endif default value */ + +/* ------------------------------------------------------------ */ + +/* If "x" is the "qm_block" value for a given QLIST, "q_more()" */ +/* will clip its "n_a" parameter to a minimum of "QM_GETMIN(x)" */ +/* alignment units when extending the QLIST. */ + +/* "QM_GETMIN(x)" is chosen so that "q_more()" will request a */ +/* minimum of at least "x" bytes when calling "malloc()". (If */ +/* "x" is a multiple of QMASIZE, "q_more()" will request a min- */ +/* imum of exactly "x" bytes.) */ + +/* ------------------------------------------------------------ */ + +#define QM_GETMIN(x) (ALIGNSIZ(x) - HDR_ASIZE) + +/* ------------------------------------------------------------ */ +/* public variables */ +/* ------------------------------------------------------------ */ + +#ifdef QMSA /* stand-alone version */ +char *mempool; /* pointer to/into storage pool */ +long poolsize; /* storage pool size in bytes */ +#endif /* endif "QMSA" */ + +/* ------------------------------------------------------------ */ +/* module-private variables */ +/* ------------------------------------------------------------ */ + +MODPRIV char *qm_ce_msg; /* used by "qm_ce()" */ + /* freed system memory blocks */ +MODPRIV QM_HDR *sys_free = NULLQH; + +MODPRIV QLIST QM_SQL [ONE]; /* used by "sq..." functions */ + +/* ------------------------------------------------------------ */ +/* functions */ +/* ------------------------------------------------------------ */ + +/* Function: V_OBJ *qm_sbrk(ux) */ +/* Summary: Lowest-level "stand-alone" allocation routine. */ + +/* ------------------------------------------------------------ */ + +/* x3u_int ux; - Number of bytes to allocate (0+). */ + +/* ------------------------------------------------------------ */ + +/* "qm_sbrk()" is the lowest-level allocation routine used by */ +/* the "stand-alone" version of the QMALLOC package. */ + +/* "qm_sbrk()" allocates a block of the specified size and re- */ +/* turns the associated block pointer. If the block cannot be */ +/* allocated, "qm_sbrk()" returns a null pointer. */ + +/* ------------------------------------------------------------ */ + +#ifdef QMSA /* stand-alone version */ +MODPRIV V_OBJ *qm_sbrk (ux) +x3u_int ux; /* # of bytes to allocate (0+) */ +{ + long lx; /* "signed long" byte count */ + int n; /* "signed int" byte count */ + V_OBJ *result; /* result pointer */ + +/* ------------------------------------------------------------ */ + + n = (int) ux; /* "signed int" byte count */ + /* safety measure */ + if (n < ZERO) return (NULLVP); + lx = (long) n; /* "signed long" byte count */ + + if (mempool == NULLCP) + { + x_panic ("Need to initialize mempool and poolsize"); + } + + if (lx > poolsize) /* sufficient room? */ + { /* no */ + return (NULLVP); /* return a null pointer */ + } + + result = mempool; /* point to new block */ + poolsize -= lx; /* reduce recorded pool size */ + mempool += n; /* move pointer past new block */ + return (result); /* return block pointer */ +} +#endif /* endif "QMSA" */ + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC qm_ce(NO_PARAM) */ +/* Summary: Handles inconsistent-allocation errors. */ + +/* ------------------------------------------------------------ */ + +/* Various functions call "qm_ce()" if it appears that bad */ +/* pointers are being used or memory is corrupted. "qm_ce()" */ +/* prints an error message and terminates the program. */ + +/* "qm_ce()" produces the message "inconsistent memory chain" */ +/* by default. The global character pointer "qm_ce_msg" may be */ +/* used to specify a secondary message string. If this pointer */ +/* is non-null when "qm_ce()" is called, "qm_ce()" will add the */ +/* specified message string to the base message. */ + +/* ------------------------------------------------------------ */ + +MODPRIV V_FUNC qm_ce(NO_PARAM) +{ + /* base message */ + char *msg = "inconsistent memory chain"; + + if (qm_ce_msg != NULLCP) /* add secondary message? */ + { /* yes */ + x_panic ("%s: %s",msg,qm_ce_msg); + } + else + { /* no */ + x_panic (msg); + } +} + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC chk_qm0(cp) */ +/* Summary: Checks a dynamic-memory pointer. */ + +/* ------------------------------------------------------------ */ + +/* V_OBJ *cp; - Dynamic-memory storage pointer previously */ +/* returned by "qmalloc()" or a related */ +/* function. */ + +/* ------------------------------------------------------------ */ + +/* "chk_qm0(cp)" checks the "V_OBJ *" pointer "cp" and term- */ +/* inates the caller with an error message if "cp" is not a */ +/* valid "qmalloc()" storage pointer. */ + +/* Note: A valid storage pointer becomes invalid if the */ +/* associated storage is freed. */ + +/* "chk_qm0()" is the non-macro version of "chk_qmp()". See */ +/* the description of "chk_qmp()" for additional information. */ + +/* ------------------------------------------------------------ */ + +MODPUB V_FUNC chk_qm0(cp) +V_OBJ *cp; /* dynamic-memory pointer */ +{ + REG_VAR QM_HDR *mcb; /* memory block pointer */ + +/* ------------------------------------------------------------ */ + + if (cp == NULLVP) qm_ce(); /* check for null pointer */ + + /* point to the header block */ + mcb = ((QM_HDR *) cp) - ONE; + qm_chkuse(mcb); /* check the header block */ +} + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC chk_qma (qp) */ +/* Summary: Checks an entire QLIST. */ + +/* ------------------------------------------------------------ */ + +/* QLIST *qp; - QLIST to check. */ + +/* ------------------------------------------------------------ */ + +/* "chk_qma()" performs some consistency checks on the QLIST */ +/* specified by "qp". */ + +/* ------------------------------------------------------------ */ + +MODPUB V_FUNC chk_qma (qp) +QLIST *qp; /* QLIST to check */ +{ + REG_VAR QM_HDR *mcb; /* memory block pointer */ + +/* ------------------------------------------------------------ */ + + /* check for null pointer */ + if (qp == NULL_QLS) qm_ce(); + +/* ------------------------------------------------------------ */ + +/* The following block of code checks the free list associated */ +/* with the QLIST. */ + + for (mcb = qp->qm_free; mcb != NULLQH; mcb = mcb->nxt_free) + { + qm_chkrel(mcb); /* consistency check */ + } + +/* ------------------------------------------------------------ */ + +/* The following block of code checks the system-memory list */ +/* associated with the QLIST. */ + + for (mcb = qp->qm_sysmem; mcb != NULLQH; mcb = mcb->nxt_free) + { + qm_chkuse(mcb); /* consistency check */ + } +} + +/* ------------------------------------------------------------ */ + +/* Function: long sys_mem() */ +/* Summary: Estimates amount of system memory available. */ + +/* ------------------------------------------------------------ */ + +/* "sys_mem()" estimates the amount of free (unallocated) sys- */ +/* tem memory available and returns the result (in bytes). The */ +/* value returned is conservative (low). */ + +/* ------------------------------------------------------------ */ + +/* Technical notes: */ + +/* 1. The result does not include unused storage space in */ +/* QLISTs. */ + +/* 2. If the host O/S is MS-DOS, "sys_mem()" assumes that the */ +/* calling program was compiled using Microsoft C's "large" */ +/* memory model. */ + +/* 3. "WSP_SIZE" should fall into the range of 5,000 to 50,000 */ +/* bytes. */ + +/* 4. "WSP_SLOTS" should not exceed 250 under MS-DOS. */ + +/* 5. "sys_mem()" is accurate up to "WSP_SIZE * WSP_SLOTS" */ +/* bytes. */ + +/* ------------------------------------------------------------ */ + +#define WSP_SLOTS 250 /* # of segments to try for */ +#define WSP_SIZE 5120 /* size of each segment */ + +/* ------------------------------------------------------------ */ + +#ifdef QMSA /* stand-alone version */ +MODPUB long sys_mem() +{ + return (poolsize); +} +#endif /* endif "QMSA" */ + +/* ------------------------------------------------------------ */ + +#ifndef QMSA /* "malloc"-based version */ +MODPUB long sys_mem() +{ + REG_VAR char *cp; /* single allocation pointer */ + REG_VAR int i; /* scratch */ + REG_VAR int n_seg; /* # of segments allocated */ + + char *wsp_ptr [WSP_SLOTS]; /* list of allocation pointers */ + +/* ------------------------------------------------------------ */ + + /* try to allocate memory */ + for (n_seg = ZERO; n_seg < WSP_SLOTS; n_seg++) + { + cp = (char *) malloc ((x3u_int) WSP_SIZE); + if (cp == NULLCP) break; + wsp_ptr [n_seg] = cp; + } + /* free the allocated memory */ + for (i = ZERO; i < n_seg; i++) + { + free (wsp_ptr [i]); /* free the current block */ + } + /* return the result */ + return (((long) n_seg) * (long) WSP_SIZE); +} +#endif /* endif not "QMSA" */ + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC qfree(cp) */ +/* Summary: Frees memory allocated by "qmalloc()". */ + +/* ------------------------------------------------------------ */ + +/* V_OBJ *cp; - Pointer returned by "qmalloc()" or a re- */ +/* lated function. */ + +/* ------------------------------------------------------------ */ + +/* "qfree(cp)" returns the dynamic memory associated with "cp" */ +/* to the QLIST from which it was obtained. */ + +/* "qfree()" may be used to free memory allocated by the */ +/* following functions: */ +/* */ +/* qcalloc() qmalloc() qrealloc() */ + +/* "qfree()" should not be used to free memory allocated by the */ +/* standard MALLOC functions (calloc, malloc, etc.). */ + +/* ------------------------------------------------------------ */ + +MODPUB V_FUNC qfree (cp) +V_OBJ *cp; /* previously-allocated pointer */ +{ + REG_VAR QM_HDR *cur_mcb; /* memory block being freed */ + REG_VAR x3u_long lx; /* scratch */ + int m_flag; /* O.K.-to-merge flag */ + QM_SIZE_T m_size; /* merged block size */ + QM_HDR *nxt_mcb; /* next block in free list */ + QM_HDR *prev; /* preceding block in free list */ + QLIST *qp; /* QLIST to use */ + +/* ------------------------------------------------------------ */ + +/* initial setup */ + + if (cp == NULLVP) qm_ce(); /* null pointer? */ + /* point to the QM_HDR block */ + cur_mcb = ((QM_HDR *) cp) - ONE; + qm_chkuse(cur_mcb); /* consistency check */ + qm_setrel(cur_mcb); /* mark block as released */ + qp = cur_mcb->qm_owner; /* get the QLIST to use */ + cur_mcb->nxt_free = NULLQH; /* clear the next-free pointer */ + +/* ------------------------------------------------------------ */ + +/* handle the simplest case */ + + if (qp->qm_free == NULLQH) /* is QLIST's freelist empty? */ + { /* yes */ + qp->qm_free = cur_mcb; /* stick the freed block in */ + return; /* done - exit */ + } + +/* ------------------------------------------------------------ */ + +/* find position in free-list */ + +/* When the following loop is completed, "prev" points to the */ +/* header which should precede "cur_mcb" in the free-list, and */ +/* "nxt_mcb" points to the header which should follow "cur_mcb" */ +/* in the list. */ + +/* "prev" will be null (NULLQH) if "cur_mcb" belongs at the */ +/* beginning of the list, and "nxt_mcb" will be null (NULLQH) */ +/* if "cur_mcb" belongs at the end of the list. Since we have */ +/* already verified that the list is nonempty, "prev" and */ +/* "nxt_mcb" cannot both be null. */ + + prev = NULLQH; + nxt_mcb = qp->qm_free; + + while ((nxt_mcb != NULLQH) && (addr(nxt_mcb) < addr(cur_mcb))) + { + qm_chkrel(nxt_mcb); /* consistency check */ + prev = nxt_mcb; + nxt_mcb = nxt_mcb->nxt_free; + } + +/* ------------------------------------------------------------ */ + +/* another consistency check */ + +/* Does the preceding free memory block overlap the beginning */ +/* of the block being freed now? */ + + if (prev != NULLQH) + { + if ((addr(prev) >= addr(cur_mcb)) || + (addr(NXT_POS(prev)) > addr(ALIGN_P(cur_mcb)))) + { /* yes - consistency error */ + x_panic ("qfree: overlap -1"); + } + } + +/* ------------------------------------------------------------ */ + +/* another consistency check */ + +/* Does the end of the block being freed now overlap the begin- */ +/* ning of the next free block? */ + + if (nxt_mcb != NULLQH) + { + if ((addr(cur_mcb) >= addr(nxt_mcb)) || + (addr(NXT_POS(cur_mcb)) > addr(ALIGN_P(nxt_mcb)))) + { /* yes - consistency error */ + x_panic ("qfree: overlap +1"); + } + } + +/* ------------------------------------------------------------ */ + +/* Can we merge the block being freed with the preceding free */ +/* block? */ + + m_flag = FALSE; + + if ((prev != NULLQH) && + (NXT_POS(prev) == ALIGN_P(cur_mcb))) + { /* the blocks are adjoining */ + /* get the merged block size */ + lx = QM_ASIZE(prev) + QM_ASIZE(cur_mcb); + /* value as it will be stored */ + m_size = (QM_SIZE_T) lx; + /* will the size fit? */ + if (lx == (x3u_long) m_size) m_flag = TRUE; + } + + if (m_flag) /* can the blocks be merged? */ + { /* yes */ + prev->qa_size = m_size; /* set the total size */ + cur_mcb = prev; /* point to the resulting block */ + qm_setrel(cur_mcb); /* set the consistency flag */ + } + else + { /* no - put it in the free list */ + if (nxt_mcb == qp->qm_free) + { /* head of free list */ + if (prev != NULLQH) x_panic ("qfree: prev"); + qp->qm_free = cur_mcb; + } + else + { /* inside the free list */ + if (prev == NULLQH) x_panic ("qfree: prev"); + prev->nxt_free = cur_mcb; + } + /* point to the next block */ + cur_mcb->nxt_free = nxt_mcb; + } + +/* ------------------------------------------------------------ */ + +/* Can we merge it with the next block? */ + + m_flag = FALSE; + + if ((nxt_mcb != NULLQH) && + (NXT_POS(cur_mcb) == ALIGN_P(nxt_mcb))) + { /* the blocks are adjoining */ + /* get the merged block size */ + lx = QM_ASIZE(cur_mcb) + QM_ASIZE(nxt_mcb); + /* value as it will be stored */ + m_size = (QM_SIZE_T) lx; + /* will the size fit? */ + if (lx == (x3u_long) m_size) m_flag = TRUE; + } + + if (m_flag) + { /* yes - do it */ + /* set the total size */ + cur_mcb->qa_size = m_size; + qm_setrel(cur_mcb); /* set the consistency flag */ + /* point to the next block */ + cur_mcb->nxt_free = nxt_mcb->nxt_free; + } +} + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC q_more(qp,n_a) */ +/* Summary: Support function for "qmalloc()". */ + +/* ------------------------------------------------------------ */ + +/* QLIST *qp; - QLIST to use. */ +/* x3u_long n_a; - Memory needed, in units of QMASIZE. */ + +/* ------------------------------------------------------------ */ + +/* "q_more(qp,n_a)" gets the requested amount of dynamic memory */ +/* from the freed system-memory list (sys_free) or from the */ +/* operating system and adds it to the specified QLIST. */ + +/* "n_a" includes the size of the free-list (qm_free) memory */ +/* block header, but not the size of the system ("qm_sysmem" or */ +/* "sys_free") memory block header. */ + +/* ------------------------------------------------------------ */ + +#ifdef QMSA /* stand-alone version */ +MODPRIV int q_more (qp,n_a) +#else /* "malloc"-based version */ +MODPRIV V_FUNC q_more (qp,n_a) +#endif /* endif "QMSA" */ + +QLIST *qp; /* QLIST to use */ +x3u_long n_a; /* # of alloc. units required */ +{ + x3u_long lx; /* scratch */ + QM_HDR *mcb; /* memory block header pointer */ + QM_HDR *prev; /* pointer to preceding block */ + QM_SIZE_T ux; /* scratch */ + +/* ------------------------------------------------------------ */ + +/* adjust request as necessary */ + + lx = (x3u_long) qp->qm_block; + if (lx == ZERO) lx = QM_DEFBLK; + lx = QM_GETMIN(lx); + if (n_a < lx) n_a = lx; + +/* ------------------------------------------------------------ */ + +/* check the general free pool */ + + for (prev = NULLQH, mcb = sys_free; + mcb != NULLQH; + prev = mcb, mcb = mcb->nxt_free) + { /* try the next system block */ + qm_chkrel(mcb); /* consistency check */ + + if ((QM_ASIZE(mcb) - HDR_ASIZE) >= n_a) + { /* found a block large enough */ + if (prev == NULLQH) /* at the start of the list */ + { /* delete it from the list */ + sys_free = mcb->nxt_free; + } + else /* it's inside the list */ + { /* delete it from the list */ + prev->nxt_free = mcb->nxt_free; + } + + break; /* got it */ + } + } + +/* ------------------------------------------------------------ */ + +/* use the system if necessary */ + + if (mcb == NULLQH) /* have we got it yet? */ + { /* no - must "malloc()" it */ + lx = QMASIZE * (HDR_ASIZE + n_a); + ux = (QM_SIZE_T) lx; + + if (lx != (x3u_long) ux) + { +#ifdef QMSA /* stand-alone version */ + return (FALSE); +#else /* "malloc"-based version */ + x_panic ("qmalloc: request too large"); +#endif /* endif "QMSA" */ + } + +#ifdef QMSA /* stand-alone version */ + mcb = (QM_HDR *) qm_sbrk (ux); +#else /* "malloc"-based version */ + mcb = (QM_HDR *) malloc (ux); +#endif /* endif "QMSA" */ + } + +/* ------------------------------------------------------------ */ + +/* check the results */ + + if (mcb == NULLQH) /* did we get it? */ + { /* no - error */ +#ifdef QMSA /* stand-alone version */ + return (FALSE); +#else /* "malloc"-based version */ + x_error ("insufficient memory"); +#endif /* endif "QMSA" */ + } + +/* ------------------------------------------------------------ */ + +/* build a system memory header */ + + /* size including header itself */ + mcb->qa_size = n_a + HDR_ASIZE; + qm_setuse(mcb); /* set the consistency flag */ + +/* ------------------------------------------------------------ */ + +/* add to system-memory list */ + + mcb->nxt_free = qp->qm_sysmem; + qp->qm_sysmem = mcb; + +/* ------------------------------------------------------------ */ + +/* build an allocation header */ + + mcb++; /* point to new header */ + mcb->qm_owner = qp; /* "QLIST" to put it in */ + mcb->qa_size = n_a; /* size including header itself */ + qm_setuse(mcb); /* set the consistency flag */ + +/* ------------------------------------------------------------ */ + +/* add to QLIST's free-list */ + + qfree ((V_OBJ *) (mcb + ONE)); + +#ifdef QMSA /* stand-alone version */ + return (TRUE); +#endif /* endif "QMSA" */ +} + +/* ------------------------------------------------------------ */ + +/* Function: V_OBJ *qmalloc (qp, nb) */ +/* Summary: Allocates memory from a QLIST. */ + +/* ------------------------------------------------------------ */ + +/* QLIST *qp; - QLIST to use (or QM_GEN). */ +/* int nb; - Number of bytes required (1+). */ + +/* ------------------------------------------------------------ */ + +/* "qmalloc(qp,nb)" allocates the specified number of bytes */ +/* from the specified QLIST and returns a pointer to the allo- */ +/* cated block of storage. */ + +/* If the caller does not use multiple allocation lists, the */ +/* predefined general-purpose list "QM_GEN" may be used. */ + +/* "nb" is declared as a signed value, but is interpreted as an */ +/* unsigned value. */ + +/* If the QLIST does not contain sufficient free storage, */ +/* "qmalloc()" adds dynamic memory to the QLIST as necessary. */ + +/* Memory allocated by "qmalloc()" may be freed using */ +/* "qfree()". */ + +/* "qmalloc()" prints an error message and terminates the */ +/* caller if sufficient memory cannot be allocated. */ + +/* See the header file "x3mem.h" for additional information. */ + +/* ------------------------------------------------------------ */ + +/* Internal note: */ + +/* The sizes referred to in the following code are in units */ +/* of the alignment size (QMASIZE), with the exception of "nb" */ +/* and "nu". */ + +/* ------------------------------------------------------------ */ + +MODPUB V_OBJ *qmalloc (qp, nb) +QLIST *qp; /* QLIST to use */ +int nb; /* number of bytes required */ +{ + REG_VAR QM_HDR *mcb; /* memory block header pointer */ + REG_VAR QM_HDR *mcx; /* pointer to left-over block */ + x3u_long n_a; /* # of alignment units needed */ + /* "malloc()"-compatible size */ + QM_SIZE_T nu = (QM_SIZE_T) nb; + REG_VAR QM_HDR *prev; /* previous header in freelist */ + REG_VAR x3u_long x_a; /* size of the left-over block */ + +/* ------------------------------------------------------------ */ + +/* initial setup */ + + /* set the default QLIST */ + if (qp == NULL_QLS) x_panic ("qmalloc: null"); + if (nu == ZERO) nu = ONE; /* check the size request */ + n_a = ALIGNSIZ(nu); /* # of alignment units needed */ + + if (qp->qm_nofree == FALSE) /* is the list freeable? */ + { /* yes */ + n_a += HDR_ASIZE; /* include a block header */ + } + + prev = mcb = NULLQH; /* initial (null) block pointer */ + +/* ------------------------------------------------------------ */ + +/* Search the QLIST freelist for a block of memory that is */ +/* large enough. */ + + while (mcb == NULLQH) /* got a memory block yet? */ + { /* no - try to get one */ + for (prev = NULLQH, mcb = qp->qm_free; + mcb != NULLQH; + prev = mcb, mcb = mcb->nxt_free) + { /* advance to the next entry */ + qm_chkrel(mcb); /* consistency check */ + if (QM_ASIZE(mcb) >= n_a) break; + } + + if (mcb == NULLQH) /* did we find a block? */ + { /* no */ +#ifdef QMSA /* stand-alone version */ + /* get more memory from system */ + if (q_more (qp, n_a) == FALSE) return (NULLVP); +#else /* "malloc"-based version */ + q_more (qp, n_a); /* get more memory from system */ +#endif /* endif "QMSA" */ + } + } + +/* ------------------------------------------------------------ */ + +/* break block up if necessary */ + +/* "mcb" now points to the "QM_HDR" header of a block in the */ +/* freelist that is large enough. If the block is significant- */ +/* ly larger than we need it to be, we break it into two pieces */ +/* and leave the left-over portion in the freelist. */ + +/* The left-over portion must be split off from the end of the */ +/* block, as opposed to the beginning. This requirement is */ +/* imposed by "qrealloc()". */ + +/* We don't adjust the consistency-check field for the "used" */ +/* block (*mcb) here. If this is necessary, it is done before */ +/* the block is returned. */ + +/* ------------------------------------------------------------ */ + + if ((QM_ASIZE(mcb) - n_a) > (HDR_ASIZE + QM_SLACK)) + { /* break it up */ + /* size of the left-over block */ + x_a = mcb->qa_size - n_a; + mcb->qa_size = n_a; /* set size of "used" block */ + + /* point to the left-over block */ + mcx = (QM_HDR *) NXT_POS(mcb); + mcx->qa_size = x_a; /* set its size */ + /* set its next-pointer */ + mcx->nxt_free = mcb->nxt_free; + qm_setrel(mcx); /* set its consistency flag */ + mcb->nxt_free = mcx; /* put it back in the freelist */ + } + +/* ------------------------------------------------------------ */ + +/* remove block from freelist */ + + if (mcb == qp->qm_free) /* at head of freelist? */ + { /* yes - just advance the head */ + if (prev != NULLQH) x_panic ("qmalloc: prev"); + qp->qm_free = mcb->nxt_free; + } + else + { /* no - adjust preceding entry */ + if (prev == NULLQH) x_panic ("qmalloc: prev"); + prev->nxt_free = mcb->nxt_free; + } + +/* ------------------------------------------------------------ */ + +/* wrap it up */ + + if (qp->qm_nofree == FALSE) /* is the list freeable? */ + { /* yes - create a header */ + mcb->qm_owner = qp; /* save the (QLIST) owner */ + mcb->qa_size = n_a; /* block size including header */ + qm_setuse(mcb); /* set the consistency flag */ + mcb++; /* point to the user's portion */ + } + + return ((V_OBJ *) mcb); /* give it away */ +} + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC qflush (qp) */ +/* Summary: Releases an entire QLIST. */ + +/* ------------------------------------------------------------ */ + +/* QLIST *qp; - QLIST to free. */ + +/* ------------------------------------------------------------ */ + +/* Globals (in): */ + +/* char qm_retsys; - "Flush to system" flag. */ + +/* ------------------------------------------------------------ */ + +/* "qflush(qp)" frees up all of the dynamic memory associated */ +/* with the specified QLIST. The freed memory may be re- */ +/* allocated to any QLIST using "qmalloc()". */ + +/* "qflush(qp)" clears the QLIST header after releasing the */ +/* memory. The empty QLIST may be re-used for new allocation */ +/* calls. If the "qm_nofree" flag is used, this flag should be */ +/* re-initialized. */ + +/* ------------------------------------------------------------ */ + +/* Technical note: */ + +/* If the global flag "qm_retsys" is FALSE, "qmalloc()" retains */ +/* primary control of the freed memory. This is the default */ +/* mode of operation. */ + +/* If the global flag "qm_retsys" is TRUE, "qflush()" returns */ +/* primary control of the freed memory to the lower-level */ +/* memory allocation function "malloc()". */ + +/* ------------------------------------------------------------ */ + +MODPUB V_FUNC qflush(qp) +QLIST *qp; /* QLIST to use */ +{ + REG_VAR QM_HDR *cur_mcb; /* current memory block header */ + QM_HDR *nxt_mcb; /* next memory block header */ + +/* ------------------------------------------------------------ */ + + if (qp == (QLIST *) NULLVP) qm_ce(); + +/* ------------------------------------------------------------ */ + + for (cur_mcb = qp->qm_sysmem; + cur_mcb != NULLQH; + cur_mcb = nxt_mcb) + { + qm_chkuse(cur_mcb); /* consistency check */ + /* point to the next header */ + nxt_mcb = cur_mcb->nxt_free; + +#ifndef QMSA /* "malloc"-based version */ + if (qm_retsys) /* return memory to system? */ + { /* yes - use "free()" */ + V_CAST free ((V_OBJ *) cur_mcb); + } + else +#endif /* endif not "QMSA" */ + { /* no - put it in a common pool */ + qm_setrel(cur_mcb); /* set the consistency flag */ + /* move it to "sys_free" list */ + cur_mcb->nxt_free = sys_free; + sys_free = cur_mcb; + } + } + + p_clr(qp); /* clear the QLIST header */ +} + +/* ------------------------------------------------------------ */ + +/* Function: V_OBJ *qcalloc (qp, num, sz) */ +/* Summary: Allocates memory from a QLIST. */ + +/* ------------------------------------------------------------ */ + +/* QLIST *qp; - QLIST to use (or QM_GEN). */ +/* x3u_int num; - Number of items required (1+). */ +/* x3u_int sz; - Size of each item. */ + +/* ------------------------------------------------------------ */ + +/* "qcalloc(qp,num,sz)" is roughly equivalent to "qmalloc(qp, */ +/* num*sz)" with the distinction that "qcalloc()" clears the */ +/* block of memory allocated before returning it. */ + +/* Memory allocated by "qcalloc()" may be freed using */ +/* "qfree()". */ + +/* ------------------------------------------------------------ */ + +MODPUB V_OBJ *qcalloc (qp, num, sz) +QLIST *qp; /* QLIST to use */ +x3u_int num; /* No. of items required (1+) */ +x3u_int sz; /* Size of each item */ +{ + REG_VAR V_OBJ *result; /* result pointer */ + +/* ------------------------------------------------------------ */ + + int nb = num * sz; /* number of bytes required */ + result = qmalloc (qp, nb); /* returns a block (or exits) */ + b_clr (result, nb); /* clear the block obtained */ + return (result); /* return the result pointer */ +} + +/* ------------------------------------------------------------ */ + +/* Function: V_OBJ *qrealloc (cp, nb) */ +/* Summary: Re-allocates dynamic memory. */ + +/* ------------------------------------------------------------ */ + +/* V_OBJ *qp; - "qmalloc()" storage to reallocate. */ +/* int nb; - New block size, in bytes (1+). */ + +/* ------------------------------------------------------------ */ + +/* If "cp" is a pointer previously returned by "qmalloc()" or a */ +/* related function, "qrealloc(cp,nb)" changes the size of the */ +/* allocated block to the new value "nb". */ + +/* The block may be moved in the process. "qrealloc()" returns */ +/* a pointer to the new block location (or to the old block */ +/* location, if the block is not moved). */ + +/* "nb" is declared as a signed integer, but interpreted as an */ +/* unsigned integer. */ + +/* The contents of the block are unchanged up to the lesser of */ +/* the old and new block sizes. */ + +/* Memory allocated by "qrealloc()" may be freed using */ +/* "qfree()". */ + +/* "qrealloc()" prints an error message and terminates the */ +/* caller if sufficient memory cannot be allocated. */ + +/* "qrealloc()" should not be used in conjunction with the */ +/* standard "malloc()" and "free()" functions. */ + +/* ------------------------------------------------------------ */ + +MODPUB V_OBJ *qrealloc (cp, nb) +V_OBJ *cp; /* storage to reallocate */ +int nb; /* user request (in bytes) */ +{ + REG_VAR QM_HDR *cur_mcb; /* QM_HDR being reallocated */ + REG_VAR QLIST *qp; /* QLIST to use */ + REG_VAR V_OBJ *result; /* result pointer */ + REG_VAR x3u_long u_lx; /* scratch (must be x3u_long) */ + REG_VAR x3u_int ux; /* scratch (must be x3u_int ) */ + +/* ------------------------------------------------------------ */ + + REG_VAR x3u_int u_nb; /* adjusted size request */ + REG_VAR x3u_int u_nc; /* number of bytes to copy */ + REG_VAR x3u_int u_old; /* size of old block */ + +/* ------------------------------------------------------------ */ + +/* initial setup */ + + if (cp == NULLVP) qm_ce(); /* null pointer? */ + /* point to the QM_HDR block */ + cur_mcb = ((QM_HDR *) cp) - ONE; + qm_chkuse(cur_mcb); /* consistency check */ + + qp = cur_mcb->qm_owner; /* get the QLIST to use */ + if (nb == ZERO) nb = ONE; /* check the size request */ + u_nb = (x3u_int) nb; /* interpret "nb" as unsigned */ + +/* ------------------------------------------------------------ */ + +/* get size of old block */ + +/* "u_old" holds the number of bytes allocated for the old */ +/* block, excluding the memory block header. */ + + u_old = (x3u_int) ((QM_ASIZE(cur_mcb) - HDR_ASIZE) * QMASIZE); + +/* ------------------------------------------------------------ */ + +/* adjust the new block size */ + +/* To reduce fragmentation, "qrealloc()" reallocates memory in */ +/* blocks of "QM_RAFF" bytes. */ + +/* To accomplish this, the following code rounds "u_nb" up to */ +/* the nearest "QM_RAFF" boundary. The adjustment has no */ +/* effect if "u_nb" is already aligned on a "QM_RAFF" */ +/* boundary. */ + +/* The adjustment is suppressed if the adjusted value will not */ +/* fit into an unsigned integer. */ + +/* ------------------------------------------------------------ */ + + u_lx = (x3u_long) u_nb; + u_lx = (((u_lx - ONE) / QM_RAFF) + ONE) * QM_RAFF; + ux = (x3u_int) u_lx; + if (u_lx == (x3u_long) ux) u_nb = ux; + +/* ------------------------------------------------------------ */ + +/* is reallocation necessary? */ + + if ((u_nb <= u_old) && ((u_old - u_nb) < QM_RAFF)) + { /* no */ + return (cp); /* return the existing pointer */ + } + +/* ------------------------------------------------------------ */ + +/* determine the copy count */ + +/* The following code sets "u_nc" to the number of data bytes */ +/* to be copied. */ + + u_nc = (u_nb < u_old) ? u_nb : u_old; + +/* ------------------------------------------------------------ */ + +/* reallocate the block */ + + /* allocate new storage */ + result = qmalloc (qp,(int) u_nb); + + /* copy the data */ +#ifdef QMSA /* stand-alone version */ + { + char *p1 = result; + char *p2 = cp; + + while (u_nc-- > ZERO) *p1++ = *p2++; + } +#else /* "malloc"-based version */ + V_CAST memcpy (result, cp, u_nc); +#endif /* endif "QMSA" */ + + qfree (cp); /* free the old block */ + return (result); /* return the result pointer */ +} + +/* ------------------------------------------------------------ */ +/* simplified QMALLOC interface layer */ +/* ------------------------------------------------------------ */ + +/* The following interface layer can be used by application */ +/* programs which do not require multiple QLISTs. */ + +/* ------------------------------------------------------------ */ + +/* Function: V_OBJ *sqCalloc(i,j) */ +/* Summary: Similar to "calloc(i,j)". */ + +/* ------------------------------------------------------------ */ + +/* x3u_int i,j; - Product of these two integers gives the */ +/* number of bytes to allocate. */ + +/* ------------------------------------------------------------ */ + +MODPUB V_OBJ *sqCalloc(i,j) +x3u_int i; +x3u_int j; +{ + return ((V_OBJ *) qcalloc (QM_SQL, i, j)); +} + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC sqChkHeap() */ +/* Summary: Checks the entire "sq..." heap. */ + +/* ------------------------------------------------------------ */ + +/* "sqChkHeap()" performs some consistency checks on the */ +/* "sq..." heap. */ + +/* ------------------------------------------------------------ */ + +MODPUB V_FUNC sqChkHeap() +{ + chk_qma (QM_SQL); +} + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC sqChkPtr (p, s) */ +/* Summary: Checks an allocated storage pointer. */ + +/* ------------------------------------------------------------ */ + +/* V_OBJ *p; - Pointer previously returned by one of the */ +/* "sq..." memory allocation functions. */ +/* char *s; - Message string (see below). */ + +/* "sqChkPtr()" performs some consistency checks on the speci- */ +/* fied pointer. If the pointer is invalid, "sqChkPtr()" pro- */ +/* duces an error message and terminates the caller. The error */ +/* message includes the specified message string. */ + +/* ------------------------------------------------------------ */ + +MODPUB V_FUNC sqChkPtr (p, s) +V_OBJ *p; +char *s; +{ + if (p == NULLVP) + { + if ((s == NULLCP) || (*s == CH_EOS)) + { + x_panic ("null pointer"); + } + else + { + x_panic ("null pointer: %s",s); + } + } + + if ((s != NULLCP) && (*s != CH_EOS)) qm_ce_msg = s; + chk_qm0 (p); + qm_ce_msg = NULLCP; +} + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC sqFlush() */ +/* Summary: Frees all "sq..." storage. */ + +/* ------------------------------------------------------------ */ + +/* "sqFlush()" releases all of the storage previously allocated */ +/* by "sq..." memory allocation functions. Memory is dealloca- */ +/* ted at the system (or "malloc") level. */ + +/* ------------------------------------------------------------ */ + +MODPUB V_FUNC sqFlush() +{ + qm_retsys++; + qflush (QM_SQL); + qm_retsys--; +} + +/* ------------------------------------------------------------ */ + +/* Function: V_FUNC sqFree (p) */ +/* Summary: Frees one storage block. */ + +/* ------------------------------------------------------------ */ + +/* V_OBJ *p; - Pointer previously returned by one of the */ +/* "sq..." memory allocation functions. */ + +/* "sqFree(p)" deallocates the storage associated with the */ +/* specified pointer. */ + +/* Storage is returned to the "sq..." dynamic memory pool. It */ +/* is not released to the system. (Use "sqFlush()" to deallo- */ +/* cate the "sq..." heap at the system level.) */ + +/* ------------------------------------------------------------ */ + +MODPUB V_FUNC sqFree (p) +V_OBJ *p; +{ + qfree (p); +} + +/* ------------------------------------------------------------ */ + +/* Function: V_OBJ *sqMalloc (n) */ +/* Summary: Similar to "malloc (n)". */ + +/* ------------------------------------------------------------ */ + +/* x3u_int n; - Number of bytes to allocate. */ + +/* ------------------------------------------------------------ */ + +MODPUB V_OBJ *sqMalloc(n) +x3u_int n; +{ + return (qmalloc (QM_SQL, (int) n)); +} + +/* ------------------------------------------------------------ */ + +/* Function: V_OBJ *sqRealloc (p, n) */ +/* Summary: Similar to "realloc (p, n)". */ + +/* ------------------------------------------------------------ */ + +/* V_OBJ *p; - Pointer previously returned by one of the */ +/* "sq..." memory allocation functions. */ +/* x3u_int n; - New block size. */ + +/* ------------------------------------------------------------ */ + +MODPUB V_OBJ *sqRealloc (p, n) +V_OBJ *p; +x3u_int n; +{ + return (qrealloc (p, (int) n)); +}