forked from lda/telodendria
Begin working on Util man page
This commit is contained in:
parent
f07ea912b2
commit
6900d0649e
5 changed files with 100 additions and 79 deletions
83
man/man3/Util.3
Normal file
83
man/man3/Util.3
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
.Dd $Mdocdate: November 25 2022 $
|
||||||
|
.Dt UTIL 3
|
||||||
|
.Os Telodendria Project
|
||||||
|
.Sh NAME
|
||||||
|
.Nm Util
|
||||||
|
.Nd Some misc. helper functions that don't need their own headers.
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.In Util.h
|
||||||
|
.Ft unsigned long
|
||||||
|
.Fn UtilServerTs "void"
|
||||||
|
.Ft unsigned long
|
||||||
|
.Fn UtilLastModified "char *"
|
||||||
|
.Ft int
|
||||||
|
.Fn UtilMkdir "const char *" "const mode_t"
|
||||||
|
.Ft char *
|
||||||
|
.Fn UtilUtf8Encode "unsigned long"
|
||||||
|
.Ft char *
|
||||||
|
.Fn UtilStringDuplicate "char *"
|
||||||
|
.Ft char *
|
||||||
|
.Fn UtilStringConcat "char *" "char *"
|
||||||
|
.Ft int
|
||||||
|
.Fn UtilSleepMillis "long"
|
||||||
|
.Ft size_t
|
||||||
|
.Fn UtilParseBytes "char *"
|
||||||
|
.Ft ssize_t
|
||||||
|
.Fn UtilGetDelim "char **" "size_t *" "int" "FILE *"
|
||||||
|
.Ft ssize_t
|
||||||
|
.Fn UtilGetLine "char **" "size_t *" "FILE *"
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Pp
|
||||||
|
This header holds a number of random functions related to strings,
|
||||||
|
time, and other tasks that don't require a full API, just one or
|
||||||
|
two functions. For the most part, the functions here are entirely
|
||||||
|
standalone, depending only on POSIX functions, however there are a
|
||||||
|
few that specifically utilize Telodendria APIs. Those are noted.
|
||||||
|
.Pp
|
||||||
|
.Fn UtilServerTs
|
||||||
|
gets the current time in milliseconds since the Unix epoch. This
|
||||||
|
uses
|
||||||
|
.Xr gettimeofday 2
|
||||||
|
and time_t, and converts it to a single number, which is then
|
||||||
|
returned to the caller. A note on the 2038 problem: as long as
|
||||||
|
sizeof(long) >= 8, that is, as long as the long datatype is 64 bits
|
||||||
|
or more, which it is on all modern 64-bit Unix-like operating
|
||||||
|
systems, then everything should be fine. Expect Telodendria on 32 bit
|
||||||
|
machines to break in 2038. I didn't want to try to hack together
|
||||||
|
some system to store larger numbers than the architecture supports.
|
||||||
|
We can always re-evaluate things over the next decade.
|
||||||
|
.Pp
|
||||||
|
.Fn UtilUtf8Encode
|
||||||
|
takes a UTF-8 codepoint and encodes it into a string buffer
|
||||||
|
containing between 1 and 4 bytes. The string buffer is allocated
|
||||||
|
on the heap, so it should be freed when it is no longer needed.
|
||||||
|
.Pp
|
||||||
|
.Fn UtilStringDuplicate
|
||||||
|
duplicates a NULL-terminated string, and returns a new string on the
|
||||||
|
heap. This is useful when a function takes in a string that it needs
|
||||||
|
to store for for long amounts of time, even perhaps after the
|
||||||
|
original string is long gone.
|
||||||
|
.Pp
|
||||||
|
.Fn UtilSleepMillis
|
||||||
|
sleeps the calling thread for the given number of milliseconds. It
|
||||||
|
occurred to me that POSIX does not specify a super friendly way to
|
||||||
|
sleep, so this is a wrapper around the POSIX
|
||||||
|
.Xr nanosleep 2
|
||||||
|
designed to make its usage much, much simpler.
|
||||||
|
.Pp
|
||||||
|
.Fn UtilLastModified
|
||||||
|
uses
|
||||||
|
.Xr stat 2
|
||||||
|
to get the last modified time of the given file. This is used
|
||||||
|
primarily for caching file data.
|
||||||
|
.Pp
|
||||||
|
.Fn UtilStringConcat
|
||||||
|
takes in two NULL-terminated strings and returns their concatenation.
|
||||||
|
It works a lot like
|
||||||
|
.Xr strcat 3 ,
|
||||||
|
but it takes care of allocating memory big enough to hold both
|
||||||
|
strings. One or both strings may be NULL. If a string is NULL, it
|
||||||
|
is treated like an empty string.
|
||||||
|
.Sh RETURN VALUES
|
||||||
|
.Pp
|
||||||
|
TODO
|
|
@ -464,8 +464,6 @@ HttpServerWorkerThread(void *args)
|
||||||
HashMap *requestParams;
|
HashMap *requestParams;
|
||||||
ssize_t requestPathLen;
|
ssize_t requestPathLen;
|
||||||
|
|
||||||
int lineError = -1;
|
|
||||||
|
|
||||||
ssize_t i = 0;
|
ssize_t i = 0;
|
||||||
HttpRequestMethod requestMethod;
|
HttpRequestMethod requestMethod;
|
||||||
|
|
||||||
|
@ -484,13 +482,13 @@ HttpServerWorkerThread(void *args)
|
||||||
/* Get the first line of the request.
|
/* Get the first line of the request.
|
||||||
*
|
*
|
||||||
* Every once in a while, we're too fast for the client. When this
|
* Every once in a while, we're too fast for the client. When this
|
||||||
* happens, UtilGetLine() sets lineError to EAGAIN. If we get
|
* happens, UtilGetLine() sets errno to EAGAIN. If we get
|
||||||
* EAGAIN, then clear the error on the stream and try again
|
* EAGAIN, then clear the error on the stream and try again
|
||||||
* after 1ms. This is typically more than enough time for the
|
* after 1ms. This is typically more than enough time for the
|
||||||
* client to send data. */
|
* client to send data. */
|
||||||
firstRead = UtilServerTs();
|
firstRead = UtilServerTs();
|
||||||
while ((lineLen = UtilGetLine(&line, &lineSize, fp, &lineError)) == -1
|
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) == -1
|
||||||
&& lineError == EAGAIN)
|
&& errno == EAGAIN)
|
||||||
{
|
{
|
||||||
clearerr(fp);
|
clearerr(fp);
|
||||||
|
|
||||||
|
@ -571,7 +569,7 @@ HttpServerWorkerThread(void *args)
|
||||||
goto internal_error;
|
goto internal_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((lineLen = UtilGetLine(&line, &lineSize, fp, &lineError)) != -1)
|
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) != -1)
|
||||||
{
|
{
|
||||||
char *headerKey;
|
char *headerKey;
|
||||||
char *headerValue;
|
char *headerValue;
|
||||||
|
|
|
@ -245,7 +245,7 @@ TelodendriaConfigParse(HashMap * config, LogConfig * lc)
|
||||||
GET_DIRECTIVE("max-cache");
|
GET_DIRECTIVE("max-cache");
|
||||||
ASSERT_NO_CHILDREN("max-cache");
|
ASSERT_NO_CHILDREN("max-cache");
|
||||||
ASSERT_VALUES("max-cache", 1);
|
ASSERT_VALUES("max-cache", 1);
|
||||||
tConfig->maxCache = UtilStringToBytes(ArrayGet(value, 0));
|
tConfig->maxCache = UtilParseBytes(ArrayGet(value, 0));
|
||||||
|
|
||||||
GET_DIRECTIVE("federation");
|
GET_DIRECTIVE("federation");
|
||||||
ASSERT_NO_CHILDREN("federation");
|
ASSERT_NO_CHILDREN("federation");
|
||||||
|
|
19
src/Util.c
19
src/Util.c
|
@ -263,7 +263,7 @@ UtilSleepMillis(long ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
UtilStringToBytes(char *str)
|
UtilParseBytes(char *str)
|
||||||
{
|
{
|
||||||
size_t bytes = 0;
|
size_t bytes = 0;
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ UtilStringToBytes(char *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream, int *err)
|
UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream)
|
||||||
{
|
{
|
||||||
char *curPos, *newLinePtr;
|
char *curPos, *newLinePtr;
|
||||||
size_t newLinePtrLen;
|
size_t newLinePtrLen;
|
||||||
|
@ -321,7 +321,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream, int *err)
|
||||||
|
|
||||||
if (!linePtr || !n || !stream)
|
if (!linePtr || !n || !stream)
|
||||||
{
|
{
|
||||||
*err = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +331,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream, int *err)
|
||||||
|
|
||||||
if (!(*linePtr = Malloc(*n)))
|
if (!(*linePtr = Malloc(*n)))
|
||||||
{
|
{
|
||||||
*err = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,6 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream, int *err)
|
||||||
|
|
||||||
if (ferror(stream) || (c == EOF && curPos == *linePtr))
|
if (ferror(stream) || (c == EOF && curPos == *linePtr))
|
||||||
{
|
{
|
||||||
*err = errno;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,9 +357,9 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream, int *err)
|
||||||
if (SSIZE_MAX / 2 < *n)
|
if (SSIZE_MAX / 2 < *n)
|
||||||
{
|
{
|
||||||
#ifdef EOVERFLOW
|
#ifdef EOVERFLOW
|
||||||
*err = EOVERFLOW;
|
errno = EOVERFLOW;
|
||||||
#else
|
#else
|
||||||
*err = ERANGE;
|
errno = ERANGE;
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -369,7 +368,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream, int *err)
|
||||||
|
|
||||||
if (!(newLinePtr = Realloc(*linePtr, newLinePtrLen)))
|
if (!(newLinePtr = Realloc(*linePtr, newLinePtrLen)))
|
||||||
{
|
{
|
||||||
*err = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +390,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream, int *err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
UtilGetLine(char **linePtr, size_t * n, FILE * stream, int *err)
|
UtilGetLine(char **linePtr, size_t * n, FILE * stream)
|
||||||
{
|
{
|
||||||
return UtilGetDelim(linePtr, n, '\n', stream, err);
|
return UtilGetDelim(linePtr, n, '\n', stream);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,6 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Util.h: Some misc. helper functions that provide functionality that
|
|
||||||
* doesn't need its own full API. The functions here are entirely
|
|
||||||
* stand-alone, and generally don't depend on any of the other APIs
|
|
||||||
* defined by Telodendria.
|
|
||||||
*/
|
|
||||||
#ifndef TELODENDRIA_UTIL_H
|
#ifndef TELODENDRIA_UTIL_H
|
||||||
#define TELODENDRIA_UTIL_H
|
#define TELODENDRIA_UTIL_H
|
||||||
|
|
||||||
|
@ -35,25 +29,6 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the current type in milliseconds since the Unix epoch. This uses
|
|
||||||
* POSIX gettimeofday(2) and time_t, and converts it to a single number,
|
|
||||||
* which is returned.
|
|
||||||
*
|
|
||||||
* A note on the 2038 problem: that's a long ways away, screw future
|
|
||||||
* me!
|
|
||||||
*
|
|
||||||
* Kidding. As long as (sizeof(long) == 8), that is, as long as the
|
|
||||||
* long datatype is 64 bits, which is is on all modern 64-bit Unix-like
|
|
||||||
* operating systems, then everything should be fine. Expect
|
|
||||||
* Telodendria on 32-bit machines to break in 2038. I didn't want to
|
|
||||||
* try to hack together some system to store larger numbers than the
|
|
||||||
* architecture supports. We can always re-evaluate things over the
|
|
||||||
* next decade.
|
|
||||||
*
|
|
||||||
* Return: A long representing the current time in milliseconds since
|
|
||||||
* the beginning of the Unix epoch, just as the Matrix spec requires.
|
|
||||||
*/
|
|
||||||
extern unsigned long
|
extern unsigned long
|
||||||
UtilServerTs(void);
|
UtilServerTs(void);
|
||||||
|
|
||||||
|
@ -63,59 +38,25 @@ extern unsigned long
|
||||||
extern int
|
extern int
|
||||||
UtilMkdir(const char *, const mode_t);
|
UtilMkdir(const char *, const mode_t);
|
||||||
|
|
||||||
/*
|
|
||||||
* Encode a single UTF-8 codepoint as a string buffer containing
|
|
||||||
* between 1 and 4 bytes. The string buffer is allocated on the heap,
|
|
||||||
* so it should be freed when it is no longer needed.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
*
|
|
||||||
* (unsigned long) The UTF-8 codepoint to encode as a byte buffer.
|
|
||||||
*
|
|
||||||
* Return: a null-terminated byte buffer representing the UTF-8
|
|
||||||
* codepoint.
|
|
||||||
*/
|
|
||||||
extern char *
|
extern char *
|
||||||
UtilUtf8Encode(unsigned long);
|
UtilUtf8Encode(unsigned long);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Duplicate a null-terminated string, and return a new string on the
|
|
||||||
* heap.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* (char *) The string to duplicate. It can be located anywhere on
|
|
||||||
* the heap or the stack.
|
|
||||||
*
|
|
||||||
* Return: A pointer to a null-terminated string on the heap. You must
|
|
||||||
* free() it when you're done with it. This may also return NULL if the
|
|
||||||
* call to malloc() fails.
|
|
||||||
*/
|
|
||||||
extern char *
|
extern char *
|
||||||
UtilStringDuplicate(char *);
|
UtilStringDuplicate(char *);
|
||||||
|
|
||||||
extern char *
|
extern char *
|
||||||
UtilStringConcat(char *, char *);
|
UtilStringConcat(char *, char *);
|
||||||
|
|
||||||
/*
|
|
||||||
* Sleep for the given number of milliseconds. This is a simple wrapper
|
|
||||||
* for nanosleep() that makes its usage much easier.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* (long) The number of milliseconds to sleep for.
|
|
||||||
*
|
|
||||||
* Return: The result of nanosleep().
|
|
||||||
*/
|
|
||||||
extern int
|
extern int
|
||||||
UtilSleepMillis(long);
|
UtilSleepMillis(long);
|
||||||
|
|
||||||
extern size_t
|
extern size_t
|
||||||
UtilStringToBytes(char *);
|
UtilParseBytes(char *);
|
||||||
|
|
||||||
extern ssize_t
|
extern ssize_t
|
||||||
UtilGetDelim(char **, size_t *, int, FILE *, int *);
|
UtilGetDelim(char **, size_t *, int, FILE *);
|
||||||
|
|
||||||
extern ssize_t
|
extern ssize_t
|
||||||
UtilGetLine(char **, size_t *, FILE *, int *);
|
UtilGetLine(char **, size_t *, FILE *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_UTIL_H */
|
#endif /* TELODENDRIA_UTIL_H */
|
||||||
|
|
Loading…
Reference in a new issue