Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4908a60
Fix the qprintf() % bug (with changes copied from the apos_autoscale …
Lightning11wins Feb 26, 2026
a044167
Improve documentation of qprintf().
Lightning11wins Apr 6, 2026
a5ff3ab
Add LIKELY() and UNLIKELY() where it is obvious.
Lightning11wins Apr 6, 2026
9e97d25
Improve function and struct doc comments.
Lightning11wins Apr 8, 2026
3c317ae
Improve readability of several functions with better code patterns an…
Lightning11wins Apr 8, 2026
ff299ae
Improve tools for handling errors from qprintf().
Lightning11wins Apr 10, 2026
7a68189
Improve #include formatting.
Lightning11wins Apr 10, 2026
3770556
Refactor qpfPrintf_va_internal() to improve readability and maintaina…
Lightning11wins Apr 10, 2026
6566a97
Clean up qprintf a little bit more.
Lightning11wins Apr 13, 2026
db66d7e
Update docs for qprintf.
Lightning11wins Apr 13, 2026
91bbea9
Resolve greptile comments.
Lightning11wins Apr 13, 2026
0d99e11
Fix missing no_grow check.
Lightning11wins Apr 14, 2026
76a9049
Fix a Greptile comment with testing.
Lightning11wins Apr 14, 2026
47327c0
Fix a Greptile comment and update qpf_internal_itoa().
Lightning11wins Apr 14, 2026
dbeec43
Fix a buffer underflow bug caused by a previous fix.
Lightning11wins Apr 14, 2026
2f65012
Modify error line numbers to be stored as unsigned shorts instead of …
Lightning11wins Apr 14, 2026
b9e7e5a
Clean up.
Lightning11wins Apr 14, 2026
d93c43b
Add code to handle edge cases.
Lightning11wins Apr 27, 2026
1a0faf8
Add support for using grow functions to qprintf.
Lightning11wins May 14, 2026
fc43c9e
Add code to assert error types passed to QPERR() are valid.
Lightning11wins May 14, 2026
b29817c
Fix compiler error.
Lightning11wins May 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 58 additions & 34 deletions centrallix-lib/include/qprintf.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
#ifndef _QPRINTF_H
#define _QPRINTF_H

#ifdef CXLIB_INTERNAL
#include "cxsec.h"
#include "magic.h"
#else
#include "cxlib/cxsec.h"
#include "cxlib/magic.h"
#endif

/************************************************************************/
/* Centrallix Application Server System */
/* Centrallix Base Library */
/* */
/* Copyright (C) 1998-2006 LightSys Technology Services, Inc. */
/* Copyright (C) 1998-2026 LightSys Technology Services, Inc. */
/* */
/* You may use these files and this library under the terms of the */
/* GNU Lesser General Public License, Version 2.1, contained in the */
Expand All @@ -22,48 +14,80 @@
/* Module: qprintf.c, qprintf.h */
/* Author: Greg Beeley (GRB) */
/* Creation: January 31, 2006 */
/* Description: Quoting Printf routine, used to make sure that */
/* injection type attacks don't occur when building */
/* strings. These functions do not support some of the */
/* more advanced (and dangerous) features of the normal */
/* printf() library calls. */
/* Description: Quoting Printf routine that helps to prevent injection */
/* attacks when building strings. These functions also do */
/* not support some of the more advanced (and dangerous) */
/* features found in the standard printf() library. */
/* See centrallix-sysdoc/QPrintf.md for more information. */
/************************************************************************/


#include <stdarg.h>

typedef int (*qpf_grow_fn_t)(char**, size_t*, size_t, void*, size_t);
#ifdef CXLIB_INTERNAL
#include "cxsec.h"
#include "magic.h"
#else
#include "cxlib/cxsec.h"
#include "cxlib/magic.h"
#endif

#define QPF_ERR_T_NO_ERRORS (0) /* a default error buffer value with no errors */
#define QPF_ERR_T_NOTIMPL (1<<0) /* unimplemented feature */
#define QPF_ERR_T_BUFOVERFLOW (1<<1) /* dest buffer too small */
#define QPF_ERR_T_INSOVERFLOW (1<<2) /* NLEN or *LEN restriction occurred */
#define QPF_ERR_T_NOTPOSITIVE (1<<3) /* %POS conversion but number was neg */
#define QPF_ERR_T_BADSYMBOL (1<<4) /* &SYM filter did not match the data. */
#define QPF_ERR_T_MEMORY (1<<5) /* Memory allocation failed (internal). */
#define QPF_ERR_T_BADLENGTH (1<<6) /* Length for NLEN or *LEN was invalid */
#define QPF_ERR_T_BADFORMAT (1<<7) /* Format string was invalid */
#define QPF_ERR_T_RESOURCE (1<<8) /* Internal resource limit hit */
#define QPF_ERR_T_NULL (1<<9) /* NULL pointer passed (e.g. as a string) */
#define QPF_ERR_T_INTERNAL (1<<10) /* Unrecoverable internal error. */
#define QPF_ERR_T_BADFILE (1<<11) /* Bad filename for &FILE filter */
#define QPF_ERR_T_BADPATH (1<<12) /* Bad pathname for &PATH filter */
#define QPF_ERR_T_BADCHAR (1<<13) /* Bad character for filter (e.g. an octothorpe for &DB64) */
#define QPF_ERR_COUNT (14) /* The number of errors listed above. */

/*** A function to grow a string buffer.
***
*** @param str The string buffer being grown.
*** @param size A pointer to the current size of the string buffer.
*** @param offset An offset up to which data must be preserved.
*** @param args Arguments for growing the buffer.
*** @param req The requested size.
*** @returns True (1) if successful, and false (0) if an error occurs.
***/
typedef int (*qpf_grow_fn_t)(char** str, size_t* size, size_t offset, void* args, size_t req);

/*** Stores information about a qprint session, including details about errors
*** such as parsing and formatting issues that have occurred.
***
*** @param Errors An error mask indicating any errors that have occurred, or
*** 0 (aka. `QPF_ERR_T_NO_ERRORS`) if no errors have occurred.
*** @param ErrorLines An array where each index represents a type of error in
*** order (e.g. 0 represents `QPF_ERR_T_NOTIMPL`) and each value represents
*** the line number where the error occurred, or 0 if this error type has
*** not occurred during the session.
***/
typedef struct _QPS
{
unsigned int Errors; /* QPF_ERR_T_xxx */
unsigned short ErrorLines[QPF_ERR_COUNT];
}
QPSession, *pQPSession;

#define QPF_ERR_T_NOTIMPL 1 /* unimplemented feature */
#define QPF_ERR_T_BUFOVERFLOW 2 /* dest buffer too small */
#define QPF_ERR_T_INSOVERFLOW 4 /* NLEN or *LEN restriction occurred */
#define QPF_ERR_T_NOTPOSITIVE 8 /* %POS conversion but number was neg */
#define QPF_ERR_T_BADSYMBOL 16 /* &SYM filter did not match the data. */
#define QPF_ERR_T_MEMORY 32 /* Memory allocation failed (internal). */
#define QPF_ERR_T_BADLENGTH 64 /* Length for NLEN or *LEN was invalid */
#define QPF_ERR_T_BADFORMAT 128 /* Format string was invalid */
#define QPF_ERR_T_RESOURCE 256 /* Internal resource limit hit */
#define QPF_ERR_T_NULL 512 /* NULL pointer passed (e.g. as a string) */
#define QPF_ERR_T_INTERNAL 1024 /* Uncorrectable internal error. */
#define QPF_ERR_T_BADFILE 2048 /* Bad filename for &FILE filter */
#define QPF_ERR_T_BADPATH 4096 /* Bad pathname for &PATH filter */
#define QPF_ERR_T_BADCHAR 8192 /* Bad character for filter (e.g. an octothorpe for &DB64) */

#define QPERR(x) (s->Errors |= (x))

/*** QPrintf methods ***/
pQPSession qpfOpenSession();
pQPSession qpfOpenSession(void);
int qpfCloseSession(pQPSession s);
int qpfClearErrors(pQPSession s);
unsigned int qpfErrors(pQPSession s);
void qpfLogErrors(pQPSession s);
int qpfNoGrow(char** str, size_t* size, size_t offs, void* arg, size_t req_size);
int qpfSysMallocGrow(char** str, size_t* size, size_t offset, void* args, size_t req_size);
int qpfPrintf(pQPSession s, char* str, size_t size, const char* format, ...);
int qpfPrintf_va(pQPSession s, char* str, size_t size, const char* format, va_list ap);
int qpfPrintf_g(pQPSession s, char** str, size_t* size, qpf_grow_fn_t grow_fn, void* grow_arg, const char* format, ...);
int qpfPrintf_gva(pQPSession s, char** str, size_t* size, qpf_grow_fn_t grow_fn, void* grow_arg, const char* format, va_list ap);
void qpfRegisterExt(char* ext_spec, int (*ext_fn)(), int is_source);

/*** Raw interface - should only be used internally by cxlib **/
Expand Down
Loading