/* ------------------------------------------------------------------------
@NAME       : btparse.h
@DESCRIPTION: Declarations and types for users of the btparse library.

              (Actually, btparse.h is generated from btparse.h.in by
              the `configure' script, in order to automatically determine
              the appropriate values of HAVE_USHORT and HAVE_BOOLEAN.)
@GLOBALS    :
@CALLS      :
@CREATED    : 1997/01/19, Greg Ward
@MODIFIED   :
@VERSION    : $Id: btparse.h.in,v 1.35 1999/12/28 18:23:17 greg Exp $
@COPYRIGHT  : Copyright (c) 1996-97 by Gregory P. Ward.  All rights reserved.

              This file is part of the btparse library.  This library is
              free software; you can redistribute it and/or modify it under
              the terms of the GNU General Public License as
              published by the Free Software Foundation; either version 2
              of the License, or (at your option) any later version.
-------------------------------------------------------------------------- */
#ifndef BTPARSE_H
#define BTPARSE_H

#ifdef _POSIX_C_SOURCE
  #define TEMP_SAVE_POSIX_C_SOURCE _POSIX_C_SOURCE
  #undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE 200809L

#include <sys/types.h>                  /* probably supplies 'ushort' */
#include <stdio.h>

#include "config.h" /* not btparse's config.h but Tellico's */

/*
 * Here we attempt to define HAVE_USHORT if a typdef for `ushort' appears
 * in <sys/types.h>.  The detective work is actually done by the
 * `configure' script, so if compilation fails because of duplicate
 * definitions of `ushort', that's a bug in `configure' -- please tell me
 * about it!
 */

#ifndef HAVE_USHORT
# define HAVE_USHORT 0
#endif

#if ! HAVE_USHORT                       /* needed for various bitmaps */
typedef unsigned short ushort;
#endif


/* Likewise for boolean. */

#ifndef HAVE_BOOLEAN
# define HAVE_BOOLEAN 0
#endif

#if ! HAVE_BOOLEAN
typedef int boolean;
#endif

#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif

#ifndef HAVE_STRLWR
# define HAVE_STRLWR 0
#endif

#ifndef HAVE_STRUPR
# define HAVE_STRUPR 0
#endif


/* Parsing (and post-processing) options */

#define BTO_CONVERT   1                 /* convert numbers to strings? */
#define BTO_EXPAND    2                 /* expand macros? */
#define BTO_PASTE     4                 /* paste substrings together? */
#define BTO_COLLAPSE  8                 /* collapse whitespace? */

#define BTO_NOSTORE   16

#define BTO_FULL (BTO_CONVERT | BTO_EXPAND | BTO_PASTE | BTO_COLLAPSE)
#define BTO_MACRO (BTO_CONVERT | BTO_EXPAND | BTO_PASTE)
#define BTO_MINIMAL 0

#define BTO_STRINGMASK (BTO_CONVERT | BTO_EXPAND | BTO_PASTE | BTO_COLLAPSE)

#define BT_VALID_NAMEPARTS "fvlj"
#define BT_MAX_NAMEPARTS 4

typedef enum
{
   BTE_UNKNOWN,
   BTE_REGULAR,
   BTE_COMMENT,
   BTE_PREAMBLE,
   BTE_MACRODEF
/*
   BTE_ALIAS,
   BTE_MODIFY
*/
} bt_metatype;

#define NUM_METATYPES ((int) BTE_MACRODEF + 1)

typedef enum
{
   BTAST_BOGUS,                           /* to detect uninitialized nodes */
   BTAST_ENTRY,
   BTAST_KEY,
   BTAST_FIELD,
   BTAST_STRING,
   BTAST_NUMBER,
   BTAST_MACRO
} bt_nodetype;

typedef enum
{
   BTN_FIRST, BTN_VON, BTN_LAST, BTN_JR, BTN_NONE
} bt_namepart;

typedef enum
{
   BTJ_MAYTIE,                          /* "discretionary" tie between words */
   BTJ_SPACE,                           /* force a space between words */
   BTJ_FORCETIE,                        /* force a tie (~ in TeX) */
   BTJ_NOTHING                          /* nothing between words */
} bt_joinmethod;


#define USER_DEFINED_AST 1

#define zzcr_ast(ast,attr,tok,txt)              \
{                                               \
   (ast)->filename = InputFilename;             \
   (ast)->line = (attr)->line;                  \
   (ast)->offset = (attr)->offset;              \
   (ast)->text = strdup ((attr)->text);         \
}

#define zzd_ast(ast)                            \
/* printf ("zzd_ast: free'ing ast node with string %p (%s)\n", \
           (ast)->text, (ast)->text); */ \
   if ((ast)->text != NULL) free ((ast)->text);


#ifdef USER_DEFINED_AST
typedef struct _ast
{
   struct _ast *right, *down;
   const char *     filename;
   int              line;
   int              offset;
   bt_nodetype    nodetype;
   bt_metatype    metatype;
   char *           text;
} AST;
#endif /* USER_DEFINED_AST */


typedef struct
{
   /*
    * `string' is the string that has been split; items[0] ...
    * items[num_items-1] are pointers into `string', or NULL for empty
    * substrings.  Note that `string' is actually a copy of the string
    * passed in to bt_split_list() with NULs inserted between substrings.
    */

   char *  string;
   int     num_items;
   char ** items;
} bt_stringlist;


typedef struct
{
   bt_stringlist * tokens;              /* flat list of all tokens in name */
   char ** parts[BT_MAX_NAMEPARTS];     /* each elt. is list of pointers */
                                        /* into `tokens->string' */
   int     part_len[BT_MAX_NAMEPARTS];  /* length in tokens */
} bt_name;


typedef struct tex_tree_s
{
   char * start;
   int    len;
   struct tex_tree_s
        * child,
        * next;
} bt_tex_tree;


typedef struct
{
   /* These determine the order (and presence) of parts in the name. */
   int         num_parts;
   bt_namepart parts[BT_MAX_NAMEPARTS];

   /*
    * These lists are always in the order of the bt_namepart enum -- *not*
    * dependent on the particular order of parts the user specified!  (This
    * will make it a bit harder if I ever allow more than one occurrence of
    * a part in a format; since I don't allow that, I'm not [yet] worried
    * about it!)
    */
   const char *       pre_part[BT_MAX_NAMEPARTS];
   char *       post_part[BT_MAX_NAMEPARTS];
   char *       pre_token[BT_MAX_NAMEPARTS];
   const char *       post_token[BT_MAX_NAMEPARTS];
   boolean      abbrev[BT_MAX_NAMEPARTS];
   bt_joinmethod join_tokens[BT_MAX_NAMEPARTS];
   bt_joinmethod join_part[BT_MAX_NAMEPARTS];
} bt_name_format;


typedef enum
{
   BTERR_NOTIFY,                /* notification about next action */
   BTERR_CONTENT,               /* warning about the content of a record */
   BTERR_LEXWARN,               /* warning in lexical analysis */
   BTERR_USAGEWARN,             /* warning about library usage */
   BTERR_LEXERR,                /* error in lexical analysis */
   BTERR_SYNTAX,                /* error in parser */
   BTERR_USAGEERR,              /* fatal error in library usage */
   BTERR_INTERNAL               /* my fault */
} bt_errclass;

typedef enum
{
   BTACT_NONE,                  /* do nothing on error */
   BTACT_CRASH,                 /* call exit(1) */
   BTACT_ABORT                  /* call abort() */
} bt_erraction;

typedef struct
{
   bt_errclass errclass;
   const char *      filename;
   int         line;
   const char *      item_desc;
   int         item;
   const char *message;
} bt_error;

typedef void (*bt_err_handler) (bt_error *);


#if defined(__cplusplus__) || defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

/* Function prototypes */

/* init.c */
void  bt_initialize (void);
void  bt_free_ast (AST *ast);
void  bt_cleanup (void);

/* input.c */
void    bt_set_stringopts (bt_metatype metatype, ushort options);
AST * bt_parse_entry_s (char *    entry_text,
                        const char *    filename,
                        int       line,
                        ushort    options,
                        boolean * status);
AST * bt_parse_entry   (FILE *    infile,
                        const char *    filename,
                        ushort    options,
                        boolean * status);
AST * bt_parse_file    (char *    filename,
                        ushort    options,
                        boolean * overall_status);

/* postprocess.c */
void bt_postprocess_string (char * s, ushort options);
char * bt_postprocess_value (AST * value, ushort options, boolean replace);
char * bt_postprocess_field (AST * field, ushort options, boolean replace);
void bt_postprocess_entry (AST * entry, ushort options);

/* error.c */
void   bt_reset_error_counts (void);
int    bt_get_error_count (bt_errclass errclass);
int *  bt_get_error_counts (int *counts);
ushort bt_error_status (int *saved_counts);

/* macros.c */
void bt_add_macro_value (AST *assignment, ushort options);
void bt_add_macro_text (const char * macro, const char * text, const char * filename, int line);
void bt_delete_macro (const char * macro);
void bt_delete_all_macros (void);
int bt_macro_length (const char *macro);
char * bt_macro_text (const char * macro, const char * filename, int line);

/* traversal.c */
AST *bt_next_entry (AST *entry_list, AST *prev_entry);
bt_metatype bt_entry_metatype (AST *entry);
char *bt_entry_type (AST *entry);
char *bt_entry_key (AST *entry);
AST *bt_next_field (AST *entry, AST *prev, char **name);
AST *bt_next_macro (AST *entry, AST *prev, char **name);
AST *bt_next_value (AST *head,
                    AST *prev,
                    bt_nodetype *nodetype,
                    char **text);
char *bt_get_text (AST *node);

/* modify.c */
void bt_set_text (AST * node, char * new_text);
void bt_entry_set_key (AST * entry, char * new_key);

/* names.c */
bt_stringlist * bt_split_list (char *   string,
                               char *   delim,
                               char *   filename,
                               int      line,
                               const char *   description);
void bt_free_list (bt_stringlist *list);
bt_name * bt_split_name (const char *  name,
                         const char *  filename,
                         int     line,
                         int     name_num);
void bt_free_name (bt_name * name);

/* tex_tree.c */
bt_tex_tree * bt_build_tex_tree (char * string);
void          bt_free_tex_tree (bt_tex_tree **top);
void          bt_dump_tex_tree (bt_tex_tree *node, int depth, FILE *stream);
char *        bt_flatten_tex_tree (bt_tex_tree *top);

/* string_util.c */
void bt_purify_string (char * string, ushort options);
void bt_change_case (char transform, char * string, ushort options);

/* format_name.c */
bt_name_format * bt_create_name_format (char * parts, boolean abbrev_first);
void bt_free_name_format (bt_name_format * format);
void bt_set_format_text (bt_name_format * format,
                         bt_namepart part,
                         char * pre_part,
                         char * post_part,
                         char * pre_token,
                         char * post_token);
void bt_set_format_options (bt_name_format * format,
                            bt_namepart part,
                            boolean abbrev,
                            bt_joinmethod join_tokens,
                            bt_joinmethod join_part);
char * bt_format_name (bt_name * name, bt_name_format * format);

#if defined(__cplusplus__) || defined(__cplusplus) || defined(c_plusplus)
}
#endif

// Wipe out the temporary version we just used
#undef _POSIX_C_SOURCE

// If POSIX_SOURCE existed before, bring back the saved value
#undef _POSIX_C_SOURCE
#ifdef TEMP_SAVE_POSIX_C_SOURCE
    #define _POSIX_C_SOURCE TEMP_SAVE_POSIX_C_SOURCE
    #undef TEMP_SAVE_POSIX_C_SOURCE
#endif

#endif /* BTPARSE_H */
