New memory management subsystem.
This commit is contained in:
parent
1801ca9c74
commit
9b4288cf9c
3
Makefile
3
Makefile
@ -12,7 +12,8 @@ CC ?= gcc
|
|||||||
#CC ?= tcc
|
#CC ?= tcc
|
||||||
#CC ?= musl-tcc
|
#CC ?= musl-tcc
|
||||||
CFLAGS += -O2 -pedantic -g -Wall -Wextra
|
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
|
LDFLAGS += -lm
|
||||||
BIN ?= slidescript
|
BIN ?= slidescript
|
||||||
|
|
||||||
|
0
src/compression.c
Executable file → Normal file
0
src/compression.c
Executable file → Normal file
259
src/eprintf.c
Normal file
259
src/eprintf.c
Normal file
@ -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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
0
src/inc/compression.h
Executable file → Normal file
0
src/inc/compression.h
Executable file → Normal file
0
src/inc/config.h
Executable file → Normal file
0
src/inc/config.h
Executable file → Normal file
0
src/inc/deps.h
Executable file → Normal file
0
src/inc/deps.h
Executable file → Normal file
0
src/inc/enc.h
Executable file → Normal file
0
src/inc/enc.h
Executable file → Normal file
45
src/inc/eprintf.h
Normal file
45
src/inc/eprintf.h
Normal file
@ -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 */
|
0
src/inc/inset.h
Executable file → Normal file
0
src/inc/inset.h
Executable file → Normal file
0
src/inc/lexer.h
Executable file → Normal file
0
src/inc/lexer.h
Executable file → Normal file
0
src/inc/math.h
Executable file → Normal file
0
src/inc/math.h
Executable file → Normal file
0
src/inc/md5.h
Executable file → Normal file
0
src/inc/md5.h
Executable file → Normal file
0
src/inc/network.h
Executable file → Normal file
0
src/inc/network.h
Executable file → Normal file
0
src/inc/pipe.h
Executable file → Normal file
0
src/inc/pipe.h
Executable file → Normal file
0
src/inc/sbyteswap.h
Executable file → Normal file
0
src/inc/sbyteswap.h
Executable file → Normal file
0
src/inc/search.h
Executable file → Normal file
0
src/inc/search.h
Executable file → Normal file
6
src/inc/tar.h
Executable file → Normal file
6
src/inc/tar.h
Executable file → Normal file
@ -26,6 +26,12 @@ THE SOFTWARE
|
|||||||
#ifndef __TAR__
|
#ifndef __TAR__
|
||||||
#define __TAR__
|
#define __TAR__
|
||||||
|
|
||||||
|
#include "x3mem.h"
|
||||||
|
|
||||||
|
UX3_EXT QLIST QM_TAR [ONE]; // Dynamic-memory QLIST
|
||||||
|
|
||||||
|
extern void tar_free_pool (void);
|
||||||
|
|
||||||
#ifndef _DEFAULT_SOURCE
|
#ifndef _DEFAULT_SOURCE
|
||||||
#define _DEFAULT_SOURCE
|
#define _DEFAULT_SOURCE
|
||||||
#endif
|
#endif
|
||||||
|
0
src/inc/util.h
Executable file → Normal file
0
src/inc/util.h
Executable file → Normal file
0
src/inc/vars.h
Executable file → Normal file
0
src/inc/vars.h
Executable file → Normal file
275
src/inc/x3basic.h
Normal file
275
src/inc/x3basic.h
Normal file
@ -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
|
333
src/inc/x3mem.h
Normal file
333
src/inc/x3mem.h
Normal file
@ -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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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 */
|
2
src/inset.c
Executable file → Normal file
2
src/inset.c
Executable file → Normal file
@ -8,6 +8,7 @@
|
|||||||
#include "inc/deps.h"
|
#include "inc/deps.h"
|
||||||
#include "inc/inset.h"
|
#include "inc/inset.h"
|
||||||
#include "inc/lexer.h"
|
#include "inc/lexer.h"
|
||||||
|
#include "inc/tar.h"
|
||||||
#include "inc/vars.h"
|
#include "inc/vars.h"
|
||||||
#include "inc/util.h"
|
#include "inc/util.h"
|
||||||
|
|
||||||
@ -75,6 +76,7 @@ char *parse_bq(char *string)
|
|||||||
strcat (varbuffer, "\n");
|
strcat (varbuffer, "\n");
|
||||||
|
|
||||||
variable_pointer = process_line(varbuffer);
|
variable_pointer = process_line(varbuffer);
|
||||||
|
tar_free_pool();
|
||||||
if(variable_pointer == NULL)
|
if(variable_pointer == NULL)
|
||||||
syn_error("ss:error:backquoted function must return string!");
|
syn_error("ss:error:backquoted function must return string!");
|
||||||
|
|
||||||
|
3
src/lexer.c
Executable file → Normal file
3
src/lexer.c
Executable file → Normal file
@ -346,7 +346,6 @@ char *process_line(char *line)
|
|||||||
return retbuf;
|
return retbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* COMPRESSION AND DECOMPRESSION */
|
/* COMPRESSION AND DECOMPRESSION */
|
||||||
else if(strncmp("decompress",tok_srch,10) == 0)
|
else if(strncmp("decompress",tok_srch,10) == 0)
|
||||||
{
|
{
|
||||||
@ -354,6 +353,7 @@ char *process_line(char *line)
|
|||||||
struct tar_t *archive = NULL;
|
struct tar_t *archive = NULL;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
tar_free_pool();
|
||||||
tok_srch = strtok(NULL, "\"");
|
tok_srch = strtok(NULL, "\"");
|
||||||
if(tok_srch == NULL)
|
if(tok_srch == NULL)
|
||||||
{
|
{
|
||||||
@ -430,6 +430,7 @@ char *process_line(char *line)
|
|||||||
struct tar_t *archive = NULL;
|
struct tar_t *archive = NULL;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
tar_free_pool();
|
||||||
tok_srch = strtok(NULL, "\"");
|
tok_srch = strtok(NULL, "\"");
|
||||||
if(tok_srch == NULL)
|
if(tok_srch == NULL)
|
||||||
{
|
{
|
||||||
|
4
src/main.c
Executable file → Normal file
4
src/main.c
Executable file → Normal file
@ -11,6 +11,7 @@
|
|||||||
#include "inc/util.h"
|
#include "inc/util.h"
|
||||||
#include "inc/lexer.h"
|
#include "inc/lexer.h"
|
||||||
#include "inc/pipe.h"
|
#include "inc/pipe.h"
|
||||||
|
#include "inc/tar.h"
|
||||||
#include "inc/vars.h"
|
#include "inc/vars.h"
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@ -62,6 +63,7 @@ int main(int argc, char **argv)
|
|||||||
pipechk = get_cmd_count();
|
pipechk = get_cmd_count();
|
||||||
|
|
||||||
return_dat = process_line(spipe[0].command);
|
return_dat = process_line(spipe[0].command);
|
||||||
|
tar_free_pool();
|
||||||
|
|
||||||
// Blank line, getting up outta here.
|
// Blank line, getting up outta here.
|
||||||
if(return_dat == NULL) continue;
|
if(return_dat == NULL) continue;
|
||||||
@ -74,6 +76,8 @@ int main(int argc, char **argv)
|
|||||||
set_var(varc, "PIPE", return_dat);
|
set_var(varc, "PIPE", return_dat);
|
||||||
// Process functions based on previous pipe return
|
// Process functions based on previous pipe return
|
||||||
return_dat = process_line(spipe[ii].command);
|
return_dat = process_line(spipe[ii].command);
|
||||||
|
tar_free_pool();
|
||||||
|
|
||||||
// set PIPE var back to NULL after use, keep the struct clean
|
// set PIPE var back to NULL after use, keep the struct clean
|
||||||
set_var(varc, "\0", "\0");
|
set_var(varc, "\0", "\0");
|
||||||
// Check to see if there's anything to even display
|
// Check to see if there's anything to even display
|
||||||
|
0
src/math.c
Executable file → Normal file
0
src/math.c
Executable file → Normal file
0
src/network.c
Executable file → Normal file
0
src/network.c
Executable file → Normal file
0
src/pipe.c
Executable file → Normal file
0
src/pipe.c
Executable file → Normal file
0
src/search.c
Executable file → Normal file
0
src/search.c
Executable file → Normal file
339
src/tar.c
Executable file → Normal file
339
src/tar.c
Executable file → Normal file
@ -27,12 +27,16 @@ static int iszeroed(char * buf, size_t size);
|
|||||||
// make directory recursively
|
// make directory recursively
|
||||||
static int recursive_mkdir(const char * dir, const unsigned int mode);
|
static int recursive_mkdir(const char * dir, const unsigned int mode);
|
||||||
|
|
||||||
int tar_read(const int fd, struct tar_t ** archive, const char verbosity){
|
int tar_read (const int fd,
|
||||||
if (fd < 0){
|
struct tar_t **archive, const char verbosity)
|
||||||
|
{
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
ERROR("Bad file descriptor");
|
ERROR("Bad file descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!archive || *archive){
|
if (!archive || *archive)
|
||||||
|
{
|
||||||
ERROR("Bad 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;
|
struct tar_t ** tar = archive;
|
||||||
char update = 1;
|
char update = 1;
|
||||||
|
|
||||||
for(count = 0; ; count++){
|
for(count = 0; ; count++)
|
||||||
*tar = malloc(sizeof(struct tar_t));
|
{
|
||||||
if (update && (read_size(fd, (*tar) -> block, 512) != 512)){
|
*tar = qmalloc (QM_TAR, sizeof (struct tar_t));
|
||||||
|
if (update && (read_size(fd, (*tar) -> block, 512) != 512))
|
||||||
|
{
|
||||||
V_PRINT(stderr, "Error: Bad read. Stopping");
|
V_PRINT(stderr, "Error: Bad read. Stopping");
|
||||||
tar_free(*tar);
|
tar_free(*tar);
|
||||||
*tar = NULL;
|
*tar = NULL;
|
||||||
@ -53,8 +59,10 @@ int tar_read(const int fd, struct tar_t ** archive, const char verbosity){
|
|||||||
|
|
||||||
update = 1;
|
update = 1;
|
||||||
// if current block is all zeros
|
// if current block is all zeros
|
||||||
if (iszeroed((*tar) -> block, 512)){
|
if (iszeroed((*tar) -> block, 512))
|
||||||
if (read_size(fd, (*tar) -> block, 512) != 512){
|
{
|
||||||
|
if (read_size(fd, (*tar) -> block, 512) != 512)
|
||||||
|
{
|
||||||
V_PRINT(stderr, "Error: Bad read. Stopping");
|
V_PRINT(stderr, "Error: Bad read. Stopping");
|
||||||
tar_free(*tar);
|
tar_free(*tar);
|
||||||
*tar = NULL;
|
*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
|
// check if next block is all zeros as well
|
||||||
if (iszeroed((*tar) -> block, 512)){
|
if (iszeroed((*tar) -> block, 512))
|
||||||
|
{
|
||||||
tar_free(*tar);
|
tar_free(*tar);
|
||||||
*tar = NULL;
|
*tar = NULL;
|
||||||
|
|
||||||
// skip to end of record
|
// 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));
|
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
|
// skip over data and unfilled block
|
||||||
unsigned int jump = oct2uint((*tar) -> size, 11);
|
unsigned int jump = oct2uint((*tar) -> size, 11);
|
||||||
if (jump % 512){
|
|
||||||
|
if (jump % 512)
|
||||||
|
{
|
||||||
jump += 512 - (jump % 512);
|
jump += 512 - (jump % 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
// move file descriptor
|
// move file descriptor
|
||||||
offset += 512 + jump;
|
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));
|
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;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tar_write(const int fd, struct tar_t ** archive, const size_t filecount, const char * files[], const char verbosity){
|
int tar_write (const int fd,
|
||||||
if (fd < 0){
|
struct tar_t ** archive,
|
||||||
|
const size_t filecount,
|
||||||
|
const char * files[],
|
||||||
|
const char verbosity)
|
||||||
|
{
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
ERROR("Bad file descriptor");
|
ERROR("Bad file descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!archive){
|
if (!archive)
|
||||||
|
{
|
||||||
ERROR("Bad 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
|
// if there is old data
|
||||||
struct tar_t ** tar = archive;
|
struct tar_t ** tar = archive;
|
||||||
if (*tar){
|
|
||||||
|
if (*tar)
|
||||||
|
{
|
||||||
// skip to last entry
|
// skip to last entry
|
||||||
while (*tar && (*tar) -> next){
|
while (*tar && (*tar) -> next)
|
||||||
|
{
|
||||||
tar = &((*tar) -> next);
|
tar = &((*tar) -> next);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get offset past final entry
|
// get offset past final entry
|
||||||
unsigned int jump = 512 + oct2uint((*tar) -> size, 11);
|
unsigned int jump = 512 + oct2uint((*tar) -> size, 11);
|
||||||
if (jump % 512){
|
if (jump % 512)
|
||||||
|
{
|
||||||
jump += 512 - (jump % 512);
|
jump += 512 - (jump % 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
// move file descriptor
|
// move file descriptor
|
||||||
offset = (*tar) -> begin + jump;
|
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));
|
RC_ERROR("Unable to seek file: %s", strerror(rc));
|
||||||
}
|
}
|
||||||
tar = &((*tar) -> next);
|
tar = &((*tar) -> next);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write entries first
|
// 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_ERROR("Failed to write entries");
|
||||||
}
|
}
|
||||||
|
|
||||||
// write ending data
|
// 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");
|
ERROR("Failed to write end data");
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear original names from data
|
// clear original names from data
|
||||||
tar = archive;
|
tar = archive;
|
||||||
while (*tar){
|
|
||||||
|
while (*tar)
|
||||||
|
{
|
||||||
memset((*tar) -> name, 0, 100);
|
memset((*tar) -> name, 0, 100);
|
||||||
tar = &((*tar) -> next);
|
tar = &((*tar) -> next);
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tar_free(struct tar_t * archive){
|
static void *woof (void *bark)
|
||||||
while (archive){
|
{
|
||||||
|
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;
|
struct tar_t * next = archive -> next;
|
||||||
free(archive);
|
free(archive);
|
||||||
archive = next;
|
archive = next;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int tar_ls(FILE * f, struct tar_t * archive, const size_t filecount, const char * files[], const char verbosity){
|
void tar_free_pool (void)
|
||||||
if (!verbosity){
|
{
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filecount && !files){
|
if (filecount && !files)
|
||||||
|
{
|
||||||
ERROR("Non-zero file count provided, but file list is NULL");
|
ERROR("Non-zero file count provided, but file list is NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (archive){
|
while (archive)
|
||||||
if (ls_entry(f, archive, filecount, files, verbosity) < 0){
|
{
|
||||||
|
if (ls_entry(f, archive, filecount, files, verbosity) < 0)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
archive = archive -> next;
|
archive = archive -> next;
|
||||||
@ -179,23 +237,35 @@ int tar_ls(FILE * f, struct tar_t * archive, const size_t filecount, const char
|
|||||||
return 0;
|
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;
|
int ret = 0;
|
||||||
|
|
||||||
// extract entries with given names
|
// extract entries with given names
|
||||||
if (filecount){
|
if (filecount)
|
||||||
if (!files){
|
{
|
||||||
|
if (!files)
|
||||||
|
{
|
||||||
ERROR("Received non-zero file count but got NULL file list");
|
ERROR("Received non-zero file count but got NULL file list");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (archive){
|
while (archive)
|
||||||
for(size_t i = 0; i < filecount; i++){
|
{
|
||||||
if (!strncmp(archive -> name, files[i], MAX(strlen(archive -> name), strlen(files[i])))){
|
for(size_t i = 0; i < filecount; i++)
|
||||||
if (lseek(fd, archive -> begin, SEEK_SET) == (off_t) (-1)){
|
{
|
||||||
|
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));
|
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;
|
ret = -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -205,15 +275,19 @@ int tar_extract(const int fd, struct tar_t * archive, const size_t filecount, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// extract all
|
// extract all
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
// move offset to beginning
|
// 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));
|
RC_ERROR("Unable to seek file: %s", strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract each entry
|
// extract each entry
|
||||||
while (archive){
|
while (archive)
|
||||||
if (extract_entry(fd, archive, verbosity) < 0){
|
{
|
||||||
|
if (extract_entry(fd, archive, verbosity) < 0)
|
||||||
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
archive = archive -> next;
|
archive = archive -> next;
|
||||||
@ -223,17 +297,24 @@ int tar_extract(const int fd, struct tar_t * archive, const size_t filecount, co
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tar_update(const int fd, struct tar_t ** archive, const size_t filecount, const char * files[], const char verbosity){
|
int tar_update (const int fd,
|
||||||
if (!filecount){
|
struct tar_t ** archive,
|
||||||
|
const size_t filecount,
|
||||||
|
const char * files[],
|
||||||
|
const char verbosity)
|
||||||
|
{
|
||||||
|
if (!filecount)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filecount && !files){
|
if (filecount && !files)
|
||||||
|
{
|
||||||
ERROR("Non-zero file count provided, but file list is NULL");
|
ERROR("Non-zero file count provided, but file list is NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer for subset of files that need to be updated
|
// 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;
|
struct stat st;
|
||||||
int count = 0;
|
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
|
// check each source to see if it was updated
|
||||||
struct tar_t * tar = *archive;
|
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
|
// make sure original file exists
|
||||||
if (lstat(files[i], &st)){
|
if (lstat(files[i], &st))
|
||||||
|
{
|
||||||
all = 0;
|
all = 0;
|
||||||
RC_ERROR("Could not stat %s: %s", files[i], strerror(rc));
|
RC_ERROR("Could not stat %s: %s", files[i], strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the file in the archive
|
// find the file in the archive
|
||||||
struct tar_t * old = exists(tar, files[i], 1);
|
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 there is an older version, check its timestamp
|
||||||
if (old){
|
if (old)
|
||||||
if (st.st_mtime > oct2uint(old -> mtime, 11)){
|
{
|
||||||
|
if (st.st_mtime > oct2uint(old -> mtime, 11))
|
||||||
|
{
|
||||||
strncpy(newer[count++], files[i], strlen(files[i]));
|
strncpy(newer[count++], files[i], strlen(files[i]));
|
||||||
V_PRINT(stdout, "%s", files[i]);
|
V_PRINT(stdout, "%s", files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if there is no older version, just add it
|
// if there is no older version, just add it
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
strncpy(newer[count++], files[i], strlen(files[i]));
|
strncpy(newer[count++], files[i], strlen(files[i]));
|
||||||
V_PRINT(stdout, "%s", files[i]);
|
V_PRINT(stdout, "%s", files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update listed files only
|
// 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");
|
ERROR("Unable to update archive");
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
for(int i = 0; i < count; i++){
|
for(int i = 0; i < count; i++)
|
||||||
free(newer[i]);
|
{
|
||||||
|
// free(newer[i]);
|
||||||
}
|
}
|
||||||
free(newer);
|
// free(newer);
|
||||||
|
|
||||||
return all?0:-1;
|
return all?0:-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tar_remove(const int fd, struct tar_t ** archive, const size_t filecount, const char * files[], const char verbosity){
|
int tar_remove (const int fd, struct tar_t ** archive, const size_t filecount, const char * files[], const char verbosity)
|
||||||
if (fd < 0){
|
{
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// archive has to exist
|
// archive has to exist
|
||||||
if (!archive || !*archive){
|
if (!archive || !*archive)
|
||||||
|
{
|
||||||
ERROR("Got bad archive");
|
ERROR("Got bad archive");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filecount && !files){
|
if (filecount && !files)
|
||||||
|
{
|
||||||
ERROR("Non-zero file count provided, but file list is NULL");
|
ERROR("Non-zero file count provided, but file list is NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filecount){
|
if (!filecount)
|
||||||
|
{
|
||||||
V_PRINT(stderr, "No entries specified");
|
V_PRINT(stderr, "No entries specified");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get file permissions
|
// get file permissions
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (fstat(fd, &st)){
|
if (fstat(fd, &st))
|
||||||
|
{
|
||||||
RC_ERROR("Unable to stat archive: %s", strerror(rc));
|
RC_ERROR("Unable to stat archive: %s", strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset offset of original file
|
// 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));
|
RC_ERROR("Unable to seek file: %s", strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
// find first file to be removed that does not exist
|
// find first file to be removed that does not exist
|
||||||
int ret = 0;
|
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]);
|
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;
|
unsigned int write_offset = 0;
|
||||||
struct tar_t * prev = NULL;
|
struct tar_t * prev = NULL;
|
||||||
struct tar_t * curr = *archive;
|
struct tar_t * curr = *archive;
|
||||||
while(curr){
|
|
||||||
|
while(curr)
|
||||||
|
{
|
||||||
// get original size
|
// get original size
|
||||||
int total = 512;
|
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);
|
total += oct2uint(curr -> size, 11);
|
||||||
if (total % 512){
|
if (total % 512)
|
||||||
|
{
|
||||||
total += 512 - (total % 512);
|
total += 512 - (total % 512);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int match = check_match(curr, filecount, files);
|
const int match = check_match(curr, filecount, files);
|
||||||
|
|
||||||
if (match < 0){
|
if (match < 0)
|
||||||
|
{
|
||||||
ERROR("Match failed");
|
ERROR("Match failed");
|
||||||
}
|
}
|
||||||
else if (!match){
|
else if (!match)
|
||||||
|
{
|
||||||
// if the old data is not in the right place, move it
|
// 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;
|
int got = 0;
|
||||||
while (got < total){
|
while (got < total)
|
||||||
|
{
|
||||||
// go to old data
|
// 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));
|
RC_ERROR("Cannot seek: %s", strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
// copy chunk out
|
// 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");
|
ERROR("Read error");
|
||||||
}
|
}
|
||||||
|
|
||||||
// go to new position
|
// 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));
|
RC_ERROR("Cannot seek: %s", strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
// write data in
|
// write data in
|
||||||
if (write_size(fd, buf, 512) != 512){
|
if (write_size(fd, buf, 512) != 512)
|
||||||
|
{
|
||||||
RC_ERROR("Write error: %s", strerror(rc));
|
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;
|
write_offset += 512;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
read_offset += total;
|
read_offset += total;
|
||||||
write_offset += total;
|
write_offset += total;
|
||||||
|
|
||||||
// skip past data
|
// 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));
|
RC_ERROR("Cannot seek: %s", strerror(rc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prev = curr;
|
prev = curr;
|
||||||
curr = curr -> next;
|
curr = curr -> next;
|
||||||
}
|
}
|
||||||
else{// if name matches, skip the data
|
else
|
||||||
struct tar_t * tmp = curr;
|
{// if name matches, skip the data
|
||||||
if (!prev){
|
// struct tar_t * tmp = curr;
|
||||||
|
if (!prev)
|
||||||
|
{
|
||||||
*archive = curr -> next;
|
*archive = curr -> next;
|
||||||
if (*archive){
|
if (*archive)
|
||||||
|
{
|
||||||
(*archive) -> begin = 0;
|
(*archive) -> begin = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
prev -> next = curr -> next;
|
prev -> next = curr -> next;
|
||||||
|
|
||||||
if (prev -> next){
|
if (prev -> next)
|
||||||
|
{
|
||||||
prev -> next -> begin = curr -> begin;
|
prev -> next -> begin = curr -> begin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
curr = curr -> next;
|
curr = curr -> next;
|
||||||
free(tmp);
|
// free(tmp);
|
||||||
|
|
||||||
// next read starts after current entry
|
// next read starts after current entry
|
||||||
read_offset += total;
|
read_offset += total;
|
||||||
@ -407,40 +526,50 @@ int tar_remove(const int fd, struct tar_t ** archive, const size_t filecount, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resize file
|
// resize file
|
||||||
if (ftruncate(fd, write_offset) < 0){
|
if (ftruncate(fd, write_offset) < 0)
|
||||||
|
{
|
||||||
RC_ERROR("Could not truncate file: %s", strerror(rc));
|
RC_ERROR("Could not truncate file: %s", strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add end data
|
// 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");
|
V_PRINT(stderr, "Error: Could not close file");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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;
|
struct stat st;
|
||||||
while (archive){
|
while (archive)
|
||||||
|
{
|
||||||
V_PRINT(f, "%s", archive -> name);
|
V_PRINT(f, "%s", archive -> name);
|
||||||
|
|
||||||
// if not found, print error
|
// if not found, print error
|
||||||
if (lstat(archive -> name, &st)){
|
if (lstat(archive -> name, &st))
|
||||||
|
{
|
||||||
int rc = errno;
|
int rc = errno;
|
||||||
fprintf(f, "Could not ");
|
fprintf(f, "Could not ");
|
||||||
if (archive -> type == SYMLINK){
|
if (archive -> type == SYMLINK)
|
||||||
|
{
|
||||||
fprintf(f, "readlink");
|
fprintf(f, "readlink");
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
fprintf(f, "stat");
|
fprintf(f, "stat");
|
||||||
}
|
}
|
||||||
fprintf(f, " %s: %s", archive -> name, strerror(rc));
|
fprintf(f, " %s: %s", archive -> name, strerror(rc));
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
if (st.st_mtime != oct2uint(archive -> mtime, 11)){
|
{
|
||||||
|
if (st.st_mtime != oct2uint(archive -> mtime, 11))
|
||||||
|
{
|
||||||
fprintf(f, "%s: Mod time differs", archive -> name);
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int print_entry_metadata(FILE * f, struct tar_t * entry){
|
int print_entry_metadata(FILE * f, struct tar_t * entry)
|
||||||
|
{
|
||||||
if (!entry){
|
if (!entry){
|
||||||
return -1;
|
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");
|
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);
|
strncpy(path, entry -> name, len);
|
||||||
|
|
||||||
// remove file from path
|
// 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){
|
if (recursive_mkdir(path, DEFAULT_DIR_MODE) < 0){
|
||||||
V_PRINT(stderr, "Could not make directory %s", path);
|
V_PRINT(stderr, "Could not make directory %s", path);
|
||||||
free(path);
|
// free(path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
free(path);
|
// free(path);
|
||||||
|
|
||||||
// create file
|
// create file
|
||||||
const unsigned int size = oct2uint(entry -> size, 11);
|
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){
|
if ((*tar) -> type == DIRECTORY){
|
||||||
// save parent directory name (source will change)
|
// save parent directory name (source will change)
|
||||||
const size_t len = strlen((*tar) -> name);
|
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);
|
strncpy(parent, (*tar) -> name, len);
|
||||||
|
|
||||||
// add a '/' character to the end
|
// 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 ..
|
// if not special directories . and ..
|
||||||
const size_t sublen = strlen(dir -> d_name);
|
const size_t sublen = strlen(dir -> d_name);
|
||||||
if (strncmp(dir -> d_name, ".", sublen) && strncmp(dir -> d_name, "..", sublen)){
|
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);
|
sprintf(path, "%s/%s", parent, dir -> d_name);
|
||||||
|
|
||||||
// recursively write each subdirectory
|
// 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);
|
tar = &((*tar) -> next);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(path);
|
// free(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(d);
|
closedir(d);
|
||||||
|
|
||||||
free(parent);
|
// free(parent);
|
||||||
|
|
||||||
tar = &((*tar) -> next);
|
tar = &((*tar) -> next);
|
||||||
}
|
}
|
||||||
@ -1064,7 +1195,7 @@ int recursive_mkdir(const char * dir, const unsigned int mode){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * path = calloc(len + 1, sizeof(char));
|
char * path = qcalloc (QM_TAR, len + 1, sizeof(char));
|
||||||
strncpy(path, dir, len);
|
strncpy(path, dir, len);
|
||||||
|
|
||||||
// remove last '/'
|
// 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));
|
EXIST_ERROR("Could not create directory %s: %s", path, strerror(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
free(path);
|
// free(path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
0
src/util.c
Executable file → Normal file
0
src/util.c
Executable file → Normal file
0
src/vars.c
Executable file → Normal file
0
src/vars.c
Executable file → Normal file
18
src/x3basic.c
Normal file
18
src/x3basic.c
Normal file
@ -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"
|
1395
src/x3mem.c
Normal file
1395
src/x3mem.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user