/*************************************************************************
 ***                        main.c                       (JJB TEMPLAR) ***
 *** Date modifications begun: 7/8/89.                                 ***
 *** Last modified: 28/8/89.                                           ***
 *************************************************************************/
/*** Ahem. Here we go...                                               ***
 *************************************************************************/

#include "less.h"
#include "position.h"

#include <workbench/startup.h>
#include <exec/memory.h>

extern struct WBStartup *WBenchMsg;
char                    *filename;
struct WBArg            *wbArgs;

int         new_file;
char        current_file[128];
int         ac;
int         curr_ac;

static struct Remember *RemKey;

struct IntuitionBase    *IntuitionBase;
struct GfxBase          *GfxBase;
struct IconBase         *IconBase;

extern BPTR file;
extern int  nbufs;
extern int  quit_at_eof;
extern int  f_nbufs;
extern int  back_scroll;
extern int  top_scroll;
extern int  sc_height;
extern char version[];      /* Version string. */
extern struct Window *Window;

void    dolibs();
BPTR    OpenArg(struct WBArg *);
void    edit(int);
void    add_file();
void    next_file(int);
void    prev_file(int);
void    printf(char *);
char    *strint(int);
void    sprintf();
void    cleanup(char *,int);

void    dolibs() /*======================================================*/
{
    if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L)))
        cleanup("ERROR: failed to open intuition.library!\n",20);
    if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L)))
        cleanup("ERROR: failed to open graphics.library!\n",20);
    if (!(IconBase = (struct IconBase *)OpenLibrary("icon.library",0L)))
        printf("WARNING: failed to open icon.library!\n");
}

BPTR    OpenArg(wa) /*===================================================*/
struct WBArg *wa;   /* All these mixed-case function names!              */
{
LONG    olddir;
BPTR    file;

    if (wa->wa_Lock) olddir = CurrentDir(wa->wa_Lock);
    file = Open(wa->wa_Name, MODE_OLDFILE);

    if (wa->wa_Lock) CurrentDir(olddir);    /* Why move back? For CLI? */
    return(file);
}

void    edit(filenum) /*=================================================*/
int     filenum;      /* Move to file number "filenum" in wbArgs[].      */
{
long    f;
char    message[100];
static int  any_edited  = 0;
static int  hold_scroll = 0;

    if (!filenum) {
        if (curr_ac >= ac) {
            error("No current file",1);
            return;
        }
        filenum = curr_ac;
    }

    filename = wbArgs[curr_ac].wa_Name;
    if (!(f = OpenArg(&wbArgs[filenum]))) {
        sprintf(message, "Cannot open %s!", filename);
        if (any_edited) error(message,0);   /* Where to put error? In */
        else {                              /* status line if a file */
            puts(message);                  /* has already been opened, */
            flush();                        /* or to screen if not. */
          /* Wait two seconds for him to read message */
            Delay(100L);
            hold_scroll = 1;
        }
        return;
    }

  /* Close the current input file and set up to use the new one. */
    if (file > 0) Close(file);
    new_file = 1;               /* Flag it (for prompt.c) */
    strcpy(current_file, filename);
    file = f;
    opticon(filename);          /* Check icon for args */
    ch_init(f_nbufs);
    init_mark();                /* Just clears all the marks. */
    any_edited = 1;             /* Flag this (for error message above) */

    if (hold_scroll) {
      /* Before erasing screen, display filename and ask for a keystroke. */
        error(filename,1);
        hold_scroll = 0;        /* New edit, error message from previous */
    }                          /* file still on screen (not error line). */

    jump_back(1);               /* Jump to line 1 of new file. */
    setbar(2);                  /* Complete reset of scroll bar. */
}

void    add_file() /*====================================================*/
{
    if (ac >= MAXAC) error("No room in table for new file!",0);
    else {
        wbArgs[ac].wa_Name = AllocRemember(&RemKey,250,MEMF_CLEAR);
        if (!wbArgs[ac].wa_Name) error("No space for filename!",0);
        else {
            if (!r_string("Filename",wbArgs[ac].wa_Name,249)) return;
            wbArgs[ac].wa_Lock = NULL;
            ac++;
            edit(curr_ac = ac - 1);
        }
    }
}

void    next_file(n) /*==================================================*/
int     n;
{
    if (curr_ac + n >= ac) {
        if (quit_at_eof) cleanup(NULL,0);
        error("No next file!",0);
    }
    else edit(curr_ac += n);
}

void    prev_file(n) /*==================================================*/
int     n;
{
    if (curr_ac - n < 0) error("No previous file!",0);
    else edit(curr_ac -= n);
}

void    main(argc,argv) /*===============================================*/
int     argc;
char    **argv;
{
register int    i,j;
struct WBArg cliArgs[MAXAC];

    dolibs();           /* IntuitionBase */

    doopts(argc,argv);

    if (!argc) {        /* Workbench */
        wbArgs = WBenchMsg->sm_ArgList;
        argc   = WBenchMsg->sm_NumArgs;
        if (argc < 2) cleanup(NULL,50);   /* Removed console. Bummer. */
        j = 0;      argc--;
        while ((j < argc) && (j < MAXAC)) {
            cliArgs[j] = wbArgs[j + 1];
            j++;
        }
        wbArgs = cliArgs;   /* Copy over, so array can be added to */
    }
    else {              /* CLI */
        argv++;     argc--;
        if (argc > 10) argc = 10;

        for (i=j=0; i < argc; i++) {      /* Only filename args. */
            if ((argv[i][0] != '+') && (argv[i][0] != '-') && (argv[i][0] != '#')) {
                cliArgs[j].wa_Lock = 0;     /* So OpenArg checks for !Lock */
                cliArgs[j].wa_Name = argv[i];
                j++;
            }
        }

        wbArgs = cliArgs;
        argc = j;       /* ac set to argc, also used by WB stuff */
    }

  /* Set up list of files to be examined. */
    ac = argc;      /* Filename count */
    curr_ac = 0;    /* Current arg to use */

    ttopen();                   /* Opens window, and console */
    initbell();                 /* Set up bell */

    if (back_scroll < 0) {
        back_scroll = sc_height-1;
        if (top_scroll) back_scroll--;
    }

  /* Select the first file to examine. */
    if (ac < 1) cleanup("ERROR: no file specified\n",50);
    else {
        do {
            edit(0);
            if (file > 0) /* We can open this file. */
            break;
            putc('\n');  flush();
        } while (++curr_ac < ac);   /* Keeping trying. */
    }

    if (file > 0) commands();       /* Managed to open a file */
    cleanup(NULL,0);
}

void    printf(cp) /*====================================================*/
register char   *cp;
{
    if (!WBenchMsg) Write(Output(),cp,strlen(cp));
}

char    *strint(i) /*====================================================*/
register int    i; /* Simple integer to decimal string routine */
{
register char    *ret;
static char buf[10];
    ret = &buf[9];
    *ret = 0;
    while (i > 0) {
        *(--ret) = (i % 10) + '0';
        i /= 10;
    }
    if (!*ret) *(--ret) = '0';
    return(ret);
}

void    sprintf(dst,cp,pnt) /*===========================================*/
register char   *dst,*cp;
ULONG   pnt;
{
ULONG   *arg;
    arg = &pnt;
    while (*cp) {
        if (*cp == '%') switch (*(++cp)) {
            case ('d'): strcpy(dst,strint((int)*arg++));
                        while (*dst) dst++;                /* On to zero */
                        break;
            case ('s'): strcpy(dst,(char *)*arg++);
                        while (*dst) dst++;
                        break;
            case ('c'): *dst++ = (char)*arg++;
                        break;
            default: *dst++ = *cp;
        }
        else *dst++ = *cp;
        cp++;               /* Inc it here, so in just once place */
    }
    *dst = 0;
}

void    cleanup(cp,err) /*===============================================*/
char    *cp;            /* No bra required. Just a simple exit.          */
int     err;            /* I don't like doing all this if (x) Close(x)   */
{                       /* stuff, but leave it in for the mo...          */
    if (cp) printf(cp);
    if (file > 0) Close(file);
    freebell();     /* Drop bell stuff. OK if not there, so no need to check */
    ttclose();      /* OKAY if tty not open, so no need to check. */
    ch_memdump();   /* FreeMem bufs in ch.c */
    if (RemKey) FreeRemember(&RemKey,TRUE);
    if (IconBase) CloseLibrary(IconBase);
    if (GfxBase) CloseLibrary(GfxBase);
    if (IntuitionBase) CloseLibrary(IntuitionBase);
    XCEXIT(err);
}
