Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!overload!dillon From: dillon@overload.Berkeley.CA.US (Matthew Dillon) Newsgroups: comp.sys.amiga.programmer Subject: Re: ResEdit for the Amiga? It's not impossible... and it's desirable Message-ID: Date: 18 Jun 91 19:51:58 GMT References: <14224@dog.ee.lbl.gov> <1991Jun17.083311.7113@grasp1.univ-lyon1.fr> Distribution: comp.sys.amiga.programmer Organization: Not an Organization Lines: 192 In article <1991Jun17.083311.7113@grasp1.univ-lyon1.fr> stephane@grasp1.univ-lyon1.fr (Stephane Guillard) writes: >In article <14224@dog.ee.lbl.gov> jnmoyne@lbl.gov (Jean-Noel MOYNE) writes: >>[about a ResEdit for the Amiga] >> >>Well, creating such a thing for the Amiga doesn't look as impossible as >>that. Think about the WB 2.0, and the way it handles windows, screens and >>gadgets: tags. >>... The whole problem is that of convenience and extensibility. Unless the system can be made convenient to the programmer and also be extensible and easily modifiable, nobody will use it. I've had my go at resources, both attempts didn't work too well, but here's a new idea: (1) embedded program resources are a great idea but not easily editable. Take, for example, an IntuiText structure. While you might declare such a structure: struct IntuiText RES_IText = { ..... &MyFont ..... }; The compiler & linker will not necessarily generate output that is referencable by a resource editor, even if symbols are left intact and a special naming convention is used for the variable. Example: SAS and DICE residentable code. The &MyFont is not known at link time, only at run time. To make such resources editable would require the programmer to not write residentable code! This is obviously not a desirable description (2) solution: Give the program special arguments to enter a 'resource editing' mode. Being run-time, all declared structures will be resolved to real pointers. The disadvantage is that now it us up to the program to edit the resources. (3) solution: Here is where a library comes in. In the program declare a structural array of editable resources, like this: struct Resource { char *res_Type; /* type of resource (name) */ union { void *Ptr; /* pointer to resource */ long Offset; } u; long res_Size; /* size of res. in bytes */ long res_Flags; /* user, system, whatever */ } ResAry[] = { #define res_Ptr u.Ptr #define res_Offset u.Offset Since resources are edited run time, this array will have been resolved even if the program is residentable. In this manner, a single library call can be made to 'edit the resources'. A resource such as an IntuiText structure may contain a pointer to a TextAttr structure which itself may or may not be a resource, depending on whether it is in the Resource array or not. The library, given the above array, can determine exactly what resources are editable and what sub-resources (resources in resources) are editable. The final problem is that of modifying the executable itself after resource editing is complete. There are two possibilities related to this: (1) Do not modify the executable. Instead, the library writes out the resource structure(s) pointed to by ResAry[] to a separate file. The program when run normally must then call a library routine with ResAry as an argument to 'load' the resources. Since it is not necessary for the library to modify any pointers, the library need only load those portions of the 'resources' that are not pointers. For example, given an IntuiText resource the library does not bother to store the pointer to the TextFont in the file (or if it does, it ignores it on load) because while the TextFont itself might be modified, the structure remains at the same location run-time. (2) Modify the executable. Difficult at best, even with symbols, because the library would have to convert run-time pointers into hunk offsets etc etc etc... a mess. (4) program example: /* * defaults */ char TextBuf[128] = { "This is a test" }; char TxName[64] = { "topaz.font" }; struct TextAttr Ta = { TxName, 9, 0, 0 }; struct IntuiText MyText = { -1, -1, JAM2, 0, 0, &MyFont, TextBuf, NULL }; struct Resource ResAry[] = { "TextAttr", &Ta, sizeof(TextAttr), 0, "MyText", &MyText, sizeof(MyText), 0, "CStr", TextBuf, sizeof(TextBuf), 0, "CStr, TxName, sizeof(TxName), 0 NULL }; main(ac, av) short ac; char *av[]; { /* * note that the LoadResources() call never modifies any * *pointers*, only the non-pointer portion of a resource. * This means that LoadResources() needs no special knowledge * of the memory model. */ LoadResources(ResAry, "S:MyResFile"); if (ac == 1 && stricmp(av[1], "RESEDIT") == 0) { EditResources(ResAry, "S:MyResFile"); exit(0); } ... run program ... UnLoadResources(ResAry, "S:MyResFile"); } The *Resources() calls are library calls. This system is quite simple, but has extensibility in its capabilities. (1) Defaults are embedded in the executable. (2) The executable is never modified. (3) the resource editor call is smart enough to arrange editing in a hierarchal fashion, i.e. it knows that the TextBuf resource is a sub-resource of the MyText resource because it sees the pointers in the array entry and in the MyText structure are the same. (4) The program can have support for multiple users each with their own resource configuration, or one user with several configurations for different purposes. DEVELOPERS NEED TO Agree on the format of resource structures. For the most part they can actually follow standard amiga structures such as the NewWindow structure, and even include BitMap's and the like and even constructs that are determined run-time by the program since all resource editing is done run-time. Some things are obvious... CStr is a pointer to a standard string buffer whos maximum size is given in the resource structure. What is not so obvious is, say, how to represent an IFF file. static-sized IFF is easy, you simply have a resource type of "IFF" and a pointer to a large buffer. But this presents limits on the IFF file -- it cannot be larger than the buffer. I propose that we agree on extensibile typesi or flags, such as have a RESF_DYNAMIC flag which indicates to the resource library that the res_Ptr is actually a pointer to a pointer which the library should fill in with an AllocMem() enough to hold a dynamically sized resource. I also propose a RESF_FOFFSET flag which indicates to the resource that the res_Offset field be loaded with the offset of the resource in the resource file instead of actually loading the resource. Finally, I propose a RESF_ARRAY to go along with RESF_DYNAMIC which specifies that not only is the resource to be dynamically loaded, but also that the user be able to specify several of the same type that are loaded as an array of that type of resource. For example, for an editor the user could specify an array of NewWindow structures defining where additional editor windows are to be openned. In this case res_Ptr points to an array of NewWindow structures instead of just one, with the res_Size field reflecting the sizee of the array in bytes, i.e. sizeof(NewWindow) * NumberOfUserDefinedWindows Sorry for the long-winded message, but what do people think? -Matt -- Matthew Dillon dillon@Overload.Berkeley.CA.US 891 Regal Rd. uunet.uu.net!overload!dillon Berkeley, Ca. 94708 USA