/*
** Copyright (C) 2001-2011 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/
#ifndef _UTILS_H
#define _UTILS_H

#include <silk/silk.h>

RCSIDENTVAR(rcsID_UTILS_H, "$SiLK: utils.h 16752 2011-02-24 17:41:51Z mthomas $");

/*
**  a collection of utility routines.
**
**  Suresh L Konda
*/

#include <silk/skstream.h>

#ifdef SK_HAVE_GETOPT_LONG_ONLY
#include <getopt.h>
#else
#include <silk/gnu_getopt.h>
#endif


/*
 *    Where to create temp files by default.  This can be overridden
 *    by the --temp-dir switch (assuming skOptionsTempDirRegister() is
 *    in use), or environment variable named in SK_TEMPDIR_ENVAR1 or
 *    the environment variable named in SK_TEMPDIR_ENVAR2.
 *
 *    If this is not defined, no default exists.
 */
#define SK_TEMPDIR_DEFAULT "/tmp"

/*
 *    Name of primary envionment variable that holds name of temp
 *    directory.  This is consulted when the --temp-dir switch is not
 *    given.
 */
#define SK_TEMPDIR_ENVAR1 "SILK_TMPDIR"

/*
 *    Name of alternate envionment variable that holds name of temp
 *    directory.  Used when the --temp-dir switch is not given and the
 *    variable named by SK_TMPDIR_ENVAR1 is not set.
 */
#define SK_TEMPDIR_ENVAR2 "TMPDIR"



typedef enum {
    /* Command was successful */
    SKUTILS_OK = 0,

    /* Input to function is null or invalid (e.g., 0 length bitmap) */
    SKUTILS_ERR_INVALID = -1,

    /* Input to function was empty (or contained only whitespace) */
    SKUTILS_ERR_EMPTY = -2,

    /* Unexpected/Bad character or number is unparseable */
    SKUTILS_ERR_BAD_CHAR = -3,

    /* Value overflows the parser */
    SKUTILS_ERR_OVERFLOW = -4,

    /* Value underflows the parser */
    SKUTILS_ERR_UNDERFLOW = -5,

    /* Range is invalid (min > max) */
    SKUTILS_ERR_BAD_RANGE = -6,

    /* Unexpected end-of-input */
    SKUTILS_ERR_SHORT = -7,

    /* Too many fields provided */
    SKUTILS_ERR_TOO_MANY_FIELDS = -8,

    /* Out of memory */
    SKUTILS_ERR_ALLOC = -9,

    /* Miscellaneous error */
    SKUTILS_ERR_OTHER = -10,

    /* Value is below the minimum */
    SKUTILS_ERR_MINIMUM = -11,

    /* Value is above the maximum */
    SKUTILS_ERR_MAXIMUM = -12
} silk_utils_errcode_t;



/*
**
**  sku-compat.c
**
*/

/* silk.h will #define intmax_t sk_intmax_t if required */
typedef int64_t sk_intmax_t;

/* silk.h will #define imaxdiv_t sk_imaxdiv_t if required */
typedef struct sk_imaxdiv_st {
    sk_intmax_t quot; /* Quotient  */
    sk_intmax_t rem;  /* Remainder */
} sk_imaxdiv_t;

/* silk.h will #define imaxdiv sk_imaxdiv if required */
sk_imaxdiv_t sk_imaxdiv(sk_intmax_t numer, sk_intmax_t denom);
/*
 *    Do the integer division of 'numer' by 'denom'; return a
 *    structure that contains the 'quot' (quotient) and the 'rem'
 *    (remainder).
 *
 *    Conforming to C99.
 */


/* silk.h will #define memccpy sk_memccpy if required */
void *sk_memccpy(void *dst, const void *src, int c, size_t len);
/*
 *    Copy bytes from 'src' to 'dst' stopping after the first
 *    occurance of 'c' or when 'len' octets have been copied,
 *    whichever comes first.  If 'c' was not found, NULL is returned;
 *    else return value pointing to character after 'c' in 'dst'.
 *
 *    Conforming to C99.
 */


/* silk.h will #define setenv sk_setenv if required */
int sk_setenv(const char *name, const char *value, int overwrite);
/*
 *    Set environment variable 'name' to 'value', unless 'name' already
 *    exists in the environment and 'overwrite' is 0.
 *
 *    Return 0 on success.  Return -1 and set errno on memory
 *    allocation error or if 'name' contains a '=' character.  Assumes
 *    'name' and 'value' are not NULL.
 *
 *    Conforming to POSIX.1-2001
 */


/* silk.h will #define strsep sk_strsep if required */
char *sk_strsep(char **stringp, const char *delim);
/*
 *    Locate in *stringp first occurrence of any member of 'delim'.
 *    Change that character to '\0', modify '*stringp' to point to the
 *    following character, and return the original value of *stringp.
 *
 *    Return NULL if *stringp is NULL or when **stringp is '\0'; i.e.,
 *    when the end of the string is reached.
 *
 *    Empty field is determined by testing the returned value to '\0'.
 *
 *    Comforming to BSD 4.4
 */


/* silk.h will #define timegm sk_timegm if required */
time_t sk_timegm(struct tm *tm);
/*
 *    Do the reverse of gmtime(): Take a time structure and return
 *    seconds since the epoch in the UTC timezone.
 *
 *    No standard; common on Open Source systems.
 */


#if 0
int sk_snprintf(
    char       *str,
    size_t      size,
    const char *format,
    ...);
/*
 *    Replacement for snprintf() that always NUL terminates the string.
 */


int sk_vsnprintf(
    char       *str,
    size_t      size,
    const char *format,
    va_list     args);
/*
 *    Replacement for vsnprintf() that always NUL terminates the string.
 */
#endif



/*
**
**  skbitmap.c
**
*/


typedef struct sk_bitmap_st {
    uint32_t   *map;
    uint32_t    num_bits;
    uint32_t    count;
} sk_bitmap_t;

typedef struct sk_bitmap_iter_st {
    const sk_bitmap_t  *bitmap;
    uint32_t            map_idx;
    uint8_t             bits;
    uint8_t             pos;
} sk_bitmap_iter_t;


/* Internal macros.  Not for public use. */
#define _BMAP_INDEX(p)      ((p) >> 5)
#define _BMAP_OFFSET(p)     (1 << ((p) & 0x1F))
#define _BMAP_IS_SET(b, p)  ((b)->map[_BMAP_INDEX(p)] & _BMAP_OFFSET(p))



int skBitmapCreate(sk_bitmap_t **bitmap_out, uint32_t num_bits);
/*
 *    Create a new empty bitmap capable of holding 'num_bits' bits.
 *    All bits in the map are set to 0/LOW/OFF.  Return the bitmap in
 *    the location given by 'bitmap_out'.  Returns 0 if successful; -1
 *    for a memory allocation error or if 'num_bits' is zero.
 */


int skBitmapBind(
    sk_bitmap_t    *bitmap,
    uint32_t        num_bits,
    uint32_t       *bitarray,
    size_t          sizeof_bitarray);
/*
 *    Bind 'bitmap' to an existing array of uint32_t, 'bitarray', and
 *    clear the bitmap.  'num_bits' is number of bits you want to the
 *    bitmap to hold.  'sizeof_bitarray' should be the value of
 *    sizeof(bitarray).
 *
 *    This function can be used to create bitmaps on the stack without
 *    having to use the allocation code in skBitmapCreate().  These
 *    bitmaps should NOT be skBitmapDestroy()'ed.
 */


void skBitmapDestroy(sk_bitmap_t **bitmap);
/*
 *    Destroy the bitmap at location given by 'bitmap' that was
 *    created by skBitmapCreate().
 */


void skBitmapClearAllBits(sk_bitmap_t *bitmap);
/*
 *    Turn OFF all the bits in 'bitmap' and set the high-bit count to
 *    zero.
 */


uint32_t skBitmapGetSizeF(const sk_bitmap_t *bitmap);
#ifdef SKBITMAP_DEBUG
#  define skBitmapGetSize(bitmap) skBitmapGetSizeF(bitmap)
#else
#  define skBitmapGetSize(bitmap) ((bitmap)->num_bits)
#endif
/*
 *    Return the number of bits that 'bitmap' can hold.
 */


uint32_t skBitmapGetHighCountF(const sk_bitmap_t *bitmap);
#ifdef SKBITMAP_DEBUG
#  define skBitmapGetHighCount(bitmap) skBitmapGetHighCountF(bitmap)
#else
#  define skBitmapGetHighCount(bitmap) ((bitmap)->count)
#endif
/*
 *    Return the number of bits in 'bitmap' that are ON.
 */


int skBitmapGetBitF(const sk_bitmap_t *bitmap, uint32_t pos);
#ifdef SKBITMAP_DEBUG
#  define skBitmapGetBit(bitmap, pos) skBitmapGetBitF(bitmap, pos)
#else
#  define skBitmapGetBit(bitmap, pos)           \
    (((pos) >= (bitmap)->num_bits)              \
     ? -1                                       \
     : (_BMAP_IS_SET((bitmap), (pos)) ? 1 : 0))
#endif
/*
 *    Return 1 if the bit at position 'pos' in 'bitmap' is ON; return
 *    0 if it is OFF.
 */


void skBitmapSetBitF(sk_bitmap_t *bitmap, uint32_t pos);
#ifdef SKBITMAP_DEBUG
#  define skBitmapSetBit(bitmap, pos) skBitmapSetBitF(bitmap, pos)
#else
#  define skBitmapSetBit(bitmap, pos)                                   \
    if (((pos)>=(bitmap)->num_bits) || _BMAP_IS_SET((bitmap), (pos))) { \
        /* no-op */                                                     \
    } else {                                                            \
        (bitmap)->map[_BMAP_INDEX(pos)] |= _BMAP_OFFSET(pos);           \
        ++(bitmap)->count;                                              \
    }
#endif
/*
 *    Turn ON the bit at position 'pos' in 'bitmap'.  Adjust the
 *    bitmap's high-bit counter.
 */


void skBitmapClearBitF(sk_bitmap_t *bitmap, uint32_t pos);
#ifdef SKBITMAP_DEBUG
#  define skBitmapClearBit(bitmap, pos) skBitmapClearBitF(bitmap, pos)
#else
#  define skBitmapClearBit(bitmap, pos)                                 \
    if (((pos)>=(bitmap)->num_bits) || !_BMAP_IS_SET((bitmap),(pos))) { \
        /* no-op */                                                     \
    } else {                                                            \
        (bitmap)->map[_BMAP_INDEX(pos)] &= ~(_BMAP_OFFSET(pos));        \
        --(bitmap)->count;                                              \
    }
#endif
/*
 *    Turn OFF the bit at position 'pos' in 'bitmap'.  Adjust the
 *    bitmap's high-bit counter.
 */


void skBitmapComplement(sk_bitmap_t *bitmap);
/*
 *    Modify 'bitmap' in place to hold its complement.
 */


int skBitmapIntersection(sk_bitmap_t *dest, const sk_bitmap_t *src);
/*
 *    Compute the union of 'dest' and 'src', placing the result in
 *    'dest'.  The bitmaps must be of the same size.  If they are not
 *    of the same size, returns -1, else returns 0.
 */


int skBitmapUnion(sk_bitmap_t *dest, const sk_bitmap_t *src);
/*
 *    Compute the intersection of 'dest' and 'src', placing the result
 *    in 'dest'.  The bitmaps must be of the same size.  If they are
 *    not of the same size, returns -1, else returns 0.
 */


void skBitmapIteratorBind(const sk_bitmap_t *bitmap, sk_bitmap_iter_t *iter);
/*
 *    Bind the bitmap iterator 'iter' to iterate over the high bits in
 *    the bitmap 'bitmap'.
 */

int skBitmapIteratorNext(sk_bitmap_iter_t *iter, uint32_t *pos);
/*
 *    Set 'pos' to the next high bit in the bitmap that is bound to
 *    the iterator 'iter' and return SK_ITERATOR_OK.  If the iterator
 *    has visited all the high bits in the bitmap, leave the value in
 *    'pos' unchanged and return SK_ITERATOR_NO_MORE_ENTRIES.
 */


void skBitmapIteratorReset(sk_bitmap_iter_t *iter);
/*
 *    Allow the bitmap iterator 'iter' to iterate over the bitmap
 *    again.
 */


/*
 *  BITS_IN_WORD(&countptr, word);
 *
 *    Set the value pointed at by 'countptr' to the number of bits
 *    that are high in the 32-bit value 'word'.
 *
 * Fast method of computing the number of bits in a 32-bit word.  From
 * http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
 */
#define BITS_IN_WORD(countptr, word)                                    \
    do {                                                                \
        uint32_t vv = (word) - (((word) >> 1) & 0x55555555);            \
        vv = (vv & 0x33333333) + ((vv >> 2) & 0x33333333);              \
        *(countptr) = (((vv + (vv >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24; \
    } while(0)


/* Private macro used by GET_MASKED_BITS and SET_MASKED_BITS.  This
 * creates a 32-bit integer with the first `s' least-significat bits
 * turned on. */
#define _BITMASK(s) (((s) >= 32) ? (~(uint32_t)0) : (~((~(uint32_t)0) << (s))))


/*
 * GET_MASKED_BITS(x, o, s)
 *
 * Given an integer value (<=32 bits) x, return an integer
 * representing the set of bits within x starting at offset o (from
 * the least-significant bit) of size s in bits.  Works on 32, 16, and
 * 8 bit integers.
 *
 * 76543210  GET_MASKED_BITS(x, 2, 4) would return the value represent by
 * ..xxxx..  the middle 4 bits of a single byte, as shown at the left.
 */
#define GET_MASKED_BITS(x, o, s) (((x) >> (o)) & _BITMASK((s)))


/*
 * SET_MASKED_BITS(x, v, o, s)
 *
 * Given an integer variable (<=32 bits) x, sets x to the value
 * created by seting the set of bits within x starting at offset o
 * (from the least-significant bit) of size s in bits to v.  This is
 * the setting equivalent to GET_MASKED_BITS.  This works on variables
 * which are 32, 16, or 8 bit integers.
 */
#define SET_MASKED_BITS(x, v, o, s)                                     \
    ((x) = ((x) & (~(_BITMASK((s)) << (o)))) | (((v) & _BITMASK((s))) << (o)))


/*
 *  BITMAP_DECLARE(var_name, size);
 *
 *    Declares the bitmap 'var_name' that will hold size bits numbered
 *    from 0 to size-1.
 */
#define BITMAP_DECLARE(name, size)                                      \
    uint32_t name[((size) >> 5) + ((((size) & 0x1F) == 0) ? 0 : 1)]

/*
 *  BITMAP_INIT(name);
 *
 *    Clears all the bits in the bitmap named 'name'.  This macro must
 *    appear in the same scope as the BITMAP_DECLARE() macro.
 */
#define BITMAP_INIT(name) memset(&name, 0, sizeof(name))

/*
 *  BITMAP_SETBIT(name, pos);
 *  is_set = BITMAP_GETBIT(name, pos);
 *
 *    Set or get the bit as position 'pos' in bitmap 'name'.
 */
#define BITMAP_SETBIT(name, pos)                        \
    ((name)[_BMAP_INDEX(pos)] |= _BMAP_OFFSET(pos))
#define BITMAP_GETBIT(name, pos)                                \
    (((name)[_BMAP_INDEX(pos)] & _BMAP_OFFSET(pos)) ? 1 : 0)



/*
**
**    sku-app.c
**
*/

int skMsgNone(const char *, ...)
    SK_CHECK_PRINTF(1, 2);
/*
 *    The null message function.  Does nothing and returns zero.
 */

int skMsgNoneV(const char *, va_list);
/*
 *    The null message function.  Does nothing and returns zero.
 */

typedef struct skAppContext_st skAppContext_t;
/*
 *    Struct that contains global information about the application:
 *    its name, full path, options.
 */

void skAppRegister(const char *name);
/*
 *    Register the application.  Other functions below assume you've
 *    passed argv[0] as the value of 'name'.
 */

void skAppUnregister(void);
/*
 *    Destroy all data structures and free all memory associated with
 *    this application.
 */

const char *skAppRegisteredName(void);
/*
 *    Return the name that was used to register the application.  This
 *    is the value that was passed to skAppRegister().  The return
 *    value should be considered read-only.
 */

const char *skAppName(void);
/*
 *    Return a short name for the application.  This is the basename
 *    of the registered name.  The return value should be considered
 *    read-only.
 */

const char *skAppFullPathname(void);
/*
 *    Return the full path to application.  This will consult the PATH
 *    envar and cgetcwd() to find the complete path to the
 *    application.  The return value should be considered read-only.
 */

char *skAppDirParentDir(char *buf, size_t buf_len);
/*
 *    Return the application's directory's parent directory in 'buf',
 *    a character array of 'buf_len' bytes. e.g., if the rwfilter
 *    application lives in "/usr/local/bin/rwfilter", this function
 *    puts "/usr/local" into buf.  Return value is a pointer to 'buf',
 *    or NULL on error.
 */

void skAppUsage(void);
/*
 *    Print short usage information---telling the user to use the
 *    ``--help'' option---to stderr and exit the application with a
 *    FAILURE exit status.
 */

void skAppStandardUsage(
    FILE                   *fh,
    const char             *usage_msg,
    const struct option    *app_options,
    const char            **app_help);
/*
 *    Print, to the 'fh' file handle, the current application's name,
 *    the 'usage_msg', each option in 'app_options' and its 'app_help'
 *    string.  Returns control to the application.
 */

void skAppContextSet(skAppContext_t *a_context);
/*
 *    Use '*a_context' as the global application context.
 */

skAppContext_t *skAppContextGet(void);
/*
 *    Return the address of the application's global context.
 */

FILE *skAppSetErrStream(FILE *f);
/*
 *    Sets the error stream to 'f' for any messages printed with
 *    skAppPrintErrV() or skAppUsage().  When 'f' is NULL, calling
 *    skAppPrintErr(), skAppPrintErrV(), and skAppUsage() will result
 *    in no output being generated.
 *
 *    Returns the previous value of the error-stream.
 */

void skAppSetFuncPrintErr(sk_msg_vargs_fn_t fn);
/*
 *    Sets the function that skAppPrintErr() will call to print its
 *    arguments.  If 'fn' is NULL, resets skAppPrintErr() to use its
 *    default function, which is skAppPrintErrV().  To disable
 *    printing of errors, pass 'skMsgNoneV' to this function.
 */

void skAppSetFuncPrintSyserror(sk_msg_vargs_fn_t fn);
/*
 *    Sets the function that skAppPrintSyserror() will call to print
 *    its arguments.  If 'fn' is NULL, resets skAppPrintSyserror() to
 *    use its default function, which is skAppPrintSyserrorV().  To
 *    disable printing of errors, pass 'skMsgNoneV' to this function.
 */

void skAppSetFuncPrintFatalErr(sk_msg_fn_t fn);
/*
 *    Sets the function that skAppPrintAbortMsg(),
 *    skAppPrintBadCaseMsg(), and skAppPrintNoMemoryMsgFunction() will
 *    call to print their arguments.  If 'fn' is NULL, resets the
 *    functions to use the default function, which is skAppPrintErr().
 *    To disable printing of errors, pass 'skMsgNone' to this
 *    function.
 */

int skAppPrintErrV(const char *fmt, va_list args);
/*
 *    Prints the application name, a colon, the result of formatting
 *    the arguments using v*printf(), and a newline to the stream set
 *    by skAppContextSetErrStream, which defaults to stderr.
 *
 *    This is the default function used by skAppPrintErr() to print
 *    error messages.
 */

int skAppPrintSyserrorV(const char *fmt, va_list args);
/*
 *    Prints the application name, a colon, the result of formatting
 *    the arguments using v*printf(), the result of calling
 *    strerror(), and a newline to the stream set by
 *    skAppContextSetErrStream, which defaults to stderr.
 *
 *    This is the default function used by skAppPrintSyserror() to
 *    print system error messages.
 */

#ifdef TEST_PRINTF_FORMATS
#define skAppPrintErr printf
#else
int skAppPrintErr(const char *fmt, ...)
    SK_CHECK_PRINTF(1, 2);
#endif
/*
 *    Calls the function set by skAppSetFuncPrintErr()---which has the
 *    default value skAppPrintErrV()---to format and print the
 *    arguments using the given format 'fmt'.
 */


#ifdef TEST_PRINTF_FORMATS
#define skAppPrintSyserror printf
#else
int skAppPrintSyserror(const char *fmt, ...)
    SK_CHECK_PRINTF(1, 2);
#endif
/*
 *    Calls the function set by skAppSetFuncPrintSyserror()---which
 *    has the default value skAppPrintSyserrorV()---to format and
 *    print the arguments using the given format 'fmt'.
 */


int skTraceMsg(const char *fmt, ...)
    SK_CHECK_PRINTF(1, 2);
/*
 *  chars_printed = skTraceMsg(...);
 *
 *    Prints a message to the standard error.  This function appends a
 *    final newline to the output.  This function may used by
 *    TRACEMSG(), see sktracemsg.h.
 */


int skAppSetSignalHandler(void (*sig_handler)(int signal));
/*
 *    Install the function 'sig_handler' to be called whenever the
 *    application receives a SIGINT, SIGTERM, SIGQUIT, or SIGPIPE.
 *
 *    The parameter passed to 'sig_handler' will be the received
 *    signal.
 *
 *    Return 0 on success, or -1 if the handler cannot be installed.
 */


void skAppPrintAbortMsg(
    const char *func_name,
    const char *file_name,
    int         line_number);
/*
 *    Use skAbort() to call this function.
 *
 *    skAbort() is a macro defined in silk.h that calls this function
 *    with the current function name (if the compiler supports it),
 *    filename, and line number macros.  Once this function returns,
 *    the skAbort() macro calls abort().
 *
 *    This function will call the function specified by
 *    skAppSetFuncPrintFatalErr() to print a message containing the
 *    specified 'func_name', 'file_name' and 'line_number' values.
 *    This function will return.  It is the caller's responsibility to
 *    call abort().
 */


void skAppPrintBadCaseMsg(
    const char *func_name,
    const char *file_name,
    int         line_number,
    int64_t     value,
    const char *value_expr);
/*
 *    Use skAbortBadCase(case_expr) to call this function.
 *
 *    skAbortBadCase() is a macro defined in silk.h that calls this
 *    function with the current function name (if the compiler
 *    supports it), filename, line number macros, the value of
 *    'case_expr' as an int64_t and the stringification of
 *    'case_expr'.  Once this function returns, the skAbortBadCase()
 *    macro calls abort().
 *
 *    This function will call the function specified by
 *    skAppSetFuncPrintFatalErr() to print an appropriate message
 *    regarding switch(value_expr) getting an unexpected value.  This
 *    function will return.  It is the caller's responsibility to call
 *    abort().
 */


#ifdef SK_HAVE_C99___FUNC__
#define skAppPrintOutOfMemory(oom_string)                               \
    skAppPrintNoMemoryMsgFunction(__func__, __FILE__, __LINE__, oom_string)
#else
#define skAppPrintOutOfMemory(oom_string)                               \
    skAppPrintNoMemoryMsgFunction(NULL, __FILE__, __LINE__, oom_string)
#endif


void skAppPrintNoMemoryMsgFunction(
#ifdef SK_HAVE_C99___FUNC__
    const char         *func_name,
#else
    const char  UNUSED(*func_name),
#endif
    const char         *file_name,
    int                 line_number,
    const char         *object_name);
/*
 *    Use skAppPrintOutOfMemory("object_name") to call this function.
 *
 *    skAppPrintOutOfMemory() is a macro defined above that calls this
 *    function with the current function name (if the compiler
 *    supports it), filename, line number macros, the value for
 *    'object_name'.
 *
 *    This function will call the function specified by
 *    skAppSetFuncPrintFatalErr() to print a message about being out
 *    of memory and unable to allocate 'object_name'.  'object_name'
 *    may be NULL.  This function will return.  It is the caller's
 *    responsibility to exit the program.
 */


/*
**
**    sku-options.c
**
*/

/* long option arg types */
#define NO_ARG          0
#define REQUIRED_ARG    1
#define OPTIONAL_ARG    2

/* macro to print whether switch requires an argument */
#define SK_OPTION_HAS_ARG(switch)             \
    (((switch).has_arg == REQUIRED_ARG)       \
     ? "Req Arg"                              \
     : (((switch).has_arg == OPTIONAL_ARG)    \
        ? "Opt Arg"                           \
        : (((switch).has_arg == NO_ARG)       \
           ? "No Arg"                         \
           : "BAD 'has_arg' VALUE")))


/* generic types for dealing with opaque handles */
typedef void *clientData;
typedef int (* optHandler)(clientData cData, int optIndex, char *optArg);
typedef void (* usage_fn_t)(void);


void skOptionsSetup(void);
/*
 *    Prepare the application to process options.  It is not necessary
 *    to call this funtion explicitly, as skAppRegister() calls this
 *    function for you.
 */

void skOptionsTeardown(void);
/*
 *    Free all memory associated with options processing.  It is not
 *    necessary to call this funtion explicitly, as skAppUnregister()
 *    calls this function for you.
 */

void skOptionsSetUsageCallback(usage_fn_t help_fn);
/*
 *    Register the function 'help_fn' as the function the appliction
 *    will invoke when the user runs the application with the --help
 *    option.  If not specified, no output is produced by --help.
 *
 *    This function should print its results to the stdout.
 *
 *    It is recommended that this function print a brief summary of
 *    the purpose of the application, and then print every switch the
 *    function accepts.  The skAppStandardUsage() function can be used
 *    to print much of this information.
 */

void skOptionsSetVersionCallback(usage_fn_t version_fn);
/*
 *    Register the function 'version_fn' as the function the
 *    application will invoke when the user runs the application with
 *    the --version option.  If not specified, information about the
 *    version of libsilk that the application is using will be
 *    printed.
 *
 *    This function should print its results to the stdout.
 *
 *    It is recommended that this function print information about how
 *    the application was compiled and the license(s) that the
 *    application is released under.
 */

int skOptionsRegister(
    const struct option    *options,
    optHandler              handler,
    clientData              cData);

/* deprecated names: for compatibility */
#define optionsRegister skOptionsRegister
#define optionsParse    skOptionsParse


void skOptionsDefaultUsage(FILE *fh);
/*
 *    Print usage information about the default options that all
 *    applications support to the named file handle.
 */


#ifndef SK_SUPPORT_CONF_FILE
#  define SK_SUPPORT_CONF_FILE 0
#endif
#if  SK_SUPPORT_CONF_FILE
int optionsHandleConfFile(char *filename);
/*
 * optionsHandleConfFile:
 *
 *     Loads a configuration file.  The configuration file consists of
 *     a series of newline-terminated lines.  A line consisting of
 *     only whitespace, or whose first non-whitespace character is a
 *     `#' character is ignored.  All other lines should consist of a
 *     single option name followed by the option's value (if any),
 *     seperated by whitespace.  Whitespace at the beginning and end
 *     of the line is ignored.
 *
 * BUGS:
 *     If you intersperse switches (options) and arguments, arguments
 *     before the configuration file is parsed will not be seen.
 *
 *  Return:
 *      0 if ok. -1 else
 */
#endif  /* SK_SUPPORT_CONF_FILE */


int skOptionsParse(int argc, char **argv);
/*
 *  skOptionsParse:
 *      Adjust the global options array to allow for the help
 *      option. If help is selected by the user, call the stashed
 *      usageFunction.  Parse input options given a set of
 *      pre-registered options and their handlers.  For each
 *      legitimate option, call the handler.
 *  SideEffects:
 *      The individual handlers update whatever datastruture they wish
 *      to via the clientData argument to the handler.
 *  Return:
 *      optind which points at the first non-option argument passed if
 *      all is OK.  If not OK, the return -1 for error.
 */


int skOptionsCheckDirectory(const char *dirname, const char *option_name);
/*
 *    Verify that the directory in 'dirname' exists, that the length
 *    is shorter than PATH_MAX, and that we have a full path to the
 *    directory.  If so, return 0; otherwise, print an error that the
 *    option named by 'option_name' was bad and return -1.
 */


int skOptionsGetShortestPrefix(const char *option_name);
/*
 *    Return the length of the shortest unique prefix required to
 *    match the option whose complete name is 'option_name'.  Return
 *    -1 if option_name is NULL, empty, or if no options have the name
 *    'option_name'.
 */


int skOptionsTempDirRegister(const char **var_location);
/*
 *    Registers a --temp-directory switch for the application.  Use
 *    skOptionsTempDirUsage() to print the usage for this switch.
 *
 *    The parameter 'var_location' must be specified.  The variable at
 *    that location will be set to the location the user provides in
 *    the --temp-directory switch.
 *
 *    The variable at 'var_location' is only modified if the user
 *    specifies the --temp-directory switch,
 */

void skOptionsTempDirUsage(FILE *fh);
/*
 *    Print the usage information for the --temp-directory switch.
 */


/*
**
**    skqsort.c
**
*/


void skQSort(
    void   *buffer,
    size_t  number_elements,
    size_t  element_size,
    int   (*cmp)(const void *, const void *));

void skQSort_r(
    void   *buffer,
    size_t  number_elements,
    size_t  element_size,
    int   (*cmp)(const void *, const void *, void *),
    void   *thunk);


/*
**
**    skoptions-notes.c
**
*/


int skOptionsNotesRegister(int *note_strip);

void skOptionsNotesTeardown(void);

void skOptionsNotesUsage(FILE *fh);

int skOptionsNotesAddToStream(skstream_t *stream);



/*
**
**    sku-times.c
**
*/

typedef enum {
    SKTIMESTAMP_NOMSEC   = (1 << 0),
    SKTIMESTAMP_MMDDYYYY = (1 << 1),
    SKTIMESTAMP_EPOCH    = (1 << 2),
    SKTIMESTAMP_ISO      = (1 << 3),
    SKTIMESTAMP_UTC      = (1 << 4),
    SKTIMESTAMP_LOCAL    = (1 << 5)
} sktimestamp_flags_t;


#define SKTIMESTAMP_STRLEN 28
/*
 *    Minimum size of buffer to pass to sktimestamp_r().
 */


char *sktimestamp_r(
    char       *outbuf,
    sktime_t    t,
    int         timestamp_flags);
/*
 *    Fill 'outbuf' with an ASCII version of the time 't' and return a
 *    pointer to 'output'.  This function assumes that 'outbuf' is at
 *    least SKTIMESTAMP_STRLEN characters long.
 *
 *    By default, the timestamp will be in the form:
 *
 *        "YYYY/MM/DDTHH:MM:SS.sss"
 *
 *    where "sss" == milliseconds, the "T" is a literal 'T'.
 *
 *    The parameter 'timestamp_flags' can be used to change the
 *    printed time, where the flags are a bitwise OR of the
 *    sktimestamp_flags_t values.
 *
 *    The following fields for 'timestamp_flags' are mutually
 *    exclusive; if more than one is set, the time is printed in the
 *    default form (and the SKTIMESTAMP_NOMSEC bit is ignored):
 *
 *        SKTIMESTAMP_EPOCH prints the value as the number of seconds
 *        since the UNIX epoch.  The timezone bits are ignored.
 *
 *            "SSSSSSSSSS[.sss]"
 *
 *        SKTIMESTAMP_MMDDYYYY causes the time to be printed as:
 *
 *            "MM/DD/YYYY HH:MM:SS[.sss]"
 *
 *        SKTIMESTAMP_ISO causes the time to be printed as
 *
 *            "YYYY-MM-DD HH:MM:SS[.sss]"
 *
 *    The following bit operates independently of any other bits:
 *
 *        SKTIMESTAMP_NOMSEC suppresses the printing of the
 *        milliseconds.  The milliseconds value is dropped and the
 *        remaining value is NOT rounded.
 *
 *    The 'timestamp_flags' value can affect the timezone used when
 *    printing the time.  If neither (or both) of the following bits
 *    are set, the time is printed in UTC unless SiLK was configured
 *    with --enable-local-timezone, in which case the local timezone
 *    is used.
 *
 *        SKTIMESTAMP_UTC causes the value to be printed in UTC,
 *        regardless of whether SiLK was configured with the
 *        --enable-local-timezone switch.
 *
 *        SKTIMESTAMP_LOCAL causes the value to be printed in the
 *        local timezone, regardless of whether SiLK was configured
 *        with the --enable-local-timezone switch.
 */


char *sktimestamp(
    sktime_t    t,
    int         timestamp_flags);
/*
 *    Similar to sktimestamp_r(), except returns the value in a static
 *    buffer.
 */


int skGetMaxDayInMonth(int yr, int mo);
/*
 *    Return the maximum day in a given month/year
 *
 *    NOTE:  Months are in the 1..12 range and NOT 0..11
 *
 */


sktime_t sktimeNow(void);
/*
 *    Return an sktime set to the current UTC time to millisecond
 *    precision.
 */


#define sktimeCreate(sktc_seconds, sktc_milliseconds)                   \
    ((sktime_t)(INT64_C(1000) * (sktc_seconds) + (sktc_milliseconds)))
/*
 *    Given a value containing seconds since the UNIX epoch (such as a
 *    time_t) and a millisecond count, return an sktime_t.  The second
 *    parameter can be any value containing milliseconds.  There is no
 *    restriction on the range of its value.
 */


#define sktimeCreateFromTimeval(sktc_tv)                                \
    sktimeCreate((sktc_tv)->tv_sec, ((sktc_tv)->tv_usec / 1000))
/*
 *    Given a pointer to a struct timeval, return an sktime_t
 */


#define sktimeGetParts(sktgp_time, sktgp_seconds, sktgp_milliseconds)   \
    do {                                                                \
        imaxdiv_t sktgp_d = imaxdiv((sktgp_time), INT64_C(1000));       \
        *(sktgp_seconds) = sktgp_d.quot;                                \
        *(sktgp_milliseconds) = sktgp_d.rem;                            \
    } while (0)
/*
 *    Given an sktime_t value, fill 'seconds' and 'milliseconds' with
 *    the number of seconds and milliseconds that value represents.
 */


#define sktimeGetSeconds(sktgs_time)            \
    ((sktgs_time) / INT64_C(1000))
/*
 *    Given an sktime_t, return the number of seconds since the UNIX
 *    epoch as an integer.
 */


#define sktimeGetMilliseconds(sktgm_time)       \
    ((sktgm_time) % INT64_C(1000))
/*
 *    Given an sktime_t, return fractional seconds as an integer.
 */



/*
**
**    sku-bigsockbuf.c
**
*/

int skGrowSocketBuffer(int sock, int direction, int size);
/*
 *    There is no portable way to determine the max send and receive
 *    buffers that can be set for a socket, so guess then decrement
 *    that guess by 2K until the call succeeds.  If n > 1MB then the
 *    decrement by .5MB instead.
 *
 *    Returns size or -1 for error
 */


/*
**
**    sku-filesys.c
**
*/

char *skBasename(const char *fp);
/*
 *    Strip directory prefix from the file path fp.  Returns a pointer
 *    to a static string buffer.
 */


char *skBasename_r(char *dest, const char *src, size_t dest_size);
/*
 *    Thread safe version of skBasename()
 */


char *skDirname(const char *fp);
/*
 *    Strip file name suffix from the file path fp.  Returns a pointer
 *    to a static string buffer.
 */


char *skDirname_r(char *dest, const char *src, size_t dest_size);
/*
 *    Thread safe version of skDirname()
 */


#define FILEIsATty(fd)          isatty(fileno(fd))
/*
 *    Returns 1 if the FILE* fd is a tty, 0 otherwise
 */


int isFIFO(const char *name);
/*
 *    Returns 1 if name exists and is a FIFO; returns 0 otherwise.
 */


int skDirExists(const char *dName);
/*
 *    Returns 1 if dName exists and is a directory; returns 0
 *    otherwise.
 */


int skFileExists(const char *fName);
/*
 *    Returns 1 if fName exists and is a regular file; returns 0
 *    otherwise.
 */


off_t skFileSize(const char *fName);
/*
 *    Returns the size of the file fName.  Returns 0 if file is empty
 *    or if it does not exist; use skFileExists() to check for existence
 */


int skFileSetLock(int fd, short type, int cmd);
/*
 *    Perform a locking operation on the opened file represented by
 *    the file descriptor 'fd'.  'type' is the type of lock, it should
 *    be one of F_RDLCK for a read lock, F_WRLCK for a write lock, or
 *    F_UNLCK to unlock a previously locked file.  'cmd' should be one
 *    of F_SETLKW to wait indefinitely for a lock, or F_SETLK to
 *    return immediately.  Return 0 if successful, -1 otherwise.  Use
 *    errno to determine the error.
 */


char *skFindFile(
    const char *base_name,
    char       *buf,
    size_t      bufsize,
    int         verbose);
/*
 *    Find the given file 'base_name' in one of several places:
 *
 *    -- If 'base_name' begins with a slash (/), copy it to 'buf'.
 *    -- See if the environment variable named by the cpp macro
 *       ENV_SILK_PATH (normally SILK_PATH) is defined.  If so, check
 *       for the file in:
 *         * $SILK_PATH/share/silk/file_name
 *         * $SILK_PATH/share/file_name
 *         * $SILK_PATH/file_name (for historical resaons)
 *    -- Take the full path to the application (/yadda/yadda/bin/app),
 *       lop off the app's immediate parent directory---which leaves
 *       /yadda/yadda---and check for the file in the:
 *         * "/share/silk" subdir (/yadda/yadda/share/silk/file_name)
 *         * "/share" subdir (/yadda/yadda/share/file_name)
 *
 *    If found---and if the total path is less than 'bufsize-1'
 *    characters---fills 'buf' with a full path to the file and
 *    returns a pointer to 'buf'.
 *
 *    If not found or if 'buf' is too small to hold the full path;
 *    returns NULL and leaves 'buf' in an unknown state.
 */


char *skFindPluginPath(
    const char *dlPath,
    char       *path,
    size_t      path_len,
    const char *verbose_prefix);
/*
 *    Attempt to find the named plug-in, 'dlPath', in one of several
 *    places.  If the function searches and finds the plug-in, it
 *    copies that location to the character array 'path'--whose
 *    caller-allocated size if 'path_len'---and returns 'path';
 *    otherwise return NULL.  This routine checks:
 *
 *    -- If 'dlPath' contains a slash, assume the path to plug-in is
 *       correct and return NULL.
 *    -- See if the environment variable named by the cpp macro
 *       ENV_SILK_PATH (normally SILK_PATH) is defined.  If so, check
 *       for the plug-in in the subdirectories of $SILK_PATH specified
 *       in the SILK_SUBDIR_PLUGINS macro, namely:
 *         * $SILK_PATH/lib/silk/dlPath
 *         * $SILK_PATH/share/lib/dlPath
 *         * $SILK_PATH/lib/dlPath
 *    -- Take the full path to the application "/yadda/yadda/bin/app",
 *       lop off the app's immediate parent directory--which leaves
 *       "/yadda/yadda", and check the SILK_SUBDIR_PLUGINS
 *       subdirectories:
 *         * "/lib/silk" subdir (/yadda/yadda/lib/silk/dlPath)
 *         * "/share/lib" subdir (/yadda/yadda/share/lib/dlPath)
 *         * "/lib" subdir (/yadda/yadda/lib/dlPath)
 *
 *    If 'verbose_prefix' is not NULL, the function uses
 *    skAppPrintErr() to print every pathname it checks, prefixing the
 *    pathname with the string in 'verbose_prefix'.
 *
 *    Return NULL if 'dlPath' was not found of if the search was not
 *    performed; otherwise return a char* which is the buffer passed
 *    into the subroutine.
 */



int skOpenFile(const char *FName, int mode, FILE **fp, int *isPipe);
/*
 *  status = skOpenFile(file, mode, &fp, &isPipe);
 *
 *    Open 'file' as a pipe or as a regular file depending on whether
 *    it is a gzipped file or not.  A file is considered gzipped if
 *    its name contains the string ".gz\0" or ".gz.".
 *
 *    The name of the file is given in the C-string 'file'; 'mode'
 *    determines whether to open 'file' for reading (mode==0) or
 *    writing (mode==1).
 *
 *    The file pointer to the newly opened file is put into 'fp'.  The
 *    value pointed to by 'isPipe' is set to 0 if fopen() was used to
 *    open the file, or 1 if popen() was used.  The caller is
 *    responsible for calling fclose() or pclose() as appropriate.
 *
 *    The function returns 0 on success, or 1 on failure.
 */


int skMakeDir(const char *directory);
/*
 *    Make the complete directory path to 'directory', including
 *    parent(s) if required.  Return 0 on success.  Return 1 on
 *    failure and set errno.
 */


int skCopyFile(const char *srcPath, const char *destPath);
/*
 *    Copy the file 'srcPath' to 'destPath'.  'destPath' may be a file
 *    or a directory.  Return 0 on success, or errno on failure.
 */


int skMoveFile(const char *srcPath, const char *destPath);
/*
 *    Move the file at 'srcPath' to 'destPath'.  'destPath' may be a
 *    file or a directory.  Return 0 on success, or errno on failure.
 */


const char *skTempDir(
    const char     *user_temp_dir,
    sk_msg_fn_t     err_fn);
/*
 *    Return the location of the temporary directory.
 *
 *    If a temporary directory is not specified or if the specified
 *    location does not exist, return NULL.  In addition, if 'err_fn'
 *    is specified, print an error message using that function.
 *
 *    If 'user_temp_dir' is specified, that location is used.
 *    Otherwise, locations specified by the SILK_TMPDIR and TMPDIR
 *    environment variables are checked, in that order.  Finally, the
 *    DEFAULT_TEMP_DIR is used if defined.
 */


int skOpenPagerWhenStdoutTty(
    FILE  **output_stream,
    char  **pager);
/*
 *    Attempts to redirect the '*output_stream' to the paging program
 *    '*pager.'
 *
 *    If output changed so that it goes to a pager, 1 is returned; if
 *    the output is unchanged, 0 is returned.  If an error occurred in
 *    invoking the pager, -1 is returned.
 *
 *    If the '*output_stream' is NULL, it is assumed that the output
 *    was being sent to stdout.  If the '*output_stream' is not stdout
 *    or not a terminal, no paging is preformed and 0 is returned.
 *
 *    If '*pager' is NULL, the environment variable SILK_PAGER is
 *    checked for the paging program; if that is NULL, the PAGER
 *    environment variable is checked.  If that is also NULL, no
 *    paging is performed and 0 is returned.
 *
 *    If there was a problem invoking the pager, an error is printed
 *    and -1 is returned.
 *
 *    If the pager was started, the *output_stream value is set to the
 *    pager stream, and *pager is set to the name of the pager (if the
 *    user's environment was consulted), and 1 is returned.  To close
 *    the pager, use the skClosePager() function, or call pclose() on
 *    the *output_stream.
 *
 *    Due to the race condition of checking the status of the child
 *    process, it is possible for 1 to be returned even though the
 *    pager has exited.  In this case the tool's output will be lost.
 */


void skClosePager(FILE *output_stream, const char *pager);
/*
 *    If skOpenPagerWhenStdoutTty() returns a positive value, use this
 *    function to close the pager stream.  Prints an error if the
 *    close fails.
 */


int skGetLine(
    char       *out_buffer,
    size_t      buf_size,
    FILE       *stream,
    const char *comment_start);
/*
 *    Fill 'out_buffer' with the next non-blank, non-comment line read
 *    from 'stream'.  The caller should supply 'out_buffer' and pass
 *    its size in the 'buf_size' variable.  The return value is the
 *    number of lines that were read to get a valid line.
 *
 *    The final newline will be removed; if comment_start is provided,
 *    it will also be removed from line.
 *
 *    If a line longer than buf_size is found, out_buffer will be set
 *    to the empty string but the return value will be positive.
 *
 *    At end of file, 0 is returned and out_buffer is the empty
 *    string.
 */


ssize_t skreadn(
    int     fd,
    void   *buf,
    size_t  count);
/*
 *  Reads 'count' bytes from the file descriptor 'fd' into the buffer
 *  'buf'.  The return value is the number of bytes actually read.
 *  Will return less than 'count' if an end-of-file situation is
 *  reached.  In an error condition, returns -1.  More information
 *  about the error can be derived from 'errno'.
 */

ssize_t skwriten(
    int         fd,
    const void *buf,
    size_t      count);
/*
 *  Writes 'count' bytes from the buffer 'buf' to the file descriptor
 *  'fd'.  The return value is the number of bytes actually written.
 *  If the underlying `write' call returns zero, this function will
 *  return a value less than 'count'.  It is unknown if this actually
 *  occurs in any real-life conditions.  In an error condition,
 *  returns -1.  More information about the error can be derived from
 *  'errno'.
 */



/*
**
**    sku-ips.c
**
*/


int skIntegerLog2(uint64_t value);
/*
 *    Return the log2 of 'value' as an integer.  This is the position
 *    of the most significant bit in 'value', assuming the MSB is
 *    number 63 and the LSB is 0.  Returns -1 if 'value' is 0.
 */


int skCIDRComputePrefix(
    const skipaddr_t   *start_addr,
    const skipaddr_t   *end_addr,
    skipaddr_t         *new_start_addr);
/*
 *    Compute the largest CIDR block that begins at 'start_addr' and
 *    contains no IPs larger than 'end_addr', and return the CIDR
 *    designation for that block.  For example:
 *
 *        skCIDRComputePrefix(10.0.0.2, 10.0.0.5, NULL) => 31
 *
 *    When 'new_start_addr' is not NULL, it's value is set to 0 if the
 *    CIDR block completely contains all IPs between 'start_addr' and
 *    'end_addr' inclusive.  Otherwise, its value is set to the IP that
 *    follows that block covered by the CIDR block.
 *
 *    Returns -1 if 'end_addr' < 'start_addr'.
 *
 *    This function allows one to print all CIDR blocks from 'start'
 *    to 'end' using:
 *
 *        do {
 *            cidr_prefix = skCIDRComputePrefix(&start, &end, &new_start);
 *            printf("%s/%d", skipaddrString(buf, start, 0), cidr_prefix);
 *            skipaddrCopy(&start, &new_start);
 *        } while (!skipaddrIsZero(&start));
 *
 *    Continuing the above example:
 *
 *        skCIDRComputePrefix(10.0.0.2, 10.0.0.5, &new) => 31, new => 10.0.0.4
 *        skCIDRComputePrefix(10.0.0.4, 10.0.0.5, &new) => 31, new => 0
 *
 *    which means that the IP range 10.0.0.2--10.0.0.5 is contained by
 *    the two CIDR blocks:
 *
 *        10.0.0.2/31
 *        10.0.0.4/31
 */

int skComputeCIDR(
    uint32_t    start_ip,
    uint32_t    end_ip,
    uint32_t   *new_start_ip);
/*
 *    Older interface to skCIDRComputePrefix() that uses integers for
 *    the IP addresses.
 */


int skCIDR2IPRange(
    const skipaddr_t   *ipaddr,
    uint32_t            cidr,
    skipaddr_t         *min_ip,
    skipaddr_t         *max_ip);
/*
 *    Compute the minimum and maximum IPs that are represented by
 *    'ipaddr' when the CIDR mask 'cidr' is applied to it.  Return -1
 *    if 'cidr' is too large for the type of IP address.
 *
 *    Either of the output values, 'min_ip' or 'max_ip', may point to
 *    the same memory as 'ipaddr'.
 *
 *    See also skCIDRComputeEnd().
 */


int skCIDRComputeStart(
    const skipaddr_t   *ipaddr,
    uint32_t            cidr,
    skipaddr_t         *min_ip);
/*
 *    Compute the minimum IP that is covered by the CIDR block
 *    'ipaddr'/'cidr' and fill 'min_ip' with that value.  Return -1 if
 *    'cidr' is too marge for the type of IP address.
 *
 *    'min_ip' may point to the same memory as 'ipaddr'.
 *
 *    See also skCIDR2IPRange().
 */


int skCIDRComputeEnd(
    const skipaddr_t   *ipaddr,
    uint32_t            cidr,
    skipaddr_t         *max_ip);
/*
 *    Compute the maximum IP that is covered by the CIDR block
 *    'ipaddr'/'cidr' and fill 'max_ip' with that value.  Return -1 if
 *    'cidr' is too marge for the type of IP address.
 *
 *    'max_ip' may point to the same memory as 'ipaddr'.
 *
 *    See also skCIDR2IPRange().
 */


int skIPv6PolicyParse(
    sk_ipv6policy_t    *ipv6_policy,
    const char         *policy_name,
    const char         *option_name);
/*
 *    Parse the string 'policy_name' and set 'ipv6_policy' to the
 *    parsed value.  Return 0 on success.
 *
 *    If 'policy_name' is not a valid policy, return -1.  In addition,
 *    if 'option_name' is non-NULL, print an error message that the
 *    'policy_name' was invalid.
 */


int skIPv6PolicyOptionsRegister(sk_ipv6policy_t *ipv6_policy);
/*
 *    Add an option that will allow the user to determine how IPv6
 *    flow records are handled.  This function will also check the
 *    environment variabled namd by SILK_IPV6_POLICY_ENVAR for a
 *    policy to follow.  After skOptionsParse() sucessfully returns, the
 *    variable pointed to by 'ipv6_policy' will contain the IPv6
 *    policy to follow.
 *
 *    Before calling this function, the caller should set the variable
 *    that ipv6_policy points at to the application's default IPv6
 *    policy.
 *
 *    If IPv6 support is not enabled, the ipv6_policy is set to ignore
 *    IPv6 flows, the environment is not checked, and no option is
 *    registered
 */


void skIPv6PolicyUsage(FILE *fh);
/*
 *    Print the help text for the --ipv6-policy switch to the named
 *    file handle.  Uses the default policy that was set when
 *    skIPv6PolicyOptionsRegister() was called.
 */


typedef struct skIPWildcard_st {
#if !SK_ENABLE_IPV6
    uint32_t            m_blocks[4][256/32];
    uint16_t            m_min[4];
    uint16_t            m_max[4];
#else
    uint32_t            m_blocks[8][65536/32];
    uint16_t            m_min[8];
    uint16_t            m_max[8];
#endif
    uint8_t             num_blocks;
} skIPWildcard_t;

typedef struct skIPWildcardIterator_st {
    const skIPWildcard_t   *ipwild;
    uint16_t                i_block[8];
    unsigned                no_more_entries :1;
    unsigned                force_ipv6 :1;
} skIPWildcardIterator_t;


/* Status of an iterator. */
typedef enum {
    /* More entries */
    SK_ITERATOR_OK=0,
    /* No more entries */
    SK_ITERATOR_NO_MORE_ENTRIES
} skIteratorStatus_t;



#define _IPWILD_BLOCK_IS_SET(ipwild, block, val)                        \
    ((ipwild)->m_blocks[(block)][_BMAP_INDEX(val)] & _BMAP_OFFSET(val))

#define _IPWILD_IPv4_IS_SET(ipwild, ipaddr)                             \
    (_IPWILD_BLOCK_IS_SET((ipwild), 0, 0xFF&(skipaddrGetV4(ipaddr) >> 24))&& \
     _IPWILD_BLOCK_IS_SET((ipwild), 1, 0xFF&(skipaddrGetV4(ipaddr) >> 16))&& \
     _IPWILD_BLOCK_IS_SET((ipwild), 2, 0xFF&(skipaddrGetV4(ipaddr) >>  8))&& \
     _IPWILD_BLOCK_IS_SET((ipwild), 3, 0xFF&(skipaddrGetV4(ipaddr))))


void skIPWildcardClear(skIPWildcard_t *ipwild);
/*
 *    Zero all values in the skIPWildcard_t 'ipwild'.
 */



#if !SK_ENABLE_IPV6
#  define skIPWildcardIsV6(ipwild)   0
#  define skIPWildcardCheckIp(ipwild, ipaddr) \
    _IPWILD_IPv4_IS_SET(ipwild, ipaddr)
#else
#  define skIPWildcardIsV6(ipwild) (8 == (ipwild)->num_blocks)
int skIPWildcardCheckIp(const skIPWildcard_t *ipwild, const skipaddr_t *ip);
#endif
/*
 *    Return 1 if 'ip' is represented in by 'ipwild'; 0 otherwise.
 */


int skIPWildcardIteratorBind(
    skIPWildcardIterator_t *iter,
    const skIPWildcard_t   *ipwild);
/*
 *    Bind the iterator 'iter' to iterate over the entries in the
 *    skIPWildcard_t 'ipwild'.
 */


#if SK_ENABLE_IPV6
int skIPWildcardIteratorBindV6(
    skIPWildcardIterator_t *iter,
    const skIPWildcard_t   *ipwild);
/*
 *    Bind the iterator 'iter' to iterate over the entries in the
 *    skIPWildcard_t 'ipwild'.  Similar to skIPWildcardIteratorBind(),
 *    but instructs the iterator to return IPv6 addresses.
 */
#endif  /* SK_ENABLE_IPV6 */


skIteratorStatus_t skIPWildcardIteratorNext(
    skIPWildcardIterator_t *iter,
    skipaddr_t             *out_ip);
/*
 *    Fill 'out_ip' with the next IP address represented by the
 *    IPWildcard that is bound to the iterator 'iter'.  Return
 *    SK_ITERATOR_OK if 'out_ip' was filled with an IP address, or
 *    SK_ITERATOR_NO_MORE_ENTRIES otherwise.
 */


void skIPWildcardIteratorReset(skIPWildcardIterator_t *iter);
/*
 *    Allow 'iter' to iterate again over the entries in the IPWildcard
 *    that is bound to it.
 */


/*
**
**    sku-string.c
**
*/

typedef enum {
    SKIPADDR_CANONICAL, SKIPADDR_ZEROPAD, SKIPADDR_DECIMAL
} skipaddr_flags_t;

char *skipaddrString(char *outbuf, const skipaddr_t *ip, uint32_t ip_flags);
/*
 *    Fill 'outbuf' with a string represenation of the IP address in
 *    'ip'.  The form of the string will depend on the values in
 *    'ip_flags', which should contain a value from
 *    'skipaddr_flags_t'.  The size of 'outbuf' must be at least
 *    SK_NUM2DOT_STRLEN bytes in length.  The function returns a
 *    pointer to 'outbuf'.
 */


char *num2dot(uint32_t ip);
/*
 *    Converts the integer form of an IPv4 IP address to the dotted-quad
 *    version.  ip is taken to be in native byte order; returns a
 *    pointer to a static string buffer.
 *
 *    Returns NULL on error.
 */


char *num2dot0(uint32_t ip);
/*
 *    Like num2dot(), but will zero-pad the octects: num2dot0(0) will
 *    return "000.000.000.000"
 */


#define SK_NUM2DOT_STRLEN 46
/*
 *    Length of buffer required to hold an IPv6 address.  This is
 *    taken from INET6_ADDRSTRLEN used by inet_ntop(), which can
 *    return "0000:0000:0000:0000:0000:00FF:000.000.000.000"
 */

char *num2dot_r(uint32_t ip, char *outbuf);
/*
 *    Thread safe version of num2dot().  The 'outbuf' should be at
 *    least SK_NUM2DOT_STRLEN characters long.
 */


char *num2dot0_r(uint32_t ip, char *outbuf);
/*
 *    Thread safe version of num2dot0().  The 'outbuf' should be at
 *    least SK_NUM2DOT_STRLEN characters long.
 */


const char *skNameToAddr(const char *name, struct in_addr *addr);
/*
 *    Uses domain name resolution to convert the hostname 'name' to an
 *    IPV4 address.
 *
 *    Returns NULL on success, and error message on failure.
 */

char *tcpflags_string(uint8_t flags);
/*
 *    Return an 8 character string denoting which TCP flags are set.
 *    If all flags are on, FSRPAUEC is returned.  For any flag that is
 *    off, a space (' ') appears in place of the character.  Returns a
 *    pointer to a static buffer.
 */


#define SK_TCPFLAGS_STRLEN 9

char *tcpflags_string_r(uint8_t flags, char *outbuf);
/*
 *    Thread-safe version of tcpflags_string().  The 'outbuf' should
 *    be at least SK_TCPFLAGS_STRLEN characters long.
 */


int skStrip(char *line);
/*
 *    Strips all leading and trailing whitespace from 'line'.
 *    Modifies line in place.
 */


void skToLower(char *cp);
/*
 *    Converts uppercase letters in 'cp' to lowercase.  Modifies the
 *    string in place.
 */


void skToUpper(char *cp);
/*
 *    Converts lowercase letters in 'cp' to uppercase.  Modifies the
 *    string in place.
 */


const char *skStringParseStrerror(int errcode);
/*
 *    Return a string describing the last error that occurred when
 *    invoking the skStringParse* functions.
 */


int skStringParseNumberList(
    uint32_t                  **number_list,
    uint32_t                   *number_count,
    const char                 *input,
    uint32_t                    min_val,
    uint32_t                    max_val,
    uint32_t                    max_number_count);
/*
 *    Given a C-string containing a list---i.e., comma or hyphen
 *    delimited set---of non-negative integers, e.g., "4,3,2-6",
 *    allocate and return, via the 'number_list' parameter, an array
 *    whose values are the numbers the list contains, breaking ranges
 *    into a list of numbers.  If duplicates appear in the input, they
 *    will appear in the return value.  Order is maintained.  Thus
 *    given the C-string 'input' of "4,3,2-6", the function will set
 *    *number_list to a newly allocated array containing
 *    {4,3,2,3,4,5,6}.  The number of entries in the array is returned
 *    in '*number_count'.  The list of number is limited by the
 *    'min_val' and 'max_val' parameters; a 'max_val' of 0 means no
 *    maximum.  The maximum size of the array to be returned is given
 *    by 'max_number_count'; when this value is 0 and max_value is not
 *    zero, it is set to the number of possible values (1+max-min);
 *    when max_number_count is 0 and max_value is 0, it is set to a
 *    large (2^24) number of entries.  In all cases, the function
 *    tries to keep the returned array as small as possible.  On
 *    success, 0 is returned.
 *
 *    INPUT:
 *      number_list -- the address in which to return the array
 *      number_count -- the address in which to store the
 *          number valid elements in the returned array.
 *      input -- the string buffer to be parsed
 *      min_value -- the minimum allowed value in user input
 *      max_value -- the maximum allowed value in user input.  When
 *          max_value is 0, there is no maximum.
 *      max_number_count -- the maximum number of entries the array
 *          returned in 'number_list' is allowed to have.
 *
 *    The caller should free() the returned array when finished
 *    processing.
 *
 *    On error, a silk_utils_errcode_t value is returned.
 */


int skStringParseNumberListToBitmap(
    sk_bitmap_t                *out_bitmap,
    const char                 *input);
/*
 *    Similar to skStringParseNumberList(), except that instead of
 *    returning an array, bits are set in the sk_bitmap_t 'out_bitmap'
 *    which the caller must have previously created.
 *
 *    The input may have values from 0 to skBitmapGetSize(out_bitmap)-1.
 *
 *    This function does NOT clear the bits in 'out_bitmap' prior to
 *    setting the bits based on 'input.  When re-using a bitmap, the
 *    caller should first call skBitmapClearAllBits().
 *
 *    If an error occurs, a silk_utils_errcode_t value is returned and
 *    the bitmap will be left in an unknown state.
 */


int skStringParseIP(skipaddr_t *out_val, const char *ip_string);
/*
 *    Parses a C-string containing an IPv4 or IPv6 address in the
 *    "canonical" presenation form and sets the value pointed to by
 *    'out_val' to the result.
 *
 *    In addition, a single integer value will be parsed as IPv4
 *    address.
 *
 *    Returns 0 and puts the result into 'out_val' if parsing was
 *    successful and the 'ip_string' only contained the IP address and
 *    optional leading and/or trailing whitespace.
 *
 *    Returns a positive value and puts the result into 'out_val' if
 *    parsing was successful and 'ip_string' contains additional,
 *    non-whitespace text.  The return value is the number of
 *    characters that were parsed as part of the IP address and any
 *    leading whitespace.  That is, the return value is the position
 *    in 'ip_string' where the trailing text begins.  Whitespace
 *    between the IP address and the trailing text is not parsed.
 *
 *    Returns one of the silk_utils_errcode_t values on error.
 *
 *    This routine will not parse IPs in CIDR notation; or rather, it
 *    will parse the IP portion, but the return value will be the
 *    position of the '/' character.  To correctly parse IPs in CIDR
 *    notation, use skStringParseCIDR() or skStringParseIPWildcard().
 */


int skStringParseIPWildcard(
    skIPWildcard_t *ipwild,
    const char     *ip_string);
/*
 *    Takes a C-string containing an IPv4 or IPv6 address and fills
 *    'ipwild' with the result.
 *
 *    Returns 0 and puts result into 'ipwild' if parsing was
 *    successful and 'ip_string' contained only the IP address and
 *    optional leading or trailing whitespace.
 *
 *    Returns one of the silk_utils_errcode_t values on error.
 *
 *    The 'ip_string' can be in CIDR notation such as "1.2.3.0/24" or
 *    "ff80::/16"; in the canonical form "1.2.3.4" or
 *    "::FFFF:0102:0304", an integer 16909056, an integer with a CIDR
 *    designation 16909056/24, or in SiLK wildcard notation: a IP in
 *    the canonical form with an 'x' respresenting an entire octet
 *    "1.2.3.x" in IPv4 or entire hexadectet in IPv6
 *    "1:2:3:4:5:6:7.x", or a dotted quad with lists or ranges in any
 *    or all octets or hexadectets "1.2,3.4,5.6,7", "1.2.3.0-255",
 *    "::2-4", "1-2:3-4:5-6:7-8:9-a:b-c:d-e:0-ffff".
 *
 *    Note that wildcard characters (',','-','x') and CIDR notation
 *    cannot be combined in a single address.
 *
 *    See also skStringParseCIDR().
 */


int skStringParseCIDR(
    skipaddr_t *out_val,
    uint32_t   *out_cidr,
    const char *ip_string);
/*
 *    Parses a C-string containing an IPv4 or IPv6 address in the
 *    "canonical" presenation form with an optional CIDR designation.
 *    Sets the values pointed to by 'out_val' and 'out_cidr' to the
 *    parsed IP address and the CIDR designation.  If no CIDR
 *    designation is present in 'ip_string', 'out_cidr' is set to the
 *    complete IP length: 32 for IPv4, 128 for IPv6.
 *
 *    In addition, a single integer value will be parsed as IPv4
 *    address, with an optional CIDR designation.
 *
 *    Returns 0 and puts the result into 'out_val' if parsing was
 *    successful and the 'ip_string' only contained the IP address,
 *    the CIDR designation, and optional leading and/or trailing
 *    whitespace.
 *
 *    Returns one of the silk_utils_errcode_t values on error.
 *
 *    If the CIDR mask is too large for the type of IP,
 *    SKUTILS_ERR_MAXIMUM is returned.
 *
 *    It is an error for 'ip_string' to contain any text other than
 *    the IP string, CIDR designation, and leading or trailing
 *    whitespace.  SKUTILS_ERR_BAD_CHAR will be returned.
 *
 *    This routine will not parse the SiLK IP Wildcard notation; use
 *    skStringParseIPWildcard() for that.
 */


#define PORT_REQUIRED    1
#define PORT_FORBIDDEN   2
#define IPV6_FORBIDDEN   4
#define PORT_WAS_GIVEN  64

typedef struct sk_hostport_st {
    char               *host_name;
    skipaddr_t          host_ip;
    uint16_t            port;
    uint16_t            flags;
    /* struct sockaddr    *sockaddr; */
} sk_hostport_t;


int skStringParseHostPortPair(
    sk_hostport_t      *sockaddr,
    const char         *host_port);
/*
 *    Parse a host:port pair or a host.  Set the flags member in the
 *    'sockaddr' as to what is required/forbidden.
 *
 *    The host can be a dotted decimal IPv4 address, a hex string IPv6
 *    address, or a hostname.  The host can be enclosed in '[' and
 *    ']', and it must be so enclosed when an IPv6 hex string includes
 *    a port number, for example "[::]:80"
 */


int skStringParseDatetime(
    sktime_t   *time_val,
    const char *time_string,
    int        *resulting_precision);
/*
 *    Attempts to parse the 'time_string' as a date in the form
 *    YYYY/MM/DD[:HH[:MM[:SS[.sss]]]].  Sets *time_val to that time in
 *    milliseconds since the UNIX epoch.  Assumes the time in UTC
 *    unless SiLK was configured with the --enable-local-timezone
 *    switch, in which case the time is assumed to be in the local
 *    timezone.
 *
 *    If 'resulting_precision' is non-null, it is filled with the
 *    index of the last "section" of date parsed.  If it is NULL, the
 *    precision is not recorded, but parsing still occurs.
 *
 *    The "sections" are:
 *        1. Years parsed
 *        2. Months parsed
 *        3. Days parsed
 *        4. Hours parsed
 *        5. Minutes parsed
 *        6. Seconds parsed
 *        7. Fractional seconds parsed
 *
 *    Note that skStringParseDatetime() will return -1 if the
 *    time_string does not contain at least Day precision.
 *
 *    Return 0 on success.  Returns a silk_utils_errcode_t value on an
 *    error; error conditions include an empty string, malformed date,
 *    or extra text after the date.  Returns SKUTILS_ERR_SHORT if the
 *    date does not have at least day precision.
 */


int skStringParseDatetimeRange(
    sktime_t   *start,
    sktime_t   *end,
    const char *s_datetime,
    int        *start_precision,
    int        *end_precision);
/*
 *    Attempts to parse 's_datetime' as a datetime or a range of
 *    datetimes.  If only one date is found, it is stored in 'start'
 *    and the value of the end date is set to INT64_MAX.
 *
 *    If two dash-separated dates are found, the first is stored in
 *    'start' and the second is stored in 'end'.
 *
 *    If 'start_precision' is not NULL, it is filled with the index of
 *    the last "section" of date parsed.  If it is NULL, the precision
 *    is not recorded, but parsing still occurs.
 *
 *    Similarly, if 'end_precision' is not NULL and a second date was
 *    parsed, it is filled with the index of the last "section" of
 *    date parsed.  If it is NULL, the precision is not recorded.  See
 *    skStringParseDatetime() for a description of "sections" of a date.
 *
 *    Returns 0 if dates are parsed correctly.
 *
 *    Returns an silk_utils_errcode_t value on error, including
 *    SKUTILS_ERR_SHORT if the either date does not have at least day
 *    precision, and SKUTILS_ERR_BAD_RANGE if the end-date is earlier
 *    than the start-date.
 */


int skDatetimeCeiling(
    sktime_t       *ceiling_time,
    const sktime_t *t,
    int             precision);
/*
 *    Takes the time 't' and a 'precision' to which it was
 *    parsed---see skStringParseDatetime() for a description of
 *    "sections" of a date---and puts into 'ceiling_time' the
 *    latest-possible timestamp that meets the precision.  't' and
 *    'ceiling_time' may point to the same memory.
 *
 *    skStringParseDatetime() parses a time to the earliest-possible
 *    timestamp that meets the constraints parsed.  For example,
 *    "1990/12/25:05" is assumed to mean "1990/12/25:05:00:00.000".
 *    Passing that value to skDatetimeCeiling() would result in the
 *    timestamp for "1990/12/25:05:59:59.999".
 *
 *    skDatetimeCeiling() is commonly used to calculate the endpoint
 *    for a range of dates.  For example, "2004/12/25-2004/12/26:3"
 *    should represent everything between "2004/12/25:00:00:00.000"
 *    and "2004/12/26:03:59:59.999".
 *
 *    The time is assumed to be in UTC unless SiLK was configured with
 *    the --enable-local-timezone switch.  The timezone is only a
 *    factor for times that are coarser than hour precision.
 */


int skStringParseUint32(
    uint32_t   *result_val,
    const char *int_string,
    uint32_t    min_val,
    uint32_t    max_val);
/*
 *    Attempts to parse the C string 'int_string' as an unsigned
 *    32-bit integer.  In addition, verifies that the value is between
 *    'min_val' and 'max_val' inclusive.  A 'max_val' of 0 is
 *    equivalent to UINT32_MAX; i.e., the largest value that will fit
 *    in a 32bit value.  Puts the result into location pointed to by
 *    'result_val'.  Ignores any whitespace around the number.
 *
 *    Returns 0 and fills 'result_val' when 'int_string' contains only
 *    a number and whitespace and the number is parsable and the
 *    resulting value is within the limits.
 *
 *    Returns a positive value and fills 'result_val' when
 *    'int_string' contains a value within the limits and contains
 *    additional non-whitespace text.  The return value is the number
 *    of characters parsed in 'int_string'.  The return value does
 *    not include whitespace between the number and the trailing text;
 *    e.g; "7 x" would set *result_val to 7 and return 1.
 *
 *    Returns a silk_utils_errcode_t value on error.
 */


int skStringParseUint64(
    uint64_t   *result_val,
    const char *int_string,
    uint64_t    min_val,
    uint64_t    max_val);
/*
 *    As skStringParseUint32(), except that it attempts to parse the
 *    C-string 'int_string' as an unsigned 64-bit integer and a
 *    'max_val' of 0 represents UINT64_MAX.
 */



/* options flags to pass to skStringParseHumanUint64() */
typedef enum {
    /* Use 1024 for k, etc.  This is the default unless
     * SK_HUMAN_LOWER_SI is specified. */
    SK_HUMAN_LOWER_TRADITIONAL = 0,

    /* Use 1000 instead of 1024 for k, etc. */
    SK_HUMAN_LOWER_SI = 1,

    /* Use 1024 for K, etc.  This is the default unless
     * SK_HUMAN_UPPER_SI is specified. */
    SK_HUMAN_UPPER_TRADITIONAL = 0,

    /* Use 1000 instead of 1024 for K, etc. */
    SK_HUMAN_UPPER_SI = 2,

    /* Do not allow whitespace between the number and the suffix---the
     * position of the suffix will be the function's return value.
     * This is the default unless SK_HUMAN_MID_WS is specified. */
    SK_HUMAN_MID_NO_WS = 0,

    /* Ignore whitespace between the number and the suffix */
    SK_HUMAN_MID_WS = 4,

    /* Parse trailing whitespace.  This is the default unless
     * SK_HUMAN_END_NO_WS is specified. */
    SK_HUMAN_END_WS = 0,

    /* Do not parse trailing whitespace.  The position of the first
     * whitespace chacter is the function's return value. */
    SK_HUMAN_END_NO_WS = 8
} skHumanFlags_t;

/* Default settings from skStringParseHumanUint64() */
#define SK_HUMAN_NORMAL                                         \
    (SK_HUMAN_LOWER_TRADITIONAL | SK_HUMAN_UPPER_TRADITIONAL    \
     | SK_HUMAN_MID_NO_WS | SK_HUMAN_END_WS)

int skStringParseHumanUint64(
    uint64_t       *result_val,
    const char     *int_string,
    int             parse_flags);
/*
 *    Attempts to parse the C string 'int_string' as an unsigned
 *    64-bit integer, ignoring leading whitespace.  In addition,
 *    handles human suffixes such as k, m, g, and t.  Puts the result
 *    into location pointed to by 'result_val'.
 *
 *    Returns a value >= 0 the string was parsable.  Returns 0 when
 *    nothing other than parsed whitespace was present.  A positive
 *    return value is the index into 'int_string' of the first
 *    non-parsed character following the successfully parsed number;
 *    e.g; "1x" would set *result_val to 1 and return 2.
 *
 *    Returns an silk_utils_errcode_t value on error.  Note that "NaN"
 *    returns SKUTILS_ERR_BAD_CHAR.
 *
 *    The 'parse_flags' value is made by or-ing flags from
 *    skHumanFlags_t together.  See their descriptions above.
 */


/* Following are used by skStringParseRange32() */

#define SKUTILS_RANGE_SINGLE_OPEN   0
/* Allow single values '3' and open-ended ranges '3-' */

#define SKUTILS_RANGE_NO_SINGLE     (1<<0)
/* Force the value to be a range, but allow open-ended ranges */

#define SKUTILS_RANGE_NO_OPEN       (1<<1)
/* Allow single values '3' or complete ranges '3-5'; i.e., force an
 * upper bound on any range */

#define SKUTILS_RANGE_ONLY_RANGE    (SKUTILS_RANGE_NO_SINGLE \
                                     | SKUTILS_RANGE_NO_OPEN)
/* Only support ranges, and force the range to have both bounds */

int skStringParseRange32(
    uint32_t   *range_lower,
    uint32_t   *range_upper,
    const char *range_string,
    uint32_t    min_val,
    uint32_t    max_val,
    int         flags);
/*
 *    Attempts to parse the C-string 'range_string' as a range of two
 *    32-bit integers; that is, as a 32-bit integer representing the
 *    lower bound of the range, a hyphen '-', and the upper bound of
 *    the range.  The function sets 'range_lower' to the lower bound,
 *    and 'range_upper' to the upper bound.
 *
 *    The function also verifies that the bounds on the range fall
 *    between 'min_val' and 'max_val' inclusive.  A 'max_val' of 0 is
 *    equivalent to UINT32_MAX.
 *
 *    If flags does not contain 'SKUTILS_RANGE_NO_SINGLE', this
 *    function will also parse a single value, similar to
 *    skStringParseUint32().  When this occurs, both 'range_lower' and
 *    'range_upper' are set to the single value.  There is no way for
 *    the caller to tell whether the function parsed a single value
 *    '4' or a range where the bounds are identical '4-4'.
 *    SKUTILS_ERR_SHORT is returned when a single value is present and
 *    SKUTILS_RANGE_NO_SINGLE is specified.
 *
 *    If flags does not contain 'SKUTILS_RANGE_NO_OPEN', the upper
 *    bound of the range is optional.  That is, a 'range_string' of
 *    '5-' will result in the upper bound being set to 'max_val', or
 *    UINT32_MAX if 'max_val' is 0.  SKUTILS_ERR_SHORT is returned
 *    when an open-ended range is given and SKUTILS_RANGE_NO_OPEN is
 *    specified.
 *
 *    Whitespace around the range will be ignored.  Whitespace within
 *    the range will result in SKUTILS_ERR_BAD_CHAR being returned.
 *
 *    Returns 0 on success, or a silk_utils_errcode_t value on error.
 */


int skStringParseRange64(
    uint64_t   *range_lower,
    uint64_t   *range_upper,
    const char *range_string,
    uint64_t    min_val,
    uint64_t    max_val,
    int         flags);
/*
 *    As skStringParseRange32(), except that it attempts to parse the
 *    C-string 'range_string' as two unsigned 64-bit integers and a
 *    'max_val' of 0 represents UINT64_MAX.
 */


int skStringParseDouble(
    double     *result_val,
    const char *dbl_string,
    double      min_val,
    double      max_val);
/*
 *    Attempts to parse the C string 'dbl_string' as a floating point
 *    value (double).  In addition, verifies that the value is between
 *    'min_val' and 'max_val' inclusive.  A 'max_val' of 0 is
 *    equivalent to HUGE_VAL.  Puts the result into location pointed
 *    to by 'result_val'.  Ignores any whitespace around the number.
 *
 *    Returns 0 and fills 'result_val' when 'dbl_string' contains only
 *    a number and whitespace and the number is parsable and the
 *    resulting value is within the limits.
 *
 *    Returns a positive value and fills 'result_val' when
 *    'dbl_string' contains a value within the limits and contains
 *    additional non-whitespace text.  The return value is the number
 *    of characters parsed, not including whitespace between the
 *    number and the additional text; e.g; "1.1 x" would set
 *    *result_val to 1.1 and return 3.
 *
 *    Returns an silk_utils_errcode_t value on error.  Note that "NaN"
 *    returns SKUTILS_ERR_BAD_CHAR.
 */


int skStringParseDoubleRange(
    double     *range_lower,
    double     *range_upper,
    const char *range_string,
    double      min_val,
    double      max_val,
    int         flags);
/*
 *    As skStringParseRange32(), except that it attempts to parse the
 *    C-string 'range_string' as two double values and a 'max_val' of
 *    0 represents HUGE_VAL.
 */




/* TCP FLAGS HANDLING */

/* Sets any high-flags in 'flags' to high in 'var'.  Other high-flags
 * in 'var' are not affected. */
#define TCP_FLAG_SET_FLAG( var, flags ) ((var) |= (flags))

/* Returns 1 if the high-flags in 'flags' are also high in 'var';
 * returns 0 otherwise. */
#define TCP_FLAG_TEST( var, flags ) ( (((flag) & (var)) != 0) ? 1 : 0 )

/* Returns 1 if, for all high-flags in 'mask', the only high-bits in
 * 'var' are thost that are set in 'high'; return 0 otherwise.  See
 * skStringParseTCPFlagsHighMask() for details. */
#define TCP_FLAG_TEST_HIGH_MASK( var, high, mask ) \
    ( (((var) & (mask)) == ((high) & (mask))) ? 1 : 0 )



int skStringParseTCPFlags(
    uint8_t    *result,
    const char *flag_string);
/*
 *    Parses the C-string 'flag_string' as a block of TCP flags and
 *    puts the value into the memory pointed at by 'result'.  Flag
 *    strings can only contain the following characters:
 *
 *        F f (FIN)
 *        S s (SYN)
 *        R r (RESET)
 *        P p (PUSH)
 *        A a (ACK)
 *        U u (URGENT)
 *        E e (ECE)
 *        C c (CWR)
 *
 *    Returns 0 when 'flag_string' contains valid TCP flag characters
 *    and whitespace.  Returns 0 and sets 'result' to 0 if the string
 *    is empty or contains only whitespace.
 *
 *    Otherwise, a silk_utils_errcode_t value is returned.
 */


int skStringParseTCPFlagsHighMask(
    uint8_t    *high,
    uint8_t    *mask,
    const char *flag_string);
/*
 *    Parses 'flag_string' as a HIGH/MASK pair of blocks of TCP flags.
 *    Both the HIGH and MASK portions of the string are flag strings,
 *    and are interpreted by skStringParseTCPFlags().
 *
 *    In a HIGH/MASK pair, the TCP flags listed in HIGH must be set;
 *    flags listed in MASK but not in HIGH must be low; flags not
 *    listed in MASK can have any value.  It is an error if a flag is
 *    listed in HIGH but not in MASK; that is, HIGH must be a subset
 *    of MASK.  For example: "AS/ASFR" means ACK,SYN must be high,
 *    FIN,RST must be low, and the other flags--PSH,URG,ECE,CWR--may
 *    have any value.
 *
 *    If successful, returns 0.  Otherwise, an silk_utils_errcode_t
 *    value is returned.
 *
 *    The inputs 'high' and 'mask' are overwritten with the bitmap of
 *    the flags set.
 *
 *    It is an error for any trailing text (other than whitespace) to
 *    follow the MASK.  Returns SKUTILS_ERR_SHORT if MASK has no
 *    value; returns SKUTILS_ERR_BAD_RANGE if HIGH is not a subset of
 *    MASK.
 */


/*
 * flag definitions.
 */
#define CWR_FLAG (1 << 7)         /* 128 */
#define ECE_FLAG (1 << 6)         /*  64 */
#define URG_FLAG (1 << 5)         /*  32 */
#define ACK_FLAG (1 << 4)         /*  16 */
#define PSH_FLAG (1 << 3)         /*   8 */
#define RST_FLAG (1 << 2)         /*   4 */
#define SYN_FLAG (1 << 1)         /*   2 */
#define FIN_FLAG (1)              /*   1 */


const char *skSignalToName(int signal_num);
/*
 *    Return the name of the signal that has the specified value.  The
 *    returned string does not include the "SIG" prefix.  For example,
 *    calling this function with the value 9 returns "KILL".
 *
 *    If 'signal_number' is not recognized as a signal, the return
 *    value is "?".
 */


int skStringParseSignal(int *signal_num, const char *signal_name);
/*
 *    Parse 'signal_name' as either the name of a signal or the number
 *    of a signal.  The leading "SIG" on 'signal_name' is optional.
 *
 *    If the first non-whitespace chacter in 'signal_name' is a digit,
 *    the return value is similar to that for skStringParseUint32().
 *
 *    The function returns 0 if 'signal_name' only contains a signal
 *    name and optional leading and/or trailing whitespace.
 *
 *    A return value greater than 0 indicates that a signal name was
 *    parsed, but that additional text appears in the string.  The
 *    return value indicates the number of character that were parsed.
 *
 *    On error, the function returns one of the following values:
 *    SKUTILS_ERR_INVALID if an input value is NULL; SKUTILS_ERR_EMPTY
 *    if 'signal_name' contains only whitespace, or
 *    SKUTILS_ERR_BAD_CHAR if the string does not contain a valid
 *    signal name.
 */






#endif /* _UTILS_H */

/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/
