|
|
|
mdx_util
- Memory Descriptor (MDX) UtilitiesThe MDX_UTIL package provides functions for creating and manipulating dynamically sized and dynamically growing memory regions.
This package was inspired by my SDX_UTIL string descriptor package which, in turn, was inspired by VAX/VMS descriptors which consisted of (i) 16 bits of flags including the data type of the object being described, (ii) the 16-bit length of the object, and (iii) the 32-bit address of the object.
While I originally expected MDX_UTIL to be a simple, byte-oriented clone of SDX_UTIL, I unfortunately included the ability to treat a memory region as an array of fixed-size elements — a C++ STL vector, if you wish, and my most common use case. Part way into the writing of the package, I was torn between putting the array functionality into a separate package, say ADX_UTIL, or to keep going and decide later after some experience with an array-capable MDX_UTIL package.
I chose the latter course,
for better or worse,
although I'm bothered all the same,
of course, of course.(We miss you, Mr. Ed!)
A sequence of bytes is simply an array of one-byte elements in MDX_UTIL's
view. The following example creates a zero-length memory descriptor (whose
default element size is one byte) and concatenates 50 copies of a 13-byte
sequence of bytes, "Hello, World!" in this case. There is no significance
aside from convenience to my using a string here; one could just as easily
create a 13-byte array of arbitrary, "!isprint()
able" bytes.
Note that there are no separators between the sequences of bytes. The example appends the 13-byte sequences end-on-end, 50 times, to the initially empty memory buffer. The result is 650 (13*50) bytes of data. The example adds a NUL terminator as the 651st byte to produce an actual string in the I-could-care-less memory buffer.
#include <stdio.h> -- Standard I/O definitions. #include <string.h> -- Standard C string functions. #include "mdx_util.h" -- Memory Descriptor utilities. MemoryDx pbx ; size_t i ; ... mdxCreate (NULL, 0, MdxDynamic, &pbx) ; for (i = 0 ; i < 50 ; i++) { mdxAddS (pbx, false, -- Add sequence of bytes. "Hello, World!", strlen ("Hello, World!")) ; } mdxAddB (pbx, 0) ; -- Add NUL byte. printf ("Complete region: \"%s\"\n", (char *) mdxRegionP (pbx, 0)) ; mdxDestroy (pbx) ;
Alternatively, don't add the NUL byte, but retrieve the length of 650:
printf ("Complete region: \"%*s\"\n", (int) mdxLength (descriptor), (char *) mdxRegionP (pbx, 0)) ;
(NOTE: The example below is very awkward, as you will see. Use the ADX_UTIL package instead — it handles all the bookkeeping and housekeeping for you.)
A memory region can also be treated as an array of fixed-size elements. The following example reads a complete text file into an array of SDX_UTIL string descriptors, one element per line, a convenient framework for a simple text editor.
#include "mdx_util.h" -- Memory Descriptor utilities. #include "sdx_util.h" -- String Descriptor utilities. FILE *file ; size_t length, numLines = 0 ; ssize_t count ; MemoryDx mdx ; StringDx *element30, sdx ; mdxCreate (NULL, 0, MdxDynamic, &mdx) ; mdxElementSize (mdx, (ssize_t) sizeof (StringDx)) ; file = fopen ("example.txt", "r") ; for ( ; ; ) { -- Break on EOF or error. sdxCreate (NULL, -1, SdxDynamic, &sdx) ; if (sdxReadLine (file, sdx, &count) || (count < 1)) break ; mdxAddS (mdx, false, (const void *) &sdx, sizeof (StringDx)) ; numLines++ ; } fclose (file) ; --------------------- -- Access line 20. -- --------------------- printf ("Line 20: \"%s\"\n", sdxStringZ (*((StringDx) mdxRegionP (mdx, 20-1)))) ; ------------------------------------------------ -- Insert a line between line 30 and line 31. -- ------------------------------------------------ length = mdxLength (mdx) ; -- Make room for new line. mdxSetLength (mdx, length + 1) ; element30 = (StringDx *) mdxRegionP (mdx, 30-1) ; memmove ((void *) &element30[2], (const void *) &element30[1], (length - 30) * sizeof (StringDx)) ; -- Create and store new line. sdxCreate ("I'm the new line 31!!!", -1, SdxVolatile, &sdx) ; element30[1] = sdx ; ------------------------- -- Delete lines 41-45. -- ------------------------- element40 = (StringDx *) mdxRegionP (mdx, 40-1) ; -- Destroy descriptors being deleted for (i = 1 ; i <= 5 ; i++) { -- (or save them in cut/undo buffer). sdxDestroy (element40[i]) ; } length = mdxLength (mdx) ; -- Move lines 46..n down to line 41. memmove ((void *) &element40[1], (const void *) &element40[6], (length - 45) * sizeof (StringDx)) ; -- Decrease region length by 5 lines. mdxSetLength (mdx, length - (45-40)) ;
Hmmm, functional, but not pretty. Use the ADX_UTIL package instead!
Note on the example above: the memory region is an array of
pointers (StringDx
) to string descriptors
(_StringDx
), not an array of string descriptors themselves.
mdxAddB()
- adds a byte to a described memory region.mdxAddS()
- adds a sequence of bytes to a described memory region.mdxAlignment()
- sets or gets the byte boundary for alignment.mdxCopy()
- copy the contents of one memory descriptor to another.mdxCreate()
- creates a memory descriptor.mdxDestroy()
- destroys a memory descriptor.mdxDuplicate()
- duplicates a memory descriptor.mdxErase()
- erases the contents of a memory descriptor.mdxGrow()
- increases the size of a descriptor's memory region.mdxIncrement()
- sets or gets the block size used to expand regions.mdxLength()
- returns the length of a described memory region.mdxOwn()
- takes ownership of a described memory region.mdxRegionP()
- returns a pointer to a described memory region.mdxSetLength()
- sets the length of a described memory region.mdx_util.c
mdx_util.h
(See libgpl
for the complete source, including support routines and build files.)