/*********************** mic.h ****************************/
/* file da includere per usare le funzioni della libreria */
/* libmic.a (aix)                                         */
/* mic.lib  (dos,os2)                                     */
/**********************************************************/
#ifndef _MIC
#define _MIC

#ifdef TRUE_AIX
#define	OS	'A'
#define _LARGE_FILES
#endif
#ifdef TRUE_LNX
#define	OS	'L'
#define _LARGEFILE_SOURCE
#define _FILE_OFFSET_BITS       64
#endif
#ifdef TRUE_SUN
#define	OS	'S'
#define _LARGEFILE_SOURCE
#define _FILE_OFFSET_BITS       64
#endif
#ifdef TRUE_SGI
#define	OS	'I'
#endif
#ifdef TRUE_HP
#define	OS	'H'
#define _LARGEFILE_SOURCE
#define _FILE_OFFSET_BITS       64
#define __STDC_EXT__
#endif
#ifdef TRUE_W32
#define	OS	'W'
#endif
#ifdef TRUE_MAC
#define	OS	'M'
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <limits.h>
#include <signal.h>
#include <errno.h>
#include <dirent.h>
#ifdef _TC
  #include <fcntl.h>
  #include <io.h>
  #include <dos.h>
#include <sys\stat.h>
  #define PATH_SEPS	"\\"
  #define PATH_SEP	'\\'
  #define PATH_DELIM	';'
  #define PATH_DELIMS	";"
  #define lstat stat
#endif
#ifdef _OS2
  #define INCL_DOSFILEMGR
  #include <os2.h>
  #define PATH_SEPS	"\\"
  #define PATH_SEP	'\\'
  #define PATH_DELIM	';'
  #define PATH_DELIMS	";"
  #define isatty  _isatty
  #define access  _access
  #define umask   _umask
  #define chmod   _chmod
  #define lstat   stat
#endif
#ifdef _AIX
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/utsname.h>
#define min(x,y) ((x)<(y) ? (x) : (y))
#define max(x,y) ((x)>(y) ? (x) : (y))
#define PATH_SEPS	"/"
#define PATH_SEP	'/'
#define PATH_DELIM	':'
#define PATH_DELIMS	":"
  #ifndef TRUE_W32
  #define O_BINARY	0
  #endif
  #ifdef TRUE_AIX
  #define unsetenv env_unset
  #endif
#ifdef TRUE_SUN
#include <arpa/nameser_compat.h>
#define unsetenv env_unset
#endif
#ifdef TRUE_HP
#define setegid(x) setregid(-1,x)
#define seteuid(x) setreuid(-1,x)
#define unsetenv env_unset
#endif
#ifdef TRUE_W32
#include <locale.h>
#endif
#endif
/******************** MACRO ********************/
#define SWAP(a,b)	a^=b^=a^=b
#define MIN(a,b)	((a)<(b))?(a):(b)
#define MAX(a,b)	((a)>(b))?(a):(b)
#define PUSH(top,k)	*top++=k
#define POP(top)	*--top
#define ONTOP(top)	*(top-1)
/******************** CONST ********************/
#define then
#define true    1
#define false   0
#define EOLN   '\n'
#define MAXINT 0x7FFFFFFF
/******************** TYPES ********************/
#include <stdint.h>
#if INTPTR_MAX == INT64_MAX
  typedef unsigned long long	u__;
  typedef signed long long	i__;
#elif INTPTR_MAX == INT32_MAX
  typedef unsigned long		u__;
  typedef signed long		i__;
#endif
  typedef unsigned char 	u8;
  typedef unsigned short 	u16;
  typedef unsigned int		u32;
  typedef unsigned long long	u64;
  typedef signed char 		i8;
  typedef signed short		i16;
  typedef signed int		i32;
  typedef signed long long	i64;
  typedef long long int		llint;
  typedef char			bool;
  typedef unsigned char		boolean;
  typedef unsigned char		byte;
  typedef unsigned short	word;
  typedef unsigned int		longword;
  typedef word			SOC[16];
  typedef
    struct
    {
      word len;
      byte *mem;
    }				Lstring;
  typedef
    struct XY {
      int	x,y;
    }	*			xy;
/******************** variable length strings */
  typedef
    struct VLS {
      byte	*s;
      longword	l,z;
    }	*			vls;
/******************** linked lists */
  typedef
    struct LL
    {
      void	*info;
      struct LL	*next;
    }	*			ll;
/******************** binary trees and double linked lists	*/
/* same structure, multiple use					*/
  typedef
    struct BT {
      int	ikey;
      vls	vkey;
      void	*info;
      struct BT	*l, *r;
      int	depth;
    }	*			bt;
/******************** FSA: Finite State Automata */
#define Special_any_char 256
#define Special_null_set 257
#define Special_null_str 258
#define Special_any_str  299
#define LINK    true
#define NOLINK  false
  typedef
    struct C
    {
      word Key;					/* 0..255 char, >Special_code */
      byte *InfoPtr;				/* informazione associata */
      struct C *Sub,*Next;
    }				CharList;
  typedef CharList*		Automa;
/******************** pairs */
  typedef
    struct PAIR {
      byte	*x, *y;
    }	*			pair;
/******************** ordered integer list */
  typedef
    struct OIL {
      int	*ikey;
      void	**info;
      u32	l,z,gr;
    }	*			oil;

/******************** standard replacements */
#ifdef TRUE_AIX
double round(double x);
int lround(double x);
#endif
bool isdig(byte x);		/* replacement of isdigit()		*/
bool isxdig(byte x);		/* replacement of isxdigit()		*/
byte locase(byte c);		/* replacement of tolower()		*/
byte upcase(byte c);		/* replacement of toupper()		*/
/******************** memory blocks */
byte *toUp(byte *m, int l);
/* convert m, l bytes long, to uppercase	*/
/* return a reference to a uppercase copy of m	*/
byte *memlocase(byte *m, int l);/* convert m to lowercase in place	*/
int mem_cmp(byte *x, int lx, byte *y, int ly); /* mem compare: if x<y rc=-1; if x==y rc=0; if x>y rc=1 */
byte *seek_eosoc(byte *s, int l);
/* return first not escaped occurrence of ']' in s, l bytes long	*/
/* or NULL if not found							*/
byte *seek_matching(byte *s, int l);
/* return nested matching closing parenthesis in s, l bytes long	*/
/* skip escaped chars and set of chars [....]				*/
/* or NULL if not found							*/
/******************** strings */
bool ispfx(byte *p, byte *s);	/* true if p is prefix of s		*/
bool iswhole(byte *s);		/* true if all chars in s are digits	*/
bool isNumber(byte *s);		/* true if s is a number in the form [space]*[+|-][0-9]*.[0-9]*/
int str_cmp(byte *x, byte *y); /* string compare: if x<y rc=-1; if x==y rc=0; if x>y rc=1 */
int declen(u64 x);		/* lenght of decimal representation of x */
longword vls_setgr(byte x);
/* set memory allocation granularity for vls_new, vls_resize */
/* gr=2**x, default x=6 gr=64 */
/* return previous value */
vls vls_new3(byte *m, longword ml, longword size);
/* create new vls */
/* if size<=ml the lower multiple of gr will be used */
/* initialize with m (can be NULL), ml bytes long */
vls vls_new2(byte *m, longword ml);
/* create a new vls, ml+1 bytes long */
/* initialize with m (can be NULL) */
vls vls_dup(vls x);
/* create new vls, initialize with x) */
vls vls_new(byte *s);
/* create new vls, initialize with s (can be NULL) */
vls vls_free(vls s);
/* free variable length string s, return NULL */
byte *vls_resize(vls s, longword new_l);
/* adjust variable lenght string s size in order to contain new_l chars*/
byte *vls_truncate(vls s, int skip);
/* cut s at skip position */
byte *vls_setm(vls s, byte *m, int ml);
/* assign m, ml bytes long, to variable length string s */
byte *vls_sets(vls s, byte *y);
/* assign y (can be NULL) to variable length string s */
byte *vls_setv(vls dest, vls source);
/* copy source to dest */
byte *vls_addm(vls s, byte *m, longword ml);
/* concatenate y to variable length string s */
byte *vls_adds(vls s, byte *y);
/* concatenate y to variable length string s */
byte *vls_addv(vls s, vls x);
byte *vls_addc(vls s, byte ch);
/* add a single char to variable length string s */
byte *vls_addss(vls x, ...);
/* add a NULL terminated list of strings to vls x */
byte *vls_subc(vls s);
/* remove a single char from vls tail */
byte *vls_rtrim(vls s);
/* remove trailing spaces from s */
byte *vls_insm(vls s, int skip, byte *y, int yl);
/* insert string y, yl bytes long, into variable length string s */
byte *vls_insert(vls s, int skip, byte *y);
/* insert y into x at skip pos */
/* negative skip refers to string end */
byte *vls_delete(vls s, int skip, longword n);
/* delete n bytes from variable length string s, starting from skip pos */
/* negative skip refers to string end */
byte *vls_sandrm(vls s, byte *x, int xlen, byte *y, int ylen);
/* search and replace x, xlen bytes long, with y, ylen bytes long, in s */
byte *vls_sandr(vls s, byte *x, byte *y);
/* search and replace x with y in s */
byte *vls_prefix_sandrm(vls s, byte *x, int xlen, byte *y, int ylen);
/* replace x, xlen bytes long, with y, ylen bytes long in s */
/* if s contains x as prefix */
byte *vls_prefix_sandr(vls s, byte *x, byte *y);
/* replace x with y in s, if s contains x as prefix */
byte *vls_fdload(vls s, int fd);
/* load file fd into s */
byte *vls_fload(vls s, FILE *r);
/* load file r into s */
byte *vls_fwrite(vls s, FILE *w);
/* write variable string length s to file w */
byte *vls_fread(vls s, FILE *r);
/* read variable string length s from file r */
byte *vls_getcwd(vls s);
/* get current working dir into variable length string s */
/* if s is NULL a pointer to an internal buffer is returned */
byte *vls_readln(vls s, FILE *f);
/* read from file f a single line terminated by \n or EOF */
/* return string or NULL if no chars where read */
/* if s is NULL an internal permanent storage will be used */
byte *vls_read0(vls s, FILE *f);
/* read from file f a single line terminated by \0 or EOF */
/* return string or NULL if no chars where read */
byte *vls_readupto(vls s, FILE *f, byte term);
/* read from file f a single line terminated term or EOF */
/* return string or NULL if no chars where read */
byte *vls_write(vls s, FILE *f);
/* write s to file f */
byte *vls_writeln(vls s, FILE *f);
/* write s followed by a new line to file f */
byte *vls_inc(vls s);
byte *vls_dec(vls s);
byte *vls_fdread(vls s, int fd);
byte *vls_fdwrite(vls s, int fd);
byte *vls_encrypt(vls s, longword k); /* encrypt a vls in place */
byte *vls_decrypt(vls s, longword k); /* decrypt a vls in place */

/******************** numbers */
int imax(int x, int y);		/* integer max */
int imin(int x, int y);		/* integer min */
int sign(int x);		/* rc=1 if x>0, rc=-1 if x<0, rc=0 if x=0 */
int is_prime(u64 n);		/* true if n is a prime number */
/******************** time */
u64 ss1970(struct timeval *tv);	/* time from epoch in seconds		*/
u64 millisec(void);		/* time from epoch in milliseconds	*/
double tv_2double(struct timeval t); /* convert timeval to double	*/
double tv_delta(struct timeval *result, struct timeval beg, struct timeval end); /* compute time between start and stop, put it into result if not NULL */
double tv_incr(struct timeval *result, struct timeval t); /* add t to result */
double tv_add(struct timeval *result, struct timeval t1, struct timeval t2); /* compute t1+t2, put it into result if not NULL */
byte *tv_dhms(struct timeval tv, byte dec); /* return a static string with tv formatted as __d__h__m__[.dec]s,  dec is the number of decimals for seconds 0..6 */
byte *sec2days_hh_mm_ss(longword sec);	/* return a static string in [days-][hh:][mm:]ss format */
byte *sec2hhmmss(longword sec);		/* return a static string in [__d][__h][__m]__s format */
byte *sec2HHMMSS(int x);		/* return a static string in HH:MM SS format */
u32 wdhms(byte *x);			/* compute _w_d_h_m_s to seconds*/
/******************** timers */
struct timeval *startimer(void);	/* start a new timer		*/
double laptimer(struct timeval *tv_start); /* read timer value	*/
double stoptimer(void);		/* stop last started timer (tv_2double)	*/
byte *elapsedtimer(byte dec);	/* stop last started timer (tv_dhms)	*/
/******************** files */
void binary_stdin(void); /* set stdin in O_BINARY mode */
void binary_stdout(void); /* set stdout in O_BINARY mode */
void binary_stderr(void); /* set stderr in O_BINARY mode */
bool isopen(int fd); /* return true if file descriptor 'fd' is open */
llint FileSize(const byte *filename); /* -1 se il file non esiste */
llint objsize(vls fn);
/* return the size of a given filesystem object */
/* recursively descend subdirectories		*/
bool exist (const byte *filename); /* true if filename exist*/
bool isreg (const byte *filename); /* true if filename is a regular file */
bool isdir (const byte *filename); /* true if filename is a directory */
byte *symlnref(byte *p); /* return (new) value of symbolic link p, or NULL */
int eclassify(struct stat inode);
/* relation between effective uid and inode 'inode' */
/* rc= 0:owner 1:group 2:other */
boolean isexe(byte *fn); /* check if file 'fn' is executable */
boolean isinpath(byte *fn); /* search fn in path and return true if it's executable */

/******************** system calls */
void msleep(int ms);		/* sleep for ms milliseconds		*/
int mkdir_p(byte *pathname); /* create a path by calling mkdir for each path element */
int chown_r(vls pn, uid_t owner, gid_t group); /* recursive chown */
int rm_r(vls pathname); /* recursively remove a directory */
vls mktmpdir(byte *pname); /* create /tmp/$pname.$$ and remove when program ends */
int remove_chain(byte *pathname); /* remove a symlink and the file it refers to */

/******************** signal handling */
void no_int(bool block);	/* block signals, restore previous mask if block=false */
void inst_signal_handler(int signum, void (*handler)(int));
/******************** access control lists*/
bool ACL_read(vls a, byte *pathname); /* get ACL for pathname, true if ACL are enabled */
bool ACL_write(vls a, byte *pathname); /* set ACL for pathname, true if successfull */

ll ll_new(void *dato, ll r);
/* create a new LL node (dato,r) */
ll ll_dup(ll A);
/* return a copy of A */
ll ll_cat(ll A, ll B);
/* concatenate two lists, return A+B */
/* return *A			*/
void *ll_push(ll *A, void *dato);
/* PUSH dato sulla pila, crea un nuovo record in testa		*/
/* return dato */
void *ll_append(ll *A, void *dato);
/* appende un elemento ad una pila				*/
/* return dato */
void *ll_pop(ll *A);
/* POP dato dalla lista, cancella il primo record		*/
/* restituisce il dato memorizzato				*/
ll ll_free(ll A);
/* free all elements from stack A */
/* return NULL */
ll ll_findstr(ll A, byte *s);
/* return the node containing string 's' as info or NULL	*/
longword ll_len(ll A);
/* number of stacked elements */
ll ll_reverse(ll *B);
/* Inverte l'ordine di accesso dei dati sulla lista		*/
/* return il nuovo puntatore alla testa				*/
void *ll_popref(ll *A, void *p);
/* esegue il POP del primo elemento con un certo indirizzo	*/
/* restituisce il puntatore al dato associato o NULL */

int bt2dll(bt B);
/* convert in place a binary tree to a double linked list */
bt dll2bt4(bt B, int first, int last, int curr);
bt dll2bt(bt B);
/* convert in place a double linked list to a binary tree */
bt bt_balance(bt B);
/* balance binary tree B, return the new root */
int bt_save(bt B, FILE *w);
bt bt_load(FILE *r);

/******************** binary tree */ 
bt bt_new(int i, vls v, void *d); /* create a new node, initialize it with i,v,d		*/
bt bt_newnode(int i, byte *m, int l, void *d); /* create a new node, malloc vkey using (m,l) */
bt bt_free(bt B); /* free all nodes and associated vls in binary tree B, return NULL */
int bt_len(bt B);	/* return the number of nodes of binary tree B */
int bt_depth(bt B);	/* return the depth of binary tree B */
int avl_lever(bt B); /* AVL rebalancing needed? rc=-1 left, rc=1 right */
void avl_setDepth(bt B, bool recurse); /* compute AVL tree node depth */
bt avl_lrot(bt x);	/* AVL left rotate */
bt avl_rrot(bt y);	/* AVL right rotate */
int bt_nodes(ll *P, bt B);
/* create a sorted list of references to nodes */
/* return the number of nodes	*/
int bt_cursor(ll *P, bt B);
/* create a sorted list of nodes info */
/* return the number of nodes   */
int bt_keys(ll *P, bt B);
/* create a sorted list of references to (byte *) vkeys */
/* return the number of nodes   */
int bt_for(bt B, int (*f)(bt)); /* run function f for each node of binary tree B	*/
int bt_print(bt B); /* print to stdout all nodes, cast info to str */

/******************** binary tree with integer key */ 
bt bti_insert(bt *B, int k, vls v, void *d); /* return node with ikey==k, create a new one if not exist, init new node with k,v,d, no malloc */
bt bti_search(bt B, int k); /* search a node with key k in binary tree B */

/******************** binary tree with VLS key */ 
bt btv_insert(bt *B, int i, vls k, void *d); /* return node with vkey==k, create a new one if not exist, init new node with i,k,d, no malloc                  */
bt btv_insv(bt *B, int i, vls k, void *d);
bt btv_insm(bt *B, int i, byte *k, int l, void *d);
bt btv_inss(bt *B, int i, byte *k, void *d);
/* return node with vkey==k, create a new one if not exist, malloc */
bt btv_search(bt B, vls k); /* search a node with key k in binary tree B */
bt btv_searchm(bt B, byte *k, int l); /* search a node with key k in binary tree B */
bt btv_searchs(bt B, byte *k); /* search a node with key k in binary tree B */
bt btnum_insv(bt *B, int i, vls k, void *d);
bt btts_insv(byte *template, bt *B, int i, vls k, void *d);

/******************** double linked lists */
bt dll_push(bt *B, int i, vls v, void *d);
bt dll_append(bt *B, int i, vls v, void *d);
int dll_len(bt B);

bt dllv_insv(bt *B, int i, vls k, void *d);
/* return node with vkey==k, create a new one if not exist */
bt dllv_insm(bt *B, int i, byte *k, int l, void *d);
bt dllv_inss(bt *B, int i, byte *k, void *d);
bt dll_seek_first(bt B);
bt dll_seek_last(bt B);
bt dll_seek_rel(bt B, int offset);
bt dll_seek_vkey(bt B, byte *k);/* return node with vkey==k or NULL */
bt dll_seek_ikey(bt B, int k);	/* return node with ikey==k or NULL */
int dll_offset(bt B);
bt dll_pop(bt *B);
bt dll_free(bt B);
bt dlli_insm(bt *B, int k, byte *m, int l, void *d);
/* return node with ikey==k, create a new one if not exist */
bt dllts_insv(byte *template, bt *B, int i, vls k, void *d);
bt dllts_insm(byte *template, bt *B, int i, byte *k, int l, void *d);
bt dllts_inss(byte *template, bt *B, int i, byte *k, void *d);
bt dllnum_insv(bt *B, int i, vls k, void *d);
bt dllnum_insm(bt *B, int i, byte *k, int l, void *d);
bt dllnum_inss(bt *B, int i, byte *k, void *d);

int dlli_bubblesort(bt B);
/* sort by ikey dll B */
int dlli_bubblerevsort(bt B);
/* reverse sort by ikey dll B */
int dll_reverse(bt B);
/* inverte l'ordine di scorrimento di una dll */
/* restituisce il numero di elementi nella lista */

/* search a key into B, return node with key==k or NULL*/
bt dllv_search(bt B, vls k);
bt dlli_search(bt B, int k);
/* search/add a key to B, return node with key==k */
bt dllv_insert(bt *B, int i, vls k, void *d);
bt dlli_insert(bt *B, int k, vls v, void *d);

Automa cl_new(word k, Automa n); /* create a new node */
Automa cl_add(Automa *B, word k); /* search/insert key in a CharList */
Automa cl_seek(Automa A, word w); /* return CharList element with Key w, or NULL */
Automa cl_dup(Automa S); /* return a duplicate of a CharList */
int cl_nlinks(Automa A, Automa L);
/* return the number of elements in A pointing to L */
ll a_walk1 (Automa A, byte c);
/* start a new walk */
/* return a list of pointers for nextstep	*/
ll a_walk2 (ll L, byte c);
/* continue a started walk */
ll a_walk(Automa A, byte *s, int l);
Automa FreeAutoma(Automa Base, bool destroyptr);
/* distrugge un Automa */
/* free di tutti in nodi di un Automa, tiene conto di eventuali link */
/* se 'destroyinfo' viene fatta la free anche dell'informazione associata al nodo */
/* ritorna NULL */

/******************** Key Value DB*/
Automa kvadd(Automa *A, byte *k, int l);
/* search/insert key k, l bytes long, in A	*/
/* return node					*/
byte *kvset(Automa *A, byte *k, int l, byte *v);
/* associate in A value v to key k, l bytes long */
/* return old v	*/
byte *kvunset(Automa *A, byte *k, int l);
/* associate in A NULL to key k, l bytes long */
/* return old v	*/
Automa kvref(Automa A, byte *k, int l);
/* search key k, l bytes long, in A	*/
/* return node if any, or NULL		*/
byte *kvalue(Automa A, byte *k, int l);
/* search key k, l bytes long, in A			*/
/* return value associated to k or NULL if not there	*/
ll kvls(Automa A);
/* build and return a list of (key,value) pairs	*/
/* keys are new strings, values are string references */
int kv2sv(Automa Xb, char **sv, vls k);
/* fill sv with all "key=value" */
/* return the number of sv elements assigned */

/******************** Regular Expressions */
bt ree_new(byte *s, int l, bool cs);
/* build and return a new RE expression from s, l bytes long		*/
/* operators: &=and |=or !=not ~=ci `=cs ()=subexpression		*/
/* priority from higher to lower: () ` ~ ! & |				*/
bool ree_eval(bt ree, byte *s);
/* true if string s matches RE expression ree		*/
bt ree_free(bt ree);
/* free a RE expression tree, return NULL		*/
Automa Re2Automa(byte *re, int l, byte *eqP);
/* return a new Automa matching regular expression re, l bytes long	*/
/* special chars: * ? [set] \spec					*/
Automa Re2Automa_ci(byte *re, int l, byte *eqP);
/* return a new Automa matching regular expression re, l bytes long	*/
/* case insensitive							*/
/* special chars: * ? [set] \spec					*/
int a_merge(Automa *rc, byte *re, int l, byte *eqP, bool cs);
/* merge regular expression re, l bytes long, to rc	*/
/* case sensitive if cs is true				*/
Automa mem2Automa(byte *s, int l, byte *eqP, bool cs);
/* return a new Automa matching string s, l bytes long  */
byte *a_match (Automa A, byte *s, int l);
/* return info associated to s, l bytes long, or NULL   */
/* case sensitive if cs is true				*/
int a_count(Automa Xb, vls k);
/* count and return the number of end-nodes in Xb */
byte *Match(Automa A, byte *SearchString);
/* Ricerca nell'automa A la stringa S */
/* ritorna l'informazione associata ad S in A oppure */
/*   NULL   --> stringa non riconosciuta */
bool match_re(byte *re, byte *s);
/* return true if string s matches regular expression re */
bool match_re_ll(byte *re, ll P);
/* return true if at least one string in P matches re */
bool match_ere(byte *ere, byte *s);
/* return true if string s matches regular expression re */
/* ere is a list of re separated by char '|' */
bool match_ere_eq(byte *ere, byte *s, byte *eq);
/* return true if s matches one of re of ere */
/* or if re is '=' and s=eq */
byte *A_mmatch(ll MRE, byte *SearchString);
/* search a string in a Multi Regular Expression */
/* returns associated info or NULL if not present */
int winmatch(byte *pattern, byte *str);
/* return TRUE if windows pattern matches str	*/
/* the only metachrs are '*' and '?'		*/

Automa SearchList(Automa A, byte C);
/* Ricerca nella lista semplice puntata da Automa */
/* restituisce NULL se il carattere 'C' non Š presente nella lista */
/* altrimenti restituisce il puntatore all'elemento della lista che */
/* ha come chiave associata 'C' */
byte *A_memsearch(Automa A, byte *M, int l);
/* search string 'M', l bytes long, in 'A'        */
/* returns associated info or NULL if not present */
byte *A_strsearch(Automa A, byte *S);
/* search null term string 'S', in 'A'            */
/* returns associated info or NULL if not present */

int Add_Re (Automa *A, byte *Re, int l, byte *Eq, bool link);
/* inserisce una espressione regolare in un Automa */
/* Aggiunge all'automa di riconoscimento 'A' l'espressione regolare 'RE' */
/* lunga l bytes, associandogli il puntatore Eq                      */
/*   A       --> automa nel quale inserire RE                        */
/*   Re      --> espressione regolare da inserire (lunga l bytes)    */
/*   Eq      --> informazione da associare a RE                      */
/*   link    --> se true i livelli vengono linkati e non copiati     */
/* ritorna: */
/*   0  --> tutto ok */
/*   1  --> rami precedenti resi irraggiungibili */
/*   2  --> ramo inserito ma irraggiungibile     */
/**/
/* grammatica per RE */
/* re      ::= <char><re> | *<re> | ?<re> | [set]<re> | (void)   */
/* set     ::= <set_item> | <set_item>,<set> | (void)            */
/* set_item::= <item> | -<item> | !<item> | (void)               */
/* item    ::= <char><item> | <char>-<char>item |                */
/**/
/* Caratteri speciali in RE */
/* *        any char sequence      */
/* ?        any single char        */
/* [set]    un carattere nell'insieme (cfr. function mem2soc())  */
/* \        skip next special char (* ? [ \)                     */
bool Add_Mem (Automa *A, byte *s, int l, byte *Eq);
/* inserisce la stringa 's' lunga 'l' bytes nell'automa A e gli associa Eq */
/* A        --> Automa nel quale inserire                */
/* s        --> stringa da inserire  (lunga l bytes)     */
/* Eq       --> stringa da associare                     */
/* rc   0=ok    1=ricopertura */
bool Add_Str (Automa *A, byte *s, byte *Eq);
/* inserisce una stringa (null-term) in un Automa */
/* inserisce la stringa S nell'automa A e gli associa Eq */
/* A        --> Automa nel quale inserire                */
/* s        --> stringa da inserire  (null terminated)   */
/* Eq       --> stringa da associare                     */
/* rc   0=ok    1=ricopertura */
Automa Add_Elem (Automa *A, word W, byte *EqP);
/* inserisce un elemento in una lista (Automa) */
/* l'elemento 'W' viene inserito nella lista puntata da 'A' e ad esso */
/* viene associata l'informazione 'EqP' */
/* se l'elemento era gi… presente nella lista la precedente informazione */
/* associata 'EqP' viene sostituita con la nuova */
/**/
/* restituisce il puntatore all'elemento creato/trovato */
void Scandisci (Automa Xb, word RecLevel);
/* dump su stderr di un Automa */
/* genera su stderr tutte le associazioni RE -> Info */
/* contenute nell'automa Xb */
/* Il parametro RecLevel deve essere sempre passato a 0 */
void Visita (Automa Xb, word RecLevel);
/* dump su stderr di un Automa */
/* genera su stderr tutte le associazioni RE -> Info */
/* contenute nell'automa Xb */
/* Il parametro RecLevel deve essere sempre passato a 0 */

pair pair_new(byte *n, byte *p);
pair pair_find(ll X, byte *n, byte *p);
pair pair_free(pair p);

/******************** oneway crypto */
longword NextSeed(longword Seed);
/* genera un nuovo numero pseudocasuale */
longword memcyp (byte *s, int l);
/* crittografia a senso unico */
/* calcola un codice a partire dai primi l byte della stringa s */
longword cyp (byte *s);
/* crittografia a senso unico */
/* null term s */

/******************** XOR bidirectional crypto */
byte *memkc(byte *m, int ml, longword key, byte nbits);
/* encode/decode memory block m, l bytes long, using key+nbits */
/* nbits slightly change algorithm, must vary in 1..24 range */

/******************** DES: data encryption standard */
#define KEYLEN  776
void InitKey (byte *Key, const byte *chiave);
/* inizializza una chiave per il Des */
/*   La funzione InitKey Inizializza le chiavi che il DES utilizzera` */
/*   per codificare/decodificare il messaggio. La chiave passata come */
/*   parametro viene usata per i primi 8 bytes (64 bit). Il parametro */
/*   Key deve essere di almeno 16*48+8= 768+8 = 776 = KEYLEN bytes */
void Des (byte *block, const byte *Key, bool DecodeFlag);
/* cifra/decifra un blocco di dati */
/* block     : array di 8 caratteri, viene sovrascritto */
/* Key       : la chiave, inizializzata con InitKey, usata cifrare/decodificare */
/* DecodeFlag: True --> decodifica; False --> codifica) */

FILE *fopenlck(const char *path, const char *mode);
/* open a file and place an advisory lock */

/******************** input */
int fdread(int fd, byte *m, int l);
/* read from file descriptor fd at most l bytes, store them into m */
byte *readln(FILE *f);
/* read from file f a single line terminated by \n or EOF */
/* return a static string or NULL if no chars where read*/
byte *fgettoken(FILE *f);
/* legge un token da un stream */
/* legge il prossimo token dal file f         */
/*   salta tutti gli spazi iniziali           */
/*   se il token inizia con "'` cerca il corrispondente */
/*   se il token inizia con # cerca il fine riga        */
/*   restituisce un puntatore ad una zona     */
/*   statica contenente la stringa finale     */
/*   o NULL se fine file                      */
longword fgetw (FILE *ifile);
/* legge un long da un file */
/* legge da ifile 2 byte di x, dal pi— significativo al meno */
longword fgetl (FILE *ifile);
/* legge un long da un file */
/* legge da ifile i 4 byte di x, dal pi— significativo al meno */
llint fgetll (FILE *ifile);
/* legge da ifile gli 8 byte di x */
byte *Rline(byte *buffer, int maxb, FILE *r);
/* reads a line from 'r'. A line is terminated by '\n' or EOF      */
/* terminates if EOLN has not been encountered and maxb characters */
/* had been read */
/* returns buffer if at least one char has been read, NULL otherwise */

/******************** output */
int fdwrite(int fd, byte *m, int l);
/* write m, l bytes long, to file descriptor fd */
void fputw (longword x, FILE *ofile);
/* scrive un long su un file */
/* scrive su ofile 2 byte di x, dal pi— significativo al meno */
void fputl (longword x, FILE *ofile);
/* scrive un long su un file */
/* scrive su ofile i 4 byte di x, dal pi— significativo al meno */
void fputll (llint x, FILE *ofile);
/* scrive su ofile gli 8 byte di x, dal pi— significativo al meno */
int fputm (byte *m, int l, FILE *w);	/* write l bytes to file w 	*/
int putm(byte *m, int l);		/* write l bytes to stdout 	*/
int fputv (vls v, FILE *w);		/* write vls to file w		*/
int putv (vls v);			/* write vls to stdout		*/
int putb (byte *s);			/* write s to stdout		*/
byte *fhexdump(byte *s, int l, FILE *outfile);
/* dump in hex di una stringa */
/* scrive su outfile la stringa s, lunga l bytes, in HEX */
/* ritorna s */
void fbindump(longword x, FILE *f);
/* dump in binario di un numero */
/* output sul file f della rappresentazione binaria di x */
/* lunga sempre 32 cifre */
int Wline(byte *s, FILE *w);
/* writes a string followed by '\n' to stream 'w' */
/* return the number of char written */
int Log(int argc, ...);
/* write to stderr a timestamp, any number of strings, and finally a NL */

/******************** encoding */
longword b2l (byte *m);
/* legge da m 4 byte e compone un longword */
byte *l2b(byte *b, longword l);
/* scrive l nei primi 4 bytes di b */
longword mtoi (char *m, word l);
/* convert string 'M', l bytes long, to longword */
/* no check on content of 'M' */
byte *i2a(int x);
byte *lltoa(llint x);
/* Trasforma l'intero x in stringa. Notazione decimale */
/* restituisce un puntatore a zona statica */
llint a2llint (byte *s);
/* convert string s, to long long int */
u32 a2u (byte *s, int l);
/* convert string s, l bytes long, to unsigned int */
byte *u2a(unsigned int X);
/* Trasforma l'intero X positivo in stringa. Notazione decimale */
/* restituisce un puntatore a zona statica */
byte *ltom(longword x, byte *m, word l);
/* writes 'x' in decimal format to 'm' */
/* l is the lenght of field to be filled */
/* return m */
byte *ftoa(double x, int precision);
/* Trasforma il float x in stringa. Notazione decimale */
/* restituisce un puntatore a zona statica */
longword atob5(byte *a);
/* da una stringa di cifre 'base5' crea un numero */
longword mtob5(byte *m, byte l);
/* da una sequenza di cifre lunga l, crea un numero */
byte *b5toa(byte *a, longword x);
/* trasforma il numero x nella stringa che lo rappresenta in 'base 5' */
/* a viene sovrascritto per i primi 8 char */
byte *b5tom(byte *m, byte l, longword x);
/* trasforma il numero x nella stringa che lo rappresenta in 'base 5' */
/* m viene sovrascritto per i primi l char */

/******************** Work in progress */
char *nn(char *x);			/* not NULL string reference */
int nnstrcmp(char *x, char *y);
longword bit_reversed(longword x);
/* scambia il bit 0 con il 31, 1 con 30, 2 con 29 etc. */
char *myhostname(void);
byte *machine_id(void);
/* uname della macchina */
/* restituisce il puntatore ad una stringa di 12 char utili */
/* il valore restituito Š diverso per ogni macchina.        */
bool machine_ok(byte *appl_id);
/* controllo autorizzazione per una applicazione */
/* true se il controllo sulle autorizzazioni ha dato esito positivo         */
/* le password sono sul file indicato dalla variabile MPWDF                 */
/* con default = "/MPWDF.DAT". In esso ogni riga ha la forma:               */
/* <sep>nome_programma<sep>password<nl>                                     */
/* le righe che iniziano con # sono commenti */

byte *dtfill(byte *template, const struct tm *tp);
/* fill 'template' with values in 'tp' */
/* yyyy or yy=year, mm=month, dd=day, jjj=day of year */
/* HH=hour, MM=minutes, SS=seconds */
/* return template */
byte *ts_new(byte *template);
/* return a newly mmallocated area containing given template filled	*/
/* with current timestamp */
void TimeStmp(FILE *w);
/* print timestamp to output file w */
/* YYYYMMDD HH:MM.SS --> w */
long dtscan3(byte *template, byte *s, bool gm);
/* extract time fields from s and calculate timestamp */
/* gm indicates if s refers to gmtime or localtime    */
/* yyyy or yy=year, mm=month, dd=day, jjj=day of year */
/* HH=hour, MM=minutes, SS=seconds */
long dtscan(byte *template, byte *s);
/* dtscan3 with gm=false --> localtime */
long dtscan_gm(byte *template, byte *s);
/* dtscan3 with gm=true --> gmtime */
int days(int Y, int M);
/* number of days in month M, year Y */
int weekday(int Y, int M, int D);
/* compute day of week */
/* Y    year    1901..2099      */
/* M    month   1..12           */
/* D    day     1..days(Y,M)    */
/* rc=  dow     0(sunday)..6(saturday)  */
int deltadays(int Y1, int M1, int D1, int Y2, int M2, int D2);
/* number of days between two dates     */
/* Yx   year    1901..2099              */
/* Mx   month   1..12                   */
/* Dx   day     1..days(Yx,Mx)          */
int julian(int Y, int M, int D);
/* julian date                          */
/* Y    year    1901..2099              */
/* M    month   1..12                   */
/* D    day     1..days(Y,M)            */
int dtcheck(byte *template, byte *ts);
/* return 0 if ts contains a valid timestamp */
/* yyyy=year, mm=month, dd=day */
/* HH=hour, MM=minutes, SS=seconds */

int metachr(byte *s);
/* legge un metacarattere da una stringa */
/* ritorna il numero di caratteri letti da s (null term). varia da 1 a 5    */
/* viene estratto dalla stringa s il primo 'metacarattere' che puo` essere: */
/* #ddd       ASCII dec   code ddd (max. 3 digit)    PASCAL like */
/* $hh        ASCII hex   code hh  (max. 2 digit)    PASCAL like */
/* \#         ascii # */
/* \$         ascii $ */
/* \ooo       ASCII octal code ooo (max. 3 digit)    C like */
/* \0xhh      ASCII hex   code hh  (max. 2 digit)    C like */
/* \a         ASCII  7 BELL                          C like */
/* \b         ASCII  8 BACKSPACE                     C like */
/* \t         ASCII  9 TAB                           C like */
/* \n         ASCII 10 NL                            C like */
/* \v         ASCII 11 VT                            C like */
/* \f         ASCII 12 FF                            C like */
/* \r         ASCII 13 CR                            C like */
/* \\         il carattere \ (se seguito da spec)    C like */
int metastr(byte *s);
/* trasforma i metacaratteri in una stringa */
/* ritorna la lunghezza di s dopo aver trasformato in essa tutti i */
/* 'metacaratteri' (cfr. metachr) */
char *single_adjust(char *s);
/* trasforma alcuni caratteri speciali */
/* sostituisce nella stringa s i seguenti caratteri speciali: */
/*   \x         il carattere speciale x  */
/*   #xxx       codice ascii xxx         */
/*   $xx        codice ascii Hex(xx);    */

void env_unset(byte *varname);
/* remove a variable from environment */
void *mmalloc(longword len);
/* malloc controllata */
/* malloc con controllo errore, se va male stampa un messaggio ed esce */
void *mfree(void *p, longword len);
/* free con aggiornamento variabili consumo memoria */
void *sfree(byte *p);
/* mfree di una stringa*/
void *mrealloc(void *oldp, longword old_size, longword new_size);
/* realloc con controllo di errore */
byte *memdup(byte *s, int len);
/* duplica una stringa */
/* come strdup, ma duplica anche eventuali \0 e usa mmalloc */
byte *mstrdup(byte *s);
/* come strdup ma usa mmalloc */
byte *mcopy(byte *dest, byte *src, u32 n);
/* copy n bytes from src to dest */
byte *dollar(byte *s);
/* return a copy of s with the following forms resolved */
/* $VAR ${VAR} \$ ~ \~  */

byte *pathname(byte *filename);
/* la parte path di un pathname */
/* restituisce il puntatore ad una zona statica con il pathname del nomefile */
/* nomefile = pathname(nomefile) + basename(nomefile) */

/* byte *basename(byte *nomefile); */
/* la parte name di un pathname */
/* restituisce il puntatore ad una zona statica con il nome del nomefile */
/* nomefile = pathname(nomefile) + basename(nomefile) */

byte *Pbasename(byte *s);
/* la parte name di un pathname */
/* ritorna il puntatore al primo carattere dopo l'ultimo slash */
byte *Pextension(byte *s);
/* la parte 'extension' di un pathname */
/* ritorna il puntatore all'ultimo punto della stringa 's' */

byte *pathsearch(byte *f);
/* search regular file 'f' through the PATH */
/* and return a pointer to the found pathname or NULL if not found */
/* the function mallocs the buffer to store the return value */
/* free it when no more useful */

byte *mktmpname (const byte *path, byte *ext);
/* genera un nome di file nuovo */
/* restituisce il puntatore ad una zona statica che contiene il nome     */
/* di un file non esistente nella directory "path" con estensione "ext"  */
/* in caso di errore restituisce NULL                                    */
byte *mktmpnam (const byte *path);
/* genera un nome di file nuovo */
/* restituisce un puntatore a zona statica contenente un nome di file */
/* del tipo "N.$$$" con n >=1 e tale che il file non esista */
/* nella directory specificata */
bool dtrename(byte *fn, byte *ddir);
/* rename file fn by adding a timestamp yyyymmddHHMMSS between name and ext */
/* if ddir is NULL, fn remains in source dir */
llint f2fd_copy(int sd, FILE *r, llint n);
/* copy (at most) n bytes from r to sd */
bool fdcopy(int w, int r);
/* read from file descriptor r, write to w */
byte hex(byte c);
/* converte un carattere in hex */
/* converte il carattere x nel suo valore esadecimale  */
/* vale come caso particolare anche per cifre decimali */
/* c deve essere nell'insieme [0..9,A..F,a..f]         */
char hexdigit(char nibble);
/* converte un nibble nella sua rappresentazione in hex */
int pos(byte x, byte *s);
/* posizione di un carattere in una stringa */
/* cerca il carattere x nella stringa *s */
/* se non trovato ritorna -1 */
int revpos (byte x, byte *s);
/* posizione di un carattere nel reverse di una stringa */
/* indice dell'ultima occorrenza del carattere x nella stringa s */
/* -1 se non trovato */

word *mem2soc (SOC Acc, const byte *S, int l);
/* build a new set of chars from string S, l bytes long	*/
/* change in place and return Acc			*/
/* Grammar						*/
/* set     ::= <set_item> | <set_item>,<set>		*/
/* set_item::= <item> | -<item> | !item | (void)	*/
/* item    ::= <char><item> | <char>-<char>item | (void) */
/* special chars:					*/
/*   ,     --> items separator				*/
/*   !     --> complement	(at item beginning)	*/
/*   -     --> delta       	(at item beginning)	*/
/*   -     --> interval		(between two chars)	*/
/*   \     --> skip special char (, - ! \)		*/
bool Soc_in (byte x, SOC S);
/* test di appartenenza ad un insieme */
/* true if x in SOC */
word *Soc_add_char (byte x, SOC S);
/* add element x to set S, return S	*/
word *Soc_add_soc (SOC A, SOC B);
/* unione di due insiemi */
/* A = A+B */
/* ritorna A */
word *Soc_sub_soc (SOC A, SOC B);
/* differenza di due insiemi */
/* A = A-B */
/* ritorna A */
bool Soc_isempty (SOC S);
/* ritorna true se l'insieme e' vuoto */
word *Soc_empty(SOC X);
/* svuota l'insieme */
word *Soc_add_str(byte *s, int len, SOC rc);
/* if len==-1 s is \0 terminated */
word *Soc_add_fx(int (*f)(int), SOC rc);
/* example f2soc(isdigit,x) */

int shtokens(byte *s);
/* tokenize string s as usually shell do */
/* \x  --> x		*/
/* 'xxx' --> xxx	*/
/* "xxx" --> xxx	*/
/* return the number of tokens in s */
int tokenize_n(byte *s, int n);
int tokenize(byte *s);
/* substitute multi spaces with a single \0 */
/* return the number of tokens in s */

bool str2bool(byte *s, bool def_rc);
/* on/off true/false 1/0 Yes/No --> 1/0 */

byte *strrep(byte *s, int count);
/* return string s repeated count times */
byte *strcut(byte *s, byte sep, int numcampo);
/* n-esimo token di una stringa */
/* restituisce il puntatore ad una zona statica contenente n-esimo campo */
/* della stringa s. Il carattere sep delimita un campo dall'altro */
/* il token risultato Š lungo al massimo 255 caratteri */
byte *strtrunc(byte *s, int len, int maxlen);
/* restituisce il puntatore ad una zona statica contenente */
/* la stringa s, troncata a maxlen caratteri */
vls substrft(byte *x, int len, int from, int to);
/* extract a substring from a given string      */
/* return a newly mallocated vls                */
/* negative from/to refers to string end        */
vls fieldsft(byte *x, int len, byte sep, int from, int to);
/* extract from x a range of sep separated fields       */
/* return a newly mallocated vls                        */
/* negative from/to refers to string end                */
vls wordsft(byte *x, int len, SOC IFS, int from, int to);
/* extract from x a range of IFS separated words        */
/* return a newly mallocated vls                        */
/* negative from/to refers to string end                */
vls substr(byte *x, int len, int skip, int count);
/* extract a substring from a given string	*/
/* return a newly mallocated vls		*/
vls fields(byte *x, byte sep, int skip, int count);
/* extract a range of sep separated fields from a given vls */
/* return a newly mallocated vls		*/
vls words(byte *x, SOC IFS, int skip, int count);
/* extract a range of IFS separated words from a given vls */
/* return a newly mallocated vls		*/
Automa mkAttrMap(byte *p, byte sep);
/* return a new Automa with attribute --> fieldnum mapping for ecut() */
vls useAttrMap(byte *k, Automa attrMap);
/* search {attrname} and replace with attrnum	*/
/* return a new vls				*/
vls ecut(byte *x, byte *keydef, byte dsep);
/* return a newly mallocated vls key extracted from x using rules in keydef */
/* BNF */
/* keydef::=keytok|keytok(keydef)|keydef keytok			*/
/* keytok::=char|\char|{$|w|W|c|#}range|{f|F}char range		*/
/* range::=number|number..|number..number|number,|number,number	*/
/* dsep is defaul field separator used by # and @{}		*/
vls fcut(byte *x, byte *flst, byte dsep);
/* extract from x a list of fields	*/
/* flst: #n \# char			*/
/* return a new vls			*/
byte *strchrs(byte *s, byte *cset);
/* search s for chars in cset, return first char in s belonging to cset */
byte *strtr (byte *s, byte x, byte y);
/* x --> y in una stringa */
/* trasforma tutte le occorrenze di un carattere in una stringa */
/* Trasforma, nella stringa s, tutti le occorrenze del carattere 'x' */
/* in 'y' */
/* ritorna s */
byte *memtr(byte *s, word l, byte x, byte y);
/* change x to y in s, l byte long */
/* return s */
byte *memreverse(byte *s, int len);
/* reverse mem in place */
byte *strdel (byte *s, byte *delim);
/* cancella da s tutti i caratteri che sono in delim */
/* ritorna s */
byte *strshl(byte *s);
/* shift left string 's' */
/* return s */
byte *upstring(byte *s);
/* converte la stringa s in caratteri maiuscoli */
/* ritorna la stringa s */
byte *lomem(byte *m, int l);
byte *lostring(byte *s);
/* converte la stringa s in caratteri minuscoli */
/* ritorna la stringa s */
byte *strstrip(byte *s);
/* removes from 's' all ending spaces. return s */
byte *pad(byte *dest, byte *source, int size, byte filler);
/* copy source into dest up to size bytes, eventually fill using filler */

byte *V_or (byte *a, byte *b, word len);
/* vectorial OR */
/* a |= b */
/* restituisce a */
byte *V_and (byte *a, byte *b, word len);
/* vectorial AND */
/* a &= b */
/* restituisce a */
byte *V_xor (byte *a, byte *b, word len);
/* byte to byte XOR */
/* a ^= b */
/* return a */
byte *V_not (byte *a, word len);
/* vectorial NOT */
/* a = ~a */
/* return a */

longword crc32(longword crc, byte *buf, longword len);
/* Calcola il CRC32 di un blocco di bytes */
longword initcrc(void);
/* valore iniziale del CRC */
/* restituisce un valore fisso che server per inizializzare ad un valore dato */
/* una variabile che verr… usata per calcolare un CRC */
longword nextcrc(longword oldcrc, int c);
/* aggiorna il valore del CRC */
/* restituisce il valore del CRC calcolato a partire dal precedente CRC */
/* con aggiunta del byte c */
longword fcrc(FILE *r);
/* CRC di un file */
/* restituisce il CRC calcolato sul file 'r', che deve essere gi… aperto */
/* a partire dalla posizione corrente */
/* al termine il file sar… stato letto completamente */
longword addcrc(longword crc, byte *m, llint len);
/* valore del crc a partire dal precedente con aggiunta dei c bytes in m */
longword memcrc(byte *m, llint len);
/* CRC di un blocco di memoria */
/* calcolo del crc per un blocco di bytes lungo 'len' */
longword strcrc(byte *s);
/* CRC di una stringa */
/* calcolo del crc per una null term string */
longword fcrc1(byte *filename);
/* come fcrc, ma con apertura e chiusura del file */
longword fcrc2(byte *filename, llint N);
/* versione ottimizzata di fcrc1 */
longword dcrc2(byte *nomedir);
/* calcola il crc della directory sommando i crc delle sue entry */
llint fcopy_n(FILE *w, FILE *r, llint n);
/* read at most n bytes from r, write them to w */
/* return number of bytes written */
llint fcopy_crc(FILE *w, FILE *r, llint n, longword *crc);
/* fcopy with crc compute */
llint fcopy(FILE *w, FILE *r, llint n);
/* read n bytes from file r, if eof not encountered before */
/* write them to w, if not null */
/* return the number of bytes actually read and successfully written */
llint fcopy_eof(FILE *w, FILE *r);
int filecopy(byte *source, byte *dest);
int metacopy(byte *source, byte *dest, byte silent);
/* copy metadata from source to dest */
int dircopy(byte *source, byte *dest);
/* copy all regular files from source to dest */
int filesync(FILE *master, FILE *slave);
/* sync master to slave, both files must be at SEEK_END		*/
/* rc=1		can't append, rollback				*/
/* rc=2		can't overwrite					*/
int m2fsync(byte *master, i64 msz, FILE *slave);
/* sync memory block master, msz bytes long, to file slave	*/
/* slave must be at SEEK_END					*/
/* rc=1		can't append, rollback				*/
/* rc=2		can't overwrite					*/

byte *msg(word N);
/* returns the message number 'N' */
/* message table and index are automatically generated from utility */
/* 'msgtable' and must be included in the source */
int imsg(byte *s);
/* look for the null term string 's' in msgtable */
/* returns the index of 's' in msgtable, -1 if not present */

int int_cmp(int x, int y);
int vls_cmp(vls x, vls y);
/* vls compare: if x<y rc=-1; if x==y rc=0; if x>y rc=1 */
int vls_cmp_ci(vls x, vls y);
int ts_cmp(byte *template, byte *ts1, byte *ts2);
/* vls case insensitive compare: if x<y rc=-1; if x==y rc=0; if x>y rc=1 */
int number_cmp(byte *n1, byte *n2);
int number_memcmp(byte *x, int lx, byte *y, int ly);
/* compare string representing whole numbers */
/* return -1 if x<y, 0 if x==y, 1 if x>y */
int number_strcmp(byte *x, byte *y);

vls quote2(byte *s, int l);
vls quote(byte *s);
int mchdir(byte *path);
/* chdir() and set PWD env var too */

/* base64.c */
int base64_len(int x);
/* the lenght of the base64 representation of a string with length x */
byte *base64_enc (byte *rc, byte *x, int xlen);
byte *base64_encode (byte *rc, byte *x);
/* proxy Basic authentication user:pwd encoding			*/
/* if rc==NULL, return a pointer to a newly mallocated area	*/
vls base64_decode(byte *x);
/* return a newly allocated vls */
byte *base64_shuffle(byte *key);
/* return shuffled base64_alpha */

/* html.c */
byte *jstr(byte *s, int l, int t);
/* return a single or double quoted string */
void html_quote(byte *s, int l, int t);
int html_esc(byte c);
/* write to standard output a single char with HTML special chars escaped */
/* return the number of written chars */
int html_escm(byte *m, int l);
/* write to standard output m, l bytes long, with HTML special chars escaped */
/* return the number of written chars */
int html_escs(byte *s);
/* write to standard output string s with HTML special chars escaped */
/* return the number of written chars */
byte *html_escv(vls x);
/* html encode x in place, affected chars &"'<> */
int html_href(int c);
/* write to stdout c, with special href characters encoded */
/* return the number of written chars */
int html_hrefm(byte *m, int l);
/* write to standard output m, l bytes long, with href encoding */
/* return the number of written chars */
int html_hrefs(byte *s);
/* write to standard output string s with href encoding */
/* return the number of written chars */
byte *vls_urlencode(vls x);
/* encode x in place */
byte *vls_urldecode(vls x);
/* decode x in place */
void html_input(byte *type, byte *name, byte *value, byte *args);
void html_option(byte *value, bool selected, byte *label);
void html_a(byte *href, byte *args, byte *s);
void html_th(byte *s);
void html_td(byte align, byte *bg, byte *args);
void html_boolean(byte *name, bool value, bool submit);
void html_cbox(byte *name, int checked, bool disabled);

int http_time(char *s, struct tm *tm);	/* rc=1 if successful */

/* cgi.c */
bt addcgi(vls name, vls value);
bt setcgi(vls name, vls value);
vls cgienvv(byte *name);
byte *cgienv(byte *name);
ll cgienvll(byte *pfx);
int SessionPfx(byte *pfx);
vls SessionVar(byte *varname, byte *defvalue);
void addcgimem(byte *s, int s_len, byte mode);
/* add or replace 'name=value' */
/* mode: 'k'=don't replace, 'r':replace, 'a':append */
byte *UNIQUE_ID(void);
/* compose and export a UNIQUE_ID if not provided by httpd server */
int pb_create(byte *pb_npipe);
void html_pb_open(void);
void pb_update(int pb_fd, llint sz, llint cl);
llint up2b(int pb_fd, llint actsize, llint cl, vls boundary, FILE *w);
int parse_multipart(byte *b);
void init_cgienv(vls upload_dir, byte *pname);
/* initializes CGI environment */

byte *cgi_username(byte *passwd_filename);
/* restituisce il nome dell'utente che ha fatto la request      */
/* NULL se non sono state fornite credenziali                   */

byte *get_cryptedpwd(byte *fn, byte *u);
/* search into file 'fn' crypted password for user u	*/
/* each line contains username:password:		*/
/* return a new copy of crypted password		*/
void webauth_forget_user(byte *pname);
byte *webauth_known_user(byte *pname);
/* username the request come from, if any */
bool webauth_require_valid_user(byte *application_name, byte *copyright, byte *style, byte *background);
/* check if user is known, if not output an authentication form */

byte *export(byte *name, byte *value);
byte *username(int uid);
byte *groupname(int gid);
byte *email_owner(byte *email);
byte *email(byte *user);

vls tea(byte *s, int slen, byte *key, int keylen, bool encode);
vls tea_encm(byte *s, int slen, byte *key, int keylen);
vls tea_decm(byte *s, int slen, byte *key, int keylen);
void tea_decode(longword *v,longword *k);
/* data: 64 bits=8 bytes, key 128 bits=16 bytes, decode in place */
void tea_encode(longword *v, longword *k);
/* data: 64 bits=8 bytes, key 128 bits=16 bytes, encode in place */

int runcmd(vls out, char **argv);
/* run given command with arguments, return command rc		*/
/* if 'out' is not NULL at end it will contain command output	*/

int tcp_port(byte *service_name, int default_portnumber);
/* return the portnumber associated to a named service */
int tcp_stream(byte *h, int p, int tmo);
/* establish a tcpip connection with host h, port p, timeout in seconds */
/* return the socket descriptor, or -3:socket -2:gethostbyname -1:connect */

int next_counter(byte *fn, byte *vname);
/* update counter in file 'fn', return incremented value	*/
/* rc=-1 if open fails						*/

DIR *mopendir(byte *dirname);
/* same as opendir, but manages NULL or "" */

byte *fs_enc(vls rc, byte *s);
byte *fs_enc_unix(vls rc, byte *s, int slen);
byte *fs_enc_nt(vls rc, byte *s, int slen);
/* encode special characters in s */

byte *fs_dec(vls rc, byte *s);
/* decode special characters in s */

byte *md5(byte *m, int l);
/* return md5 checksum of buffer m, l bytes long */

/* cofs_api.c */
byte *cofs_error(int x);
int print_error(int x);
byte *cofs_token(byte *hostname);
/* return a newly mallocated string or NULL */
bt cofs_connect(ll rp, byte *hostname, byte *token);
/* connect to VFS server */
int cofs_simple_command(ll rp, byte *hostname, byte *tok, byte *vpath, byte *cmd);
int cofs_chdir(ll rp, byte *hostname, byte *tok, byte *vpath);
int cofs_stat(ll rp, byte *hostname, byte *tok, byte *vpath);
int cofs_crc32(ll rp, byte *hostname, byte *tok, byte *vpath);
int cofs_mkdir(ll rp, byte *hostname, byte *tok, byte *vpath);
int cofs_remove(ll rp, byte *hostname, byte *tok, byte *vpath);
int cofs_ls(ll rp, byte *hostname, byte *tok, byte *vpath);
int cofs_read(ll rp, byte *hostname, byte *tok, llint off, llint len, byte *vpath);
llint f_fd_copy_n(int w, FILE *r, llint n);
/* read at most n bytes from r, write them to w */
/* return number of bytes written */
int cofs_write(ll rp, byte *hostname, byte *tok, llint off, llint len, byte *vpath);
int cofs_append(ll rp, byte *hostname, byte *tok, llint len, byte *vpath);
int cofs_truncate(ll rp, byte *hostname, byte *tok, llint len, byte *vpath);
int cofs_run(ll rp, byte *hostname, byte *tok, llint len, byte *alias);

xy getrange(byte *s);
/* return a skip,offset pair from string containing a range definition */
byte *permute(byte *s, int len, longword seed);
/* return a random permutation of s, len bytes long */

byte *hostip(byte *hostname);
/* resolve hostname and return ip address in standard dotted form */
/* return a pointer to static area if successful or NULL	*/

byte *ascii2gsm(vls x);
/* x from ASCII to GSM*/
byte *gsm2ascii(vls x);
/* x from GSM to ASCII	*/

int csv_puts(byte *s, FILE *w);
/* write a field to CSV file			*/
/* return the number of written characters	*/
int csv_nl(FILE *w);
/* return the number of written characters */
int csv_getv(vls v, FILE *r);
/* get first CSV field from r, store it into v	*/
/* return code 					*/
/*   0:normal field				*/
/*   1:last field in row			*/
/*   2:last field in file			*/

vls os_uuid(void);
/* return a static vls containing OS unique identifier */
byte *keygen(byte *rc, int len);
/* generate a random key, len bytes long */
uint random32(uint seed);
/* return a 32-bit random number		*/
/* initialize sequence with seed, if not zero	*/
int debug_init(void);		/* rewrite /tmp/debug.txt */
int debug(byte *n, byte *v);	/* append n='v' to /tmp/debug.txt */

/******************** controlling ANSI tty */
#define BLACK   0   /* colors for textcolor, textbackground */
#define RED     1
#define GREEN   2
#define YELLOW  3
#define BLUE    4
#define MAGENTA 5
#define CYAN    6
#define WHITE   7
#define BW40    0   /* modes for textmode */
#define C40     1
#define BW80    2
#define C80     3
void ansi_gotoxy(byte x, byte y);
/* move cursor to x,y home=1,1 */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_clrscr(void);
/* clear screen */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_clreol(void);
/* clear current line */
/* deve essere installato un ANSI device driver */
/* output su stderr */
byte ansi_getattr(void);
/* ritorna la maschera corrente degli attributi video */
/* bit 0-3: fg color */
/* bit   4: high/low intensity */
/* bit 5-7: bg color */
/* bit   8: blink on/off */
byte ansi_setattr(byte newattr);
/* imposta in blocco tutti gli attributi video */
/* bit 0-3: fg color */
/* bit   4: high/low intensity */
/* bit 5-7: bg color */
/* bit   8: blink on/off */
/* ritorna il precedente attributo video */
void ansi_normvideo(void);
/* resetta tutti gli attributi (compresi i colori) */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_highvideo(void);
/* imposta l'attributo bright */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_lowvideo(void);
/* cancella l'attributo bright */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_modeblink(void);
/* imposta l'attributo BLINK */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_noblink(void);
/* resetta l'attributo BLINK */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_reverse(void);
/* reverse current video attributes */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_textcolor(byte color);
/* imposta il colore dei caratteri */
/* 0=black 1=red ... 7=white */
/* 8-15 bright colors        */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_textbackground(byte color);
/* imposta il colore di fondo */
/* 0=black 1=red ... 7=white */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_textmode(byte mode);
/* imposta la modalit… testo */
/* 0=BW40 1=C40 2=BW80 3=C80 */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_plot(byte x, byte y, byte c);
/* write char c at x,y */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_drawx(byte x1, byte x2, byte y);
/* horizontal line at y from x1 to x2 */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_drawy(byte x, byte y1, byte y2);
/* Vertical line at x from y1 to y2 */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_box(byte x1, byte y1, byte x2, byte y2);
/* box with single line with x1,y1 upper left, x2,y2 bottom right corner */
/* deve essere installato un ANSI device driver */
/* output su stderr */
void ansi_cursor(byte show);
/* show or hide cursor */

/******************** EBCDIC */
byte *ascii_to_ebcdic (byte *s);
/* ASCII --> EBCDIC a null-term string */
/* Converts an ASCII string to EBCDIC.  Must be a valid "C" string */
/* Input: a pointer to a '\0' terminated string.                   */
/* the buffer is modified in place and then returned               */
byte *ascii_to_ebcdic_field (byte *s, word len);
/* ASCII --> EBCDIC a string */
/* Converts an ASCII string, len bytes long, to EBCDIC.            */
/* Input: a pointer to a len bytes long buffer.                    */
/* the buffer is modified in place and then returned               */
byte *ebcdic_to_ascii (byte *s);
/* EBCDIC --> ASCII a null-term string */
/* Converts an EBCDIC string to ASCII.  Must be a valid "C" string */
/* Input: a pointer to a '\0' terminated string.                   */
/* the buffer is modified in place and then returned               */
byte *ebcdic_to_ascii_field (byte *s, word len);
/* EBCDIC --> ASCII a string */
/* Converts an EBCDIC string, len bytes long, to ASCII.            */
/* Input: a pointer to a len bytes long buffer.                    */
/* the buffer is modified in place and then returned               */

long rgb(int r, int g, int b);
/* return 24-bit color with (r,g,b) components	*/
long rgb2hsv(long c);
/* convert color c from rgb to hsv representation	*/
long rgb_add(long c1, long c2);
/* sum rgb components of colors c1 and c2	*/
/* return resulting color			*/
long rgb_dist(long c1, long c2);
/* return distance of colors c1 and c2	*/
long rgb_maxcontrast(long c);
/* return color with maximum contrast with color c	*/
long rgb_thr(long c, byte thr);
/* limit maximum value of each (r,g,b) components of color c	*/
/* to a maximum of threshold thr				*/
/* return resulting color					*/

void mergesort(int *a, int n);
byte *asort(byte *a, int n);
void txtsort(byte **a, int min, int max);
int binsearch(int *a, int min, int max, int key);
/* search key into sorted array a from a[min] to a[max] */
/* return index of key, or -1 if not found */
byte *nextperm(byte *s, int l);
/* compute next permutation of string s, l bytes long */
byte **ntxtperm(byte **t, int l);
/* compute next permutation of text t, l lines long */

/* sorted integer array */
int *sia_seek(int *A, int n, int k);
/* search k into sorted array A, n int long */
/* return address of k, or NULL if not found */
int *sia_insert(int *A, int n, int k);
/* insert a new element k into array A, n int long */
/* return address of new element, keep array sorted */
int *sia_remove(int *A, int n, int *B);
/* remove element B from sorted array A */
/* return address of removed element */

/* ordered integer list */
oil oil_new(u32 size);
/* create an empty ordered integer list */
oil oil_free(oil A);
int oil_append(oil A, int key, void *x);
/* append (key,x) to list A */
int oil_search(oil A, int key);
/* search key in A, return index or -1 if not found */
int oil_insert(oil A, int key, void *x);
/* search/add (key,x) into ordered list A */
/* return index */
int oil_remove(oil A, int idx);
/* remove idx-th element from list A */

int N_len(byte *x);
int N_cmp(byte *x, int xl, byte *y, int yl);
vls N_add(byte *x, int xl, byte *y, int yl);
vls N_sub(byte *x, int xl, byte *y, int yl);
vls N_mul(byte *x, int xl, byte *y, int yl);
vls N_div(vls mod, byte *x, int xl, byte *y, int yl);
/* return x/y, store remainder into mod (if not NULL) */

int apath(byte *dirname);
/* add dirname to PATH environment variable if not already there	*/
/* rc=0 PATH changed, rc=1 PATH unchanged				*/

int tty_readchar(int MIN, int TIME);
/*
MIN == 0, TIME == 0 (polling read)
MIN > 0, TIME == 0 (blocking read)
MIN == 0, TIME > 0 (read with timeout)
MIN > 0, TIME > 0 (read with interbyte timeout)
*/

int KeyPressed();
/* true if there is a char into stdin ready to be read with Inkey() */
int Inkey();
/* read a single character, without echo, from stdin  */

/* calendar functions */
int is_leap(int year);
u32 ymdays(u32 year, u32 month);
u32 tm2days(struct tm *tm);		/* days since epoch */
i64 tm2sec(struct tm *tm);		/* seconds since epoch */

long arg_max(void);			/* detect ARG_MAX in a portable way */
#endif
