/* infocom.c
 *
 *  ``pinfocom'' -- a portable Infocom Inc. data file interpreter.
 *  Copyright (C) 1987-1992  InfoTaskForce
 *
 *  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 2 of the License, 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; see the file COPYING.  If not, write to the
 *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * $Header: RCS/infocom.c,v 3.0 1992/10/21 16:56:19 pds Stab $
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>

#include "infocom.h"
#include "patchlevel.h"

#define COPYRIGHT   "\n\
    This program comes with ABSOLUTELY NO WARRANTY.\n\
    This program is free software, and you are welcome to redistribute it\n\
    under certain conditions; see the file COPYING in the source directory\n\
    for full details.\n"

#define USAGE       "Usage: %-8s [-aAehoOpPstTvV] [-c context] [-i indent] [-l lines]\n\t\t[-m margin] [-r savefile] "
#define OPTIONS     "aAc:ehi:l:m:oOpPr:stTvV"

#ifndef RMARGIN
#define RMARGIN 2
#endif
#ifndef LMARGIN
#define LMARGIN 0
#endif
#ifndef CONTEXT
#define CONTEXT 2
#endif

header_t    data_head;
obj_info_t  objd;
gflags_t    gflags;
file_t      file_info;

word        random1;
word        random2;
word        pc_offset;
word        pc_page;
word        resident_blocks;
word        save_blocks;

byte        *base_ptr;
byte        *base_end;
byte        *vocab;
byte        *global_ptr;
byte        *end_res_p;
word        *stack_base;
word        *stack_var_ptr;
word        *stack;

byte        *prog_block_ptr;

/* Score Routine Variables */

char        *ti_location;
char        *ti_status;

/* Input Routine Variables */

byte        *wsbf_strt;
byte        *end_of_sentence;
word        num_vocab_words;
word        vocab_entry_size;
byte        *strt_vocab_table;
byte        *end_vocab_table;

/* Print Routine Variables */

byte        *common_word_ptr;
print_buf_t *pbf_p;

char ws_table[] = { ' ','\t','\r','.',',','?','\0','\0' };

char table[] =
{
    'a','b','c','d','e','f','g','h','i','j','k','l','m',
    'n','o','p','q','r','s','t','u','v','w','x','y','z',
    'A','B','C','D','E','F','G','H','I','J','K','L','M',
    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
    ' ',' ','0','1','2','3','4','5','6','7','8','9','.',
    ',','!','?','_','#','\'','"','/','\\','-',':','(',')',
    '\0','\0'
};


static void
usage A1(const char *, name)
{
    extern const char *scr_usage;
    extern const char *scr_long_usage;

    const char *cp;

    for (cp = &name[strlen(name)-1];
         cp>=name && (isalnum(*cp) || (*cp=='.') || (*cp=='_') || (*cp=='-'));
         --cp)
    {}

    fprintf(stdout, USAGE, cp+1);
    fprintf(stdout, "%s%s[filename]\n",
            scr_usage, *scr_usage ? " " : "");

    fprintf(stdout,
           "\nPortable Infocom Datafile Interpreter:  Version %d.%d\n",
           VERSION, PATCHLEVEL);
    puts(COPYRIGHT);

    puts("\
\t-h\toutput the data file header\n\
\t-o\toutput object names, attributes and links\n\
\t-O\toutput object tree\n\
\t-v\toutput the game vocabulary\n\
\t-V\tverify the game data file\n\n\
\t-a\tdisplay changes to object attributes while playing\n\
\t-A\tdisplay value tests of object attributes while playing\n\
\t-c #\tset # of context lines to keep when paging\n\
\t-e\techo each command before executing\n\
\t-i #\tindent game output # of spaces\n\
\t-l #\tset # of screen lines\n\
\t-m #\tset # of spaces as right margin\n\
\t-p\tdon't page long output\n\
\t-P\tset alternate prompt flag\n\
\t-r file\trestore saved game file after starting up\n\
\t-s\tdon't display status line\n\
\t-t\tdisplay changes to object tree while playing\n\
\t-T\tset Tandy licensing flag\n");

    if (scr_long_usage != NULL)
        puts(scr_long_usage);
}


void
seed_random()
{
    extern word     random1;
    extern word     random2;
#ifdef NO_RANDOM
    random1 = 0xFFFF;
    random2 = 0xFFFF;
#else
    random1 = time(0) >> 16;
    random2 = time(0) & 0xFFFF;
#endif
}


int
main A2(int, argc, char **, argv)
{
    extern int atoi P((const char *));
    extern int getopt P((int, char* const*, const char *));
    extern int  optind;
    extern char *optarg;

    extern char sname[];
    extern const char *scr_opt_list;

    char        *cmd_name;
    char        *optlist;
    char        *snm    = NULL;
    Bool        head    = 0;
    Bool        objs    = 0;
    Bool        vocab1  = 0;
    Bool        tree    = 0;
    Bool        verfy   = 0;
    Bool        play    = 1;
    Bool        prompt  = 0;
    Bool        tandy   = 0;
    int         margin  = RMARGIN;
    int         indent  = LMARGIN;
    int         lines   = 0;
    int         context = CONTEXT;
    int         width;
    int         c;

    cmd_name = argv[0];

    if ((argc = scr_cmdarg(argc, &argv)) == 0)
    {
        usage(cmd_name);
        return (1);
    }

    gflags.filenm = NULL;
    gflags.paged = 1;
    gflags.pr_status = 1;

    optlist = xmalloc(sizeof(OPTIONS) + strlen(scr_opt_list));

    strcpy(optlist, OPTIONS);
    strcat(optlist, scr_opt_list);

    while ((c = getopt(argc, argv, optlist)) != -1)
    {
        switch (c)
        {
            case 'a':
                gflags.pr_attr = 1;
                break;
            case 'A':
                gflags.pr_atest = 1;
                break;
            case 'c':
                context = atoi(optarg);
                break;
            case 'e':
                gflags.echo = 1;
                break;
            case 'h':
                head = 1;
                play = 0;
                break;
            case 'i':
                indent = atoi(optarg);
                break;
            case 'l':
                lines = atoi(optarg);
                break;
            case 'm':
                margin = atoi(optarg);
                break;
            case 'o':
                objs = 1;
                play = 0;
                break;
            case 'O':
                tree = 1;
                play = 0;
                break;
            case 'p':
                gflags.paged = 0;
                break;
            case 'P':
                prompt = 1;
                break;
            case 'r':
                snm = optarg;
                break;
            case 's':
                gflags.pr_status = 0;
                break;
            case 't':
                gflags.pr_xfers = 1;
                break;
            case 'T':
                tandy = 1;
                break;
            case 'v':
                vocab1 = 1;
                play = 0;
                break;
            case 'V':
                verfy = 1;
                play = 0;
                break;
            default:
                scr_getopt(c, optarg);
                break;

            case '?':
                usage(cmd_name);
                return (1);
        }
    }

    gflags.game_state = NOT_INIT;

    width = scr_setup(margin, indent, lines, context);

    /*
     * Open the game file, if possible...
     */
    if ((argc > optind+1)
        || ((gflags.filenm = open_file(argv[optind])) == NULL))
    {
        usage(cmd_name);
        return (1);
    }

    init();

    if (play)
    {
        check_version();

        scr_begin();

        gflags.game_state = INIT_GAME;

        if (snm != NULL)
        {
            strcpy(sname, snm);
            restore();
            gflags.game_state = PLAY_GAME;
        }
        else
            change_status();

        if (tandy)
            F1_SETB(B_TANDY);
        if (prompt)
            F1_SETB(B_ALT_PROMPT);

        interp();

        scr_end();
    }
    else
    {
        if (snm != NULL)
        {
            strcpy(sname, snm);
            restore();
        }

        pbf_p->max = width;
        options(verfy, head, objs, vocab1, tree);
    }

    scr_shutdown();

    return (0);
}