AG_STRING(3)

NAME
AG_String - agar C string specific functions

SYNOPSIS

    #include <agar/core.h>

DESCRIPTION
The functions described here are used to construct and manipulate C strings (byte strings with a terminating NUL character), and convert text between different character encodings.

FORMATTED OUTPUT CONVERSION
char * AG_Printf(const char *format, ...)

char * AG_PrintfN(Uint buffer, const char *format, ...)

AG_FmtString * AG_PrintfP(const char *format, ...)

void AG_FreeFmtString(AG_FmtString *fs)

AG_Size AG_ProcessFmtString(AG_FmtString *fs, char *dst, AG_Size dstSize)

void AG_RegisterFmtStringExt(const char *fmt, AG_FmtStringExtFn extFn)

TYPE AG_FMTSTRING_ARG(AG_FmtString *fs)

void AG_UnregisterFmtStringExt(const char *fmt)

The AG_Printf() function performs formatted output conversion (similar to printf(3), with Agar-specific extensions). AG_Printf() returns a pointer to an internally managed buffer, which will remain valid until the application or thread terminates (in multithreaded mode, thread-local storage is used). The caller must not attempt to free(3) the returned pointer.

The AG_PrintfN() variant allows multiple buffers to be used. The buffer argument specifies the buffer index to use (any integer up to AG_STRING_BUFFER_MAX is valid).

The AG_PrintfP() function allocates and initializes a new AG_FmtString structure from the given format string and arguments. Unlike AG_Printf() which accepts literal values as arguments, the arguments to AG_PrintfP() must be pointers to specifically typed data. Those arguments will be accessed only at a later time (when AG_ProcessFmtString() is called).

AG_ProcessFmtString() processes a format string (previously returned by AG_PrintfP()), writing the formatted output to dst (which should be at least dstSize bytes in size). If insufficient space is available in the buffer, the output is truncated.

AG_FreeFmtString() releases all resources allocated by a format string.

AG_ProcessFmtString() returns the number of characters that would have been copied were dstSize unlimited. The formatted output is always NUL-terminated.

Agar's formatting engine supports the following built-in specifiers:

%d, %i
    int
%ld, %li
    long int
%lld, %lli
    long long int or Sint64
%o, %u, %x, %X
    unsigned int
%lu, %lo, %lx
    long unsigned int
%llu, %llo, %llx
    long long unsigned int or Uint64
%c  char
%s  char *
%f, %g
    float *
%lf, %lg
    double *
%[u8]
    Uint8 *
%[s8]
    Sint8 *
%[u16]
    Uint16 *
%[s16]
    Sint16 *
%[u32]
    Uint32 *
%[s32]
    Sint32 *
%[u64]
    Uint64 * (needs AG_HAVE_64BIT)
%[s64]
    Sint64 * (needs AG_HAVE_64BIT)
%[objName]
    AG_Object * (Returns object name)
%[objType]
    AG_Object * (Returns class name)

Specifiers for user-defined formatting routines can be registered at runtime. For example, the ag_math library, upon initialization, registers %[V] for its M_Vector(3) type, %[M] for its M_Matrix(3) type, etc. (see M_String(3) for a complete list).

The AG_RegisterFmtStringExt() function registers a new "%[foo]" style specifier. The extFn calback functions should be of the form:

    typedef AG_Size (*AG_FmtStringExtFn)(AG_FmtString *fs, char *dst,
                                        AG_Size dstSize);

The callback is expected to write to fixed-size buffer dst, and return the number of characters that would have been written were dstSize unlimited. The callback function can NUL-terminate the string, but it is not a requirement. A generic pointer to the argument variable can be obtained from the AG_FMTSTRING_ARG() macro.

The AG_UnregisterFmtStringExt() function removes the given extended format specifier.

SEPARATING STRINGS
char * AG_Strsep(char **stringp, const char *delim)

The AG_Strsep() function locates, in the string referenced by *stringp, the first occurrence of any character in the string delim (or the terminating NUL character) and replaces it with a NUL. The location of the next character after the delimiter character (or NULL, if the end of the string was reached) is stored in *stringp. The original value of *stringp is returned.

An “empty” field (i.e., a character in the string delim occurs as the first character of *stringp) can be detected by comparing the location referenced by the returned pointer to NUL. If *stringp is initially NULL, AG_Strsep() returns NULL.

COPYING AND CONCATENATING STRINGS
char * AG_Strdup(const char *s)

char * AG_TryStrdup(const char *s)

AG_Size AG_Strlcpy(char *dst, const char *src, AG_Size dst_size)

AG_Size AG_Strlcat(char *dst, const char *src, AG_Size dst_size)

AG_Size AG_StrlcpyInt(char *dst, int number, AG_Size dst_size)

AG_Size AG_StrlcatInt(char *dst, int number, AG_Size dst_size)

AG_Size AG_StrlcpyUint(char *dst, Uint number, AG_Size dst_size)

AG_Size AG_StrlcatUint(char *dst, Uint number, AG_Size dst_size)

The AG_Strdup() function returns a copy of the given C string. If insufficient memory is available, a AG_FatalError(3) is raised. The AG_TryStrdup() variant returns NULL on failure.

The AG_Strlcpy() and AG_Strlcat() functions copy and concatenate C strings respectively. They are designed to be safer, more consistent, and less error prone replacements for strncpy(3) and strncat(3). Unlike those functions, AG_Strlcpy() and AG_Strlcat() take the full size of the buffer (not just the length) and guarantee to NUL-terminate the result (as long as size is larger than 0 or, in the case of AG_Strlcat(), as long as there is at least one byte free in dst). Note that a byte for the NUL should be included in size.

The AG_Strlcpy() function copies up to size - 1 characters from the NUL-terminated string src to dst, NUL-terminating the result. The AG_Strlcat() function appends the NUL-terminated string src to the end of dst. It will append at most size - strlen(dst) - 1 bytes, NUL-terminating the result.

The AG_Strlcpy() and AG_Strlcat() functions return the total length of the string they tried to create. For AG_Strlcpy() that means the length of src. For AG_Strlcat() that means the initial length of dst plus the length of src.

AG_StrlcpyInt(), AG_StrlcpyUint(), AG_StrlcatInt(), and AG_StrlcatUint() convert an integer to a string representation (equivalent to a printf(3) "%d" or "%u"). The resulting string is copied to (or concatenated against) the destination buffer.

UNICODE OPERATIONS
AG_Char * AG_ImportUnicode(const char *encoding, const char *src, AG_Size *pOutLen, AG_Size *pOutSize)

int AG_ExportUnicode(const char *encoding, char *dst, const AG_Char *src, AG_Size dstSize)

inline AG_Size AG_LengthUTF8(const char *s)

inline int AG_CharLengthUTF8(unsigned char byte)

inline AG_Size AG_LengthUCS4(const AG_Char *ucs)

inline int AG_LengthUTF8FromUCS4(const AG_Char *ucs, AG_Size *rv)

inline AG_Size AG_CharLengthUTF8FromUCS4(AG_Char ch)

AG_ImportUnicode() converts the string src (in specified encoding) to internal (UCS-4) format. On success, it returns a newly-allocated UCS-4 buffer. The number of characters in the string is returned in pOutLen (if not NULL). Recognized values for encoding include "US-ASCII" and "UTF-8". If Agar was compiled with iconv(3) support then any character set supported by iconv may be specified.

The AG_ExportUnicode() function converts the contents of the given UCS-4 text buffer to the specified encoding ("US-ASCII and "UTF-8" are handled internally by Agar, other encodings are handled through iconv where available). The resulting text is written to the specified buffer dst, which should be of the specified size dstSize, in bytes. The written string is always NUL-terminated.

AG_LengthUTF8() counts the number of characters in the given UTF-8 string. On success, it returns 0 the character count is written to rv. If the string is not a valid UTF-8 string, the function returns -1.

AG_CharLengthUTF8() evaluates whether the given byte is the start of an UTF-8 character sequence and returns the sequence length in bytes (or 1 if there is none).

AG_LengthUCS4() returns the number of characters in the given UCS-4 text buffer (analogous to strlen(3)). The terminating NUL is not included in the returned count.

AG_LengthUTF8FromUCS4() returns the number of bytes that would be needed to encode the given UCS-4 string in UTF-8 encoding. On success, it returns 0 and writes the count to rv. If ucs contains an invalid Unicode character, it fails and returns -1.

AG_CharLengthUTF8FromUCS4() returns the number of bytes that would be needed to encode the given UCS-4 character as an UTF-8 character sequence.

STRING OPERATIONS
inline int AG_Strcasecmp(const char *s1, const char *s2)

inline int AG_Strncasecmp(const char *s1, const char *s2, AG_Size n)

const char * AG_Strcasestr(const char *big, const char *little)

void AG_StrReverse(char *s)

The AG_Strcasecmp() and AG_Strncasecmp() functions peforms case-insensitive comparison between two C strings s1 and s2. The return value is greater than, equal to, or less than 0 depending on whether s1 is lexicographically greater than, equal to, or less than s2.

The AG_Strcasestr() function is a case-insensitive version of the standard strstr(3). It locates the first occurence of the little string in the big string.

The AG_StrReverse() function reverses all characters in the C string s.

EXAMPLES
The following Agar-GUI code creates an AG_Label(3), passing a formatted string (in an internally-managed buffer) to the label constructor:

    int myInt = 1234;
    AG_LabelNewS(win, 0, AG_Printf("myInt=%d", myInt));

Whenever multiple strings are needed simultaneously, AG_PrintfN() allows a buffer index to be specified:

    void MyFn(const char *string1, const char *string2);
    MyFn(AG_PrintfN(0, "First string"),
         AG_PrintfN(1, "Second string"));

The following code uses AG_Strsep() to parse a string, and prints each token in separate line:

    char *string = AG_Strdup("abc,def,ghi");
    char *pString = string, *token;
    while ((token = AG_Strsep(&string, ",")) != NULL) {
    	printf("%s\n", token);
    }
    free(pString);

The following code constructs a string and appends a formatted number to it:

    char myBuffer[30];
    int i = 0;
    for (i = 0; i < 10; i++) {
    	AG_Strlcpy(myBuffer, "Item #", sizeof(myBuffer));
    	AG_StrlcatInt(myBuffer, i, sizeof(myBuffer));
    }

The following code converts a string from LATIN-1 (iso-8859-1) encoding to Unicode, counts the number of characters, and exports the string to UTF-8 encoding:

    char *dst;
    AG_Char *unicode, *s;
    int count = 0;
    AG_Size dstLen;
    if ((unicode = AG_ImportUnicode("LATIN1", input, NULL)) == NULL) {
    	AG_FatalError(NULL);
    }
    for (s = &unicode[0]; *s != ' '; s++) {
    	count++;
    }
    if (AG_LengthUTF8FromUCS4(unicode, &dstLen) == -1) {
    	AG_FatalError(NULL);
    }
    dst = AG_Malloc(dstLen);
    AG_ExportUnicode("UTF-8", dst, unicode, dstLen)

The following GUI code fragment registers an extension to the AG_Printf(3) formatting engine, and uses the new format when creating static and polled labels:

    AG_Size
    PrintMyVector(AG_FmtString *fs, char *dst, AG_Size dstSize)
    {
    	struct my_vector *my = AG_FMTSTRING_ARG(fs);
    	return AG_Snprintf(dst, dstSize, "[%f,%f]", my->x, my->y);
    }
    ...
    struct my_vector v;
    AG_RegisterFmtStringExt("myVec", PrintMyVector);
    AG_LabelNewS(win, 0, AG_Printf("Static label: %[myVec]", &v));
    AG_LabelNewPolled(win, 0, "Polled label: %[myVec]", &v);

SEE ALSO
AG_Error(3), AG_Intro(3), strcmp(3), string(3), strlen(3)

HISTORY
The AG_String interface was first documented in Agar 1.5.0.