My C utilitiy library is just one of my
computer related personal projects.
This project is
C Utility Library
I have a bunch of data abstractions that I tend to
use when I write C code that I have collected together
into my own personal C utility library.
All of the code in this library has the following
Copyright (c) 199x by Wayne C. Gramlich.
All rights reserved.
Permission to use, copy, modify, distribute, and
sell this software for any purpose is hereby
granted without fee provided that the above
copyright notice and this permission are retained.
The author makes no representations about the
suitability of this software for any purpose.
It is provided "as is" without express or implied
This is basically the same copyright notice used for
the code in the X11 release. Basically all it says
is that you are free to use the code and you do not
owe me a dime; likewise if you do not like the code
for any reason, I do not owe you a dime. That is all
there is to it.
For each data abstraction there tends to be 4 or 5 files
that I use for declaration, implementation and testing:
In addition to the data abstraction files, I have:
A definition header contains the actual structure
definitions that implement data type. In general,
a definition header should only be included by the
code that implements the data type, but there are
occasional instances where it is necessary to
violate abstraction boundaries. Definition header
files have a suffix of `_defs.h'.
An exports header contains the prototypes for
the exported global routines for the datatype.
It is legitimate for any source file to include
an exports header file. Exports header files
have a suffix of `_exports.h'.
A types header contains C typedefs for the data
type. A types header file can be legitimately
included by either other header files or by any
C source file. Types header files have a suffix
The reason why types header files are not rolled
into exports header files is because it is really
to get a cycle of routine prototypes that need
type definitions that have not been defined yet.
The only way to ensure that these cycles do not
occur is to have all C typedef occur before any
Implementation Source File
The implementation source file contains the routine
definitions that implement the data abstraction.
Source files end with a plain `.c' suffix.
A test file is a C program that exercises a
data abstraction to ensure that it works reasonably.
Test files end with a suffix of `_test.c'.
It is a common practice to make header files be
standalone so that they do not need any other
header files to be pre-included for use.
Unfortunately, the practice of stand-alone header
files predates the Unix system header files. So
for each Unix header file that I use, I have created
a simple wrapper header file that ensures that
it is a standalone header file. Wrapper header
files have a prefix of `unix_'.
There a few miscellaneous files that do not fit
any of the criteria above.
As with any effort, if I were going to do it again,
I would do some things differently. However, my
overall plan is to stop writing code in C entirely,
and write all new code for my personal projects in
my own personal programming language
(STIPPLE). Thus, I have no intentions of fixing
any of the architectual problems associated with this
C utility library.
The data types provided by the C utility library are
(in alphabetical order):
While it seemed like a good idea at the time
I wrote it, I tend not to write code that uses
attribute value lists. Hence, I've never
really used this package.
I wrote up some generic error routines. I used
these some of the time.
When I was writing the first
STIPPLE compiler in C I incorrectly decided
that the standard Unix file I/O library would
not correctly keep track of position, so I wrote
my own file I/O package. This was a complete
I have found hash tables to be incredibly useful
in all of the code that I write. There are
two kinds -- ones that implement a set abstraction
and ones that implement a key-value pair
abstraction. This one implements the set
Back in 1990 when I first started writing this
library I had grandious plans that I would be
very careful to arrange that memory to preserve
locality of reference. This heap package was
the mechanism by which I was going to achieve
this locality. Well, it was a very bad idea.
There are no real tools to help figure out memory
locality issues. Furthermore, by making memory
allocation an explicit argument, it cluttered
up all of the interfaces that used it. What's
worse is that this bad idea managed to make it
STIPPLE where I'm going to have to tediously
rip it out. Sigh.
There are a few routines for working with
integers that I use all the time, so they
are in the utility library.
I am a strong believer of strongly typed
languages. The type rules implemented by
lint are significantly stickier than standard
ANSI-C. So I tend to run my code through
lint to see what problems it uncovers. In
order to get lint to not complain about some
standard routines in libc, I declare them in
a separate "C" file and compile it into a .ln
file with line. My goal is to have lint emit
no warnings and no errors.
I find the number of string routines in libc
to be quite inadequate. So I've had to define
a number of my own.
For a while I thought I was going to use dynamic
strings for everything, but eventually decided
it was a real hassle not being able to easily
print out the contents of a string in the debugger.
This abstraction is used here and there in some
of the older code, but is not used in the newer
I find key-value hash tables to be extremely
Vector (Dynamic Array)
The vector data type is probably the most
commonly used type from this package.
Write buffers are used to implement the dynamic
strings and file I/O. Since I don't think either
of those types were very successful, I do not
think this data types is very successful either.
source and header files are available.
Copyright (c) 1995-1998
Wayne C. Gramlich All rights reserved.