/***********************************************\ * * * Snap * * (c) Mikael Karlsson 1988 * * * \***********************************************/ /* Auto: make */ #ifdef SNAPREXX #include "minrexx.h" #endif #define ARGVAL() (*++(*argv) || (--argc && *++argv)) /* signals */ LONGBITS startsignal, insertsignal, cancelsignal, donesignal; LONGBITS movesignal, clicksignal, timersignal, initsignal, cwsignal; ULONG startsignum = -1L; ULONG insertsignum = -1L; ULONG cancelsignum = -1L; ULONG donesignum = -1L; ULONG movesignum = -1L; ULONG clicksignum = -1L; ULONG timersignum = -1L; ULONG initsignum = -1L; ULONG cwsignum = -1L; ULONG WaitSignal; /* program */ struct SnapRsrc *SnapRsrc = NULL; struct Task *MyTask; /* Snap state machine */ WORD action; WORD state; /* clipboard */ struct IOClipReq *ClipReq = NULL; struct MsgPort *ClipPort = NULL; /* timer device */ struct MsgPort *TimerPort = NULL; struct timerequest MyTR; /* input device */ struct MsgPort *inputDevPort = NULL; struct Interrupt handlerStuff; struct IOStdReq *inputRequestBlock = NULL; struct InputEvent SimEvent; WORD textqual; WORD gfxqual; WORD insertkey; WORD cwkey; WORD modinsert; UBYTE *CharData = NULL; UBYTE TrueUnderscore; /* console */ struct MsgPort *ConPort = NULL; struct IOStdReq *ConIOR = NULL; struct KeyMap keymap; /* windows */ struct MsgPort *Sharedport = NULL; SHORT Sharedrefs; IMPORT UBYTE *WindowTitle; IMPORT struct Window *ControlWindow; struct Window *SaveWin = NULL; IMPORT struct Gadget SaveGad; IMPORT struct Gadget NameGad; struct GfxSnap *SwapGS = NULL; struct MinList CachedWindows; IMPORT struct StringInfo TranspSI; /* libraries */ struct IntuitionBase *IntuitionBase = NULL; struct GfxBase *GfxBase = NULL; struct LayersBase *LayersBase = NULL; struct ArpBase *ArpBase = NULL; /* struct DosLibrary *DosBase = NULL; */ /* graphics */ struct Screen *theScreen; struct Layer *theLayer; struct RastPort rp, TempRp, MyRP; struct BitMap TempBM, MyBM; UBYTE *TempRaster = NULL; IMPORT struct FileRequester NameFR; IMPORT UBYTE SaveName[256]; IMPORT UBYTE SaveDirName[256]; BPTR SnapFile; /* ARexx stuff */ #ifdef SNAPREXX ULONG rexxsignal; IMPORT struct rexxCommandList rcl[]; WORD disp(); #endif /* detaching */ ULONG _BackGroundIO = 0; ULONG _stack = 4096L; ULONG _priority = 4L; char *_procname = "Snap"; #ifdef LATTICE extern BPTR _Backstdout; #endif LATTICE WORD isdigit(c) REGISTER char c; { return (WORD)(c>='0' && c<='9'); } #ifdef AZTEC_C char *strupr(str) char *str; { register char *p = str; register char c; while (c = *p) { if ('a' <= c && c <= 'z') { *p = c - ('a' - 'A'); } ++p; } return str; } #endif AZTEC_C LONG dectoint(str) REGISTER char *str; { REGISTER long val = 0; REGISTER char c; while (isdigit(c = *str)) { val = (((val<<2)+val)<<1) + c-'0'; str++; } return(val); } LONG hextoint(str) REGISTER char *str; { REGISTER long val = 0; REGISTER char c; while (c = *str) { val <<= 4; val |= (c & 15) + (isdigit(c) ? 0 : 9); str++; } return(val); } WORD insertcount; VOID InsertAscii(ascii) ULONG ascii; { if (insertcount == 1) { /* Time for second char */ /* Not necessary to patch here but it guarantees that all inserted chars end up in the same window. */ SafePatch(); } InvertKeyMap(ascii, &SimEvent, &keymap); DoIO(inputRequestBlock); if (SnapRsrc->chardelay) { MyTR.tr_node.io_Command = TR_ADDREQUEST; MyTR.tr_time.tv_micro = SnapRsrc->chardelay; MyTR.tr_time.tv_secs = 0; DoIO((struct IOStdReq *)&MyTR); } ++insertcount; } VOID GadText(Gad, Str, Len) struct Gadget *Gad; char *Str; LONG Len; { char temp[256]; SHORT i; SetDrMd(ControlWindow->RPort, JAM2); SetAPen(ControlWindow->RPort, 0L); RectFill(ControlWindow->RPort, (LONG)Gad->LeftEdge, (LONG)Gad->TopEdge, (LONG)Gad->LeftEdge + Gad->Width - 1, (LONG)Gad->TopEdge + Gad->Height - 1); SetAPen(ControlWindow->RPort, 1L); SetBPen(ControlWindow->RPort, 0L); Move(ControlWindow->RPort, (LONG)Gad->LeftEdge + 1, (LONG)Gad->TopEdge + ControlWindow->RPort->Font->tf_Baseline + 1); if (TextLength(ControlWindow->RPort, Str, Len) > Gad->Width) { i = Len; strncpy(temp, Str, i - 3); strcat(temp, "..."); while (TextLength(ControlWindow->RPort, temp, (LONG)i) > Gad->Width) { --i; temp[i] = '\0'; temp[i-3] = '.'; } Text(ControlWindow->RPort, temp, (LONG)i); } else { Text(ControlWindow->RPort, Str, Len); } } VOID SwapColorMap(GS) struct GfxSnap *GS; { struct ViewPort *vp = &GS->window->WScreen->ViewPort; LONG i = (GS->viewmode & HAM ? 16 : 1L << GS->depth); ULONG col; while (i-- && (col = GetRGB4(vp->ColorMap, i)) != -1L) { SetRGB4(vp, i, (LONG)GS->rgb[i][0] >> 4, (LONG)GS->rgb[i][1] >> 4, (LONG)GS->rgb[i][2] >> 4); GS->rgb[i][0] = ((col >> 8) & 0x0f) << 4; GS->rgb[i][1] = ((col >> 4) & 0x0f) << 4; GS->rgb[i][2] = ((col >> 0) & 0x0f) << 4; } } VOID CheckWindowMsgs() { struct IntuiMessage *Msg; struct IntuiMessage *QdMsg = NULL; ULONG Class; USHORT Code; struct Window *Win; struct Gadget *Gad; while (Sharedport && (QdMsg || (Msg = (struct IntuiMessage *)GetMsg(Sharedport)))) { if (QdMsg) { Msg = QdMsg; QdMsg = NULL; } Class = Msg->Class; Code = Msg->Code; Win = Msg->IDCMPWindow; Gad = (struct Gadget *)Msg->IAddress; ReplyMsg((struct Message *)Msg); switch (Class) { case CLOSEWINDOW: { if (Win == ControlWindow) { ControlWindow = NULL; if (SaveWin) { struct GfxSnap *GS; SetWindowTitles(SaveWin, WindowTitle, NULL); GS = (struct GfxSnap *)SaveWin->UserData; RefreshGList(&GS->DiskGad, GS->window, NULL, 1L); SaveWin = NULL; } } else { struct GfxSnap *GS; GS = (struct GfxSnap *)Win->UserData; FreePlanes(&GS->BM, GS->width, GS->height); Kill(GS); if (Win == SaveWin) { if (ControlWindow) { OffGadget(&SaveGad, ControlWindow, NULL); } SaveWin = NULL; } } closesharedwindow(Win); break; } case NEWSIZE: { AdjustSize((struct GfxSnap *)Win->UserData); break; } case MOUSEMOVE: { /* Collapse all consecutively queued MOUSEMOVE msgs */ while ((QdMsg = (struct IntuiMessage *)GetMsg(Sharedport)) && (QdMsg->Class == MOUSEMOVE)) { ReplyMsg((struct Message *)QdMsg); } SyncGS((struct GfxSnap *)Win->UserData); break; } case ACTIVEWINDOW: { if (Win != ControlWindow) { struct GfxSnap *GS; GS = (struct GfxSnap *)Win->UserData; RefreshGList(&GS->DiskGad, GS->window, NULL, 1L); } break; } case INACTIVEWINDOW: { if (Win != ControlWindow) { struct GfxSnap *GS; if (SwapGS) { SwapColorMap(SwapGS); SwapGS = NULL; } GS = (struct GfxSnap *)Win->UserData; RefreshGList(&GS->DiskGad, GS->window, NULL, 1L); } break; } case GADGETUP: { switch (Gad->GadgetID) { case VPROP: case HPROP: { SyncGS((struct GfxSnap *)Win->UserData); break; } case SAVEGAD: { savepic: if (SaveWin) { WORD success; if (SaveName[0] == '\0') { DisplayBeep(NULL); ActivateGadget(&NameGad, ControlWindow, NULL); break; } SnapFile = (BPTR)Open(SaveName, MODE_NEWFILE); success = SaveGS((struct GfxSnap *)SaveWin->UserData); Close(SnapFile); if (success) { SetWindowTitles(ControlWindow, "Saved ok", NULL); } else { DeleteFile(SaveName); DisplayBeep(NULL); SetWindowTitles(ControlWindow, "Save failed", NULL); } } break; } case NAMEGAD: { /* Should only happen with Arp */ strcpy(SaveDirName, SaveName); strcpy(SaveName, BaseName(SaveDirName)); *(BaseName(SaveDirName)) = '\0'; NameFR.fr_Window = ControlWindow; (VOID)FileRequest(&NameFR); TackOn(SaveDirName, SaveName); strcpy(SaveName, SaveDirName); GadText(&NameGad, SaveName, (LONG)strlen(SaveName)); break; } case DISKGAD: { struct GfxSnap *GS; if (!ControlWindow && !OpenCW()) { DisplayBeep(NULL); break; } if (Win == SaveWin) { goto savepic; } if (SaveWin) { SetWindowTitles(SaveWin, WindowTitle, NULL); GS = (struct GfxSnap *)SaveWin->UserData; RefreshGList(&GS->DiskGad, GS->window, NULL, 1L); } else { GadText(&SaveGad, "Save", 4L); OnGadget(&SaveGad, ControlWindow, NULL); } SaveWin = Win; SetWindowTitles(SaveWin, "Selected", NULL); GS = (struct GfxSnap *)SaveWin->UserData; RefreshGList(&GS->DiskGad, GS->window, NULL, 1L); break; } default: { break; } } break; } case MOUSEBUTTONS: { if (Win != ControlWindow) { if (Code == SELECTDOWN && !SwapGS) { SwapGS = (struct GfxSnap *)Win->UserData; SwapColorMap(SwapGS); } else if (Code == SELECTUP && SwapGS) { SwapColorMap(SwapGS); SwapGS = NULL; } } break; } default: { break; } } } if (QdMsg) { ReplyMsg((struct Message *)QdMsg); } } #define WriteStdOut(str) Write(StdOut, str, (LONG)strlen(str)) VOID main(argc, argv) int argc; char **argv; { WORD create = 0, usage = 0; BPTR StdOut = (BPTR)Open("*", MODE_OLDFILE); #ifdef LATTICE if(_Backstdout) Close(_Backstdout); _Backstdout = 0; #endif LATTICE #ifdef AZTEC_C Enable_Abort = 0; #endif AZTEC_C if (!(SnapRsrc = (struct SnapRsrc *)OpenResource(SNAPRSRC))) { create = 1; SnapRsrc = Create(SnapRsrc); SnapRsrc->node.ln_Type = NT_RESOURCE; SnapRsrc->node.ln_Name = SNAPRSRC; SnapRsrc->Task = FindTask(NULL); SnapRsrc->Priority = 51; SnapRsrc->textqual = IEQUALIFIER_LCOMMAND; SnapRsrc->gfxqual = IEQUALIFIER_RCOMMAND; SnapRsrc->insertkey = 0x17; SnapRsrc->cwkey = 0x11; strcpy(&SnapRsrc->Prepend[0], "> "); strcpy(&SnapRsrc->Append[0], ""); SnapRsrc->flags = TRUEUNDERSCORE; SnapRsrc->chardelay = 0; SnapRsrc->linedelay = 0; SnapRsrc->CrawlPtrn = 0x7777; SnapRsrc->StartUnit = UNIT_FRAME; SnapRsrc->FrameMask = 1; SnapRsrc->GadOffset = 52; SnapRsrc->CacheSize = 10; SnapRsrc->BadChar = '?'; AddResource(SnapRsrc); } if (!argc) { /* WB Startup */ if (!create) { /* Second time from WB -- Remove Snap */ Signal(SnapRsrc->Task, SIGBREAKF_CTRL_C); goto exitpoint; } else { goto skipargs; } } if (create && StdOut) { WriteStdOut("Snap 1.4 (c) 1990 Mikael Karlsson\n"); } for (argc--, argv++; argc > 0; argc--, argv++) { if (**argv == '-') { /* Argument coming up */ switch(*++(*argv)) { case 'p': priority: { /* Priority */ if (ARGVAL()) { WORD pri = dectoint(*argv); if (pri>50 && pri<128) { SnapRsrc->Priority = pri; } } else { usage = 1; } break; } case 't': textqual: { if (ARGVAL()) { SnapRsrc->textqual = hextoint(*argv); } else { usage = 1; } break; } case 'g': gfxqual: { if (ARGVAL()) { SnapRsrc->gfxqual = hextoint(*argv); } else { usage = 1; } break; } case 'i': insertkey: { if (ARGVAL()) { SnapRsrc->insertkey = hextoint(*argv); } else { usage = 1; } break; } case 'w': cwkey: { if (ARGVAL()) { SnapRsrc->cwkey = hextoint(*argv); } else { usage = 1; } break; } case 'c': chardelay: { if (ARGVAL()) { SnapRsrc->chardelay = dectoint(*argv) * 1000; } else { usage = 1; } break; } case 'l': linedelay: { if (ARGVAL()) { SnapRsrc->linedelay = dectoint(*argv) * 1000; } else { usage = 1; } break; } case 'a': crawlptrn: { if (ARGVAL()) { SnapRsrc->CrawlPtrn = hextoint(*argv); } else { usage = 1; } break; } case 'X': noxerox: { SnapRsrc->flags &= ~XEROX; break; } case 'x': xerox: { SnapRsrc->flags |= XEROX; break; } case 'E': noearlypatch: { SnapRsrc->flags &= ~EARLYPATCH; break; } case 'e': earlypatch: { SnapRsrc->flags |= EARLYPATCH; break; } case 'R': fakeunderscore: { SnapRsrc->flags &= ~TRUEUNDERSCORE; break; } case 'r': realunderscore: { SnapRsrc->flags |= TRUEUNDERSCORE; break; } case 'J': nojoinlong: { SnapRsrc->flags &= ~JOINLONG; break; } case 'j': joinlong: { SnapRsrc->flags |= JOINLONG; break; } case 'A': append: case 'P': prepend: { char *dest = (**argv == 'A' ? &SnapRsrc->Append[0] : &SnapRsrc->Prepend[0]); if (*++(*argv) || (--argc && ++argv)) { /* "" is ok */ char *src = *argv; WORD i = 16; while (*src && i--) { *dest++ = *src++; } *dest = '\0'; } else { usage = 1; } break; } case 'u': startunit: { if (ARGVAL()) { switch(dectoint(*argv)) { case 1: { SnapRsrc->StartUnit = UNIT_CHAR; break; } case 0: default: { SnapRsrc->StartUnit = UNIT_FRAME; break; } } } else { usage = 1; } break; } case 'b': planemask: { if (ARGVAL()) { SnapRsrc->FrameMask = hextoint(*argv); } else { usage = 1; } break; } case 'o': gadoffset: { if (ARGVAL()) { SnapRsrc->GadOffset = dectoint(*argv); } else { usage = 1; } break; } case 'C': cachesize: { if (ARGVAL()) { SnapRsrc->CacheSize = dectoint(*argv); } else { usage = 1; } break; } case 'B': badchar: { if (ARGVAL()) { SnapRsrc->BadChar = dectoint(*argv); } else { usage = 1; } break; } case 'Q': quit: { Close(StdOut); if (create) { goto close; } else { Signal(SnapRsrc->Task, SIGBREAKF_CTRL_C); goto exitpoint; } } case '?': { usage = 1; break; } default: { if (StdOut) { WriteStdOut("Bad option: -"); Write(StdOut, *argv, 1L); WriteStdOut(".\n"); } usage = 1; break; } } } else { (VOID)strupr(*argv); if (!strcmp(*argv, "PRIORITY")) { (*argv)[1] = '\0'; /* Fake no argument */ goto priority; /* Terrible, ain't it? */ } else if (!strcmp(*argv, "TEXTQUAL")) { (*argv)[1] = '\0'; goto textqual; } else if (!strcmp(*argv, "GFXQUAL")) { (*argv)[1] = '\0'; goto gfxqual; } else if (!strcmp(*argv, "INSERTKEY")) { (*argv)[1] = '\0'; goto insertkey; } else if (!strcmp(*argv, "CWKEY")) { (*argv)[1] = '\0'; goto cwkey; } else if (!strcmp(*argv, "PREPEND")) { (*argv)[1] = '\0'; goto prepend; } else if (!strcmp(*argv, "APPEND")) { (*argv)[1] = '\0'; goto append; } else if (!strcmp(*argv, "CHARDELAY")) { (*argv)[1] = '\0'; goto chardelay; } else if (!strcmp(*argv, "LINEDELAY")) { (*argv)[1] = '\0'; goto linedelay; } else if (!strcmp(*argv, "CRAWLPTRN")) { (*argv)[1] = '\0'; goto crawlptrn; } else if (!strcmp(*argv, "XEROX")) { goto xerox; } else if (!strcmp(*argv, "NOXEROX")) { goto noxerox; } else if (!strcmp(*argv, "EARLYPATCH")) { goto earlypatch; } else if (!strcmp(*argv, "NOEARLYPATCH")) { goto noearlypatch; } else if (!strcmp(*argv, "TRUEUNDERSCORE")) { goto realunderscore; } else if (!strcmp(*argv, "FAKEUNDERSCORE")) { goto fakeunderscore; } else if (!strcmp(*argv, "JOINLONG")) { goto joinlong; } else if (!strcmp(*argv, "NOJOINLONG")) { goto nojoinlong; } else if (!strcmp(*argv, "STARTUNIT")) { (*argv)[1] = '\0'; goto startunit; } else if (!strcmp(*argv, "PLANEMASK")) { (*argv)[1] = '\0'; goto planemask; } else if (!strcmp(*argv, "GADOFFSET")) { (*argv)[1] = '\0'; goto gadoffset; } else if (!strcmp(*argv, "CACHESIZE")) { (*argv)[1] = '\0'; goto cachesize; } else if (!strcmp(*argv, "BADCHAR")) { (*argv)[1] = '\0'; goto badchar; } else if (!strcmp(*argv, "QUIT")) { goto quit; } else if (strcmp(*argv, "?") && StdOut) { WriteStdOut("Bad switch/keyword: "); WriteStdOut(*argv); WriteStdOut(".\n"); } usage = 1; } } if (usage && StdOut) { WriteStdOut("Usage:\n"); WriteStdOut(" snap -pNN -tXX -gXX -iXX -wXX -Pstr -Astr -cNN -lNN -aXXXX\n"); WriteStdOut(" -x -X -e -E -uN -r -R -j -J -bXX -oNN -CNN -BNN -Q\n"); WriteStdOut(" or\n"); WriteStdOut(" snap PRIORITY/k TEXTQUAL/k GFXQUAL/k INSERTKEY/k CWKEY/k\n"); WriteStdOut(" PREPEND/k APPEND/k CHARDELAY/k LINEDELAY/k CRAWLPTRN/k\n"); WriteStdOut(" XEROX/s NOXEROX/s EARLYPATCH/s NOEARLYPATCH/s STARTUNIT/k\n"); WriteStdOut(" TRUEUNDERSCORE/s FAKEUNDERSCORE/s JOINLONG/s NOJOINLONG/s\n"); WriteStdOut(" PLANEMASK/k GADOFFSET/k CACHESIZE/k BADCHAR/s QUIT/s\n"); } skipargs: if (StdOut) { Close(StdOut); } if (!create) { /* Tell him there are new settings available */ Signal(SnapRsrc->Task, SIGBREAKF_CTRL_F); goto exitpoint; } textqual = SnapRsrc->textqual; gfxqual = SnapRsrc->gfxqual; insertkey = SnapRsrc->insertkey; cwkey = SnapRsrc->cwkey; TrueUnderscore = SnapRsrc->flags & TRUEUNDERSCORE ? 1 : 0; if (!OpenStuff()) { goto close; } #ifdef SNAPREXX rexxsignal = upRexxPort("SNAP", &rcl, NULL, &disp); #endif /* This is what we're waiting for */ WaitSignal = startsignal | insertsignal | initsignal | cancelsignal | #ifdef SNAPREXX rexxsignal | #endif cwsignal | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F; FOREVER { REGISTER LONGBITS sig = Wait(WaitSignal | (Sharedport ? (1L << Sharedport->mp_SigBit) : 0L)); CheckWindowMsgs(); #ifdef SNAPREXX if (sig & rexxsignal) { dispRexxPort(); } #endif if (sig & SIGBREAKF_CTRL_C) { /* This is my cue. Exit if there are no open windows depending on us */ if (Sharedrefs) { DisplayBeep(NULL); } else { goto close; } } if (sig & SIGBREAKF_CTRL_F) { /* Hey, seems like there are new settings available. */ textqual = SnapRsrc->textqual; gfxqual = SnapRsrc->gfxqual; insertkey = SnapRsrc->insertkey; cwkey = SnapRsrc->cwkey; TrueUnderscore = SnapRsrc->flags & TRUEUNDERSCORE ? 1 : 0; } if (sig & initsignal) { if (SnapRsrc->flags & (XEROX | EARLYPATCH)) { SafePatch(); /* Patch dangerous functions */ } } if (sig & cancelsignal) { SafeRestore(); } if (sig & startsignal) { /* The handler wants a word in. */ SafePatch(); if (action == snapgfx) { /* Check user action */ HandleGfx(); /* Get the picture :-) */ } else if (action == snaptext) { if (HandleChars()) { /* Snap some chars */ if (SnapRsrc->flags & XEROX) { sig |= insertsignal; } } } else { /* Previous snap wasn't finished when this one started. */ SetSignal(0L, movesignal|cancelsignal|donesignal|clicksignal|timersignal); DisplayBeep(NULL); action = noaction; } if (!(sig & insertsignal)) { SafeRestore(); /* Layers unlocked - all safe */ } } if (sig & insertsignal) { LONG i; struct Snap *Snap; ULONG ascii; action = insert; if (Snap = FetchClip()) { /* Get clipboard data */ /* get the current keymap */ ConIOR->io_Command = CD_ASKDEFAULTKEYMAP; ConIOR->io_Length = sizeof (struct KeyMap); ConIOR->io_Data = (APTR) &keymap; ConIOR->io_Flags = 1; /* no IOQuick */ DoIO(ConIOR); /* Set up an input request */ inputRequestBlock->io_Command = IND_WRITEEVENT; inputRequestBlock->io_Flags = 0L; inputRequestBlock->io_Length = (long)sizeof(struct InputEvent); inputRequestBlock->io_Data = (APTR)&SimEvent; /* Translate chars in SnapSpace and insert them into the input stream. */ insertcount = 0; ascii = 13; /* Simulate start of new line */ for (i = 0; Snap->Chars[i] && (action == insert); ++i) { if (ascii == 13 && modinsert) { int cnt = 0; while (ascii = SnapRsrc->Prepend[cnt++]) { InsertAscii(ascii); } } ascii = Snap->Chars[i]; if (ascii == 10) { if (modinsert) { int cnt = 0; while (ascii = SnapRsrc->Append[cnt++]) { InsertAscii(ascii); } } ascii = 13; /* WYSIWYG? Hah! */ if (SnapRsrc->linedelay) { MyTR.tr_node.io_Command = TR_ADDREQUEST; MyTR.tr_time.tv_micro = SnapRsrc->linedelay; MyTR.tr_time.tv_secs = 0; DoIO((struct IOStdReq *)&MyTR); } } InsertAscii(ascii); } if (modinsert) { int cnt = 0; while (ascii = SnapRsrc->Append[cnt++]) { InsertAscii(ascii); } } SafeRestore(); /* "Depatch" */ /* Free memory given to us by FetchClip() */ FreeMem(Snap, Snap->Size); } action = noaction; modinsert = 0; } if (sig & cwsignal) { if (!ControlWindow && !OpenCW()) { DisplayBeep(NULL); } } } close: #ifdef SNAPREXX dnRexxPort(); #endif CloseStuff(); /* Guess what */ exitpoint: ; }