srcstr. This argument may be
0, in that case, srcstr must be 0-terminated and
the length will be determined in base64_decode()
int. When non-0, the
length of the decoded buffer will be stored in this
value.cmm_free() to
de-allocate it.
See also base64_encode().
unsigned char *encoded;
char *decoded;
encoded = base64_encode ("Hello World!", 0, 0);
decoded = base64_decode (encoded, 0, 0);
if (strcmp ("Hello World!", decoded))
error ("Something went very wrong!\n");
The following code snippet decodes an external buffer encbuf, having
length enclen. The result is stored in the integer declen.
extern unsigned char *encbuf;
extern int enclen;
int declen;
char *decbuf;
base64_decode (encbuf, enclen, &declen);
printf ("Encoded buffer having %d bytes "
"is now decoded into %d bytes\n",
enclen, declen);
base64_encode will self-determine
the length by assuming that str is a 0-terminated
string.
int. When non-0, this value
` will be set to the length of the encoded buffer.cmm_free() to
de-allocate it. The encoded buffer is formatted in such a way that the
lines have a maximum of 76 characters. When necessary, the padding
character = is used.
See also base64_decode().
Hello World.
char *ret = base64_encode ("Hello World!", 0, 0);
printf ("'Hello World' leads to: %s\n", ret);
cmm_free (ret);
The following code snippet encodes an arbitrary-length buffer buf
having the length buflen.
The buffer does not need to be 0-terminated. Also, the length of the
output is stored.
extern char *buf;
extern int buflen;
int retlen;
char *ret;
ret = base64_encode (buf, buflen, &retlen);
printf ("Buffer having length %d expands to %d "
"when encoded.\n", buflen, retlen);
tabsize is the hash table size
BTHash structure, usable in other
bth_*() functions
BTHash structure (allocated in memory)
and returns a pointer to it. The structure is then usable in other
bth_*() functions.
The functions of the bth_*() family implement a hash algorithm for
strings, where the hash table points to binary trees. BTHash-stored
strings therefore have a storage that never runs out (except for
out-of-memory errors). The relevant functions are:
bth_init(int tabsz) - initializes;
bth_insert(char const *str, void *data, int dlen) -
inserts a string (key) and data;
bth_lookup(char const *str) - looks up given a keybth_*() functions.
h is a pointer to an initialized BTHash structure, str
identifies the information to insert, data is the information to
insert, having length dlen
BTNode, duplicates the given information
in the node, and stores a reference to the node in the hash-table
specified by h.
If a node identified by the same str already exists, then its
previous data contents are overwritten.
Note that the argument h must point to an initialized BTHash
structure; use function bth_init() to initialize it.
BTHash structure, having the read buffer as key and an
order counter as the data. Finally, the identifier hello is looked
up. When found, its order number is shown.
int main (int argc, char **argv) {
char buf[200], *cp;
int count = 0, *data;
BTNode *node;
BTHash *h;
h = bth_init (50);
while (1) {
fgets (buf, 199, stdin);
if (feof (stdin))
break;
if ( (cp = strchr (buf, '\n')) )
*cp = 0;
++count;
node = bth_insert (h, buf, &count, sizeof(int));
}
if ( (data = bth_lookup (h, "hello")) )
printf ("hello: %d\n", *data);
return (0);
}
str identifies the data to look up
str failed to
match a node
h.
The return value 0 signals that no match was made.
A non-zero return value is a void*, pointing to the data area that
was stored with the identifier str. Note that data doesn't
point to the node itself, but to an amorph buffer. The caller is
responsible for typecasting the return value into a meaningful pointer.
bth_insert().
top is the tree root, str is the key for the node to insert,
data points to a data buffer 'belonging' to the node, dlen is the
length of the data buffer
top. The node is identified by its key str, and the data area
identified by data and dlen is included in the node.
When a node with the identifier str already exists, then the node's
data are overwritten with the specified data.
The internal node organization is very simple: each node has a left
and right pointer, a char *str pointing to the key,
and a void *data. Note that the data are
referred to by a void*, it is the caller's responsibility to
typecast to the right format during traversal. Note also that there's a
function btn_lookup() to find nodes.
void print (BTNode what) {
if (what) {
print (what->left);
printf ("%s -> %s\n", what->str, (char *) what->data);
print (what->right);
}
}
int main () {
BTNode *top;
top = btn_insert ("Rik", "Kanaalstr. 122", 15);
top = btn_insert ("Karel", "Marskramerstr. 3", 18);
top = btn_insert ("Harry", "Hazenveld 12", 13);
top = btn_insert ("Peter", "Rubensstr. 29", 14);
print (top);
return (0);
}
top is the tree root, str is the identifying key
str wasn't found in the
tree
str in the tree
pointed to by top. When found, a pointer to the node's data area is
returned. When not found, 0 is returned.
BTNode *top;
char *data;
top = btn_insert ("Rik", "Kanaalstr. 122", 15);
top = btn_insert ("Karel", "Marskramerstr. 3", 18);
top = btn_insert ("Harry", "Hazenveld 12", 13);
top = btn_insert ("Peter", "Rubensstr. 29", 14);
if ( (data = btn_lookup ("Harry")) )
printf ("Address: %s\n", data);
else
printf ("No address found for Harry.\n");
buf is the buffer to "escape"
cmm_free() or cmm_cleanup(),
because internally in this function, the cmm*() approach is used.
Hello+World%0A:
char
normalbuf [] = "Hello World\n",
*cgibuf = cgi_escape (normalbuf);
printf ("CGI format: %s\n"
"Normal : %s\n", cgibuf, normalbuf);
cmm_free (cgibuf);
vars is a pointer to a a string table where variable names
will be stored, the values will be stored in vals. Note: both
string tables must be initialized to {0,0}.
$REQUEST_METHOD found in the
environment
$REQUEST_METHOD is neither
GET nor POST
GET method, no
$QUERY_STRING found in the environment
POST method, no
$CONTENT_LENGTH found in the environment
$CONTENT_LENGTH does not yield a number
multipart/form-data
result, but the decoding has failed
The variables are stored in the Strtab structure pointed to by the
first argument, their values in the structure pointed to by the
second argument. The conversion is handled in such a way that
vars->s[0] is the name of the first variable, and vals->s[0] is
its corresponding value. The values, as stored in vals are
'un-escaped', meaning that + characters are converted into
spaces, %XY sequences are converted to normal characters, etc..
This function handles both the GET and POST methods. In the
GET method, the raw CGI data are expected in the environment variable
$QUERY_STRING. In the POST method, the raw data are expected on
stdin, while $CONTENT_LENGTH is the length of the raw data buffer.
The input stream for the POST method may be redefined using
cgi_setpostfile() (e.g., for debugging).
Multipart form data are also supported. E.g., consider the following form:
<form name="myform" action="/cgi-bin/myaction"
enctype="multipart/form-data">
<input type="text" name="mytext">
<input type="file" name="myfile">
<input type="submit">
</form>
In this case, the call to cgi_getdata() in the "myaction" program will result in the following variable / value pairs:
| Index | var | val |
| 0 | mytext | entered text |
| 1 | myfile | temporary filename |
When handling uploaded files, the sent contents are placed in a
temporary file with a name returned by tmp_file(). That name
is stored as the value.
See also: cgi_ismultipart(), cgi_unescape(), tmp_file(), tmp_clean(),
cgi_setpostfile()
Strtab structures for the CGI
data and calls cgi_getdata() to fill them. The CGI data are
then printed in "human readable" format.
Strtab var = {0, 0},
val = {0, 0};
int i;
if (cgi_getdata (&var, &val))
error ("CGI conversion failed\n");
printf ("%d variable/value pairs:\n", var.n);
for (i = 0; i < var.n; i++)
printf ("%s = %s\n", var.s[i], val.s[i]);
Now, assuming that there is a CGI variable called myfile,
the following code snippet prints the filesize and removes the
file:
struct stat statbuf;
if ( (i = stab_ifind (var, "myfile")) > -1 ) {
printf ("myfile found at index %d\n", i);
if (! stat (val.s[i], &statbuf))
printf ("file size: %d\n", statbuf.st_size);
tmp_clean ();
}
buf is a bare (unencoded) CGI-received buffer, len is the
buffer length
buf is not multi-part
cgi_getdata(). When
the buffer is in the format:
-----------------------xy123czz Content-Disposition: .... .. .. data ..
then the buffer is recognized as a multipart header. The magic
key that splits the buffer into variable/value pairs is copied
in memory (here: xy123czz) and a pointer is returned.
POST methodinf is the input stream to use instead of stdin
POST methods. In normal situations this stream is
stdin.
Note: This function does not set the variable METHOD, nor does
it set CONTENT_LENGTH. To cause a subsequent call to read the
alternative stream, the METHOD must be POST and
CONTENT_LENGTH must be the number of characters waiting in the
alternative stream.
See also cgi_getdata().
FILE *inf;
Strtab var = {0,0},
val = {0,0};
int ret;
if (inf = fopen ("/tmp/tempdata", "r"))
cgi_setpostfile (inf);
if ( (ret = cgi_getdata (&var, &val)) )
error ("Error %d while reading CGI data\n", ret);
buf points to the ascii-Z string to change from CGI format to
C-string format
Note that the buffer argument is changed in-place; i.e, the function does not duplicate it. There is no re-allocation, the buffer may or may not be in allocated memory. To change buffers where the (decoded) contents may contain literal 0-characters, use cgi_unescape_buf().
See also cgi_escape(), cgi_unescape_buf().
char buf [] = "Hello+World%0a"; printf (cgi_unescape (buf));
buf is the buffer to change from CGI format to C-string format,
len is its length
+ characters to spaces, and the changing of
hexadecimal %XY sequences to their corresponding ascii characters.
Note that the buffer argument is changed in-place; i.e, the function does not duplicate it. There is no re-allocation, the buffer may or may not be in allocated memory. The new buffer length is returned; the caller may reallocate the used space to this size.
To change ascii-Z strings, you can also use cgi_unescape().
// (a)
char *buf = "Hello+World%0a";
printf (cgi_unescape (buf));
// (b)
char *buf = "Hello+World%0a";
printf (cgi_unescape_buf (buf, strlen (buf) + 1));
Note the "strlen(buf)+1"; the count of characters to decode must include the trailing '\0'.
fname is the file to sum up
Note that this is indeed a very basic and simple checksum
algorithm. See checksum_adler32() and
fchecksum_adler32() for a more elaborate and more
widely adopted checksum approach.
int sum = checksum ("/etc/issue");
if (sum == -1)
printf ("/etc/issue could not be read\n");
else
printf ("checksum of /etc/issue: %d\n", sum);
data is a the buffer to investigate, len its length
fchecksum_alder32() for a function to
determine the checksum of a file.
minlev is the minimum level to include in the count, use 0 for "all",
maxlev is the maximum level, use -1 for "all"
cmm*() functions, xstrdup(), tt(str_add()),
etc.
void *x;
// Allocate some memory in level 0
cmm_setlevel (0);
x = cmm_malloc (300); // Allocate some memory
x = cmm_malloc (500);
// Allocate some more in level 1
cmm_setlevel (1);
x = cmm_malloc (200);
// Show what we have got so far
printf("Overall allocated: %d bytes\n"
"In level 0: %d bytes\n"
"In level 1: %d bytes\n",
cmm_allocated(0, -1),
cmm_allocated(0, 0),
cmm_allocated(1, 1));
mem is a pointer to allocated memory
mem,
or 0 when the block was not allocated within CMM or when it was already
freed
mem was allocated. If so, the size of the
reserved area is returned.
This function can be used to check whether a given pointer addresses
CMM-allocated memory: if not, cmm_blocksize() will return 0.
void *mem;
char *str;
mem = cmm_malloc (200);
str = xstrdup ("Hello World\n");
printf ("Memory reserved for 'mem': %d\n",
"Memory reserved for 'str': %d\n",
cmm_blocksize (mem), cmm_blocksize (str));
minlev is the minimum level to clean up
cmm_malloc() (and hence
using the associated functions, xstrdup() etc.) at the
level minlev or above.
Note: to free one single block of memory, use cmm_free().
See also cmm_malloc(), cmm_setlevel(), etc..
void *x;
int n,
oldlev;
oldlev = cmm_setlevel (0xdeaf); // Define a new level
x = cmm_malloc (10); // Allocate some memory
x = cmm_malloc (20);
// Cleanup and report.
printf ("Within the level: %d blocks freed\n",
cmm_cleanup (0xdeaf));
cmm_setlevel (oldlev); // Reset the level
cmm_malloc()-d memorymem is memory block to free
mem was not
previously allocated cmm_malloc(), cmm_realloc(), xmalloc(),
str_printf(), etc..
Note that to deallocate a series of blocks, belonging to a
given "level", cmm_cleanup() may be used.
If the memory block "mem" was NOT previously allocated with
cmm_malloc(), then the memory is freed anyway -- but in that
case, the internal memory management has probably gone haywire.
This is signalled to the caller with a nonzero return value.
Ergo, you can safely use cmm_free() in your programs instead
of free(), even for normal malloc()-d pointers.
To find out whether a block was allocated in cmm*(), you can use
cmm_blocksize().
See also cmm_malloc(), cmm_setlevel(), cmm_cleanup(),
cmm_blocksize() and other cmm*() functions.
void *x;
x = cmm_malloc (1000); // Allocate memory
if (cmm_free (x)) // Free or report an error
fprintf (stderr,
"While trying to free block:\n"
"memory wasn't previously allocated\n");
sz is the number of bytes to allocate
out_of_memory() when the
pool is exhausted. The requested memory is internally stored with
the current level, so that it may be subsequently freed using
cmm_free() or cmm_cleanup().
Note that the requested sz bytes must be a positive number. When
requesting zero bytes, or when requesting a negative size, a
program error occurs.
See also: cmm_setlevel(), cmm_free(), out_of_memory(),
cmm_storeblock(), cmm*() functions.
cmm_malloc()-d block of memorymem is a pointer to previously cmm_malloc()-d memory, or 0 in
which case the memory will just be cmm_malloc()-d,
newsz is the size, which may be 0 to free the block
cmm_malloc()-d, or
newsz == 0 and the block was already freed.out_of_memory()) when the pool is
exhausted.
The first argument, mem, may be a 0-pointer, in which
case the function behaves just like cmm_malloc().
The second argument may be a size of 0 bytes, in which case the function behaves like cmm_free ().
The function cmm_realloc() tries to be "nice" when it encounters
a reallocation request for a block that is not in the internal
dministration yet. In such a case, cmm_realloc() will fullfil
the request (i.e., will re-allocate) and will then insert a
reference to the memory into the private administration. This
practice is of course discouraged, blocks should be allocated
right from the start using the cmm*() functions, or xmalloc(),
xstrdup(), xcalloc() etc..
Note that a non-positive newsz count of bytes will lead to a
program error. If that occurs, check your program for the code
that causes this and fix it.
void *x;
x = cmm_malloc (100); // allocate some memory
x = cmm_realloc (x, 300); // reallocate
printf ("%d bytes occupied\n", // report, this must
cmm_allocated (0, -1)); // now show "300"
newlev is the new cmm level
To retrieve the current level, simply call cmm_setlevel(-1) and inspect the return value.
The level is relevant regarding the functionality of
cmm_cleanup(). You can define a "level" of allocation using
cmm_setlevel(), and then call cmm_cleanup() to deallocate
all blocks in that level.
See also cmm_malloc(), cmm_cleanup(), cmm_allocated(),
cmm*() functions,
void *x;
int oldlev;
oldlev = cmm_setlevel (100); // Set the level.
x = cmm_malloc (1000); // Allocate two blocks.
x = cmm_malloc (200);
// Show what we have got so far
printf ("Allocated at level 100: %d bytes\n",
cmm_allocated (100, 100));
// Clean up level 100 and higher
printf ("For level 100 and up: %d blocks freed\n",
cmm_cleanup (100));
cmm_setlevel (oldlev); // Switch back to previous level
mem is the pointer to allocated memore to store in administration,
sz is the size of the allocated memory_
mem argument), or
0 when the internal allocation (necessary for administrative purposes)
has failed
cmm_cleanup()
to sweep the memory. The level is stored with a reference to the current
level, see cmm_setlevel() for details.
This function is used internally. However, it can be used to store previously allocated user memory, e.g., memory allocated in a library function.
cmm_storeblock()
is called to put a reference to the block in the cmm
administration.
char *mem;
mem = some_function_that_allocates_a_string ();
if (! cmm_storeblock (mem, strlen (mem)))
out_of_memory ();
// Alternatively you could of course use:
char *mem, *tmp;
tmp = some_function_that_allocates_a_string ();
mem = xstrdup (mem); // this autmatically stores in cmm
free (tmp);
The function fills its arguments nread and nwritten with respectively the byte count of the read information and of the written information.
The return value signals whether the copying went succesful, or whether one of the files could not be opened, or whether only some bytes could be copied. In the last case, the caller should remove the destination file, since the copying action has lead to a currupt file.
Note that a function movefile() also exists, which (obviously) moves
a source to a destination.
src for reading.
dest for
writing.
nread does not equal nwritten,
corrupted copy. Note: the caller should then remove
dest, it is an invalid file.
dest does not yield a regular file
path. The caller should check that dest yields a
regular file, and not e.g. a directory; or that all
directory components in dest exist.
// (1) Example WITH storage of read/written bytes:
int ret, totread, totwritten;
ret = copyfile ("/etc/profile", "/tmp/out", &totread, &totwritten);
if (ret) {
fprintf (stderr, "Copy failure\n");
if (ret == CP_MISMATCH)
unlink ("/tmp/out");
} else
printf ("Copying succesful, %d bytes\n", totread);
// (2) Example WITHOUT storage of read/written bytes:
if ( (ret = copyfile ("/etc/profile", "/tmp/out", 0, 0)) ) {
if (ret == CP_MISMATCH)
unlink ("/tmp/out");
error ("Copy failure\n");
}
purpose is a one-liner stating the program purpose,
version is a version ID
copyright_setoutput().
See also:
copyright_setoutput() -
to define a different output stream
copyright_owner() -
to define a different "owner"
copyright_contact() -
to define different contact information
copyright ("log file parser", "2.12");
This leads to something similar to:
e-tunity log file parser V2.12 (linkage 1.09) Copyright (c) e-tunity 2000 ff. All rights reserved. Contact e-tunity (info@e-tunity.com) for more information.
new_contact is the new contact name to appear
copyright()
function to new_contact.
See also: copyright().
new_owner is the new "owner" name
copyright()
function to new_owner.
See also: copyright().
copyright() functionoutputfile is new output file for copyright(),
instead of stderr
copyright() function is stderr.
This function redefines that stream.
See also: copyright().
fork():
fork() and a number of other calls to
'safely' start a detached daemon process. The parent process may wait for
the daemon to terminate, but doesn't have to; the deamon is fully
detached.
The actions are the following:
/dev/null. That way, if the program calls a spurious
printf(), the information will be silently discared to
/dev/null. Similarly, a gets() won't wait for input.
setsid(2)) so that when terminating, zombies are
avoided.
Following these actions, the parent process can safely exit and
leave the forked process running, which now will be detached and
belonging to init.
Error conditions are returned as negative values both in the parent and child branch. The following symbolic names are used:
DM_P_FORK_ERR: Failure to fork, reported in the
parent branch.
DM_P_IPC_ERR: Failure to set up inter process
communication (IPC) with the child. Reported in the parent branch.
DM_P_STDIN_ERR: The child failed to to reopen stdin on
/dev/null. Reported in the parent branch.
DM_C_STDIN_ERR: The child failed to to reopen stdin on
/dev/null. Reported in the child branch.
DM_P_STDOUT_ERR: The child failed to reopen
stdout. Reported in the parent branch.
DM_C_STDOUT_ERR: The child failed to reopen
stdout. Reported in the child branch.
DM_P_STDERR_ERR: The child failed to reopen
stderr. Reported in the parent branch.
DM_C_STDERR_ERR: The child failed to reopen
stderr. Reported in the child branch.
DM_P_SESSION_ERR: Child failed to become a session
leader. This may actually not be a fatal error if the parent
process already called setsid() itself. See the manpage
for setsid(3). Reported in the parent branch.
DM_C_SESSION_ERR: Child failed to become a session
leader. Reported in the child branch.
A valid approach to using daemonize() and to handle errors is
the following.
daemonize() is called, and its result is stored in a
local variable.
printf()
etc. will no longer work.
DM_P_* values mean that you're in the parent
branch. Such values can be reported using the standard
functions like (f)printf() or error().
DM_C_* values mean that you're in the child
branch. Reporting through (f)printf() is no use. Such
values can be reported using logmsg()
or syslog(3), but don't have to. Their counterparts
are available as DM_P_* to the parent process.
// The daemon function.
void act_daemon () {
int i;
// Let's log to /var/log/messages.
log_setup ("/dev/syslog/user/notice", 0, 0);
// Loop every approx. 5 seconds for one minute.
for (i = 0; i < 60; i += 5) {
logmsg ("Test daemon now active for %d secs", i);
sleep (5);
}
}
// The main function to fire up the daemon.
int main () {
int pid;
printf ("Starting daemon...\n");
if ( (pid = daemonize()) > 0) {
// Parent branch: no errors.
printf ("Daemon started at process ID %d\n"
"Watch /var/log/messages for the output.\n", pid);
} else if (pid == 0) {
// Child branch: no errors.
act_daemon();
} else {
// Parent or child branch, error. It's enough when we report the
// DM_P_* errors that are seen by the parent; the child process
// can rely on the parent reporting this.
switch (pid) {
case DM_P_FORK_ERR:
error ("Failed to fork\n");
case DM_P_IPC_ERR:
error ("Failed to set up IPC pipe\n");
case DM_P_STDIN_ERR:
error ("Child failed to close/reopen stdin\n");
case DM_P_STDOUT_ERR:
error ("Child failed to close/reopen stdout\n");
case DM_P_STDERR_ERR:
error ("Child failed to close/reopen stderr\n");
case DM_P_SESSION_ERR:
error ("Child failed to become session leader\n");
default:
error ("Other (unspecified) error, code %d\n", pid);
}
}
// All done.
return (0);
}
v is the required version for this program,
msg is an appropriate error message, or 0 to get a default
v. If not, an error is issued.
The argument v is the required version number. E.g., imagine that
e-lib 5.15 implements some very handy function that your
program uses. In that case it would be a good idea to verify that the
system that your program runs on, has e-lib 5.15 or higher.
The argument msg is an error message, displayed when the e-lib
version is lower than the required v. In that case, a fatal error
will occur.
The msg argument may be set to 0, in which case a default error
message is displayed. msg may alternatively be a string, optionally
containing two format specifiers for double values. The first one
will be expanded to the currently active e-lib version, the second
one will be expanded to the required version. (Good format specifiers
are, e.g., %.2f, which yields two decimals. This nicely conforms with
the e-lib versioning.)
See also elib_version().
// Example 1: we require version 5.15, and use
// the default error message
elib_require (5.15, 0);
// Example 2: we require version 5.15, and have
// our own error message. We show the active
// e-lib version and the required version.
char *msg = str_printf ("You seem to have e-lib V%g. However,\n"
"this program needs %g. Ask your admin\n"
"to upgrade e-lib! The most recent\n"
"version can be found on\n"
"http://public.e-tunity.com.\n",
5.15, elib_version());
elib_require (5.15, msg);
// Since we got this far, msg is no longer needed.
cmm_free (msg);
See also elib_require().
printf ("Current e-lib version: %.2f\n", elib_version());
a and b are the strings to compare
a if a is smaller, or over the length of
b if b is smaller.
When the strings match over this length, !0 is returned.
See also strnicmp().
fmt is a printf-like format string, other arguments may follow
stderr in a formatted way. The program
name, if set using setprogname (), is included. When logging is
enabled using log_setup (), then the error message is also written
to the log file before exiting.
See also setprogname (), log_setup (), logmsg ().
error ("bad input: %s\n", buf);
will produce something similar to:
progname: bad input: whatever progname: aborting...
f is the file to investigate
fstat() errors, -2 for fread() errors
unsigned int pointed to by csum.
See e.g. http://en.wikipedia.org/wiki/Adler-32 for a
description. See also checksum_alder32() for a function to
determine the checksum of a buffer.
f is the file to read from, it must be opened for reading
EOF was encountered.
f and stored in allocated memory. A
pointer to that memory block is returned. The line length in the file
virtually unlimited; fgetline() will continue reading until one whole
line, terminated by \n, is read.
Note: The caller is responsible for freeing the memory pointed to by
the return value. This must be done using cmm_free() or
cmm_cleanup().
To strip any terminating \n characters, stripstr() can be used.
int main (int argc, char **argv) {
FILE *f;
char *buf;
int lineno = 0;
if (argc != 2)
error ("Usage: %s inputfile\n", argv[0]);
if (! (f = fopen (argv[1], "r")) )
error ("Cannot read %s: %s\n", argv[1], strerror(errno));
while ( (buf = fgetline (f)) ) {
printf ("%8d %s", ++lineno, buf);
cmm_free (buf);
}
fclose (f);
return (0);
}
fname is the name of the file to inspect
Note that currently a FT_OFFDOC return value cannot distinguish
between the Office document types.
static char *desc [] = {
"unknown", "tiff (big endian)", "tiff (little endian)",
"png", "gif", "jpeg", "bmp", "xpm", "officedoc",
"rtf", "xml",
};
int main (int argc, char **argv) {
int i, ret;
for (i = 1; i < argc; i++) {
printf ("%s: ", argv [i]);
if ( (ret = filetype (argv [i])) < 0 )
printf ("error determining type\n");
else
printf ("%s\n", desc [ret]);
}
return (0);
}
fin_read()block is a pointer to data to "push back" into
the file
nbytes is the block size in bytes
inf is the file where fin_read() will read the next
timefin_read()) the block will be re-read.
fin_read()
block is a pointer where the data will be stored
nbytes is the number of bytes to read
inf is the file (stream) to read fromfin_push() to read
data from a file, and to be able to "push back" data. Following
a push-back operation by fin_push(), the next fin_read()
call will return the pushed-back bytes.
When used without fin_push(), fin_read() is similar
to fread().
The pushing-back of bytes is a FILO-operation, first-in-last-out (or LIFO, if you prefer). That means that the bytes that are pushed back first, are read as last.
There is no limit on the number of bytes to push back (except for
situations of memory exhaustion). The functions fin_read() and
fin_push() are re-entrant; they can
be used for many reading operations in the same program. (The
internal administration is based on the input file handle).
FILE *inf; char block [100]; fin_read (block, 100, inf); fin_push (block, 10, inf); fin_read (block, 100, inf);
logfp is a pointer to a char*, where the current logfile
name will be stored; maxszp is a pointer to an int where
the current maximum logfile size will be stored, nhistp is a
pointer to an int where the current number of history logs
will be stored.
log_setup() call.
Each argument can be a NULL-pointer, in which case the
appropriate value will not be stored. E.g., when only logfp
is a valid pointer, but the other arguments are 0, then only the
current logfile name is stored.
Note that the char* pointed to by logfp is set to point
to allocated memory. The caller is responsible for
cmm_free()-ing it.
char *logf;
int maxsz, nhist;
// Temporarily redirect logging.
get_log_setup (&logf, &maxsz, &nhist);
log_setup ("/dev/syslog/user/notice", 0, 0);
// Log our stuff.
logmsg ("Hi there!\n");
// Restore logging to whatever it was.
log_setup (logf, maxsz, nhist);
cmm_free (logf);
key is the string to compute a hash for
hashbuf() to compute a hash value, and
returns it. See hashbuf() for more information.
This function is used by the bth_*() functions.
bth_*() functions.
key is the buffer to compute the hash for, length is the buffer
length, seed is an initial value
buf is the buffer in which to escape special characters
buf
html_escape() converts these
characters to HTML-escape-sequences, such as < >, &
and so on (see also the ISO8859-1 specification.)
The character conversions are:
< and > are converted to < and >
& is converted to &
'
"
&#xyz; where xyz is a three-digit 10-based
ASCII code.
Note that the returned value points to allocated memory. The
caller is responsible for the deallocation of it. (As with all
e-lib functions, use cmm_free() to deallocate memory...)
Other *ML conversion functions are ml_encode() and ml_decode().
These are similar to html_unescape() and html_escape(), but
support a larger collection of character maps.
See also html_unescape().
char *converted = html_escape ("<\"Hello World\">");
printf ("%s\n", converted);
The following code undoes this:
html_unescape (converted);
buf is the buffer to process
< are converted to their original
characters.
Note that the buffer which is passed as the argument, is modified
in-place. The caller should make a local copy before calling
html_unescape() if the original buffer contents are to be
preserved.
Other *ML conversion functions are ml_encode() and ml_decode().
These are similar to html_unescape() and html_escape(), but
support a larger collection of character maps.
See also html_escape().
fname is the name of afile holding the image file to inspect,
isp is a pointer to an ImageSize structure that will be filled
with size data
For these images, the structure pointed to by isp is filled with
the correct width and height data. The ImageSize structure just
holds two int elements: a w (for width) and h (for height).
See also: filetype()
ImageSize is = {0, 0};
int ret;
if (! (ret = image_size ("myfile.gif", &is)) )
printf ("width: %d, height: %d\n", is.w, is.h);
else switch (ret) {
case IS_NOFILE:
printf ("no such file\n");
break;
case IS_UNSUPP:
printf ("unsupported image format\n");
break;
default:
printf ("file cannot be parsed\n");
break;
}
lap_start() is stopped
and the recorded laptimes are logged to a file, defined by
lap_setup().
Note that task and their stopwatches are stacked. This function stops the last started stopwatch and outputs the results.
The logging of laptimes is suppressed if the logfile name (as
defined by lap_setup()) is an invalid string (NULL) or if the
corresponding file cannot be opened.
Lap times and logging can be suppressed for an entire program by
either never calling lap_setup(), or temporarily by calling
lap_setup(0). Temporary suppression of logging must however occur
prior to a stopwatch start by lap_start(); and not between a
lap_start() and a lap_end().
The output that is generated is in the reversed order; last
stopped stopwatches are written first to the log file. This is
inherent to the stack principle of the lap_*() functions.
Use, e.g., tac logfilename to reverse the lines order.
The shown output represents, per generated line:
void function () {
int i;
double d;
lap_start ("myfunc");
for (i = 0; i < 1000; i++)
d = (10.0 * (double) i) / 3;
system ("ls > /dev/null");
lap_end ();
}
int main () {
int i;
lap_setup ("/tmp/lap.log");
lap_start ("main");
lap_start ("main:loop");
for (i = 0; i < 10; i++)
function ();
lap_end ();
system ("ls > /dev/null");
lap_end();
return (0);
}
After tac /tmp/lap.log an overview is shown of the following:
"main" with the overall time spent;
"main:loop" with the time spent inside the loop
that calls function();
"function"fname is the filename to log laptimes to,
or 0 if no logging required
lap_start() and lap_end().
Note: This function does not make a duplicate of the fname
argument. Be sure to keep this string in memory during the
run of the program where the lap*() functions are used.
See also: lap_start(), lap_end()
task is the name of the task whose stopwatch should be started
lap_end(). Note that the log file for stopwatch output must
be defined via lap_setup().
See also: lap_setup(), lap_end()
logmsg() is calledlogmsg() are not "flushed" after each write. This
may speed up the application (especially on slow file systems),
but will cause the logs not to be up-to-date.
Note that by calling log_dontflush() after (or before) a
log_setup(), the rotating and sizing of logfiles gets disabled
during the current program run.
Also note that when the the system log facility is used( by
using /dev/syslog/ as the log file name in log_setup()),
logfile flushing does not apply.
logmsg()
log_setup ()fmt is a format string a-la printf(), the remaining arguments
are expanded according to the format
/dev/syslog/), then the following bullets do not apply.
I.c., timestamping is left to the system log handling and so on.
log_timestamp(0).
fmt is a 0, nothing is logged but the file is
rotated (if necessary).
log_setup(), see the info there.
log_dontflush(). However, this will prevent the logs
from being rotated.
log_wrap(1) before issuing logmsg()
calls.
See also log_setup(), log_timestamp(), log_dontflush(),
log_rotate().
log_setup ("/var/log/myprog.log", 10000, 3);
logmsg ("some message\n");
This defines /var/log/myprog.log as the log file, with a max size
of 10000 bytes and 3 history files. Then a message is sent to
the file.
fname is the logfile name, maxsz is the limit, nhist is the
number of old versions to keep
fname if its size exceeds
maxsz bytes. When rotating, the file is renamed to
fname.1. Any pre-existing fname.1 is renamed to
.2 and so on; nhist history files are kept.
This function is used by, e.g., logmsg(). See the description there.
logmsg()
function. The logfname defines the log file to which messages are
appended. The argument maxsz defines the logfile size. When the size
of the file exceeds this, the old file is renamed to a *.1 version
and compressed into *.1.gz, and a new file is created. The nhist
argument specifies the number of history files to keep.
E.g., when nhist == 2, then a bare log file will exist plus two
history files, named *.1.gz and *.2.gz.
Newly created log files automatically receive the permissions 0666, i.e., readable and writable by all.
Notes:
logfname, maxsz and
nhist. This is implemented in order to allow customization
of the logging of already compiled programs.
log_setup() before calling logmsg().
Otherwise, the log file name will be empty and logmsg() will
not produce output.
stdout for log file
stderr for log file
fac and lev have special
meanings; see below.
The 'special' filename /dev/syslog/fac/lev selects the
system log facility for logging purposes. The name also selects the
facility and level:
auth,
authpriv, cron, daemon, ftp, kern, local0
through local7, lpr, mail, news, syslog,
user and uucp. When the fac part matches none of the
above, then user is taken.
emerg,
alert, crit, err, warning, notice, info
and debug. These are the 'emergency levels' in decreasing
order of importance. When lev matches none of the above,
then notice is taken.
See also logmsg() to log a message, log_timestamp() to
enable or disable timestamping, and msg_and_log() to
log a message and optionally produce a message on stderr.
log_setup ("/var/log/myprog.log", // filename
10 * 1024, // rotate when size > 10K
4); // keep 4 history logs
logmsg ("something to log\n");
Once the program is compiled, logging can be changed by, e.g.:
$ ############### Example 1: $ export ELOGNAME=/var/log/someother.log # log to some file $ export ELOGSIZE=200000 # 200K logs $ export ELOGHIST=10 # 5 history files $ myprog # run the program $ $ ############### Example 2: $ export ELOGNAME= # suppress logging $ myprog # run the program
onoff is a switch; 0 turns timestamping off, !0 turns it on
logmsg() will produce a log entry that is affected
by the setting.
Note that timestamping is by default ON. Furthermore, when
log_setup() is instructed to send its messages to the system log
facility, then the timestamping cannot be influenced.
log_setup ("/tmp/my.log", 50000, 5);
logmsg ("an entry with a timestamp\n");
log_timestamp (0);
logmsg ("an entry without\n");
onoff is a switch, 0 will disable line wrapping
See also: logmsg(), log_*()
port is the port to which the socket will be bound
socket(2)),
you can analyze errno for details
errno for details
bind(2)),
you can analyze errno for details
buf argument,
over len bytes. The output is stored in the array digest,
of which the first 16 bytes are used. The caller is responsible
for making sure that digest is (at least) 16 bytes long. See
also sha1().
unsigned char digest[16];
int i;
md5 ("Hello World", 11, digest);
for (i = 0; i < 16; i++)
printf ("%2.2x", digest[i]);
putchar ('\n');
buf is a buffer to use as source for decoding
< in a HTML or XML string
is decoded into <. In contrast to the function html_unescape(), a
much "wider" range of character maps is supported.
The returned buffer is in allocated memory. The caller is responsible for freeing it.
See also ml_encode(), html_escape(), html_unescape().
buf is buffer to use as source for encoding
<.
The returned buffer is in allocated memory. The caller is responsible for freeing it.
See also ml_decode().
mm is a MailMsg handle, partnr indicates the
ordinal number of the mail message body to retrieve
partnr is 0, the main
body is returned. In multipart messages, this is the full text,
including all parts. The first part of a multipart message starts
at partnr 1. Note that mmsg_parts() indicates how many
parts there are.
The return value points to a string holding the body. The caller may not deallocate or change this.
text/plain.
MailMsg *mm; // MailMsg handle
extern char *buffer; // some text buffer
int parts; // parts in message
char *ctype; // content type
int i; // loop var
mm = mmsg_new();
mmsg_parse (buffer);
parts = mmsg_parts (mm);
if (!parts)
printf ("main body:\n%s\n", mmsg_body (mm, 0));
else for (i = 1; i <= parts; i++) {
printf ("body of part %d:\n", i);
ctype = mmsg_partheaderval (mm, i, "content-type");
if (ctype && stristr (ctype, "text/plain"))
printf ("%s\n", mmsg_body (mm, i));
else
printf ("cannot display\n");
}
MailMsg handlemm is a MailMsg handle
mm are freed.
MailMsg *mm;
mm = mmsg_new ();
mmsg_parse ("some mail message");
mmsg_destroy (mm);
mm is a MailMsg handle,
fname is a filename, holding a mail message
errno for reasons)
mmsg_parse(), or mmsg_fparse(),
except that the
message to parse is expected in a file. See mmsg_parse() for
further information.
/tmp/msg.
MailMsg *mm;
int nbytes;
mm = mmsg_new();
if ( (nbytes = mmsg_fileparse (mm, "/tmp/msg")) < 0 )
error ("cannot parse file msg: %s\n",
strerror(errno));
else if (!nbytes)
error ("empty mail message\n");
printf ("%d bytes parsed from message\n", nbytes);
mm is a MailMsg handle,
f is a filehandle, opened for reading
mmsg_parse(), except that the
message to parse is read from a file handle.
See mmsg_parse() and mmsg_fileparse() for
further information.
mm is a MailMsg handle, partnr indicates a part
\n-separated lines,
or 0 when partnr is out of range
partnr is 0, then the header of the main mail message is
returned. For multipart messages, partnr can range from 1 up
to and including mmsg_parts() to access the headers of parts.
MailMsg *mm;
int i;
mm = mmsg_new();
if (mmsg_fileparse (mm, "/tmp/somefile") <= 0)
error ("no valid mail in /tmp/somefile\n");
for (i = 0; i < mmsg_parts(mm); i++) {
printf ("Header of part %d:\n");
if (!i)
printf ("Note: that's the main header\n");
printf ("%s", mmsg_header (mm, i));
}
mm is MailMsg handle, var is the variable to find
in the main header
MailMsg *mm;
char *from, *subject;
extern char *buffer; // some buffer holding a message
mm = mmsg_new ();
mmsg_parse (mm, buffer);
from = mmsg_headerval (mm, "from");
subject = mmsg_headerval (mm, "subject");
printf ("Mail sent by: %s\n"
"Mail subject: %s\n",
from ? from : "<<no sender address found>>\n",
subject ? subject : "<<no subject specified>>\n");
cmmsg_free (from);
cmm_free (subject);
MailMsg handleMailMsg structure
MailMsg handle.
It must be called before a mail message can be parsed using
mmsg_parse(), mmsg_fparse() or mmsg_fileparse().
mmsg_parse(), mmsg_fparse().
mm is a MailMsg handle, buffer is a mail message to
parse
mmsg_fparse() exists to parse a mail
message from a file handle, and a function mmsg_fileparse()
exists to parse a mail message from a named file.
The normal way of using mmsg_parse() and the other mmsg_*()
functions is:
MailMsg handle is prepared using mmsg_new().
mmsg_parse() is called to parse a mail message from a
string buffer.
mmsg_body(mm, 0) will always return the main
mail message body;
mmsg_header(mm, 0) will return the main mail
headers;
mmsg_headerval(mm, "from") will return the
value of the main header stating the From: address;
mmsg_parts(mm) will return the number of parts
when the mail message is a MIME/multipart
message, or 0 when the mail message doesn't have
parts;
mmsg_body(mm, 1) will return the first part of
a multipart message, mmsg_header(mm, 1) will
return the headers of that part;
mmsg_partheaderval (mm, 1, "content-type") will
return the value of the Content-Type: header
of the first part of the mail message;
mmsg_reset(mm) will deallocate parts of the MailMsg
handle, so that mmsg_parse() can be called
again;
mmsg_destroy(mm) will deallocate all parts of
the MailMsg handle.MailMsg handle and parses a
mail message contained in a variable buffer. The number of
parts is shown.
MailMsg *mm; // MailMsg handle
extern char *buffer; // buffer holding text
mm = mmsg_new();
mmsg_parse (buffer);
if (mmsg_parts(mm))
printf ("mail message has %d parts\n",
mmsg_parts());
else
printf ("mail message has just one body\n");
mm is a MailMsg handle, partnr is the mail message
part to inspect, var is the variable whose value is
retrieved
partnr is out of range, or
if the variable was not found in the indicated header
partnr is 0 and var is from,
then the From: address is returned. The argument partnr
may be greater than 0 when multipart messages are expected.
int i;
char *encoding, *decoded;
extern MailMsg *mm;
for (i = 1; i <= mmsg_parts(mm); i++) {
encoding = mmsg_partheaderval (mm, i, "content-transfer-encoding");
if (encoding && stristr (encoding, "base64")) {
printf ("Message part %d is base64-encoded\n", i);
decoded = base64_decode (mmsg_body (mm, i),
strlen(mmsg_body (mm, i)), 0);
printf ("Decoded body part:\n%s\n", decoded);
cmm_free (decoded);
}
cmm_free (encoding);
}
mm is a MailMsg handle
MailMsg handlemm is a MailMsg handle to reset
MailMsg
handle. The handle can be re-used to parse a new message.
mm:
MailMsg *mm; extern char *buf1, *buf2; mm = mmsg_new (); mmsg_parse (mm, buf1); . . . mmsg_reset (mm); mmsg_parse (mm, buf2); . . . mmsg_destroy (mm);
mm is a MailMsg handle, var is the header variable
to set, val is the value
MailMsg *mm;
extern char *buffer;
mm = mmsg_new()
mmsg_parse (mm, buffer);
mmsg_setheader (mm, "X-Custom-Header",
"new header variable");
printf ("Modified header:\n%s\n",
mmsg_header (mm, 0));
// This will show
// X-Custom-Header: new header variable
// as one of the displayed header lines
src is a source file, dst is the destination file name (not just
a directory)
src for reading,
errno holds the cause
dest for
writing, errno holds the cause
nread does not equal nwritten,
corrupted copy. Note: the caller should then remove
dest, it is an invalid file.
dest does not yield a regular file
path. The caller should check that dest yields a
regular file, and not e.g. a directory.
copyfile(), but the original src could not be
removed afterwords.src to dst.
This function is similar to copyfile(), except that (obviously)
src no longer exists after a successful operation. In contrast to the
system function rename(), movefile() will also work across
filesystems. (Internally, if a rename failes, copyfile() will be
called to do the job.)
The return value signals the success or failure reason. Most of the
return values are identical to copyfile().
/tmp/a to
/usr/local/bin/a. The error conditions are caught.
int res;
if (res = movefile ("/tmp/a", "/usr/local/bin/a")) {
fprintf (stderr, "Failed to move file: ");
switch (res) {
case CP_NOINF:
fprintf (stderr, "/tmp/a not found: %s\n",
strerror (errno));
break;
case CP_NOOUTF:
fprintf (stderr, "cannot write /usr/local/bin/a: %s\n",
strerror (errno));
break;
case CP_MISMATCH:
fprintf (stderr, "file corruption during operation\n");
unlink ("/usr/local/bin/a");
break;
case CP_DST_IS_NO_FILE:
fprintf (stderr, "/usr/local/bin/a isn't a true file,\n"
"maybe your system lacks /usr/local/bin?\n");
break;
case MV_CANNOT_RM_SRC:
fprintf (stderr, "/tmp/a cannot be removed, but "
"/usr/local/bin/a succesfully created\n");
break;
}
}
stderr when in verbose modeprintf()
stderr, prefixed by a program name (if
one is set using setprogname ()), if the required verbosity as
indicated by the verb argument, is matched by the number of
previous calls to msg_on().
For example, a msg() call with a
required verbosity 1 will appear if msg_on() was called at
least once.
See also msg_and_log() to log a message and optionally show it on
stderr.
msg_on (); msg (0, "this will always appear\n"); msg (1, "this will appear with this verbosity level\n"); msg (2, "this will only appear with a higher level\n");
The following code snippet is more elaborate. As long as -v flags
appear in the program options, the verbosity is increased. Further on
through the code, msg() calls are placed that during a run will
appear only if the "verbosity level" at invocation was sufficiently
high.
int opt;
while ( (opt = getopt (argc, argv, "vcd:g:")) > 0 ) {
switch (opt) {
case 'v':
msg_on ();
break;
.
. Other options, c, d and g would be handled
. here
.
}
}
.
.
.
msg (1, "High-priority message\n");
msg (3, "This appears only when -vvv was given\n");
msg()
printf()
msg() and logmsg() into one function.
Depending on the verbosity level, the resulting message is shown
on stderr. The message is also sent to the logfile via logmsg().
Before calling this function, setprogname() and logsetup()
should be called.
setprogname ("myprog"); // define program name
logsetup ("/var/log/myprog.log", // define logging name
50000, 5); // with maxsize and nhist
// Now the following two are equivalent:
// (a)
msg (2, "testing %d %d %d\n", 1, 2, 3);
logmsg ("testing %d %d %d\n", 1, 2, 3);
// (b)
msg_and_log (2, "testing %d %d %d\n", 1, 2, 3);
msg() may or may not produce messages,
depending on the verbosity level.
See also msg().
int opt;
while ( (opt = getopt (argc, argv, "v")) > 0 ) {
switch (opt) {
case 'v': msg_on ();
break;
...
}
}
error()
function. You can redefine this handler using set_memerr().
See also
xmalloc(), xrealloc(), xstrdup() etc.,
set_memerr (), error()
ps_makesnapshot(). See this function for
more information.
The return value is a pointer to a PsList structure. This structure
holds:
nlist,
PsEntry structures, named
list.Each list entry is a structure of the following information:
char *name: the program name, without path directory;
char **argv and int argc: the arguments of the
program, with argv[0] being the full program name, with
directory;
char state: the runstate, R for running, S for
stopped, Z for zombie;
int pid and int ppid: the PID and parent PID;
int uid and int gid: the UID and group ID.This function will work on systems where:
/proc holds process information (e.g. Linux systems). This is
by far the preferred method to make snapshots. If this
directory is not found, then:
ps command can output all necessary
information. In these cases, ps_makesnapshot() will
run ps to obtain the necessary information.
Note that the allocated memory must be freed using
ps_freesnapshot().
PsList *l = ps_makesnapshot();
int i;
for (i = 0; i < l->nlist; i++) {
PsEntry e = l->list[i];
printf ("At pid %d: %s\n", e.pid, e.name);
}
ps_freesnapshot(l);
ps_makesnapshot()
ps_makesnapshot(). The list is sorted by process ID. To sort
otherwise (e.g. by command name or runstate), run your own
qsort().
PsList *list;
int i;
list = ps_makesnapshot();
ps_sortsnapshot(list);
for (i = 0; i < list->nlist; i++)
printf ("%d ", list->list[i].pid);
ps_freesnapshot (list);
ndigits is the number of digits to fill in the result,
firstzero specifies, when !0, that the leftmost digit may be
a zero
double to avoid precision loss
random_ulong (10, 0). Such keys are
typically used to identify unique records in a database, or
the similar.
Note that the caller should call srand() before using this
funtion to ensure more 'random-ness'.
int i;
srand (time(0));
for (i = 0; i < 10; i++)
printf ("%.0f\n", random_ulong (30, 0));
rc_read(). The number of entries previously in storage is
returned; the new number of entries is of course zero.
See also rc_read(), rc_value().
fname is the name of a resource file to scan
# sign are ignored alltogether, and lines
with # in the middle are split, so that the #-part is
ignored. E.g.,
# This is comment. variable value # This too.
variable This \ # <-- note the backslash!
variable has a very long value.
This assigns the value This variable has a very long value to variable variable.
VAR is a name of an (other) variable. E.g., after:
who world msg Hello $(who)
the variable msg has the value Hello world.
rc_read() to scan
filename. Note that the INCLUDE must occur in upper case.
The function rc_read() allows an INCLUDE nesting up to
100 deep.
After reading a resource, the functions rc_value() or
rc_setting() can be used to access the data. Function rc_clean()
can be used to reset (clean up) the storage of resource
data. Function rc_setval() can be used to add a value to the
pool of resource variables.
Note 1: The rc_*() functions share one data area for the stored
variables. Also, subsequent calls to rc_read etc. will overwrite
previously stored settings. (In other words, this family of functions is
not "reentrant".)
Note 2: The argument fname will be overruled by a filename stored
in the environment variable RC_FILE. This behavior is implemented to
support "closed" existing programs that rely on rc_read(). This means
that if an environment variable RC_FILE exists, then that file will
be read; regardless of the argument fname.
# this is comment
var_one setting_one # more comment
var_two setting_two \ # even more comment
continued here # yet more comment
base /etc
rc $(base)/rc.d
initlev $(rc)/rc3.d
INCLUDE /etc/my-other.rc
Then the following will apply:
rc_read ("/tmp/my.rc") will return 5
rc_value ("var_two") will return
"setting_two continued here"
rc_value ("initlev") will return /etc/rc.d/rc3.d
/etc/my-other.rc will also be included
in the set.rc_read()char*, which
rc_setting() will alter to point to
allocated memory, filled with the index-th
variable name
char*, will be set to point
to the index-th valuerc_read() call, the scanned data can be
either accessed using rc_setting() or rc_value().
The rc_setting() function is used to loop through all the
settings in a resource file. The first setting starts at slot 0,
the last is at slot max-1. The max value is the return value
from rc_read().
Note that rc_setting() allocates memory and sets the pointers
var and val to point to that memory. The caller is responsible for
freeing this memory, which must be done using cmm_free() or
cmm_cleanup().
int max, i;
char *var, *val;
max = rc_read ("/tmp/my.rc");
for (i = 0; i < max; i++) {
if (rc_setting (i, &var, &val))
error ("no setting at slot %d, while there should be\n",
i);
printf ("name: %s, setting: %s\n", var, val);
cmm_free (var);
cmm_free (val);
}
name is a variable name, setting is its value
rc_read(). By using rc_setval(), entries can be added that are
not stated in the file.
The setting that is added is also taken into account during the
expansion of variables. E.g., when the setting is $(somevar), then
rc_value(name) will return the expansion of the variable somevar.
Inversely, if a pre-existing variable a with the value $(somevar)
exists, then after the following call:
rc_setval ("somevar", "a new value");
the value of variable a will be a new value.
name is the name of variable to retrieve
rc_read().
When the variable name to determine is a-priori known, rc_value()
can be used to determine its setting.
NOTE THAT the list of variables is scanned without respect to casing.
When the variable name(s) to search are not known, rc_setting()
can be used to loop through all variable/value sets. See also
rc_read(), rc_setting() and rc_setval().
regex is an extended regular expression to match string with,
str is the string to search in, lenp points to an
int where the matched length is stored (when lenp is
not 0)
str where regex was matched,
or 0 when
str, or when
regex in str. A pointer to
the first occurrence is returned. When lenp is not 0,
then the number of matched chars is stored there.
To test whether an expression is valid, use rx_match(), whose
return value may not be RX_BADREGEX. This function
rx_find() doesn't provide that capability; the return value 0
is used for situations where the match cannot be made and for
situations where regex is invalid.
This function heavily relies on the POSIX standard. Some "less than POSIXy" systems will lack the support for regular expressions.
Normally, matching will be with regard to casing. Use
rx_ignorecase(1) to match while ignoring casing, or switch
back to case-sensitivity with rx_ignorecase(0).
onoff is not-0 to select case-insensitive matching (ignoring),
or 0 to select case-sensitive matching (the default)
rx_match() and rx_find()
match strings against regular expressions.
regex is an extended regular expression to match string with,
str is the string to compare to regex
regcomp() and regexec().
This function heavily relies on the POSIX standard. Some "less than POSIXy" systems will lack the support for regular expressions.
Normally, matching will be with regard to casing. Use
rx_ignorecase(1) to match while ignoring casing, or switch
back to case-sensitivity with rx_ignorecase(0).
newhandler is a pointer to the new out of memory handler function
newhandler() during
out-of-memory errors. A pointer to the previous out-of-memory
handler is returned. The type Errfunptr is a pointer to a function
that has a void argument list and that returns void.
f and then exit. In main() the handler is installed,
memory is allocated, and then the previous handler is
re-installed.
void myhandler (void) {
extern FILE *f;
fclose (f);
error ("out of memory\n");
}
int main () {
Errfunptr prev;
void *memory;
.
prev = set_memerr (myhandler);
memory = xmalloc (10000);
set_memerr (prev);
.
.
}
A more "elaborate" approach would be to let the out of memory handler
(myhandler() in the above example) "chain" the call to any previous
handler(s).
error() and msg()pname is the program name to use when displaying messages
setprogname ("myprog");
error ("Something bad has happened.\n");
This leads to something similar to: myprog: Something bad has happened.
sleep implementationsec is the sleeping time, as a double-precision value
errno in that case), !0
otherwise
sleep(3), no signals occur, and hence, no signal catcher
activity is disturbed.
The argument sec specifies the sleep time, up to microsecond
precision.
int value, which will
be incremented when the signal is seenint value which
is used as a flag when the signal is seen. The caller must at some given
time investigate the flag integer to see whether the signal arrived or
not.
Note that this function can be called more than once, to specify the
catching of all signals that should be caught. Note also that the
signals that are already caught by sig_catch() should not be
specified as triggers via the standard signal() function; only one of
the methods will work.
Furthermore, all restrictions of signal catching apply. E.g., the program
behaviour is undefined when a SIGSEGV is caught, and SIGKILL
signals cannot be caught. See the manpage on the signal() function
for more information.
int main () {
int sighup_seen = 0,
sigterm_seen = 0;
sig_catch (SIGHUP, &sighup_seen);
sig_catch (SIGTERM, &sigterm_seen);
while (1) {
if (sighup_seen) {
printf ("Seen a SIGHUP\n");
sighup_seen = 0;
}
if (sigterm_seen) {
printf ("Seen a SIGTERM\n");
exit (0);
}
sleep (1);
}
return (0);
}
buf is the buffer to inspect
buf. I.e., all characters up to and including the
next \r\n or just \n are skipped. A pointer to the position just
beyond that \r\n or \n is returned.
char *buf = "hello\nworld";
printf (skipline (buf)); // prints "world"
int count = 0;
char *cp;
for (cp = buf, count = 0;
cp = skipline (cp);
cp)
;
printf ("There are %d newlines in the buffer\n", count);
sprintf()-like capabilitiesStrtab table to add a
string to
... are the format string and remaining
argumentstab after addition of the new string
tab similar to stab_addstr(), except
for the fact that the string to add is specified using a format string
and variable arguments.
See also stab_addstr(), stab_free()
Strtab tab = {0, 0};
int i, nstr;
stab_addstr (&tab, "Hello World");
nstr = stab_addsprintf (&tab, "%d + %d = %d", 3, 4, 3 + 4);
for (i = 0; i < nstr; i++)
printf ("%s\n", tab.s[i]);
newstr will be added
newstr was added
tab.
String tables (type Strtab) are structures with two fields:
n, specifying the number of contained strings,
s, an array of char*-s, pointing to the contained
strings.When using string tables, the following general rules apply:
Strtab mytab = {0,0}. The functions stab_*() depend on
a valid initialization.
mytab.n may be inspected. Also, most stab_*() functions
have a return value that serves the same purpose.
mytab.s[index]
is used, with index ranging from 0 to mytab.n - 1
See also stab_free() which de-allocates the Strtab components,
and stab_addsprintf() to add strings in a sprintf()-like manner,
or stab_find() and stab_ifind() to find string in a table.
Strtab stab = {0, 0};
int i;
for (i = 0; i < 5; i++)
stab_addstr (&stab, "Hello World\n");
printf ("%d strings in table\n", stab.n);
for (i = 0; i < stab.n; i++)
printf ("String %d: %s\n", i, stab.s[i]);
stab_free (&stab);
tab is searched for string. See also
stab_ifind(), which searches case-insensitively.
Strtab mytab;
int i;
.
.
if ( (i = stab_find (&mytab, "hello world")) >= 0 )
printf ("string found at %d: %s\n",
i, mytab.s[i]);
stab is a pointer to the string table to reset
Strtab structure pointed
to by stab. The member fields are re-set to 0 (for subsequent
usage).
See also stab_addstr ().
string could not be found
tab for string, without regard to casing.
See also stab_find().
tab is a pointer to the string table
tab is. It is
mainly used before outputting strings, to determine the maximum span.
(The implementation of this function is quite trivial.)
tab points to the string table to pop from
stab_addstr() and stab_addsprintf(). These functions
"push" strings onto the stack.
The function stab_popstr() removes the last added string, and
returns it, thereby "popping". The return value points to
allocated memory; the caller is responsible for freeing it. The
freeing must be done using either cmm_free() or
cmm_cleanup().
A stack underflow is indicated by a 0-pointer. Note that the remaining
stack size can always be retrieved via tab->n.
See also stab_addstr(), stab_addsprintf().
Strtab stack = {0, 0};
int i;
char *cp;
// Push 10 strings onto the stack
for (i = 0; i < 10; i++)
stab_addsprintf (&stack, "string number %d", i);
// Now pop, until the stack is empty. Also release the
// popped memory.
while ( (cp = stab_popstr (&stack)) ) {
printf ("popped string: %s\n", cp);
cmm_free (cp);
}
bufbuf and
adds newstr to it.
Note: The caller is responsible for freeing the memory afterwords,
when buf is no longer needed. This must be done with either
cmm_free() or with cmm_cleanup().
char *buf = 0;
buf = str_add (buf, "Hello");
buf = str_addchar (buf, ' ');
buf = str_add (buf, "world!");
printf ("Buffer is now: %s\n", buf);
cmm_free (buf);
buf.
See also str_add().
a and b are two strings to compare
strlen(a) and strlen(b)
when the strings fully match (disregarding casing).
strnicmp().
int i;
i = str_equal ("HELLO", "hello"); // i == 5
i = str_equal ("HELLO", "h"); // i == 1
i = str_equal ("HELLO", "world"); // i == 0
a and b are the strings to compare
a is "less",
a is "more",
a and b are equalstrcmp(), except that the string
comparisons are made without regard to casing. This function mainly
exists because some Unices lack stricmp() or strcasecmp().
See also stristr(), strupr().
buf is the buffer to strip
char* pointer to changed string
sub1 is replaced by sub2. The searching for
sub1 within the string is case-insensitive.
The memory pointed to by *src must be dynamically allocated. This
function will re-allocated and re-shift that memory. Also, a
pointer to this memory block is returned.
char *x;
x = xstrdup ("Goodbye World!\n");
x = strireplace (&x, "goodbye", "Hello");
buf where search occurs, or 0 when search
was not found. A pointer to the first character of buf is also
returned when search is 0.
buf for the first occurrence of search and returns
a pointer to it. The string search is case-insensitive. This function is
therefore similar to strstr(), except for the insensitiveness.
a is "bigger",
b is "bigger"a and b are compared over len bytes, without regard
to casing. This function is similar to strstr(), except that the
comparisons are case-insensitive.
fmt and ... are the (standard) printf()-like arguments
sprintf(), except that the built
string is dynamically allocated. The caller is responsible to returning
this memory to the pool using cmm_free().
char *x = str_printf ("Hello %s...", "world");
Note: The caller is responsible for freeing the memory that is
pointed to by the return value. This must be done using either
cmm_free() or cmm_cleanup().
char verylongbuf [256];
char *cp;
.
.
cp = str_short (verylongbuf, 50);
logmsg ("buf = [%s]\n", cp);
cmm_free (cp);
buf to upper case. The
conversion is done in-place; i.e., the caller should make a copy of
buf if its contents should be preserved.
fmt and args are vprintf()-like arguments
vsprintf(), except that the string is
created using allocated memory. There is therefore no risk of buffer
overflow.
filename is the name of the file to inspect
In order to succeed in determining an appropriate extension, the file
must exist. Also note that the suggested name for MS-Office document
types is always .doc. There is no support for different Office
document types, e.g., .xls.
The return value is a suggested name. This function does not
actually rename the file in question. The suggested name is
allocated; the caller should free the memory when appropriate.
The freeing must be done using cmm_free() or cmm_cleanup().
See also supply_ext(), filetype().
char *newname;
newname = suggest_ext ("/tmp/myfile");
printf ("%s\n", newname);
cmm_free (newname);
filename is the name of file to inspect
suggest_ext() or filetype().
Note that in order to succeed in determining an appropriate
extension, the file must exist and the process must be able
to rename it. When these conditions are not met, then the
returned "new name" is just a duplicate of the old name. In any
case, the caller should free the memory occupied by the returned
name when appropriate. This freeing must be done with either
cmm_free() or cmm_cleanup().
See also filetype(), suggest_ext().
char *newname;
newname = supply_ext ("/tmp/myfile");
printf ("%s\n", newname);
cmm_free (newname);
tmp_file()tmp_file() or tmp_fopen() are removed.
Note:
fur successful removal, the files must be closed. The caller
is responsible for that. The removal of files is not checked for
success or failure.
See also tmp_file(), tmp_fopen(), tmp_fileprefix().
Strtab storage. That way, all filenames constructed by
tmp_file() are known in e-lib. When tmp_cleanup() is called,
all the files are removed.
The temporary files consist of a prefix, followed by the process
ID, a dot, and an order number. The prefix is normally /tmp/e.
Therefore default temporary filenames are
/tmp/eprocessid.ordernumber, e.g., /tmp/e002391.1.
The directory part of the prefix can be redefined by calling
tmp_fileprefix().
Note that this function is neither reentrancy-safen or thread-safe.
It's a pretty basic way of making temporary file names. It's strongly
suggested that you take a look at tmp_fopen(), which is both
reentrancy and thread-safe.
See also tmp_clean(), tmp_fileprefix().
/tmp, the other under
/usr/tmp. The last call to tmp_clean() removes all files having
the temporary names.
char const *f1, *f2;
f1 = tmp_file ();
tmp_fileprefix ("/usr/tmp");
f2 = tmp_file ();
printf ("First one: %s\n"
"Second one: %s\n", f1, f2);
tmp_clean ();
// This outputs something like:
// /tmp/e123456.1
// /usr/tmp/e123456.2
prefix is the name prefix to use for temporary files
tmp_file() and tmp_fopen().
The argument prefix may in fact also contain a
directory part, as in /tmp/, or /usr/tmp/my.
The default temporary file prefix is /tmp/e. Any calls to
tmp_fileprefix() will overrule this default.
See also tmp_file(), tmp_clean().
// from now on make temp files as /usr/tmp/myprog*
tmp_fileprefix ("/usr/tmp/myprog");
filename is set to point to the name of the opened file, if
filename is not 0
mktemp() and mkstemp() in the manpages for more
info.)
The return value is the opened file, or 0 on error. In the latter case
errno may be inspected to see what the error is.
The argument filename may be set by the caller to the address of a
char*. In that case, tmp_fopen() will set this pointer to point to
the name of the file in question. When filename is 0, then
tmp_fopen() will not provide information about the temporary file, but
will only add this name to the internal list of temporary files. After
closing, all temporary files that were created using tmp_fopen() or
tmp_file() may be removed using tmp_clean().
/usr/tmp/ with a prefix myfile. The file will
therefore be created as something like /usr/tmp/myfileABCDEF.
char *n;
FILE *f;
tmp_fileprefix ("/usr/tmp/myfile");
if (! (f = tmp_fopen (&n)) )
error ("Failed to open tmpfile %s: %s\n",
n, strerror (errno));
printf ("Temp file %s is now open for writing.\n",
n);
fprintf (f, "Hello World!\n");
fclose (f);
printf ("Temp file %s is now used and closed.\n",
n);
tmp_clean();
printf ("Temp file %s is now removed.\n",
n);
n is the number of elements to alloocate, sz is the size of
each element
out_of_memory() to issue an error.
The allocated memory is set to zero. Internally, the cmm*() set
of functions is used so that a memory trail usage trail is
available. Therefore, note that the thus allocated memory may
only be freed using cmm_free() or cmm_cleanup().
See also set_memerr(), out_of_memory(), x...().
size is the number of bytes to allocate
out_of_memory() to issue an error.
Internally, this function uses cmm_malloc() so that the memory
usage trail is recorded. Therefore, note that xmalloc()-d memory
may only be freed using cmm_free() or cmm_cleanup().
See also set_memerr(), out_of_memory(), x*(), cmm*().
out_of_memory() to issue an error.
When oldmem is 0, the memory is just allocated. Internally, the
function maps to the cmm*() functions so that a memory usage
trail is available. Therefore note that you may only free
xrealloc()-d memory with cmm_free() or with cmm_cleanup(),
and not with the standard free().
See also set_memerr(), out_of_memory(), x*(), cmm*().
x is the string to duplicate
strdup(), except that
out_of_memory() is called when a string duplication fails.
Furthermore, it uses internally the cmm*() set of functions, so
that a memory usage trail is available. Therefore note that you
may only free memory returned by xstrdup() with cmm_free()
or cmm_cleanup().
xstrdup(0) will return a 0-pointer.
See also set_memerr(), out_of_memory(), x...().
zip_threshold(). The
buffer is compressed in-place (i.e., its memory is reallocated) and the
size sz is adjusted accordingly.
See also zip_decompress(), zip_threshold().
char *buf = 0;
int i;
long sz;
for (i = 0; i < 10; i++)
buf = str_addprintf (buf, "This is the %d'th string.\n", i);
sz = strlen (buf);
printf ("Size before compression: %ld\n", sz);
buf = zip_compress (buf, &sz);
printf ("Size after compression: %ld\n", sz);
buf = zip_decompress (buf, &sz);
printf ("Size after decompression: %ld\n"
"Buffer contents: %s\n", sz, buf);
buf is decompressed (to a greater size)
and the associated memory is re-allocated. The size, pointed
to by sz, is adjusted.
See also zip_compress(), zip_threshold().
zip_compress().
diff is the number of bytes to gain with compression
zip_compress() will leave its buffer in an uncompressed
state.
The default threshold value is 95.
See also zip_compress(), zip_decompress().
compress() will compress
a buffer only when the gain is more than 40%.
void *compress (char *buf,
unsigned long *len) {
// Determine the requested gain: 60% off
// the original length. Then set the
// requested gain.
unsigned long req_gain = *len * 4 / 10;
zip_threshold ( (int) req_gain );
// Now zip it up.
return (zip_compress (buf, len));
}