/*
** Copyright (C) 2001-2007 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.225-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 F19628-00-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.h"

RCSIDENTVAR(rcsID_UTILS_H, "$SiLK: utils.h 7644 2007-06-26 16:48:40Z mthomas $");

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


#ifdef HAVE_GETOPT_LONG_ONLY
#  include <getopt.h>
#else
#  include "gnu_getopt.h"
#endif

#define isRunningOnNode()  0


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

#if !HAVE_IMAXDIV
#  define imaxdiv sk_imaxdiv
#endif
imaxdiv_t sk_imaxdiv(intmax_t numer, 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.
 */


#if !HAVE_MEMCCPY
#  define memccpy sk_memccpy
#endif
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 points to character after 'c' in 'dst'.
 *
 *    Conforming to C99.
 */


#if !HAVE_TIMEGM
#  define timegm sk_timegm
#endif
time_t sk_timegm(struct tm *tm);
/*
 *    Does the reverse of gmtime().  Takes a time structure and
 *    returns 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 {
    uint32_t   *map;
    uint32_t    num_bits;
    uint32_t    count;
} sk_bitmap_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.
 *    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.
 */


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


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.
 */


typedef struct {
    uint32_t            m_octets[4][256/32];
} skOctetMap_t;

typedef struct {
    const skOctetMap_t *omap;
    uint16_t            i_octet[4];
} skOctetMapIterator_t;

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



#define _OMAP_OCT_IS_SET(omap, o, ip)                           \
    ((omap)->m_octets[(o)][_BMAP_INDEX(ip)] & _BMAP_OFFSET(ip))

#define _OMAP_IP_IS_SET(omap, ip)                           \
    (_OMAP_OCT_IS_SET((omap), 0, (((ip) >> 24) & 0xFF)) &&  \
     _OMAP_OCT_IS_SET((omap), 1, (((ip) >> 16) & 0xFF)) &&  \
     _OMAP_OCT_IS_SET((omap), 2, (((ip) >>  8) & 0xFF)) &&  \
     _OMAP_OCT_IS_SET((omap), 3, ((ip)         & 0xFF)))


void skOctetMapClear(skOctetMap_t *octetmap);
/*
 *    Zero all values in the 'octetmap'.
 */


#ifdef SKBITMAP_DEBUG
#  define skOctetMapGetIp(octetmap, ip) skOctetMapGetIpF(octetmap, ip)
#else
#  define skOctetMapGetIp(octetmap, ip) \
    (_OMAP_IP_IS_SET(octetmap, ip) ? 1 : 0)
#endif
int skOctetMapGetIpF(const skOctetMap_t *octetmap, uint32_t ip);
/*
 *    Return 1 if 'ip' is represented in the 'octetmap'; 0 otherwise.
 */


int skOctetMapIteratorInitialize(
    skOctetMapIterator_t  *iter,
    const skOctetMap_t    *octetmap);
/*
 *    Prepare the iterator 'iter' to iterate over the entries in the
 *    'octetmap'.
 */


skIteratorStatus_t skOctetMapIteratorNext(
    uint32_t               *out_ip,
    skOctetMapIterator_t   *iter);
/*
 *    Fill 'out_ip' with the next IP address represented by the
 *    octetmap 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 skOctetMapIteratorReset(skOctetMapIterator_t *iter);
/*
 *    Allow 'iter' to iterate again over the octetmap that is bound to
 *    it.
 */


/* 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
**
*/

typedef int (*sk_msg_fn_t)(const char *, ...);
/*
 *    The type of message functions.  These should use the same
 *    semantics as printf.
 */

typedef int (*sk_msg_vargs_fn_t)(const char *, va_list);
/*
 *    The type of message functions with the arguments expanded to a
 *    variable argument list.
 */

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

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

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

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

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

extern 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.
 */

extern 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.
 */

extern 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.
 */

extern 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.
 */

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

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

extern 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.
 */

extern void skAppSetFuncPrintErr(sk_msg_vargs_fn_t fn);
/*
 *    skAppPrintErr() will call this funtion to print its arguments.
 *    By default, skAppPrintErr() uses skAppPrintErrV().
 */

extern void skAppSetFuncPrintSyserror(sk_msg_vargs_fn_t fn);
/*
 *    skAppPrintSyserror() will call this funtion to print its
 *    arguments.  By default, skAppPrintSyserror() uses
 *    skAppPrintSyserrorV().
 */

extern 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.
 */

extern 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
extern int skAppPrintErr(const char *fmt, ...);
#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
extern int skAppPrintSyserror(const char *fmt, ...);
#endif
/*
 *    Calls the function set by skAppSetFuncPrintSyserror()---which
 *    has the default value skAppPrintSyserrorV()---to format and
 *    print the arguments using the given format 'fmt'.
 */


/*
**
**    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")))

/* name of option for app to load a dynamlic library */
#define OPT_DYNAMIC_LIBRARY "dynamic-library"


/* 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);

void skOptionsTeardown(void);

void skOptionsSetUsageCallback(usage_fn_t fn);

int optionsSetup(usage_fn_t fn);
/* returns 0 (ok), 1 (not ok) */

void optionsTeardown(void);

int optionsRegister(void *inOptions, optHandler handler, clientData cData);


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


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
 */

int optionsParse(int argc, char **argv);
/*
 *  optionsParse:
 *      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.
 */


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

typedef enum {
    /* do not change the way the time is displayed */
    SK_TIMESTAMP_CURRENT,
    /* use the default mode of displaying the time */
    SK_TIMESTAMP_DEFAULT,
    /* display the time as "MM/DD/YYYY hh:mm:ss[.sss]" */
    SK_TIMESTAMP_MMDDYYYY,
    /* display the time as "YYYY/MM/DD:hh:mm:ss[.sss]" */
    SK_TIMESTAMP_YYYYMMDD
} sktimestamp_mode_t;

typedef enum {
    /* do not change whether the fractional seconds are displayed */
    SK_TIME_FRACSEC_CURRENT,
    /* display the fractional seconds if that is the default */
    SK_TIME_FRACSEC_DEFAULT,
    /* force the fractional seconds to be displayed */
    SK_TIME_FRACSEC_ON,
    /* do not display the fractional seconds */
    SK_TIME_FRACSEC_OFF
} sktime_fracsec_mode_t;


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


void sktimestampSetMode(
    sktimestamp_mode_t      tsm,
    sktime_fracsec_mode_t   fsm);
/*
 *    Set the default mode that sktimestamp_r() uses for displaying
 *    the time.  To only change one value, use the *_CURRENT setting
 *    for the other setting.  The display of fractional seconds may be
 *    controlled on each invocation of sktimestamp_r().
 */


int sktimestampSuppressingFracSecs(void);
/*
 *    Return 1 if fractional seconds should be suppressed; 0
 *    otherwise; that is, return 0 if fractional seconds should be
 *    printed, and 1 otherwise.
 */


char *sktimestamp_r(
    char                   *outbuf,
    const struct timeval   *tval,
    int                     suppress_fracsec);
/*
 *    Fill 'outbuf' with an ASCII version of the time.  'outbuf' must
 *    be at least SK_TIMESTAMP_STRLEN characters long.  'tval' is the
 *    time (see gettimeofday(2)).
 *
 *    If SiLK was NOT configured with the --enable-legacy-timestamps
 *    switch, the timestamp will be in the form:
 *
 *        "YYYY/MM/DD:HH:MM:SS.sss"
 *
 *    where sss == milliseconds, and the time will be printed in the
 *    local timezone.
 *
 *    If SiLK was configured with --enable-legacy-timestamps, the
 *    timestamp will be in the form:
 *
 *        "MM/DD/YYYY HH:MM:SS"
 *
 *    The value will be in UTC unless SiLK was configured with
 *    --enable-local-timezone switch.
 *
 *
 */


char *sktimestamp(
    const struct timeval   *tval,
    int                     suppress_fracsec);
/*
 *    Similar to sktimestamp_r(), except returns the value in a static
 *    buffer.
 */

char *timestamp_r(uint32_t t, char *outbuf);
/*
 *    DEPRECATED.  DO NOT USE IN NEW CODE.
 *
 *    Legacy wrapper around sktimestamp_r().  't' is seconds since the
 *    UNIX epoch.
 */


char *timestamp(uint32_t t);
/*
 *    DEPRECATED.  DO NOT USE IN NEW CODE.
 *
 *    Legacy wrapper around timestamp_r().
 */


int maxDayInMonth(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
 *
 */


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

int bigsockbuf(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 *baseName(const char *fp);
/*
 *    Strip directory prefix from the file path fp.  Returns a pointer
 *    to a static string buffer.
 */


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


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


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


#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 dirExists(const char *dName);
/*
 *    Returns 1 if dName exists and is a directory; returns 0
 *    otherwise.
 */


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


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


#define getRLockFD(fd)         silkFileLocks((fd), F_RDLCK, F_SETLK)
#define getRLockFILE(fp)       getRLockFD(fileno(fp))
/*
 *    int ret = getRLockFD(int fd);           // file descriptor
 *    int ret = getRLockFILE(FILE *fp);       // file pointer
 *
 *    Get an exclusive read lock on the opened file.  It does not
 *    wait.
 *
 *    Returns: 0 OK; 1 failed;
 *
 */


#define getRLockFD_Wait(fd)    silkFileLocks((fd), F_RDLCK, F_SETLKW)
#define getRLockFILE_Wait(fp)  getRLockFD_Wait(fileno(fp))
/*
 *    int ret = getRLockFD_Wait(int fd);      // file descriptor
 *    int ret = getRLockFILE_Wait(FILE *fp);  // file pointer
 *
 *    Get an exclusive read lock on the opened file.  It waits till it
 *    gets the lock indefinitely.
 *
 *    Returns: 0 OK; 1 failed;
 *
 */


#define getWLockFD(fd)         silkFileLocks((fd), F_WRLCK, F_SETLK)
#define getWLockFILE(fp)       getWLockFD(fileno(fp))
/*
 *    int ret = getWLockFD(int fd);           // file descriptor
 *    int ret = getWLockFILE(FILE *fp);       // file pointer
 *
 *    Get an exclusive write lock on the opened file.  It does not
 *    wait.
 *
 *    Returns: 0 OK; 1 failed;
 *
 */


#define getWLockFD_Wait(fd)    silkFileLocks((fd), F_WRLCK, F_SETLKW)
#define getWLockFILE_Wait(fp)  getWLockFD_Wait(fileno(fp))
/*
 *    int ret = getWLockFD_Wait(int fd);      // file descriptor
 *    int ret = getWLockFILE_Wait(FILE *fp);  // file pointer
 *
 *    Get an exclusive write lock on the opened file.  It waits till
 *    it gets the lock indefinitely.
 *
 *    Input: the file descriptor
 *
 *    Returns: 0 OK; 1 failed;
 *
 */


#define releaseLockFD(fd)      silkFileLocks((fd), F_UNLCK, F_SETLK)
#define releaseLockFILE(fp)    releaseLockFD(fileno(fp))
/*
 *    int ret = releaseLockFD(int fd);        // file descriptor
 *    int ret = releaseLockFILE(FILE *fp);    // file pointer
 *
 *    Release a previously locked file.
 *
 *    Returns: 0 OK; 1 failed;
 *
 */


int silkFileLocks(int fd, short type, int cmd);
/*
 *    Perform a locking operation on the specified file.  For use by
 *    the convenience macros above, which see.
 */


char *skFindFile(const char *basename, char *buf, size_t bufsize, int verbose);
/*
 *    Find the given file 'basename' in one of several places:
 *
 *    -- 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 *findFile(const char *basename);
/*
 *  findFile(file_name);
 *
 *    Legacy version of skFindFile().  Returns a value the caller
 *    should free().
 *
 *    DO NOT USE IN NEW CODE.
 */


char *skutilsFindPluginPath(
    const char *dlPath,
    char       *path,
    size_t      path_len,
    int         verbose);
/*
 *    Find the given plugin path, 'dlPath', in one of several places;
 *    if found copy that location in the character array 'path'--whose
 *    caller-allocated size if 'path_len'---and return 'path';
 *    otherwise return NULL.  This routine checks:
 *
 *    -- If 'dlPath' contains a slash, 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:
 *         * $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 for the plug-in in the:
 *         * "/share/lib" subdir (/yadda/yadda/share/lib/dlPath)
 *         * "/lib" subdir (/yadda/yadda/lib/dlPath)
 *
 *    If 'verbose' is greater than 0, uses skAppPrintErr() to print
 *    every directory it checks.
 *
 *    Return NULL if 'dlPath' was not found; otherwise return a char*
 *    which is the buffer passed into the subroutine.
 */



int openFile(const char *FName, int mode, FILE **fp, int *isPipe);
/*
 *  status = openFile(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 mkDirPath(const char *directory);
/*
 *  mkDirPath:
 *      make full directory path including parent if required
 *  Input: char * path
 *  Output: 0 on success, 1 on failure
 */


int copyFile(const char *srcPath, const char *destPath);
/*
 * copyFile:
 *      Copies the file "source" to "dest".  "Dest" may be a file or a
 *      directory.
 * Input: char * source
 *        char * dest
 * Output: 0 on success, errno on failure.
 */

int moveFile(const char *srcPath, const char *destPath);
/*
 * moveFile:
 *      Moves the file "source" to "dest".  "Dest" may be a file or a
 *      directory.
 * Input: char * source
 *        char * dest
 * Output: 0 on success, errno on failure.
 */

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.
 */


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

int skComputeCIDR(
    uint32_t    start_ip,
    uint32_t    end_ip,
    uint32_t   *new_start_ip);
/*
 *    Compute the largest CIDR block that starts and 'start_ip' and
 *    contains no IPs larger than 'end_ip', and return the number of
 *    bits that that CIDR block contains.  For example:
 *
 *        computeCIDR(2, 5, NULL) => 31
 *
 *    When 'new_start_ip' is not NULL, it's value is set to 0 if the
 *    CIDR block completely contains all IPs between 'start_ip' and
 *    'end_ip'.  Otherwise, its value is set to the IP that follows
 *    that block covered by the CIDR block.  This allows one to print
 *    all CIDR blocks by using:
 *
 *        do {
 *            bits = computeCIDR(start, end, &new_start);
 *            printf("%s/%d", num2dot(start), bits);
 *            start = new_start;
 *        } while (start != 0);
 *
 *    Continuing the above example:
 *
 *        computeCIDR(2, 5, &new) => 31, new => 4
 *        computeCIDR(4, 5, &new) => 31, new => 0
 *
 *    Returns -1 if end_ip < start_ip.
 */



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


#define MALLOCCOPY(a,b) {if (!((a)=strdup(b))) {fprintf(stderr,"MALLOCCOPY: Out of memory at %s:%d\n", __FILE__, __LINE__);exit(1);}}
/*
 *    Duplicate the C string 'b' into 'a'.  Exits if not enough memory.
 */


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 16

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.
 */


uint32_t dot2num(const char *ip);
/*
 *    Converts the string buffer ip containing an IPv4 dotted-quad IP
 *    address into an integer in the native byte order.
 *
 *    Returns 0xFFFFFFFF on error.
 */

const char *skNameToAddr(const char *name, struct in_addr *addr);
/* 
 *    Uses domain name resolution to convert '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 strip(char *line);
/*
 *    Strips all whitespace from the start and end of line.  Modifies
 *    line in place.
 */


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


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


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, an error message is printed (via skAppPrintErr()), and
 *    -1 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.
 *
 *    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, -1 is returned and the bitmap will be left
 *    in an unknown state.
 *
 *    The input may have values from 0 to skBitmapGetSize(out_bitmap)-1.
 */


int skStringParseNumberListToBitArray(
    uint32_t                   *out_bitarray,
    const char                 *input,
    uint32_t                    bitarray_size);
/*
 *    Similar to skStringParseNumberList(), except that instead of
 *    returning an array, bits are set in the bitfield array
 *    'out_bitarray'.  'out_bitarray' should have been declared with
 *
 *        BITMAP_DECLARE('out_bitarray', 'bitarray_size').
 *
 *    The input may have values from 0 to (bitarray_size-1).
 */


uint8_t *skParseNumberList(
    const char *input,
    uint8_t    minValue,
    uint8_t    maxValue,
    uint8_t   *returnValueCount);
/*
 * skParseNumberList
 *
 *    DEPRECATED.  Use skStringParseNumberList() instead.
 */


int skStringParseIP(uint32_t *out_val, const char *ip_string);
/*
 *    Parses a C-string containing an IPv4 address or an integer and
 *    sets the value pointed to by 'out_val' to the result.  Leading
 *    and trailing whitespace will be ignored.
 *
 *    Returns a non-negative value and puts result into 'out_val' if
 *    parsing was successful.  A return value of 0 means that only the
 *    IPv4 address or integer and whitespace were present.  A positive
 *    return value indicates that a value was parsed, but that
 *    'ip_string' contains additional non-whitespace text.  The return
 *    value is the position in the 'ip_string' where this additional
 *    text begins.
 *
 *    Returns -1 if 'ip_string' was empty; returns -2 if it contained
 *    only whitespace; returns -3 if there was text that could not be
 *    parsed, if the octet values are too large, or if octets are
 *    missing.
 *
 *    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 skStringParseWildcardIP().
 */


int skIPStringToBitmap(uint32_t bitmap[4][8], const char *ip_string);
/*
 *    DEPRECATED.  Use skStringParseWildcardIP() instead.
 */


int skStringParseWildcardIP(
    skOctetMap_t   *octetmap,
    const char     *ip_string);
/*
 *    Takes a C-string containing an IPv4 address and fills the
 *    'octetmap' with the result.
 *
 *    Returns 0 and puts result into 'octetmap' if parsing was
 *    successful; returns 1 if 'ip_string' was empty; returns 2 if it
 *    contained only whitespace; returns -1 if there was text that
 *    could not be parsed.  Leading and trailing whitespace will be
 *    ignored.
 *
 *    The 'ip_string' can be in CIDR notation "1.2.3.0/24", in
 *    ordinary dotted decimal notation "1.2.3.4", an integer 16909056,
 *    an integer with a CIDR designation 16909056/24, or in SiLK
 *    wildcard notation: a dotted-quad with an 'x' respresenting an
 *    entire octet "1.2.3.x" (equivalent to "1.2.3.0/24"), or a dotted
 *    quad with lists or ranges in any or all octets "1.2,3.4,5.6,7"
 *    or "1.2.3.0-255".
 */


int skStringParseDatetime(
    struct timeval *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
 *    UNIX epoch seconds.  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 -1 and prints an message on an
 *    error; error contions include an empty string, malformed date,
 *    or extra text after the date.
 */


int skStringParseDatetimeRange(
    struct timeval *start,
    struct timeval *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 seconds value of the end date is set to LONG_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.
 *
 *    Note that skStringParseDatetimeRange() will return -1 if either
 *    date does not contain at least Day precision.
 *
 *    Returns -1 if the date found is unparsable, or if a dash is
 *    found, the date on either side is unparsable.
 *
 *    Returns 1 if two dates are found and parsed, but the end-date is
 *    earlier than the start_date.
 *
 *    Returns 0 if dates are parsed correctly.
 */


int skDatetimeCeiling(
    struct timeval         *ceiling_time,
    const struct timeval   *time_val,
    int                     precision);
/*
 *    Takes 'time_val' 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.
 *
 *    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.000000".
 *    Passing that value to skDatetimeCeiling() would result in the
 *    timestamp for "1990/12/25:05:59:59.999999".
 *
 *    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.000000"
 *    and "2004/12/26:03:59:59.999999".
 *
 *    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 index
 *    into 'int_string' of the first non-whitespace character
 *    following the successfully parsed number; e.g; "1 x" would set
 *    *result_val to 1 and return 3.
 *
 *    A negative return value signals an error: -1 if 'int_string' is
 *    NULL; -2 if it is empty or contained only whitespace; -3 if
 *    string is unparseable; -4 if value overflows the parser; -11 if
 *    value is less than 'min_val'; -12 is value is greater than
 *    'max_val'.
 */


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.
 */



/* options flags to pass to skStringParseHumanUint64() */
typedef enum {
    SK_HUMAN_NORMAL = 0,
    SK_HUMAN_LOWER_TRADITIONAL = 0,
    SK_HUMAN_UPPER_TRADITIONAL = 0,
    SK_HUMAN_LOWER_SI = 1,
    SK_HUMAN_UPPER_SI = 2,
    SK_HUMAN_MID_WS = 4,
    SK_HUMAN_MID_NO_WS = 0,
    SK_HUMAN_END_WS = 0,
    SK_HUMAN_END_NO_WS = 8
} skHumanFlags_t;

int skStringParseHumanUint64(
    uint64_t       *result_val,
    const char     *int_string,
    skHumanFlags_t  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.
 *
 *    A negative return value signals an error: -1 if 'int_string; is
 *    NULL; -2 if it is empty or contained only whitespace; -3 if
 *    string is unparseable; -4 if value overflows the parser; -5 if
 *    value underflows the parser; -6 if value is NAN.
 *
 *    parse_flags is made by or-ing flags from skHumanFlags_t together.
 *    These flags affect the parsing as follows:
 *    SK_HUMAN_NORMAL             use defaults
 *    SK_HUMAN_LOWER_TRADITIONAL  use 1024 instead of 1000 for k, etc.
 *    SK_HUMAN_UPPER_TRADITIONAL  use 1024 instead of 1000 for K, etc.
 *    SK_HUMAN_LOWER_SI           use 1000 instead of 1024 for k, etc.
 *    SK_HUMAN_UPPER_SI           use 1000 instead of 1024 for K, etc.
 *    SK_HUMAN_MID_WS             ignore white space between number & suffix
 *    SK_HUMAN_MID_NO_WS          don't parse white space betwn number & suffix
 *    SK_HUMAN_END_WS             parse & ignore white space after suffixn
 *    SK_HUMAN_END_NO_WS          do not parse white space after suffix
 */


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 index
 *    into 'dbl_string' of the first non-whitespace character
 *    following the successfully parsed number; e.g; "1.1 x" would set
 *    *result_val to 1.1 and return 5.
 *
 *    A negative return value signals an error: -1 if 'dbl_string' is
 *    NULL; -2 if it is empty or contained only whitespace; -3 if
 *    string is unparseable; -4 if value overflows the parser; -5 if
 *    value underflows the parser; -11 if value is less than
 *    'min_val'; -12 is value is greater than 'max_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 'flag_string' as a block of TCP flags.  Flag strings can
 *    only contain the following characters:
 *        F (FIN)
 *        S (SYN)
 *        R (RESET)
 *        P (PUSH)
 *        A (ACK)
 *        U (URGENT)
 *        E (ECE)
 *        C (CWR)
 *
 *    Returns 0 when 'flag_string' contains only TCP flag characters and
 *    whitespace.
 *
 *    When an unrecognized character is seen, parsing stops and the
 *    function returns the position (1-based) of the that character in
 *    'flag_string'---ie, returns the number of characters successfully
 *    parsed.
 *
 *    Assumes flag_string is a NULL-terminated string.  Overwrites the
 *    value of 'result'.
 */


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().  Any TCP flags
 *    not listed in 'mask' can have any value; flags listed 'high'
 *    must be set; flags listed in 'mask' but not in 'high' must be
 *    low.  It is an error if a flag is listed in 'high' but not in
 *    '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 the string is unparsable as high/mask pairs, returns -1.
 *
 *    If the high portion of the string contains a flag not found in
 *    the mask portion of the string, returns -1.
 *
 *    If successful, returns 0.
 *
 *    The inputs 'high' and 'mask' are overwritten with the bitmap of
 *    the flags set.
 */


/* Whether to support 8 bit TCP flags. */
#define TCP_8_BIT_FLAGS 1

/*
 * 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 */

#endif /* _UTILS_H */


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