From rld1@cec.wustl.edu Mon, 27 Sep 1999 08:35:54 -0500 (CDT) From: "Robert L Dickinson"To: "Timothy Rue" Subject: RE: The unchanging and "REAL" Open direction. Date: 27 Sep 1999 13:35:54 GMT Content-type: multipart/mixed; [edited] > +++> I reassembled my source last night and tried to get back into > +++> it. I think it would be a good thing for me to do a little > +++> clean-up and documentation before making it publicly available. > +++> I'll plan on e-mailing you a presentable version sometime this > +++> weekend. Alas, one of my favorite aspects of software programming is that I have the freedom to change and mold the software any way I like----but sometimes that get's me into trouble. After reviewing my original undocumented code, I convinced myself that it could be done better and in a more organized fashion. So, like a fool, I rewrote it. And besides that, people no doubt will wonder why in the world I code in assembly in this day and age of "platform independence", not to mention that I've re-invented several wheels again. Answers to these wonders exist, but anyway, lets talk about what this code does. GENERAL: To sum it up, right now it does basically nothing, but in a very nice way. I have organized all re-usable code into "vic.library", which is accessed by "AI" as well as the other future commands. In fact, it is intended that any other application is free to access these common routines directly from "vic.library" as well, or by calling the "AI" and other future commands. SETUP: To install it, simply put "vic.library" in "LIBS:", then you are ready to run "AI" as a command from wherever you want. Test my error detection by running "AI" before putting "vic.library" in "LIBS:". No special version of the Amiga operating system or hardware is required. TESTING: To test the current functionality, run "AI" with various arguments. This will demonstrate the common error reporting window. The only recognized argument at this time is "-n ", but several errors can be seen. Try each of the following commands: AI AI -unk AI -n AI -n name AI -n name -n Obviously the successful error message is there for debugging only and will be gone in the future. OK, so thats where it stands right now. Nothing very exciting, and certainly nothing that hasn't been seen in zillions of programs before. But anyway, this is only the starting point. All suggestions are welcome, of course. -Robert Binary "vic.library" at vic-lib.lha Source: ; version/revision of this library (this should always match _libinfo declared below) THIS_VERSION EQU 0 THIS_REVISION EQU 1 ; miscellaneous numeric constants ERRBUF_SIZE EQU 1024 STACK_SIZE EQU 8192 ; Node Type values, see "exec/nodes.i" NT_LIBRARY EQU 9 ; Library structure, see "exec/libraries.i" LIB_NODE EQU 0 LIB_FLAGS EQU 14 LIB_KBYTE00 EQU 15 LIB_NEGSIZE EQU 16 LIB_POSSIZE EQU 18 LIB_VERSION EQU 20 LIB_REVISION EQU 22 LIB_IDSTRING EQU 24 LIB_CHECKSUM EQU 28 LIB_OPENCNT EQU 32 LIB_SIZE EQU 34 ; our library extension L_EXECBASE EQU LIB_SIZE+0 L_INTUITIONBASE EQU LIB_SIZE+4 L_DATA EQU LIB_SIZE+8 L_ERRBUF EQU L_DATA+4 L_ERRPOS EQU L_DATA+8 L_ERRWINDOW EQU L_DATA+12 L_ERRREADPORT EQU L_ERRWINDOW+4 L_ERRWRITEPORT EQU L_ERRWINDOW+38 L_ERRREADREQ EQU L_ERRWINDOW+72 L_ERRWRITEREQ EQU L_ERRWINDOW+120 L_ERRCHAR EQU L_ERRWINDOW+168 L_ERRFLAGS EQU L_ERRWINDOW+169 L_TASK EQU L_ERRWINDOW+170 L_TASKSTACK EQU L_TASK+92 L_TASKPORT EQU L_TASKSTACK+STACK_SIZE L_SIZE EQU L_TASKPORT+34 ; function identifications passed to _Indirect used to index _subvec array MSG_STACKERROR EQU 4 MSG_PRINTERROR EQU 5 MSG_SHOWERRWINDOW EQU 6 MSG_HIDEERRWINDOW EQU 7 MSG_COUNT EQU 8 ; exec.library functions we use _Alert EQU -108 _AllocMem EQU -198 _FreeMem EQU -210 _AddTask EQU -282 _RemTask EQU -288 _FindTask EQU -294 _Wait EQU -318 _AllocSignal EQU -330 _FreeSignal EQU -336 _PutMsg EQU -366 _GetMsg EQU -372 _ReplyMsg EQU -378 _WaitPort EQU -384 _CloseLibrary EQU -414 _OpenLibrary EQU -552 _OpenDevice EQU -444 _CloseDevice EQU -450 _DoIO EQU -456 _SendIO EQU -462 _CheckIO EQU -468 _AbortIO EQU -480 _CacheClearU EQU -636 ; version 36+ (release 2.0+) ; intuition.library functions we use _CloseWindow EQU -72 _OpenWindow EQU -204 _WindowToFront EQU -312 _ActivateWindow EQU -450 ; version 33+ (release 1.2+) SECTION _Lib,CODE ; exit immediately if somebody executes this object module _Stub MOVEQ #-1,D0 RTS ; library header data _libhead DC.W $4AFC DC.L _libhead,_libtail DC.B $80,THIS_VERSION,NT_LIBRARY,0 DC.L _libname,_libinfo,_libmake _libname DC.B "vic.library",0 _libinfo DC.B "vic 0.1 (26.9.99)",13,10,0 _libmake DC.L L_SIZE,_libvec,0,_LibInit _libvec DC.L _LibOpen,_LibClose,_LibExpunge,_LibReserved DC.L __StackError,__PrintError,__ShowErrWindow,__HideErrWindow DC.L _CopyArg DC.L _StrLen,_StrCopy,_StrCmp,_StrDup,_StrFree DC.L -1 ; miscellaneous constants _ibname DC.B "intuition.library",0 _cdname DC.B "console.device",0 _setevents DC.B $9B,"11{",0 _closeevent DC.B $9B,"11;",0 _nwerr DC.W 0,0,640,130,-1 DC.L $00000000,$0000000F,0,0,_libname,0,0 DC.W 75,50,-1,-1,$0001 _subvec DC.L 0,0,0,0 DC.L _StackError,_PrintError,_ShowErrWindow,_HideErrWindow ; _LibInit ; initialize this library ; ; INPUTS ; A6 - pointer to exec library ; D0 - pointer to this library ; A0 - pointer to data area ; ; OUTPUTS ; D0 - pointer to this library or NULL ; ; COMMENTS ; If our initialization is successful, we need ; to return our library pointer, otherwise we ; return NULL to indicate failure. ; ; Note that the failure cleanup in this routine ; should match the cleanup in _LibExpunge. ; ; SEE ALSO ; _LibExpunge ; _LibInit MOVEM.L A2-A3/A5-A6,-(SP) MOVEA.L D0,A5 MOVE.L A6,L_EXECBASE(A5) MOVE.L A0,L_DATA(A5) MOVE.W #THIS_REVISION,LIB_REVISION(A5) MOVEA.L L_EXECBASE(A5),A6 ; open intuition.library LEA _ibname,A1 MOVEQ #0,D0 JSR _OpenLibrary(A6) MOVE.L D0,L_INTUITIONBASE(A5) BEQ lifail0 ; open intuition.library failed (unlikely) MOVEA.L L_EXECBASE(A5),A6 ; allocate error message buffer MOVE.L #ERRBUF_SIZE,D0 MOVEQ #0,D1 JSR _AllocMem(A6) MOVE.L D0,L_ERRBUF(A5) BEQ lifail1 ; error message buffer allocation failed MOVEA.L D0,A0 ADDA.W #ERRBUF_SIZE,A0 MOVE.B #10,-(A0) MOVE.L A0,L_ERRPOS(A5) CLR.L L_ERRWINDOW(A5) MOVE.B #1,L_TASK+8(A5) ; initialize library task MOVE.B #0,L_TASK+9(A5) MOVE.L #_libname,L_TASK+10(A5) LEA L_TASKSTACK(A5),A0 MOVE.L A0,L_TASK+58(A5) ADDA.L #STACK_SIZE,A0 MOVE.L A0,L_TASK+54(A5) MOVE.L A0,L_TASK+62(A5) MOVE.L A5,L_TASK+88(A5) LEA L_TASKPORT(A5),A0 ; initialize task port JSR _InitPort MOVE.B #0,L_TASKPORT+14(A5) MOVE.B #16,L_TASKPORT+15(A5) LEA L_TASK(A5),A0 MOVE.L A0,L_TASKPORT+16(A5) LEA L_TASK(A5),A1 LEA _LibTask,A2 SUBA.L A3,A3 JSR _AddTask(A6) MOVE.L A5,D0 BRA.S lipass0 ; skip failure processing MOVEA.L L_EXECBASE(A5),A6 ; remove task upon failure LEA L_TASK(A5),A1 JSR _RemTask(A6) MOVEA.L L_EXECBASE(A5),A6 ; free error message buffer upon failure MOVEA.L L_ERRBUF(A5),A1 MOVE.L #ERRBUF_SIZE,D0 JSR _FreeMem(A6) lifail1 MOVEA.L L_EXECBASE(A5),A6 ; close intuition.library upon failure MOVEA.L L_INTUITIONBASE(A5),A1 JSR _CloseLibrary(A6) lifail0 MOVEQ #0,D0 ; return NULL upon failure lipass0 MOVEM.L (SP)+,A2-A3/A5-A6 RTS ; _LibTask ; process library messages and perform respective duties ; ; INPUTS ; ; OUTPUTS ; ; COMMENTS ; This task is alive for the duration of our library's ; existance. Some critical library functions pass their ; respective calls to this task through it's message ; port so that they can be processed in a safe manner. ; (Safe in that there will be no possibility of multiple ; accessors calling conflicting function simultaneously ; and having to use the Exec _Forbid/_Permit functions.) ; ; Note that this routine is self modifying. When a ; message is received, the appropriate routine address ; is copied into a JSR instruction for execution. ; ; Messages received by this routine are expected to have ; the register bank as part of the message, which will ; be updated with the results of the indirect function ; call before the message is replied. ; ; BUGS ; _AlertError calls are passed a NULL parameter in A0 ; which causes serious problems. Hopefully we never need ; to display an alert anyway, but this should still be ; fixed to make our failures somewhat graceful at least. ; ; SEE ALSO ; _Indirect ; _LibTask MOVEA.L $00000004,A6 SUBA.L A1,A1 JSR _FindTask(A6) MOVEA.L D0,A0 MOVEA.L 88(A0),A5 MOVEA.L L_EXECBASE(A5),A6 MOVEQ #16,D0 JSR _AllocSignal(A6) ltloop0 MOVE.L #$00010000,D0 TST.L L_ERRWINDOW(A5) BEQ.S ltskip2 MOVEQ #1,D2 MOVE.B L_ERRREADPORT+15(A5),D1 LSL.L D1,D2 OR.L D2,D0 ltskip2 JSR _Wait(A6) ltloop1 LEA L_TASKPORT(A5),A0 JSR _GetMsg(A6) TST.L D0 BEQ.S ltskip1 MOVEA.L D0,A4 MOVE.L 20+60(A4),D0 ; get message number CMPI.L #MSG_COUNT,D0 BCC ltfail0 ; message number out of range (greater than or equal to MSG_COUNT) LSL.L #2,D0 LEA _subvec,A0 TST.L 0(A0,D0) BEQ ltfail0 ; message number has no vector MOVE.L 0(A0,D0),ltmod0+2 ; self modifying code, see COMMENTS CMPI.W #36,20(A6) BCS.S ltskip0 JSR _CacheClearU(A6) ; clear instruction cache so that modified code will be refetched ltskip0 MOVE.L A4,_msg MOVEM.L D0-D7/A0-A6,-(SP) MOVE.L SP,_sp MOVEM.L 20(A4),D0-D7/A0-A6 ; load registers from message ltmod0 JSR _SelfModify ; call indirect function (function address modified above, see COMMENTS) MOVEA.L _msg,A7 MOVEM.L D0-D7/A0-A6,20(A7) ; save registers to message MOVEA.L _sp,SP MOVEM.L (SP)+,D0-D7/A0-A6 MOVEA.L A4,A1 ; function call complete, reply JSR _ReplyMsg(A6) BRA.S ltloop1 ltskip1 TST.L L_ERRWINDOW(A5) BEQ ltloop0 LEA L_ERRREADREQ(A5),A1 JSR _CheckIO(A6) TST.L D0 BEQ ltloop0 LEA L_ERRREADPORT(A5),A0 JSR _WaitPort(A6) TST.L D0 BEQ ltloop0 LEA L_ERRREADPORT(A5),A0 JSR _GetMsg(A6) TST.L D0 BEQ ltloop0 MOVE.B L_ERRCHAR(A5),D2 LEA L_ERRREADREQ(A5),A1 MOVE.W #2,28(A1) MOVE.L #1,36(A1) LEA L_ERRCHAR(A5),A0 MOVE.L A0,40(A1) JSR _SendIO(A6) MOVE.B D2,D0 CMPI.B #$9B,D0 BNE.S ltskipch0 MOVE.B #1,L_ERRFLAGS(A5) BRA ltloop0 ltskipch0 MOVEQ #0,D1 MOVE.B L_ERRFLAGS(A5),D1 LEA _closeevent,A0 TST.B 0(A0,D1) CMP.B 0(A0,D1),D0 BNE.S ltskipch1 ADDQ.B #1,D1 MOVE.B D1,L_ERRFLAGS(A5) TST.B 0(A0,D1) BNE ltloop0 MOVEA.L A5,A6 JSR _HideErrWindow MOVEA.L L_EXECBASE(A5),A6 BRA ltloop0 ltskipch1 CLR.B L_ERRFLAGS(A5) BRA ltloop0 ltfail0 MOVE.L #$35080000,D0 SUBA.L A0,A0 JSR _AlertError BRA ltloop1 RTS ; this routine should never return _sp DC.L 0 _msg DC.L 0 ; _SelfModify ; intended never to be called ; ; SEE ALSO ; _LibTask ; _SelfModify MOVE.L #$35000000,D0 SUBA.L A0,A0 JSR _AlertError RTS ; _Indirect ; pass a function call to vic.library task for ; processing ; ; INPUTS ; A6 - pointer to this library ; all registers - parameters for function call ; stack parameter - identification of function to call ; ; OUTPUTS ; all registers - parameters returned by function call ; ; COMMENTS ; This function should be invoked with a JMP instead of ; a JSR. Since this routine is not expected to return to ; the caller, the stack parameter will be removed from ; the stack in this routine. Also, the caller must not ; allocate anything else on the stack because this routine ; will not know how to remove it. ; ; The purpose of this routine is to allow a tiny stub ; routine to put the function identification number on ; the stack and JMP to this routine, which will call the ; specified function indirectly by posting a message to ; our library port. Once the message is returned, we ; will return back to the caller's caller, as if the ; requested routine had been called directly. This ; whole process can be thought of as a way of isolating ; a subroutine call from the caller's task without the ; caller knowing it. Instead of the caller's task ; executing the subroutine, our library task is told to ; execute it instead, on it's own time, with it's own ; task. The original caller sleeps in the mean time. ; ; The message that we pass on to the library task is a bit ; convoluted. We create the Message structure on the ; stack frame in such a way that the registers we save ; on the stack will follow the Message structure in ; memory, to be used as part of the message. This is made ; possible by the fact that the stack grows downward. ; As the message contents are modified by the library's ; task while we are a sleep, our stack frame is actually ; being modified. When we restore the registers, we will ; actually be restoring the modified values. ; ; SEE ALSO ; _LibTask ; _Indirect MOVEM.L D0-D7/A0-A6,-(SP) ; save our registers on the stack, part of the Message structure SUBA.L #34+20,SP ; set up our stack frame for Port and Message structures MOVEA.L SP,A4 MOVEA.L A6,A5 MOVEA.L L_EXECBASE(A5),A6 MOVEA.L A4,A0 ; initialize Port structure JSR _InitPort MOVEQ #-1,D0 ; allocate wait signal JSR _AllocSignal(A6) CMPI.L #31,D0 BHI ifail0 ; this error isn't trapped MOVE.B #0,14(A4) MOVE.B D0,15(A4) SUBA.L A1,A1 JSR _FindTask(A6) MOVE.L D0,16(A4) CLR.L 34+0(A4) ; initialize Message structure CLR.L 34+4(A4) MOVE.B #5,34+8(A4) CLR.B 34+9(A4) CLR.L 34+10(A4) MOVE.L A4,34+14(A4) MOVE.W #20+64,34+18(A4) LEA L_TASKPORT(A5),A0 ; send message to vic.library task LEA 34(A4),A1 JSR _PutMsg(A6) MOVEQ #1,D0 ; wait for message to be returned MOVE.B 15(A4),D1 LSL.L D1,D0 JSR _Wait(A6) MOVE.B 15(A4),D0 ; free wait signal JSR _FreeSignal(A6) ifail0 ADDA.L #34+20,SP ; clean up our stack frame MOVEM.L (SP)+,D0-D7/A0-A6 ; restore registers, as altered by Message processing ADDQ.L #4,SP ; this instruction is critical, read COMMENTS section RTS ; _LibOpen ; request access to this library ; this standard library function is required by Exec ; ; INPUTS ; A6 - pointer to this library ; ; OUTPUTS ; D0 - pointer to this library or NULL ; ; COMMENTS ; If this open is successful, we need to return ; our library pointer. For failure, we simply ; return NULL. ; ; SEE ALSO ; _LibClose ; _LibOpen ADDQ.W #1,LIB_OPENCNT(A6) BNE.S loskip0 MOVE.W #$FFFF,LIB_OPENCNT(A6) ; prevent wrap around loskip0 MOVE.L A6,D0 RTS ; _LibClose ; release access to this library ; this standard library function is required by Exec ; ; INPUTS ; A6 - pointer to this library ; ; OUTPUTS ; D0 - pointer to data area or NULL ; ; COMMENTS ; If we are actually closing down, we need to ; return the data pointer that we received during ; initialization so that it can be freed by ; Exec. If we are staying loaded, then we must ; return NULL. ; ; SEE ALSO ; _LibOpen ; _LibClose CMPI.W #$FFFF,LIB_OPENCNT(A6) ; once we have this many opens, we lose track and stop closing BEQ.S lcskip0 SUBQ.W #1,LIB_OPENCNT(A6) ; if this wraps around (to $FFFF), we loose track also lcskip0 MOVEQ #0,D0 RTS ; _LibExpunge ; expunge this library ; this standard library function is required by exec ; ; INPUTS ; A6 - pointer to this library ; ; OUTPUTS ; D0 - pointer to data area or NULL ; ; COMMENTS ; If we are actually closing down, we need to ; return the data pointer that we received during ; initialization so that it can be freed by ; Exec. If we are staying loaded, then we must ; return NULL. ; ; Note that the cleanup in this routine should ; match the initializations in _LibInit. ; ; SEE ALSO ; _LibInit ; _LibExpunge MOVEQ #0,D0 TST.W LIB_OPENCNT(A6) BNE.S leskip0 MOVEM.L D2/A5-A6,-(SP) MOVEA.L A6,A5 JSR __HideErrWindow MOVEA.L L_EXECBASE(A5),A6 LEA L_TASK(A5),A1 ; remove task JSR _RemTask(A6) MOVEA.L L_ERRBUF(A5),A1 ; free error message buffer MOVE.L #ERRBUF_SIZE,D0 JSR _FreeMem(A6) MOVEA.L L_INTUITIONBASE(A5),A1 ; close intuition.library JSR _CloseLibrary(A6) MOVE.L L_DATA(A5),D2 ; do final cleanup MOVE.L A5,A1 MOVE.L (A1)+,A0 MOVE.L (A1),A1 MOVE.L A0,(A1) MOVE.L A1,4(A0) MOVE.L A5,A1 MOVEQ #0,D0 MOVE.W LIB_NEGSIZE(A5),D0 SUBA.L D0,A1 ADD.W LIB_POSSIZE(A5),D0 JSR _FreeMem(A6) MOVE.L D2,D0 MOVEM.L (SP)+,D2/A5-A6 leskip0 RTS ; _LibReserved ; this function is reserved for future use ; this standard library function is required by exec ; ; INPUTS ; ; OUTPUTS ; D0 - NULL ; _LibReserved MOVEQ #0,D0 RTS ; SEE ALSO ; _StackError ; __StackError MOVE.L #MSG_STACKERROR,-(SP) JMP _Indirect ; SEE ALSO ; _PrintError ; __PrintError MOVE.L #MSG_PRINTERROR,-(SP) JMP _Indirect ; SEE ALSO ; _ShowErrWindow ; __ShowErrWindow MOVE.L #MSG_SHOWERRWINDOW,-(SP) JMP _Indirect ; SEE ALSO ; _HideErrWindow ; __HideErrWindow MOVE.L #MSG_HIDEERRWINDOW,-(SP) JMP _Indirect ; _CopyArg ; copies the next argument in a command line into the ; specified buffer ; ; INPUTS ; A0 - pointer to a non-terminated command-line string ; D0 - length of string in A0 ; A1 - pointer to output string buffer ; ; OUTPUTS ; D0 - number of characters used from original string ; ; COMMENTS ; This routine copies the next command-line argument into ; the buffer specified, terminating the string with a ; NULL. Note that the input string is not NULL-terminated ; and the size must be specified. The return value of this ; function is the number of characters that were used up ; from the input string, which not necessarily match the ; length of the NULL-terminated output string due to spaces ; being stripped and such. ; _CopyArg MOVE.L D0,-(SP) caloop0 TST.L D0 BEQ.S cadone0 SUBQ.L #1,D0 MOVE.B (A0)+,D1 CMPI.B #32,D1 BLS.S caloop0 CMPI.B #'"',D1 BEQ.S caskip0 caloop1 MOVE.B D1,(A1)+ TST.L D0 BEQ.S cadone0 SUBQ.L #1,D0 MOVE.B (A0)+,D1 CMPI.B #32,D1 BLS.S cadone0 BRA.S caloop1 caskip0 NOP caloop2 TST.L D0 BEQ.S cadone0 SUBQ.L #1,D0 MOVE.B (A0)+,D1 CMPI.B #'"',D1 BEQ.S cadone0 MOVE.B D1,(A1)+ BRA.S caloop2 cadone0 CLR.B (A1) NEG.L D0 ADD.L (SP)+,D0 RTS ; _StrLen ; returns the length of a NULL-terminated string ; ; INPUTS ; A0 - NULL-terminated string ; ; OUTPUTS ; D0 - length ; _StrLen MOVEQ #-1,D0 slloop0 ADDQ.L #1,D0 TST.L (A0)+ BNE.S slloop0 RTS ; _StrCopy ; copy a NULL-terminated string ; ; INPUTS ; A0 - source NULL-terminated string ; A1 - destination NULL-terminated string ; ; OUTPUTS ; D0 - address of NULL in destination string ; _StrCopy NOP scloop1 MOVE.B (A0)+,(A1)+ BNE.S scloop1 MOVE.L A1,D0 SUBQ.L #1,D0 RTS ; _StrCmp ; returns zero if the strings are equal ; ; INPUTS ; A0 - NULL-terminated string ; A1 - NULL-terminated string ; ; OUTPUTS ; D0 - zero if equal ; _StrCmp MOVEQ #-1,D0 scloop0 CMPM.B (A0)+,(A1)+ BNE.S scfail0 TST.B -1(A0) BNE.S scloop0 MOVEQ #0,D0 scfail0 RTS ; _StrDup ; allocates a copy of a NULL-terminated string ; ; INPUTS ; A0 - NULL-terminated string ; ; OUTPUTS ; D0 - NULL-terminated string ; _StrDup MOVEM.L A4-A6,-(SP) MOVE.L A0,A4 MOVEA.L A6,A5 JSR _StrLen MOVEA.L L_EXECBASE(A5),A6 ADDQ.L #1,D0 MOVEQ #0,D1 JSR _AllocMem(A6) TST.L D0 BEQ.S sdfail0 MOVEA.L A5,A6 MOVEA.L A4,A0 MOVEA.L D0,A1 MOVEA.L D0,A4 JSR _StrCopy MOVE.L A4,D0 sdfail0 MOVEM.L (SP)+,A4-A6 RTS ; _StrFree ; frees a NULL-terminated string ; ; INPUTS ; A0 - NULL-terminated string ; _StrFree MOVEM.L A4-A6,-(SP) MOVE.L A0,A4 MOVEA.L A6,A5 JSR _StrLen MOVEA.L L_EXECBASE(A5),A6 ADDQ.L #1,D0 MOVE.L A4,A1 JSR _FreeMem(A6) MOVEM.L (SP)+,A4-A6 RTS ; _StackError ; this function concatenates the specified string to ; the current error message for later outputting. ; ; INPUTS ; A0 - pointer to a NULL-terminated string (error message) ; ; OUTPUTS ; ; COMMENTS ; This is done to allow lower-level code to record errors ; as well as higher level code. Any routine that fails ; but returns an error code should call this routine, ; but routines that fail and don't return an error code ; should use _PrintError. This way, the error can be ; traced from the low-level code outward to the actual ; routine that printed the error, all in one error message. ; ; SEE ALSO ; _PrintError ; _StackError MOVE.L A0,D0 seloop0 TST.B (A0)+ BNE.S seloop0 MOVE.L L_ERRBUF(A6),D1 MOVEA.L L_ERRPOS(A6),A1 CMPI.B #32,(A1) ; (A1) is a white space BLS.S seskip0 ; skip ': ' separator CMPA.L D1,A1 BCS.S sedone1 ; A1 less than D1 MOVE.B #' ',-(A1) CMPA.L D1,A1 BCS.S sedone1 ; A1 less than D1 MOVE.B #':',-(A1) seskip0 SUBQ.L #1,A0 seloop1 CMPA.L D0,A0 BLS.S sedone1 ; A0 less than or equal to D0 CMPA.L D1,A1 BCS.S sedone1 ; A1 less than D1 MOVE.B -(A0),-(A1) BRA.S seloop1 sedone1 MOVE.L A1,L_ERRPOS(A6) RTS ; _PrintError ; this function concatenates the specified string to ; the current error message and outputs the whole ; message preceeded by the name of the reporter. ; ; INPUTS ; A0 - pointer to a NULL-terminated error string ; A1 - pointer to a NULL-terminated name string of reporter ; ; OUTPUTS ; ; COMMENTS ; Error strings should be reported regardless of whether ; or not you are returning an error code. If you are ; returning an error code, you should use _StackError, ; but if not then use this routine. This mechanism allows ; errors to be reported in a format that shows each detection ; of the error from the low-level code out to the high-level ; code, producing a sort of "call-stack" to aid in debugging. ; ; SEE ALSO ; _StackError ; _PrintError MOVEM.L A5-A6,-(SP) MOVEA.L A1,A5 JSR _StackError MOVEA.L A5,A0 MOVEA.L A6,A5 MOVE.L L_ERRBUF(A5),D1 MOVEA.L L_ERRPOS(A5),A1 CMPA.L D1,A1 BCS.S pedone0 ; A1 less than D1 MOVE.B #' ',-(A1) CMPA.L D1,A1 BCS.S pedone0 ; A1 less than D1 MOVE.B #'-',-(A1) CMPA.L D1,A1 BCS.S pedone0 ; A1 less than D1 MOVE.B #' ',-(A1) pedone0 MOVE.L A1,L_ERRPOS(A5) JSR _StackError JSR _ShowErrWindow TST.L L_ERRWINDOW(A5) BEQ.S pefail0 MOVE.L L_ERRBUF(A5),D0 ADD.L #ERRBUF_SIZE,D0 SUB.L L_ERRPOS(A5),D0 MOVEA.L L_EXECBASE(A5),A6 LEA L_ERRWRITEREQ(A5),A1 MOVE.W #3,28(A1) MOVE.L D0,36(A1) MOVE.L L_ERRPOS(A5),40(A1) JSR _DoIO(A6) pefail0 MOVEA.L L_ERRBUF(A5),A0 ADDA.W #ERRBUF_SIZE,A0 MOVE.B #10,-(A0) MOVE.L A0,L_ERRPOS(A5) MOVEM.L (SP)+,A5-A6 RTS _ShowErrWindow MOVEM.L A5-A6,-(SP) MOVEA.L A6,A5 TST.L L_ERRWINDOW(A5) BNE sewskip0 MOVEA.L L_INTUITIONBASE(A5),A6 LEA _nwerr,A0 JSR _OpenWindow(A6) MOVE.L D0,L_ERRWINDOW(A5) BEQ sewskip0 MOVEA.L L_EXECBASE(A5),A6 LEA L_ERRWRITEPORT(A5),A0 JSR _InitPort MOVEQ #-1,D0 JSR _AllocSignal(A6) MOVE.B #0,L_ERRWRITEPORT+14(A5) MOVE.B D0,L_ERRWRITEPORT+15(A5) SUBA.L A1,A1 JSR _FindTask(A6) MOVE.L D0,L_ERRWRITEPORT+16(A5) LEA L_ERRWRITEREQ(A5),A0 LEA L_ERRWRITEPORT(A5),A1 JSR _InitStdIOReq LEA L_ERRREADPORT(A5),A0 JSR _InitPort MOVEQ #-1,D0 JSR _AllocSignal(A6) MOVE.B #0,L_ERRREADPORT+14(A5) MOVE.B D0,L_ERRREADPORT+15(A5) SUBA.L A1,A1 JSR _FindTask(A6) MOVE.L D0,L_ERRREADPORT+16(A5) LEA L_ERRREADREQ(A5),A0 LEA L_ERRREADPORT(A5),A1 JSR _InitStdIOReq MOVE.L #132,L_ERRWRITEREQ+36(A5) ; size of release 1.2 Window structure MOVE.L L_ERRWINDOW(A5),L_ERRWRITEREQ+40(A5) LEA _cdname,A0 MOVEQ #0,D0 LEA L_ERRWRITEREQ(A5),A1 MOVEQ #0,D1 JSR _OpenDevice(A6) MOVE.L L_ERRWRITEREQ+20(A5),L_ERRREADREQ+20(A5) MOVE.L L_ERRWRITEREQ+24(A5),L_ERRREADREQ+24(A5) TST.L D0 BNE.S sewfail0 MOVEA.L L_EXECBASE(A5),A6 LEA L_ERRWRITEREQ(A5),A1 MOVE.W #3,28(A1) MOVE.L #4,36(A1) MOVE.L #_setevents,40(A1) JSR _DoIO(A6) LEA L_ERRREADREQ(A5),A1 MOVE.W #2,28(A1) MOVE.L #1,36(A1) LEA L_ERRCHAR(A5),A0 MOVE.L A0,40(A1) JSR _SendIO(A6) BRA.S sewskip0 sewfail0 MOVEA.L L_INTUITIONBASE(A5),A6 MOVEA.L L_ERRWINDOW(A5),A0 JSR _CloseWindow(A6) CLR.L L_ERRWINDOW(A5) sewskip0 TST.L L_ERRWINDOW(A5) BEQ.S sewskip1 MOVEA.L L_INTUITIONBASE(A5),A6 MOVEA.L L_ERRWINDOW(A5),A0 JSR _WindowToFront(A6) ; CMPI.W #33,LIB_VERSION(A6) ; BLT.S sewskip1 ; MOVEA.L L_ERRWINDOW(A5),A0 ; JSR _ActivateWindow(A6) sewskip1 MOVEM.L (SP)+,A5-A6 RTS _HideErrWindow MOVEM.L A5-A6,-(SP) MOVEA.L A6,A5 TST.L L_ERRWINDOW(A5) BEQ.S hewskip0 MOVEA.L L_EXECBASE(A5),A6 LEA L_ERRREADREQ(A5),A1 JSR _CheckIO(A6) TST.L D0 BNE.S hewskip1 LEA L_ERRREADREQ(A5),A1 JSR _AbortIO(A6) hewskip1 LEA L_ERRREADPORT(A5),A0 JSR _WaitPort(A6) LEA L_ERRREADPORT(A5),A0 JSR _GetMsg(A6) TST.L D0 BNE.S hewskip2 BRA.S hewskip1 hewskip2 LEA L_ERRWRITEREQ(A5),A1 JSR _CloseDevice(A6) MOVE.B L_ERRWRITEPORT+15(A5),D0 JSR _FreeSignal(A6) MOVE.B L_ERRREADPORT+15(A5),D0 JSR _FreeSignal(A6) MOVEA.L L_INTUITIONBASE(A5),A6 MOVEA.L L_ERRWINDOW(A5),A0 JSR _CloseWindow(A6) CLR.L L_ERRWINDOW(A5) hewskip0 MOVEM.L (SP)+,A5-A6 RTS _InitPort CLR.L (A0) CLR.L 4(A0) MOVE.B #4,8(A0) CLR.B 9(A0) CLR.L 10(A0) MOVE.B #2,14(A0) CLR.B 15(A0) CLR.L 16(A0) MOVE.B #5,32(A0) CLR.B 33(A0) LEA 20(A0),A0 JSR _NewList RTS _InitStdIOReq CLR.L (A0) CLR.L 4(A0) MOVE.B #5,8(A0) CLR.B 9(A0) CLR.L 10(A0) MOVE.L A1,14(A0) MOVE.W #48,18(A0) CLR.L 20(A0) CLR.L 24(A0) CLR.W 28(A0) CLR.B 30(A0) CLR.B 31(A0) CLR.L 32(A0) CLR.L 36(A0) CLR.L 40(A0) CLR.L 44(A0) RTS _NewList MOVE.L A0,(A0) ADDQ.L #4,(A0) CLR.L 4(A0) MOVE.L A0,8(A0) RTS ; _AlertError ; display an alert ; ; INPUTS ; D0 - alert number ; A0 - alert message ; ; OUTPUTS ; ; COMMENTS ; After displaying the alert, this function waits forever ; or until the task is removed. This is intended only for ; our own fatal errors, obviously, but should allow us to ; freeze gracefully so that the rest of the system doesn't ; suffer. ; _AlertError MOVEM.L D7/A5-A6,-(SP) MOVEA.L $00000004,A6 MOVE.L D0,D7 MOVEA.L A0,A5 ; need to figure out this parameter JSR _Alert(A6) MOVEQ #0,D0 JSR _Wait(A6) ; wait forever MOVEM.L (SP)+,D7/A5-A6 RTS _libtail DS.W 0 END Binary "AI" at AI.lha Source: ; exec.library functions we use _Forbid EQU -132 _AllocMem EQU -198 _FreeMem EQU -210 _FindTask EQU -294 _GetMsg EQU -372 _ReplyMsg EQU -378 _WaitPort EQU -384 _CloseLibrary EQU -414 _OpenLibrary EQU -552 ; dos.library functions we use _Write EQU -48 _Output EQU -60 ; vic.library functions we use _StackError EQU -30 _PrintError EQU -36 ;_ShowErrWindow EQU -42 ;_HideErrWindow EQU -48 _CopyArg EQU -54 ;_StrLen EQU -60 ;_StrCopy EQU -66 _StrCmp EQU -72 _StrDup EQU -78 _StrFree EQU -84 ; mode definitions MODE_CREATE EQU 1 ; absolute pointer to exec.library _eb EQU $00000004 SECTION _Prog,CODE _Setup MOVE.L D0,_cmdlen MOVE.L A0,_cmdstr MOVEA.L _eb,A6 SUBA.L A1,A1 JSR _FindTask(A6) MOVE.L D0,_tc MOVEA.L _tc,A2 MOVE.L 10(A2),_tcprev MOVE.L #_tcname,10(A2) TST.L 172(A2) BNE.S sskipwb0 CLR.L _cmdlen CLR.L _cmdstr LEA 92(A2),A0 JSR _WaitPort(A6) LEA 92(A2),A0 JSR _GetMsg(A6) MOVE.L D0,_wbmsg sskipwb0 LEA _dbname,A1 MOVEQ #0,D0 JSR _OpenLibrary(A6) MOVE.L D0,_db BEQ.S sfail0 LEA _vbname,A1 MOVEQ #0,D0 JSR _OpenLibrary(A6) MOVE.L D0,_vb BEQ.S sfail1 JSR _ParseCmdLine MOVEA.L _vb,A1 JSR _CloseLibrary(A6) BRA.S spass1 sfail1 MOVEA.L _db,A6 JSR _Output(A6) BEQ.S spass1 LEA _vberr,A0 MOVE.L D0,D1 MOVE.L A0,D2 MOVEQ #-1,D3 sloop0 ADDQ.L #1,D3 TST.B (A0)+ BNE.S sloop0 JSR _Write(A6) MOVEA.L _eb,A6 spass1 MOVEA.L _db,A1 JSR _CloseLibrary(A6) sfail0 MOVEA.L _tc,A2 TST.L 172(A2) BNE.S sskipwb1 JSR _Forbid(A6) MOVEA.L _wbmsg,A1 JSR _ReplyMsg(A6) sskipwb1 MOVE.L _tcprev,10(A2) MOVEQ #0,D0 RTS _ParseCmdLine MOVEM.L D4/A4-A6,-(SP) MOVEA.L _eb,A6 MOVE.L _cmdlen,D0 MOVEQ #0,D1 JSR _AllocMem(A6) TST.L D0 BEQ pclfail0 MOVEA.L D0,A5 MOVE.L _cmdlen,D4 SUBQ.L #1,D4 MOVEA.L _cmdstr,A4 MOVEA.L _vb,A6 pclloop0 MOVEA.L A4,A0 MOVE.L D4,D0 MOVEA.L A5,A1 JSR _CopyArg(A6) SUB.L D0,D4 ADDA.L D0,A4 TST.B (A5) BEQ pcldone0 MOVEA.L A5,A0 JSR _CheckKeyword CMPI.L #_dashn,D0 BNE pcldashn0 TST.B _cmdmode BEQ.S pcldashn2 CMPI.B #MODE_CREATE,_cmdmode BEQ.S pcldashn2 LEA _errambigmode0,A0 LEA _tcname,A1 JSR _PrintError(A6) BRA pclfail1 pcldashn2 MOVE.B #MODE_CREATE,_cmdmode TST.L _optname BEQ.S pcldashn1 LEA _errambigopt0,A0 LEA _tcname,A1 JSR _PrintError(A6) BRA.S pclfail1 pcldashn1 MOVEA.L A4,A0 MOVE.L D4,D0 MOVEA.L A5,A1 JSR _CopyArg(A6) SUB.L D0,D4 ADDA.L D0,A4 TST.B (A5) BNE.S pcldashn3 LEA _errmissname0,A0 LEA _tcname,A1 JSR _PrintError(A6) BRA.S pclfail1 pcldashn3 MOVEA.L A5,A0 JSR _StrDup(A6) MOVE.L D0,_optname BNE.S pcldashn4 LEA _errdupstr0,A0 LEA _tcname,A1 JSR _PrintError(A6) BRA.S pclfail1 pcldashn4 BRA pclloop0 pcldashn0 MOVEA.L A5,A0 JSR _StackError(A6) LEA _errunknownopt0,A0 LEA _tcname,A1 JSR _PrintError(A6) BRA.S pclfail1 pcldone0 NOP LEA _success,A0 LEA _tcname,A1 JSR _PrintError(A6) pclfail1 TST.L _optname BEQ.S pclskip1 MOVEA.L _vb,A6 MOVEA.L _optname,A0 JSR _StrFree(A6) pclskip1 MOVEA.L _eb,A6 MOVEA.L A5,A1 MOVE.L _cmdlen,D0 JSR _FreeMem(A6) BRA.S pclpass0 pclfail0 MOVEA.L _vb,A6 LEA _errallocmem0,A0 LEA _tcname,A1 JSR _PrintError(A6) pclpass0 MOVEM.L (SP)+,D4/A4-A6 RTS _CheckKeyword MOVEM.L A2-A3/A6,-(SP) MOVEA.L A0,A3 MOVEA.L _vb,A6 LEA _keywords,A2 ckloop0 MOVEA.L (A2)+,A1 MOVEA.L A3,A0 JSR _StrCmp(A6) TST.L D0 BEQ.S ckdone0 TST.L (A2) BNE.S ckloop0 MOVEQ #0,D0 BRA.S ckpass0 ckdone0 MOVE.L -4(A2),D0 ckpass0 MOVEM.L (SP)+,A2-A3/A6 RTS SECTION _Const,DATA _tcname DC.B "AI",0 _dbname DC.B "dos.library",0 _vbname DC.B "vic.library",0 _success DC.B "success",0 _vberr DC.B 'Unable to open VIC library! (Verify "LIBS:vic.library" exists.)',10,0 _errallocmem0 DC.B "unable to allocate memory for command-line argument buffer",0 _errambigmode0 DC.B "ambiguous command mode",0 _errambigopt0 DC.B "ambiguous option specification",0 _errdupstr0 DC.B "unable to duplicate name string",0 _errunknownopt0 DC.B "unknown option",0 _errmissname0 DC.B "missing name",0 _dashn DC.B "-n",0 _keywords DC.L _dashn DC.L 0 SECTION _Var,BSS _tc DS.L 1 _tcprev DS.L 1 _cmdlen DS.L 1 _cmdstr DS.L 1 _wbmsg DS.L 1 _db DS.L 1 _vb DS.L 1 _optname DS.L 1 _cmdmode DS.B 1 END