From a6555970692300fd931ba5d28d0fdef8e2d88384 Mon Sep 17 00:00:00 2001 From: deadwood Date: Fri, 19 Jul 2013 18:45:16 +0000 Subject: [PATCH] console-handler: Tabs->spaces git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@47732 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- rom/filesys/console_handler/completion.c | 1600 ++++++++------- rom/filesys/console_handler/con_handler.c | 1283 ++++++------ rom/filesys/console_handler/con_handler_intern.h | 259 +-- rom/filesys/console_handler/support.c | 2355 +++++++++++----------- rom/filesys/console_handler/support.h | 126 +- 5 files changed, 2825 insertions(+), 2798 deletions(-) rewrite rom/filesys/console_handler/completion.c (70%) rewrite rom/filesys/console_handler/con_handler.c (84%) rewrite rom/filesys/console_handler/con_handler_intern.h (73%) rewrite rom/filesys/console_handler/support.c (77%) diff --git a/rom/filesys/console_handler/completion.c b/rom/filesys/console_handler/completion.c dissimilarity index 70% index 4feb857bd4..ac04417198 100644 --- a/rom/filesys/console_handler/completion.c +++ b/rom/filesys/console_handler/completion.c @@ -1,804 +1,796 @@ -/* - Copyright © 1995-2011, The AROS Development Team. All rights reserved. - $Id$ - - Desc: - Lang: english -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "con_handler_intern.h" -#include "support.h" -#include "completion.h" - -#include -#include - -#define DEBUG 0 -#include - -/****************************************************************************************/ - -struct matchnode -{ - struct Node node; - UBYTE name[1]; -}; - -/****************************************************************************************/ - -struct completioninfo -{ - struct filehandle *fh; - struct List matchlist; - APTR pool; - WORD nummatchnodes; - WORD wordstart; - BOOL wordquoted; - UBYTE filepart[256]; - UBYTE dirpart[256]; - UBYTE pattern[256*2+3]; - UBYTE match[256]; - BOOL withinfo; -}; - -/****************************************************************************************/ - -/* Delay opening of the gadtools.library to the first time InitCompletion is called */ - -static struct completioninfo *InitCompletion(struct filehandle *fh, BOOL withinfo) -{ - struct completioninfo *ci = NULL; - APTR pool; - - if (fh->gtbase == NULL) - fh->gtbase = OpenLibrary("gadtools.library", 39); - - if (fh->gfxbase == NULL) - fh->gfxbase = (APTR)OpenLibrary("graphics.library", 39); - - if (fh->lastwritetask && GadToolsBase) - if (fh->lastwritetask->tc_Node.ln_Type == NT_PROCESS) - { - if ((pool = CreatePool(MEMF_CLEAR, 1024, 1024))) - { - BOOL ok = FALSE; - - if ((ci = (struct completioninfo *)AllocPooled(pool, sizeof(*ci)))) - { - ci->pool = pool; - ci->fh = fh; - ci->withinfo = withinfo; - NewList(&ci->matchlist); - - ok = TRUE; - } - - if (!ok) - { - DeletePool(pool); - ci = NULL; - } - } - } - - return ci; -} - -/****************************************************************************************/ - -static void CleanupCompletion(struct completioninfo *ci) -{ - DeletePool(ci->pool); -} - -/****************************************************************************************/ - -static void PrepareCompletion(struct filehandle *fh, struct completioninfo *ci) -{ - WORD i; - BOOL in_quotes = FALSE; - - /* Find word start */ - - ci->wordstart = i = ci->fh->inputstart; - - while(i != ci->fh->inputpos) - { - switch(ci->fh->inputbuffer[i++]) - { - case '"': - in_quotes = !in_quotes; - if (in_quotes) ci->wordstart = i; - break; - - case ' ': - if (!in_quotes) ci->wordstart = i; - break; - } - } - - strncpy(ci->dirpart, - &ci->fh->inputbuffer[ci->wordstart], - ci->fh->inputpos - ci->wordstart); - strcpy(ci->filepart, FilePart(ci->dirpart)); - - *(PathPart(ci->dirpart)) = '\0'; - - ci->wordquoted = in_quotes; - - D(bug("PrepareCompletion: dirpart = \"%s\" filepart = \"%s\"\n", ci->dirpart, ci->filepart)); -} - -/****************************************************************************************/ - -static void AddQuotes(struct completioninfo *ci, STRPTR s, LONG s_size) -{ - LONG len = strlen(s); - - if (!ci->wordquoted) - { - if (len < s_size - 1) - memmove(s + 1, s, len + 1); - s[0] = '"'; - } - else - { - len--; - } - - if (len < s_size - 3) - { - if ((s[len] != '/') && (s[len] != ':')) - { - s[len + 1] = '"'; - s[len + 2] = '\0'; - } - } -} - -/****************************************************************************************/ - -static void InsertIntoConBuffer(struct completioninfo *ci, STRPTR s) -{ - WORD i = ci->fh->conbufferpos; - - /* Lame code, but speed is no issue here */ - while((ci->fh->conbuffersize < CONSOLEBUFFER_SIZE) && *s) - { - memmove(&ci->fh->consolebuffer[i + 1], - &ci->fh->consolebuffer[i], - ci->fh->conbuffersize - i); - - ci->fh->consolebuffer[i++] = *s++; - ci->fh->conbuffersize++; - } -} - -/****************************************************************************************/ - -static void DoFileReq(struct filehandle *fh, struct completioninfo *ci) -{ - struct Library *AslBase; - BPTR lock, olddir; - - if ((lock = DupLock(((struct Process *)ci->fh->lastwritetask)->pr_CurrentDir))) - { - olddir = CurrentDir(lock); - - if ((AslBase = OpenLibrary("asl.library", 36))) - { - struct FileRequester *fr; - struct TagItem tags[] = - { - {ASLFR_Window , (IPTR)ci->fh->window }, - {ASLFR_DoPatterns , (IPTR)TRUE }, - {ASLFR_InitialPattern, 0 }, - {TAG_DONE } - }; - - tags[2].ti_Data = (IPTR)(ci->withinfo ? "#?" : "~(#?.info)"); - - if ((fr = AllocAslRequest(ASL_FileRequest, tags))) - { - if (AslRequest(fr, NULL)) - { - UBYTE c; - - strcpy(ci->match, fr->fr_Drawer); - AddPart(ci->match, fr->fr_File, sizeof(ci->match)); - - if (ci->match[0]) - { - if (strchr(ci->match, ' ')) AddQuotes(ci, ci->match, sizeof(ci->match)); - - c = ci->match[strlen(ci->match) - 1]; - if ((c != '/') && (c != ':')) - { - strncat(ci->match, " ", sizeof(ci->match)); - } - - InsertIntoConBuffer(ci, ci->match); - } - - } - FreeAslRequest(fr); - } - - CloseLibrary(AslBase); - - } /* if ((AslBase = OpenLibrary("asl.library", 36))) */ - - CurrentDir(olddir); - UnLock(lock); - } -} - -/****************************************************************************************/ - -static BOOL PreparePattern(struct filehandle *fh, struct completioninfo *ci) -{ - WORD parsecode; - - parsecode = ParsePatternNoCase(ci->filepart, ci->pattern, sizeof(ci->pattern)); - if (parsecode != -1) - { - if (parsecode == 0) - { - if (ci->withinfo) - { - strncat(ci->filepart, "#?", sizeof(ci->filepart)); - } - else - { - strncat(ci->filepart, "~(#?.info)", sizeof(ci->filepart)); - } - parsecode = ParsePatternNoCase(ci->filepart, ci->pattern, sizeof(ci->pattern)); - } - } - - return (parsecode == 1); - -} - -/****************************************************************************************/ - -static void AddMatchNode(struct filehandle *fh, struct completioninfo *ci, - STRPTR name, WORD type) -{ - struct matchnode *mn; - struct Node *prev, *check; - WORD size; - BOOL exists = FALSE; - - size = strlen(name) + 1 + sizeof(struct matchnode) + ((type > 0) ? 1 : 0); - - if ((mn = AllocPooled(ci->pool, size))) - { - strcpy(mn->name, name); - mn->node.ln_Name = mn->name; - - if (type == 1) strcat(mn->name, "/"); - if (type == 2) strcat(mn->name, ":"); - - /* Sort into matchlist */ - - prev = NULL; - ForeachNode(&ci->matchlist, check) - { - WORD match; - - match = Stricmp(mn->name, ((struct matchnode *)check)->name); - if (match < 0) break; - if (match == 0) - { - exists = TRUE; - break; - } - - prev = check; - } - - if (!exists) - { - Insert(&ci->matchlist, (struct Node *)mn, prev); - ci->nummatchnodes++; - } - else - { - FreePooled(ci->pool, mn, size); - } - } -} - -/****************************************************************************************/ - -static void ScanDir(struct filehandle *fh, struct completioninfo *ci) -{ - struct FileInfoBlock *fib; - BPTR lock; - - if ((fib = AllocDosObject(DOS_FIB, 0))) - { - if ((lock = Lock(ci->dirpart, SHARED_LOCK))) - { - if (Examine(lock, fib)) - { - while(ExNext(lock, fib)) - { - if (MatchPatternNoCase(ci->pattern, fib->fib_FileName)) - { - BOOL isdir = (fib->fib_DirEntryType > 0); - - AddMatchNode(fh, ci, fib->fib_FileName, (isdir ? 1 : 0)); - } - } - } - - UnLock(lock); - } - - FreeDosObject(DOS_FIB, fib); - } -} - -/****************************************************************************************/ - - -static void ScanVol(struct filehandle *fh, struct completioninfo *ci) -{ - struct DosList *dlist; - - dlist = LockDosList(LDF_READ | LDF_VOLUMES | LDF_DEVICES | LDF_ASSIGNS); - - while ((dlist = NextDosEntry(dlist, LDF_VOLUMES | LDF_ASSIGNS | LDF_DEVICES)) != NULL) - { - STRPTR devname = AROS_BSTR_ADDR(dlist->dol_Name); - - if (MatchPatternNoCase(ci->pattern, devname)) - { - AddMatchNode(fh, ci, devname, 2); - - } - } - UnLockDosList(LDF_READ | LDF_VOLUMES | LDF_DEVICES | LDF_ASSIGNS); -} - -static void DoScan(struct filehandle *fh, struct completioninfo *ci) -{ - BPTR lock, olddir; - - if ((lock = DupLock(((struct Process *)ci->fh->lastwritetask)->pr_CurrentDir))) - { - olddir = CurrentDir(lock); - - if (ci->dirpart[0] == 0) ScanVol(fh, ci); - ScanDir(fh, ci); - - CurrentDir(olddir); - UnLock(lock); - } -} - -/****************************************************************************************/ - -#define BUTTON_EXTRA_WIDTH 16 -#define BUTTON_EXTRA_HEIGHT 6 -#define BORDER_X 4 -#define BORDER_Y 4 -#define BUTTON_SPACING_X 8 -#define LV_BUTTON_SPACING_Y 4 -#define LV_EXTRA_HEIGHT 4 - -#define ID_LISTVIEW 1 -#define ID_OK 2 -#define ID_CANCEL 3 - -/****************************************************************************************/ - -static BOOL DoChooseReq(struct filehandle *fh, struct completioninfo *ci) -{ - static const char oktext[] = "Ok"; - static const char canceltext[] = "Cancel"; - static const char titletext[] = "Select filename"; - - struct RastPort temprp; - struct DrawInfo *dri; - struct Window *win; - struct Gadget *gadlist, *gad, *lvgad; - struct NewGadget ng; - APTR vi; - WORD i, buttonwidth, buttonheight, visible_lv_lines; - WORD winwidth, winheight, winleft, wintop; - LONG sec, micro, secold, microold; - BOOL retval = FALSE; - - if ((dri = GetScreenDrawInfo(ci->fh->window->WScreen))) - { - if ((vi = GetVisualInfoA(ci->fh->window->WScreen, NULL))) - { - InitRastPort(&temprp); - SetFont(&temprp, dri->dri_Font); - - buttonwidth = TextLength(&temprp, oktext, strlen(oktext)); - i = TextLength(&temprp, canceltext, strlen(canceltext)); - buttonwidth = (buttonwidth > i) ? buttonwidth : i; - buttonwidth += BUTTON_EXTRA_WIDTH; - - buttonheight = dri->dri_Font->tf_YSize + BUTTON_EXTRA_HEIGHT; - - i = ci->nummatchnodes > 15 ? 15 : ci->nummatchnodes; - if (i < 4) i = 4; - - winheight = i * (dri->dri_Font->tf_YSize + 1) + - LV_EXTRA_HEIGHT + - LV_BUTTON_SPACING_Y + - buttonheight + - BORDER_Y * 2; - - winwidth = buttonwidth * 2 + BUTTON_SPACING_X + BORDER_X * 2; - i = ci->fh->window->WScreen->Width * 1 / 3; - if (i > winwidth) winwidth = i; - - winleft = ci->fh->window->WScreen->MouseX - - (winwidth + ci->fh->window->WScreen->WBorLeft + - ci->fh->window->WScreen->WBorRight) / 2; - wintop = ci->fh->window->WScreen->MouseY - - (winheight + ci->fh->window->WScreen->WBorTop + - dri->dri_Font->tf_YSize + 1 + - ci->fh->window->WScreen->WBorBottom) / 2; - - gad = CreateContext(&gadlist); - - ng.ng_LeftEdge = ci->fh->window->WScreen->WBorLeft + BORDER_X; - ng.ng_TopEdge = ci->fh->window->WScreen->WBorTop + dri->dri_Font->tf_YSize + 1 + BORDER_Y; - ng.ng_Width = winwidth - BORDER_X * 2; - ng.ng_Height = winheight - BORDER_Y * 2 - buttonheight - LV_BUTTON_SPACING_Y; - ng.ng_GadgetText = NULL; - ng.ng_TextAttr = NULL; - ng.ng_GadgetID = ID_LISTVIEW; - ng.ng_Flags = 0; - ng.ng_VisualInfo = vi; - ng.ng_UserData = 0; - - { - struct TagItem lvtags[] = - { - {GTLV_Labels , (IPTR)&ci->matchlist }, - {GTLV_ShowSelected , 0 }, - {GTLV_Selected , 0 }, - {TAG_DONE } - }; - - gad = lvgad = CreateGadgetA(LISTVIEW_KIND, gad, &ng, lvtags); - - visible_lv_lines = (ng.ng_Height - LV_EXTRA_HEIGHT) / (dri->dri_Font->tf_YSize + 1); - } - - ng.ng_TopEdge += ng.ng_Height + LV_BUTTON_SPACING_Y; - ng.ng_Width = buttonwidth; - ng.ng_Height = buttonheight; - ng.ng_GadgetText = oktext; - ng.ng_GadgetID = ID_OK; - - gad = CreateGadgetA(BUTTON_KIND, gad, &ng, NULL); - - ng.ng_LeftEdge += winwidth - buttonwidth - BORDER_X * 2; - ng.ng_GadgetText = canceltext; - ng.ng_GadgetID = ID_CANCEL; - - gad = CreateGadgetA(BUTTON_KIND, gad, &ng, NULL); - - if (gad) - { - struct TagItem wintags[] = - { - {WA_CustomScreen, (IPTR)ci->fh->window->WScreen }, - {WA_Title , (IPTR)titletext }, - {WA_CloseGadget , TRUE }, - {WA_DragBar , TRUE }, - {WA_DepthGadget , TRUE }, - {WA_Activate , TRUE }, - {WA_AutoAdjust , TRUE }, - {WA_Left , winleft }, - {WA_Top , wintop }, - {WA_InnerWidth , winwidth }, - {WA_InnerHeight , winheight }, - {WA_IDCMP , IDCMP_CLOSEWINDOW | - IDCMP_RAWKEY | - IDCMP_VANILLAKEY | - LISTVIEWIDCMP | - BUTTONIDCMP }, - {WA_Gadgets , (IPTR)gadlist }, - {TAG_DONE } - - }; - - if ((win = OpenWindowTagList(NULL, wintags))) - { - BOOL done = FALSE; - BOOL doit = FALSE; - - CurrentTime(&secold, µold); - - while (!done && !doit) - { - struct IntuiMessage *msg; - - WaitPort(win->UserPort); - - while((msg = GT_GetIMsg(win->UserPort))) - { - switch(msg->Class) - { - case IDCMP_CLOSEWINDOW: - done = TRUE; - break; - - case IDCMP_VANILLAKEY: - switch(msg->Code) - { - case 27: - done = TRUE; - break; - - case 13: - doit = TRUE; - break; - } - break; - - case IDCMP_RAWKEY: - { - WORD scroll = 0; - BOOL page = FALSE; - BOOL extreme = FALSE; - - switch(msg->Code) - { - case RAWKEY_UP: - scroll = -1; - break; - - case RAWKEY_DOWN: - scroll = 1; - break; - - case RAWKEY_PAGEUP: - scroll = -1; - page = TRUE; - break; - - case RAWKEY_PAGEDOWN: - scroll = 1; - page = TRUE; - break; - - case RAWKEY_HOME: - scroll = -1; - extreme = TRUE; - break; - - case RAWKEY_END: - scroll = 1; - extreme = TRUE; - break; - - case RAWKEY_NM_WHEEL_UP: - scroll = -1; - break; - - case RAWKEY_NM_WHEEL_DOWN: - scroll = 1; - break; - } - - if (msg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) - { - page = TRUE; - } - - if (msg->Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT | IEQUALIFIER_CONTROL)) - { - extreme = TRUE; - } - - if (scroll) - { - IPTR getsel; - struct TagItem tags[] = - { - {GTLV_Selected, (IPTR)&getsel }, - {TAG_IGNORE , TRUE }, - {TAG_DONE } - }; - WORD sel; - - GT_GetGadgetAttrsA(lvgad, win, NULL, tags); - sel = (WORD)getsel; - - if (extreme) - { - scroll *= ci->nummatchnodes; - } - else if (page) - { - scroll *= visible_lv_lines; - } - - sel += scroll; - if (sel < 0) sel = ci->nummatchnodes - 1; - if (sel >= ci->nummatchnodes) sel = 0; - - tags[0].ti_Data = (IPTR)sel; - tags[1].ti_Tag = GTLV_MakeVisible; - tags[1].ti_Data = (IPTR)sel; - - GT_SetGadgetAttrsA(lvgad, win, NULL, tags); - } - } - break; - - case IDCMP_GADGETUP: - gad = (struct Gadget *)msg->IAddress; - - switch(gad->GadgetID) - { - case ID_OK: - doit = TRUE; - break; - - case ID_CANCEL: - done = TRUE; - break; - - case ID_LISTVIEW: - CurrentTime(&sec, µ); - if (DoubleClick(secold, microold, sec, micro)) doit = TRUE; - secold = sec; microold = micro; - break; - } - break; - - } /* switch(msg->Class) */ - - GT_ReplyIMsg(msg); - - } /* while((msg = GT_GetIMsg(win->UserPort))) */ - - } /* while (!done && !doit) */ - - if (doit) - { - struct Node *node; - IPTR sel; - - struct TagItem gettags[] = - { - {GTLV_Selected, (IPTR)&sel }, - {TAG_DONE } - }; - - GT_GetGadgetAttrsA(lvgad, win, NULL, gettags); - - i = 0; - ForeachNode(&ci->matchlist, node) - { - if ((WORD)sel == i) - { - AddPart(ci->match, node->ln_Name, sizeof(ci->match)); - - retval = TRUE; - break; - } - i++; - } - - } /* if (doit) */ - - CloseWindow(win); - - } /* if ((win = OpenWindowTagList(NULL, wintags))) */ - - } /* if (gad) */ - - FreeGadgets(gadlist); - FreeVisualInfo(vi); - - } /* if ((vi = GetVisualInfoA(ci->fh->window->WScreen, NULL))) */ - - FreeScreenDrawInfo(ci->fh->window->WScreen, dri); - - } /* if ((dri = GetScreenDrawInfo(fh->window->WScreen))) */ - - return retval; -} - -/****************************************************************************************/ - -void Completion(struct filehandle *fh, BOOL withinfo) -{ - struct completioninfo *ci; - - if ((ci = InitCompletion(fh, withinfo))) - { - PrepareCompletion(fh, ci); - - if (!ci->dirpart[0] && !ci->filepart[0]) - { - DoFileReq(fh, ci); - } - else - { - if (PreparePattern(fh, ci)) - { - BOOL doprint = FALSE; - - DoScan(fh, ci); - - strncpy(ci->match, ci->dirpart, sizeof(ci->match)); - - if (ci->nummatchnodes == 1) - { - AddPart(ci->match, - ((struct matchnode *)GetHead(&ci->matchlist))->name, - sizeof(ci->match)); - - doprint = TRUE; - } - else if (ci->nummatchnodes > 1) - { - doprint = DoChooseReq(fh, ci); - } - - if (doprint) - { - WORD backspaces; - UBYTE c; - - if (strchr(ci->match, ' ')) AddQuotes(ci, ci->match, sizeof(ci->match)); - - /* Insert as many backspaces in front of the string, - to erase whole "word" first (starting at ci->wordstart) - before reprinting expanded filename */ - - backspaces = ci->fh->inputpos - ci->wordstart; - - memmove(ci->match + backspaces, ci->match, sizeof(ci->match) - backspaces); - memset(ci->match, 8, backspaces); - - c = ci->match[strlen(ci->match) - 1]; - if ((c != '/') && (c != ':')) - { - strncat(ci->match, " ", sizeof(ci->match)); - } - - InsertIntoConBuffer(ci, ci->match); - - } - } - } - - CleanupCompletion(ci); - - } /* if ((ci = InitCompletion())) */ - -} - -/****************************************************************************************/ +/* + Copyright © 1995-2011, The AROS Development Team. All rights reserved. + $Id$ + + Desc: + Lang: english +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "con_handler_intern.h" +#include "support.h" +#include "completion.h" + +#include +#include + +#define DEBUG 0 +#include + +/****************************************************************************************/ + +struct matchnode +{ + struct Node node; + UBYTE name[1]; +}; + +/****************************************************************************************/ + +struct completioninfo +{ + struct filehandle *fh; + struct List matchlist; + APTR pool; + WORD nummatchnodes; + WORD wordstart; + BOOL wordquoted; + UBYTE filepart[256]; + UBYTE dirpart[256]; + UBYTE pattern[256 * 2 + 3]; + UBYTE match[256]; + BOOL withinfo; +}; + +/****************************************************************************************/ + +/* Delay opening of the gadtools.library to the first time InitCompletion is called */ + +static struct completioninfo *InitCompletion(struct filehandle *fh, BOOL withinfo) +{ + struct completioninfo *ci = NULL; + APTR pool; + + if (fh->gtbase == NULL) + fh->gtbase = OpenLibrary("gadtools.library", 39); + + if (fh->gfxbase == NULL) + fh->gfxbase = (APTR) OpenLibrary("graphics.library", 39); + + if (fh->lastwritetask && GadToolsBase) + if (fh->lastwritetask->tc_Node.ln_Type == NT_PROCESS) + { + if ((pool = CreatePool(MEMF_CLEAR, 1024, 1024))) + { + BOOL ok = FALSE; + + if ((ci = (struct completioninfo *) AllocPooled(pool, sizeof(*ci)))) + { + ci->pool = pool; + ci->fh = fh; + ci->withinfo = withinfo; + NewList(&ci->matchlist); + + ok = TRUE; + } + + if (!ok) + { + DeletePool(pool); + ci = NULL; + } + } + } + + return ci; +} + +/****************************************************************************************/ + +static void CleanupCompletion(struct completioninfo *ci) +{ + DeletePool(ci->pool); +} + +/****************************************************************************************/ + +static void PrepareCompletion(struct filehandle *fh, struct completioninfo *ci) +{ + WORD i; + BOOL in_quotes = FALSE; + + /* Find word start */ + + ci->wordstart = i = ci->fh->inputstart; + + while (i != ci->fh->inputpos) + { + switch (ci->fh->inputbuffer[i++]) + { + case '"': + in_quotes = !in_quotes; + if (in_quotes) + ci->wordstart = i; + break; + + case ' ': + if (!in_quotes) + ci->wordstart = i; + break; + } + } + + strncpy(ci->dirpart, &ci->fh->inputbuffer[ci->wordstart], ci->fh->inputpos - ci->wordstart); + strcpy(ci->filepart, FilePart(ci->dirpart)); + + *(PathPart(ci->dirpart)) = '\0'; + + ci->wordquoted = in_quotes; + + D(bug("PrepareCompletion: dirpart = \"%s\" filepart = \"%s\"\n", ci->dirpart, ci->filepart)); +} + +/****************************************************************************************/ + +static void AddQuotes(struct completioninfo *ci, STRPTR s, LONG s_size) +{ + LONG len = strlen(s); + + if (!ci->wordquoted) + { + if (len < s_size - 1) + memmove(s + 1, s, len + 1); + s[0] = '"'; + } + else + { + len--; + } + + if (len < s_size - 3) + { + if ((s[len] != '/') && (s[len] != ':')) + { + s[len + 1] = '"'; + s[len + 2] = '\0'; + } + } +} + +/****************************************************************************************/ + +static void InsertIntoConBuffer(struct completioninfo *ci, STRPTR s) +{ + WORD i = ci->fh->conbufferpos; + + /* Lame code, but speed is no issue here */ + while ((ci->fh->conbuffersize < CONSOLEBUFFER_SIZE) && *s) + { + memmove(&ci->fh->consolebuffer[i + 1], &ci->fh->consolebuffer[i], ci->fh->conbuffersize - i); + + ci->fh->consolebuffer[i++] = *s++; + ci->fh->conbuffersize++; + } +} + +/****************************************************************************************/ + +static void DoFileReq(struct filehandle *fh, struct completioninfo *ci) +{ + struct Library *AslBase; + BPTR lock, olddir; + + if ((lock = DupLock(((struct Process *) ci->fh->lastwritetask)->pr_CurrentDir))) + { + olddir = CurrentDir(lock); + + if ((AslBase = OpenLibrary("asl.library", 36))) + { + struct FileRequester *fr; + struct TagItem tags[] = + { + { ASLFR_Window, (IPTR) ci->fh->window }, + { ASLFR_DoPatterns, (IPTR) TRUE }, + { ASLFR_InitialPattern, 0 }, + { TAG_DONE } }; + + tags[2].ti_Data = (IPTR) (ci->withinfo ? "#?" : "~(#?.info)"); + + if ((fr = AllocAslRequest(ASL_FileRequest, tags))) + { + if (AslRequest(fr, NULL)) + { + UBYTE c; + + strcpy(ci->match, fr->fr_Drawer); + AddPart(ci->match, fr->fr_File, sizeof(ci->match)); + + if (ci->match[0]) + { + if (strchr(ci->match, ' ')) + AddQuotes(ci, ci->match, sizeof(ci->match)); + + c = ci->match[strlen(ci->match) - 1]; + if ((c != '/') && (c != ':')) + { + strncat(ci->match, " ", sizeof(ci->match)); + } + + InsertIntoConBuffer(ci, ci->match); + } + + } + FreeAslRequest(fr); + } + + CloseLibrary(AslBase); + + } /* if ((AslBase = OpenLibrary("asl.library", 36))) */ + + CurrentDir(olddir); + UnLock(lock); + } +} + +/****************************************************************************************/ + +static BOOL PreparePattern(struct filehandle *fh, struct completioninfo *ci) +{ + WORD parsecode; + + parsecode = ParsePatternNoCase(ci->filepart, ci->pattern, sizeof(ci->pattern)); + if (parsecode != -1) + { + if (parsecode == 0) + { + if (ci->withinfo) + { + strncat(ci->filepart, "#?", sizeof(ci->filepart)); + } + else + { + strncat(ci->filepart, "~(#?.info)", sizeof(ci->filepart)); + } + parsecode = ParsePatternNoCase(ci->filepart, ci->pattern, sizeof(ci->pattern)); + } + } + + return (parsecode == 1); + +} + +/****************************************************************************************/ + +static void AddMatchNode(struct filehandle *fh, struct completioninfo *ci, STRPTR name, WORD type) +{ + struct matchnode *mn; + struct Node *prev, *check; + WORD size; + BOOL exists = FALSE; + + size = strlen(name) + 1 + sizeof(struct matchnode) + ((type > 0) ? 1 : 0); + + if ((mn = AllocPooled(ci->pool, size))) + { + strcpy(mn->name, name); + mn->node.ln_Name = mn->name; + + if (type == 1) + strcat(mn->name, "/"); + if (type == 2) + strcat(mn->name, ":"); + + /* Sort into matchlist */ + + prev = NULL; + ForeachNode(&ci->matchlist, check) + { + WORD match; + + match = Stricmp(mn->name, ((struct matchnode *) check)->name); + if (match < 0) + break; + if (match == 0) + { + exists = TRUE; + break; + } + + prev = check; + } + + if (!exists) + { + Insert(&ci->matchlist, (struct Node *) mn, prev); + ci->nummatchnodes++; + } + else + { + FreePooled(ci->pool, mn, size); + } + } +} + +/****************************************************************************************/ + +static void ScanDir(struct filehandle *fh, struct completioninfo *ci) +{ + struct FileInfoBlock *fib; + BPTR lock; + + if ((fib = AllocDosObject(DOS_FIB, 0))) + { + if ((lock = Lock(ci->dirpart, SHARED_LOCK))) + { + if (Examine(lock, fib)) + { + while (ExNext(lock, fib)) + { + if (MatchPatternNoCase(ci->pattern, fib->fib_FileName)) + { + BOOL isdir = (fib->fib_DirEntryType > 0); + + AddMatchNode(fh, ci, fib->fib_FileName, (isdir ? 1 : 0)); + } + } + } + + UnLock(lock); + } + + FreeDosObject(DOS_FIB, fib); + } +} + +/****************************************************************************************/ + +static void ScanVol(struct filehandle *fh, struct completioninfo *ci) +{ + struct DosList *dlist; + + dlist = LockDosList(LDF_READ | LDF_VOLUMES | LDF_DEVICES | LDF_ASSIGNS); + + while ((dlist = NextDosEntry(dlist, LDF_VOLUMES | LDF_ASSIGNS | LDF_DEVICES)) != NULL) + { + STRPTR devname = AROS_BSTR_ADDR(dlist->dol_Name); + + if (MatchPatternNoCase(ci->pattern, devname)) + { + AddMatchNode(fh, ci, devname, 2); + + } + } + UnLockDosList(LDF_READ | LDF_VOLUMES | LDF_DEVICES | LDF_ASSIGNS); +} + +static void DoScan(struct filehandle *fh, struct completioninfo *ci) +{ + BPTR lock, olddir; + + if ((lock = DupLock(((struct Process *) ci->fh->lastwritetask)->pr_CurrentDir))) + { + olddir = CurrentDir(lock); + + if (ci->dirpart[0] == 0) + ScanVol(fh, ci); + ScanDir(fh, ci); + + CurrentDir(olddir); + UnLock(lock); + } +} + +/****************************************************************************************/ + +#define BUTTON_EXTRA_WIDTH 16 +#define BUTTON_EXTRA_HEIGHT 6 +#define BORDER_X 4 +#define BORDER_Y 4 +#define BUTTON_SPACING_X 8 +#define LV_BUTTON_SPACING_Y 4 +#define LV_EXTRA_HEIGHT 4 + +#define ID_LISTVIEW 1 +#define ID_OK 2 +#define ID_CANCEL 3 + +/****************************************************************************************/ + +static BOOL DoChooseReq(struct filehandle *fh, struct completioninfo *ci) +{ + static const char oktext[] = "Ok"; + static const char canceltext[] = "Cancel"; + static const char titletext[] = "Select filename"; + + struct RastPort temprp; + struct DrawInfo *dri; + struct Window *win; + struct Gadget *gadlist, *gad, *lvgad; + struct NewGadget ng; + APTR vi; + WORD i, buttonwidth, buttonheight, visible_lv_lines; + WORD winwidth, winheight, winleft, wintop; + LONG sec, micro, secold, microold; + BOOL retval = FALSE; + + if ((dri = GetScreenDrawInfo(ci->fh->window->WScreen))) + { + if ((vi = GetVisualInfoA(ci->fh->window->WScreen, NULL))) + { + InitRastPort(&temprp); + SetFont(&temprp, dri->dri_Font); + + buttonwidth = TextLength(&temprp, oktext, strlen(oktext)); + i = TextLength(&temprp, canceltext, strlen(canceltext)); + buttonwidth = (buttonwidth > i) ? buttonwidth : i; + buttonwidth += BUTTON_EXTRA_WIDTH; + + buttonheight = dri->dri_Font->tf_YSize + BUTTON_EXTRA_HEIGHT; + + i = ci->nummatchnodes > 15 ? 15 : ci->nummatchnodes; + if (i < 4) + i = 4; + + winheight = i * (dri->dri_Font->tf_YSize + 1) + LV_EXTRA_HEIGHT + LV_BUTTON_SPACING_Y + buttonheight + + BORDER_Y * 2; + + winwidth = buttonwidth * 2 + BUTTON_SPACING_X + BORDER_X * 2; + i = ci->fh->window->WScreen->Width * 1 / 3; + if (i > winwidth) + winwidth = i; + + winleft = ci->fh->window->WScreen->MouseX + - (winwidth + ci->fh->window->WScreen->WBorLeft + ci->fh->window->WScreen->WBorRight) / 2; + wintop = ci->fh->window->WScreen->MouseY + - (winheight + ci->fh->window->WScreen->WBorTop + dri->dri_Font->tf_YSize + 1 + + ci->fh->window->WScreen->WBorBottom) / 2; + + gad = CreateContext(&gadlist); + + ng.ng_LeftEdge = ci->fh->window->WScreen->WBorLeft + BORDER_X; + ng.ng_TopEdge = ci->fh->window->WScreen->WBorTop + dri->dri_Font->tf_YSize + 1 + BORDER_Y; + ng.ng_Width = winwidth - BORDER_X * 2; + ng.ng_Height = winheight - BORDER_Y * 2 - buttonheight - LV_BUTTON_SPACING_Y; + ng.ng_GadgetText = NULL; + ng.ng_TextAttr = NULL; + ng.ng_GadgetID = ID_LISTVIEW; + ng.ng_Flags = 0; + ng.ng_VisualInfo = vi; + ng.ng_UserData = 0; + + { + struct TagItem lvtags[] = + { + { GTLV_Labels, (IPTR) &ci->matchlist }, + { GTLV_ShowSelected, 0 }, + { GTLV_Selected, 0 }, + { TAG_DONE } }; + + gad = lvgad = CreateGadgetA(LISTVIEW_KIND, gad, &ng, lvtags); + + visible_lv_lines = (ng.ng_Height - LV_EXTRA_HEIGHT) / (dri->dri_Font->tf_YSize + 1); + } + + ng.ng_TopEdge += ng.ng_Height + LV_BUTTON_SPACING_Y; + ng.ng_Width = buttonwidth; + ng.ng_Height = buttonheight; + ng.ng_GadgetText = oktext; + ng.ng_GadgetID = ID_OK; + + gad = CreateGadgetA(BUTTON_KIND, gad, &ng, NULL); + + ng.ng_LeftEdge += winwidth - buttonwidth - BORDER_X * 2; + ng.ng_GadgetText = canceltext; + ng.ng_GadgetID = ID_CANCEL; + + gad = CreateGadgetA(BUTTON_KIND, gad, &ng, NULL); + + if (gad) + { + struct TagItem wintags[] = + { + { WA_CustomScreen, (IPTR) ci->fh->window->WScreen }, + { WA_Title, (IPTR) titletext }, + { WA_CloseGadget, TRUE }, + { WA_DragBar, TRUE }, + { WA_DepthGadget, TRUE }, + { WA_Activate, TRUE }, + { WA_AutoAdjust, TRUE }, + { WA_Left, winleft }, + { WA_Top, wintop }, + { WA_InnerWidth, winwidth }, + { WA_InnerHeight, winheight }, + { WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_RAWKEY | IDCMP_VANILLAKEY | LISTVIEWIDCMP | BUTTONIDCMP }, + { WA_Gadgets, (IPTR) gadlist }, + { TAG_DONE } + }; + + if ((win = OpenWindowTagList(NULL, wintags))) + { + BOOL done = FALSE; + BOOL doit = FALSE; + + CurrentTime(&secold, µold); + + while (!done && !doit) + { + struct IntuiMessage *msg; + + WaitPort(win->UserPort); + + while ((msg = GT_GetIMsg(win->UserPort))) + { + switch (msg->Class) + { + case IDCMP_CLOSEWINDOW: + done = TRUE; + break; + + case IDCMP_VANILLAKEY: + switch (msg->Code) + { + case 27: + done = TRUE; + break; + + case 13: + doit = TRUE; + break; + } + break; + + case IDCMP_RAWKEY: + { + WORD scroll = 0; + BOOL page = FALSE; + BOOL extreme = FALSE; + + switch (msg->Code) + { + case RAWKEY_UP: + scroll = -1; + break; + + case RAWKEY_DOWN: + scroll = 1; + break; + + case RAWKEY_PAGEUP: + scroll = -1; + page = TRUE; + break; + + case RAWKEY_PAGEDOWN: + scroll = 1; + page = TRUE; + break; + + case RAWKEY_HOME: + scroll = -1; + extreme = TRUE; + break; + + case RAWKEY_END: + scroll = 1; + extreme = TRUE; + break; + + case RAWKEY_NM_WHEEL_UP: + scroll = -1; + break; + + case RAWKEY_NM_WHEEL_DOWN: + scroll = 1; + break; + } + + if (msg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) + { + page = TRUE; + } + + if (msg->Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT | IEQUALIFIER_CONTROL)) + { + extreme = TRUE; + } + + if (scroll) + { + IPTR getsel; + struct TagItem tags[] = + { + { GTLV_Selected, (IPTR) &getsel }, + { TAG_IGNORE, TRUE }, + { TAG_DONE } }; + WORD sel; + + GT_GetGadgetAttrsA(lvgad, win, NULL, tags); + sel = (WORD) getsel; + + if (extreme) + { + scroll *= ci->nummatchnodes; + } + else if (page) + { + scroll *= visible_lv_lines; + } + + sel += scroll; + if (sel < 0) + sel = ci->nummatchnodes - 1; + if (sel >= ci->nummatchnodes) + sel = 0; + + tags[0].ti_Data = (IPTR) sel; + tags[1].ti_Tag = GTLV_MakeVisible; + tags[1].ti_Data = (IPTR) sel; + + GT_SetGadgetAttrsA(lvgad, win, NULL, tags); + } + } + break; + + case IDCMP_GADGETUP: + gad = (struct Gadget *) msg->IAddress; + + switch (gad->GadgetID) + { + case ID_OK: + doit = TRUE; + break; + + case ID_CANCEL: + done = TRUE; + break; + + case ID_LISTVIEW: + CurrentTime(&sec, µ); + if (DoubleClick(secold, microold, sec, micro)) + doit = TRUE; + secold = sec; + microold = micro; + break; + } + break; + + } /* switch(msg->Class) */ + + GT_ReplyIMsg(msg); + + } /* while((msg = GT_GetIMsg(win->UserPort))) */ + + } /* while (!done && !doit) */ + + if (doit) + { + struct Node *node; + IPTR sel; + + struct TagItem gettags[] = + { + { GTLV_Selected, (IPTR) &sel }, + { TAG_DONE } }; + + GT_GetGadgetAttrsA(lvgad, win, NULL, gettags); + + i = 0; + ForeachNode(&ci->matchlist, node) + { + if ((WORD) sel == i) + { + AddPart(ci->match, node->ln_Name, sizeof(ci->match)); + + retval = TRUE; + break; + } + i++; + } + + } /* if (doit) */ + + CloseWindow(win); + + } /* if ((win = OpenWindowTagList(NULL, wintags))) */ + + } /* if (gad) */ + + FreeGadgets(gadlist); + FreeVisualInfo(vi); + + } /* if ((vi = GetVisualInfoA(ci->fh->window->WScreen, NULL))) */ + + FreeScreenDrawInfo(ci->fh->window->WScreen, dri); + + } /* if ((dri = GetScreenDrawInfo(fh->window->WScreen))) */ + + return retval; +} + +/****************************************************************************************/ + +void Completion(struct filehandle *fh, BOOL withinfo) +{ + struct completioninfo *ci; + + if ((ci = InitCompletion(fh, withinfo))) + { + PrepareCompletion(fh, ci); + + if (!ci->dirpart[0] && !ci->filepart[0]) + { + DoFileReq(fh, ci); + } + else + { + if (PreparePattern(fh, ci)) + { + BOOL doprint = FALSE; + + DoScan(fh, ci); + + strncpy(ci->match, ci->dirpart, sizeof(ci->match)); + + if (ci->nummatchnodes == 1) + { + AddPart(ci->match, ((struct matchnode *) GetHead(&ci->matchlist))->name, sizeof(ci->match)); + + doprint = TRUE; + } + else if (ci->nummatchnodes > 1) + { + doprint = DoChooseReq(fh, ci); + } + + if (doprint) + { + WORD backspaces; + UBYTE c; + + if (strchr(ci->match, ' ')) + AddQuotes(ci, ci->match, sizeof(ci->match)); + + /* Insert as many backspaces in front of the string, + to erase whole "word" first (starting at ci->wordstart) + before reprinting expanded filename */ + + backspaces = ci->fh->inputpos - ci->wordstart; + + memmove(ci->match + backspaces, ci->match, sizeof(ci->match) - backspaces); + memset(ci->match, 8, backspaces); + + c = ci->match[strlen(ci->match) - 1]; + if ((c != '/') && (c != ':')) + { + strncat(ci->match, " ", sizeof(ci->match)); + } + + InsertIntoConBuffer(ci, ci->match); + + } + } + } + + CleanupCompletion(ci); + + } /* if ((ci = InitCompletion())) */ + +} + +/****************************************************************************************/ diff --git a/rom/filesys/console_handler/con_handler.c b/rom/filesys/console_handler/con_handler.c dissimilarity index 84% index 4a5bdc8138..fe7a62ccc8 100644 --- a/rom/filesys/console_handler/con_handler.c +++ b/rom/filesys/console_handler/con_handler.c @@ -1,633 +1,650 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "con_handler_intern.h" -#include "support.h" - -#undef SDEBUG -#undef DEBUG -#define SDEBUG 0 -#define DEBUG 0 -#include - -static char *BSTR2C(BSTR srcs) -{ - UBYTE *src = BADDR(srcs); - char *dst; - - dst = AllocVec(src[0] + 1, MEMF_ANY); - if (!dst) - return NULL; - memcpy (dst, src + 1, src[0]); - dst[src[0]] = 0; - return dst; -} -static WORD isdosdevicec(CONST_STRPTR s) -{ - UBYTE b = 0; - while (s[b]) { - if (s[b] == ':') - return b; - b++; - } - return -1; -} - -#define ioReq(x) ((struct IORequest *)x) - -static const struct NewWindow default_nw = -{ - 0, /* LeftEdge */ - 0, /* TopEdge */ - -1, /* Width */ - -1, /* Height */ - 1, /* DetailPen */ - 0, /* BlockPen */ - 0, /* IDCMP */ - WFLG_DEPTHGADGET | - WFLG_SIZEGADGET | - WFLG_DRAGBAR | - WFLG_SIZEBRIGHT | - WFLG_SMART_REFRESH | - WFLG_ACTIVATE, - 0, /* FirstGadget */ - 0, /* CheckMark */ - "CON:", /* Title */ - 0, /* Screen */ - 0, /* Bitmap */ - 100, /* MinWidth */ - 70, /* MinHeight */ - 32767, /* MaxWidth */ - 32767, /* MaxHeight */ - WBENCHSCREEN /* type */ -}; - - -static LONG MakeConWindow(struct filehandle *fh) -{ - LONG err = 0; - - if (fh->otherwindow == NULL) { - struct TagItem win_tags [] = - { - {WA_PubScreen ,0 }, - {WA_AutoAdjust ,TRUE }, - {WA_PubScreenName ,0 }, - {WA_PubScreenFallBack ,TRUE }, - {TAG_DONE } - }; - - win_tags[2].ti_Data = (IPTR)fh->screenname; - D(bug("[contask] Opening window on screen %s, IntuitionBase = 0x%p\n", fh->screenname, IntuitionBase)); - - /* Autoadjust doesn't enforce the window's width and height to be larger than - minwidth and minheight, so we set it here to avoid crashes in devs/console - if a user does e.g. dir >con:0/0/0/0 - */ - fh->nw.Width = fh->nw.Width > fh->nw.MinWidth ? fh->nw.Width : -1; - fh->nw.Height = fh->nw.Height == -1 || fh->nw.Height > fh->nw.MinHeight ? fh->nw.Height : fh->nw.MinHeight; - - fh->window = OpenWindowTagList(&fh->nw, (struct TagItem *)win_tags); - } else { - D(bug("[contask] Using window %p\n", fh->otherwindow)); - fh->window = fh->otherwindow; - } - - if (fh->window) - { - D(bug("contask: window opened\n")); - fh->conreadio->io_Data = (APTR)fh->window; - fh->conreadio->io_Length = sizeof (struct Window); - - if (0 == OpenDevice("console.device", CONU_SNIPMAP, ioReq(fh->conreadio), 0)) - { - const UBYTE lf_on[] = {0x9B, 0x32, 0x30, 0x68 }; /* Set linefeed mode */ - - D(bug("contask: device opened\n")); - - fh->flags |= FHFLG_CONSOLEDEVICEOPEN; - - fh->conwriteio = *fh->conreadio; - fh->conwriteio.io_Message.mn_ReplyPort = fh->conwritemp; - - /* Turn the console into LF+CR mode so that both - linefeed and carriage return is done on - */ - fh->conwriteio.io_Command = CMD_WRITE; - fh->conwriteio.io_Data = (APTR)lf_on; - fh->conwriteio.io_Length = 4; - - DoIO(ioReq(&fh->conwriteio)); - - } /* if (0 == OpenDevice("console.device", CONU_STANDARD, ioReq(fh->conreadio), 0)) */ - else - { - err = ERROR_INVALID_RESIDENT_LIBRARY; - } - if (err) CloseWindow(fh->window); - - } /* if (fh->window) */ - else - { - D(bug("[contask] Failed to open a window\n")); - err = ERROR_NO_FREE_STORE; - } - - return err; -} - -static BOOL MakeSureWinIsOpen(struct filehandle *fh) -{ - if (fh->window) - return TRUE; - return MakeConWindow(fh) == 0; -} - -static void close_con(struct filehandle *fh) -{ - /* Clean up */ - - D(bug("[CON] Deleting timer request 0x%p\n", fh->timerreq)); - if (fh->timerreq) - { - CloseDevice((struct IORequest *)fh->timerreq); - DeleteIORequest((struct IORequest *)fh->timerreq); - } - - D(bug("[CON] Deleting timer port 0x%p\n", fh->timermp)); - DeleteMsgPort(fh->timermp); - - if (fh->flags & FHFLG_CONSOLEDEVICEOPEN) - { - D(bug("[CON] Closing console.device...\n")); - CloseDevice((struct IORequest *)fh->conreadio); - } - - D(bug("[CON] Closing window 0x%p\n", fh->window)); - if (fh->window) - CloseWindow(fh->window); - - D(bug("[CON] Delete console.device IORequest 0x%p\n", fh->conreadio)); - DeleteIORequest(ioReq(fh->conreadio)); - - D(bug("[CON] Delete console.device MsgPort 0x%p\n", fh->conreadmp)); - FreeVec(fh->conreadmp); - - if (fh->screenname) - FreeVec(fh->screenname); - if (fh->wintitle) - FreeVec(fh->wintitle); - if (fh->pastebuffer) - FreeMem(fh->pastebuffer,PASTEBUFSIZE); - - CloseLibrary((struct Library*)fh->intuibase); - CloseLibrary((struct Library*)fh->dosbase); - - /* These libraries are opened only if completion was used */ - if (fh->gfxbase) - CloseLibrary((struct Library*)fh->gfxbase); - if (fh->gtbase) - CloseLibrary(fh->gtbase); - - FreeVec(fh); -} - -static struct filehandle *open_con(struct DosPacket *dp, LONG *perr) -{ - char *filename, *fn; - struct filehandle *fh; - struct DeviceNode *dn; - LONG err, ok; - LONG i; - - dn = BADDR(dp->dp_Arg3); - *perr = ERROR_NO_FREE_STORE; - fh = AllocVec(sizeof(struct filehandle), MEMF_PUBLIC | MEMF_CLEAR); - if (!fh) - return NULL; - - fh->intuibase = (APTR)OpenLibrary("intuition.library", 0); - fh->dosbase = (APTR)OpenLibrary("dos.library", 0); - fh->utilbase = (APTR)OpenLibrary("utility.library", 0); - Forbid(); - fh->inputbase = (struct Device *)FindName(&SysBase->DeviceList, "input.device"); - Permit(); - - if (!fh->intuibase || !fh->dosbase || !fh->utilbase || !fh->inputbase) { - CloseLibrary((APTR)fh->utilbase); - CloseLibrary((APTR)fh->dosbase); - CloseLibrary((APTR)fh->intuibase); - FreeVec(fh); - return NULL; - } - - fh->timermp = CreateMsgPort(); - fh->timerreq = (struct timerequest*)CreateIORequest(fh->timermp, sizeof(struct timerequest)); - OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)fh->timerreq, 0); - - err = 0; - filename = BSTR2C((BSTR)dp->dp_Arg1); - fn = filename; - i = isdosdevicec(fn); - if (i >= 0) - fn += i + 1; - - fh->contask = FindTask(0); - - NEWLIST(&fh->pendingReads); - - /* Create msgport for console.device communication */ - fh->conreadmp = AllocVec(sizeof (struct MsgPort) * 2, MEMF_PUBLIC|MEMF_CLEAR); - if (fh->conreadmp) - { - - fh->conreadmp->mp_Node.ln_Type = NT_MSGPORT; - fh->conreadmp->mp_Flags = PA_SIGNAL; - fh->conreadmp->mp_SigBit = AllocSignal(-1); - fh->conreadmp->mp_SigTask = fh->contask; - NEWLIST(&fh->conreadmp->mp_MsgList); - - fh->conwritemp = fh->conreadmp + 1; - - fh->conwritemp->mp_Node.ln_Type = NT_MSGPORT; - fh->conwritemp->mp_Flags = PA_SIGNAL; - fh->conwritemp->mp_SigBit = AllocSignal(-1); - fh->conwritemp->mp_SigTask = fh->contask; - NEWLIST(&fh->conwritemp->mp_MsgList); - - - fh->conreadio = (struct IOStdReq *)CreateIORequest(fh->conreadmp, sizeof (struct IOStdReq)); - if (fh->conreadio) - { - D(bug("contask: conreadio created, parms '%s'\n", fn)); - - fh->nw = default_nw; - - if (parse_filename(fh, fn, &fh->nw)) - { - if (!(fh->flags & FHFLG_AUTO)) - { - err = MakeConWindow(fh); - if (!err) - ok = TRUE; - } - else - { - ok = TRUE; - } - } - else - err = ERROR_BAD_STREAM_NAME; - - if (!ok) - { - DeleteIORequest(ioReq(fh->conreadio)); - } - - } /* if (fh->conreadio) */ - else - { - err = ERROR_NO_FREE_STORE; - } - - } /* if (fh->conreadmp) */ - else - { - err = ERROR_NO_FREE_STORE; - } - - if (dn->dn_Startup) - fh->flags |= FHFLG_RAW; - - if (!ok) - close_con(fh); - - *perr = err; - FreeVec(filename); - return fh; -} - -static void startread(struct filehandle *fh) -{ - if (fh->flags & FHFLG_ASYNCCONSOLEREAD) - return; - fh->conreadio->io_Command = CMD_READ; - fh->conreadio->io_Data = fh->consolebuffer; - fh->conreadio->io_Length = CONSOLEBUFFER_SIZE; - SendIO((struct IORequest*)fh->conreadio); - fh->flags |= FHFLG_ASYNCCONSOLEREAD; -} - -static void stopwait(struct filehandle *fh, struct DosPacket *waitingdp, ULONG result) -{ - if (waitingdp) - { - AbortIO((struct IORequest *)fh->timerreq); - WaitIO((struct IORequest *)fh->timerreq); - replypkt(waitingdp, result); - } -} - -static void stopread(struct filehandle *fh, struct DosPacket *waitingdp) -{ - struct Message *msg, *next_msg; - - stopwait(fh, waitingdp, DOSFALSE); - - ForeachNodeSafe(&fh->pendingReads, msg, next_msg) - { - struct DosPacket *dpr; - - Remove((struct Node *)msg); - dpr = (struct DosPacket*)msg->mn_Node.ln_Name; - replypkt(dpr, DOSFALSE); - } -} - -LONG CONMain(struct ExecBase *SysBase) -{ - struct MsgPort *mp; - struct DosPacket *dp; - struct Message *mn; - struct FileHandle *dosfh; - LONG error; - struct filehandle *fh; - struct FileLock *fl; - struct DosPacket *waitingdp = NULL; - - D(bug("[CON] started\n")); - mp = &((struct Process*)FindTask(NULL))->pr_MsgPort; - WaitPort(mp); - dp = (struct DosPacket*)GetMsg(mp)->mn_Node.ln_Name; - D(bug("[CON] startup message received. port=0x%p path='%b'\n", mp, dp->dp_Arg1)); - - fh = open_con(dp, &error); - if (!fh) { - D(bug("[CON] init failed\n")); - goto end; - } - D(bug("[CON] 0x%p open\n", fh)); - replypkt(dp, DOSTRUE); - - for(;;) - { - ULONG conreadmask = 1L << fh->conreadmp->mp_SigBit; - ULONG timermask = 1L << fh->timermp->mp_SigBit; - ULONG packetmask = 1L << mp->mp_SigBit; - ULONG sigs; - - sigs = Wait(packetmask | conreadmask | timermask); - - if (sigs & timermask) { - if (waitingdp) { - replypkt(waitingdp, DOSFALSE); - waitingdp = NULL; - } - } - - if (sigs & conreadmask) { - GetMsg(fh->conreadmp); - fh->flags &= ~FHFLG_ASYNCCONSOLEREAD; - if (waitingdp) - { - stopwait(fh, waitingdp, DOSTRUE); - waitingdp = NULL; - } - D(bug("IO_READ %d\n", fh->conreadio->io_Actual)); - fh->conbuffersize = fh->conreadio->io_Actual; - fh->conbufferpos = 0; - /* terminate with 0 char */ - fh->consolebuffer[fh->conbuffersize] = '\0'; - if (fh->flags & FHFLG_RAW) - { - LONG inp; - /* raw mode */ - for(inp = 0; (inp < fh->conbuffersize) && (fh->inputpos < INPUTBUFFER_SIZE); ) - { - fh->inputbuffer[fh->inputpos++] = fh->consolebuffer[inp++]; - } - fh->inputsize = fh->inputstart = fh->inputpos; - HandlePendingReads(fh); - } /* if (fh->flags & FHFLG_RAW) */ - else - { - /* Cooked mode */ - if (process_input(fh)) - { - /* - * process_input() returns TRUE when EOF was received after the WAIT console - * has been closed by the owner. - */ - dp = NULL; - goto end; - } - } /* if (fh->flags & FHFLG_RAW) else ... */ - startread(fh); - } - - while ((mn = GetMsg(mp))) { - dp = (struct DosPacket*)mn->mn_Node.ln_Name; - dp->dp_Res2 = 0; - D(bug("[CON 0x%p] packet 0x%p:%d 0x%p,0x%p,0x%p\n", - fh, dp, dp->dp_Type, dp->dp_Arg1, dp->dp_Arg2, dp->dp_Arg3)); - error = 0; - switch (dp->dp_Type) - { - case ACTION_FH_FROM_LOCK: - fl = BADDR(dp->dp_Arg2); - if (fl->fl_Task != mp || - fl->fl_Key != (IPTR)fh) { - replypkt2(dp, DOSFALSE, ERROR_OBJECT_NOT_FOUND); - break; - } - fh->usecount--; - FreeMem(fl, sizeof(*fl)); - /* Fallthrough */ - case ACTION_FINDINPUT: - case ACTION_FINDOUTPUT: - case ACTION_FINDUPDATE: - dosfh = BADDR(dp->dp_Arg1); - dosfh->fh_Interactive = DOSTRUE; - dosfh->fh_Arg1 = (SIPTR)fh; - fh->usecount++; - fh->breaktask = dp->dp_Port->mp_SigTask; - D(bug("[CON] Find fh=%x. Usecount=%d\n", dosfh, fh->usecount)); - replypkt(dp, DOSTRUE); - break; - case ACTION_COPY_DIR_FH: - fl = AllocMem(sizeof(*fl), MEMF_CLEAR | MEMF_PUBLIC); - if (fl == BNULL) { - replypkt2(dp, (SIPTR)BNULL, ERROR_NO_FREE_STORE); - } else { - fh->usecount++; - fl->fl_Task = mp; - fl->fl_Key = (IPTR)fh; - replypkt(dp, (SIPTR)MKBADDR(fl)); - } - break; - case ACTION_END: - fh->usecount--; - D(bug("[CON] usecount=%d\n", fh->usecount)); - if (fh->usecount <= 0) - { - if (fh->flags & FHFLG_WAIT) - { - D(bug("[CON] Delayed close, waiting...\n")); - - /* - * Bounce all pending read and waits (the same as we do when exiting). - * However the process is still around, waiting for EOF input. - * Our user has just closed his struct FileHandle and dropped us. - */ - stopread(fh, waitingdp); - waitingdp = NULL; - fh->flags = (fh->flags & ~FHFLG_READPENDING) | FHFLG_WAITFORCLOSE; - } - else - goto end; - } - replypkt(dp, DOSTRUE); - break; - case ACTION_READ: - if (!MakeSureWinIsOpen(fh)) { - replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE); - break; - } - fh->breaktask = dp->dp_Port->mp_SigTask; - startread(fh); - con_read(fh, dp); - break; - case ACTION_WRITE: - if (!MakeSureWinIsOpen(fh)) { - replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE); - break; - } - fh->breaktask = dp->dp_Port->mp_SigTask; - startread(fh); - answer_write_request(fh, dp); - break; - case ACTION_SCREEN_MODE: - { - D(bug("ACTION_SCREEN_MODE %s\n", dp->dp_Arg1 ? "RAW" : "CON")); - if (dp->dp_Arg1 && !(fh->flags & FHFLG_RAW)) - { - /* Switching from CON: mode to RAW: mode */ - fh->flags |= FHFLG_RAW; - fh->inputstart = fh->inputsize; - fh->inputpos = fh->inputsize; - HandlePendingReads(fh); - } - else - { - /* otherwise just copy the flags */ - if (dp->dp_Arg1) - fh->flags |= FHFLG_RAW; - else - fh->flags &= ~FHFLG_RAW; - } - replypkt(dp, DOSTRUE); - } - break; - case ACTION_CHANGE_SIGNAL: - { - struct Task *old = fh->breaktask; - if (dp->dp_Arg2) - fh->breaktask = (struct Task*)dp->dp_Arg2; - replypkt2(dp, DOSTRUE, (SIPTR)old); - } - break; - case ACTION_WAIT_CHAR: - { - if (!MakeSureWinIsOpen(fh)) { - replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE); - break; - } - if (fh->inputsize > 0) - { - replypkt(dp, DOSTRUE); - } - else - { - LONG timeout = dp->dp_Arg1; - LONG sec = timeout / 1000000; - LONG usec = timeout % 1000000; - - fh->timerreq->tr_node.io_Command = TR_ADDREQUEST; - fh->timerreq->tr_time.tv_secs = sec; - fh->timerreq->tr_time.tv_micro = usec; - SendIO((struct IORequest *)fh->timerreq); - waitingdp = dp; - } - startread(fh); - } - break; - case ACTION_IS_FILESYSTEM: - replypkt(dp, DOSFALSE); - break; - case ACTION_DISK_INFO: - { - /* strange console handler features */ - struct InfoData *id = BADDR(dp->dp_Arg1); - memset(id, 0, sizeof(struct InfoData)); - id->id_DiskType = (fh->flags & FHFLG_RAW) ? - AROS_MAKE_ID('R','A','W', 0) : AROS_MAKE_ID('C','O','N', 0); - id->id_VolumeNode = (BPTR)fh->window; - id->id_InUse = (IPTR)fh->conreadio; - replypkt(dp, DOSTRUE); - } - break; - case ACTION_SEEK: - /* Yes, DOSTRUE. Check Guru Book for details. */ - replypkt2(dp, DOSTRUE, ERROR_ACTION_NOT_KNOWN); - break; - default: - bug("[CON] unknown action %d\n", dp->dp_Type); - replypkt2(dp, DOSFALSE, ERROR_ACTION_NOT_KNOWN); - break; - } - } - } -end: - D(bug("[CON] 0x%p closing\n", fh)); - if (fh) - { - D(bug("[CON] Cancelling read requests...\n")); - stopread(fh, waitingdp); - - if (fh->flags & FHFLG_ASYNCCONSOLEREAD) - { - D(bug("[CON] Aborting console ioReq 0x%p\n", fh->conreadio)); - - AbortIO(ioReq(fh->conreadio)); - WaitIO(ioReq(fh->conreadio)); - } - - D(bug("[CON] Closing handle...\n")); - close_con(fh); - } - - if (dp) - { - D(bug("[CON] Replying packet 0x%p\n", dp)); - replypkt(dp, DOSFALSE); - } - - D(bug("[CON] 0x%p closed\n", fh)); - return 0; -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "con_handler_intern.h" +#include "support.h" + +#undef SDEBUG +#undef DEBUG +#define SDEBUG 0 +#define DEBUG 0 +#include + +static char *BSTR2C(BSTR srcs) +{ + UBYTE *src = BADDR(srcs); + char *dst; + + dst = AllocVec(src[0] + 1, MEMF_ANY); + if (!dst) + return NULL; + memcpy(dst, src + 1, src[0]); + dst[src[0]] = 0; + return dst; +} +static WORD isdosdevicec(CONST_STRPTR s) +{ + UBYTE b = 0; + while (s[b]) + { + if (s[b] == ':') + return b; + b++; + } + return -1; +} + +#define ioReq(x) ((struct IORequest *)x) + +static const struct NewWindow default_nw = +{ + 0, /* LeftEdge */ + 0, /* TopEdge */ + -1, /* Width */ + -1, /* Height */ + 1, /* DetailPen */ + 0, /* BlockPen */ + 0, /* IDCMP */ + WFLG_DEPTHGADGET | + WFLG_SIZEGADGET | + WFLG_DRAGBAR | + WFLG_SIZEBRIGHT | + WFLG_SMART_REFRESH | + WFLG_ACTIVATE, + 0, /* FirstGadget */ + 0, /* CheckMark */ + "CON:", /* Title */ + 0, /* Screen */ + 0, /* Bitmap */ + 100, /* MinWidth */ + 70, /* MinHeight */ + 32767, /* MaxWidth */ + 32767, /* MaxHeight */ + WBENCHSCREEN /* type */ +}; + + +static LONG MakeConWindow(struct filehandle *fh) +{ + LONG err = 0; + + if (fh->otherwindow == NULL) + { + struct TagItem win_tags[] = + { + { WA_PubScreen, 0 }, + { WA_AutoAdjust, TRUE }, + { WA_PubScreenName, 0 }, + { WA_PubScreenFallBack, TRUE }, + { TAG_DONE } + }; + + win_tags[2].ti_Data = (IPTR) fh->screenname; + D(bug("[contask] Opening window on screen %s, IntuitionBase = 0x%p\n", fh->screenname, IntuitionBase)); + + /* Autoadjust doesn't enforce the window's width and height to be larger than + minwidth and minheight, so we set it here to avoid crashes in devs/console + if a user does e.g. dir >con:0/0/0/0 + */ + fh->nw.Width = fh->nw.Width > fh->nw.MinWidth ? fh->nw.Width : -1; + fh->nw.Height = fh->nw.Height == -1 || fh->nw.Height > fh->nw.MinHeight ? fh->nw.Height : fh->nw.MinHeight; + + fh->window = OpenWindowTagList(&fh->nw, (struct TagItem *) win_tags); + } + else + { + D(bug("[contask] Using window %p\n", fh->otherwindow)); + fh->window = fh->otherwindow; + } + + if (fh->window) + { + D(bug("contask: window opened\n")); + fh->conreadio->io_Data = (APTR) fh->window; + fh->conreadio->io_Length = sizeof(struct Window); + + if (0 == OpenDevice("console.device", CONU_SNIPMAP, ioReq(fh->conreadio), 0)) + { + const UBYTE lf_on[] = + { 0x9B, 0x32, 0x30, 0x68 }; /* Set linefeed mode */ + + D(bug("contask: device opened\n")); + + fh->flags |= FHFLG_CONSOLEDEVICEOPEN; + + fh->conwriteio = *fh->conreadio; + fh->conwriteio.io_Message.mn_ReplyPort = fh->conwritemp; + + /* Turn the console into LF+CR mode so that both + linefeed and carriage return is done on + */ + fh->conwriteio.io_Command = CMD_WRITE; + fh->conwriteio.io_Data = (APTR) lf_on; + fh->conwriteio.io_Length = 4; + + DoIO(ioReq(&fh->conwriteio)); + + } /* if (0 == OpenDevice("console.device", CONU_STANDARD, ioReq(fh->conreadio), 0)) */ + else + { + err = ERROR_INVALID_RESIDENT_LIBRARY; + } + if (err) + CloseWindow(fh->window); + + } /* if (fh->window) */ + else + { + D(bug("[contask] Failed to open a window\n")); + err = ERROR_NO_FREE_STORE; + } + + return err; +} + +static BOOL MakeSureWinIsOpen(struct filehandle *fh) +{ + if (fh->window) + return TRUE; + return MakeConWindow(fh) == 0; +} + +static void close_con(struct filehandle *fh) +{ + /* Clean up */ + + D(bug("[CON] Deleting timer request 0x%p\n", fh->timerreq)); + if (fh->timerreq) + { + CloseDevice((struct IORequest *) fh->timerreq); + DeleteIORequest((struct IORequest *) fh->timerreq); + } + + D(bug("[CON] Deleting timer port 0x%p\n", fh->timermp)); + DeleteMsgPort(fh->timermp); + + if (fh->flags & FHFLG_CONSOLEDEVICEOPEN) + { + D(bug("[CON] Closing console.device...\n")); + CloseDevice((struct IORequest *) fh->conreadio); + } + + D(bug("[CON] Closing window 0x%p\n", fh->window)); + if (fh->window) + CloseWindow(fh->window); + + D(bug("[CON] Delete console.device IORequest 0x%p\n", fh->conreadio)); + DeleteIORequest(ioReq(fh->conreadio)); + + D(bug("[CON] Delete console.device MsgPort 0x%p\n", fh->conreadmp)); + FreeVec(fh->conreadmp); + + if (fh->screenname) + FreeVec(fh->screenname); + if (fh->wintitle) + FreeVec(fh->wintitle); + if (fh->pastebuffer) + FreeMem(fh->pastebuffer, PASTEBUFSIZE); + + CloseLibrary((struct Library*) fh->intuibase); + CloseLibrary((struct Library*) fh->dosbase); + + /* These libraries are opened only if completion was used */ + if (fh->gfxbase) + CloseLibrary((struct Library*) fh->gfxbase); + if (fh->gtbase) + CloseLibrary(fh->gtbase); + + FreeVec(fh); +} + +static struct filehandle *open_con(struct DosPacket *dp, LONG *perr) +{ + char *filename, *fn; + struct filehandle *fh; + struct DeviceNode *dn; + LONG err, ok; + LONG i; + + dn = BADDR(dp->dp_Arg3); + *perr = ERROR_NO_FREE_STORE; + fh = AllocVec(sizeof(struct filehandle), MEMF_PUBLIC | MEMF_CLEAR); + if (!fh) + return NULL; + + fh->intuibase = (APTR) OpenLibrary("intuition.library", 0); + fh->dosbase = (APTR) OpenLibrary("dos.library", 0); + fh->utilbase = (APTR) OpenLibrary("utility.library", 0); + Forbid(); + fh->inputbase = (struct Device *) FindName(&SysBase->DeviceList, "input.device"); + Permit(); + + if (!fh->intuibase || !fh->dosbase || !fh->utilbase || !fh->inputbase) + { + CloseLibrary((APTR) fh->utilbase); + CloseLibrary((APTR) fh->dosbase); + CloseLibrary((APTR) fh->intuibase); + FreeVec(fh); + return NULL; + } + + fh->timermp = CreateMsgPort(); + fh->timerreq = (struct timerequest*) CreateIORequest(fh->timermp, sizeof(struct timerequest)); + OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *) fh->timerreq, 0); + + err = 0; + filename = BSTR2C((BSTR) dp->dp_Arg1); + fn = filename; + i = isdosdevicec(fn); + if (i >= 0) + fn += i + 1; + + fh->contask = FindTask(0); + + NEWLIST(&fh->pendingReads); + + /* Create msgport for console.device communication */ + fh->conreadmp = AllocVec(sizeof(struct MsgPort) * 2, MEMF_PUBLIC | MEMF_CLEAR); + if (fh->conreadmp) + { + + fh->conreadmp->mp_Node.ln_Type = NT_MSGPORT; + fh->conreadmp->mp_Flags = PA_SIGNAL; + fh->conreadmp->mp_SigBit = AllocSignal(-1); + fh->conreadmp->mp_SigTask = fh->contask; + NEWLIST(&fh->conreadmp->mp_MsgList); + + fh->conwritemp = fh->conreadmp + 1; + + fh->conwritemp->mp_Node.ln_Type = NT_MSGPORT; + fh->conwritemp->mp_Flags = PA_SIGNAL; + fh->conwritemp->mp_SigBit = AllocSignal(-1); + fh->conwritemp->mp_SigTask = fh->contask; + NEWLIST(&fh->conwritemp->mp_MsgList); + + fh->conreadio = (struct IOStdReq *) CreateIORequest(fh->conreadmp, sizeof(struct IOStdReq)); + if (fh->conreadio) + { + D(bug("contask: conreadio created, parms '%s'\n", fn)); + + fh->nw = default_nw; + + if (parse_filename(fh, fn, &fh->nw)) + { + if (!(fh->flags & FHFLG_AUTO)) + { + err = MakeConWindow(fh); + if (!err) + ok = TRUE; + } + else + { + ok = TRUE; + } + } + else + err = ERROR_BAD_STREAM_NAME; + + if (!ok) + { + DeleteIORequest(ioReq(fh->conreadio)); + } + + } /* if (fh->conreadio) */ + else + { + err = ERROR_NO_FREE_STORE; + } + + } /* if (fh->conreadmp) */ + else + { + err = ERROR_NO_FREE_STORE; + } + + if (dn->dn_Startup) + fh->flags |= FHFLG_RAW; + + if (!ok) + close_con(fh); + + *perr = err; + FreeVec(filename); + return fh; +} + +static void startread(struct filehandle *fh) +{ + if (fh->flags & FHFLG_ASYNCCONSOLEREAD) + return; + fh->conreadio->io_Command = CMD_READ; + fh->conreadio->io_Data = fh->consolebuffer; + fh->conreadio->io_Length = CONSOLEBUFFER_SIZE; + SendIO((struct IORequest*) fh->conreadio); + fh->flags |= FHFLG_ASYNCCONSOLEREAD; +} + +static void stopwait(struct filehandle *fh, struct DosPacket *waitingdp, ULONG result) +{ + if (waitingdp) + { + AbortIO((struct IORequest *) fh->timerreq); + WaitIO((struct IORequest *) fh->timerreq); + replypkt(waitingdp, result); + } +} + +static void stopread(struct filehandle *fh, struct DosPacket *waitingdp) +{ + struct Message *msg, *next_msg; + + stopwait(fh, waitingdp, DOSFALSE); + + ForeachNodeSafe(&fh->pendingReads, msg, next_msg) + { + struct DosPacket *dpr; + + Remove((struct Node *) msg); + dpr = (struct DosPacket*) msg->mn_Node.ln_Name; + replypkt(dpr, DOSFALSE); + } +} + +LONG CONMain(struct ExecBase *SysBase) +{ + struct MsgPort *mp; + struct DosPacket *dp; + struct Message *mn; + struct FileHandle *dosfh; + LONG error; + struct filehandle *fh; + struct FileLock *fl; + struct DosPacket *waitingdp = NULL; + + D(bug("[CON] started\n")); + mp = &((struct Process*) FindTask(NULL))->pr_MsgPort; + WaitPort(mp); + dp = (struct DosPacket*) GetMsg(mp)->mn_Node.ln_Name; + D(bug("[CON] startup message received. port=0x%p path='%b'\n", mp, dp->dp_Arg1)); + + fh = open_con(dp, &error); + if (!fh) + { + D(bug("[CON] init failed\n")); + goto end; + } + D(bug("[CON] 0x%p open\n", fh)); + replypkt(dp, DOSTRUE); + + for (;;) + { + ULONG conreadmask = 1L << fh->conreadmp->mp_SigBit; + ULONG timermask = 1L << fh->timermp->mp_SigBit; + ULONG packetmask = 1L << mp->mp_SigBit; + ULONG sigs; + + sigs = Wait(packetmask | conreadmask | timermask); + + if (sigs & timermask) + { + if (waitingdp) + { + replypkt(waitingdp, DOSFALSE); + waitingdp = NULL; + } + } + + if (sigs & conreadmask) + { + GetMsg(fh->conreadmp); + fh->flags &= ~FHFLG_ASYNCCONSOLEREAD; + if (waitingdp) + { + stopwait(fh, waitingdp, DOSTRUE); + waitingdp = NULL; + } + D(bug("IO_READ %d\n", fh->conreadio->io_Actual)); + fh->conbuffersize = fh->conreadio->io_Actual; + fh->conbufferpos = 0; + /* terminate with 0 char */ + fh->consolebuffer[fh->conbuffersize] = '\0'; + if (fh->flags & FHFLG_RAW) + { + LONG inp; + /* raw mode */ + for (inp = 0; (inp < fh->conbuffersize) && (fh->inputpos < INPUTBUFFER_SIZE);) + { + fh->inputbuffer[fh->inputpos++] = fh->consolebuffer[inp++]; + } + fh->inputsize = fh->inputstart = fh->inputpos; + HandlePendingReads(fh); + } /* if (fh->flags & FHFLG_RAW) */ + else + { + /* Cooked mode */ + if (process_input(fh)) + { + /* + * process_input() returns TRUE when EOF was received after the WAIT console + * has been closed by the owner. + */ + dp = NULL; + goto end; + } + } /* if (fh->flags & FHFLG_RAW) else ... */ + startread(fh); + } + + while ((mn = GetMsg(mp))) + { + dp = (struct DosPacket*) mn->mn_Node.ln_Name; + dp->dp_Res2 = 0; + D( + bug("[CON 0x%p] packet 0x%p:%d 0x%p,0x%p,0x%p\n", fh, dp, dp->dp_Type, dp->dp_Arg1, dp->dp_Arg2, + dp->dp_Arg3)); + error = 0; + switch (dp->dp_Type) + { + case ACTION_FH_FROM_LOCK: + fl = BADDR(dp->dp_Arg2); + if (fl->fl_Task != mp || fl->fl_Key != (IPTR) fh) + { + replypkt2(dp, DOSFALSE, ERROR_OBJECT_NOT_FOUND); + break; + } + fh->usecount--; + FreeMem(fl, sizeof(*fl)); + /* Fallthrough */ + case ACTION_FINDINPUT: + case ACTION_FINDOUTPUT: + case ACTION_FINDUPDATE: + dosfh = BADDR(dp->dp_Arg1); + dosfh->fh_Interactive = DOSTRUE; + dosfh->fh_Arg1 = (SIPTR) fh; + fh->usecount++; + fh->breaktask = dp->dp_Port->mp_SigTask; + D(bug("[CON] Find fh=%x. Usecount=%d\n", dosfh, fh->usecount)); + replypkt(dp, DOSTRUE); + break; + case ACTION_COPY_DIR_FH: + fl = AllocMem(sizeof(*fl), MEMF_CLEAR | MEMF_PUBLIC); + if (fl == BNULL) + { + replypkt2(dp, (SIPTR) BNULL, ERROR_NO_FREE_STORE); + } + else + { + fh->usecount++; + fl->fl_Task = mp; + fl->fl_Key = (IPTR) fh; + replypkt(dp, (SIPTR) MKBADDR(fl)); + } + break; + case ACTION_END: + fh->usecount--; + D(bug("[CON] usecount=%d\n", fh->usecount)); + if (fh->usecount <= 0) + { + if (fh->flags & FHFLG_WAIT) + { + D(bug("[CON] Delayed close, waiting...\n")); + + /* + * Bounce all pending read and waits (the same as we do when exiting). + * However the process is still around, waiting for EOF input. + * Our user has just closed his struct FileHandle and dropped us. + */ + stopread(fh, waitingdp); + waitingdp = NULL; + fh->flags = (fh->flags & ~FHFLG_READPENDING) | FHFLG_WAITFORCLOSE; + } + else + goto end; + } + replypkt(dp, DOSTRUE); + break; + case ACTION_READ: + if (!MakeSureWinIsOpen(fh)) + { + replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE); + break; + } + fh->breaktask = dp->dp_Port->mp_SigTask; + startread(fh); + con_read(fh, dp); + break; + case ACTION_WRITE: + if (!MakeSureWinIsOpen(fh)) + { + replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE); + break; + } + fh->breaktask = dp->dp_Port->mp_SigTask; + startread(fh); + answer_write_request(fh, dp); + break; + case ACTION_SCREEN_MODE: + { + D(bug("ACTION_SCREEN_MODE %s\n", dp->dp_Arg1 ? "RAW" : "CON")); + if (dp->dp_Arg1 && !(fh->flags & FHFLG_RAW)) + { + /* Switching from CON: mode to RAW: mode */ + fh->flags |= FHFLG_RAW; + fh->inputstart = fh->inputsize; + fh->inputpos = fh->inputsize; + HandlePendingReads(fh); + } + else + { + /* otherwise just copy the flags */ + if (dp->dp_Arg1) + fh->flags |= FHFLG_RAW; + else + fh->flags &= ~FHFLG_RAW; + } + replypkt(dp, DOSTRUE); + } + break; + case ACTION_CHANGE_SIGNAL: + { + struct Task *old = fh->breaktask; + if (dp->dp_Arg2) + fh->breaktask = (struct Task*) dp->dp_Arg2; + replypkt2(dp, DOSTRUE, (SIPTR) old); + } + break; + case ACTION_WAIT_CHAR: + { + if (!MakeSureWinIsOpen(fh)) + { + replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE); + break; + } + if (fh->inputsize > 0) + { + replypkt(dp, DOSTRUE); + } + else + { + LONG timeout = dp->dp_Arg1; + LONG sec = timeout / 1000000; + LONG usec = timeout % 1000000; + + fh->timerreq->tr_node.io_Command = TR_ADDREQUEST; + fh->timerreq->tr_time.tv_secs = sec; + fh->timerreq->tr_time.tv_micro = usec; + SendIO((struct IORequest *) fh->timerreq); + waitingdp = dp; + } + startread(fh); + } + break; + case ACTION_IS_FILESYSTEM: + replypkt(dp, DOSFALSE); + break; + case ACTION_DISK_INFO: + { + /* strange console handler features */ + struct InfoData *id = BADDR(dp->dp_Arg1); + memset(id, 0, sizeof(struct InfoData)); + id->id_DiskType = + (fh->flags & FHFLG_RAW) ? AROS_MAKE_ID('R', 'A', 'W', 0) : AROS_MAKE_ID('C', 'O', 'N', 0); + id->id_VolumeNode = (BPTR) fh->window; + id->id_InUse = (IPTR) fh->conreadio; + replypkt(dp, DOSTRUE); + } + break; + case ACTION_SEEK: + /* Yes, DOSTRUE. Check Guru Book for details. */ + replypkt2(dp, DOSTRUE, ERROR_ACTION_NOT_KNOWN); + break; + default: + bug("[CON] unknown action %d\n", dp->dp_Type); + replypkt2(dp, DOSFALSE, ERROR_ACTION_NOT_KNOWN); + break; + } + } + } +end: + D(bug("[CON] 0x%p closing\n", fh)); + if (fh) + { + D(bug("[CON] Cancelling read requests...\n")); + stopread(fh, waitingdp); + + if (fh->flags & FHFLG_ASYNCCONSOLEREAD) + { + D(bug("[CON] Aborting console ioReq 0x%p\n", fh->conreadio)); + + AbortIO(ioReq(fh->conreadio)); + WaitIO(ioReq(fh->conreadio)); + } + + D(bug("[CON] Closing handle...\n")); + close_con(fh); + } + + if (dp) + { + D(bug("[CON] Replying packet 0x%p\n", dp)); + replypkt(dp, DOSFALSE); + } + + D(bug("[CON] 0x%p closed\n", fh)); + return 0; +} diff --git a/rom/filesys/console_handler/con_handler_intern.h b/rom/filesys/console_handler/con_handler_intern.h dissimilarity index 73% index f1914a7b19..6d2c05952d 100644 --- a/rom/filesys/console_handler/con_handler_intern.h +++ b/rom/filesys/console_handler/con_handler_intern.h @@ -1,129 +1,130 @@ -#ifndef __CON_HANDLER_INTERN_H -#define __CON_HANDLER_INTERN_H -/* - Copyright © 1995-2011, The AROS Development Team. All rights reserved. - $Id$ - - Desc: Internal header-file for emulation-handler. - Lang: english -*/ - -/* AROS includes */ -#include -#include -#include -#include -#include -#include - -/* -** stegerg: -** -** if BETTER_WRITE_HANDLING is #defined then writes are sent to -** console.device in smaller parts (max. 256 bytes or upto next -** LINEFEED). -** -** NOTE: Could be problematic with control sequences in case of -** the 256-Byte-Block write (write size is >256 but no LINE- -** FEED was found in this first (or better actual) 256 bytes -** to be written. -** -**/ - -#define BETTER_WRITE_HANDLING 1 -#define RMB_FREEZES_OUTPUT 1 - -#define CONTASK_STACKSIZE (AROS_STACKSIZE) -#define CONTASK_PRIORITY 5 - -#define CONSOLEBUFFER_SIZE 256 -#define INPUTBUFFER_SIZE 256 -#define CMD_HISTORY_SIZE 32 -#define PASTEBUFSIZE 16384 - -struct conTaskParams -{ - struct conbase *conbase; - struct Task *parentTask; - ULONG initSignal; -}; - -struct filehandle -{ - struct IOStdReq *conreadio; - struct IOStdReq conwriteio; - struct MsgPort *conreadmp; - struct MsgPort *conwritemp; - struct Window *window; - struct Window *otherwindow; /* WINDOW0xXXXXXXXX parameter */ - struct Task *contask; - struct Task *breaktask; - struct Task *lastwritetask; - struct MinList pendingReads; - struct NewWindow nw; - struct MsgPort *timermp; - struct timerequest *timerreq; - UBYTE *wintitle; - UBYTE *screenname; -#if BETTER_WRITE_HANDLING - LONG partlywrite_actual; - LONG partlywrite_size; -#endif - WORD conbufferpos; - WORD conbuffersize; - WORD inputstart; /* usually 0, but needed for multi-lines (CONTROL RETURN) */ - WORD inputpos; /* cursor pos. inside line */ - WORD inputsize; /* length of input string */ - WORD canreadsize; - WORD historysize; - WORD historypos; - WORD historyviewpos; - WORD usecount; - UWORD flags; - - UBYTE consolebuffer[CONSOLEBUFFER_SIZE + 2]; - UBYTE inputbuffer[INPUTBUFFER_SIZE + 2]; - UBYTE historybuffer[CMD_HISTORY_SIZE][INPUTBUFFER_SIZE + 1]; - - /* If pastebuffer != 0, this contains data to paste from ConClip */ - WORD pastebufferpos; - WORD pastebuffersize; - STRPTR pastebuffer; - struct Device *inputbase; - struct IntuitionBase *intuibase; - struct GfxBase *gfxbase; - struct DosLibrary *dosbase; - struct Library *gtbase; - struct Library *utilbase; -}; - -/* filehandle flags */ - -#define FHFLG_READPENDING 1 -#define FHFLG_WRITEPENDING 2 -#define FHFLG_CANREAD 4 -#define FHFLG_WAIT 8 /* filename contained WAIT */ -#define FHFLG_RAW 16 /* in RAW mode */ -#define FHFLG_ASYNCCONSOLEREAD 32 /* There is a pending async console.device CMD_READ request */ -#define FHFLG_AUTO 64 /* filename contained AUTO */ -#define FHFLG_CONSOLEDEVICEOPEN 128 -#define FHFLG_EOF 256 -#define FHFLG_WAITFORCLOSE 512 /* Console with WAIT is waiting to be closed */ - -#undef InputBase -#undef IntuitionBase -#undef DOSBase -#undef GadToolsBase -#undef UtilityBase - -/* FIXME: Remove these #define xxxBase hacks - Do not use this in new code ! -*/ -#define InputBase fh->inputbase -#define IntuitionBase fh->intuibase -#define DOSBase fh->dosbase -#define GadToolsBase fh->gtbase -#define GfxBase fh->gfxbase -#define UtilityBase fh->utilbase - -#endif /* __CON_HANDLER_INTERN_H */ +#ifndef __CON_HANDLER_INTERN_H +#define __CON_HANDLER_INTERN_H +/* + Copyright © 1995-2011, The AROS Development Team. All rights reserved. + $Id$ + + Desc: Internal header-file for emulation-handler. + Lang: english +*/ + +/* AROS includes */ +#include +#include +#include +#include +#include +#include + +/* + ** stegerg: + ** + ** if BETTER_WRITE_HANDLING is #defined then writes are sent to + ** console.device in smaller parts (max. 256 bytes or upto next + ** LINEFEED). + ** + ** NOTE: Could be problematic with control sequences in case of + ** the 256-Byte-Block write (write size is >256 but no LINE- + ** FEED was found in this first (or better actual) 256 bytes + ** to be written. + ** + **/ + +#define BETTER_WRITE_HANDLING 1 +#define RMB_FREEZES_OUTPUT 1 + +#define CONTASK_STACKSIZE (AROS_STACKSIZE) +#define CONTASK_PRIORITY 5 + +#define CONSOLEBUFFER_SIZE 256 +#define INPUTBUFFER_SIZE 256 +#define CMD_HISTORY_SIZE 32 +#define PASTEBUFSIZE 16384 + +struct conTaskParams +{ + struct conbase *conbase; + struct Task *parentTask; + ULONG initSignal; +}; + +struct filehandle +{ + struct IOStdReq *conreadio; + struct IOStdReq conwriteio; + struct MsgPort *conreadmp; + struct MsgPort *conwritemp; + struct Window *window; + struct Window *otherwindow; /* WINDOW0xXXXXXXXX parameter */ + struct Task *contask; + struct Task *breaktask; + struct Task *lastwritetask; + struct MinList pendingReads; + struct NewWindow nw; + struct MsgPort *timermp; + struct timerequest *timerreq; + UBYTE *wintitle; + UBYTE *screenname; +#if BETTER_WRITE_HANDLING + LONG partlywrite_actual; + LONG partlywrite_size; +#endif + WORD conbufferpos; + WORD conbuffersize; + WORD inputstart; /* usually 0, but needed for multi-lines (CONTROL RETURN) */ + WORD inputpos; /* cursor pos. inside line */ + WORD inputsize; /* length of input string */ + WORD canreadsize; + WORD historysize; + WORD historypos; + WORD historyviewpos; + WORD usecount; + UWORD flags; + + UBYTE consolebuffer[CONSOLEBUFFER_SIZE + 2]; + UBYTE inputbuffer[INPUTBUFFER_SIZE + 2]; + UBYTE historybuffer[CMD_HISTORY_SIZE][INPUTBUFFER_SIZE + 1]; + + /* If pastebuffer != 0, this contains data to paste from ConClip */ + WORD pastebufferpos; + WORD pastebuffersize; + STRPTR pastebuffer; + struct Device *inputbase; + struct IntuitionBase *intuibase; + struct GfxBase *gfxbase; + struct DosLibrary *dosbase; + struct Library *gtbase; + struct Library *utilbase; +}; + +/* filehandle flags */ + +#define FHFLG_READPENDING 1 +#define FHFLG_WRITEPENDING 2 +#define FHFLG_CANREAD 4 +#define FHFLG_WAIT 8 /* filename contained WAIT */ +#define FHFLG_RAW 16 /* in RAW mode */ +#define FHFLG_ASYNCCONSOLEREAD 32 /* There is a pending async console.device CMD_READ request */ +#define FHFLG_AUTO 64 /* filename contained AUTO */ +#define FHFLG_CONSOLEDEVICEOPEN 128 +#define FHFLG_EOF 256 +#define FHFLG_WAITFORCLOSE 512 /* Console with WAIT is waiting to be closed */ + +#undef InputBase +#undef IntuitionBase +#undef DOSBase +#undef GadToolsBase +#undef UtilityBase + +/* + * FIXME: Remove these #define xxxBase hacks + * Do not use this in new code ! + */ +#define InputBase fh->inputbase +#define IntuitionBase fh->intuibase +#define DOSBase fh->dosbase +#define GadToolsBase fh->gtbase +#define GfxBase fh->gfxbase +#define UtilityBase fh->utilbase + +#endif /* __CON_HANDLER_INTERN_H */ diff --git a/rom/filesys/console_handler/support.c b/rom/filesys/console_handler/support.c dissimilarity index 77% index f4bbf6f654..d5d0d8caf3 100644 --- a/rom/filesys/console_handler/support.c +++ b/rom/filesys/console_handler/support.c @@ -1,1169 +1,1186 @@ -/* - Copyright © 1995-2011, The AROS Development Team. All rights reserved. - $Id$ - - Desc: Support functions for console handler. - Lang: english -*/ - -/****************************************************************************************/ - -#define CYCLIC_HISTORY_WALK 0 - -/****************************************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SDEBUG 0 -#define DEBUG 0 -#include - -#include -#include -#include - -#include "con_handler_intern.h" -#include "support.h" -#include "completion.h" - -#define ioReq(x) ((struct IORequest *)x) - -void replypkt(struct DosPacket *dp, SIPTR res1) -{ - struct MsgPort *mp; - struct Message *mn; - - mp = dp->dp_Port; - mn = dp->dp_Link; - mn->mn_Node.ln_Name = (char*)dp; - dp->dp_Port = &((struct Process*)FindTask(NULL))->pr_MsgPort; - dp->dp_Res1 = res1; - PutMsg(mp, mn); -} -void replypkt2(struct DosPacket *dp, SIPTR res1, SIPTR res2) -{ - dp->dp_Res2 = res2; - replypkt(dp, res1); -} - - -/******************************************************************************************/ - -static const UBYTE up_seq[] = {'A'}; -static const UBYTE down_seq[] = {'B'}; -static const UBYTE right_seq[] = {'C'}; -static const UBYTE left_seq[] = {'D'}; -static const UBYTE shift_up_seq[] = {'T'}; -static const UBYTE shift_down_seq[] = {'S'}; -static const UBYTE shift_right_seq[] = {' ', '@'}; -static const UBYTE shift_left_seq[] = {' ', 'A'}; -static const UBYTE shift_tab_seq[] = {'Z'}; -static const UBYTE help_seq[] = {'?', '~'}; -static const UBYTE f1_seq[] = {'0', '~'}; -static const UBYTE f2_seq[] = {'1', '~'}; -static const UBYTE f3_seq[] = {'2', '~'}; -static const UBYTE f4_seq[] = {'3', '~'}; -static const UBYTE f5_seq[] = {'4', '~'}; -static const UBYTE f6_seq[] = {'5', '~'}; -static const UBYTE f7_seq[] = {'6', '~'}; -static const UBYTE f8_seq[] = {'7', '~'}; -static const UBYTE f9_seq[] = {'8', '~'}; -static const UBYTE f10_seq[] = {'9', '~'}; -static const UBYTE paste_seq[] = {'0', ' ', 'v'}; -static const UBYTE f11_seq[] = {'2', '0', '~'}; -static const UBYTE f12_seq[] = {'2', '1', '~'}; -static const UBYTE shift_f1_seq[] = {'1', '0', '~'}; -static const UBYTE shift_f2_seq[] = {'1', '1', '~'}; -static const UBYTE shift_f3_seq[] = {'1', '2', '~'}; -static const UBYTE shift_f4_seq[] = {'1', '3', '~'}; -static const UBYTE shift_f5_seq[] = {'1', '4', '~'}; -static const UBYTE shift_f6_seq[] = {'1', '5', '~'}; -static const UBYTE shift_f7_seq[] = {'1', '6', '~'}; -static const UBYTE shift_f8_seq[] = {'1', '7', '~'}; -static const UBYTE shift_f9_seq[] = {'1', '8', '~'}; -static const UBYTE shift_f10_seq[] = {'1', '9', '~'}; -static const UBYTE shift_f11_seq[] = {'3', '0', '~'}; -static const UBYTE shift_f12_seq[] = {'3', '1', '~'}; -static const UBYTE insert_seq[] = {'4', '0', '~'}; -static const UBYTE pageup_seq[] = {'4', '1', '~'}; -static const UBYTE pagedown_seq[] = {'4', '2', '~'}; -static const UBYTE pause_seq[] = {'4', '3', '~'}; -static const UBYTE break_seq[] = {'5', '3', '~'}; -static const UBYTE home_seq[] = {'4', '4', '~'}; -static const UBYTE end_seq[] = {'4', '5', '~'}; -static const UBYTE shift_insert_seq[] = {'5', '0', '~'}; -static const UBYTE shift_pageup_seq[] = {'5', '1', '~'}; -static const UBYTE shift_pagedown_seq[] = {'5', '2', '~'}; -static const UBYTE shift_home_seq[] = {'5', '4', '~'}; -static const UBYTE shift_end_seq[] = {'5', '5', '~'}; - -/* F11, F12, insert, pageup, pagedown, ... seq taken from - RKRM: Devices/Console/Reading from the Console Device/Information about the Input Stream */ - -static CONST struct csimatch -{ - CONST UBYTE *seq; - WORD len; - WORD inp; -} -csimatchtable[] = -{ - {up_seq , 1, INP_CURSORUP }, - {down_seq , 1, INP_CURSORDOWN }, - {right_seq , 1, INP_CURSORRIGHT }, - {left_seq , 1, INP_CURSORLEFT }, - {shift_up_seq , 1, INP_SHIFT_CURSORUP }, - {shift_down_seq , 1, INP_SHIFT_CURSORDOWN }, - {shift_right_seq , 2, INP_SHIFT_CURSORRIGHT }, - {shift_left_seq , 2, INP_SHIFT_CURSORLEFT }, - {shift_tab_seq , 1, INP_SHIFT_TAB }, - {help_seq , 2, INP_HELP }, - {f1_seq , 2, INP_F1 }, - {f2_seq , 2, INP_F2 }, - {f3_seq , 2, INP_F3 }, - {f4_seq , 2, INP_F4 }, - {f5_seq , 2, INP_F5 }, - {f6_seq , 2, INP_F6 }, - {f7_seq , 2, INP_F7 }, - {f8_seq , 2, INP_F8 }, - {f9_seq , 2, INP_F9 }, - {f10_seq , 2, INP_F10 }, - {f11_seq , 3, INP_F11 }, - {f12_seq , 3, INP_F12 }, - {shift_f1_seq , 3, INP_SHIFT_F1 }, - {shift_f2_seq , 3, INP_SHIFT_F2 }, - {shift_f3_seq , 3, INP_SHIFT_F3 }, - {shift_f4_seq , 3, INP_SHIFT_F4 }, - {shift_f5_seq , 3, INP_SHIFT_F5 }, - {shift_f6_seq , 3, INP_SHIFT_F6 }, - {shift_f7_seq , 3, INP_SHIFT_F7 }, - {shift_f8_seq , 3, INP_SHIFT_F8 }, - {shift_f9_seq , 3, INP_SHIFT_F9 }, - {shift_f10_seq , 3, INP_SHIFT_F10 }, - {shift_f11_seq , 3, INP_SHIFT_F11 }, - {shift_f12_seq , 3, INP_SHIFT_F12 }, - {insert_seq , 3, INP_INSERT }, - {pageup_seq , 3, INP_PAGEUP }, - {pagedown_seq , 3, INP_PAGEDOWN }, - {pause_seq , 3, INP_PAUSE }, - {break_seq , 3, INP_BREAK }, - {home_seq , 3, INP_HOME }, - {end_seq , 3, INP_END }, - {shift_insert_seq , 3, INP_SHIFT_INSERT }, - {shift_pageup_seq , 3, INP_SHIFT_PAGEUP }, - {shift_pagedown_seq , 3, INP_SHIFT_PAGEDOWN }, - {shift_home_seq , 3, INP_SHIFT_HOME }, - {shift_end_seq , 3, INP_SHIFT_END }, - {paste_seq , 3, INP_PASTE }, - {0 , 0, 0 } -}; - - -/******************************************************************************************/ - -static UBYTE hex2val(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - c &= ~0x20; - return c - 'A' + 10; -} -/* strtoul() not used because it is much larger and uses .bss - * TODO: Sanity checks. */ -static IPTR string2val(const char *s, WORD len) -{ - IPTR v = 0; - - if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { - s += 2; - while (len-- > 0 && *s) { - v <<= 4; - v |= hex2val(*s); - s++; - } - } else { - while (len-- > 0 && *s) { - v *= 10; - v += *s - '0'; - s++; - } - } - return v; -} - -BOOL parse_filename(struct filehandle *fh, char *filename, struct NewWindow *nw) -{ - char *param; - UBYTE c; - WORD paramid = 1; - LONG paramval = 0; - BOOL ok = TRUE, done = FALSE, paramok = FALSE; - - ASSERT_VALID_PTR(fh); - ASSERT_VALID_PTR(nw); - - param = filename; - ASSERT_VALID_PTR(param); - - while (!done) - { - c = *filename++; - - switch(c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (paramid <= 4) - { - paramval *= 10; - paramval += c - '0'; - } - paramok = TRUE; - break; - - case '\0': - done = TRUE; - /* fall through */ - - case '/': - if (paramok) - { - UWORD paramlen = filename - param - 1; - - switch(paramid) - { - case 1: - nw->LeftEdge = paramval; - break; - - case 2: - nw->TopEdge = paramval; - break; - - case 3: - nw->Width = paramval; - break; - - case 4: - nw->Height = paramval; - break; - - case 5: - if ((fh->wintitle = AllocVec(paramlen + 1, MEMF_PUBLIC))) - { - CopyMem(param, fh->wintitle, paramlen); - fh->wintitle[paramlen] = '\0'; - nw->Title = fh->wintitle; - } - break; - - default: - if (!strnicmp(param, "WAIT", paramlen)) - { - fh->flags |= FHFLG_WAIT; - } - else if (!strnicmp(param, "CLOSE", paramlen)) - { - nw->Flags |= WFLG_CLOSEGADGET; - } - else if (!strnicmp(param, "NOCLOSE", paramlen)) - { - nw->Flags &= ~WFLG_CLOSEGADGET; - } - else if (!strnicmp(param, "AUTO", paramlen)) - { - fh->flags |= FHFLG_AUTO; - } - else if (!strnicmp(param, "INACTIVE", paramlen)) - { - nw->Flags &= ~WFLG_ACTIVATE; - } - else if (!strnicmp(param, "NODEPTH", paramlen)) - { - nw->Flags &= ~WFLG_DEPTHGADGET; - } - else if (!strnicmp(param, "NOSIZE", paramlen)) - { - nw->Flags &= ~WFLG_SIZEGADGET; - } - else if (!strnicmp(param, "NODRAG", paramlen)) - { - nw->Flags &= ~WFLG_DRAGBAR; - } - else if (!strnicmp(param, "NOBORDER", paramlen)) - { - nw->Flags |= WFLG_BORDERLESS; - } - else if (!strnicmp(param, "BACKDROP", paramlen)) - { - nw->Flags |= WFLG_BACKDROP; - nw->Flags &= ~(WFLG_DRAGBAR | WFLG_SIZEGADGET); - } - else if (!strnicmp(param, "SIMPLE", paramlen)) - { - /* TODO */ - } - else if (!strnicmp(param, "SMART", paramlen)) - { - /* TODO */ - } - else if (!strnicmp(param, "ALT", paramlen)) - { - /* TODO: style "ALT30/30/200/200" */ - } - else if (!strnicmp(param, "WINDOW", 6)) - { - /* Do we need some sanity checks here? */ - fh->otherwindow = (struct Window*)string2val(param + 6, paramlen - 6); - } - else if (!strnicmp(param, "SCREEN", 6)) - { - if ((fh->screenname = AllocVec(paramlen - 5, MEMF_PUBLIC))) - { - CopyMem(param + 6, fh->screenname, paramlen - 6); - fh->screenname[paramlen - 6] = '\0'; - } - } - break; - - } /* switch(paramid) */ - - paramok = FALSE; - - } /* if (paramok) */ - - paramval = 0; - paramid++; - param = filename; - break; - - default: - if (paramid < 5) - { - done = TRUE; - ok = FALSE; - } - else - paramok = TRUE; - break; - - } /* switch(c) */ - - } /* while (!done) */ - - return ok; -} - -/******************************************************************************************/ - - -void do_write(struct filehandle *fh, APTR data, ULONG length) -{ - fh->conwriteio.io_Command = CMD_WRITE; - fh->conwriteio.io_Data = data; - fh->conwriteio.io_Length = length; - - DoIO((struct IORequest *)&fh->conwriteio); -} - -/******************************************************************************************/ - -void do_movecursor(struct filehandle *fh, UBYTE direction, UBYTE howmuch) -{ - UBYTE seq[6]; /* 9B <0> */ - ULONG size; - - if (howmuch > 0) - { - seq[0] = 0x9B; - - if (howmuch == 1) - { - seq[1] = direction; - size = 2; - } else { - sprintf(&seq[1],"%d%c", howmuch, direction); - size = strlen(seq); - } - - do_write(fh, seq, size); - } -} - -/******************************************************************************************/ - -void do_cursorvisible(struct filehandle *fh, BOOL on) -{ - UBYTE seq[4]; - ULONG size = 0; - - seq[size++] = 0x9B; - if (!on) seq[size++] = '0'; - seq[size++] = ' '; - seq[size++] = 'p'; - - do_write(fh, seq, size); -} - -/******************************************************************************************/ - -void do_deletechar(struct filehandle *fh) -{ - UBYTE seq[] = {0x9B, 'P'}; - - do_write(fh, seq, 2); -} - -/******************************************************************************************/ - -void do_eraseinline(struct filehandle *fh) -{ - UBYTE seq[] = {0x9B, 'K'}; - - do_write(fh, seq, 2); -} - -/******************************************************************************************/ - -void do_eraseindisplay(struct filehandle *fh) -{ - UBYTE seq[] = {0x9B, 'J'}; - - do_write(fh, seq, 2); -} -/******************************************************************************************/ -static void copy_from_pastebuf(struct filehandle * fh) -{ - if (fh->conbufferpos >= fh->conbuffersize && - fh->pastebuffer && - fh->pastebufferpos < fh->pastebuffersize) - { - ULONG len = CONSOLEBUFFER_SIZE; - ULONG pastelen = fh->pastebuffersize - fh->pastebufferpos; - if (pastelen < len) len = pastelen; - - D(bug("Copying %d bytes from paste buffer\n",len)); - - fh->conbufferpos = 0; - CopyMem(fh->pastebuffer + fh->pastebufferpos, - &fh->consolebuffer, - len); - fh->conbuffersize = len; - fh->pastebufferpos += len; - if (fh->pastebufferpos >= fh->pastebuffersize) { - FreeMem(fh->pastebuffer,PASTEBUFSIZE); - fh->pastebuffer = 0; - } - } -} - -WORD scan_input(struct filehandle *fh, UBYTE *buffer) -{ - CONST struct csimatch *match; - UBYTE c; - WORD result = INP_DONE; - - copy_from_pastebuf(fh); - - if (fh->conbufferpos < fh->conbuffersize) - { - c = fh->consolebuffer[fh->conbufferpos++]; - D(bug("scan_input: check char %d\n",c)); - switch(c) - { - case 3: - case 4: - case 5: - case 6: - result = INP_CTRL_C - 3 + (WORD)c; - break; - - case 8: - /* FIXME: Ugh... Race condition, anyone? The qualifier might - have changed between the keypress and the time we do this */ - if (PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) - { - result = INP_SHIFT_BACKSPACE; - } else { - result = INP_BACKSPACE; - } - break; - - case 9: - result = INP_TAB; - break; - - case 10: - result = INP_LINEFEED; - break; - - case 12: /* CTRL-L */ - *buffer = c; - result = INP_ECHO_STRING; - break; - - case 13: - result = INP_RETURN; - break; - - case 127: - if (PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) - { - result = INP_SHIFT_DELETE; - } else { - result = INP_DELETE; - } - break; - - case 24: - result = INP_CONTROL_X; - break; - - case 28: /* CTRL-\ */ - result = INP_EOF; - break; - - case 0x9B: /* CSI */ - result = INP_UNKNOWN; - - match = csimatchtable; - for(;match->seq;match++) - { - if (!strncmp(match->seq, &(fh->consolebuffer[fh->conbufferpos]), match->len)) - { - result = match->inp; - fh->conbufferpos += match->len; - break; - } - } - break; - - default: - /* normal keys */ - *buffer = c; - result = INP_STRING; - break; - - } /* switch(c) */ - - } /* if (fh->conbufferpos < fh->conbuffersize) */ - - D(bug("scan_input: result %d\n",result)); - - return result; -} - -/******************************************************************************************/ - -void add_to_history(struct filehandle *fh) -{ - BOOL add_to_history = FALSE; - - fh->inputbuffer[fh->inputsize] = '\0'; - - /* Don't add emptry strings */ - if (fh->inputbuffer[fh->inputstart] == '\0') return; - - if (fh->historysize == 0) - { - add_to_history = TRUE; - } - else - { - WORD old_historypos; - - old_historypos = fh->historypos - 1; - if (old_historypos < 0) old_historypos = fh->historysize - 1; - - if (strcmp(&fh->inputbuffer[fh->inputstart], fh->historybuffer[old_historypos])) - { - /* add to history only if different from last history entry */ - - add_to_history = TRUE; - } - } - - if (add_to_history) - { - if (fh->historysize < CMD_HISTORY_SIZE) fh->historysize++; - - strcpy(fh->historybuffer[fh->historypos], &fh->inputbuffer[fh->inputstart]); - - fh->historypos++; - if (fh->historypos >= CMD_HISTORY_SIZE) fh->historypos = 0; - } - - fh->historyviewpos = fh->historypos; -} - -/******************************************************************************************/ - -void history_walk(struct filehandle *fh, WORD inp) -{ - if (fh->historysize) - { - #if !CYCLIC_HISTORY_WALK - BOOL walk_to_empty_string = FALSE; - #endif - WORD len; - - switch(inp) - { - case INP_SHIFT_CURSORUP: - fh->historyviewpos = 0; - break; - - case INP_SHIFT_CURSORDOWN: - fh->historyviewpos = fh->historysize - 1;; - break; - - case INP_CURSORUP: - #if CYCLIC_HISTORY_WALK - fh->historyviewpos--; - if (fh->historyviewpos < 0) fh->historyviewpos = fh->historysize - 1; - #else - if (fh->historyviewpos != -1) - { - fh->historyviewpos--; - if (fh->historyviewpos < 0 - && fh->historysize == CMD_HISTORY_SIZE) - fh->historyviewpos = CMD_HISTORY_SIZE - 1; - if (fh->historyviewpos == fh->historypos) - fh->historyviewpos = -1; - } - if (fh->historyviewpos == -1) - walk_to_empty_string = TRUE; - #endif - break; - - case INP_CURSORDOWN: - #if CYCLIC_HISTORY_WALK - fh->historyviewpos++; - if (fh->historyviewpos >= fh->historysize) fh->historyviewpos = 0; - #else - if (fh->historyviewpos != fh->historypos) - { - if (fh->historyviewpos == -1 - && fh->historysize == CMD_HISTORY_SIZE) - fh->historyviewpos = fh->historypos; - fh->historyviewpos = (fh->historyviewpos + 1) - % CMD_HISTORY_SIZE; - } - if (fh->historyviewpos == fh->historypos) - walk_to_empty_string = TRUE; - #endif - break; - } - - if (fh->inputpos > fh->inputstart) - { - do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart); - } - - do_eraseinline(fh); - - fh->inputsize = fh->inputstart; - fh->inputpos = fh->inputstart; - - #if !CYCLIC_HISTORY_WALK - if (!walk_to_empty_string) - { - #endif - len = strlen(fh->historybuffer[fh->historyviewpos]); - if (len > (INPUTBUFFER_SIZE - fh->inputstart)) - { - len = INPUTBUFFER_SIZE - fh->inputstart; - } - - if (len > 0) - { - CopyMem(fh->historybuffer[fh->historyviewpos], - &fh->inputbuffer[fh->inputstart], - len); - - fh->inputsize += len; - fh->inputpos += len; - - do_write(fh, &fh->inputbuffer[fh->inputstart], len); - } - - #if !CYCLIC_HISTORY_WALK - } /* if (!walk_to_empty_string) */ - #endif - - } /* if (fh->historysize) */ -} - -/****************************************************************************************/ - -static const STRPTR CONCLIP_PORTNAME = "ConClip.rendezvous"; - -struct MyEditHookMsg -{ - struct Message msg; - struct SGWork *sgw; - WORD code; -}; - -static void do_paste(struct filehandle * fh) -{ - struct MsgPort replyport, *port; - struct SGWork sgw; - struct MyEditHookMsg msg; - struct StringInfo sinfo; - - if (!(port = FindPort(CONCLIP_PORTNAME))) { - D(bug("ConClip not running, but we got a ConClip paste request")); - return; - } - - D(bug("PASTE REQUEST!\n")); - - replyport.mp_Node.ln_Type = NT_MSGPORT; - replyport.mp_Node.ln_Name = NULL; - replyport.mp_Node.ln_Pri = 0; - replyport.mp_Flags = PA_SIGNAL; - replyport.mp_SigBit = SIGB_SINGLE; - replyport.mp_SigTask = FindTask(NULL); - NEWLIST(&replyport.mp_MsgList); - - msg.msg.mn_Node.ln_Type = NT_MESSAGE; - msg.msg.mn_ReplyPort = &replyport; - msg.msg.mn_Length = sizeof(msg); - - msg.code = 'V'; - msg.sgw = &sgw; - - /* FIXME: Ensure no fields are left uninitialized */ - - sgw.Gadget = 0; - sgw.WorkBuffer = AllocMem(PASTEBUFSIZE,MEMF_CLEAR | MEMF_ANY); - sgw.PrevBuffer = 0; - sgw.IEvent = 0; - sgw.Code = 'V'; - sgw.Actions = 0; - sgw.LongInt = 0; - sgw.GadgetInfo = 0; - sgw.EditOp = EO_BIGCHANGE; - sgw.BufferPos = 0; - sgw.NumChars = 0; - - /* ConClip only ever looks at MaxChars in StringInfo */ - sinfo.MaxChars = PASTEBUFSIZE; - sgw.StringInfo = &sinfo; - - SetSignal(0, SIGF_SINGLE); - PutMsg(port, &msg.msg); - WaitPort(&replyport); - - D(bug("Pasting %d bytes\n",sgw.BufferPos)); - - if (fh->pastebuffer) FreeMem(fh->pastebuffer,PASTEBUFSIZE); - fh->pastebuffer = sgw.WorkBuffer; - fh->pastebuffersize = sgw.BufferPos; - fh->pastebufferpos = 0; -} - - -/****************************************************************************************/ - -BOOL process_input(struct filehandle *fh) -{ - UBYTE c; - WORD inp; - while((inp = scan_input(fh, &c)) != INP_DONE) - { - D(bug("Input Code: %d\n",inp)); - - switch(inp) - { - case INP_CURSORLEFT: - if (fh->inputpos > fh->inputstart) - { - fh->inputpos--; - do_movecursor(fh, CUR_LEFT, 1); - } - break; - - case INP_SHIFT_CURSORLEFT: /* move to beginning of line */ - case INP_HOME: - if (fh->inputpos > fh->inputstart) - { - do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart); - fh->inputpos = fh->inputstart; - } - break; - - case INP_CURSORRIGHT: - if (fh->inputpos < fh->inputsize) - { - fh->inputpos++; - do_movecursor(fh, CUR_RIGHT, 1); - } - break; - - case INP_SHIFT_CURSORRIGHT: /* move to end of line */ - case INP_END: - if (fh->inputpos != fh->inputsize) - { - do_movecursor(fh, CUR_RIGHT, fh->inputsize - fh->inputpos); - fh->inputpos = fh->inputsize; - } - break; - - case INP_CURSORUP: /* walk through cmd history */ - case INP_CURSORDOWN: - case INP_SHIFT_CURSORUP: - case INP_SHIFT_CURSORDOWN: - history_walk(fh, inp); - break; - - case INP_BACKSPACE: - if (fh->inputpos > fh->inputstart) - { - do_movecursor(fh, CUR_LEFT, 1); - - if (fh->inputpos == fh->inputsize) - { - do_deletechar(fh); - - fh->inputsize--; - fh->inputpos--; - } else { - WORD chars_right = fh->inputsize - fh->inputpos; - - fh->inputsize--; - fh->inputpos--; - - do_cursorvisible(fh, FALSE); - do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right); - do_deletechar(fh); - do_movecursor(fh, CUR_LEFT, chars_right); - do_cursorvisible(fh, TRUE); - - memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right); - - } - } - break; - - case INP_SHIFT_BACKSPACE: - if (fh->inputpos > fh->inputstart) - { - do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart); - if (fh->inputpos == fh->inputsize) - { - do_eraseinline(fh); - - fh->inputpos = fh->inputsize = fh->inputstart; - } else { - WORD chars_right = fh->inputsize - fh->inputpos; - - do_cursorvisible(fh, FALSE); - do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right); - do_eraseinline(fh); - do_movecursor(fh, CUR_LEFT, chars_right); - do_cursorvisible(fh, TRUE); - - memmove(&fh->inputbuffer[fh->inputstart], &fh->inputbuffer[fh->inputpos], chars_right); - - fh->inputsize -= (fh->inputpos - fh->inputstart); - fh->inputpos = fh->inputstart; - } - } - break; - - case INP_DELETE: - if (fh->inputpos < fh->inputsize) - { - fh->inputsize--; - - if (fh->inputpos == fh->inputsize) - { - do_deletechar(fh); - } else { - WORD chars_right = fh->inputsize - fh->inputpos; - - do_cursorvisible(fh, FALSE); - do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right); - do_deletechar(fh); - do_movecursor(fh, CUR_LEFT, chars_right); - do_cursorvisible(fh, TRUE); - - memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right); - } - } - break; - - case INP_SHIFT_DELETE: - if (fh->inputpos < fh->inputsize) - { - fh->inputsize = fh->inputpos; - do_eraseinline(fh); - } - break; - - case INP_CONTROL_X: - if ((fh->inputsize - fh->inputstart) > 0) - { - if (fh->inputpos > fh->inputstart) - { - do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart); - } - do_eraseinline(fh); - - fh->inputpos = fh->inputsize = fh->inputstart; - } - break; - - case INP_ECHO_STRING: - do_write(fh, &c, 1); - break; - - case INP_STRING: - if (fh->inputsize < INPUTBUFFER_SIZE) - { - do_write(fh, &c, 1); - - if (fh->inputpos == fh->inputsize) - { - fh->inputbuffer[fh->inputpos++] = c; - fh->inputsize++; - } else { - WORD chars_right = fh->inputsize - fh->inputpos; - - do_cursorvisible(fh, FALSE); - do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right); - do_movecursor(fh, CUR_LEFT, chars_right); - do_cursorvisible(fh, TRUE); - - memmove(&fh->inputbuffer[fh->inputpos + 1], &fh->inputbuffer[fh->inputpos], chars_right); - fh->inputbuffer[fh->inputpos++] = c; - fh->inputsize++; - } - } - break; - - case INP_EOF: - D(bug("[CON] Read EOF (window closing)\n")); - - if (fh->flags & FHFLG_WAITFORCLOSE) - return TRUE; - - fh->flags |= FHFLG_EOF; - if (fh->flags & FHFLG_AUTO && fh->window) - { - CloseWindow(fh->window); - fh->window = NULL; - } - - /* fall through */ - - case INP_RETURN: - if (fh->inputsize < INPUTBUFFER_SIZE) - { - if (inp != INP_EOF) - { - c = '\n'; - do_write(fh, &c, 1); - add_to_history(fh); - - fh->inputbuffer[fh->inputsize++] = '\n'; - } - - fh->inputstart = fh->inputsize; - fh->inputpos = fh->inputstart; - - if (fh->inputsize) - HandlePendingReads(fh); - - if ((fh->flags & FHFLG_EOF) && (fh->flags & FHFLG_READPENDING)) - { - struct Message *msg = (struct Message*)RemHead((struct List *)&fh->pendingReads); - struct DosPacket *dp = (struct DosPacket*)msg->mn_Node.ln_Name; - - if (dp) - { - replypkt2(dp, 0, 0); - fh->flags &= ~FHFLG_EOF; - } - - if (IsListEmpty(&fh->pendingReads)) - fh->flags &= ~FHFLG_READPENDING; - } - - } /* if (fh->inputsize < INPUTBUFFER_SIZE) */ - break; - - case INP_LINEFEED: - if (fh->inputsize < INPUTBUFFER_SIZE) - { - c = '\n'; - do_write(fh, &c, 1); - add_to_history(fh); - - fh->inputbuffer[fh->inputsize++] = c; - fh->inputstart = fh->inputsize; - fh->inputpos = fh->inputsize; - } - break; - - case INP_CTRL_C: - case INP_CTRL_D: - case INP_CTRL_E: - case INP_CTRL_F: - if (fh->breaktask) - { - Signal(fh->breaktask, 1L << (12 + inp - INP_CTRL_C)); - } - break; - - case INP_TAB: - Completion(fh, FALSE); - break; - - case INP_SHIFT_TAB: - Completion(fh, TRUE); - break; - - case INP_PASTE: - do_paste(fh); - break; - - } /* switch(inp) */ - - } /* while((inp = scan_input(fh, &c)) != INP_DONE) */ - - return FALSE; -} - - -BOOL answer_write_request(struct filehandle *fh, struct DosPacket *dp) -{ - UBYTE *buffer = (UBYTE*)dp->dp_Arg2; - LONG length = dp->dp_Arg3; - -#if RMB_FREEZES_OUTPUT - struct Window *conwindow; - - conwindow = ((struct ConUnit *)fh->conwriteio.io_Unit)->cu_Window; - - while((PeekQualifier() & IEQUALIFIER_RBUTTON) && - conwindow && (conwindow == IntuitionBase->ActiveWindow)) - { - Delay(2); - } -#endif - - if ((dp->dp_Port->mp_Flags & PF_ACTION) == PA_SIGNAL && - dp->dp_Port->mp_SigTask) - { - fh->lastwritetask = dp->dp_Port->mp_SigTask; - } - - - do_write(fh, buffer, length); - replypkt2(dp, length, 0); - - return TRUE; -} - -void answer_read_request(struct filehandle *fh, struct DosPacket *dp, ULONG dp_Arg3) -{ - ULONG readlen; - - readlen = (fh->inputsize < dp_Arg3) ? fh->inputsize : dp_Arg3; - - CopyMem(fh->inputbuffer, (UBYTE*)dp->dp_Arg2, readlen); - CopyMem(fh->inputbuffer + readlen, fh->inputbuffer, fh->inputsize - readlen); - - fh->inputsize -= readlen; - fh->inputpos -= readlen; - fh->inputstart -= readlen; - - replypkt2(dp, readlen, 0); -} - -void HandlePendingReads(struct filehandle *fh) -{ - if (fh->flags & FHFLG_READPENDING) - { - struct DosPacket *dp; - struct Message *msg, *next_msg; - - ForeachNodeSafe(&fh->pendingReads, msg, next_msg) - { - Remove((struct Node *)msg); - dp = (struct DosPacket*)msg->mn_Node.ln_Name; - answer_read_request(fh, dp, dp->dp_Arg3); - - if (fh->inputsize == 0) - break; - - } - if (IsListEmpty(&fh->pendingReads)) - fh->flags &= ~FHFLG_READPENDING; - } - - if (fh->inputsize) - { - fh->flags |= FHFLG_CANREAD; - fh->canreadsize = fh->inputsize; - } -} - -void con_read(struct filehandle *fh, struct DosPacket *dp) -{ - if (fh->flags & FHFLG_CANREAD) - { - ULONG readlen = (fh->canreadsize < dp->dp_Arg3) ? fh->canreadsize : dp->dp_Arg3; - - answer_read_request(fh, dp, readlen); - - fh->canreadsize -= readlen; - if (fh->canreadsize == 0) - fh->flags &= ~FHFLG_CANREAD; - - } - else - { - if (fh->flags & FHFLG_EOF) - { - replypkt2(dp, 0, 0); - fh->flags &= ~FHFLG_EOF; - } - else if (fh->flags & FHFLG_RAW) - { - replypkt2(dp, 0, 0); - } - else - { - AddTail((struct List *)&fh->pendingReads, (struct Node *)dp->dp_Link); - fh->flags |= FHFLG_READPENDING; - } - } -} +/* + Copyright © 1995-2011, The AROS Development Team. All rights reserved. + $Id$ + + Desc: Support functions for console handler. + Lang: english +*/ + +/****************************************************************************************/ + +#define CYCLIC_HISTORY_WALK 0 + +/****************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SDEBUG 0 +#define DEBUG 0 +#include + +#include +#include +#include + +#include "con_handler_intern.h" +#include "support.h" +#include "completion.h" + +#define ioReq(x) ((struct IORequest *)x) + +void replypkt(struct DosPacket *dp, SIPTR res1) +{ + struct MsgPort *mp; + struct Message *mn; + + mp = dp->dp_Port; + mn = dp->dp_Link; + mn->mn_Node.ln_Name = (char*) dp; + dp->dp_Port = &((struct Process*) FindTask(NULL))->pr_MsgPort; + dp->dp_Res1 = res1; + PutMsg(mp, mn); +} +void replypkt2(struct DosPacket *dp, SIPTR res1, SIPTR res2) +{ + dp->dp_Res2 = res2; + replypkt(dp, res1); +} + + +/******************************************************************************************/ + +static const UBYTE up_seq[] = { 'A' }; +static const UBYTE down_seq[] = { 'B' }; +static const UBYTE right_seq[] = { 'C' }; +static const UBYTE left_seq[] = { 'D' }; +static const UBYTE shift_up_seq[] = { 'T' }; +static const UBYTE shift_down_seq[] = { 'S' }; +static const UBYTE shift_right_seq[] = { ' ', '@' }; +static const UBYTE shift_left_seq[] = { ' ', 'A' }; +static const UBYTE shift_tab_seq[] = { 'Z' }; +static const UBYTE help_seq[] = { '?', '~' }; +static const UBYTE f1_seq[] = { '0', '~' }; +static const UBYTE f2_seq[] = { '1', '~' }; +static const UBYTE f3_seq[] = { '2', '~' }; +static const UBYTE f4_seq[] = { '3', '~' }; +static const UBYTE f5_seq[] = { '4', '~' }; +static const UBYTE f6_seq[] = { '5', '~' }; +static const UBYTE f7_seq[] = { '6', '~' }; +static const UBYTE f8_seq[] = { '7', '~' }; +static const UBYTE f9_seq[] = { '8', '~' }; +static const UBYTE f10_seq[] = { '9', '~' }; +static const UBYTE paste_seq[] = { '0', ' ', 'v' }; +static const UBYTE f11_seq[] = { '2', '0', '~' }; +static const UBYTE f12_seq[] = { '2', '1', '~' }; +static const UBYTE shift_f1_seq[] = { '1', '0', '~' }; +static const UBYTE shift_f2_seq[] = { '1', '1', '~' }; +static const UBYTE shift_f3_seq[] = { '1', '2', '~' }; +static const UBYTE shift_f4_seq[] = { '1', '3', '~' }; +static const UBYTE shift_f5_seq[] = { '1', '4', '~' }; +static const UBYTE shift_f6_seq[] = { '1', '5', '~' }; +static const UBYTE shift_f7_seq[] = { '1', '6', '~' }; +static const UBYTE shift_f8_seq[] = { '1', '7', '~' }; +static const UBYTE shift_f9_seq[] = { '1', '8', '~' }; +static const UBYTE shift_f10_seq[] = { '1', '9', '~' }; +static const UBYTE shift_f11_seq[] = { '3', '0', '~' }; +static const UBYTE shift_f12_seq[] = { '3', '1', '~' }; +static const UBYTE insert_seq[] = { '4', '0', '~' }; +static const UBYTE pageup_seq[] = { '4', '1', '~' }; +static const UBYTE pagedown_seq[] = { '4', '2', '~' }; +static const UBYTE pause_seq[] = { '4', '3', '~' }; +static const UBYTE break_seq[] = { '5', '3', '~' }; +static const UBYTE home_seq[] = { '4', '4', '~' }; +static const UBYTE end_seq[] = { '4', '5', '~' }; +static const UBYTE shift_insert_seq[] = { '5', '0', '~' }; +static const UBYTE shift_pageup_seq[] = { '5', '1', '~' }; +static const UBYTE shift_pagedown_seq[] = { '5', '2', '~' }; +static const UBYTE shift_home_seq[] = { '5', '4', '~' }; +static const UBYTE shift_end_seq[] = { '5', '5', '~' }; + +/* F11, F12, insert, pageup, pagedown, ... seq taken from + RKRM: Devices/Console/Reading from the Console Device/Information about the Input Stream */ + +static CONST struct csimatch +{ + CONST UBYTE *seq; + WORD len; + WORD inp; +} +csimatchtable[] = +{ + {up_seq , 1, INP_CURSORUP }, + {down_seq , 1, INP_CURSORDOWN }, + {right_seq , 1, INP_CURSORRIGHT }, + {left_seq , 1, INP_CURSORLEFT }, + {shift_up_seq , 1, INP_SHIFT_CURSORUP }, + {shift_down_seq , 1, INP_SHIFT_CURSORDOWN }, + {shift_right_seq , 2, INP_SHIFT_CURSORRIGHT }, + {shift_left_seq , 2, INP_SHIFT_CURSORLEFT }, + {shift_tab_seq , 1, INP_SHIFT_TAB }, + {help_seq , 2, INP_HELP }, + {f1_seq , 2, INP_F1 }, + {f2_seq , 2, INP_F2 }, + {f3_seq , 2, INP_F3 }, + {f4_seq , 2, INP_F4 }, + {f5_seq , 2, INP_F5 }, + {f6_seq , 2, INP_F6 }, + {f7_seq , 2, INP_F7 }, + {f8_seq , 2, INP_F8 }, + {f9_seq , 2, INP_F9 }, + {f10_seq , 2, INP_F10 }, + {f11_seq , 3, INP_F11 }, + {f12_seq , 3, INP_F12 }, + {shift_f1_seq , 3, INP_SHIFT_F1 }, + {shift_f2_seq , 3, INP_SHIFT_F2 }, + {shift_f3_seq , 3, INP_SHIFT_F3 }, + {shift_f4_seq , 3, INP_SHIFT_F4 }, + {shift_f5_seq , 3, INP_SHIFT_F5 }, + {shift_f6_seq , 3, INP_SHIFT_F6 }, + {shift_f7_seq , 3, INP_SHIFT_F7 }, + {shift_f8_seq , 3, INP_SHIFT_F8 }, + {shift_f9_seq , 3, INP_SHIFT_F9 }, + {shift_f10_seq , 3, INP_SHIFT_F10 }, + {shift_f11_seq , 3, INP_SHIFT_F11 }, + {shift_f12_seq , 3, INP_SHIFT_F12 }, + {insert_seq , 3, INP_INSERT }, + {pageup_seq , 3, INP_PAGEUP }, + {pagedown_seq , 3, INP_PAGEDOWN }, + {pause_seq , 3, INP_PAUSE }, + {break_seq , 3, INP_BREAK }, + {home_seq , 3, INP_HOME }, + {end_seq , 3, INP_END }, + {shift_insert_seq , 3, INP_SHIFT_INSERT }, + {shift_pageup_seq , 3, INP_SHIFT_PAGEUP }, + {shift_pagedown_seq , 3, INP_SHIFT_PAGEDOWN }, + {shift_home_seq , 3, INP_SHIFT_HOME }, + {shift_end_seq , 3, INP_SHIFT_END }, + {paste_seq , 3, INP_PASTE }, + {0 , 0, 0 } +}; + + +/******************************************************************************************/ + +static UBYTE hex2val(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + c &= ~0x20; + return c - 'A' + 10; +} +/* strtoul() not used because it is much larger and uses .bss + * TODO: Sanity checks. */ +static IPTR string2val(const char *s, WORD len) +{ + IPTR v = 0; + + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + { + s += 2; + while (len-- > 0 && *s) + { + v <<= 4; + v |= hex2val(*s); + s++; + } + } + else + { + while (len-- > 0 && *s) + { + v *= 10; + v += *s - '0'; + s++; + } + } + return v; +} + +BOOL parse_filename(struct filehandle *fh, char *filename, struct NewWindow *nw) +{ + char *param; + UBYTE c; + WORD paramid = 1; + LONG paramval = 0; + BOOL ok = TRUE, done = FALSE, paramok = FALSE; + + ASSERT_VALID_PTR(fh); + ASSERT_VALID_PTR(nw); + + param = filename; + ASSERT_VALID_PTR(param); + + while (!done) + { + c = *filename++; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (paramid <= 4) + { + paramval *= 10; + paramval += c - '0'; + } + paramok = TRUE; + break; + + case '\0': + done = TRUE; + /* fall through */ + + case '/': + if (paramok) + { + UWORD paramlen = filename - param - 1; + + switch (paramid) + { + case 1: + nw->LeftEdge = paramval; + break; + + case 2: + nw->TopEdge = paramval; + break; + + case 3: + nw->Width = paramval; + break; + + case 4: + nw->Height = paramval; + break; + + case 5: + if ((fh->wintitle = AllocVec(paramlen + 1, MEMF_PUBLIC))) + { + CopyMem(param, fh->wintitle, paramlen); + fh->wintitle[paramlen] = '\0'; + nw->Title = fh->wintitle; + } + break; + + default: + if (!strnicmp(param, "WAIT", paramlen)) + { + fh->flags |= FHFLG_WAIT; + } + else if (!strnicmp(param, "CLOSE", paramlen)) + { + nw->Flags |= WFLG_CLOSEGADGET; + } + else if (!strnicmp(param, "NOCLOSE", paramlen)) + { + nw->Flags &= ~WFLG_CLOSEGADGET; + } + else if (!strnicmp(param, "AUTO", paramlen)) + { + fh->flags |= FHFLG_AUTO; + } + else if (!strnicmp(param, "INACTIVE", paramlen)) + { + nw->Flags &= ~WFLG_ACTIVATE; + } + else if (!strnicmp(param, "NODEPTH", paramlen)) + { + nw->Flags &= ~WFLG_DEPTHGADGET; + } + else if (!strnicmp(param, "NOSIZE", paramlen)) + { + nw->Flags &= ~WFLG_SIZEGADGET; + } + else if (!strnicmp(param, "NODRAG", paramlen)) + { + nw->Flags &= ~WFLG_DRAGBAR; + } + else if (!strnicmp(param, "NOBORDER", paramlen)) + { + nw->Flags |= WFLG_BORDERLESS; + } + else if (!strnicmp(param, "BACKDROP", paramlen)) + { + nw->Flags |= WFLG_BACKDROP; + nw->Flags &= ~(WFLG_DRAGBAR | WFLG_SIZEGADGET); + } + else if (!strnicmp(param, "SIMPLE", paramlen)) + { + /* TODO */ + } + else if (!strnicmp(param, "SMART", paramlen)) + { + /* TODO */ + } + else if (!strnicmp(param, "ALT", paramlen)) + { + /* TODO: style "ALT30/30/200/200" */ + } + else if (!strnicmp(param, "WINDOW", 6)) + { + /* Do we need some sanity checks here? */ + fh->otherwindow = (struct Window*) string2val(param + 6, paramlen - 6); + } + else if (!strnicmp(param, "SCREEN", 6)) + { + if ((fh->screenname = AllocVec(paramlen - 5, MEMF_PUBLIC))) + { + CopyMem(param + 6, fh->screenname, paramlen - 6); + fh->screenname[paramlen - 6] = '\0'; + } + } + break; + + } /* switch(paramid) */ + + paramok = FALSE; + + } /* if (paramok) */ + + paramval = 0; + paramid++; + param = filename; + break; + + default: + if (paramid < 5) + { + done = TRUE; + ok = FALSE; + } + else + paramok = TRUE; + break; + + } /* switch(c) */ + + } /* while (!done) */ + + return ok; +} + +/******************************************************************************************/ + +void do_write(struct filehandle *fh, APTR data, ULONG length) +{ + fh->conwriteio.io_Command = CMD_WRITE; + fh->conwriteio.io_Data = data; + fh->conwriteio.io_Length = length; + + DoIO((struct IORequest *) &fh->conwriteio); +} + +/******************************************************************************************/ + +void do_movecursor(struct filehandle *fh, UBYTE direction, UBYTE howmuch) +{ + UBYTE seq[6]; /* 9B <0> */ + ULONG size; + + if (howmuch > 0) + { + seq[0] = 0x9B; + + if (howmuch == 1) + { + seq[1] = direction; + size = 2; + } + else + { + sprintf(&seq[1], "%d%c", howmuch, direction); + size = strlen(seq); + } + + do_write(fh, seq, size); + } +} + +/******************************************************************************************/ + +void do_cursorvisible(struct filehandle *fh, BOOL on) +{ + UBYTE seq[4]; + ULONG size = 0; + + seq[size++] = 0x9B; + if (!on) + seq[size++] = '0'; + seq[size++] = ' '; + seq[size++] = 'p'; + + do_write(fh, seq, size); +} + +/******************************************************************************************/ + +void do_deletechar(struct filehandle *fh) +{ + UBYTE seq[] = + { 0x9B, 'P' }; + + do_write(fh, seq, 2); +} + +/******************************************************************************************/ + +void do_eraseinline(struct filehandle *fh) +{ + UBYTE seq[] = + { 0x9B, 'K' }; + + do_write(fh, seq, 2); +} + +/******************************************************************************************/ + +void do_eraseindisplay(struct filehandle *fh) +{ + UBYTE seq[] = + { 0x9B, 'J' }; + + do_write(fh, seq, 2); +} +/******************************************************************************************/ +static void copy_from_pastebuf(struct filehandle * fh) +{ + if (fh->conbufferpos >= fh->conbuffersize && fh->pastebuffer && fh->pastebufferpos < fh->pastebuffersize) + { + ULONG len = CONSOLEBUFFER_SIZE; + ULONG pastelen = fh->pastebuffersize - fh->pastebufferpos; + if (pastelen < len) + len = pastelen; + + D(bug("Copying %d bytes from paste buffer\n", len)); + + fh->conbufferpos = 0; + CopyMem(fh->pastebuffer + fh->pastebufferpos, &fh->consolebuffer, len); + fh->conbuffersize = len; + fh->pastebufferpos += len; + if (fh->pastebufferpos >= fh->pastebuffersize) + { + FreeMem(fh->pastebuffer, PASTEBUFSIZE); + fh->pastebuffer = 0; + } + } +} + +WORD scan_input(struct filehandle *fh, UBYTE *buffer) +{ + CONST + struct csimatch *match; + UBYTE c; + WORD result = INP_DONE; + + copy_from_pastebuf(fh); + + if (fh->conbufferpos < fh->conbuffersize) + { + c = fh->consolebuffer[fh->conbufferpos++]; + D(bug("scan_input: check char %d\n", c)); + switch (c) + { + case 3: + case 4: + case 5: + case 6: + result = INP_CTRL_C - 3 + (WORD) c; + break; + + case 8: + /* FIXME: Ugh... Race condition, anyone? The qualifier might + have changed between the keypress and the time we do this */ + if (PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) + { + result = INP_SHIFT_BACKSPACE; + } + else + { + result = INP_BACKSPACE; + } + break; + + case 9: + result = INP_TAB; + break; + + case 10: + result = INP_LINEFEED; + break; + + case 12: /* CTRL-L */ + *buffer = c; + result = INP_ECHO_STRING; + break; + + case 13: + result = INP_RETURN; + break; + + case 127: + if (PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) + { + result = INP_SHIFT_DELETE; + } + else + { + result = INP_DELETE; + } + break; + + case 24: + result = INP_CONTROL_X; + break; + + case 28: /* CTRL-\ */ + result = INP_EOF; + break; + + case 0x9B: /* CSI */ + result = INP_UNKNOWN; + + match = csimatchtable; + for (; match->seq; match++) + { + if (!strncmp(match->seq, &(fh->consolebuffer[fh->conbufferpos]), match->len)) + { + result = match->inp; + fh->conbufferpos += match->len; + break; + } + } + break; + + default: + /* normal keys */ + *buffer = c; + result = INP_STRING; + break; + + } /* switch(c) */ + + } /* if (fh->conbufferpos < fh->conbuffersize) */ + + D(bug("scan_input: result %d\n", result)); + + return result; +} + +/******************************************************************************************/ + +void add_to_history(struct filehandle *fh) +{ + BOOL add_to_history = FALSE; + + fh->inputbuffer[fh->inputsize] = '\0'; + + /* Don't add emptry strings */ + if (fh->inputbuffer[fh->inputstart] == '\0') + return; + + if (fh->historysize == 0) + { + add_to_history = TRUE; + } + else + { + WORD old_historypos; + + old_historypos = fh->historypos - 1; + if (old_historypos < 0) + old_historypos = fh->historysize - 1; + + if (strcmp(&fh->inputbuffer[fh->inputstart], fh->historybuffer[old_historypos])) + { + /* add to history only if different from last history entry */ + + add_to_history = TRUE; + } + } + + if (add_to_history) + { + if (fh->historysize < CMD_HISTORY_SIZE) + fh->historysize++; + + strcpy(fh->historybuffer[fh->historypos], &fh->inputbuffer[fh->inputstart]); + + fh->historypos++; + if (fh->historypos >= CMD_HISTORY_SIZE) + fh->historypos = 0; + } + + fh->historyviewpos = fh->historypos; +} + +/******************************************************************************************/ + +void history_walk(struct filehandle *fh, WORD inp) +{ + if (fh->historysize) + { +#if !CYCLIC_HISTORY_WALK + BOOL walk_to_empty_string = FALSE; +#endif + WORD len; + + switch (inp) + { + case INP_SHIFT_CURSORUP: + fh->historyviewpos = 0; + break; + + case INP_SHIFT_CURSORDOWN: + fh->historyviewpos = fh->historysize - 1; + ; + break; + + case INP_CURSORUP: +#if CYCLIC_HISTORY_WALK + fh->historyviewpos--; + if (fh->historyviewpos < 0) fh->historyviewpos = fh->historysize - 1; +#else + if (fh->historyviewpos != -1) + { + fh->historyviewpos--; + if (fh->historyviewpos < 0 && fh->historysize == CMD_HISTORY_SIZE) + fh->historyviewpos = CMD_HISTORY_SIZE - 1; + if (fh->historyviewpos == fh->historypos) + fh->historyviewpos = -1; + } + if (fh->historyviewpos == -1) + walk_to_empty_string = TRUE; +#endif + break; + + case INP_CURSORDOWN: +#if CYCLIC_HISTORY_WALK + fh->historyviewpos++; + if (fh->historyviewpos >= fh->historysize) fh->historyviewpos = 0; +#else + if (fh->historyviewpos != fh->historypos) + { + if (fh->historyviewpos == -1 && fh->historysize == CMD_HISTORY_SIZE) + fh->historyviewpos = fh->historypos; + fh->historyviewpos = (fh->historyviewpos + 1) % CMD_HISTORY_SIZE; + } + if (fh->historyviewpos == fh->historypos) + walk_to_empty_string = TRUE; +#endif + break; + } + + if (fh->inputpos > fh->inputstart) + { + do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart); + } + + do_eraseinline(fh); + + fh->inputsize = fh->inputstart; + fh->inputpos = fh->inputstart; + +#if !CYCLIC_HISTORY_WALK + if (!walk_to_empty_string) + { +#endif + len = strlen(fh->historybuffer[fh->historyviewpos]); + if (len > (INPUTBUFFER_SIZE - fh->inputstart)) + { + len = INPUTBUFFER_SIZE - fh->inputstart; + } + + if (len > 0) + { + CopyMem(fh->historybuffer[fh->historyviewpos], &fh->inputbuffer[fh->inputstart], len); + + fh->inputsize += len; + fh->inputpos += len; + + do_write(fh, &fh->inputbuffer[fh->inputstart], len); + } + +#if !CYCLIC_HISTORY_WALK + } /* if (!walk_to_empty_string) */ +#endif + + } /* if (fh->historysize) */ +} + +/****************************************************************************************/ + +static const STRPTR CONCLIP_PORTNAME = "ConClip.rendezvous"; + +struct MyEditHookMsg +{ + struct Message msg; + struct SGWork *sgw; + WORD code; +}; + +static void do_paste(struct filehandle * fh) +{ + struct MsgPort replyport, *port; + struct SGWork sgw; + struct MyEditHookMsg msg; + struct StringInfo sinfo; + + if (!(port = FindPort(CONCLIP_PORTNAME))) + { + D(bug("ConClip not running, but we got a ConClip paste request")); + return; + } + + D(bug("PASTE REQUEST!\n")); + + replyport.mp_Node.ln_Type = NT_MSGPORT; + replyport.mp_Node.ln_Name = NULL; + replyport.mp_Node.ln_Pri = 0; + replyport.mp_Flags = PA_SIGNAL; + replyport.mp_SigBit = SIGB_SINGLE; + replyport.mp_SigTask = FindTask(NULL); + NEWLIST(&replyport.mp_MsgList); + + msg.msg.mn_Node.ln_Type = NT_MESSAGE; + msg.msg.mn_ReplyPort = &replyport; + msg.msg.mn_Length = sizeof(msg); + + msg.code = 'V'; + msg.sgw = &sgw; + + /* FIXME: Ensure no fields are left uninitialized */ + + sgw.Gadget = 0; + sgw.WorkBuffer = AllocMem(PASTEBUFSIZE, MEMF_CLEAR | MEMF_ANY); + sgw.PrevBuffer = 0; + sgw.IEvent = 0; + sgw.Code = 'V'; + sgw.Actions = 0; + sgw.LongInt = 0; + sgw.GadgetInfo = 0; + sgw.EditOp = EO_BIGCHANGE; + sgw.BufferPos = 0; + sgw.NumChars = 0; + + /* ConClip only ever looks at MaxChars in StringInfo */ + sinfo.MaxChars = PASTEBUFSIZE; + sgw.StringInfo = &sinfo; + + SetSignal(0, SIGF_SINGLE); + PutMsg(port, &msg.msg); + WaitPort(&replyport); + + D(bug("Pasting %d bytes\n", sgw.BufferPos)); + + if (fh->pastebuffer) + FreeMem(fh->pastebuffer, PASTEBUFSIZE); + fh->pastebuffer = sgw.WorkBuffer; + fh->pastebuffersize = sgw.BufferPos; + fh->pastebufferpos = 0; +} + +/****************************************************************************************/ + +BOOL process_input(struct filehandle *fh) +{ + UBYTE c; + WORD inp; + while ((inp = scan_input(fh, &c)) != INP_DONE) + { + D(bug("Input Code: %d\n", inp)); + + switch (inp) + { + case INP_CURSORLEFT: + if (fh->inputpos > fh->inputstart) + { + fh->inputpos--; + do_movecursor(fh, CUR_LEFT, 1); + } + break; + + case INP_SHIFT_CURSORLEFT: /* move to beginning of line */ + case INP_HOME: + if (fh->inputpos > fh->inputstart) + { + do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart); + fh->inputpos = fh->inputstart; + } + break; + + case INP_CURSORRIGHT: + if (fh->inputpos < fh->inputsize) + { + fh->inputpos++; + do_movecursor(fh, CUR_RIGHT, 1); + } + break; + + case INP_SHIFT_CURSORRIGHT: /* move to end of line */ + case INP_END: + if (fh->inputpos != fh->inputsize) + { + do_movecursor(fh, CUR_RIGHT, fh->inputsize - fh->inputpos); + fh->inputpos = fh->inputsize; + } + break; + + case INP_CURSORUP: /* walk through cmd history */ + case INP_CURSORDOWN: + case INP_SHIFT_CURSORUP: + case INP_SHIFT_CURSORDOWN: + history_walk(fh, inp); + break; + + case INP_BACKSPACE: + if (fh->inputpos > fh->inputstart) + { + do_movecursor(fh, CUR_LEFT, 1); + + if (fh->inputpos == fh->inputsize) + { + do_deletechar(fh); + + fh->inputsize--; + fh->inputpos--; + } + else + { + WORD chars_right = fh->inputsize - fh->inputpos; + + fh->inputsize--; + fh->inputpos--; + + do_cursorvisible(fh, FALSE); + do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right); + do_deletechar(fh); + do_movecursor(fh, CUR_LEFT, chars_right); + do_cursorvisible(fh, TRUE); + + memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right); + + } + } + break; + + case INP_SHIFT_BACKSPACE: + if (fh->inputpos > fh->inputstart) + { + do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart); + if (fh->inputpos == fh->inputsize) + { + do_eraseinline(fh); + + fh->inputpos = fh->inputsize = fh->inputstart; + } + else + { + WORD chars_right = fh->inputsize - fh->inputpos; + + do_cursorvisible(fh, FALSE); + do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right); + do_eraseinline(fh); + do_movecursor(fh, CUR_LEFT, chars_right); + do_cursorvisible(fh, TRUE); + + memmove(&fh->inputbuffer[fh->inputstart], &fh->inputbuffer[fh->inputpos], chars_right); + + fh->inputsize -= (fh->inputpos - fh->inputstart); + fh->inputpos = fh->inputstart; + } + } + break; + + case INP_DELETE: + if (fh->inputpos < fh->inputsize) + { + fh->inputsize--; + + if (fh->inputpos == fh->inputsize) + { + do_deletechar(fh); + } + else + { + WORD chars_right = fh->inputsize - fh->inputpos; + + do_cursorvisible(fh, FALSE); + do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right); + do_deletechar(fh); + do_movecursor(fh, CUR_LEFT, chars_right); + do_cursorvisible(fh, TRUE); + + memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right); + } + } + break; + + case INP_SHIFT_DELETE: + if (fh->inputpos < fh->inputsize) + { + fh->inputsize = fh->inputpos; + do_eraseinline(fh); + } + break; + + case INP_CONTROL_X: + if ((fh->inputsize - fh->inputstart) > 0) + { + if (fh->inputpos > fh->inputstart) + { + do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart); + } + do_eraseinline(fh); + + fh->inputpos = fh->inputsize = fh->inputstart; + } + break; + + case INP_ECHO_STRING: + do_write(fh, &c, 1); + break; + + case INP_STRING: + if (fh->inputsize < INPUTBUFFER_SIZE) + { + do_write(fh, &c, 1); + + if (fh->inputpos == fh->inputsize) + { + fh->inputbuffer[fh->inputpos++] = c; + fh->inputsize++; + } + else + { + WORD chars_right = fh->inputsize - fh->inputpos; + + do_cursorvisible(fh, FALSE); + do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right); + do_movecursor(fh, CUR_LEFT, chars_right); + do_cursorvisible(fh, TRUE); + + memmove(&fh->inputbuffer[fh->inputpos + 1], &fh->inputbuffer[fh->inputpos], chars_right); + fh->inputbuffer[fh->inputpos++] = c; + fh->inputsize++; + } + } + break; + + case INP_EOF: + D(bug("[CON] Read EOF (window closing)\n")); + + if (fh->flags & FHFLG_WAITFORCLOSE) + return TRUE; + + fh->flags |= FHFLG_EOF; + if (fh->flags & FHFLG_AUTO && fh->window) + { + CloseWindow(fh->window); + fh->window = NULL; + } + + /* fall through */ + + case INP_RETURN: + if (fh->inputsize < INPUTBUFFER_SIZE) + { + if (inp != INP_EOF) + { + c = '\n'; + do_write(fh, &c, 1); + add_to_history(fh); + + fh->inputbuffer[fh->inputsize++] = '\n'; + } + + fh->inputstart = fh->inputsize; + fh->inputpos = fh->inputstart; + + if (fh->inputsize) + HandlePendingReads(fh); + + if ((fh->flags & FHFLG_EOF) && (fh->flags & FHFLG_READPENDING)) + { + struct Message *msg = (struct Message*) RemHead((struct List *) &fh->pendingReads); + struct DosPacket *dp = (struct DosPacket*) msg->mn_Node.ln_Name; + + if (dp) + { + replypkt2(dp, 0, 0); + fh->flags &= ~FHFLG_EOF; + } + + if (IsListEmpty(&fh->pendingReads)) + fh->flags &= ~FHFLG_READPENDING; + } + + } /* if (fh->inputsize < INPUTBUFFER_SIZE) */ + break; + + case INP_LINEFEED: + if (fh->inputsize < INPUTBUFFER_SIZE) + { + c = '\n'; + do_write(fh, &c, 1); + add_to_history(fh); + + fh->inputbuffer[fh->inputsize++] = c; + fh->inputstart = fh->inputsize; + fh->inputpos = fh->inputsize; + } + break; + + case INP_CTRL_C: + case INP_CTRL_D: + case INP_CTRL_E: + case INP_CTRL_F: + if (fh->breaktask) + { + Signal(fh->breaktask, 1L << (12 + inp - INP_CTRL_C)); + } + break; + + case INP_TAB: + Completion(fh, FALSE); + break; + + case INP_SHIFT_TAB: + Completion(fh, TRUE); + break; + + case INP_PASTE: + do_paste(fh); + break; + + } /* switch(inp) */ + + } /* while((inp = scan_input(fh, &c)) != INP_DONE) */ + + return FALSE; +} + +BOOL answer_write_request(struct filehandle *fh, struct DosPacket *dp) +{ + UBYTE *buffer = (UBYTE*) dp->dp_Arg2; + LONG length = dp->dp_Arg3; + +#if RMB_FREEZES_OUTPUT + struct Window *conwindow; + + conwindow = ((struct ConUnit *) fh->conwriteio.io_Unit)->cu_Window; + + while ((PeekQualifier() & IEQUALIFIER_RBUTTON) && conwindow && (conwindow == IntuitionBase->ActiveWindow)) + { + Delay(2); + } +#endif + + if ((dp->dp_Port->mp_Flags & PF_ACTION) == PA_SIGNAL && dp->dp_Port->mp_SigTask) + { + fh->lastwritetask = dp->dp_Port->mp_SigTask; + } + + do_write(fh, buffer, length); + replypkt2(dp, length, 0); + + return TRUE; +} + +void answer_read_request(struct filehandle *fh, struct DosPacket *dp, ULONG dp_Arg3) +{ + ULONG readlen; + + readlen = (fh->inputsize < dp_Arg3) ? fh->inputsize : dp_Arg3; + + CopyMem(fh->inputbuffer, (UBYTE*) dp->dp_Arg2, readlen); + CopyMem(fh->inputbuffer + readlen, fh->inputbuffer, fh->inputsize - readlen); + + fh->inputsize -= readlen; + fh->inputpos -= readlen; + fh->inputstart -= readlen; + + replypkt2(dp, readlen, 0); +} + +void HandlePendingReads(struct filehandle *fh) +{ + if (fh->flags & FHFLG_READPENDING) + { + struct DosPacket *dp; + struct Message *msg, *next_msg; + + ForeachNodeSafe(&fh->pendingReads, msg, next_msg) + { + Remove((struct Node *) msg); + dp = (struct DosPacket*) msg->mn_Node.ln_Name; + answer_read_request(fh, dp, dp->dp_Arg3); + + if (fh->inputsize == 0) + break; + + } + if (IsListEmpty(&fh->pendingReads)) + fh->flags &= ~FHFLG_READPENDING; + } + + if (fh->inputsize) + { + fh->flags |= FHFLG_CANREAD; + fh->canreadsize = fh->inputsize; + } +} + +void con_read(struct filehandle *fh, struct DosPacket *dp) +{ + if (fh->flags & FHFLG_CANREAD) + { + ULONG readlen = (fh->canreadsize < dp->dp_Arg3) ? fh->canreadsize : dp->dp_Arg3; + + answer_read_request(fh, dp, readlen); + + fh->canreadsize -= readlen; + if (fh->canreadsize == 0) + fh->flags &= ~FHFLG_CANREAD; + + } + else + { + if (fh->flags & FHFLG_EOF) + { + replypkt2(dp, 0, 0); + fh->flags &= ~FHFLG_EOF; + } + else if (fh->flags & FHFLG_RAW) + { + replypkt2(dp, 0, 0); + } + else + { + AddTail((struct List *) &fh->pendingReads, (struct Node *) dp->dp_Link); + fh->flags |= FHFLG_READPENDING; + } + } +} diff --git a/rom/filesys/console_handler/support.h b/rom/filesys/console_handler/support.h index 1e78f18b7d..c2549c5f0e 100644 --- a/rom/filesys/console_handler/support.h +++ b/rom/filesys/console_handler/support.h @@ -11,71 +11,71 @@ #define CUR_RIGHT 'C' #define CUR_LEFT 'D' -#define INP_DONE 0 -#define INP_CURSORLEFT 1 -#define INP_CURSORRIGHT 2 -#define INP_CURSORUP 3 -#define INP_CURSORDOWN 4 -#define INP_SHIFT_CURSORLEFT 5 -#define INP_SHIFT_CURSORRIGHT 6 -#define INP_SHIFT_CURSORUP 7 -#define INP_SHIFT_CURSORDOWN 8 -#define INP_BACKSPACE 9 -#define INP_SHIFT_BACKSPACE 10 -#define INP_DELETE 11 -#define INP_SHIFT_DELETE 12 -#define INP_RETURN 13 -#define INP_LINEFEED 14 -#define INP_TAB 15 -#define INP_SHIFT_TAB 16 -#define INP_F1 17 -#define INP_F2 18 -#define INP_F3 19 -#define INP_F4 20 -#define INP_F5 21 -#define INP_F6 22 -#define INP_F7 23 -#define INP_F8 24 -#define INP_F9 25 -#define INP_F10 26 -#define INP_F11 27 -#define INP_F12 28 -#define INP_SHIFT_F1 29 -#define INP_SHIFT_F2 30 -#define INP_SHIFT_F3 31 -#define INP_SHIFT_F4 32 -#define INP_SHIFT_F5 33 -#define INP_SHIFT_F6 34 -#define INP_SHIFT_F7 35 -#define INP_SHIFT_F8 36 -#define INP_SHIFT_F9 37 -#define INP_SHIFT_F10 38 -#define INP_SHIFT_F11 39 -#define INP_SHIFT_F12 40 -#define INP_HELP 41 -#define INP_CONTROL_X 42 -#define INP_INSERT 43 -#define INP_PAGEUP 44 -#define INP_PAGEDOWN 45 -#define INP_PAUSE 46 -#define INP_BREAK 47 -#define INP_HOME 48 -#define INP_END 49 -#define INP_SHIFT_INSERT 50 -#define INP_SHIFT_PAGEUP 51 -#define INP_SHIFT_PAGEDOWN 52 -#define INP_SHIFT_HOME 53 -#define INP_SHIFT_END 54 -#define INP_CTRL_C 55 -#define INP_CTRL_D 56 -#define INP_CTRL_E 57 -#define INP_CTRL_F 58 -#define INP_EOF 59 +#define INP_DONE 0 +#define INP_CURSORLEFT 1 +#define INP_CURSORRIGHT 2 +#define INP_CURSORUP 3 +#define INP_CURSORDOWN 4 +#define INP_SHIFT_CURSORLEFT 5 +#define INP_SHIFT_CURSORRIGHT 6 +#define INP_SHIFT_CURSORUP 7 +#define INP_SHIFT_CURSORDOWN 8 +#define INP_BACKSPACE 9 +#define INP_SHIFT_BACKSPACE 10 +#define INP_DELETE 11 +#define INP_SHIFT_DELETE 12 +#define INP_RETURN 13 +#define INP_LINEFEED 14 +#define INP_TAB 15 +#define INP_SHIFT_TAB 16 +#define INP_F1 17 +#define INP_F2 18 +#define INP_F3 19 +#define INP_F4 20 +#define INP_F5 21 +#define INP_F6 22 +#define INP_F7 23 +#define INP_F8 24 +#define INP_F9 25 +#define INP_F10 26 +#define INP_F11 27 +#define INP_F12 28 +#define INP_SHIFT_F1 29 +#define INP_SHIFT_F2 30 +#define INP_SHIFT_F3 31 +#define INP_SHIFT_F4 32 +#define INP_SHIFT_F5 33 +#define INP_SHIFT_F6 34 +#define INP_SHIFT_F7 35 +#define INP_SHIFT_F8 36 +#define INP_SHIFT_F9 37 +#define INP_SHIFT_F10 38 +#define INP_SHIFT_F11 39 +#define INP_SHIFT_F12 40 +#define INP_HELP 41 +#define INP_CONTROL_X 42 +#define INP_INSERT 43 +#define INP_PAGEUP 44 +#define INP_PAGEDOWN 45 +#define INP_PAUSE 46 +#define INP_BREAK 47 +#define INP_HOME 48 +#define INP_END 49 +#define INP_SHIFT_INSERT 50 +#define INP_SHIFT_PAGEUP 51 +#define INP_SHIFT_PAGEDOWN 52 +#define INP_SHIFT_HOME 53 +#define INP_SHIFT_END 54 +#define INP_CTRL_C 55 +#define INP_CTRL_D 56 +#define INP_CTRL_E 57 +#define INP_CTRL_F 58 +#define INP_EOF 59 #define INP_PASTE 60 -#define INP_UNKNOWN 99 -#define INP_STRING 100 -#define INP_ECHO_STRING 101 +#define INP_UNKNOWN 99 +#define INP_STRING 100 +#define INP_ECHO_STRING 101 BOOL parse_filename(struct filehandle *fh, char *filename, struct NewWindow *nw); -- 2.11.4.GIT