/*-
******************************************************************************
******************************************************************************
**
**  ARCHIVE HEADER INFORMATION
**
**  @C-file{
**      FILENAME    = "globals.h",
**      VERSION     = "1.00",
**      DATE        = "",
**      TIME        = "",
**
**      AUTHOR      = "Niel Kempson",
**      ADDRESS     = "25 Whitethorn Drive, Cheltenham, GL52 5LL, England",
**      TELEPHONE   = "+44-242 579105",
**      EMAIL       = "kempson@tex.ac.uk (Internet)",
**
**      SUPPORTED   = "yes",
**      ARCHIVED    = "tex.ac.uk, ftp.tex.ac.uk",
**      KEYWORDS    = "VVcode",
**
**      CODETABLE   = "ISO/ASCII",
**      CHECKSUM    = "51492 1481 5732 57976",
**
**      DOCSTRING   = { This file is part of VVcode.
**                  }
**  }
**
**  MODULE CONTENTS
**
**      [tbs]
**
**  COPYRIGHT
**
**      Copyright (c) 1991-1993 by Niel Kempson <kempson@tex.ac.uk>
**
**      This program 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 1, or
**      (at your option) any later version.
**
**      This program is distributed in the hope that it will be useful,
**      but WITHOUT ANY WARRANTY; without even the implied warranty of
**      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
**      General Public License for more details.
**
**      You should have received a copy of the GNU General Public License
**      along with this program; if not, write to the Free Software
**      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**      In other words, you are welcome to use, share and improve this
**      program.  You are forbidden to forbid anyone else to use, share
**      and improve what you give them.   Help stamp out software-hoarding!  
**
**  CHANGE LOG
**
******************************************************************************
******************************************************************************
*/


/*-
**============================================================================
**
** SECTION  1 - VVCODE VERSION
**
**============================================================================
*/
#define VV_MAJOR_VERSION_NO         0
#define VV_MINOR_VERSION_NO         9
#define VV_VERSION_STR              "0.97 beta"
#define VV_DATE                     "25 Nov 1992"

/*-
**============================================================================
**
** SECTION  2 - MACROS TO IMPROVE THE READABILITY OF THE SOURCE CODE
**
**
** Consider the macro definition:
**
**      #define SHOW(num1, num2)  printf("num1 = %d, num2 = %d", num1, num2)
**
** and the C code using the macro:
**
**      SHOW (1234, 5678);
**
** The expected result is:
**
**      printf ("num1 = %d, num2 = %d", 1234, 5678);
**
** since examples of the parameters should not be expanded within strings.
** A certain brain-dead compiler actually expands the parameters within the
** strings even though both editions of Kernighan & Ritchie and every C manual
** that I've read prohibit this behaviour.  The result is:
**
**      printf ("1234 = %d, 5678 = %d", 1234, 5678);
**
** which is of course silly.
**
** To avoid this misbehaviour, all macro parameters will begin with an
** underscore (_) and the parameter string must not appear in the macro
** definition, except where parameter expansion is desired.  The above macro
** would have to be redefined as:
**
**      #define SHOW(_n1, _n2)  printf("num1 = %d, num2 = %d", _n1, _n2)
**
**
** Oh, the brain dead compiler is VAX/VMS C v3.1
**============================================================================
*/

/*-
**----------------------------------------------------------------------------
** Macros for ANSI function prototypes.  If the compiler supports ANSI C, we
** take advantage of the new ANSI prototypes.  If not, the ARGS macro will
** remove the prototype declarations.  ANSI_SYNTAX will have been set 
** appropriately in machine.h
**----------------------------------------------------------------------------
*/
#if (ANSI_SYNTAX)
# define ARGS(_plist)           _plist
# define CONST                  const
# define SIZE_T                 size_t
# define TIME_T                 time_t
#else                           /* NOT (ANSI_SYNTAX) */
# define ARGS(_plist)           ()
# define CONST
# define SIZE_T                 unsigned
# define TIME_T                 long
#endif                          /* (ANSI_SYNTAX) */


/*-
**----------------------------------------------------------------------------
** Useful macros to make the source code more readable.
**----------------------------------------------------------------------------
*/
#define PRINTF                  (void) printf
#define FPRINTF                 (void) fprintf
#define SPRINTF                 (void) sprintf
#define FSCANF                  (void) fscanf
#define NULLCHAR                (char *) NULL


/*-
**----------------------------------------------------------------------------
** Macros emulating functions.  Different C compilers support the
** character/string functions below in different ways.  Some of the functions
** are not supported at all (e.g. strncmpi).  To be on the safe side, these
** functions have been defined by VVCODE.
**----------------------------------------------------------------------------
*/
#define MINIMUM(_a, _b)    	(((_a) < (_b)) ? (_a) : (_b))
#define MAXIMUM(_a, _b)    	(((_a) > (_b)) ? (_a) : (_b))

#define STRCHR                  vstrchr
#define STRRCHR                 vstrrchr
#define STRSTR                  vstrstr
#define STRRSTR                 vstrrstr
#define STRCMP                  strcmp
#define STRCMPI                 vstricmp
#define STRNCMP                 vstrncmp
#define STRNCMPI                vstrnicmp
#define STRDUP                  vstrdup
#define TOLOWER(_c)             (isupper(_c) ? tolower(_c) : (_c))
#define TOUPPER(_c)             (islower(_c) ? toupper(_c) : (_c))
#define LEAPYEAR(i)         (((i)%4)==0) && ((((i)%100)!=0) || (((i)%400)==0))
#define UPDATE_CRC32(_cc, _bb)\
  _cc = G_crc32_table[(Byte) (((Byte) _cc ^ (Byte) _bb) & 0xff)] ^ (_cc >> 8)



/*-
**============================================================================
**
** SECTION  3 - MACROS DEFINING LIMITS AND GENERAL CONSTANTS
**
**============================================================================
*/
#define MAX_ENCODED_BYTES       45
#define MAX_IP_LINE_LEN         512
#define IO_BUFFER_SIZE          4096
#define MAX_VV_RECORD_LEN       65535L
#define DECODE_REC_LEN          0
#define DECODE_DATA             1
#define ENCODE_REC_LEN          0
#define ENCODE_DATA             1
#define MIN_SPLIT_SIZE          4L
#define OVERWRITE_NO            0
#define OVERWRITE_YES           1
#define OVERWRITE_ASK           2
#define XLT_BUFFER_SIZE         4096

#define INFO_STATUS             -1
#define NORMAL_STATUS           0
#define LOG_STATUS              1
#define WARNING_STATUS          2
#define ERROR_STATUS            3
#define FATAL_STATUS            4

#define FS_PREAMBLE             8
#define FS_NAME                 2
#define FS_EXTENSION            4
#define FS_POSTAMBLE            1
#define FS_NOTHING              0


/*
**----------------------------------------------------------------------------
** Macros used by lookup_key() defining whether the qualifier needs a 
** value.
**----------------------------------------------------------------------------
*/
#define LOOKUP_UNKNOWN         (-1)
#define LOOKUP_AMBIGUOUS       (-2)

#define NO_ABBREVIATIONS        0
#define ALLOW_ABBREVIATIONS     1

#define CASE_INSENSITIVE        0
#define CASE_SENSITIVE          1


/*
**----------------------------------------------------------------------------
** VV timestamp format
**----------------------------------------------------------------------------
*/
#define DUMMY_VV_TIMESTAMP      "1991.02.15-16:12:32 GMT"
#define VV_TIMESTAMP_FORMAT     "%04d.%02d.%02d-%02d:%02d:%02d"


/*
**----------------------------------------------------------------------------
** CRC-32 constants
**----------------------------------------------------------------------------
*/
#define CRC32_TABLE_SIZE        256
#define CRC32_MASK              (Unsigned32) 0xFFFFFFFFL
#define CRC32_POLYNOMIAL        (Unsigned32) 0xEDB88320L


#define INV_FORMAT              ((Int16) -1)
#define INV_MODE                ((Int16) -1)
#define INV_RECORD_LEN          ((Int32) -1)
#define INV_TABLE_ENTRY         ((Int16) -1)
#define INV_TIMESTAMP           ((TIME_T) -2147483647L)


/*-
**============================================================================
**
** SECTION  4 - ENCODING / DECODING
**
**============================================================================
*/

#define UU_DECODING             1
#define VV_DECODING             2
#define XX_DECODING             3

/*-
**----------------------------------------------------------------------------
** There are two commonly used UUcode tables, one with a space in it, and a 
** later one with the space replaced by a tilde to avoid problems with some
** mail gateways removing trailing spaces.  This UUcode table is the one that
** doesn't have a space in it.
**----------------------------------------------------------------------------
*/
#define UU_ENCODE_TABLE    \
        "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
#define VV_ENCODE_TABLE    \
        "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
#define XX_ENCODE_TABLE    \
        "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

#define ENCODE_TABLE_LEN        (sizeof (VV_ENCODE_TABLE) - 1)
#define DECODE_TABLE_LEN        256
#define XLT_TABLE_LEN           256
#define ENCODE(c)               G_encode_table[(c) & (ENCODE_TABLE_LEN - 1)]



/*-
**============================================================================
**
** SECTION  5 - STRUCTURES AND TYPEDEFS USED
**
**============================================================================
*/

/*-
**----------------------------------------------------------------------------
** Typedefs
**----------------------------------------------------------------------------
*/
typedef char                Boolean;
typedef unsigned char       Byte;
typedef unsigned char       Unsigned8;
typedef unsigned short      Unsigned16;
typedef unsigned long       Unsigned32;
typedef short               Int16;
typedef long                Int32;

/*-
**----------------------------------------------------------------------------
** Structures
**----------------------------------------------------------------------------
*/
typedef struct
{
    char                   *q_string;
    Boolean                 val_needed;
    Boolean                 present;
    char                   *value;
} Qualifier_Struct;

typedef struct
{
    char                   *h_string;
    Boolean                 present;
    char                   *value;
} Header_Struct;

typedef struct
{
    char                    file_spec[MAX_PATH + 1];
    FILE                   *file_ptr;
    Boolean                 pipe_flag;
    Int32                   line_no;

    Int16                   mode;
    Int16                   format;
    Int32                   max_rec_len;
    Int32                   lng_rec_len;
    TIME_T                  mod_time;

    Int32                   bytecount;
    Unsigned32              crc32;
} File_Info;

typedef struct
{
    char                   *xlt_from;
    char                   *xlt_to;
    Int16                   xlt_tbl[XLT_TABLE_LEN];
} Xlt_Struct;



/*-
**============================================================================
**
** SECTION  6 - GLOBAL VARIABLES
**
**============================================================================
*/

/*-
**----------------------------------------------------------------------------
**  Declared by the VVcode main modules, but referenced as 'extern' by other
**  modules.
**----------------------------------------------------------------------------
*/
#ifdef  VVCODE_MAIN
    Unsigned32              G_crc32_table[CRC32_TABLE_SIZE];
    Int16                   G_status;
    Boolean                 G_debugging;
    Int16                   G_decode_table[DECODE_TABLE_LEN + 1];
    char                    G_encode_table[ENCODE_TABLE_LEN + 1];
    File_Info               G_log_file;
    Xlt_Struct              G_xlt_table;
#else                           /* NOT VVCODE_MAIN */
    extern Unsigned32       G_crc32_table[CRC32_TABLE_SIZE];
    extern Int16            G_status;
    extern Boolean          G_debugging;
    extern Int16            G_decode_table[DECODE_TABLE_LEN + 1];
    extern char             G_encode_table[ENCODE_TABLE_LEN + 1];
    extern File_Info        G_log_file;
    extern Xlt_Struct       G_xlt_table;
#endif                          /* VVCODE_MAIN */


/*-
**----------------------------------------------------------------------------
** Global buffers allocated dynamically at startup.
**
**  G_ip_buffer [IP_BUFFER_SIZE]    temporary string buffer used for reading
**                                  from files.      
**  G_op_buffer [OP_BUFFER_SIZE]    temporary string buffer used for writing
**                                  to files.
**  G_tmp_msg [MAX_MSG_LEN]         temporary string buffer for user messages
**
**----------------------------------------------------------------------------
*/
#define IP_BUFFER_SIZE          2048
#define OP_BUFFER_SIZE          2048
#define MAX_MSG_LEN             4096

#ifdef  VVCODE_MAIN
    char                   *G_ip_buffer;
    char                   *G_op_buffer;
    char                   *G_tmp_msg;
#else                           /* NOT VVCODE_MAIN */
    extern char            *G_ip_buffer;
    extern char            *G_op_buffer;
    extern char            *G_tmp_msg;
#endif                          /* VVCODE_MAIN */


/*-
**----------------------------------------------------------------------------
** Global variables used only by VVencode / VVdecode
**----------------------------------------------------------------------------
*/
#ifdef  VVCODE_MAIN
    char                   *G_hdrf_spec;
    File_Info               G_ip_file;
    File_Info               G_op_file;
    File_Info               G_vv_file;
    Int32                   G_ippart_bytes;
    Int16                   G_ippt_no;
    Int32                   G_oppart_bytes;
    Int16                   G_oppt_no;
    Int16                   G_overwrite_flag;
    Int32                   G_split_size;

# ifdef VVDECODE
        char                G_op_padchar;
        Int16               G_dec_type;
        Int16               G_vv_decode_version;
        char               *G_vv_operating_system;
        char               *G_vv_character_set;
# endif                         /* VVDECODE */
#endif                          /* VVCODE_MAIN */



/*-
**============================================================================
**
** SECTION  7 - COMMAND LINE PARSING
**
** The command line qualifiers fall into three categories:
**
**  a.  those that do not take a value
**  b.  those that require a value
**  c.  those that take an optional value
**
** On systems such as MS-DOS and VAX/VMS, qualifiers are separated from each
** other by spaces and from their values by equals signs.  For example:
**
**      program /qI /qII=value paramI  paramII
**      program /qI /qII       paramI  paramII
**
** For this type of command syntax it is straightforward to detect whether an
** optional qualifier is present.
**
** On Unix, the convention is to separate qualifiers both from each other and
** from their values by spaces.  Consider the command lines:
**
**      program -qI -qII value paramI  paramII
**      program -qI -qII       paramI  paramII
**
** It is difficult if not impossible to determine whether the value following
** a qualifier is a qualifier value or a parameter unless the delimiting
** characters are different or strict rules on the ordering of parameters
** and qualifiers are imposed.  We take the easy way out and specify in the
** machine.h file whether the implementation supports optional qualifier
** values.  If these values are not supported, qualifiers which could take
** optional values become qualifiers which require values.
**============================================================================
*/
#define VALUE_NEEDED            0
#define VALUE_NONE              1
#define VALUE_OPTIONAL          2


/*-
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
*/
#ifdef  VVCODE_MAIN
    static Qualifier_Struct G_cmdqual[] =
    {
    {"debug", VALUE_NONE, FALSE, NULL},
    {"encoding_table", VALUE_NEEDED, FALSE, NULL},
    {"format", VALUE_NEEDED, FALSE, NULL},
    {"help", VALUE_NONE, FALSE, NULL},
    
# if (OPTIONAL_QUALIFIER_VALUES)
        {"log", VALUE_OPTIONAL, FALSE, NULL},
# else                          /* NOT (OPTIONAL_QUALIFIER_VALUES) */
        {"log", VALUE_NONE, FALSE, NULL},
# endif                         /* (OPTIONAL_QUALIFIER_VALUES) */

    {"mode", VALUE_NEEDED, FALSE, NULL},
    {"overwrite", VALUE_NONE, FALSE, NULL},
    {"record_length", VALUE_NEEDED, FALSE, NULL},
    
# if (OPTIONAL_QUALIFIER_VALUES)
        {"timestamp", VALUE_OPTIONAL, FALSE, NULL},
# else                          /* NOT (OPTIONAL_QUALIFIER_VALUES) */
        {"timestamp", VALUE_NEEDED, FALSE, NULL},
# endif                         /* (OPTIONAL_QUALIFIER_VALUES) */

    {"translation_file", VALUE_NEEDED, FALSE, NULL},

# ifdef  VVENCODE
    {"header_filespec", VALUE_NEEDED, FALSE, NULL},
    {"split_size", VALUE_NEEDED, FALSE, NULL},
# endif                         /* VVENCODE */


# ifdef  VVDECODE
    {"index_file", VALUE_NEEDED, FALSE, NULL},
    {"pad_character", VALUE_NEEDED, FALSE, NULL},
    {"uudecode", VALUE_NONE, FALSE, NULL},
    {"xxdecode", VALUE_NONE, FALSE, NULL},
# endif                         /* VVDECODE */

    {NULL, VALUE_NONE, FALSE, NULL}
};


    static Qualifier_Struct G_cmd_ipfile =
        {"input_file", VALUE_NEEDED, FALSE, NULL};

    static Qualifier_Struct G_cmd_opfile =
        {"output_file", VALUE_NEEDED, FALSE, NULL};

#endif                          /* VVCODE_MAIN */


#define CMDQ_DEBUG              0
#define CMDQ_ENCODE             1
#define CMDQ_FORMAT             2
#define CMDQ_HELP               3
#define CMDQ_LOG                4
#define CMDQ_MODE               5
#define CMDQ_OVERWRITE          6
#define CMDQ_RECORDLEN          7
#define CMDQ_TIMESTAMP          8
#define CMDQ_TRANSLATE          9

#ifdef  VVENCODE
# define CMDQ_HDRFILE           10
# define CMDQ_SPLIT             11
#endif                          /* VVENCODE */

#ifdef  VVDECODE
# define CMDQ_INDEXFILE         10
# define CMDQ_PADCHAR           11
# define CMDQ_UUDECODE          12
# define CMDQ_XXDECODE          13
#endif                          /* VVDECODE */


/*-
**----------------------------------------------------------------------------
** Macros used as convenient flags to test whether certain command line
** arguments and qualifiers are present.
**----------------------------------------------------------------------------
*/
#ifdef  VVCODE_MAIN
# define Q_DEBUG                (G_cmdqual[CMDQ_DEBUG].present == TRUE)
# define Q_ENCODE               (G_cmdqual[CMDQ_ENCODE].present == TRUE)
# define Q_FORMAT               (G_cmdqual[CMDQ_FORMAT].present == TRUE)
# define Q_INPUT_FILE           (G_cmd_ipfile.present == TRUE)
# define Q_LOG                  (G_cmdqual[CMDQ_LOG].present == TRUE)
# define Q_HELP                 (G_cmdqual[CMDQ_HELP].present == TRUE)
# define Q_MODE                 (G_cmdqual[CMDQ_MODE].present == TRUE)
# define Q_OUTPUT_FILE          (G_cmd_opfile.present == TRUE)
# define Q_OVERWRITE            (G_cmdqual[CMDQ_OVERWRITE].present == TRUE)
# define Q_RECORDLEN            (G_cmdqual[CMDQ_RECORDLEN].present == TRUE)
# define Q_TIMESTAMP            (G_cmdqual[CMDQ_TIMESTAMP].present == TRUE)
# define Q_TRANSLATE            (G_cmdqual[CMDQ_TRANSLATE].present == TRUE)

# ifdef  VVENCODE
#  define Q_HEADER_FILE         (G_cmdqual[CMDQ_HDRFILE].present == TRUE)
#  define Q_SPLIT               (G_cmdqual[CMDQ_SPLIT].present == TRUE)
# endif                          /* VVENCODE */

# ifdef  VVDECODE
#  define Q_INDEXFILE           (G_cmdqual[CMDQ_INDEXFILE].present == TRUE)
#  define Q_PADCHAR             (G_cmdqual[CMDQ_PADCHAR].present == TRUE)
#  define Q_UUDECODE            (G_cmdqual[CMDQ_UUDECODE].present == TRUE)
#  define Q_XXDECODE            (G_cmdqual[CMDQ_XXDECODE].present == TRUE)
# endif                          /* VVDECODE */

#endif                          /* VVCODE_MAIN */



/*-
**----------------------------------------------------------------------------
** The VVENCODE file mode strings are recorded in a global string 
** array and indexed using the series of "MODE_" macros defined below.
**----------------------------------------------------------------------------
*/
#ifdef  VVCODE_MAIN
    CONST char              *G_mode_str[] =
    {
    "binary",
    "text",
    NULL
    };
#else                           /* NOT VVCODE_MAIN */
    extern CONST char       *G_mode_str[];
#endif                          /* VVCODE_MAIN */

#define MODE_BINARY             0
#define MODE_TEXT               1


/*-
**----------------------------------------------------------------------------
** The VVENCODE file format strings are recorded in a global string 
** array and indexed using the series of "FMT_" macros defined below.
**----------------------------------------------------------------------------
*/
#ifdef  VVCODE_MAIN
    CONST char              *G_fmt_str[] =
    {
    "default",
    "stream",
    "fixed",
    "variable",
    NULL
    };
#else                           /* NOT VVCODE_MAIN */
    extern CONST char       *G_fmt_str[];
#endif                          /* VVCODE_MAIN */


#define FMT_DEFAULT             0
#define FMT_STREAM              1
#define FMT_FIXED               2
#define FMT_VARIABLE            3



/*-
**============================================================================
**
** SECTION  8 - VVE FILE DEFINITIONS AND PROCESSING
**
**============================================================================
*/

/*-
**----------------------------------------------------------------------------
** Macros fundamental to the VVENCODEd file.
**
**  VV_EOL_MARKER           -   the string appended to every line of VVENCODEd
**                              data to avoid the possibility of a line ending
**                              with a space character which may be
**                              subsequently stripped.
**  VV_PREFIX               -   the string prepended to every line of
**                              VVENCODEd data to help VVDECODE ignore
**                              unwanted lines such as mail headers.
**----------------------------------------------------------------------------
*/
#define VV_EOL_MARKER           "V"
#define VV_PREFIX               "Vv"
#define VV_POSTAMBLE_LEN        60L

#ifdef  VVDECODE
    char                   *G_vv_prefix;
    char                   *G_eol_marker;
#endif                          /* VVDECODE */

#ifdef  VVENCODE
    static CONST char      *G_vv_advert[] =
    {
    "**********************************************************************",
    "**  This is a VVencoded file.  Implementations of VVDECODE and      **",
    "**  VVENCODE are freely available for many different computers and  **",
    "**  operating systems.  The master portable C source is available   **",
    "**  from the Aston University TeX archive - the home of VVCODE.     **",
    "**                                                                  **",
    "**  If you want to find out more about VVCODE, send a message to    **",
    "**  List_Server@TeX.Ac.Uk with the subject text 'HELP VVCODE'       **",
    "**********************************************************************",
    NULL
    };
#endif                          /* VVENCODE */


#ifdef  VVCODE_MAIN
    Header_Struct           G_vvehdr[] =
    {
        {"attrbegin", FALSE, NULL},
        {"attrend", FALSE, NULL},
        {"begin", FALSE, NULL},
        {"bytecount", FALSE, NULL},
        {"characterset", FALSE, NULL},
        {"comment", FALSE, NULL},
        {"crc32", FALSE, NULL},
        {"decodeversion", FALSE, NULL},
        {"end", FALSE, NULL},
        {"format", FALSE, NULL},
        {"mode", FALSE, NULL},
        {"operatingsystem", FALSE, NULL},
        {"recordlength", FALSE, NULL},
        {"skipfrom", FALSE, NULL},
        {"skipto", FALSE, NULL},
        {"table", FALSE, NULL},
        {"timestamp", FALSE, NULL},
        {NULL, FALSE, NULL}
    };
#else                           /* NOT VVCODE_MAIN */
    extern Header_Struct    G_vvehdr;
#endif                          /* VVCODE_MAIN */


#define HDR_UNKNOWN             (-1)
#define HDR_ATTRBEGIN           0
#define HDR_ATTREND             1
#define HDR_BEGIN               2
#define HDR_BYTECOUNT           3
#define HDR_CHARACTERSET        4
#define HDR_COMMENT             5
#define HDR_CRC32               6
#define HDR_DECODEVERSION       7
#define HDR_END                 8
#define HDR_FORMAT              9
#define HDR_MODE                10
#define HDR_OPERATINGSYSTEM     11
#define HDR_RECORDLEN           12
#define HDR_SKIPFROM            13
#define HDR_SKIPTO              14
#define HDR_TABLE               15
#define HDR_TIMESTAMP           16


/*-
**----------------------------------------------------------------------------
** Macros used as convenient flags to test whether certain VVE header lines
** and arguments have been read.
**----------------------------------------------------------------------------
*/
#ifdef  VVDECODE

# define VVEH_ATTRBEGIN         (G_vvehdr[HDR_ATTRBEGIN].present == TRUE)
# define VVEH_ATTREND           (G_vvehdr[HDR_ATTREND].present == TRUE)
# define VVEH_BEGIN             (G_vvehdr[HDR_BEGIN].present == TRUE)
# define VVEH_BYTECOUNT         (G_vvehdr[HDR_BYTECOUNT].present == TRUE)
# define VVEH_CHARACTERSET      (G_vvehdr[HDR_CHARACTERSET].present == TRUE)
# define VVEH_COMMENT           (G_vvehdr[HDR_COMMENT].present == TRUE)
# define VVEH_CRC32             (G_vvehdr[HDR_CRC32].present == TRUE)
# define VVEH_DECODEVERSION     (G_vvehdr[HDR_DECODEVERSION].present == TRUE)
# define VVEH_END               (G_vvehdr[HDR_END].present == TRUE)
# define VVEH_FORMAT            (G_vvehdr[HDR_FORMAT].present == TRUE)
# define VVEH_MODE              (G_vvehdr[HDR_MODE].present == TRUE)
# define VVEH_OPERATINGSYSTEM   (G_vvehdr[HDR_OPERATINGSYSTEM].present == TRUE)
# define VVEH_RECORDLEN         (G_vvehdr[HDR_RECORDLEN].present == TRUE)
# define VVEH_SKIPFROM          (G_vvehdr[HDR_SKIPFROM].present == TRUE)
# define VVEH_SKIPTO            (G_vvehdr[HDR_SKIPTO].present == TRUE)
# define VVEH_TABLE             (G_vvehdr[HDR_TABLE].present == TRUE)
# define VVEH_TIMESTAMP         (G_vvehdr[HDR_TIMESTAMP].present == TRUE)

#endif                          /* VVDECODE */



/*-
**============================================================================
**
** SECTION  9 - XLT FILE DEFINITIONS AND PROCESSING
**
**============================================================================
*/
#define XLT_COMMENT_CHAR        '#'
#define IDX_COMMENT_CHAR        '#'

#ifdef  VVCODE_MAIN
    Header_Struct           G_xlthdr[] =
    {
        {"xlt-from", FALSE, NULL},
        {"xlt-to", FALSE, NULL},
        {"xlt-substchar", FALSE, NULL},
        {NULL, FALSE, NULL}
    };
#else                           /* NOT VVCODE_MAIN */
    extern Header_Struct    G_xlthdr[];
#endif                          /* VVCODE_MAIN */


/*-
**----------------------------------------------------------------------------
** Macros used as convenient flags to test whether certain XLT header lines
** and arguments have been read.
**----------------------------------------------------------------------------
*/
#define HDR_XLT_UNKNOWN         (-1)
#define HDR_XLT_FROM            0
#define HDR_XLT_TO              1
#define HDR_XLT_SUBSTCHAR       2


/*-
**============================================================================
**
** SECTION 10 - MACROS USED IN LIEU OF VARIABLE LENGTH ARGUMENT LISTS
**
**============================================================================
*/


/*-
**----------------------------------------------------------------------------
** Internal error message
**----------------------------------------------------------------------------
*/
#define INTERNAL_ERROR(_caller)\
            SPRINTF (G_tmp_msg, "Internal error detected in %s()", _caller);\
            user_message (FATAL_STATUS, G_tmp_msg, &G_log_file); \
            vv_exit ()


/*-
**----------------------------------------------------------------------------
** Log file messages
**----------------------------------------------------------------------------
*/
#define LOGMSG(_fmt) \
	    user_message (LOG_STATUS, _fmt, &G_log_file)

#define LOGMSG_1(_fmt, _arg1) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1); \
	    user_message (LOG_STATUS, G_tmp_msg, &G_log_file)

#define LOGMSG_2(_fmt, _arg1, _arg2) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2); \
	    user_message (LOG_STATUS, G_tmp_msg, &G_log_file)

#define LOGMSG_3(_fmt, _arg1, _arg2, _arg3) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3); \
	    user_message (LOG_STATUS, G_tmp_msg, &G_log_file)

#define LOGMSG_4(_fmt, _arg1, _arg2, _arg3, _arg4) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3, _arg4); \
	    user_message (LOG_STATUS, G_tmp_msg, &G_log_file)


/*-
**----------------------------------------------------------------------------
** Explanatory messages
**----------------------------------------------------------------------------
*/
#define INFOMSG(_fmt) \
	    user_message (INFO_STATUS, _fmt, &G_log_file)

#define INFOMSG_1(_fmt, _arg1) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1); \
	    user_message (INFO_STATUS, G_tmp_msg, &G_log_file)

#define INFOMSG_2(_fmt, _arg1, _arg2) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2); \
	    user_message (INFO_STATUS, G_tmp_msg, &G_log_file)

#define INFOMSG_3(_fmt, _arg1, _arg2, _arg3) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3); \
	    user_message (INFO_STATUS, G_tmp_msg, &G_log_file)

#define INFOMSG_4(_fmt, _arg1, _arg2, _arg3, _arg4) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3, _arg4); \
	    user_message (INFO_STATUS, G_tmp_msg, &G_log_file)


/*-
**----------------------------------------------------------------------------
** Warning messages
**----------------------------------------------------------------------------
*/
#define WARNMSG(_fmt) \
	    user_message (WARNING_STATUS, _fmt, &G_log_file)

#define WARNMSG_1(_fmt, _arg1) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1); \
	    user_message (WARNING_STATUS, G_tmp_msg, &G_log_file)

#define WARNMSG_2(_fmt, _arg1, _arg2) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2); \
	    user_message (WARNING_STATUS, G_tmp_msg, &G_log_file)

#define WARNMSG_3(_fmt, _arg1, _arg2, _arg3) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3); \
	    user_message (WARNING_STATUS, G_tmp_msg, &G_log_file)

#define WARNMSG_4(_fmt, _arg1, _arg2, _arg3, _arg4) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3, _arg4); \
	    user_message (WARNING_STATUS, G_tmp_msg, &G_log_file)


/*-
**----------------------------------------------------------------------------
** Error messages
**----------------------------------------------------------------------------
*/
#define ERRORMSG(_fmt) \
	    user_message (ERROR_STATUS, _fmt, &G_log_file)

#define ERRORMSG_1(_fmt, _arg1) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1); \
	    user_message (ERROR_STATUS, G_tmp_msg, &G_log_file)

#define ERRORMSG_2(_fmt, _arg1, _arg2) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2); \
	    user_message (ERROR_STATUS, G_tmp_msg, &G_log_file)

#define ERRORMSG_3(_fmt, _arg1, _arg2, _arg3) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3); \
	    user_message (ERROR_STATUS, G_tmp_msg, &G_log_file)

#define ERRORMSG_4(_fmt, _arg1, _arg2, _arg3, _arg4) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3, _arg4); \
	    user_message (ERROR_STATUS, G_tmp_msg, &G_log_file)


/*-
**----------------------------------------------------------------------------
** Fatal error messages
**----------------------------------------------------------------------------
*/
#define FATALMSG(_fmt) \
	    user_message (FATAL_STATUS, _fmt, &G_log_file)

#define FATALMSG_1(_fmt, _arg1) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1); \
	    user_message (FATAL_STATUS, G_tmp_msg, &G_log_file)

#define FATALMSG_2(_fmt, _arg1, _arg2) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2); \
	    user_message (FATAL_STATUS, G_tmp_msg, &G_log_file)

#define FATALMSG_3(_fmt, _arg1, _arg2, _arg3) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3); \
	    user_message (FATAL_STATUS, G_tmp_msg, &G_log_file)

#define FATALMSG_4(_fmt, _arg1, _arg2, _arg3, _arg4) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3, _arg4); \
	    user_message (FATAL_STATUS, G_tmp_msg, &G_log_file)


/*-
**----------------------------------------------------------------------------
** Usage error messages
**----------------------------------------------------------------------------
*/
#define USAGE(_fmt) \
	    usage_error (_fmt)

#define USAGE_1(_fmt, _arg1) \
	    SPRINTF (G_tmp_msg, _fmt, _arg1); \
            usage_error (G_tmp_msg)

#define USAGE_2(_fmt, _arg1, _arg2) \
            SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2); \
            usage_error (G_tmp_msg)

#define USAGE_3(_fmt, _arg1, _arg2, _arg3) \
            SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3); \
            usage_error (G_tmp_msg)

#define USAGE_4(_fmt, _arg1, _arg2, _arg3, _arg4) \
            SPRINTF (G_tmp_msg, _fmt, _arg1, _arg2, _arg3, _arg4); \
            usage_error (G_tmp_msg)


/*-
**----------------------------------------------------------------------------
** DEBUG messages
**----------------------------------------------------------------------------
*/
#if (VV_DEBUG_SUPPORT)

# define DEBUG(_fmt) \
            if (G_debugging == TRUE)\
            {\
                FPRINTF (stderr, "DEBUG: ");\
                FPRINTF (stderr, _fmt);\
                FPRINTF (stderr, "\n");\
            }
            
# define DEBUG_1(_fmt, _arg1) \
            if (G_debugging == TRUE)\
            {\
                FPRINTF (stderr, "DEBUG: ");\
                FPRINTF (stderr, _fmt, _arg1);\
                FPRINTF (stderr, "\n");\
            }

# define DEBUG_2(_fmt, _arg1, _arg2) \
            if (G_debugging == TRUE)\
            {\
                FPRINTF (stderr, "DEBUG: ");\
                FPRINTF (stderr, _fmt, _arg1, _arg2);\
                FPRINTF (stderr, "\n");\
            }

# define DEBUG_3(_fmt, _arg1, _arg2, _arg3) \
            if (G_debugging == TRUE)\
            {\
                FPRINTF (stderr, "DEBUG: ");\
                FPRINTF (stderr, _fmt, _arg1, _arg2, _arg3);\
                FPRINTF (stderr, "\n");\
            }

# define DEBUG_4(_fmt, _arg1, _arg2, _arg3, _arg4) \
            if (G_debugging == TRUE)\
            {\
                FPRINTF (stderr, "DEBUG: ");\
                FPRINTF (stderr, _fmt, _arg1, _arg2, _arg3, _arg4);\
                FPRINTF (stderr, "\n");\
            }

#else                           /* NOT (VV_DEBUG_SUPPORT) */

# define DEBUG(_fmt)
# define DEBUG_1(_fmt, _arg1)
# define DEBUG_2(_fmt, _arg1, _arg2)
# define DEBUG_3(_fmt, _arg1, _arg2, _arg3)
# define DEBUG_4(_fmt, _arg1, _arg2, _arg3, _arg4)

#endif                          /* (VV_DEBUG_SUPPORT) */



/*-
**----------------------------------------------------------------------------
** Writing to the VVE file
**----------------------------------------------------------------------------
*/
#ifdef  VVENCODE

# define VVEOUT(_fmt) \
            SPRINTF (G_op_buffer, _fmt); \
            { \
                Int32 msg_length; \
                msg_length = (Int32) strlen (G_op_buffer); \
                write_bytes (msg_length, G_op_buffer, &G_op_file); \
                G_oppart_bytes += msg_length + (Int32) TEXT_LINE_OVERHEAD; \
            }

# define VVEOUT_1(_fmt, _arg1) \
            SPRINTF (G_op_buffer, _fmt, _arg1); \
            { \
                Int32 msg_length; \
                msg_length = (Int32) strlen (G_op_buffer); \
                write_bytes (msg_length, G_op_buffer, &G_op_file); \
                G_oppart_bytes += msg_length + (Int32) TEXT_LINE_OVERHEAD; \
            }

# define VVEOUT_2(_fmt, _arg1, _arg2) \
            SPRINTF (G_op_buffer, _fmt, _arg1, _arg2); \
            { \
                Int32 msg_length; \
                msg_length = (Int32) strlen (G_op_buffer); \
                write_bytes (msg_length, G_op_buffer, &G_op_file); \
                G_oppart_bytes += msg_length + (Int32) TEXT_LINE_OVERHEAD; \
            }

# define VVEOUT_3(_fmt, _arg1, _arg2, _arg3) \
            SPRINTF (G_op_buffer, _fmt, _arg1, _arg2, _arg3); \
            { \
                Int32 msg_length; \
                msg_length = (Int32) strlen (G_op_buffer); \
                write_bytes (msg_length, G_op_buffer, &G_op_file); \
                G_oppart_bytes += msg_length + (Int32) TEXT_LINE_OVERHEAD; \
            }

# define VVEOUT_4(_fmt, _arg1, _arg2, _arg3, _arg4) \
            SPRINTF (G_op_buffer, _fmt, _arg1, _arg2, _arg3, _arg4); \
            { \
                Int32 msg_length; \
                msg_length = (Int32) strlen (G_op_buffer); \
                write_bytes (msg_length, G_op_buffer, &G_op_file); \
                G_oppart_bytes += msg_length + (Int32) TEXT_LINE_OVERHEAD; \
            }

# define VVEOUT_5(_fmt, _arg1, _arg2, _arg3, _arg4, _arg5) \
            SPRINTF (G_op_buffer, _fmt, _arg1, _arg2, _arg3, _arg4, _arg5); \
            { \
                Int32 msg_length; \
                msg_length = (Int32) strlen (G_op_buffer); \
                write_bytes (msg_length, G_op_buffer, &G_op_file); \
                G_oppart_bytes += msg_length + (Int32) TEXT_LINE_OVERHEAD; \
            }

#endif                          /* VVENCODE */




/*-
**============================================================================
**
** SECTION 11 - MISCELLANEOUS BODGES
**
**============================================================================
*/
#ifndef VVCODE_MAIN
    void                        usage_error ARGS ((CONST char *reason));
#endif                          /* VVCODE_MAIN */