/*
 * Jeffrey Friedl
 * Omron Corporation			¥ª¥à¥í¥ó¡Ê³ô¡Ë
 * Nagaokakyoshi, Japan			¢©617Ä¹²¬µþ²¼³¤°õ»û
 *
 * jfriedl@nff.ncl.omron.co.jp
 *
 * This work is placed under the terms of the GNU General Purpose License
 * (the "GNU Copyleft").
 */

/*
 * This program contains EUC-encoded Japanese text.
 * If some 8bit-unfriendly program were to strip it, things won't compile.
 * If this box -->[ª¯]<-- is empty, this file is OK. If you see a comment-
 * close there, it's been stripped and you're screwed.
 */

#ifndef MAX_LOADED_FILES
# define MAX_LOADED_FILES 10
#endif
#ifndef MAX_PATS_ON_ONE_LINE
# define MAX_PATS_ON_ONE_LINE  10
#endif

/* set defaults */
#define HAVE_SPINNER
#define LOG_FILE_SUPPORT

#include "lib/virtfile.h"

/*
 * SERVER_CONFIG
 * See the comments in lookup.c at service_socket() for info about
 * the lookup server.
 */
#ifdef SERVER_CONFIG
# undef LOG_FILE_SUPPORT
# undef HAVE_SPINNER
# define SERV_TCP_PORT 9827 /* some random number */
#else
# ifndef USE_LOCAL_OUTPUT
#  undef LOG_FILE_SUPPORT
# endif
#endif

#define string unsigned char
#define String const unsigned char

struct flags
{
    unsigned word:1;     /* if true, whole-word matches take precidence */
    unsigned fuzz:1;     /* if true, fuzzification done when appropriate */
    unsigned fold:1;     /* if true, case folding on */
    unsigned highlight:1;/* if true, matched part of line highlighted */
    unsigned filter:1;   /* if true, FILTER_SPEC exists and is enabled */
    unsigned modify:1;   /* if true, MODIFY_SPEC exists and is enabled */
    unsigned autokana:1; /* if true, automatic kana conversion on */
    unsigned tag:1;      /* if true, TAG_STRING prepended to matched lines */
    unsigned display:1;  /* if true, matching lines are shown */
    unsigned glob:1;     /* if true, patterns are wildcard globs, not regexes */

    /* the following only used in lookup.flags */
    unsigned debug:1;
    unsigned regex_debug:1;
    unsigned cmd_debug:1;
    unsigned verbose:1;
    unsigned hl_style:4;
      #define HL_STYLE_INVERSE   0
      #define HL_STYLE_BOLD      1
      #define HL_STYLE_UNDERLINE 2
      #define HL_STYLE_FLASH     3
      #define HL_STYLE_RED       4
      #define HL_STYLE_GREEN     5
      #define HL_STYLE_YELLOW    6
      #define HL_STYLE_BLUE      7
      #define HL_STYLE_PURPLE    8
      #define HL_STYLE_CYAN      9
      #define HL_STYLE_WHITE    10
      #define HL_STYLE_BLACK    11
      #define HL_STYLE_HTML     12 /* text in highlight_tag below */

    #define DECL_STYLES const char *styles[] =                               \
    {                                                                        \
	"\033[7m" , /* inverse */                                            \
	"\033[1m" , /* bold */                                               \
	"\033[4m" , /* underline */                                          \
	"\033[5m" , /* flashing */                                           \
	"\033[31m", /* red */                                                \
	"\033[32m", /* green */                                              \
	"\033[33m", /* yellow */                                             \
	"\033[34m", /* blue */                                               \
	"\033[35m", /* purple */                                             \
	"\033[36m", /* cyan */                                               \
	"\033[37m", /* white */                                              \
	"\033[30m", /* black */                                              \
    };

};

/*
 * Stuff about a file loaded in a slot.
 */
struct slot_info
{
    struct flags default_flag; /* Flags as they apply to this file.       */
    struct flags current_flag; /* Flags as they apply during a command    */
    String *prompt_format;     /* prompt string specific for this file    */
    struct fileinfo *file;     /* File and index (null if a COMBO)        */
    
    union
    {
	struct {
	    struct {                 /* The modify info, if any.           */
		String *pattern;     /* Regex to match (null if no modify) */
		regex_t regex;       /* The compiled regex itself.         */
		String *replacement; /* String to replace.                 */
		unsigned global;     /* True if it's a global replacement. */
	    } _modify_;
            #define modify_spec onefile_or_combo.onefile._modify_

	    struct {                 /* The filter info, if any.           */
		String *pattern;     /* Regex to match (null if no filte)  */
		regex_t regex;       /* The compiled regex itself.         */
		String *name;        /* Optional name of the filter.       */
		unsigned negative:1; /* True if "filter if no match".      */
	    } _filter_;
            #define filter_spec onefile_or_combo.onefile._filter_

	    String *_tag_;       /* string to print before each output line */
	    #define tag_string  onefile_or_combo.onefile._tag_

	    String *_highlight_tag_; /* for HTML highlighting */
	    #define highlight_tag onefile_or_combo.onefile._highlight_tag_
	} onefile;
	struct
	{
	    String *name;  /* name of combo */
	    unsigned char entries;
	    unsigned char entry[MAX_LOADED_FILES];
	} _combo_;
        #define combo onefile_or_combo._combo_
    } onefile_or_combo;
};

#define COMBO(SLOT_INFO) ((SLOT_INFO)->file == 0)

/*
 * General global variables.
 */
struct lookup
{
    struct flags flag;
    unsigned char cmdstart_char;
    unsigned char percent;
    long int max_lines_to_print;
    long int lines_to_print_this_time;

    String *prompt_format;    /* current prompt format string */

    struct slot_info *slot_info[MAX_LOADED_FILES];
    unsigned slots;  /* number of used entries in slot[] */
    struct slot_info *default_slot;   /* the default selected slot */
    struct slot_info *slot;  /* slot to use for this command */

    String *where; /* for error messages, indicates source of command */
    const char *prog; /* argv[0] */
    const char *prog_short; /* prog, but with any leading path stripped */

    struct        /* various line counts, grouped for clarity. */
    {
	unsigned long checked;  /* lines checked during search. */
	unsigned long matched;  /* lines that matched during search. */
	unsigned long printed;  /* lines printed during search. */
	unsigned long nonword;  /* nonword lines elided during search. */
	unsigned long filtered; /* filtered lines elided during search. */
    } count;

    struct       /* the saved-line info */
    {
	struct {
	    const struct slot_info *slot;
	    fileloc line;
	} *array;
	unsigned size;           /* Size of array[]. */
	unsigned used;           /* Elements of array[] currently used. */
	unsigned overflow;       /* Number of elements that couldn't fit. */
    } list;

    struct      /* regexes we need to check. */
    {
	String *pattern;           /* Regex string                       */
	regex_t regex;             /* Actual compiled regex.             */
	unsigned char not;         /* True if we want nonmatching lines. */
    } search[MAX_PATS_ON_ONE_LINE];
    int patterns; /* valid elements in search[] */

 #ifdef HAVE_SPINNER
    struct     /* stuff to do with the spinner */
    {
	String *chars;
	unsigned short interval;
	unsigned char char_count;
    } spinner;
 #endif /* HAVE_SPINNER */
};


/*
 * Flags for read_command_from_file() and parse_command().
 */
#define CMD_GENERAL   		0x0001
#define CMD_FILE_ONLY 		0x0010 /* command allowed only in a script  */
#define CMD_INTERACTIVE		0x0020 /* command not allowed in a file     */
#define CMD_LOAD_RELATED        0x0040 /* skip in .lookup if cmdline load   */
#define CMD_ENCODING_RELATED    0x0080 /* skip in .lookup if cmdline -jis   */
#define CMD_NEEDS_SLOT          0x0100 /* only allow if lookup.slot defined */
#define _IS_COMPILED_           0x1000 /* -- private -- */


/*
 * Possible return values of parse_command()
 */
#define COMMAND_EXECUTED_OK		10
#define COMMAND_EXECUTED_WITH_ERROR	11
#define COMMAND_NOT_FOUND		12
#define COMMAND_SKIPPED	                13

/*
 * Return value of read_commands_from_file()
 */
#define FILE_READ_OK			0
#define FILE_NOT_FOUND			1
#define FILE_HAS_UNKNOWN_COMMAND	2
#define FILE_HAS_BAD_COMMAND		3

/* defined in lookup.c */
extern struct lookup lookup;
extern const char *expand_filename_tilde(const char *filename);
extern String *gen_prompt(String *template, int showerror);
extern int slot_num(struct slot_info *s);
extern int load_file(const char *filename, unsigned flag);
extern void process_input_line(string *input, int forced_search);
extern int exit_program_now;
extern String *current_log_file;

/* defined in command.c */
extern int cmd_list_size(String *spec);
extern int cmd_show(void);
extern int cmd_output_encoding(String *, String *, String *, String *);
extern int cmd_version(void);
extern int parse_command(String *, unsigned, unsigned, unsigned);
extern int quick_command(String *str);
extern int read_commands_from_file(const char *, unsigned, unsigned);
extern int cmd_log(int closelog, int append, String *file);
/* defined in apply_regex.c */
extern unsigned linelength(const struct fileinfo *fileinfo, String *line);
extern void output_line(const struct slot_info *, String *, unsigned);
extern void apply_regex(void);
extern volatile unsigned apply_regex_abort;

/* defined in version.c */
extern const char version_string[];
extern const char version_date[];
extern const char compile_date[];
extern const char author_name[];
extern const char contact_addr[];


/*
 * General cruft.
 */
#define array_elements(array)	(sizeof(array)/sizeof(array[0]))

#define generic(ptr)    ((void *)(string *)(ptr))
#define Generic(ptr)    ((void *)(String *)(ptr))

#define str_len(X)          strlen(Generic(X))
#define strNcmp(X, Y, LEN)  strncmp(Generic(X), Generic(Y), (LEN))
#define str_cmp(X, Y)       strcmp(Generic(X), Generic(Y))
#define str_cpy(X, Y)       strcpy(generic(X), Generic(Y))
#define str_cat(X, Y)       strcat(generic(X), Generic(Y))
#define str_eql(X, Y)       (!str_cmp((X), (Y)))

#if !defined(__GNUC__)
#  if !defined(__volatile__)
#    define __volatile__ /*nothing; for use with volatile functions */
#  endif
#  if !defined(__inline__)
#    define __inline__ /*nothing; for use with volatile functions */
#  endif
#endif

#if 1
# define quote(stuff) "¡È"  #stuff "¡É"   /* do it like ¡Èthis¡É */
#else
# define quote(stuff) " \"" #stuff "\" " /* do it like "this"   */
# define quote(stuff) " ``" #stuff "'' " /* do it like ``this'' */
# define quote(stuff) " `"  #stuff "' "  /* do it like `this'   */
# define quote(stuff) "¡Ì"  #stuff "¡Í"  /* do it like ¡Ìthis¡Í */
# define quote(stuff) "¡Ú"  #stuff "¡Û"  /* do it like ¡Úthis¡Û */
# define quote(stuff) "¡Ø"  #stuff "¡Ù"  /* do it like ¡Øthis¡Ù */
# define quote(stuff) "¡Ö"  #stuff "¡×"  /* do it like ¡Öthis¡× */
# define quote(stuff) "¡Ô"  #stuff "¡Õ"  /* do it like ¡Ôthis¡Õ */
# define quote(stuff) "¡Æ"  #stuff "¡Ç"  /* do it like ¡Æthis¡Ç */
# define quote(stuff) "¢ª"  #stuff "¢«"  /* do it like ¢ªthis¢« */
#endif

/* some general system-V stuff */
#if defined(__svr4__) || defined(__DGUX__)
# define index strchr
# define rindex strrchr
# define bcopy(FROM, TO, LENGTH) memcpy(TO, FROM, LENGTH)
# if !defined(__DGUX__) /* DGUX memset is broken */
#   define bzero(ADDR, LENGTH)     memset(ADDR, LENGTH, 0)
# endif
#endif
