diff --git a/Makefile b/Makefile index a0497c7..9597a66 100755 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # (C) Copyright 2014-2021 Chris Dorman, some rights reserved (GPLv2) # Some changes and tweaks from Menchers -VERSION = \"0.6.0\" +VERSION = \"0.7.0\" VERSION_EXTRA = \"$(EXTRA)\" PREFIX ?= /usr diff --git a/docs/README.txt b/docs/README.txt index b1efb08..a5f6387 100644 --- a/docs/README.txt +++ b/docs/README.txt @@ -151,6 +151,12 @@ Changelog Changes between version bumps in SlideScript. Hoping to have a lightweight top-down scripting language by V1.0.0 release! From there it will be molding and preserving the art. +* V0.7.0 + * Ditched old LZ77 example code, and went with a more polished LZ78 () + * Converted dynamic memory management layer into LZ78 engine and tar code. + * Compress & Decompress are both fully functioning. + * Tidies, and polishing (pushing more for that full lenguage) + * V0.6.0 * Multiple dynamic memory bug fixes, SlideScript is 99% dynamic on memory use * Included if, and ifn functions for comp, isfile, isdir, etc return values. diff --git a/src/inc/x3mem.h b/src/inc/x3mem.h index a16bd16..f794ca8 100644 --- a/src/inc/x3mem.h +++ b/src/inc/x3mem.h @@ -261,6 +261,7 @@ typedef struct qlist QLIST; /* typedef the list header */ /* a QLIST pointer and as the QLIST entry itself. */ UX3_EXT QLIST QM_GEN [ONE]; /* general-purpose QLIST */ +UX3_EXT QLIST QM_LZ [ONE]; /* ------------------------------------------------------------ */ diff --git a/src/inc/x3mem.h~ b/src/inc/x3mem.h~ new file mode 100644 index 0000000..a16bd16 --- /dev/null +++ b/src/inc/x3mem.h~ @@ -0,0 +1,330 @@ +/* ------------------------------------------------------------ */ +/* 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 "deps.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/lz78/lz78.c b/src/lz78/lz78.c index f988664..ada0690 100644 --- a/src/lz78/lz78.c +++ b/src/lz78/lz78.c @@ -24,6 +24,10 @@ #include #include "lz78.h" +#include "../inc/x3mem.h" + +UX3_EXT QLIST QM_LZ [ONE]; // Dynamic-memory QLIST + /* Code used to represent an EOF */ #define DICT_CODE_EOF 256 @@ -168,14 +172,13 @@ uint8_t bitlen(uint32_t i) { } ht_dictionary* ht_dictionary_new(uint32_t d_size) { - ht_dictionary* dict = malloc(sizeof(ht_dictionary)); + ht_dictionary* dict = qmalloc(QM_LZ, sizeof(ht_dictionary)); if (dict == NULL) return NULL; d_size = DICT_LIMIT(d_size); - dict->root = calloc(1, sizeof(ht_entry) * d_size); + dict->root = qcalloc(QM_LZ, 1, sizeof(ht_entry) * d_size); if (dict->root == NULL) { - free(dict); return NULL; } else { dict->d_size = d_size; @@ -243,22 +246,19 @@ void ht_dictionary_reset(ht_dictionary* d) { void ht_dictionary_destroy(ht_dictionary* d) { if (d != NULL) { - //free(d); - printf("I SHOULD BE FREEING MEMORY RIGHT NOW!\n"); - // This is obviously going to be fixed in due course. + //qfree(d); } } dictionary* dictionary_new(uint32_t d_size) { uint16_t i; - dictionary* dict = malloc(sizeof(dictionary) + d_size); + dictionary* dict = qmalloc(QM_LZ, sizeof(dictionary) + d_size); if (dict == NULL) return NULL; d_size = DICT_LIMIT(d_size); - dict->root = malloc(sizeof(entry) * d_size); + dict->root = qmalloc(QM_LZ, sizeof(entry) * d_size); if (dict->root == NULL) { - free(dict); return NULL; } @@ -310,8 +310,7 @@ void dictionary_reset(dictionary* d) { void dictionary_destroy(dictionary* d) { if (d != NULL) { - free(d->root); - free(d); + //qfree(d); } } @@ -441,7 +440,7 @@ lz78_instance* lz78_new(uint8_t cmode, uint32_t dsize) { lz78_d* d; int max_dim = (sizeof(lz78_c) > sizeof(lz78_d)) ? sizeof(lz78_c) : sizeof(lz78_d); - i = malloc(sizeof(lz78_instance) + max_dim); + i = qmalloc(QM_LZ, (sizeof(lz78_instance) + max_dim)); if (i == NULL) return NULL; i->mode = cmode; @@ -454,13 +453,13 @@ lz78_instance* lz78_new(uint8_t cmode, uint32_t dsize) { c->completed = 0; c->main = ht_dictionary_new(c->d_size); if (c->main == NULL) { - free(i); + //qfree(i); return NULL; } c->secondary = ht_dictionary_new(c->d_size); if (c->secondary == NULL) { ht_dictionary_destroy(c->main); - free(i); + //qfree(i); return NULL; } c->bitbuf = DICT_CODE_START; @@ -473,7 +472,7 @@ lz78_instance* lz78_new(uint8_t cmode, uint32_t dsize) { d->completed = 0; d->main = dictionary_new(DICT_SIZE_MIN); if (d->main == NULL) { - free(i); + //qfree(i); return NULL; } return i; @@ -630,13 +629,13 @@ void lz78_destroy(lz78_instance *lz78) { case LZ78_MODE_DECOMPRESS: d = (lz78_d*)&lz78->state; - if (d != NULL) { - //dictionary_destroy(d->main); + if (d != NULL && d->main != NULL) { + dictionary_destroy(d->main); ht_dictionary_destroy(d->secondary); } break; } - free(lz78); + qflush(QM_LZ); } } diff --git a/src/lz78/wrapper.c b/src/lz78/wrapper.c index 1d90e36..52db009 100644 --- a/src/lz78/wrapper.c +++ b/src/lz78/wrapper.c @@ -22,6 +22,7 @@ #include #include "wrapper.h" +#include "../inc/x3mem.h" /* Structure representing the type of algorithm */ struct __algorithm { @@ -161,7 +162,7 @@ void wrapper_perror() { } wrapper* wrapper_new(uint8_t w_mode, uint8_t w_type, char* argv) { - wrapper* w = malloc(sizeof(wrapper)); + wrapper* w = qmalloc(QM_LZ, sizeof(wrapper)); if (w == NULL) return NULL; @@ -174,14 +175,14 @@ wrapper* wrapper_new(uint8_t w_mode, uint8_t w_type, char* argv) { break; default: - free(w); + qfree(w); return NULL; } if (w->data) return w; else { - free(w); + qfree(w); return NULL; } } @@ -198,7 +199,7 @@ void wrapper_destroy(wrapper* w) { default: return; } - free(w); + qflush(QM_LZ); } uint8_t wrapper_compress(wrapper* w, char* input, char* output) {