added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / arch / .unmaintained / amiga / boot / main.c
blobc64ea819794e91526bf71b9bfaf9d9d2944248a6
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Amiga bootloader -- main file
6 Lang: C
7 */
9 /*
10 * Note: This whole thing may seem a bit kludgy. It is. It was originally
11 * designed to load only one module. It has been extended to read a config
12 * file and to load multiple modules. It needs some polishing.
15 #include <exec/types.h>
16 #include <exec/execbase.h>
17 #include <exec/nodes.h>
18 #include <exec/resident.h>
19 #include <exec/memory.h>
20 #include <dos/dos.h>
21 #include <dos/rdargs.h>
23 #include <proto/dos.h>
24 #include <proto/exec.h>
25 #include <proto/alib.h>
27 #include "boot.h"
28 #include "ils.h"
29 #include "config.h"
30 #include "version.h"
32 #define D(x) if (debug) x
33 #define bug Printf
35 struct SpecialResident
37 struct Resident res;
38 ULONG magiccookie;
39 UBYTE *statusarray;
40 UWORD maxslot;
43 #define SR_COOKIE 0x4afa4afb
45 struct Module *LoadModule(char *);
46 void FreeModules(struct ModuleList *);
47 BOOL BuildTagPtrs(struct ModuleList *);
48 ULONG *AllocMoveCookie(ULONG *, ULONG);
49 struct MemList *BuildMemList(struct ilsMemList *, ULONG *, ULONG);
50 void StuffTags(struct MemList *, ULONG *, ULONG);
51 void *FindResMod(struct ilsMemList *);
52 void PrintTagPtrs(void);
53 void FreeRDArgsAll(struct RDArgs *);
54 void PatchModule(struct Module *, struct List *);
56 char *version = "$VER: " BANNER " " VERSIONSTRING " " DATE;
58 ULONG stack = 16384;
59 ULONG memtype;
60 BOOL debug, quiet;
61 ULONG ils_table[3];
62 struct ilsMemList ils_mem;
64 char cmlargs[] = "CONFIGFILE,CHIP/S,FAST/S,KICK/S,LOCAL/S,CLEAR/S,CO=CLEARONLY/S,RESET/S,DEBUG/S,SIM=SIMULATE/S,FORCE/S,QUIET/S";
66 char usage[] =
67 "Configfile : config file to use, default is \"arosboot.config\"\n"
68 "Chip : force modules to chip mem\n"
69 "Fast : force modules to fast mem\n"
70 "Kick : force modules to kick mem\n"
71 "Local : force modules to local mem\n"
72 "Clear : clear reset vectors before installing new modules\n"
73 "Clearonly : only clear reset vectors and exit\n"
74 "Reset : reset after installing new modules\n"
75 "Debug : output debugging information\n"
76 "Simulate : Simulate loading, do not actually install modules\n"
77 "Force : Force loading if modules were already loaded\n"
78 "Quiet : Be quiet [debug mode will override this]\n"
79 "\n"
80 "Order of precedence of memory: kick->local->fast->chip\n"
81 "\n"
82 "Enter options";
84 #define CML_CONFIGFILE 0
85 #define CML_CHIP 1
86 #define CML_FAST 2
87 #define CML_KICK 3
88 #define CML_LOCAL 4
89 #define CML_CLEAR 5
90 #define CML_CLEARONLY 6
91 #define CML_RESET 7
92 #define CML_DEBUG 8
93 #define CML_SIMULATE 9
94 #define CML_FORCE 10
95 #define CML_QUIET 11
96 #define CML_END 12
98 LONG cmdvec[CML_END];
101 rescookie:
102 dc.w $4afc
103 dc.l rescookie-*
104 dc.l endskip-*
105 dc.b 0 ; flags
106 dc.b 41 ; version
107 dc.b 0 ; NT_UNKNOWN
108 dc.b -120 ; priority
109 dc.l name-*
110 dc.l id-*
111 dc.l init-*
112 name: dc.b 'arosboot.cookie',0
113 id: dc.b 'arosboot.cookie 41.1 (22.3.1997)',0
114 even
115 init: moveq.l #0,d0
117 endskip:
119 Relocate this by adding a field's contents to its address.
120 rt_MatchTag also contains a (negative) offset, but unsigned pointers
121 won't handle it correctly. Just set it to the base address.
123 ULONG rescookie[] = {
124 0x4AFCFFFF, 0xFFFE0000, 0x004A0029, 0x00880000,
125 0x000C0000, 0x00180000, 0x00366172, 0x6F73626F,
126 0x6F742E63, 0x6F6F6B69, 0x65006172, 0x6F73626F,
127 0x6F742E63, 0x6F6F6B69, 0x65203431, 0x2E312028,
128 0x32322E33, 0x2E313939, 0x37290000, 0x70004E75
131 int main(int argc, char **argv)
133 struct BootConfig *config;
134 struct ModNode *modnode;
135 struct Module *module;
136 STRPTR modname;
137 struct RDArgs *rdargs;
138 int returnvalue = RETURN_OK;
139 BPTR oldcurrentdir, programdir;
140 struct ModuleList ModuleList;
141 BOOL reset, simulate, force;
143 debug = quiet = reset = simulate = force = FALSE;
145 if(SysBase->LibNode.lib_Version < 37)
147 PutStr("This program is for AmigaOS 2.04 (V37) and higher.\n\n");
148 exit(RETURN_FAIL);
151 if(!(SysBase->AttnFlags & AFF_68020))
153 PutStr("The current AROS for 68k Amigas requires a 68020 or higher processor.\n\n");
154 exit(RETURN_FAIL);
158 * The memory type MEMF_KICK has been added in V39 exec. Fall back to
159 * MEMF_CHIP if we are on an earlier version.
161 if(SysBase->LibNode.lib_Version < 39)
163 memtype = MEMF_CHIP;
164 } else
166 memtype = MEMF_KICK;
169 if( (rdargs = AllocDosObject(DOS_RDARGS, NULL)))
171 /* set default config file name */
172 cmdvec[CML_CONFIGFILE] = (LONG)"arosboot.config";
174 rdargs->RDA_ExtHelp = usage; /* FIX: why doesn't this work? */
175 rdargs->RDA_Buffer = NULL;
176 rdargs->RDA_BufSiz= 0;
178 if(!(ReadArgs(cmlargs, cmdvec, rdargs)))
180 PrintFault(IoErr(), "arosboot");
181 FreeDosObject(DOS_RDARGS, rdargs);
182 exit(RETURN_FAIL);
186 else
188 PrintFault(ERROR_NO_FREE_STORE, "arosboot");
189 exit(RETURN_FAIL);
192 if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
194 FreeRDArgsAll(rdargs);
195 PutStr("***Break\n");
196 exit(RETURN_WARN);
199 if(cmdvec[CML_FORCE]) force = TRUE;
200 if(cmdvec[CML_RESET]) reset = TRUE;
201 if(cmdvec[CML_QUIET]) quiet = TRUE;
202 if(cmdvec[CML_DEBUG])
204 debug = TRUE;
205 quiet = FALSE;
207 if(cmdvec[CML_SIMULATE]) simulate = TRUE;
209 if(!quiet) PutStr("\n" BANNER " " VERSIONSTRING "\n\n");
211 /* Order of precedence: kick->local->fast->chip */
212 if (cmdvec[CML_KICK]) memtype = MEMF_KICK;
213 else if(cmdvec[CML_LOCAL]) memtype = MEMF_LOCAL;
214 else if(cmdvec[CML_FAST]) memtype = MEMF_FAST;
215 else if(cmdvec[CML_CHIP]) memtype = MEMF_CHIP;
217 if(cmdvec[CML_CLEARONLY])
219 if(!quiet) PutStr("Clearing reset vectors.\n");
220 SysBase->KickMemPtr = NULL;
221 SysBase->KickTagPtr = NULL;
222 SysBase->KickCheckSum = NULL;
223 FreeRDArgsAll(rdargs);
224 if(reset)
226 if(!quiet) PutStr("Resetting this machine in about 5 seconds...\n");
227 Delay(250);
228 ColdReboot(); /* never returns */
230 exit(RETURN_OK);
232 else if(cmdvec[CML_CLEAR]) /* no need to clear again if already done */
234 if(!quiet) PutStr("Clearing reset vectors.\n");
235 SysBase->KickMemPtr = NULL;
236 SysBase->KickTagPtr = NULL;
237 SysBase->KickCheckSum = NULL;
240 D(bug("Debug mode\n"));
242 if(!quiet) PrintTagPtrs();
245 * InternalLoadSeg use.
247 ils_table[0] = (ULONG)&ils_read;
248 ils_table[1] = (ULONG)&ils_alloc;
249 ils_table[2] = (ULONG)&ils_free;
251 NewList((struct List *)&ils_mem);
253 if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
255 FreeRDArgsAll(rdargs);
256 PutStr("***Break\n");
257 exit(RETURN_WARN);
260 if( (FindResident("arosboot.cookie")))
262 if(!force)
264 if(!quiet)
266 PutStr("AROS modules already loaded."); /* A smart compiler merges strings */
267 PutStr(" Exiting.\n");
269 FreeRDArgsAll(rdargs);
270 exit(RETURN_OK);
272 else
274 if(!quiet)
276 PutStr("AROS modules already loaded.");
277 PutStr(" Overriding.\n");
283 * First check if we actually have a program dir (aka PROGDIR:). If we
284 * don't have one, we're in the resident list (hey, you shouldn't put
285 * us there!), and we stay right in the dir we were started from.
287 if( (programdir = GetProgramDir()))
289 oldcurrentdir = CurrentDir(programdir);
293 * Construct a List of filenames to process.
295 if(!(config = ReadConfig((char *)cmdvec[CML_CONFIGFILE])))
297 /* ReadConfig() prints it's own error string, just exit. */
298 FreeRDArgsAll(rdargs);
300 /* If we switched dirs, switch back. */
301 if(oldcurrentdir) CurrentDir(oldcurrentdir);
302 exit(RETURN_FAIL);
305 /* We no longer need them */
306 FreeRDArgsAll(rdargs);
308 if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
310 FreeConfig(config);
311 if(oldcurrentdir) CurrentDir(oldcurrentdir);
312 PutStr("***Break\n");
313 exit(RETURN_WARN);
316 if(!quiet) PutStr("Loading modules ...\n");
318 NewList((struct List *)&ModuleList);
319 ModuleList.ml_Num = 0;
322 * Traverse this list and load the modules into memory.
324 for(modnode = (struct ModNode *)config->bc_Modules.lh_Head;
325 modnode->mn_Node.ln_Succ;
326 modnode = (struct ModNode *)modnode->mn_Node.ln_Succ)
328 modname = modnode->mn_Node.ln_Name;
329 if( (module = LoadModule(modnode->mn_Node.ln_Name)) )
331 PatchModule(module, &modnode->mn_FuncList);
332 AddTail((struct List *)&ModuleList, (struct Node *)module);
333 ModuleList.ml_Num++;
334 if(!quiet) Printf("\t%s\n", (ULONG)module->m_Resident->rt_IdString);
336 else
338 modnode = NULL; /* on normal exit, this points to the last module processed */
339 break;
344 * I duplicated a CTRL-C handler a few times, instead of making it a
345 * subroutine. Else all local variables used here would have to be passed
346 * to that subroutine. I should put common cleanup code into an atexit()
347 * handler. Oh well, maybe next time.
349 if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
351 FreeConfig(config);
352 if(oldcurrentdir) CurrentDir(oldcurrentdir);
353 PutStr("***Break\n");
354 exit(RETURN_WARN);
357 if(modnode)
359 if(!simulate)
362 * If we're here, all modules we're loaded normally. Build all
363 * structures needed for the KickTag/Mem fields, and put them there.
365 if( (BuildTagPtrs(&ModuleList)) )
367 if(!quiet & !reset) PutStr("\nAll modules loaded successfully, reset to activate.\n\n");
368 else if(!quiet & reset) PutStr("\nAll modules loaded successfully.\n\n");
370 else
372 if(!quiet) PutStr("\nError building KickTagPtrs!\n");
373 FreeModules(&ModuleList);
374 returnvalue = RETURN_FAIL;
377 else
379 if(!quiet) PutStr("Simulation complete, unloading modules.\n");
380 FreeModules(&ModuleList);
381 returnvalue = RETURN_OK;
384 else
386 if(!quiet) Printf("Error loading \"%s\"\n", (ULONG)modname);
387 FreeModules(&ModuleList);
388 returnvalue = RETURN_FAIL;
391 FreeConfig(config);
393 if(reset)
395 if(!quiet) PutStr("Resetting this machine in about 5 seconds...\n");
396 Delay(250);
397 ColdReboot(); /* never returns */
400 /* If we switched dirs, switch back. */
401 if(oldcurrentdir) CurrentDir(oldcurrentdir);
403 exit(returnvalue);
406 struct Module *LoadModule(char *filename)
408 BPTR fh, seglist;
409 struct Module *mod;
411 D(bug("LoadModule(\"%s\")\n", (ULONG)filename));
412 if(!(fh = Open(filename, MODE_OLDFILE)))
414 if(!quiet) PrintFault(IoErr(), filename);
415 return 0;
418 if(!(mod = AllocVec(sizeof(struct Module), MEMF_CLEAR)))
420 if(!quiet) PutStr("Could not allocate memory for module.\n");
421 Close(fh);
422 return 0;
424 D(bug(" module = $%08lx (size %ld)\n", (ULONG)mod, sizeof(struct Module)));
426 if( (seglist = InternalLoadSeg(fh, NULL, &ils_table[0], &stack)) )
428 mod->m_SegList = seglist;
429 mod->m_Resident = FindResMod(&ils_mem);
430 if(debug)
432 if( ((struct SpecialResident *)mod->m_Resident)->magiccookie == SR_COOKIE)
433 Printf(" Module is of patchable type\n");
436 Close(fh);
437 D(bug(" SegList = $%08lx\n", BADDR(mod->m_SegList)));
438 D(bug(" Resident = $%08lx\n", (ULONG)mod->m_Resident));
441 * If this module contains a Resident structure, return it.
443 if ( (mod->m_Resident))
445 return mod;
448 return 0;
451 void FreeModules(struct ModuleList *modlist)
453 struct Module *mod, *next;
455 D(bug("FreeModules($%08lx)\n", (ULONG)modlist));
457 for(mod = (struct Module *)modlist->ml_List.mlh_Head; mod->m_Node.mln_Succ; mod = next)
459 /* get next node here, because after the Remove() it is undefined */
460 next = (struct Module *)mod->m_Node.mln_Succ;
461 Remove((struct Node *)mod);
462 InternalUnLoadSeg(mod->m_SegList, &ils_free);
463 FreeVec(mod);
467 BOOL BuildTagPtrs(struct ModuleList *modlist)
469 struct MemList *memlist;
470 ULONG *modarray;
471 ULONG i, nummods;
472 struct Module *mod;
473 ULONG *cookieptr;
474 struct ilsMemNode *cookienode;
476 D(bug("BuildTagPtrs...\n"));
479 * Allocate memory for our KickTagPtr table:
480 * number of modules loaded +2 (cookie and table terminator)
482 D(bug("Allocating KickTagPtr memory (size %ld)\n", (modlist->ml_Num+2)*sizeof(ULONG)));
483 if( (modarray = AllocVec((modlist->ml_Num+2)*sizeof(ULONG),
484 memtype|MEMF_CLEAR|MEMF_REVERSE)) )
486 D(bug(" ok\n"));
488 * Fill the KickTagPtr array with pointers to our Resident modules.
490 for(i = 0, mod = (struct Module *)modlist->ml_List.mlh_Head;
491 mod->m_Node.mln_Succ;
492 mod = (struct Module *)mod->m_Node.mln_Succ, i++)
494 D(bug(" modarray[%ld] = $%lx (module)\n", i, (ULONG)mod->m_Resident));
495 modarray[i] = (ULONG)mod->m_Resident;
497 /* i will be incremented one last time before exiting */
499 if( (cookieptr = AllocMoveCookie(rescookie, sizeof(rescookie))))
502 * Add the cookie module.
504 D(bug(" modarray[%ld] = $%lx (cookie)\n", i, (ULONG)cookieptr));
505 modarray[i] = (ULONG)cookieptr;
508 * Terminate the module array.
510 D(bug(" modarray[%ld] = $%lx (termination)\n", i+1, (ULONG)NULL));
511 modarray[i+1] = NULL;
514 * Add the cookie's memory address + size on the memlist.
516 if( (cookienode = AllocMem(sizeof(struct ilsMemNode), MEMF_CLEAR)) )
518 cookienode->imn_Addr = cookieptr;
519 cookienode->imn_Size = sizeof(rescookie);
520 AddHead((struct List *)&ils_mem, (struct Node *)cookienode);
521 ils_mem.iml_Num++;
522 ils_mem.iml_NewNum++;
525 * Cache number of modules, since it will be modified in
526 * BuildMemList. +1 because of the cookie.
528 nummods = modlist->ml_Num + 1;
531 * build a memlist to be put in KickMemPtr
533 if( (memlist = BuildMemList(&ils_mem, modarray,
534 (modlist->ml_Num+2)*sizeof(ULONG) )) )
536 StuffTags(memlist, modarray, nummods);
537 return TRUE;
541 /* If we get here, something went wrong. Free stuff. */
542 FreeMem(cookieptr, sizeof(rescookie));
544 FreeVec(modarray);
546 return FALSE;
549 ULONG *AllocMoveCookie(ULONG *cookie, ULONG size)
551 struct Resident *res;
553 D(bug("AllocMoveCookie()\n"));
555 if( (res = AllocMem(size, memtype|MEMF_REVERSE)))
557 D(bug(" Moving cookie\n"));
558 /* Relocate the cookie. */
559 CopyMem(cookie, (APTR)res, size);
561 D(bug(" Relocating cookie pointers\n"));
562 /* Relocate pointers in cookie. */
563 res->rt_MatchTag = res;
564 res->rt_EndSkip += (ULONG)&res->rt_EndSkip;
565 res->rt_Name += (ULONG)&res->rt_Name;
566 res->rt_IdString += (ULONG)&res->rt_IdString;
567 res->rt_Init += (ULONG)&res->rt_Init;
569 D(bug(" cookie @ $%lx, name @ $%lx, idstring @ $%lx\n",
570 (ULONG)res, (ULONG)res->rt_Name, (ULONG)res->rt_IdString));
572 if(!quiet) Printf("\t%s\n", (ULONG)res->rt_IdString);
574 return (ULONG *)res;
577 return 0;
580 struct MemList *BuildMemList(struct ilsMemList *prelist,
581 ULONG * modlist,
582 ULONG modlistsize)
584 struct MemList *memlist;
585 struct MemEntry *me;
586 struct ilsMemNode *node;
587 UWORD numentries;
588 ULONG size;
590 D(bug("BuildMemList()\n"));
592 * Calculate needed number of extra MemEntry fields that need to be
593 * appended to the end of our MemList structure. This number+1 (there
594 * already is one MemEntry in the MemList) is what we'll be putting in
595 * memlist->ml_NumEntries later.
597 numentries = prelist->iml_Num + 1;
598 D(bug(" number of mem areas = %ld\n", numentries+1));
600 size = ( sizeof(struct MemList) + (sizeof(struct MemEntry) * numentries) );
603 * Allocate memory from the top of the memory list, to keep fragmentation
604 * down, and hopefully to keep all our applications in one place.
606 if(!(memlist = AllocVec(size, memtype|MEMF_CLEAR|MEMF_REVERSE))) return(NULL);
609 * We have the memory. Assure that this MemList is allocated during a
610 * reset, and put it in the first MemEntry field.
612 memlist->ml_ME[0].me_Addr = memlist;
613 memlist->ml_ME[0].me_Length = size;
616 * Indicate that this node is part of a KickMem MemList, and indicate how
617 * many MemEntries there are.
619 memlist->ml_Node.ln_Type = NT_KICKMEM;
620 memlist->ml_NumEntries = numentries+1;
623 * Put the modlist in the next MemEntry.
625 me = (struct MemEntry *)( ((ULONG)memlist) + sizeof(struct MemList) );
626 me->me_Addr = modlist;
627 me->me_Length = modlistsize;
630 * Increase to the next MemEntry.
632 me = (struct MemEntry *)( ((ULONG)me) + sizeof(struct MemEntry) );
635 * Now put the data from our prelist in the remaining MemEntry fields,
636 * removing the nodes in our prelist and freeing them in the process.
638 while(prelist->iml_Num)
641 * pop a node off the list
643 node = (struct ilsMemNode *)RemHead((struct List *)prelist);
645 me->me_Addr = node->imn_Addr;
646 me->me_Length = node->imn_Size;
648 FreeMem(node, sizeof(struct ilsMemNode));
651 * Point to the next MemEntry, decrease our counter.
653 me = (struct MemEntry *)(((ULONG)me) + sizeof(struct MemEntry));
654 prelist->iml_Num--;
657 return memlist;
660 void StuffTags(struct MemList *memlist, ULONG *modlist, ULONG nummods)
662 D(bug("StuffTags(memlist $%08lx modlist $%08lx nummods %ld)\n",
663 (ULONG)memlist, (ULONG)modlist, nummods));
665 Forbid();
667 if(SysBase->KickCheckSum != (APTR)SumKickData())
669 /* Vectors had incorrect checksum. Just clear them now. */
670 D(bug("Vectors had incorrect checksum. Clearing before loading.\n"));
671 SysBase->KickTagPtr = SysBase->KickMemPtr = SysBase->KickCheckSum = NULL;
674 if(SysBase->KickMemPtr)
677 * Prepend to an existing chain of MemLists.
679 D(bug("Prepending to existing memlist (old ptr = $%lx)\n", (ULONG)SysBase->KickMemPtr));
680 memlist->ml_Node.ln_Succ = SysBase->KickMemPtr;
682 SysBase->KickMemPtr = memlist;
684 if(SysBase->KickTagPtr)
687 * Prepend to an existing chain of module lists.
689 D(bug("Prepending to existing tagptr (old ptr = $%lx)\n", (ULONG)SysBase->KickTagPtr));
690 modlist[nummods] = (ULONG)SysBase->KickTagPtr | 0x80000000;
692 SysBase->KickTagPtr = modlist;
695 * And checksum the KickPtrs. KickCheckSum is defined wrong in the include
696 * file exec/execbase.h. It is defined as APTR, but really is a ULONG.
698 SysBase->KickCheckSum = (APTR)SumKickData();
701 * Flush caches.
703 CacheClearU();
705 Permit();
708 void *FindResMod(struct ilsMemList *list)
710 struct ilsMemNode *node;
711 UWORD *ptr;
712 ULONG num, counter;
714 D(bug("Finding Resident Module..."));
717 * Search all memory blocks for the Resident struct. Only new nodes
718 * will be searched.
720 for(node = (struct ilsMemNode *)ils_mem.iml_List.mlh_Head, num = ils_mem.iml_NewNum;
721 node->imn_Node.mln_Succ || num;
722 node = (struct ilsMemNode *)node->imn_Node.mln_Succ, num--)
725 * In each block: skip to the magic word, if present.
726 * Searching by word: divide by 2
728 counter = node->imn_Size/2;
730 for(ptr = node->imn_Addr; counter; ptr++, counter--)
732 if(RTC_MATCHWORD == *ptr)
735 * Reset the counter, so that next time only new nodes will
736 * be searched.
738 ils_mem.iml_NewNum = 0;
740 D(bug(" at $%08lx\n", (ULONG)ptr));
741 return((void *)ptr);
746 D(bug(" not found\n"));
747 return 0;
750 void PrintTagPtrs(void)
752 if(SumKickData() == (ULONG)SysBase->KickCheckSum)
754 if(SysBase->KickTagPtr)
756 ULONG *list;
758 PutStr("Modules already in use:\n");
760 list = SysBase->KickTagPtr;
762 while(*list)
764 Printf("\t$%08lx", *list);
765 Printf("\t%s\n", (ULONG)((struct Resident *)*list)->rt_IdString);
767 list++;
768 if(*list & 0x80000000) list = (ULONG *)(*list & 0x7fffffff);
772 else
774 /* Don't print message if all vectors are NULL */
775 if(SysBase->KickMemPtr || SysBase->KickTagPtr || SysBase->KickCheckSum)
776 Printf("Vectors have incorrect checksum.\n");
780 void FreeRDArgsAll(struct RDArgs *rdargs)
782 FreeArgs(rdargs);
783 FreeDosObject(DOS_RDARGS, rdargs);
786 /* Turn functions on/off in module according to the function slots in funclist */
787 void PatchModule(struct Module *module, struct List *funclist)
789 struct FuncNode *funcnode;
790 UBYTE *array;
791 UWORD maxslot;
793 if( ((struct SpecialResident *)module->m_Resident)->magiccookie == SR_COOKIE)
795 /* ok, cookie found, let's patch this module */
797 array = ((struct SpecialResident *)module->m_Resident)->statusarray;
798 maxslot = ((struct SpecialResident *)module->m_Resident)->maxslot;
800 for(funcnode = (struct FuncNode *)funclist->lh_Head;
801 funcnode->fn_Node.ln_Succ;
802 funcnode = (struct FuncNode *)funcnode->fn_Node.ln_Succ)
804 /* walk function list, (un)setting entries in array */
806 /* Check if in range of library, do not touch first 4 vectors */
807 if(funcnode->fn_Slot <= maxslot && funcnode->fn_Slot > 4)
809 D(bug("Setting function %ld (slot %ld) %s\n",
810 funcnode->fn_Slot * -6,
811 funcnode->fn_Slot,
812 funcnode->fn_Status ? (ULONG)"on" : (ULONG)"off"
815 array[funcnode->fn_Slot] = funcnode->fn_Status ? 1 : 0;
817 else
819 if(!quiet)
820 Printf("Function %ld (slot %ld) outside scope of module (max %ld, %ld). Ignored.\n",
821 funcnode->fn_Slot * -6,
822 funcnode->fn_Slot,
823 maxslot * -6,
824 maxslot
830 return;
833 /* main.c */