#ifdef This_Is_A_Comment

Have you ever wanted CLI on a custom screen with 25 lines of 80 characters? 
Here it is!  By Paul Kienitz, 11/27/88.  When compiling with Aztec C, DO NOT
use the +M (3.6) or -BD (5.0) stack checking option.  There are some
provisions for compiling it without Aztec, but they are UNTESTED AND
INCOMPLETE.  Last revision date:  12/31/90.

Use the +A flag on the Aztec linker.

Improvements needed:
=> o Make it work without ConMan.
   o Make it Pure someday.
   o B option for inactive window on screen opened in back?
   o Cn xxx option to set RGB colors.
   o Mn option to set overscanmargin?
   o Someday, P option for "productivity mode" screen.
   o Dn option for screen depth.
   o hot key to bring to front and activate?  Make your own, I don't need one.
   o Invisible screen gadgets?  Nah, too difficult to make text show through.

#endif


#include <exec/exec.h>
#include <intuition/intuition.h>
#include <graphics/gfxbase.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <libraries/dosextens.h>
#include <Paul.h>


#define GREENISHNESS	{0x484, 0x000, 0x0b0, 0xcc0}
#define DEFAULTISHNESS	{0x05a, 0xfff, 0x002, 0xf80}

#define SCLI struct CommandLineInterface


typedef struct {
    adr ibase, gbase, dosbase;
    struct TextFont *fawnt;
    struct Screen *scr;
    struct Window *win;
    BPTR wandle, ceedee;
} stuffy;


adr IntuitionBase, DOSBase, IconBase, DiskfontBase;
struct GfxBase *GfxBase;

struct WBStartup *WBenchMsg;
struct Process *me;
struct Preferences *prufs;

#define PREFSIZE (long) ( (str) &prufs->color3 + 2 - (str) prufs)

SCLI *fakli = null;
str prompt, setname;

str command, processname;
BPTR oriout, fakeseglist;

bool lace = false, unshelled = false, greenify = false,
	frum = false, newfont = false, closeori = false;;


str fontname = "topaz.font";		/* no other choices for now */
long fontsize = 11;

stuffy *stuff;


struct NewScreen scrdef = {
	0, 0, 640, 204,	/* Width and Height will be set later */
	2,			/*  4 colors  */
	0, 0,		/*  detail pen = background so no white stripe at top */
	HIRES,		/* inventor of root beer */
	CUSTOMSCREEN,
	null, null,	/* title (won't actually show) filled in later */
	null, null
};


struct NewWindow windef = {
	0, 4, 640, 200,	/* TopEdge and Height will be set later */
	0, 1,
	0L,
	ACTIVATE | BACKDROP | BORDERLESS,
	null, null, null,	/* no special gadget or checkmark, no title */
	null,			/* screen pointer; will get set later */
	null,			/* no custom bitmap */
	0, 0, 0, 0,		/* ignored */
	CUSTOMSCREEN
};


/* these are all in bud.a */
extern void beginning(), ending(), CloseStuff();
extern short StuffOffs, CommandOffs, NameOffs, FakeOffs;


/* for debugging:
#define puf(S, N) (sprintf(buf, S, N), spew(buf))
#define puff(S, N, NN) (sprintf(buf, S, N, NN), spew(buf))
char buf[256];
*/


void exit();



void spew(s) str s;
{
    register long l = strlen(s);
    if (!oriout && !closeori) {
	closeori = true;
	oriout = OOpen("CON:60/40/450/80/ CLImax error: ");
    }
    if (oriout) Write(oriout, s, l);
}



void Die()
{
    BPTR *p, *pp;
    UnLoadSeg(fakeseglist);
    if (stuff->ceedee)
	UnLock(stuff->ceedee);
    if (fakli && fakli->cli_CommandDir) {
	p = gbip(fakli->cli_CommandDir);
	while (p) {
	    UnLock(p[1]);
	    pp = gbip(*p);
	    FreeMem(p, 8);
	    p = pp;
	}
    }
    CloseStuff(stuff);
    exit(10);
}



void OpenStuff ()
{   ushort *wbcolor, tallth;
    static ushort lacecolor[4] = GREENISHNESS,
		  unlacecolor[4] = DEFAULTISHNESS;
    long collor;	/* that's how Joan spelled it once */
    struct ViewPort *vp;
    short margin = (lace ? 10 : 4);

    tallth = (GfxBase->NormalDisplayRows << lace) - margin;
    if (tallth < (200 << lace))
	tallth = 200 << lace;
    else if (tallth > (246 << lace) && tallth < (256 << lace))
	tallth = 256 << lace;
    if (lace)
	scrdef.ViewModes = HIRES | LACE;
    windef.TopEdge = margin;
    windef.Height = tallth;
    scrdef.Height = tallth + margin;
    scrdef.Width = windef.Width = GfxBase->NormalDisplayColumns;
    scrdef.DefaultTitle = (ubyte *) processname;
    if (!(stuff->scr = OpenScreen(&scrdef))) {
	spew("\nCLImax: can't open screen.\n");
	Die();
    }
    windef.Screen = stuff->scr;
    if (!(stuff->win = OpenWindow(&windef))) {
	spew("\nCLImax: can't open backdrop window.\n");
	Die();
    }
    ShowTitle(stuff->scr, FALSE);
    vp = &stuff->scr->ViewPort;
    prufs = null;
    if (greenify) wbcolor = lacecolor;
    else if (prufs = Alloc(PREFSIZE)) {
	GetPrefs(prufs, PREFSIZE);
	wbcolor = &prufs->color0;
    } else wbcolor = unlacecolor;
    for (collor = 0; collor <= 3; collor++, wbcolor++)
	SetRGB4(vp, collor, (*wbcolor >> 8) & 15L,
		    (*wbcolor >> 4) & 15L,
		    *wbcolor & 15L);
    if (prufs) FreeMem(prufs, PREFSIZE);
}



BPTR CopyPath(tass) str tass;
{
    struct Process *wb = (adr) FindTask(tass);
    SCLI *wbclap;
    BPTR *wext, *mext, *lastmext, newpath = 0;
    lastmext = &newpath;
    if (!wb) return 0;
    if (!(wbclap = gbip(wb->pr_CLI))) return 0;
    for (wext = gbip(wbclap->cli_CommandDir); wext; wext = gbip(*wext)) {
	if (!(mext = AllocP(2 * sizeof(BPTR))))
	    break;
	*lastmext = (long) mext >> 2;
	lastmext = mext;
	mext[1] = DupLock(wext[1]);
	mext[0] = 0;
    }
    return (newpath);
}



void bcpy(dest, src, limit) ubyte *dest, *src; short limit;
{
    register ushort l = *(src++);
    if (l >= limit) l = limit - 1;
    *(dest++) = l;
    while (l > 0) {
	*(dest++) = *(src++);
	l--;
    }
}



void FakeCLI()
{
    if (me->pr_CLI) {
	SCLI *mec = gbip(me->pr_CLI);
	fakli->cli_DefaultStack = mec->cli_DefaultStack;  /* NewCLI does this */
	bcpy(prompt, gbip(mec->cli_Prompt), 64);
	bcpy(setname, gbip(mec->cli_SetName), 88);
	/* I just happen to know that the CLI allocates 64 bytes for the
	    prompt and 88 bytes for the setname.  On its stack. */
	fakli->cli_CommandDir = CopyPath(null);
    } else {
	register BPTR p;
	fakli->cli_DefaultStack = 1000L;
	if (!(p = CopyPath("Workbench")))
	    if (!(p = CopyPath("Initial CLI")))
		if (!(p = CopyPath("AmigaShell")))
		    if (!(p = CopyPath("New CLI")))
			p = CopyPath("Background CLI");
	fakli->cli_CommandDir = p;
	/* Why, you ask, am I including code that assumes the CLImax process
	   has been launched neither from a CLI nor from Workbench?
	       well, I use MyMenu.  and sometimes the path will get set
	   elsewhere after workbench is already under way so it doesn't know
	   it.  besides, I just had this lying around in FixCLI. */
    }
    fakli->cli_Prompt = (long) prompt >> 2;
    fakli->cli_SetName = (long) setname >> 2;
/*  if (!stuff->ceedee) stuff->ceedee = RLock("SYS:");  */
}



void DooFont()
{
    struct TextAttr f;
    f.ta_Name = (adr) fontname;
    f.ta_YSize = fontsize;
    f.ta_Style = f.ta_Flags = 0;
    stuff->fawnt = OpenFont(&f);
    if (stuff->fawnt && fontsize != stuff->fawnt->tf_YSize) {
	CloseFont(stuff->fawnt);
	stuff->fawnt = null;
    }
    if (!stuff->fawnt)
	if (DiskfontBase = (adr) OpenLibrary("diskfont.library", 0L)) {
	    stuff->fawnt = OpenDiskFont(&f);
	    CloseLibrary(DiskfontBase);
	}
    if (stuff->fawnt)
	SetFont(stuff->win->RPort, stuff->fawnt);
}



void wandle()
{
    struct DiskObject *bob;
    str toop;
    register char c;

    if (!(IconBase = OpenLibrary("icon.library", 0L))) return;
    CurrentDir(WBenchMsg->sm_ArgList->wa_Lock);
    if (bob = GetDiskObject(WBenchMsg->sm_ArgList->wa_Name)) {
	if (toop = FindToolType(bob->do_ToolTypes, "OPTION"))
	    for (c = tolower(*toop); c; c = tolower(*++toop)) {
		if (c == 'v') unshelled = true;
		else if (c == 'g') greenify = true;
		else if (c == 'i') lace = true;
		else if (c == 'e') newfont = true;
	    }
	if (toop = FindToolType(bob->do_ToolTypes, "CD")) {
	    while (*toop && *toop <= ' ') toop++;
	    if (stuff->ceedee = RLock(toop)) {
		register int l = strlen(toop);
		if (l >= 88) l = 87;
		*setname = l;
		strncpy(setname + 1, toop, l);
	    }
	}
	if (toop = FindToolType(bob->do_ToolTypes, "FROM")) {
	    while (*toop && *toop <= ' ') toop++;
	    if (*toop) {
		strcpy(command, "execute ");
		strcpy(command + 8, toop);
	    } else *command = 0;
	    frum = true;
	}
	FreeDiskObject(bob);
    }
    CurrentDir(stuff->ceedee);
    CloseLibrary(IconBase);
    IconBase = null;
}



int word, chair, ac; stray av;

char nerg()
{
    if (word > ac) return (0);
    else if (av[word][chair]) return (tolower(av[word][chair++]));
    else if (++word <= ac) return (tolower(av[word][chair = 0]));
    else return (0);
}



void handle(argc, argv) int argc; str argv[];
{
    char c;
    bool kelp = false;
    ac = argc; av = argv; word = 1; chair = 0;
    lace = false;
    for (c = nerg(); c; c = nerg()) {
	if (c == 'v') unshelled = true;
	else if (c == 'i') lace = true;
	else if (c == 'g') greenify = true;
	else if (c == 'e') newfont = true;
	else if (c == '?' || c == 'h') kelp = true;
	else if (c == 'f' && nerg() == 'r' && nerg() == 'o' && nerg() == 'm') {
	    for (c = nerg(); c && c <= ' '; c = nerg()) ;
	    frum = true;
	    if (!c) *command = 0;
	    else {
		register str cc = command + 8;
		strcpy(command, "execute ");
		while (c >= ' ') {
		    *(cc++) = c;
		    c = nerg();
		}
	    }
	}
    }
    if (kelp) {
	spew(
"\nCLImax by Paul Kienitz -- in the public domain -- usage:\n\n"
"    CLIMAX [ V ]  [ I ]  [ G ]  [ E ]   [ FROM [ scriptfile ] ]\n\n"
"The letters V, I, G, and E can be in any order, case, or spacing.\n"
" V (vanilla) means use s:CLI-Startup instead of s:Shell-Startup.\n"
" I means make an interlace screen.\n"
" G means use black-on-greenish (good for interlace) instead of\n"
"     the Workbench colors (maybe someday there'll be an RGB option).\n"
" E means use the topaz 11 font instead of the system default font.\n"
" FROM scriptfile means execute the named file (instead of S:Shell-Startup)\n"
"     before giving the first prompt.  Must be the LAST option on the line.\n"
"     Use FROM with nothing after it to use no script.\n"
"? or H means show this message.\n\n"
"For Workbench, use a tooltype OPTION= followed by V, I, G, and/or E.\n"
"Also you can use tooltype CD= to specify its current directory.\n"
"And use FROM= to specify a startup scriptfile.\n\n");
	Die();
    }
    stuff->ceedee = DupLock(me->pr_CurrentDir);
}



void Bud()	/* grow a "bud" which can detach as a child process */
{
    long tize = ((str) &ending - (str) &beginning) + 8;
    register str taskspace = AllocP(tize);
    if (!taskspace || !IntuitionBase || !GfxBase) {
	spew("\nGaaah!  Not enough memory for CLImax!\n");
	exit(20);
    }
    CopyMemQuick((str) &beginning, taskspace + 8, tize - 8);
    *((long *) taskspace) = (tize + 3) & ~3;
    ((long *) taskspace)[1] = 0;		/* fakeseglist next bptr */
    fakeseglist = (((long) taskspace) >> 2) + 1;
    taskspace += 8;
    command = (adr) (taskspace + CommandOffs);
    processname = (adr) (taskspace + NameOffs);
    fakli = (adr) (taskspace + FakeOffs);
    prompt = (str) fakli + sizeof(SCLI);
    setname = prompt + 64;
    stuff = (adr) (taskspace + StuffOffs);
    stuff->wandle = stuff->ceedee = 0;
    stuff->scr = (adr) stuff->win = stuff->fawnt = null;
    stuff->ibase = IntuitionBase;
    stuff->gbase = GfxBase;
    stuff->dosbase = DOSBase;
}



void speck(b, a) str b; long a;
{
   short hid, nyb, end;
   strcat(b, "CON:Wxxxxxx");		/* uses ConMan */
   end = strlen(b) - 1;
   for (hid = 0; hid <= 5; hid++) {
      nyb = (a >> (4*hid)) & 15;
      b[end - hid] = (nyb >= 10 ? (char) nyb + 'A' - 10 : (char) nyb + '0');
   }
}



void main(argc, argv) int argc; stray argv;
{
    char boof[50];
    BPTR L, Seg = 1;
    APTR mywptr;

    oriout = Output();
#ifndef AZTEC_C
    me = ThisProcess();
    === do something to get WBenchMsg ===
#endif
    IntuitionBase = (adr) OpenLibrary ("intuition.library", 0L);
    GfxBase = (adr) OpenLibrary ("graphics.library", 0L);
    Bud();
    if (WBenchMsg)
	wandle();
    else
	handle(argc, argv);
    OpenStuff();
    mywptr = me->pr_WindowPtr;
    me->pr_WindowPtr = (APTR) -1L;
    if (!frum)
	if (!unshelled && (L = RLock("s:shell-startup"))) {
	    strcpy(command, "execute s:shell-startup");
	    UnLock(L);
	} else if (L = RLock("s:cli-startup")) {
	    strcpy(command, "execute s:cli-startup");
	    UnLock(L);
	} else *command = 0;
    me->pr_WindowPtr = mywptr;
    FakeCLI();
    boof[0] = 0;
    speck(boof, stuff->win);
    if (newfont) DooFont();
    if (stuff->wandle = OOpen(boof)) {
	Write(stuff->wandle,
		"CLImax by Paul Kienitz maximizes your CLI.\n", 43L);
	CreateProc(processname, 0L, fakeseglist, 2000L);
    } else {
	spew("\nCLImax can't open the CON: for the window.\n"
		"If you do not have ConMan installed, you\n"
		"have to do that first!\n");
	Die();
    }
}



/* reduce size by a few K: */

#ifdef AZTEC_C

char arg[256];
str argp[3] = { "CLImax", arg, null };


void _main(alen, aptr) long alen; str aptr;  /* simplified startup code */
{
    int al = alen;
    me = ThisProcess();
    if (me->pr_CLI) {
	if (al > 255) al = 255;
	strncpy(arg, aptr, al);
	arg[al - 1] = 0;
	WBenchMsg = null;
    } else {
	WaitPort(&me->pr_MsgPort);
	WBenchMsg = (adr) GetMsg(&me->pr_MsgPort);
    }
    main(1, argp);	/* pack all args into argv[1] */
    exit(0);
}



void exit(code) int code;
{
    char c;
    if (oriout && closeori) {
	spew("\n  - press return -  ");
	Read(oriout, &c, 1L);
	Close(oriout);
    }
    if (WBenchMsg) {
	Forbid();
	ReplyMsg((struct Message *) WBenchMsg);
    }
    Exit((long) code);
}

#endif
