Update of /cvsroot/ro-oslib/OSLib/!OsLib/Tools/support/doc In directory sc8-pr-cvs1:/tmp/cvs-serv28678/!OsLib/Tools/support/doc Added Files: Tag: unix-build callback lookup m realloc resource riscos trace Log Message: Unix Build --- NEW FILE: callback --- callback.c ---------- History ------- 26th October 1992 J R C Started The |callback_| module provides a dynamically extensible multi-way, multi-level switch facility. It was initially coded as an experiment, to see if the resulting, somewhat unconventional, data structure was useful. Use in the two entirely different contexts of the |riscos_| module and the internal working of the DrawFile module are indications that it is a useful tool. The module implements a data type, called a "callback list," which allows functions to be associated with integer lists. Each callback list is entirely unrelated to any others there may be: it is possible for a cluent of |callback_| to use different callback lists for unrelated purposes. The use of integer lists as the unit of association is pragmatic, based on what seemed like the likely set of uses for the module. The callback list --- -------- ---- In abstract terms, if |Fn| is the type of a callback function (i e, a function pointer type), and |SH|, |DH| are "handle" types, the the type of a callback list is implemented as Type Callback == Leval; Type Level == List [Fn × SH] × List [Int × Level]; Type List == Opt [Level] × DH; (where List [T] == Opt [T × List [T]] and Opt [T] is either a T or NULL) This is implemented in C via Type Function == List [Fn × SH]; Type Entry == List [Int × Level]; In other words, a callback list is a list of (Fn, SH) pairs and a list of (int, Level) pairs. The module has been implemented in such a way as to use no RISC O S-specific features: in particular, it does not use |os_error *| values to return errors. The only error that can be returned by any of the functions described here is "not enough memory;" this is flagged by returning a NULL pointer, in the way that |malloc| does. The entry points are |callback_new| to create an empty callback list and |callback_delete| to dispose of one; and others to insert, delete and make callbacks. |Callback_register| is used to add a new function into the list. Its prototype is callback_l callback_register (callback_l l, callback_fn *fn, void *sh, int limit, ...) The client provides a callback list to contain the new callback, the function pointer to call back to, a handle to call it with, and an integer list (the length of the list being given in |limit|). Extra levels are created in the callback list as neccessary, and a callback record (of type Fn × SH) is inserted. Callbacks may be deleted from the list with |callback_deregister. Its prototype is void callback_deregister (callback_l l, void *sh, int limit, ...) It deletes ALL callbacks that have the given handle, and whose integer list starts with the |limit| integers provided. Callbacks with longer lists that start in the same way as the one given are also deleted. (This means that all callbacks on a given window can be deleted easily, for example.) To make the callbacks, the client must call |callback|. It has the prototype void callback (callback_l l, void *dh, int limit, ...) All callbacks which have lists starting with the |limit| integers provided will be called, util one returss |TRUE|, to indicate that it has dealt with the callback successfully. So the only communication between a called-back function and the rest of the client programme is in the handle |sh| registered in the callback list, at the time the function was registered; the handle |dh| provided when the callback is made; the boolean value returned by the function. So the protype of a callback must be |callback_fn|, defined in callback.h as typedef bool callback_fn (void *, void *); The two handles provided are again based on pragmatic evidence. The |riscos_| module passes the Wimp_Block structure to the callback: this allows functions called back from the main function |riscos| to get at all the information in the block returned from Wimp_Poll (or Wimp_PollIdle). The application is free to pass its own information to the function as well, using the other handle. This will usually be a structure of window-specific data. ViewDraw uses this technique successfully. On the other hand, the DrawData module has no data to be registered with the functions - after all, when the module is initialised, it has no way of finding out which files it will be asked to render - so all the functions in |render_| or |declare_| are passed a null pointer as one of the handles. The other handle is used to hold the per-diagram state, as documented with those modules. --- NEW FILE: lookup --- lookup.c -------- History ------- 26th October 1992 J R C Started This module provides an extensible lookup table. The programmer interface allows any number of entries to be added to a lookup table without needing memory management to be done by the calling programme. There are functions |lookup_new| to create a lookup table; |lookup_delete| to dispose of an unwanted one; |lookup_insert| to add an entry to a table; and |lookup| to do the actual searching; |lookup_enumerate| to retrieve all the tokens currently in the lookup table. The interface allows for a hashing system to be used, providing that one can be designed that allows for an extensible table: I have experimented with this, but don't have such in a bug-free form at the moment. The module stores only a |void *| value for each entry in the table. This would normally be a pointer (suitably cast) to some application-specific data associated with the name. It is the applications responsibility to ensure that if this pointer changes (because of flex movement, for example), the value in the table is updated to refer to the new location of the data. See the |resource| module for how this can be done in two different ways. It relies on the fact that a |lookup_insert| of a value with a token already known to the |lookup_| module will replace the previous value. The implementation of the lookup table is as an array of (char *, void*) pairs, of a length which is a power of 2. When a table is filled, it is |realloc|'d to the next power of 2. Pointers to tokens are held in the first word of each array element, and the data pointer in the other half. This allows only linear searching in the table; many improvements are possible here, but have not been attempted. However, the interface specified here is general enough to provide the facilities that are required without being specific enough to prohibit the various abvious enhancements. The obvious ones would be either hold the array sorted by token, cutting access time to O (log N), where N is the number of entries; or hash the token values, cutting access time to O (1). Unfortunately, one of |lookup_|'s clients makes use of a fact not intended by its interface: this is that a call to |lookup_enumerate| returns the tokens in the order they were inserted into the table. If this property were to be maintained by either of these implementations, extra work would be needed internally. (I do have a hashing implementation of the module, but it is not bug-free.) --- NEW FILE: m --- m.c --- This module provides a more secure environment for programmes that need to check their usage of memory allocation. It must be used consistently throughout a whole programme. To use it, each call to one of the memory management functions must be replaced by a call to the macro provided by the module, as follows: malloc (size) m_ALLOC (size) calloc (count, size) m_CALLOC (count, size) free (ptr) m_FREE (ptr, size) realloc (ptr, size) m_REALLOC (ptr, old_size, size) and "m.h" must be included. When you do this, if you have -DTRACE=0 (or nothing) on the command line, all the macros map straight back to the calls on the left; but when you do -DTRACE=1, they turn into calls to the checking functions defined in m.c. These have the following effects. Whenever a block of memory is allocated, it is filled with a junk byte (0xA5), so that code that relies on the contents being anything in particular will fail. Also, 4 extra bytes are allocated on the end, and these are filled with a different junk byte (0xA7). Just before memory is freed, it is filled with a third junk byte (0xA9), and the extra bytes are checked to see that they still contain the junk written in at the beginning. Also, each block has a header invisibly preceding it that links all the blocks together, in order of allocation. Each block also contains the file name and line number at which it was allocated, and a guard word (0xACCE55ED) at the very beginning to protect against overwriting at the beginning of the block. The integrity of the system is checked on every call to any of the functions. Two of the calls have extra arguments: the call m_FREE (ptr, size) allows the client to specify the size it believes the block to have been allocated with: the module checks this. If the client doesn't know, the call m_FREE (ptr, 0) disables the check. Similary, m_REALLOC (ptr, old_size, new_size) checks the size of the block before resizing it, unless old_size == 0. The call m_SUMMARY () traces all this information to the current trace destination. If the compiling was done with -DTRACE=0, it does nothing. --- NEW FILE: realloc --- realloc.c --------- Just a portable realloc with no bugs. It's called REALLOC, though. --- NEW FILE: resource --- resource.c ---------- History ------- 26th October 1992 J R C Started This module is not used by DrawFile; however, it is usd by the test programme ViewDraw. It provides functions to allow different parts (modules or shared libraries) of an application to load resources into shared structures, and access them in linear time. It uses the |lookup_| module to to this: |resource_| is the WIMP-specific part of resource loading only. The structure provided by the |lookup_| module is a tale that supplies a mapping between tokens (supplied as strings) and data pointers. This facility is used in slightly different ways by the different resource types. Messages files -------- ----- |Resource_messages| is used by an application to load a Messages file into a lookup table. On successful completion, all the tokens in the file will be in the lookup table and a buffer of messages will have been allocated. Multiple messages files may be loaded into the same lookup table. All will be subsequently deleted by a call to |resource_messages_delete|. The function works by reading the messages file into a buffer, using MessageTrans to enumerate the tokens, and storing pointers to them in the lookup table. Subsequent calls to |resource_messages| cause this block to be |realloc|'d; the call to |resource_messages_delete| frees it. Access to the messages loaded so far is therefore provided by |lookup|: this call is given a lookup table and a token, and it returns the pointer stored in the table. In this case, it is a string pointer to the message, and so should be cast to |char *| before use. Sprites files ------- ----- |Resource_sprites| is similar, but works for sprites instead. All the sprites are loaded into a sprite area which is extended using |realloc| as necessary. Multiple sprites files may be loaded into the same lookup table, and subsequently deleted by |resource_sprites_delete|. The sprites are combined using OS_SpriteOp 'merge sprite file', so duplicates are deleted. On return from |lookup|, a pointer should therefore be cast to |osspriteop_header *|. Templates files --------- ----- |Resource_templates| is alos similar, but it works on Templates files via Wimp_{Open,Load,Close}Template. Again, multiple templates files may be loaded into the same lookup table, and subsequently deleted by |resource_templates_delete|. However, in this case, each template is loaded into a separate |malloc| buffer: all are freed on deletion. Returns from |lookup| should be cast to |wimp_window *|. Future development ------ ----------- Obviously, this is all tied in with the concept of the Resource Editor. I think it would be a good idea to define a Menus resource file type along the lines of the Templates one, and define |resource_menus| etc for that file type. This would simply be a binary file containing the |wimp_menu| structure needed by Wimp_CreateMenu. File formats of each type can refer to entries in files of the other types: for example, a template in a Templates file can refer to a message in the Messages file, or to a sprite in the Sprites file; a menu in the Menus file could refer to a template in the templates file (or vice versa). In general, the dependency graph is not acyclic between the different sorts of file (though it must be at the token level). This implies that this extra looking up is done after all the files have been opened (by |resource_<something>|): this would be a new function |resource_initialise| called after all resource_<...>| calls have been made. It could even be deferred until the token is actually looked up, but that would mean that a common function (|lookup|) could no longer be used for all file formats. This would allow (e g) the message tokens in an application resources files to refer not only to text defined in the applications own Messages file, but also to text defined by modules that the application was going to use. This means that the resources exported by a module become part of its programming interface; this seems entirely reasonable. It implies that an application has to make some kind of initial call to a module that it will use: this may be undesirable. (Maybe this whole module is a Bad Thing, since it encourages data from all kinds of places to appear in the same table: it might be better for an application to maintain its own resources only, and to let each of the modules/shared libraries it uses take care of their own resources as they wish. This wouod lose a lot of the flexibility described above, however.) --- NEW FILE: riscos --- riscos.c -------- History ------- 26th October 1992 J R C Started This module uses the |callback_| module to provide a callback list and a useful set of callbacks specific to Wimp_Poll. It also provides various of the usual functions without which no application is complete and some non-function external symbols. These are used to provide access to the module in the following way: |riscos_callback| is a callback list, initially empty, which is examined every time Wimp_Poll returns to get the application to do the work appropriate for that event. If an application wants only to install an icon bar icon, and then wait for a QUIT message from the WIMP, it would look like this (ignoring all error checking): static wimp_message_list Messages = ...; static bool Quit (void *null, void *block) { riscos_quit = TRUE; return TRUE; } main (void) { riscos_initialise ("Small", &Messages, NULL, &myself); callback_register (riscos_callback, &Quit, NULL, 2, wimp_MESSAGE, message_QUIT); callback_register (riscos_callback, &Quit, NULL, 2, wimp_MESSAGE_RECORDED, message_QUIT); ... put icon on the icon bar ... riscos (); riscos_terminate (); } The function |riscos| returns only when the extern |riscos_quit| is set. |Riscos_initialise| simply creates the empty callback list |riscos_callback| and remembers the programme name for use by |riscos_complain|. By adding and removing callbacks, any combination of events can be handled by any module. The convention of the |callback_| module is that any callback (e g, |Quit| above) that return |TRUE| is considered to have "handled" the event: no other calls back are made. In addition to regiatering and deregistering callbacks, an application may need access to the following variables. (Access to these should probably be centralised further to allow usage counts to be maintained for mask bits, etc): |riscos_mask| is the mask used by Wimp_Poll or Wimp_PollIdle (type |int|); |riscos_timeout| is the timeout to be handed to Wimp_PollIdle, if used; |riscos_quit| is to be set to TRUE to close down the application; |riscos_polling_idle|, if set to |TRUE|, causes Wimp_PollIdle to be used instead of Wimp_Poll; |riscos_pollword| is set to the word to use for event PollwordNonZero (if used). The module also exports other functions,as alluded to above. These are: |riscos_error_lookup| which takes an error token with a variable number of arguments and formats it into an error block; |riscos__assert|, usually used via the macro |riscos_assert|, which provides an assertion facility that uses Wimp_ReportError; |riscos_complain| to report an error. |riscos_terminate| to delete the callback list creted by |riscos_initialise|. So, the main function is |riscos|. It works by calling Wimp_Poll (or Wimp_PollIdle), and then calling |callback| with a certain list of integers appropriate to the event just returned to find out wht the user wants done with that event. The integers it uses are as follows: wimp_NULL_REASON_CODE, wimp_DRAG_BOX: event number only wimp_REDRAW_WINDOW_REQUEST: event number, window handle wimp_OPEN_WINDOW_REQUEST: event number, window handle wimp_CLOSE_WINDOW_REQUEST: event number, window handle, mouse buttons, shifting keys wimp_POINTER_LEAVING_WINDOW: event number, window handle wimp_POINTER_ENTERING_WINDOW: event number, window handle wimp_MOUSE_CLICK: event number, window handle, icon handle, mouse buttons, shifting keys wimp_KEY_PRESSED: event number, window handle, icon handle, character (this allows different handlers to be provided for different keys - e g, F1, F2 etc, while another handler takes everything else. wimp_MENU_SELECTION: event number, main menu entry number, submenu entry number, subsubmenu entry number, ... (as many as provided) wimp_SCROLL_REQUEST: event number, window handle, mouse buttons, shifting keys wimp_LOSE_CARET, wimp_GAIN_CARET: event number, window handle, icon handle wimp_POLLWORD_NON_ZERO: event number, pollword address wimp_MESSAGE, wimp_MESSAGE_RECORDED, wimp_MESSAGE_ACKNOWLEDGE: depends on the message type message_DATA_SAVE, message_DATA_SAVE_ACK, message_DATA_LOAD, message_DATA_LOAD_ACK, message_DATA_OPEN: event number, action code, window handle, icon handle, file type message_DEVICE_CLAIM, message_DEVICE_IN_USE: event number, action code, major device, minor device message_MENU_WARNING: event number, action code, main menu entry number, submenu entry number, subsubmenu entry number, ... (as many as provided) default: event number, action code default: callback (riscos_callback, &Block, 0); The list here seems to work well; it is possible that some of these sequences are not long enough. For example, the original version did not use the file type word on the callbacks for wimp_MESSAGE_DATA_LOAD etc; but by providing it, the user can register separate callbacks for different file types arriving on windows (without losing the ability to specify a default callback to be used when there is no more specific one). (ViewDraw does this, and so ignores non-drawfiles dropped onto its icon bar icon.) There are two cases here of using information that the WIMP does not actually return in the Wimp_Block structure. The mouse button state, although returned in the structure for a Wimp_MouseClick event, are not returned for Wimp_CloseWindowRequest or Wimp_ScrollRequest. Neverthless, they are useful in these cases as they allow the application to take different action depending on (e g) whether a window was closed with SELECT or ADJUST. In addition, the states of the shifting keys are returned for Wimp_CloseWindowRequest, Wimp_MouseClick and Wimp_ScrollRequest. These are read by calling OS_Byte 129 and disjoining the states together into a word of bits: bit 0 <=> SHIFT is down bit 1 <=> CTRL is down bit 2 <=> ALT is down (constants riscos_SHIFT, riscos_CTRL and riscos_ALT are defined with these values). This could also encourage more uniformity in the treatment of these keys. There are also two auxiliary functions: |Shifting_Keys| returns the states of the SHIFT, CTRL and ALT keys, while |Mouse_Buttons| returns the state of the mouse buttons. These are used when the information is not returned via Wimp_Poll: this fact is indicated in the list above by the phrases "shifting keys" and "mouse buttons". --- NEW FILE: trace --- trace.c ------- History ------- 26th October 1992 JRC Started 23rd May 1995 JRC Updated for multiple destinations This is a simplified version of various other tracing modules that have been written at various other times. It provides an initialisation function trace_initialise(), which takes the name of an operating system variable, and sets up tracing in a way that depends on its contents as follows: e128.5 Econet (AUN) station 128.5 f$.trace File $.trace i136.170.128.5 Internet address 136.170.128.5 n null: s Standard output (may be redirected on the programme command line by '> file') t Tube (HostFS or TML) v vdu: (may be redirected by '{ > file }') There is also a function trace_terminate() whcih closes the trace output, and should be called before the programme exits. There is only one tracing function, tracef(), which takes a |printf|-like argument line and sends it to the destination. This is implemtned as a macro. If the compiling is done with -DTRACE=1, everything workd as above. Otherwise (-DTRACE=0, or nothing), all the calls macro-expand to nothing. Because you can't write a macro with a variable number of arguments, you have to play a trick to get tracef() to work with more than one argument: you have to use a macro _, defined as #define _ , and use _ instead of , in the argument list: tracef ("Window handle 0x%X, icon handle %d\n" _ w _ i); |