/* -*- mode: c; -*-
 * Copyright 2011 Nathan Phillip Brink <ohnobinki@ohnopublishing.net>
 *
 * This file is part of libstrl.
 *
 * libstrl is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * libstrl is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with libstrl.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#ifndef _LIBSTRL_STRL_H
#define _LIBSTRL_STRL_H

/**
 * \mainpage
 *
 * libstrl is a compatibility library whose purpose is to reduce the
 * number of private reimplementations of widely used and standardised
 * functions. Please see strl.h for richer documentation, examples,
 * and a list of the available substitute functions.
 */

/**
 * \file
 *
 * libstrl is a small library whose intent is to avoid packages
 * bundling their own implementations of well-defined and well-used
 * string functions in a way accessible to the developer. libstrl will
 * act as a compat layer: it will provide exactly the same API for a
 * given function as described in the manpage for that function; it
 * will not ever include additional extensions or miscellaneous
 * utility functions; its functions will behave as similarly to known
 * implementations as is possible. Yet, these functions shall be
 * implemented using original code, without looking at the original
 * function implementation's sourcecode (to escape from
 * license/copyright entanglement) as much as possible.
 *
 * During its compilation, libstrl will detect what functions are
 * available on the platform for which it is being compiled and
 * disable its implementations of those functions. If it is compiled
 * on a platform which already has implementations for every
 * compatibility function which libstrl provides, the libstrl
 * pkg-config module will not provide the linker flag for linking to
 * libstrl. Thus, the burden of ensuring that a system has at least
 * the string functions provided by libstrl is passed to libstrl
 * itself -- a package need not have a conditional requirement for
 * libstrl.
 *
 * \section families Families of Replaced Functions
 *
 * strlcat(), strlcpy(), wcscat(), and wcslcpy() are functions which
 * perform string operations on fixed-length buffers. They are to be
 * used when truncation is the preferred method of dealing with too
 * much data. These functions are commonly available on BSD
 * systems. GNU systems currently do not carry them, resulting in many
 * programs bundling their own copies of strl* and wcsl*. libstrl
 * provides implementations of this group of functions.
 *
 * strnlen() and wcsnlen() measure the length of strings of limitted
 * length. In some situations, they may also serve as ``safe''
 * versions of strlen() and wcslen(). These functions currently ship
 * with GNU systems but not BSD systems. libstrl implements these so
 * that programs written using the strnlen() or wcsnlen() conventions
 * can be used on BSD systems without having to ship their own
 * versions of these functions.
 *
 * getdelim() and getline() are very useful for the common case where
 * programs process dynamically-sized chunks of ASCII text from a
 * stream. They are reentrant by nature, avoiding use of
 * statically-allocated buffers, and have a sensible memory allocation
 * paradigm. It was noticed by the author that MacOSX 10.5 did not
 * have these functions and it is supposed that certain BSDs would not
 * either. These functions originated from GNU libc and are now POSIX
 * standards.
 *
 * asprintf() and its friend vasprintf() allow the flexibility of
 * formatting a string without having to precalculate its length. This
 * is useful in situations where fixed-length message buffers are not
 * necessary or where text must not be clipped. Also, it is unfeasible
 * to precalculate the length of many formatted strings. The method to
 * produce a variable-length formatted string conforming to the old C
 * standards where asprintf() did not yet exist would be to call
 * snprintf() with the second argument (n) being 0. snprintf() always
 * should return the size of the resulting formatted string regardless
 * of whether or not it was able to store the entire
 * string. asprintf() takes care of both finding the necessary buffer
 * length, allocating it, and formatting the string into it. These
 * functions appear in both GNU libc and BSD libc but were not added
 * to POSIX until more recently.
 *
 * \section example Example Usage
 *
 * If it makes sense for a program or library to use strlcat() and
 * strlcpy(), the package's buildsystem need only use pkg-config to
 * get compilation/linker flags from the libstrl pkg-config module and
 * include the strl.h header. To use libstrl, first find the functions
 * below which your package uses, noting the version of libstrl in
 * which each of these functions is introduced. Then ensure that you
 * have both <a
 * href="http://ohnopub.net/~ohnobinki/libstrl/">libstrl</a> and <a
 * href="http://pkgconfig.freedesktop.org/">pkgconfig</a>
 * installed. Then add the following line to your configure.ac:
 *
 * \include configure.ac
 *
 * Then, use the AC_SUBST variables produced by this macro in your
 * Makefile.am:
 *
 * \include Makefile.am
 *
 * Finally, just #include <strl.h> in any C file where you need to use
 * one of the functions for which libstrl has a backup version:
 *
 * \include myprog.c
 */

/* size_t, ssize_t */
#include <sys/types.h>

/*
 * Since we provide functions only if the system doesn't have them, we
 * here hook into the real headers so that the user need only #include
 * <strl.h>.
 */
#include <string.h>
#include <wchar.h>

#ifndef _LIBSTRL_WITH_UNIFDEF
/*
#define _LIBSTRL_DECLARE_ASPRINTF
*/

/*
#define _LIBSTRL_DECLARE_GETDELIM
*/

/*
#define _LIBSTRL_DECLARE_GETLINE
*/


#define _LIBSTRL_DECLARE_STRLCAT



#define _LIBSTRL_DECLARE_STRLCPY


/*
#define _LIBSTRL_DECLARE_STRNLEN
*/

/*
#define _LIBSTRL_DECLARE_STRNDUP
*/



#define _LIBSTRL_DECLARE_WCSLCAT



#define _LIBSTRL_DECLARE_WCSLCPY


/*
#define _LIBSTRL_DECLARE_WCSNLEN
*/

/*
#define _LIBSTRL_DECLARE_VASPRINTF
*/
#endif /* !_LIBSTRL_WITH_UNIFDEF */

#ifdef _LIBSTRL_DECLARE_ASPRINTF
/**
 * \brief
 *   Allocate a buffer of appropriate size and format a string into
 *   it.
 *
 * This function is similar to sprintf() except that the potential for
 * buffer overflows is avoided. Instead of having your code guess the
 * size of the formatted string, it may let asprintf() determine that
 * itself and allocate the buffer of an appropriate size.
 *
 * Introduced in libstrl-0.5.1.
 *
 * \param s
 *   A pointer to where the address of the newly allocated buffer
 *   containing the formatted string should be stored. On error, the
 *   value pointed to by s is undefined. On success, this will be set
 *   to a string allocated by malloc() which must be freed with
 *   free().
 * \param format
 *   The printf()-compatible format string which determines how to
 *   interpret any further arguments.
 * \return
 *   The number of bytes written into the allocated buffer, excluding
 *   the terminating NUL byte. On error, -1 is returned.
 */
int asprintf(char **s, const char *format, ...);
#endif

#ifdef _LIBSTRL_DECLARE_GETDELIM
#undef getdelim
/**
 * \brief
 *   Read from a stream until a delimiter is reached.
 *
 * Reads input from a stream until either the passed in delimiter is
 * found or the end of the file is encountered. If the file's end is
 * encountered after some bytes have been read, the retrieved string
 * will _not_ contain the delimiter. However, if the delimiter is read
 * it will be included in the string.
 *
 * Outside of libstrl, this function is available on platforms
 * conforming to POSIX.1-2008. It originated in GNU systems and there
 * are still BSD systems, such as older (and newer?) MacOSX, which
 * which don't have this. Thus, to make your program portable, you
 * should define _GNU_SOURCE before including stdio.h to cause stdio.h
 * to reveal any system headers for getdelim().
 *
 * Working since libstrl-0.4.
 *
 * \param lineptr
 *   Where to store a pointer to the allocated string. If *lineptr is
 *   not NULL, then the existing storage space (of capacity recorded
 *   in *n) will be utilized. If the existing storage space is not
 *   adequate or if *lineptr is NULL, the existing storage space shall
 *   be free()d and new space shall be allocated.
 *
 *   The string stored into *lineptr will be NULL-terminated.
 *
 *   After using getdelim(), this pointer must be free()d by the
 *   client program (unless if the program wants to reuse the storage
 *   area for future calls to getdelim()). If the program preallocates
 *   this buffer, the program must use malloc() and specify the size
 *   of the buffer in the n option.
 * \param n
 *   Where to store the capacity of the memory pointed to by
 *   *lineptr. Note that this is _not_ the size of the string being
 *   stored into *lineptr, see the return value for that information.
 *
 *   This value is ignored if *lineptr is NULL.
 * \param delim
 *   The character which acts as a delimiter. Passing '\\n' will have
 *   the same effect as calling getline() directly. In fact, this is
 *   how libstrl's getline() function is implemented.
 * \param stream
 *   The stream to read input from.
 * \return
 *   On success, the length of the stored string including the
 *   delimiter. On error or end-of-file, -1 is returned. If lineptr or
 *   n are NULL or stream is invalid, errno is set to EINVAL.
 */
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
#endif /* _LIBSTRL_DECLARE_GETDELIM */

#ifdef _LIBSTRL_DECLARE_GETLINE
#undef getline
/**
 * \brief
 *   Read one line from a stream into a buffer.
 *
 * The functionality of this function is the same as that found when
 * calling getdelim() with the same parameters with delim = '\\n'.
 *
 * Working since libstrl-0.4.
 *
 * \see getdelim()
 *
 * \param lineptr
 *   See getdelim().
 * \param n
 *   See getdelim().
 * \param stream
 *   See getdelim().
 * \return
 *   -1 on error, otherwise the size of the string stored into
 *   lineptr. See getdelim().
 */
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
#endif /* _LIBSTRL_DECLARE_GETLINE */

#ifdef _LIBSTRL_DECLARE_STRLCAT
#undef strlcat
/**
 * \brief
 *   Concatenate a string onto another string without causing the
 *   destination string to overrun its buffer.
 *
 * Outside of libstrl, this function is available from string.h on the
 * BSD platform but not the GNU platform.
 *
 * Working since libstrl-0.2.
 *
 * \param dst
 *   The string to be appended onto. This string shall not be written
 *   to beyond len bytes.
 * \param src
 *   The string being appended.
 * \param len
 *   The length of the portion of the string pointed to dst that we
 *   are allowed to write to. The terminating null byte shall be
 *   placed at dst[len - 1].
 * \return
 *   The length of the string whose creation was attempted. If the sum
 *   of the lengths of dst and src are greater than len - 1, then a
 *   truncation occurs and the return value shall be greater than or
 *   equal to len. Thus, one can detect a truncation by checking if
 *   the return value of strlcat() is greater than or equal to len.
 */
size_t strlcat(char *dst, const char *src, size_t len);

#endif /* _LIBSTRL_DECLARE_STRLCAT */

#ifdef _LIBSTRL_DECLARE_STRLCPY
#undef strlcpy
/**
 * \brief
 *   Copy a string into another buffer with extra string length checks
 *   and gauranteeing NUL termination.
 *
 * Outside of libstrl, this function is available from string.h on the
 * BSD platform but not the GNU platform.
 *
 * Based on the behavior and documentation of the strlcpy() found in
 * UnrealIRCd and OpenBSD's manpages.
 *
 * Working since libstrl-0.2.
 *
 * \param dst
 *   The buffer to copy src into.
 * \param src
 *   The string from which data should be copied. The last byte, which
 *   should be null, is ignored during the copy. However, if src has a
 *   null character before its last byte, copying shall stop there.
 * \param len
 *   The maximum number of chars which may be stored into dst. If the
 *   length of src is equal to or greater than len, then only the
 *   first len - 1 characters from src are copied into dst. This makes
 *   room for the terminating NUL character which is placed at the end
 *   of dst.
 * \return
 *   The length of the string that was created or, if len - 1 is less
 *   than the length of the string in src, the length of the string
 *   that would have been created if there was room. This will always
 *   be the same as strlen(src) and should be used to detect
 *   unintended truncation: if strlcpy() returns a length greater than
 *   or equal to the len parameter, there was a truncation.
 */
size_t strlcpy(char *dst, const char *src, size_t len);

#endif /* _LIBSTRL_DECLARE_STRLCPY */

#ifdef _LIBSTRL_DECLARE_STRNLEN
#undef strnlen
/**
 * \brief
 *   Count up to the first n characters in a string.
 *
 * GNU systems ship with strnlen(). OpenBSD does not, so this version
 * is provided by libstrl to help programs be portable between BSD and
 * GNU.
 *
 * GNU systems ship with an implementation of this function. By
 * default, libstrl will not declare this function if compiled for a
 * GNU system. Thus, programs which need to use strnlen() should
 * define the _GNU_SOURCE macro. If _GNU_SOURCE is defined, string.h
 * on GNU systems will declare strnlen(). On systems where strnlen()
 * isn't available at all, the below prototype will be declared by
 * libstrl's strl.h.
 *
 * Working since libstrl-0.2.
 *
 * \param s
 *   The string whose length should be found.
 * \param maxlen
 *   The maximum number of characters to walk the string s. If this
 *   number is reached, the function stops traversing s and returns
 *   this value.
 * \return
 *   The length of the given string or, if the string would be longer
 *   than maxlen, maxlen.
 */
size_t strnlen(const char *s, size_t maxlen);
#endif /* _LIBSTRL_DECLARE_STRNLEN */

#ifdef _LIBSTRL_DECLARE_STRNDUP
#undef strndup
/**
 * \brief
 *   Duplicate a string, but possibly truncate it.
 *
 * Allocates a new buffer, of up to length n + 1, using malloc() and
 * copy up to n bytes into it. If the passed string is shorter than n,
 * the new buffer shall be shorter than n.
 *
 * This function is a GNU extension. It was observed that it is not
 * available on MacOSX 10.5.
 *
 * New in strlcpy-0.4.
 *
 * \param s
 *   The string to duplicate.
 * \param n
 *   The maximum length of the string to return.
 * \return
 *   A pointer to a string of the same length as s or as long as n if
 *   strlen(s) is greater than n. The string will be NUL-terminated in
 *   all cases; thus, when the string is truncated the size of the
 *   returned buffer will be n + 1. If space cannot be allocated for
 *   the string, NULL is returned. The returned pointer _must_ be
 *   freed using free().
 */
char *strndup(const char *s, size_t n);
#endif /* _LIBSTRL_DECLARE_STRNDUP */

#ifdef _LIBSTRL_DECLARE_WCSLCAT
#undef wcslcat
/**
 * \brief
 *   Concatenate a wide string onto a buffer, setting the null
 *   terminator and avoiding writing beyond the end of the memory
 *   allocated in the destination buffer.
 *
 * Outside of libstrl, this function is available from wchar.h on BSD
 * systems but not on GNU systems.
 *
 * Working since libstrl-0.2.
 *
 * \param dst
 *   The wide string to which a wide string should be appended.
 * \param src
 *   The wide string to append to dst.
 * \param len
 *   The number of wchar_t items which may be written to dst,
 *   including the terminating null character. len - 1 will be the
 *   maximum length of the result of the concatenation of strings
 *   stored into dst.
 *
 * \return
 *   The length of the newly created wide string if it fit in dst or
 *   what the length of the string would be if len was big
 *   enough. This would be equal to strlen(dst) + strlen(src) - 1. If
 *   this value is greater than or equal to the len parameter,
 *   truncation has occured.
 */
size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t len);

#endif /* _LIBSTRL_DECLARE_WCSLCAT */

#ifdef _LIBSTRL_DECLARE_WCSLCPY
#undef wcslcpy
/**
 * \brief
 *   Copy a wide string into a buffer without overflowing it, placing
 *   an appropriate null terminator.
 *
 * Outside of libstrl, this function is available from wchar.h on BSD
 * systems but not on GNU systems.
 *
 * Working since libstrl-0.2.
 *
 * \param dst
 *   The buffer into which the the wide string shall be copied.
 * \param src
 *   The wide string to copy into the buffer.
 * \param len
 *   The maximum number of wide characters (wchar_t) that dst can
 *   hold.
 *
 * \return
 *   The length of wide string that was created if it fits into dst or
 *   the length of the string that would be created if len was larger
 *   if dst can not hold src. This value should be the same as
 *   strlen(src). This allows truncation detection, as if the return
 *   value is equal to or greater than len then a truncation has
 *   occured.
 */
size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t len);

#endif /* _LIBSTRL_DECLARE_WCSLCPY */

#ifdef _LIBSTRL_DECLARE_WCSNLEN
#undef wcsnlen
/**
 * \brief
 *   Count up to the first n wide characters in a string.
 *
 * GNU systems ship with wcsnlen(). OpenBSD does not, so this version
 * is provided by libstrl to help programs be portable between BSD and
 * GNU.
 *
 * You should declare _GNU_SOURCE if you are using this function to
 * make your program portable onto the GNU platform. See strnlen() for
 * details.
 *
 * Working since libstrl-0.2.
 *
 * \param s
 *   The wide string whose length should be found.
 * \param maxlen
 *   The maximum number of wide characters to walk the string s. If
 *   this number is reached, the function stops traversing s and
 *   returns this value.
 * \return
 *   The length of the given wide string or, if the wide string would
 *   be longer than maxlen, maxlen.
 */
size_t wcsnlen(const wchar_t *s, size_t maxlen);
#endif /* _LIBSTRL_DECLARE_WCSNLEN */

#ifdef _LIBSTRL_DECLARE_VASPRINTF
/**
 * \brief
 *   Allocate a buffer of appropriate size and format a string into
 *   it.
 *
 * The va_list version of asprintf().
 *
 * The technique used to determine the length of the to-be-allocated
 * buffer may not work on certain versions of Solaris.
 *
 * Introduced in libstrl-0.5.1.
 *
 * \param s
 *   A pointer to where the address of the newly allocated buffer
 *   containing the formatted string should be stored. On error, the
 *   value pointed to by s is undefined. On success, this will be set
 *   to a string allocated by malloc() which must be freed with
 *   free().
 * \param format
 *   The printf()-compatible format string which determines how to
 *   interpret any further arguments.
 * \param ap
 *   The varargs-compatible argument list. va_end() is not called on
 *   ap.
 * \return
 *   The number of bytes written into the allocated buffer, excluding
 *   the terminating NUL byte. On error, -1 is returned.
 */
#include <stdarg.h>
int vasprintf(char **s, const char *format, va_list ap);
#endif

#endif /* _LIBSTRL_STRL_H */
