/*
 * Copyright (c) 2003-2012
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 *
 * $Id: str.h 2586 2012-03-15 16:21:40Z brachman $
 */

/*****************************************************************************
 * COPYRIGHT AND PERMISSION NOTICE
 * 
 * Copyright (c) 2001-2003 The Queen in Right of Canada
 * 
 * All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, and/or sell
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, provided that the above copyright notice(s) and this
 * permission notice appear in all copies of the Software and that both the
 * above copyright notice(s) and this permission notice appear in supporting
 * documentation.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE 
 * BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
 * SOFTWARE.
 * 
 * Except as contained in this notice, the name of a copyright holder shall not
 * be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization of the
 * copyright holder.
 ***************************************************************************/

#ifndef _STR_H_
#define _STR_H_

#ifndef MAYBE_UNUSED
#define MAYBE_UNUSED	__attribute__ ((__unused__))
#endif

#include "dacs_config.h"

#include <ctype.h>
#include <regex.h>
#include <strings.h>
#include <stdio.h>

#include "mkargv.h"
#include "ds.h"

static inline MAYBE_UNUSED int
streq(const char *p, const char *q)
{

	return(strcmp(p, q) == 0);
}

static inline MAYBE_UNUSED int
strneq(const char *p, const char *q, size_t n)
{

	return(strncmp(p, q, n) == 0);
}

static inline MAYBE_UNUSED int
strcaseeq(const char *p, const char *q)
{

	return(strcasecmp(p, q) == 0);
}

static inline MAYBE_UNUSED int
strncaseeq(const char *p, const char *q, size_t n)
{

	return(strncasecmp(p, q, n) == 0);
}

/*
 * Erase a string (such as a plaintext password)
 * Make sure the function isn't optimized away because the string is not
 * read after it is written.
 * See msdn.microsoft.com/library/default.asp?url=/library/en-us/dncode/html/secure10102002.asp
 */
static MAYBE_UNUSED void
strzap(char *str)
{
  volatile char *p;

  if (str != NULL) {
	for (p = (volatile char *) str; *p != '\0'; p++)
	  *p = '\0';
  }
}

/*
 * If CH appears in STR, return its offset from the start of STR; otherwise,
 * return -1.
 * Since strchr(3) considers the terminating null character to be part
 * of the string, CH may be '\0'.
 */
static MAYBE_UNUSED int
strindex(char *str, int ch)
{
  char *p;

  if ((p = strchr(str, ch)) == NULL)
	return(-1);

  return(p - str);
}

#ifndef HAVE_STRNLEN
/*
 * Return the length of P, which may not be null-terminated, up
 * to a maximum of MAXLEN characters.
 */
static inline MAYBE_UNUSED size_t
strnlen(const char *p, size_t maxlen)
{
  char *endp;

  if ((endp = memchr(p, '\0', maxlen)) == NULL)
	return(maxlen);

  return((size_t) (endp - p));
}
#endif

#ifndef HAVE_STRNDUP
/*
 * Return a copy of P, up to a maximum of MAXLEN bytes.
 * That is, strlen() of the returned string will be the lessor of
 * strlen(p) and MAXLEN.
 * The returned string is always null-terminated.
 */
static inline MAYBE_UNUSED char *
strndup(const char *p, size_t maxlen)
{
  char *str;
  size_t len;

  len = strnlen(p, maxlen);

  str = (char *) malloc(len + 1);
  memcpy(str, p, len);
  str[len] = '\0';

  return(str);
}
#endif

static inline MAYBE_UNUSED int
is_octdigit(int ch)
{

  return(ch >= '0' && ch <= '7');
}

static inline MAYBE_UNUSED int
octdigit_val(int ch)
{

  return(ch - '0');
}

/* For strbtohex() */
#define STRBTOHEX_DEFAULT	0
#define STRBTOHEX_UPPER		(1 << 0)	/* Use upper case digits */
#define STRBTOHEX_NOZ		(1 << 1)	/* Suppress leading zero */

/* For strtr() */
typedef struct Strtr_io {
  int (*char_in)(void *);
  void *in_arg;
  int (*char_out)(int, void *);
  void *out_arg;
  char *errmsg;
} Strtr_io;

/* For strpfields() and strffields() */
typedef struct Strfields {
  Mkargv *conf;
  int argc;
  char **argv;
} Strfields;

#include <inttypes.h>

typedef enum {
#define STRNUM_I_TYPE			int
  STRNUM_I         = 1, STRNUM_INT   = 1,
  STRNUM_IGZ       = 2, STRNUM_INTGZ = 2,		/* Greater than Zero */
  STRNUM_INN       = 3, STRNUM_INTNN = 3,		/* Not Negative */
#define STRNUM_UI_TYPE			unsigned int
  STRNUM_UI        = 4, STRNUM_UINT  = 4,
#define STRNUM_UI_TYPE			unsigned int
  STRNUM_UINZ      = 5, STRNUM_UINTZ = 5,		/* Not Zero */
#define STRNUM_L_TYPE			long
  STRNUM_L         = 6, STRNUM_LONG  = 6,
#define STRNUM_UL_TYPE			unsigned long
  STRNUM_UL        = 7, STRNUM_ULONG = 7,
#define STRNUM_TIME_T_TYPE		time_t
  STRNUM_TIME_T    = 8,
#define STRNUM_MODE_T_TYPE		mode_t
  STRNUM_MODE_T    = 9,
#define STRNUM_PID_T_TYPE		pid_t
  STRNUM_PID_T     = 10,
#define STRNUM_IN_PORT_T_TYPE	in_port_t
  STRNUM_IN_PORT_T = 11,
#define STRNUM_STR_TYPE			char *
  STRNUM_STR       = 12,
#define STRNUM_SIZE_T_TYPE		size_t
  STRNUM_SIZE_T    = 13,
#define STRNUM_SSIZE_T_TYPE		ssize_t
  STRNUM_SSIZE_T   = 14,
#define STRNUM_LL_TYPE			long long
  STRNUM_LL        = 15, STRNUM_LONGLONG = 15,
#define STRNUM_ULL_TYPE	unsigned long long
  STRNUM_ULL       = 16, STRNUM_ULONGLONG = 16,
#define STRNUM_IMAX_T_TYPE		intmax_t
  STRNUM_IMAX_T    = 17, STRNUM_INTMAX_T  = 17,
#define STRNUM_UIMAX_T_TYPE		uintmax_t
  STRNUM_UIMAX_T   = 18, STRNUM_UINTMAX_T = 18,
  STRNUM_ERR       = -1
} Strnum;

typedef struct Strnum_tab {
  Strnum type;
  int size;
  char *name;
} Strnum_tab;

/* For strpack() and strunpack() */
typedef struct Strpack {
  Strnum type;
  void *ptr;
} Strpack;

/* For strsubst() */
typedef struct Strsubst {
  char *src_text;
  char *subst_text;
} Strsubst;

/* For is_strclass() */
enum {
  STRCLASS_ERROR         = 0,
  STRCLASS_LC            = (1 << 0),
  STRCLASS_UC            = (1 << 1),
  STRCLASS_ALPHA         = (STRCLASS_LC|STRCLASS_UC),
  STRCLASS_DECIMAL       = (1 << 2),
  STRCLASS_DIGITS        = STRCLASS_DECIMAL,
  STRCLASS_ALNUM         = (STRCLASS_ALPHA|STRCLASS_DECIMAL),
  STRCLASS_OCTAL         = (1 << 3),
  STRCLASS_HEX_UC        = (1 << 4),
  STRCLASS_HEX_LC        = (1 << 5),
  STRCLASS_HEX           = (STRCLASS_DECIMAL|STRCLASS_HEX_UC|STRCLASS_HEX_LC),
  STRCLASS_PUNCT         = (1 << 6),
  STRCLASS_HOSTNAME      = (1 << 7),
  STRCLASS_SPEC          = (1 << 8),
  STRCLASS_SIGNED_DIGITS = (1 << 9),
  STRCLASS_SPACE         = (1 << 10),
  STRCLASS_EOL           = (1 << 11),
  STRCLASS_PRINTABLE     = (STRCLASS_ALNUM|STRCLASS_PUNCT|STRCLASS_SPACE),
  STRCLASS_NUL           = (1 << 12),
  STRCLASS_STOPCH        = (1 << 13)
};

#define IS_STRCLASS(A, C)	((A & C) == C)

typedef struct Strtable {
  int ncols;
  int nrows;
  int align;
  int column_sep;
  Dsvec **columns;
} Strtable;

typedef struct Strtable_row_sort {
  int rownum;
  char *colval;
} Strtable_row_sort;

#ifdef __cplusplus
extern "C" {
#endif

extern int strnum(char *str, Strnum type, void *value);
extern int strnumx(char *str, Strnum type, void *value, char **endp);
extern int strnum_b(char *str, Strnum type, int base, void *value,
					char **endp);
extern Strnum_tab *strnum_lookup(char *name);
extern Strnum strnum_type(char *name);

extern char *strsuffix(char *p, size_t len, char *suffix);
extern char *strcasesuffix(const char *p, size_t len, const char *suffix);
extern char *strprefix(const char *p, const char *prefix);
extern char *strcaseprefix(const char *p, const char *prefix);
extern int strncaseprefix(char *prefix, char *word, size_t match_len);
extern Ds *strfold(char *str);
extern int is_digit_string(char *str);
extern int is_signed_digit_string(char *str);
extern int is_strclass(char *str, int allowable, ...);

extern unsigned int strba64(const unsigned char *inp,
							unsigned int nbytes, char **outp);
extern unsigned char *stra64b(const char *inp,
							  unsigned char **outp, unsigned int *nbytes);
extern unsigned int strba85(const unsigned char *inp, unsigned int nbytes,
							char **outp);
extern unsigned char *stra85b(const char *inp, unsigned char **outp,
							  unsigned int *nbytes);
extern unsigned char *strdec64(const char *inp);
extern char *strbenc64(const unsigned char *str, unsigned int len);
extern char *strenc64(char *str);

#ifndef HAVE_STRSEP
extern char *strsep(char **stringp, const char *delim);
#endif
extern int strchrcount(const char *p, int c);
extern int strchrscount(const char *p, const char *charset);
extern int strprintable(char *str, size_t nbytes, int allow_sp_ws);
extern int strcasecspn(const char *s1, const char *s2);

#ifndef HAVE_STRSTR
extern char *dacs_strstr(const char *str, const char *substr);
#define strstr dacs_strstr
#endif
extern char *strcasestr(const char *str, const char *substr);
extern char *strrstr(const char *str, const char *substr);
extern char *strrcasestr(const char *str, const char *substr);

extern char *strqs(const char *str, const char *substr);
extern char *strcaseqs(const char *str, const char *substr);
extern char *strqsx(const char *str, const char *endp, const char *substr,
					unsigned int *td_one, size_t plen, int nocase);
extern unsigned int *strqs_init(int *td_one, const char *pattern,
								size_t pattern_len, int nocase);
extern char *strpack(Strpack *desc, const char *delimit);
extern int strunpack(const char *str, const char *delimit, int limit,
					 Strpack *desc);

extern void memzap(void *s, size_t len);
extern void memzapb(void *s, int val, size_t len);
extern void *memdupn(void *, size_t len);

extern void envzap(char *name);
extern char *env_parse(char *env_string, char **env_name, char **env_val);
extern char *strcpyn(char *dst, const char *src, size_t n);
extern char *strtolower(char *);
extern char *strtoupper(char *);
extern char *strquote(char *str, char *qchars);
extern char *strdequote(char *p);
extern char *strextract(char *str, char *start_q, char *end_q);
extern char *strtrim(char *str, char *trim_chars, int limit);
extern Dsvec *strsplit(const char *str, const char *delim, int limit);
extern Dsvec *strsplitd(const char *str, const char *delimit, int limit,
						int inc_delimit);
extern Dsvec *strsplit_nocopy(char *str, const char *delim, int limit);
extern Dsvec *strsplit_re(const char *str, const char *regex, int limit,
						  char **errmsg);
extern char *strjoin_subset(Dsvec *dsv, unsigned int start, int len,
							char *sepstr);
extern char *strjoin(Dsvec *dsv, char *sepstr);
extern Dsvec *strpathparse(const char *path, int *is_abs, int *trailing);

extern Ds *struncescape(char *str);
extern char *strcescape(char *str, size_t slen);
extern Strfields *strpfields(const char *str, Strfields *fields);
extern char *strffields(const char *fmt, Strfields *spec, ...);
extern char *strregexsub(char *src, char *regex, char *repl, int cflags,
						 int repeat, char **errmsg);
extern int strmatch(char *src, char *regex);
extern int strregex(char *src, char *regex, regex_t **preg_in, int cflags,
					Dsvec *matches, char **errmsg);
extern char *strbasename(char *pathname, char *suffix);
extern char *strdirname(char *pathname);
extern char *strextname(char *pathname);
extern unsigned char *strhextob(char *str, unsigned int *lenp);
extern char *strbtohex(unsigned char *buf, size_t len, int flags);
extern Ds *strsubst(char *str, Strsubst *tab);

extern char *strchrdup(const char *s, int stop_ch, char **endp);
extern char *strcspndup(const char *s, const char *charset, char **endp);

extern char *strfmt(const char *, const char *, size_t);

extern Ds *strbtoutf16le(unsigned char *buf, size_t nbytes);

extern Strtable *strtable_init(int ncols, int column_sep, int align);
extern void strtable_add_row(Strtable *st, ...);
extern Dsvec *strtable_sort(Strtable *st, int col,
							int (*compar)(const void *, const void *));
extern void strtable_format(FILE *fp_out, Strtable *st, Dsvec *dsv_sorted);
extern void strtable_free(Strtable *st);

extern DACS_ui32 strhash32(unsigned char *str, size_t slen);
extern DACS_ui64 strhash64(unsigned char *str, size_t slen);

extern int hexpair2int(char *pair);

#ifndef HAVE_ISBLANK
extern int isblank(int);
#endif
  
/* In strtr.c */
extern int strtr_io(char *string1, char *string2, int cflag, int dflag,
					int sflag, Strtr_io *io);
extern int strtr(char *input, char *string1, char *string2, int cflag,
				 int dflag, int sflag, char **tr_string);
extern int strtr_char(int ch, char *string1, int cflag);

#ifdef __cplusplus
}
#endif

#endif
