*Apologies to Mark Knopfler!
My library software follows certain conventions that you might find useful to know when using or examining the software:
In general, each source file ("
a package of functions that operate on a particular type of object;
e.g., a network connection, a hash table, etc. Associated with each
package is a header file ("
defines an opaque handle for objects of the given type, any global
variables, and function prototypes for public functions in the package.
Naming conventions for the functions that operate on objects are as follows:
objCreate()creates a particular type of object and returns a handle that is passed to other functions in the package.
objDestroy()destroys an object.
objDelete()add and delete items in a container object; e.g., elements of a list, entries in a hash table, etc.
objGet()retrieve items by name and by index, respectively, from a container object.
I/O packages typically include the following functions:
objClose()create and destroy, respectively, objects of the given type.
objFd()returns the underlying UNIX file descriptor for an I/O object.
objIsUp()poll an I/O object.
objName()returns the name of an I/O object.
objWrite()perform actual I/O on an object.
Most of the library functions return an
code as their value: zero indicates no error,
indicates an invalid argument, etc.
Most of the packages have a global
variable that can be set to a non-zero value to enable debug output to
stdout. There's usually a command-line option,
-debug", to enable normal debug output and
-Debug" to enable more detailed output when applicable.
LGI macro below.)
aperror() is a
perror(3)-like function that formats and prints a
user error message on
stderr, followed by the
system error message corresponding to the current value of
aperror() output is enabled
by setting a global variable,
a non-zero value. (See the
LGE macro below.)
My library functions use
aperror() to report errors
(in addition to returning an error code). A rather primitive
mechanism for reporting errors? You betcha — but at
least it's there!
aperror_print is initialized to zero, you
normally won't see any error messages. My programs sometimes
aperror() output during initialization
(when configuration errors and such are most likely to occur)
and disable it thereafter.
With respect to the
obj_util_debug debug logging
aperror() error reporting described above, I later
implemented configurable, C Preprocessor-based error and debug logging.
Macros defined in
are combined in high-level macros
LGI for logging information
LGE for logging errors; for example:
LGI "(rex_match) Scanning \"%s\" for \"%s\"\n", &target[first], pattern->expression) ; ... LGE "(rex_replace) Error duplicating source string, \"%s\"\nstrdup: ", source) ;
These macros were inspired by similar macros in the
GNU Nana package.
I couldn't use Nana itself because it depends on GCC's extension for
C Preprocessor macros with variable numbers of arguments and not all
the platforms I was building on supported this extension. Hence my
syntax of, for example, "
LGI format, arg1, ...,
argN) ;", with a trailing parenthesis but no leading
These macros have worked out well for me, as they have supported my
personally use, as well as the totally different error and information
logging mechanism we used on a large company project.
More to follow when I think of it ...
In writing my software, I try to make it as portable as possible. I make use
of ANSI C libraries and header files as much as I can. Function declarations
are made in both ANSI C and non-ANSI C form, so the code will compile whether
your compiler is ANSI C-compliant or not. I've attempted to isolate compiler
and OS dependencies in a header file,
except for some networking and time definitions that are found in
The major operating systems I've built and used my software on are:
In previous years, earlier incarnations of my software were built and run on the following OSes: SunOS (on 68K and SPARC platforms), HP/UX, IBM's AIX (we had a single PC RT in the late 1980s), Lynx OS 2.4 (on a PowerPC), PalmOS (68k), and VxWorks (circa 1990 and again in 1994-1996).
I currently build/use my software on:
I've tried to write portable software. I use the Linux and Cygwin64 versions daily. I build the Windows versions periodically, but since I use Cygwin64, I don't exercise the Windows versions; in particular, I haven't explored my software's behavior in the Windows IL32P64 data model at all.
On Windows, I build static libraries and link them to console applications. The libraries are small. so there's no advantage to my figuring out DLLs yet.
The software distributions generally include the following Makefiles. The most
up-to-date Makefile is always
Makefile.linux, so start with it as
a model for new Makefiles:
Makefile.linux- for building under Linux with GNU MAKE and the default C compiler (usually gcc or clang).
Makefile.bsd- for building under BSD UNIX with BSD MAKE and the default C compiler.
Makefile.cygwin- for building under Cygwin using the default C compiler.
Makefile.ndk- for building Android libraries and command-line applications using the Android NDK tool chain (CLANG for ARM).
Makefile.nds- for building Nintendo DS libraries and standard I/O applications using the devkitPro tool chain (GCC for ARM).
Makefile.palm68k- for building PalmOS libraries and standard I/O applications under Linux using Chuan Ji's prc-tools-remix (GCC for Palm OS).
*.vcxproj- Microsoft Visual Studio solution and project files, respectively.
You might also encounter the following Makefiles which I haven't used in years:
Makefile.solaris- for building under Solaris using cc or gcc. Support for cc may not work (or be missing from newer Makefiles) since I no longer have access to the earlier (or any) Sun machines.
Makefile.tcc- for building under Linux using the blindingly fast Tiny C Compiler (TCC). Way back when, I submitted a bug report regarding the layout of fields within unions or structures that affected my CORBA code. The bug was supposedly fixed, but it appeared to still be present in later versions of the compiler. Regardless, TCC is amazing!
vaxc.com- for building under VAX/VMS. A semi-handcrafted batch file to build the code. The last VAX I had available for testing didn't have MMS (?) installed. (As an example, here's
vaxc.comfor my General Purpose library.)
With respect to PalmOS, I built my libraries with PRC-Tools (and now prc-tools-remix) and I created a number of StdIOPalm applications that use the libraries. Click on the Palm Pilot thumbnail to see the screen output from a port scanner, scanet, running in the POSE emulator. A StdIOPalm application is a command-line application that is run from/in the Palm's "Network Log" screen.
Thanks to the following people for bug and porting reports:
rex_wild(); if I was Donald Knuth, I'd have paid him for it!
I don't have the changes required for the various ports, but at least I know it's possible to port the code to the various platforms with relatively little trouble. My apologies to anyone I've left out, including those who reported bugs (e.g., in the quadword utilities and in the IPC utilities) before I started keeping a list here.
Last Update: Thu Nov 23 21:38:04 2023
Licensing: The CSOFT libraries and applications are covered by the MIT License. Basically, you are free to use the software however you see fit, in commercial or non-commerical applications. I only ask that, if your time and inclination permit, you report any bugs or portability problems you encounter. Suggestions for improvements and enhancements are welcome, but I do not guarantee I will act upon them.
opt_util- full-word option scanning package for UNIX-style command lines or strings.
gq_util- generalized queue (deque) package.
gsc_util- generic depth-first and breadth-first graph search package.
hash_util- hash table creation/search package.
list_util- generic list handling package.
nnl_util- name/number lookup package.
tpl_util- N-tuple creation and element retrieval.
perror(3)-like error reporting function.
adx_util- dynamic array handling with descriptors.
mdx_util- dynamic memory handling with descriptors.
meo_util- memory operations.
get_util- miscellaneous string scanning functions.
rex_util- full-featured regular expression matching and substitution package.
sdx_util- dynamic string handling with descriptors.
sto_util- length-limited string-to-number conversion functions.
str_util- miscellaneous string handling functions.
utf_util- Unicode Transformation Format (UTF) functions.
wcs_util- wide-character string handling functions.
bmw_util- benchmarking package.
ts_util- POSIX timespec manipulation package.
tv_util- UNIX timeval manipulation package.
bit_util- bit manipulation functions.
id3_util- ID3 tag access functions.
nbr_util- Prime numbers and fast square roots.
srt_util- SubRip Text (SRT) subtitle files.
xqt_util- shell execution package (high-level interface to UNIX shell or VMS CLI).
The following packages provide high-level, but powerful, interfaces to TCP/IP and UDP/IP networking:
tcp_util- high-level interface for TCP/IP network socket I/O.
udp_util- high-level interface for UDP/IP network socket I/O.
And the following packages implement higher-level protocols layered on top of the TCP_UTIL package:
ins_util- IN-SNEC CORTEX utilities.
lfn_util- high-level interface for LF-terminated network I/O.
nft_util- FTP server framework (UNIX, VMS, and VxWorks).
xnet_util- high-level interface to
xdr(3)-based network I/O.
The IOX package simplifies the writing of I/O-event-driven applications (e.g., network servers):
iox_util- I/O and timer event dispatcher.
port_util- simple listening ports for IOX dispatcher-based network servers.
The remaining packages are an assortment of networking support functions:
net_util- miscellaneous network functions.
skt_util- socket support functions.
xdr_util- XDR functions and utilities.
These three packages implement version-independent messages as described in Appendix B of Robert Martin's Designing Object-Oriented C++ Applications Using the Booch Method. (What he calls attributed data trees, I call name/value lists.) The VIM packages were inspired by Mike Maloney's named variables-based C++ libary which we used in one of our company's products. VIM network streams are layered on top of the TCP_UTIL package.
nvp_util- name/value pairs.
nvl_util- lists of name/value pairs.
vim_util- version-independent message streams.
The CORBA-Lite packages provide a lightweight implementation of CORBA TCP/IP messaging.
coli_util- CORBA messaging functions.
comx_util- CORBA marshaling functions.
gimx_util- GIOP marshaling utilities.
iiop_util- Internet Inter-ORB Protocol (IIOP) streams.
The following programs were used in both Versions 3 and 4 of our system. Cornet, dumpaev, milk, and the descendants of epcot and entice were used extensively. I wrote dssi, eniac, and mcci just for the heck of it and they were probably run just once to see if they worked!
No links to code — I just wanted the hand-drawn icons to brighten up the page! (Incidentally, I drew the icons with SibCode's Junior Icon Editor. I purchased JIE at the time but it is now available for free, having been replaced by the not-for-free, but more up-to-date and more powerful Sib Icon Editor and Sib Icon Studio.)
The following programs were specific to Version 3 of our system. They're all command-line tools and were a lot quicker and easier to use during testing than having to bring up the ponderous, X Windows GUIs to effect or monitor some action. I rarely used the last two, stamp and v3net.
The following programs were clients for our CORBA-based Version 4 system. As with the Version 3 programs above, these are all command-line tools and were a lot quicker and easier to use during testing than having to bring up the ponderous, Microsoft Windows GUIs to effect or monitor some action. The database clients, cdc and db4u, were very useful because they exhaustively retrieved every bit of information from the database servers, thus exercising them more than our actual system did. The point service client, psic, could request, retrieve, and display running updates of some or all of the available telemetry and non-telemetry points. The test team used to run it in parallel with the test system so that they could determine if a point-service problem was on the GUI client side of the system or the Unix server side.