/* Guru.c */

/* dekodiert Guru-Botschaften, soweit bekannt */

#include <exec/alerts.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

short readxdigit;

short doreadxdigit(char c)
{
    if((c>='0') && (c<='9'))        readxdigit=c-'0';
    else if(('A'<=c) && (c<='F'))   readxdigit=c-'A'+10;
    else if(('a'<=c) && (c<='f'))   readxdigit=c-'a'+10;
    else			    return(1);
    return(0);
}

unsigned long HexVal(char *arg)
{ /* returns the value of the given 8digit-hex-string, ignoring a leading
    '#', or 0 for fault */
    unsigned long zwerg;
    short cnt;

    if(*arg=='#')   ++arg;
    for(cnt=zwerg=0; cnt<8; ++cnt)
	{
	if(*arg==0)                 return(zwerg);
	if(doreadxdigit(*(arg++)))  return(0);
	zwerg=zwerg*16+readxdigit;
	}
    return(zwerg);
}

void puts(const char *txt) { printf("%s\n", txt); }

short comment(unsigned long guru)
{   /* ergibt 0, falls der Guru nicht direkt bekannt ist und 1 falls doch. */
    /* dadurch ist es möglich, das Flag AT_DeadEnd bei Bedarf zu invertieren */
    /* im Übrigen wird - soweit bekannt - ein Kommentartext ausgegeben */
    char *txt=NULL;
    short trial=0;

retry:
    switch(guru)
	{
	case AN_ExcptVect: txt="ExcptVect: OBSOLETE: 68000 exception vector checksum"; break;
	case AN_BaseChkSum: txt="BaseChkSum: OBSOLETE: ExecBase checksum bad"; break;
	case AN_LibChkSum: txt="LibChkSum: Library checksum failure"; break;
	case 0x81000004: txt="LibMem: most OBSOLETE, no more documented"; break;
	case AN_MemCorrupt: txt="MemCorrupt: Corrupted memory list detected by Exec.FreeMem()"; break;
	case AN_IntrMem: txt="IntrMem: No memory for interrupt servers"; break;
	case AN_InitAPtr: txt="InitAPtr: OBSOLETE: InitStruct() of an APTR source"; break;
	case AN_SemCorrupt: txt="SemCorrupt: A semaphore is in an illegal state at Exec.RemSemaphore()"; break;
	case AN_FreeTwice: txt="FreeTwice: Exec.FreeMem() on already freed memory"; break;
	case AN_BogusExcpt: txt="BogusExcpt: OBSOLETE: Illegal 68k-exception"; break;
	case AN_IOUsedTwice: txt="IOUsedTwice: Attempt to reuse open IORequest"; break;
	case AN_MemoryInsane: txt="MemoryInsane: Sanity check of memory list during Exec.AvailMem(MEMF_LARGEST)\n\tfailed"; break;
	case AN_IOAfterClose: txt="IOAfterClose: IO attempted on a closed IORequest"; break;
	case AN_StackProbe: txt="StackProbe: Stack-over-/under-flow"; break;
	case AN_BadFreeAddr: txt="BadFreeAddr: Memory header not located [usually caused by an invalid address\n\tpassed to Exec.FreeMem]"; break;
	case AN_GfxNoMem: txt="GfxNoMem: graphics.library runs out of memory"; break;
	case AN_GfxNoMemMspc: txt="GfxNoMemMspc: graphics.library runs out of memory trying to allocate\n\tMonitorSpec"; break;
	case 0x82010002: txt="CopInstr: OBSOLETE: lack of memory for copperlist"; break;
	case 0x82000003: case 0x82010003: txt="CopListOver: OBSOLETE: overflow of copperlist"; break;
	case 0x82000004: case 0x82010004: txt="CopIListOver: OBSOLETE: error on copperlist ???"; break;
	case 0x82010005: txt="CopListHead: OBSOLETE: lack of memory for copperlist-head"; break;
	case AN_LongFrame: txt="LongFrame: no memory for long-frame-copperlist"; break;
	case AN_ShortFrame: txt="ShortFrame: no memory for short-frame-copperlist"; break;
	case 0x82010008: txt="FloodFill: OBSOLETE: no memory for Graphics.FloodFill()"; break;
	case AN_TextTmpRas: txt="TextTmpRas: no memory for TmpRas within Graphics.Text()"; break;
	case AN_BltBitMap: txt="BltBitMap: no memory for Graphics.BltBitMap()"; break;
	case AN_RegionMemory: txt="RegionMemory: no memory for Regions"; break;
	case AN_MakeVPort: txt="MakeVPort: no memory to create a ViewPort"; break;
	case AN_GfxNewError: txt="GfxNewError: undocumented"; break;
	case AN_GfxFreeError: txt="GfxFreeError: undocumented"; break;
	case AN_GfxNoLCM: txt="GfxNoLCM: no emergency-memory available"; break;
	case AN_ObsoleteFont: txt="ObsoleteFont: unsupported font description used"; break;
	case AN_LayersNoMem: txt="LayersNoMem: layers.library runs out of memory"; break;
	case AN_GadgetType: txt="GadgetType: unknown gadget type"; break;
	case AN_BadGadget: txt="BadGadget: unknown gadget type"; break;
	case AN_CreatePort: txt="CreatePort: no memory to create a ???-port"; break;
	case AN_ItemAlloc: txt="ItemAlloc: no memory to allocate a(n) [Menu-?] item"; break;
	case AN_SubAlloc: txt="SubAlloc: no memory to allocate a [Menu-] sub [-item?]"; break;
	case AN_PlaneAlloc: txt="PlaneAlloc: no memory to allocate [a Bitplane ?]"; break;
	case AN_ItemBoxTop: txt="ItemBoxTop: item box top < 0"; break;
	case AN_OpenScreen: txt="OpenScreen: no memory to alloc in OpenScreen()"; break;
	case AN_OpenScrnRast: txt="OpenOpenScrnRast: no memory to alloc as raster [or RastPort ?] in OpenScreen()"; break;
	case AN_SysScrnType: txt="SysScrnType: unknown screen type in OpenScreen()"; break;
	case AN_AddSWGadget: txt="AddSWGadget: no memory to add SW[?]-Gadgets"; break;
	case AN_OpenWindow: txt="OpenWindow: no memory to alloc in OpenWindow()"; break;
	case AN_BadState: txt="BadState: \"Bad State Return entering Intuition\" [?]"; break;
	case AN_BadMessage: txt="BadMessage: bad message recieved by IDCMP"; break;
	case AN_WeirdEcho: txt="WeirdEcho: \"Weird echo causing incomprehension\" [?]"; break;
	case AN_NoConsole: txt="NoConsole: intuition couldn't open the console.device"; break;
	case AN_StartMem: txt="StartMem: dos.library gets no memory at startup"; break;
	case AN_EndTask: txt="EndTask: \"EndTask didn't\" [?]"; break;
	case AN_QPktFail: txt="QPktFail: \"QPktFail failure\" [?]"; break;
	case AN_AsyncPkt: txt="AsyncPkt: unexpected packet recieved"; break;
	case AN_FreeVec: txt="FreeVec: FreeVec failed [?]"; break;
	case AN_DiskBlkSeq: txt="DiskBlkSeq: Disk block sequence error"; break;
	case AN_BitMap: txt="BitMap: Bitmap corrupt"; break;
	case AN_KeyFree: txt="KeyFree: Key already free"; break;
	case AN_BadChkSum: txt="BadChkSum: Invalid checksum"; break;
	case AN_DiskError: txt="DiskError: Disk Error - ?"; break;
	case AN_KeyRange: txt="KeyRange: Key out of range"; break;
	case AN_BadOverlay: txt="BadOverlay: Bad overlay"; break;
	case AN_BadInitFunc: txt="BadInitFunc: invalid init packer for cli/shell"; break;
	case AN_FileReclosed: txt="FileReclosed: a filehandle was closed more than once"; break;
	case AN_BadSegList: txt="BadSegList: overlay in library seglists are not allowed"; break;
	case AN_BadExpansionFree: txt="BadExpansionFree: freeed free region"; break;
	case AN_NoWindow: txt="NoWindow: console.device can't open the initial window"; break;
	case AN_TDCalibSeek: txt="TDCalibSeek: \"calibrate: seek error\" [?]"; break;
	case AN_TDDelay: txt="TDDelay: delay: error on timer wait"; break;
	case AN_TMBadReq: txt="TMBadReq: bad request"; break;
	case AN_TMBadSupply: txt="TMBadSupply: power-supply: no 50/60Hz ticks"; break;
	case AN_DRHasDisk: txt="DRHasDisk: disk.resource.GetUnit(): ? already has disk"; break;
	case AN_DRIntNoAct: txt="DRIntNoAct: interrupt: no active unit"; break;
	case AN_BootError: txt="BootError: boot code returned an error"; break;
	case AN_NoFonts: txt="NoFonts of workbench [undocumented]"; break;
	case AN_WBBadStartupMsg1: txt="WBBadStartupMsg1 of workbench [undocumented]"; break;
	case AN_WBBadStartupMsg2: txt="WBBadStartupMsg2 of workbench [undocumented]"; break;
	case AN_WBBadIOMsg: txt="WBBadIOMsg of workbench [undocumented]"; break;
	case AN_WBInitPotionAllocDrawer: txt="WBInitPotionAllocDrawer of workbench [undocumented]"; break;
	case AN_WBCreateWBMenusCreateMenus1: txt="WBCreateWBMenusCreateMenus1 of workbench [undocumented]"; break;
	case AN_WBCreateWBMenusCreateMenus2: txt="WBCreateWBMenusCreateMenus2 of workbench [undocumented]"; break;
	case AN_WBLayoutWBMenusLayoutMenus: txt="WBLayoutWBMenusLayoutMenus of workbench [undocumented]"; break;
	case AN_WBAddToolMenuItem: txt="WBAddToolMenuItem of workbench [undocumented]"; break;
	case AN_WBReLayoutToolMenu: txt="WBReLayoutToolMenu of workbench [undocumented]"; break;
	case AN_WBinitTimer: txt="WBInitTimer of workbench [undocumented]"; break;
	case AN_WBInitLayerDemon: txt="WBInitLayerDemon of workbench [undocumented]"; break;
	case AN_WBinitWbGels: txt="WBInitWbGels of workbench [undocumented]"; break;
	case AN_WBInitScreenAndWindows1: txt="WBInitScreenAndWindows1 of workbench [undocumented]"; break;
	case AN_WBInitScreenAndWindows2: txt="WBInitScreenAndWindows2 of workbench [undocumented]"; break;
	case AN_WBInitScreenAndWindows3: txt="WBInitScreenAndWindows3 of workbench [undocumented]"; break;
	case AN_WBMAlloc: txt="WBMAlloc of workbench [undocumented]"; break;
	}
    if(txt)
	{
	if(trial)   printf("AT_DeadEnd ^ ");
	puts(txt);
	return(1);
	}
    else{
	if(++trial>1)   return(0);
	guru ^= AT_DeadEnd;
	goto retry;
	}
}

void main(int argc, char *argv[])
{
    unsigned long guru;

    for(int cnt=1; cnt<argc; ++cnt)
	{
	if((guru=HexVal(argv[cnt]))==0)
	    {
	    if((strcmp(argv[cnt], "00000000")!=0) &&
	       (strcmp(argv[cnt],"#00000000")!=0) )
		{
		printf("Invalid Guru Code %s\n", argv[cnt]);
		continue;
		}
	    }
	printf("Guru #%08lx:\n", guru);
	if((guru&~0x80000000)<256)
	  {
	  guru &= ~0x80000000;
	  if(guru>1)    printf("CPU-exception #");
	  switch(guru)
	    {
	    case 0x00:	puts("\
unknown guru [looks like CPU-exception #0, which doesn't exist but its vector\n\
\tcontains the SSP-value for a reset]");    break;
	    case 0x01:	puts("\
unknown guru [looks like CPU-exception #1, which doesn't exist but its vector\n\
\tcontains the PC-value for a reset]");     break;
	    case 0x02:	puts("2: bus-error [e.g. invalid address]"); break;
	    case 0x03:	puts("3: (long-)word access on odd address"); break;
	    case 0x04:	puts("4: opcode 'ILLEGAL'"); break;
	    case 0x05:	puts("5: division by zero"); break;
	    case 0x06:	puts("6: caused by opcode 'CHK'"); break;
	    case 0x07:	puts("7: caused by opcode 'TRAPV'"); break;
	    case 0x08:	puts("8: privilege violation\n\
\t[privileged opcode was used in UserMode]"); break;
	    case 0x09:	puts("9: trace-bit was set [do we have an impotent debugger ?]"); break;
	    case 0x0a:	puts("A: opcode $Axxx"); break;
	    case 0x0b:	puts("B: opcode $Fxxx"); break;
	    case 0x0e:	puts("E: faulty stack-frame [not 68000]"); break;
	    case 0x0f:	puts("F: uninitialized irq-vector: irq caused by perepherial,\n\
\tbut no vector given"); break;
	    case 0x18:	puts("18: spurious irq: irq & bus-error at the same time"); break;
	    case 0x19:	case 0x1a:  case 0x1b:	case 0x1c:
	    case 0x1d:	case 0x1e:  case 0x1f:
			printf("%02lx: should be an irq of level #%ld !\n",
			       guru, guru-24);
			break;
	    case 0x20:	case 0x21:  case 0x22: case 0x23:
	    case 0x24:	case 0x25:  case 0x26: case 0x27:
	    case 0x28:	case 0x29:  case 0x2a: case 0x2b:
	    case 0x2c:	case 0x2d:  case 0x2e: case 0x2f:
			printf("%02lx: opcode 'TRAP #%ld'\n",
			       guru, guru-32);
			break;
	    case 0x40:	case 0x41:  case 0x42:	case 0x43:
	    case 0x44:	case 0x45:  case 0x46:	case 0x47:
	    case 0x48:	case 0x49:  case 0x4a:	case 0x4b:
	    case 0x4c:	case 0x4d:  case 0x4e:	case 0x4f:
	    case 0x50:	case 0x51:  case 0x52:	case 0x53:
	    case 0x54:	case 0x55:  case 0x56:	case 0x57:
	    case 0x58:	case 0x59:  case 0x5a:	case 0x5b:
	    case 0x5c:	case 0x5d:  case 0x5e:	case 0x5f:
	    case 0x60:	case 0x61:  case 0x62:	case 0x63:
	    case 0x64:	case 0x65:  case 0x66:	case 0x67:
	    case 0x68:	case 0x69:  case 0x6a:	case 0x6b:
	    case 0x6c:	case 0x6d:  case 0x6e:	case 0x6f:
	    case 0x70:	case 0x71:  case 0x72:	case 0x73:
	    case 0x74:	case 0x75:  case 0x76:	case 0x77:
	    case 0x78:	case 0x79:  case 0x7a:	case 0x7b:
	    case 0x7c:	case 0x7d:  case 0x7e:	case 0x7f:
	    case 0x80:	case 0x81:  case 0x82:	case 0x83:
	    case 0x84:	case 0x85:  case 0x86:	case 0x87:
	    case 0x88:	case 0x89:  case 0x8a:	case 0x8b:
	    case 0x8c:	case 0x8d:  case 0x8e:	case 0x8f:
	    case 0x90:	case 0x91:  case 0x92:	case 0x93:
	    case 0x94:	case 0x95:  case 0x96:	case 0x97:
	    case 0x98:	case 0x99:  case 0x9a:	case 0x9b:
	    case 0x9c:	case 0x9d:  case 0x9e:	case 0x9f:
	    case 0xa0:	case 0xa1:  case 0xa2:	case 0xa3:
	    case 0xa4:	case 0xa5:  case 0xa6:	case 0xa7:
	    case 0xa8:	case 0xa9:  case 0xaa:	case 0xab:
	    case 0xac:	case 0xad:  case 0xae:	case 0xaf:
	    case 0xb0:	case 0xb1:  case 0xb2:	case 0xb3:
	    case 0xb4:	case 0xb5:  case 0xb6:	case 0xb7:
	    case 0xb8:	case 0xb9:  case 0xba:	case 0xbb:
	    case 0xbc:	case 0xbd:  case 0xbe:	case 0xbf:
	    case 0xc0:	case 0xc1:  case 0xc2:	case 0xc3:
	    case 0xc4:	case 0xc5:  case 0xc6:	case 0xc7:
	    case 0xc8:	case 0xc9:  case 0xca:	case 0xcb:
	    case 0xcc:	case 0xcd:  case 0xce:	case 0xcf:
	    case 0xd0:	case 0xd1:  case 0xd2:	case 0xd3:
	    case 0xd4:	case 0xd5:  case 0xd6:	case 0xd7:
	    case 0xd8:	case 0xd9:  case 0xda:	case 0xdb:
	    case 0xdc:	case 0xdd:  case 0xde:	case 0xdf:
	    case 0xe0:	case 0xe1:  case 0xe2:	case 0xe3:
	    case 0xe4:	case 0xe5:  case 0xe6:	case 0xe7:
	    case 0xe8:	case 0xe9:  case 0xea:	case 0xeb:
	    case 0xec:	case 0xed:  case 0xee:	case 0xef:
	    case 0xf0:	case 0xf1:  case 0xf2:	case 0xf3:
	    case 0xf4:	case 0xf5:  case 0xf6:	case 0xf7:
	    case 0xf8:	case 0xf9:  case 0xfa:	case 0xfb:
	    case 0xfc:	case 0xfd:  case 0xfe:	case 0xff:
			printf("%02lx: should be an irq-vector\n",
			       guru);
			break;
	    case 0x0c:	case 0x0d:
	    case 0x10:	case 0x11:  case 0x12:	case 0x13:
	    case 0x14:	case 0x15:  case 0x16:	case 0x17:
	    case 0x30:	case 0x31:  case 0x32:	case 0x33:
	    case 0x34:	case 0x35:  case 0x36:	case 0x37:
	    case 0x38:	case 0x39:  case 0x3a:	case 0x3b:
	    case 0x3c:	case 0x3d:  case 0x3e:	case 0x3f:
	    printf("%02lx: unknown CPU-exception\n", guru); break;
	    }
	  }
	else{ /* Library-caused Gurus: */
	    if(!comment(guru))
		{
		puts("unknown guru");
		if(guru & AT_DeadEnd)   printf("DeadEnd-Alert");
		else			printf("Recovery-Alert");
		switch(guru & 0x7f000000)
		    {
		    case 0: printf(", might be CPU-caused"); break;
		    case AN_ExecLib: printf(" within exec.library"); break;
		    case AN_GraphicsLib: printf(" within graphics.library"); break;
		    case AN_LayersLib: printf(" within layers.library"); break;
		    case AN_Intuition: printf(" within intuition.library"); break;
		    case AN_MathLib: printf(" within a maths library"); break;
		    case AN_DOSLib: printf(" within dos.library"); break;
		    case AN_RAMLib: printf(" within ramlib.library"); break;
		    case AN_IconLib: printf(" within icon.library"); break;
		    case AN_ExpansionLib: printf(" within expansion.library"); break;
		    case AN_DiskfontLib: printf(" within diskfont.library"); break;
		    case AN_AudioDev: printf(" within audio.device"); break;
		    case AN_ConsoleDev: printf(" within console.device"); break;
		    case AN_GamePortDev: printf(" within gameport.device"); break;
		    case AN_KeyboardDev: printf(" within keyboard.device"); break;
		    case AN_TrackDiskDev: printf(" within trackdisk.device"); break;
		    case AN_TimerDev: printf(" within timer.device"); break;
		    case AN_CIARsrc: printf(" within cia?.resource"); break;
		    case AN_DiskRsrc: printf(" within disk.resource"); break;
		    case AN_MiscRsrc: printf(" within misc.resource"); break;
		    case AN_BootStrap: printf(" within bootstrap"); break;
		    case AN_Workbench: printf(" within workbench"); break;
		    case AN_DiskCopy: printf(" within DiskCopy"); break;
		    case AN_GadTools: printf(" within gadtools.library"); break;
		    case AN_UtilityLib: printf(" within utility.library"); break;
		    case AN_Unknown: printf(", application-specific"); break;
		    }
		  switch(guru & 0x00ff0000)
		    {
		    case AG_NoMemory: printf(" about lack of memory"); break;
		    case AG_MakeLib: printf(" about making a library"); break;
		    case AG_OpenLib: printf(" about opening a library"); break;
		    case AG_OpenDev: printf(" about opening a device"); break;
		    case AG_OpenRes: printf(" about opening a resource"); break;
		    case AG_IOError: printf(" about an IO-error"); break;
		    case AG_NoSignal: printf(" about allocating a signal"); break;
		    case AG_BadParm: printf(" about bad parameters"); break;
		    case AG_CloseLib: printf(" about closing a library [probably too many closes or a mismatched close]"); break;
		    case AG_CloseDev: printf(" about closing a device [probably too many closes or a mismatched close]"); break;
		    case AG_ProcCreate: printf(" about a failed process creation"); break;
		    }
		  switch(guru & 0x0000ffff)
		    {
		    case AO_ExecLib: printf(" on exec.library"); break;
		    case AO_GraphicsLib: printf(" on graphics.library"); break;
		    case AO_LayersLib: printf(" on layers.library"); break;
		    case AO_Intuition: printf(" on intuition.library"); break;
		    case AO_MathLib: printf(" on a mathematical library"); break;
		    case AO_DOSLib: printf(" on dos.library"); break;
		    case AO_RAMLib: printf(" on ramlib.library"); break;
		    case AO_IconLib: printf(" on icon.library"); break;
		    case AO_ExpansionLib: printf(" on expansion.library"); break;
		    case AO_DiskfontLib: printf(" on diskfont.library"); break;
		    case AO_UtilityLib: printf(" on utility.library"); break;
		    case AO_AudioDev: printf(" on audio.device"); break;
		    case AO_ConsoleDev: printf(" on console.device"); break;
		    case AO_GamePortDev: printf(" on gameport.device"); break;
		    case AO_KeyboardDev: printf(" on keyboard.device"); break;
		    case AO_TrackDiskDev: printf(" on trackdisk.device"); break;
		    case AO_TimerDev: printf(" on timer.device"); break;
		    case AO_CIARsrc: printf(" on cia?.resource"); break;
		    case AO_DiskRsrc: printf(" on disk.resource"); break;
		    case AO_MiscRsrc: printf(" on misc.resource"); break;
		    case AO_BootStrap: printf(" on bootstrap"); break;
		    case AO_Workbench: printf(" on Workbench"); break;
		    case AO_DiskCopy: printf(" on DiskCopy"); break;
		    case AO_GadTools: printf(" on gadtools.library"); break;
		    case AO_Unknown: printf(" on something else"); break;
		    }
		printf("\n");
		}
	    }
	}
}
