/* Copyright 1997 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************/ /* File : Utils.c */ /* Purpose: Infrequently altered utilities */ /* Author : A.D.Hodgkinson */ /* History: 18-Oct-96: Created */ /*************************************************/ #include "setjmp.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdarg.h> #include <ctype.h> #include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */ #include "wimp.h" #include "wimplib.h" #include "event.h" #include "swis.h" #include "kernel.h" #include "toolbox.h" #include "event.h" #include "quit.h" #include "proginfo.h" #include "window.h" #include "gadgets.h" #include "ToolAction.h" /* NOT the proper Toolbox header, as this needed OSLib... */ #include "svcprint.h" #include "Global.h" #include "MiscDefs.h" #include "FromROSLib.h" #include "NestWimp.h" /* Debug build includes */ #ifdef TRACE /* Needed to check conversion to millipoints routines don't overflow */ #include <math.h> #endif /* Finally, Utils.h itself */ #include "Utils.h" /* Constant definitions */ #define MillipointsPerOSUnit 400 /* Locals */ const static char * base64_table="ABCDEFGHIJKLMNOP" "QRSTUVWXYZabcdef" "ghijklmnopqrstuv" "wxyz0123456789+/"; static int millipoints_per_os_unit_x = 400; static int millipoints_per_os_unit_y = 400; static int half_mppou_x = 200; static int half_mppou_y = 200; static int overflow_limit_x = 0x28f5c1; /* = (0x3fffffff / 400) rounded down for caution*/ static int overflow_limit_y = 0x28f5c1; /*************************************************/ /* lookup_token() */ /* */ /* Returns a pointer to an expanded message */ /* token, or '!' if there was an error. */ /* */ /* NB, due to various limitations of C, the */ /* lookup is done into a global fixed-size */ /* buffer. So if you pass multiple calls to this */ /* function in as parameters to something else, */ /* *it will fail* as each call points to the */ /* same buffer (which will only contain data */ /* from the last call). */ /* */ /* Parameters: Pointer to a message token; */ /* 1 to report an error if the token */ /* isn't found as well as returning */ /* a string of '!', else 0; */ /* An optional pointer to an */ /* argument to substitute into the */ /* looked up string, or NULL. */ /* */ /* Returns: Pointer to the full message text */ /* or '!' to signal an error; never */ /* a null pointer. */ /* */ /* Assumes: That the pointer to the message */ /* token is never NULL. */ /*************************************************/ char * lookup_token(char * s, int flag, char * arg) { _kernel_oserror * e; #ifdef TRACE if (tl & (1u<<0)) Printf("lookup_token: Lookup token '%s'\n",s); #endif if (strcmp(lasttokn, s)) { #ifdef TRACE if (tl & (1u<<0)) Printf("lookup_token: Proceeding\n"); #endif StrNCpy0(lasttokn, s); e = _swix(MessageTrans_Lookup, _INR(0,7), &meb, /* Pointer to control block */ s, /* String to look up */ tokens, /* Global buffer to take looked up string */ MaxMsgLen - 1, /* Size of the buffer */ arg, /* Parameter 0 */ 0, /* Parameter 1 */ 0, /* Parameter 2 */ 0); /* Parameter 3 */ if (e) { /* If the lookup fails, put '!' into the lookup buffer and if the */ /* flag passed into the function is 1, report the error too. */ #ifdef TRACE if (tl & (1u<<0)) Printf("lookup_token: Failed\n"); #endif *lasttokn = 0; strcpy(tokens, "!"); if (flag == 1) show_error_cont(e); } } #ifdef TRACE if (tl & (1u<<0)) Printf("lookup_token: Returning %s\n",tokens); #endif return (char *) &tokens; } /*************************************************/ /* lookup_choice() */ /* */ /* As lookup_token() above, but looks up the */ /* token in the Choices file, rather than the */ /* Messages file. */ /* */ /* Parameters: Pointer to a message token; */ /* 1 to report an error if the token */ /* isn't found as well as returning */ /* a string of '!', else 0; */ /* An optional pointer to an */ /* argument to substitute into the */ /* looked up string, or NULL. */ /* */ /* Returns: Pointer to the full message text */ /* or '!' to signal an error; never */ /* a null pointer. */ /* */ /* Assumes: That the pointer to the message */ /* token is never NULL. */ /*************************************************/ char * lookup_choice(char * s, int flag, char * arg) { _kernel_oserror * e; #ifdef TRACE if (tl & (1u<<0)) Printf("lookup_choice: Lookup token '%s'\n",s); #endif if (strcmp(lasttokn, s) != 0) { #ifdef TRACE if (tl & (1u<<0)) Printf("lookup_choice: Proceeding\n"); #endif StrNCpy0(lasttokn, s); e = _swix(MessageTrans_Lookup, _INR(0,7), chb, /* Pointer to control block */ s, /* String to look up */ tokens, /* Global buffer to take looked up string */ MaxMsgLen - 1, /* Size of the buffer */ arg, /* Parameter 0 */ 0, /* Parameter 1 */ 0, /* Parameter 2 */ 0); /* Parameter 3 */ if (e) { /* If the lookup fails, put '!' into the lookup buffer and if the */ /* flag passed into the function is 1, report the error too. */ #ifdef TRACE if (tl & (1u<<0)) Printf("lookup_choice: Failed\n"); #endif *lasttokn = 0; strcpy(tokens, "!"); if (flag == 1) show_error_cont(e); } } #ifdef TRACE if (tl & (1u<<0)) Printf("lookup_choice: Returning %s\n",tokens); #endif return (char *) &tokens; } /*************************************************/ /* show_error() */ /* */ /* Reports an error and exits with EXIT_FAILURE */ /* */ /* Parameters: */ /* a pointer to a _kernel_oserror structure */ /* */ /* Assumptions: */ /* none (so the pointer may be NULL) */ /*************************************************/ void show_error(_kernel_oserror *e) { if (e!=NULL) { _kernel_swi_regs r; char name[64]; char spri[13]; WimpSysInfo s; /* This call checks if errors can be reported in the Desktop, */ /* or if they need to go into a command window (useful for */ /* CLI routines for example) */ s.r0=0; s.r1=0; wimp_read_sys_info(3,&s); if (s.r0==0) fprintf(stderr,"%s\n",e->errmess); else { StrNCpy0(name,lookup_token("_TaskName:Browse",0,0)); /* Task name for 'Message from...' */ StrNCpy0(spri,lookup_token("_SpriName:!browse",0,0)); /* Sprite name to put in error box */ r.r[0] = (int) e; /* Pointer to error block */ r.r[1] = (2<<9)+(1<<8); /* Category 2 (warning) */ r.r[2] = (int) &name; /* Application name looked up above */ r.r[3] = (int) &spri; /* Sprite name looked up above */ r.r[4] = 1; /* Sprite block pointer (1 = WIMP) */ r.r[5] = (int) lookup_token("ErrorBtns:Quit",0,0); /* Custom button, 'Quit' */ _kernel_swi(Wimp_ReportError,&r,&r); } exit(EXIT_FAILURE); /* Exit after reporting the error */ } } /*************************************************/ /* show_error_cont() */ /* */ /* Reports an error but allows execution to then */ /* continue (rather than calling exit()) if the */ /* user clicks on 'Continue' rather than 'Quit'. */ /* This is accomplished by a longjmp back into */ /* wherever the setjmp was (e.g. in a poll loop) */ /* */ /* Parameters: */ /* a pointer to a _kernel_oserror structure */ /* */ /* Assumptions: */ /* none (so the pointer may be NULL) */ /*************************************************/ void show_error_cont(_kernel_oserror *e) { if (e!=NULL) { _kernel_swi_regs r; char name[64]; char spri[13]; WimpSysInfo s; #ifdef TRACE if (e->errnum == Utils_Error_Custom_Fatal) e->errnum = Utils_Error_Custom_Normal; #endif /* Force 'Quit' only for fatal errors */ if (e->errnum == Utils_Error_Custom_Fatal) show_error(e); /* This all works in much the same way as show_error() above. */ s.r0=0; s.r1=0; wimp_read_sys_info(3,&s); if (s.r0==0) fprintf(stderr,"%s\n",e->errmess); else { StrNCpy0(name,lookup_token("_TaskName:Browse",0,0)); StrNCpy0(spri,lookup_token("_SpriName:!browse",0,0)); r.r[0] = (int) e; r.r[1] = (2<<9)+(1<<8)+1; r.r[2] = (int) &name; r.r[3] = (int) &spri; r.r[4] = 1; /* Have a quit button if not running full screen and the */ /* error number isn't one defined as having a Continue */ /* button only. */ if ( e->errnum != Utils_Error_OS_Escape && e->errnum != Utils_Error_Custom_Message && !choices.full_screen ) r.r[5] = (int) lookup_token("ErrorBtns:Quit",0,0); else r.r[5] = 0; _kernel_swi(Wimp_ReportError,&r,&r); if (r.r[1] != 1) exit(EXIT_FAILURE); /* Exit if 'Quit' is selected */ else longjmp(env,1); /* Else jump back to poll loop */ } } } /*************************************************/ /* show_error_ret() */ /* */ /* Reports an error but allows execution to then */ /* continue (rather than calling exit()) if the */ /* user clicks on 'Continue' rather than 'Quit'. */ /* This is accomplished by simply returning. */ /* */ /* Parameters: */ /* a pointer to a _kernel_oserror structure */ /* */ /* Assumptions: */ /* none (so the pointer may be NULL) */ /*************************************************/ void show_error_ret(_kernel_oserror *e) { if (e!=NULL) { _kernel_swi_regs r; char name[64]; char spri[13]; WimpSysInfo s; #ifdef TRACE if (e->errnum == Utils_Error_Custom_Fatal) e->errnum = Utils_Error_Custom_Normal; #endif /* Force 'Quit' only for fatal errors */ if (e->errnum == Utils_Error_Custom_Fatal) show_error(e); /* This all works in much the same way as show_error() above. */ s.r0=0; s.r1=0; wimp_read_sys_info(3,&s); if (s.r0==0) fprintf(stderr,"%s\n",e->errmess); else { StrNCpy0(name,lookup_token("_TaskName:Browse",0,0)); StrNCpy0(spri,lookup_token("_SpriName:!browse",0,0)); r.r[0] = (int) e; r.r[1] = (2<<9)+(1<<8)+1; r.r[2] = (int) &name; r.r[3] = (int) &spri; r.r[4] = 1; /* Have a quit button if not running full screen and the */ /* error number isn't one defined as having a Continue */ /* button only. */ if ( e->errnum != Utils_Error_OS_Escape && e->errnum != Utils_Error_Custom_Message && !choices.full_screen ) r.r[5] = (int) lookup_token("ErrorBtns:Quit",0,0); else r.r[5] = 0; _kernel_swi(Wimp_ReportError,&r,&r); if (r.r[1] != 1) exit(EXIT_FAILURE); /* Exit if 'Quit' is selected, else return normally */ } } } /*************************************************/ /* report_toolbox_error() */ /* */ /* If the toolbox generates an error this funct- */ /* ion will be called to report it. Parameters */ /* are as standard for a Toolbox event handler. */ /*************************************************/ int report_toolbox_error(int eventcode,ToolboxEvent *event,IdBlock *idb,void *handle) { ChkError((_kernel_oserror *) &event->data); return 1; } /*************************************************/ /* make_no_fetch_memory_error() */ /* */ /* Typically called from Fetch.c, if a memory */ /* claim fails early in a fetch. Stores an */ /* appropriate error in the global error */ /* block 'erb'. */ /* */ /* Parameters: A numerical value to include in */ /* the message to help the */ /* programmer know where the error */ /* came from. */ /*************************************************/ void make_no_fetch_memory_error(int stage) { char num[20]; sprintf(num, "%d", stage); erb.errnum = 0; StrNCpy0(erb.errmess, lookup_token("NoMemFet:There is not enough free memory to perform this fetch (%0).", 0, num)); } /*************************************************/ /* make_no_cont_memory_error() */ /* */ /* Called if a memory claim fails during a fetch */ /* - stores an appropriate error in the global */ /* error block 'erb'. */ /* */ /* Parameters: A numerical value to include in */ /* the message to help the */ /* programmer know where the error */ /* came from. */ /*************************************************/ void make_no_cont_memory_error(int stage) { char num[20]; sprintf(num, "%d", stage); erb.errnum = 0; StrNCpy0(erb.errmess, lookup_token("NoMemRea:There is not enough free memory to continue the page fetch (%0).", 0, num)); } /*************************************************/ /* make_no_table_memory_error() */ /* */ /* Typically called from Tables.c, if a memory */ /* claim fails during table parsing routines. */ /* Stores an appropriate error in the global */ /* error block 'erb'. */ /* */ /* Parameters: A numerical value to include in */ /* the message to help the */ /* programmer know where the error */ /* came from. */ /*************************************************/ void make_no_table_memory_error(int stage) { char num[20]; sprintf(num, "%d", stage); erb.errnum = 0; StrNCpy0(erb.errmess, lookup_token("NoMemTab:There is not enough free memory to display this table (%0).", 0, num)); } /*************************************************/ /* make_no_memory_error() */ /* */ /* A general error generation routine for failed */ /* memory claims. Stores the error in the global */ /* error block 'erb'. */ /* */ /* Parameters: A numerical value to include in */ /* the message to help the */ /* programmer know where the error */ /* came from. */ /*************************************************/ void make_no_memory_error(int stage) { char num[20]; sprintf(num, "%d", stage); erb.errnum = 0; StrNCpy0(erb.errmess, lookup_token("NoMemGen:There is not enough free memory to continue this operation (%0).", 0, num)); } /*************************************************/ /* show_centred() */ /* */ /* Shows a Toolbox object centred to the screen, */ /* opened persistently where possible */ /* */ /* Parameters: */ /* An ID of any Toolbox object that will */ /* return it's Wimp window handle when */ /* Toolbox_ObjectMiscOp is called for it with */ /* a reason code of 0 - e.g. Window, DCS, */ /* Colour dialogue. */ /* */ /* Assumptions: */ /* that the ID is a valid one */ /*************************************************/ void show_centred(ObjectId o) { WimpGetWindowStateBlock w; ObjectId p; BBox b; _kernel_oserror *e; /* Get the Wimp window handle of the Toolbox object */ /* and get its size using Wimp_GetWindowState. This */ /* sounds simple, but there's a different function */ /* call to get the window handle for each object */ /* class. The best (but still poor) approach is to */ /* call the Toolbox_MiscOp SWI with a reason code */ /* of 0, which in most cases will mean 'return Wimp */ /* window handle'. If this is not the case for an */ /* object type, the Wimp call will then fault and */ /* this error condition can be used to default down */ /* to some coordinate value that seems appropriate. */ w.window_handle = 0; _swix(Toolbox_ObjectMiscOp, _INR(0,2) | _OUT(0), 0, o, 0, &w.window_handle); e = wimp_get_window_state(&w); if (e != NULL) { w.visible_area.xmin = 480; w.visible_area.ymin = 320; } else { w.visible_area.xmin = w.visible_area.xmax - w.visible_area.xmin; w.visible_area.ymin = w.visible_area.ymax - w.visible_area.ymin; } /* Find the screen x and y size in pixels and scale them */ /* to OS units using OS_ReadModeVariable calls; also work */ /* out the top left coordinates at the same time */ _swix(OS_ReadModeVariable,_INR(0,1) | _OUT(2),-1,11,&w.xscroll); _swix(OS_ReadModeVariable,_INR(0,1) | _OUT(2),-1,4,&w.yscroll); b.xmin = (((w.xscroll + 1) << w.yscroll) - w.visible_area.xmin) / 2; _swix(OS_ReadModeVariable,_INR(0,1) | _OUT(2),-1,12,&w.xscroll); _swix(OS_ReadModeVariable,_INR(0,1) | _OUT(2),-1,5,&w.yscroll); b.ymin = (((w.xscroll + 1) << w.yscroll) + w.visible_area.ymin) / 2; ChkError(toolbox_get_parent(0,o,&p,NULL)); ChkError(toolbox_show_object(0, /* Bit 0 set - Wimp_CreateMenu semantics; */ /* Bit 1 set - Wimp_CreateSubMenu semantics */ o, /* Object ID given to function */ 2, /* 0 - 'default position'; 1 - specify position in */ /* full; 2 - use top left corner coordinate pair */ &b.xmin, /* Top left corner coordinate pair */ p, /* Parent object ID */ -1)); /* Parent component ID (not interested in that) */ } /*************************************************/ /* set_corrected_extent() */ /* */ /* Sets the extent of a window, making sure that */ /* xmin = 0 and ymax = 0 (so ymin is negative, */ /* etc. etc.) - this means that topx = topy = 0. */ /* */ /* Parameters: f contains flags to pass to the */ /* Toolbox in the set extent call */ /* o is the object ID of the browser */ /* window to alter */ /* w is a pointer to a BBox with the */ /* extent coordinates in it */ /* Returns: Pointer to a _kernel_oserror or */ /* NULL, if there is no error */ /*************************************************/ _kernel_oserror * set_corrected_extent(unsigned int f, ObjectId o, BBox * w) { BBox t; t.xmin = 0; t.ymin = w->ymin - w->ymax; t.xmax = w->xmax - w->xmin; t.ymax = 0; return window_set_extent(f,o,&t); } /*************************************************/ /* find_behind() */ /* */ /* Returns the window handle of the first non- */ /* pane window in front of a given window. */ /* */ /* Parameters: int w is the handle of the window */ /* in question */ /* Returns: the handle of the first non-pane */ /* window in front of int w, or -1 */ /* if it is at the top of the stack. */ /*************************************************/ int find_behind(int w) { WimpGetWindowStateBlock s; s.window_handle = w; ChkError(wimp_get_window_state(&s)); if (s.behind != -1) { do { s.window_handle = s.behind; ChkError(wimp_get_window_state(&s)); } while(((s.flags & WimpWindow_Pane) != 0) && (s.behind != -1)); s.behind = s.window_handle; } return s.behind; } /*************************************************/ /* find_tool_sizes() */ /* */ /* Returns the title bar and scroll bar widths */ /* in OS units, including their outlines. */ /* */ /* Parameters: Pointer to an int, in which the */ /* title bar height is placed; */ /* Pointer to an int, in which the */ /* horizontal scroll bar bar height */ /* is placed; */ /* Pointer to an int, in which the */ /* vertical scroll bar width is */ /* placed. */ /* */ /* Assumes: Any of the pointers may be NULL. */ /*************************************************/ _kernel_oserror * find_tool_sizes(int * theight, int * hheight, int * vwidth) { _kernel_oserror * e; WimpGetWindowOutlineBlock outline; WimpGetWindowStateBlock s; ObjectId o; int th, hh, vw; /* Create an object with a title bar and both scroll bars */ e = toolbox_create_object(0, "ToolSizes", &o); if (e) return e; /* Open it behind the Pinboard */ s.visible_area.xmin = 256; s.visible_area.ymin = 256; s.visible_area.xmax = 512; s.visible_area.ymax = 512; s.xscroll = 0; s.yscroll = 0; s.behind = -3; e = toolbox_show_object(0, o, Toolbox_ShowObject_FullSpec, &s.visible_area, 0, -1); if (e) return e; /* Get the window state (for current visible area) and outline */ e = window_get_wimp_handle(0, o, &s.window_handle); if (e) return e; e = wimp_get_window_state(&s); if (e) return e; outline.window_handle = s.window_handle; e = wimp_get_window_outline(&outline); if (e) return e; /* Work out the various sizes */ th = outline.outline.ymax - s.visible_area.ymax; hh = s.visible_area.ymin - outline.outline.ymin; vw = outline.outline.xmax - s.visible_area.xmax; if (theight) *theight = th; if (hheight) *hheight = hh; if (vwidth) *vwidth = vw; /* Return via. deleting the temporary window */ return toolbox_delete_object(0, o); } /*************************************************/ /* register_null_claimant() */ /* */ /* Call if you want to claim null polls. */ /* */ /* Parameters: Exactly as for a Wimp event */ /* handler but without the object Id */ /*************************************************/ void register_null_claimant(int eventcode,WimpEventHandler * handler,browser_data * handle) { null_counter++; ChkError(event_register_wimp_handler(-1,eventcode,handler,handle)); #ifdef TRACE if (tl & (1u<<2)) Printf("register_null_claimant: Registered a claimant\n"); #endif if (null_counter == 1) { unsigned int mask; ChkError(event_get_mask(&mask)); mask = (mask & (~Wimp_Poll_NullMask)); ChkError(event_set_mask(mask)); #ifdef TRACE if (tl & (1u<<2)) Printf("register_null_claimant: Nulls claimed\n"); #endif } } /*************************************************/ /* deregister_null_claimant() */ /* */ /* Call if you want to release null polls. */ /* */ /* Parameters: Exactly as for a Wimp event */ /* handler but without the object Id */ /*************************************************/ void deregister_null_claimant(int eventcode,WimpEventHandler * handler,browser_data * handle) { null_counter--; ChkError(event_deregister_wimp_handler(-1,eventcode,handler,handle)); #ifdef TRACE if (tl & (1u<<2)) Printf("deregister_null_claimant: Deregistered a claimant\n"); if (null_counter < 0) { erb.errnum = Utils_Error_Custom_Normal; strcpy(erb.errmess, "deregister_null_claimant: Counter is negative; deregistrations have not matched registrations"); show_error_ret(&erb); } #endif if (null_counter < 0) null_counter = 0; if (!null_counter) { unsigned int mask; ChkError(event_get_mask(&mask)); mask = (mask | Wimp_Poll_NullMask); ChkError(event_set_mask(mask)); #ifdef TRACE if (tl & (1u<<2)) Printf("deregister_null_claimant: Nulls released\n"); #endif } } /*************************************************/ /* intersection() */ /* */ /* Takes two BBoxes and returns a pointer to a */ /* third which is the the intersection between */ /* the first two, or NULL, if they don't */ /* intersect. */ /* */ /* Parameters: Pointer to a BBox; */ /* Pointer to another BBox. */ /* */ /* Returns: Pointer to a BBox which is the */ /* intersection of the given two, */ /* or NULL, if they don't intersect. */ /*************************************************/ #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b)) BBox * intersection(BBox * a, BBox * b) { static BBox intersect; if (!a || !b) return NULL; if ((a->xmin >= b->xmax) || (a->xmax <= b->xmin) || (a->ymin >= b->ymax) || (a->ymax <= b->ymin)) return NULL; intersect.xmin = max(a->xmin,b->xmin); intersect.xmax = min(a->xmax,b->xmax); intersect.ymin = max(a->ymin,b->ymin); intersect.ymax = min(a->ymax,b->ymax); return &intersect; } /*************************************************/ /* set_graphics_intersection() */ /* */ /* Intended for redraw loop routines, this sets */ /* up a given graphics rectangle, but takes */ /* account of the intersection between this and */ /* the current (given) graphics rectangle for */ /* the redraw. The rectangle *must* be restored */ /* with restore_graphics_intersection() as soon */ /* as the rectangle set here is finished with; */ /* the caller must thus remember this rectangle */ /* for later. */ /* */ /* Parameters: Pointer to a BBox describing the */ /* rectangle to set, where xmax and */ /* ymax are inclusive; */ /* */ /* Pointer to a BBox describing the */ /* current graphics rectangle, where */ /* xmax and ymax are exclusive (e.g. */ /* as in a WimpRedrawWindowBlock's */ /* redraw_area BBox). */ /* */ /* Returns: Pointer to a BBox describing the */ /* actual rectangle that was set. If */ /* this is NULL, the two do not */ /* intersect at all and the redraw */ /* subsequent graphics window */ /* restoration can and should be */ /* skipped. */ /*************************************************/ BBox * set_graphics_intersection(BBox * rbox, BBox * cbox) { BBox * ibox; BBox ogrect = *cbox; ogrect.xmax -= 1; ogrect.ymax -= 1; ibox = intersection(rbox, &ogrect); if (!ibox) return NULL; bbc_gwindow(ibox->xmin, ibox->ymin, ibox->xmax, ibox->ymax); return ibox; } /*************************************************/ /* restore_graphics_intersection() */ /* */ /* Restores the Wimp's redraw graphics rectangle */ /* which was changed by a call to */ /* set_graphics_intersection (which *must* have */ /* been called before this restoring function). */ /* */ /* Parameters: Pointer to a BBox holding the */ /* graphics rectangle as it was */ /* before set_graphics_intersection */ /* was called, where xmax and ymax */ /* are exclusive (e.g. as in a */ /* WimpRedrawWindowBlock's */ /* redraw_area BBox). */ /*************************************************/ void restore_graphics_intersection(BBox * cbox) { BBox ogrect = *cbox; ogrect.xmax -= 1; ogrect.ymax -= 1; bbc_gwindow(ogrect.xmin, ogrect.ymin, ogrect.xmax, ogrect.ymax); } /*************************************************/ /* read_os_to_points() */ /* */ /* To avoid having to use a SWI every time */ /* a conversion is made between OS units and */ /* points or vice versa, this initialises */ /* some internal variables which are used */ /* subsequently. It may be called on a mode */ /* change, for example, to ensure things are up */ /* to date. */ /* */ /* If printing, values of MillipointsPerOSUnit */ /* as defined at the top of this file are used, */ /* since you can't read it; it seems that during */ /* a print job, this call may *not* be used, */ /* contrary to the information on PRM 3-573. */ /* This bug caused *severe* grief during the */ /* development of the print routines... */ /*************************************************/ void read_os_to_points(void) { int x = 1, y = 1; if (!printing) { if ( _swix(Font_Converttopoints, _INR(1,2) | _OUTR(1,2), x, y, &x, &y) ) { millipoints_per_os_unit_x = MillipointsPerOSUnit; millipoints_per_os_unit_y = MillipointsPerOSUnit; } else { millipoints_per_os_unit_x = x; millipoints_per_os_unit_y = y; } } else { millipoints_per_os_unit_x = MillipointsPerOSUnit; millipoints_per_os_unit_y = MillipointsPerOSUnit; } overflow_limit_x = (0x3fffffff / millipoints_per_os_unit_x) - 1; overflow_limit_y = (0x3fffffff / millipoints_per_os_unit_y) - 1; half_mppou_x = millipoints_per_os_unit_x / 2; half_mppou_y = millipoints_per_os_unit_y / 2; } /*************************************************/ /* convert_pair_to_os() */ /* */ /* Converts from millipoints to OS units. The */ /* scale factor is determined by a previous call */ /* to read_os_to_points. */ /* */ /* Parameters: A coordinate in millipoints; */ /* Another coord in millipoints; */ /* Pointer to an int into which the */ /* first coordinate, converted to OS */ /* units, is placed; */ /* Similarly a pointer to an int for */ /* the second coordinate. */ /* */ /* Assumes: The pointers may NOT be NULL. The */ /* input and output variables may be */ /* the same (so passing in x, y, &x, */ /* &y would work correctly). */ /*************************************************/ void convert_pair_to_os(int x, int y, int * osx, int * osy) { *osx = ((x + half_mppou_x) / millipoints_per_os_unit_x) & ~(wimpt_dx() - 1); *osy = ((y + half_mppou_y) / millipoints_per_os_unit_y) & ~(wimpt_dy() - 1); } /*************************************************/ /* convert_pair_to_points() */ /* */ /* Converts from OS units to millipoints. The */ /* scale factor is determined by a previous call */ /* to read_os_to_points. */ /* */ /* Parameters: A coordinate in OS units; */ /* Another coordinate in OS units; */ /* Pointer to an int into which the */ /* first coordinate, converted to */ /* millipoints, is placed; */ /* Similarly a pointer to an int for */ /* the second coordinate. */ /* */ /* Assumes: The pointers may not be NULL. The */ /* input and output variables may be */ /* the same (so passing in x, y, &x, */ /* &y would work correctly). */ /*************************************************/ void convert_pair_to_points(int x, int y, int * mpx, int * mpy) { #ifdef TRACE if (abs(x) > overflow_limit_x || abs(y) > overflow_limit_y) { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "convert_pair_to_points(): Can't convert (%d, %d) to millipoints without overflow.", x,y); show_error_ret(&erb); *mpx = *mpy = 0; return; } #endif *mpx = x * millipoints_per_os_unit_x; *mpy = y * millipoints_per_os_unit_y; } /*************************************************/ /* convert_to_os() */ /* */ /* As convert_pair_to_os() (above), but only */ /* converts one coordinate at a time. */ /* */ /* Parameters: An x coordinate in millipoints; */ /* Pointer to an int into which the */ /* coordinate, converted to OS */ /* units, is placed. */ /* */ /* Assumes: That the pointer is not NULL. The */ /* input and output variable may be */ /* the same (so passing in x, &x */ /* would work correctly); */ /* */ /* If x and y scalings differ, this */ /* will only ever use the x scaling. */ /*************************************************/ void convert_to_os(int x, int * osx) { *osx = ((x + half_mppou_x) / millipoints_per_os_unit_x) & ~(wimpt_dx() - 1); } /*************************************************/ /* convert_to_points() */ /* */ /* As convert_pair_to_points() (above), but only */ /* converts one coordinate at a time. */ /* */ /* Parameters: An x coordinate in OS units; */ /* Pointer to an int into which the */ /* coordinate, converted to milli- */ /* points, is placed. */ /* */ /* Assumes: That the pointer is not NULL. The */ /* input and output variable may be */ /* the same (so passing in x, &x */ /* would work correctly); */ /* */ /* If x and y scalings differ, this */ /* will only ever use the x scaling. */ /*************************************************/ void convert_to_points(int x, int * mpx) { #ifdef TRACE if (abs(x) > overflow_limit_x) { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "convert_to_points: Can't convert '%d' to millipoints without overflow.", x); show_error_ret(&erb); *mpx = 0; return; } #endif *mpx = x * millipoints_per_os_unit_x; } /*************************************************/ /* convert_box_to_os() */ /* */ /* As convert_pair_to_os() (above), but converts */ /* the four coordinates inside a BBox in one go. */ /* */ /* Parameters: Pointer to a BBox containing */ /* coords in millipoints; */ /* Pointer to a BBox into which the */ /* first box's coords, converted to */ /* OS units, are placed. */ /* */ /* Assumes: That neither pointer is NULL. The */ /* two pointers may be the same (so */ /* passing in &box, &box would work */ /* correctly). */ /*************************************************/ void convert_box_to_os(const BBox * mp, BBox * os) { os->xmin = ((mp->xmin + half_mppou_x) / millipoints_per_os_unit_x) & ~(wimpt_dx() - 1); os->ymin = ((mp->ymin + half_mppou_y) / millipoints_per_os_unit_y) & ~(wimpt_dy() - 1); os->xmax = ((mp->xmax + half_mppou_x) / millipoints_per_os_unit_x) & ~(wimpt_dx() - 1); os->ymax = ((mp->ymax + half_mppou_y) / millipoints_per_os_unit_y) & ~(wimpt_dy() - 1); } /*************************************************/ /* convert_box_to_points() */ /* */ /* As convert_pair_to_points() (above), but */ /* converts the four coordinates inside a BBox */ /* in one go. */ /* */ /* Parameters: Pointer to a BBox containing */ /* coords in OS units; */ /* Pointer to a BBox into which the */ /* first box's coords, converted to */ /* millipoints, are placed. */ /* */ /* Assumes: That neither pointer is NULL. The */ /* two pointers may be the same (so */ /* passing in &box, &box would work */ /* correctly). */ /*************************************************/ void convert_box_to_points(const BBox * os, BBox * mp) { #ifdef TRACE if ( abs(os->xmin) > overflow_limit_x || abs(os->ymin) > overflow_limit_y || abs(os->xmax) > overflow_limit_x || abs(os->ymax) > overflow_limit_y ) { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "convert_box_to_points: Can't convert (%d, %d, %d, %d) to millipoints without overflow.", os->xmin, os->ymin, os->xmax, os->ymax); show_error_ret(&erb); mp->xmin = mp->ymin = 0; mp->xmax = mp->ymax = 0; return; } #endif mp->xmin = os->xmin * millipoints_per_os_unit_x; mp->ymin = os->ymin * millipoints_per_os_unit_y; mp->xmax = os->xmax * millipoints_per_os_unit_x; mp->ymax = os->ymax * millipoints_per_os_unit_y; } /*************************************************/ /* read_sprite_size() */ /* */ /* Finds out the size of a given sprite in the */ /* application's sprite pool in OS units. */ /* */ /* Parameters: Pointer to the sprite name; */ /* Pointer to int into which the */ /* sprite's width is returned; */ /* Pointer to int into which the */ /* sprite's height is returned. */ /* */ /* Returns: See Parameters list. */ /* */ /* Assumes: The name pointer is not NULL, but */ /* either of the two int pointers */ /* may be. */ /*************************************************/ _kernel_oserror * read_sprite_size(char * name, int * width, int * height) { int w, h, m; _kernel_oserror * e; e = _swix(OS_SpriteOp, _INR(0,2) | _OUTR(3,4) | _OUT(6), 0x128, sprite_block, name, &w, &h, &m); if (e) return e; w = w << bbc_modevar(m, BBC_XEigFactor); h = h << bbc_modevar(m, BBC_YEigFactor); if (width) *width = w; if (height) *height = h; return NULL; } /*************************************************/ /* set_gadget_state() */ /* */ /* Greys or ungreys a gadget, only changing its */ /* state to avoid flicker. */ /* */ /* Parameters: Object ID the gadget resides in; */ /* Component ID of the gadget; */ /* 1 to grey, 0 to ungrey. */ /*************************************************/ _kernel_oserror * set_gadget_state(ObjectId o, ComponentId c, int grey_state) { _kernel_oserror * e; unsigned int flags; e = gadget_get_flags(0, o, c, &flags); if (e) return e; /* Only change state, to avoid flicker. */ if (!!grey_state != !!(flags & Gadget_Faded)) { if (grey_state) flags |= Gadget_Faded; else flags &= ~Gadget_Faded; return gadget_set_flags(0, o, c, flags); } return NULL; } /*************************************************/ /* anti_twitter() */ /* */ /* Calls the anti-twitter code over a given */ /* redraw area. */ /* */ /* Parameters: Pointer to a WimpRedrawWindow */ /* block with the redraw_area BBox */ /* holding the area over which the */ /* anti-twitter code should be */ /* called. */ /*************************************************/ void anti_twitter(WimpRedrawWindowBlock * r) { char nhantitwitter[256]; int mode, ok = 1; unsigned int modeflags; #define AntiTwitter1 50 #define AntiTwitter2 55 #ifndef TRACE /* Older interlace modules only support modes 50 and 55 */ /* directly, though can still appear to work in others. */ _swix(OS_Byte, _IN(0) | _OUT(2), 135, &mode); if (mode == AntiTwitter1 || mode == AntiTwitter2) ok = 1; else { /* If the current mode is not mode 50 or 55, this mode module */ /* may be new enough to support setting bit 8 of the modeflags */ /* to indicate interlace. */ _swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 0, &modeflags); ok = !!(modeflags & (1<<8)); } #else /* For trace builds, always try to anti-twitter (allows testing */ /* in certain non-interlaced Desktop screen modes) */ ok = 1; /* Hmph - stop compiler complaining about things not being used... */ mode = 0; modeflags = 0; #endif if (ok) { BBox gwind; BBox * area; gwind.xmin = (bbc_vduvar(BBC_GWLCol)) * wimpt_dx(); gwind.ymin = (bbc_vduvar(BBC_GWBRow)) * wimpt_dy(); gwind.xmax = (bbc_vduvar(BBC_GWRCol) + 1) * wimpt_dx(); gwind.ymax = (bbc_vduvar(BBC_GWTRow) + 1) * wimpt_dy(); area = intersection(&gwind, &r->redraw_area); if (area) { sprintf(nhantitwitter, "%%NHAntiTwitter %d %d %d %d\n", area->xmin, area->ymin, area->xmax - area->xmin, area->ymax - area->ymin); _swix(OS_CLI, _IN(0), nhantitwitter); } } } /*************************************************/ /* adjust() */ /* */ /* Returns 1 if Wimp_GetPointerInfo says that */ /* Adjust is being pressed, else 0. */ /*************************************************/ int adjust(void) { WimpGetPointerInfoBlock info; wimp_get_pointer_info(&info); return !!(info.button_state & Wimp_MouseButtonAdjust); } /*************************************************/ /* hide_gadget() */ /* */ /* Hides a given gadget by moving it out of the */ /* visible area of the window it is in. */ /* */ /* Parameters: Object ID the gadget lies in; */ /* Component ID of the gadget. */ /* */ /* Returns: 1 if the gadget was moved out, */ /* else 0. */ /*************************************************/ int hide_gadget(ObjectId o, ComponentId c) { BBox g; if (gadget_get_bbox(0, o, c, &g)) return 0; /* If the gadget has a large negative X coordinate, */ /* assume it's been moved out already. */ if (g.xmin < -4096) return 0; /* Otherwise, move it */ g.xmin -= 8192; g.xmax -= 8192; if (gadget_move_gadget(0, o, c, &g)) return 0; return 1; } /*************************************************/ /* show_gadget() */ /* */ /* Shows a given gadget hidden by hide_gadget() */ /* above. */ /* */ /* Parameters: Object ID the gadget lies in; */ /* Component ID of the gadget. */ /* */ /* Returns: 1 if the gadget was moved in, */ /* else 0. */ /*************************************************/ int show_gadget(ObjectId o, ComponentId c) { BBox g; if (gadget_get_bbox(0, o, c, &g)) return 0; /* If the gadget hasn't got a large negative X coordinate, */ /* assume it's not been moved out. */ if (g.xmin > -4096) return 0; /* Otherwise, move it */ g.xmin += 8192; g.xmax += 8192; if (gadget_move_gadget(0, o, c, &g)) return 0; return 1; } /*************************************************/ /* gadget_hidden() */ /* */ /* Call to find out if a gadget has been moved */ /* out with hide_gadget() or is still visible. */ /* */ /* Parameters: Object ID the gadget lies in; */ /* Component ID of the gadget. */ /* */ /* Returns: 1 if the gadget is hidden else 0. */ /*************************************************/ int gadget_hidden(ObjectId o, ComponentId c) { BBox g; /* If there's an error getting the gadget's bounding box, then the gadget */ /* is missing altogether or something else has gone wrong; in any case, */ /* safest action is to say it has been hidden. */ if (gadget_get_bbox(0, o, c, &g)) return 1; /* Simple assumption that this much of a negative X value = gadget hidden */ if (g.xmin < -4096) return 1; return 0; } /*************************************************/ /* slab_gadget() */ /* */ /* Slabs a gadget in briefly, by setting its */ /* Selected bit. Gadget must be made of one icon */ /* only. */ /* */ /* Parameters: Object ID the gadget lies in; */ /* Component ID of the gadget. */ /*************************************************/ void slab_gadget(ObjectId o, ComponentId c) { WimpSetIconStateBlock set; WimpGetIconStateBlock get; int icon[2]; /* Get the icon number and window handle of the gadget */ if (gadget_get_icon_list(0, o, c, icon, sizeof(icon), NULL)) return; if (window_get_wimp_handle(0, o, &get.window_handle)) return; get.icon_handle = icon[0]; /* Get the icon state */ if (wimp_get_icon_state(&get)) return; /* Set the flags as selected */ set.window_handle = get.window_handle; set.icon_handle = get.icon_handle; set.EOR_word = get.icon.flags | WimpIcon_Selected; set.clear_word = 0xffffffff; if (wimp_set_icon_state(&set)) return; /* Wait a while */ { int time_now, time_start; _swix(OS_ReadMonotonicTime, _OUT(0), &time_start); do { _swix(OS_ReadMonotonicTime, _OUT(0), &time_now); } while (time_now - time_start < 15); } /* Restore the old flags */ set.EOR_word = get.icon.flags; wimp_set_icon_state(&set); } /*************************************************/ /* slab_gadget_in() */ /* */ /* Slabs a gadget in, by setting its Selected */ /* bit. Gadget must be made of one icon only. */ /* */ /* Parameters: Object ID the gadget lies in; */ /* Component ID of the gadget. */ /*************************************************/ void slab_gadget_in(ObjectId o, ComponentId c) { WimpSetIconStateBlock set; WimpGetIconStateBlock get; int icon[2]; /* Get the icon number and window handle of the gadget */ if (gadget_get_icon_list(0, o, c, icon, sizeof(icon), NULL)) return; if (window_get_wimp_handle(0, o, &get.window_handle)) return; get.icon_handle = icon[0]; /* Get the icon state */ if (wimp_get_icon_state(&get)) return; /* Set the flags as selected */ set.window_handle = get.window_handle; set.icon_handle = get.icon_handle; set.EOR_word = get.icon.flags | WimpIcon_Selected; set.clear_word = 0xffffffff; wimp_set_icon_state(&set); } /*************************************************/ /* slab_gadget_out() */ /* */ /* Slabs a gadget out, by clearing its Selected */ /* bit. Gadget must be made of one icon only. */ /* */ /* Parameters: Object ID the gadget lies in; */ /* Component ID of the gadget. */ /*************************************************/ void slab_gadget_out(ObjectId o, ComponentId c) { WimpSetIconStateBlock set; WimpGetIconStateBlock get; int icon[2]; /* Get the icon number and window handle of the gadget */ if (gadget_get_icon_list(0, o, c, icon, sizeof(icon), NULL)) return; if (window_get_wimp_handle(0, o, &get.window_handle)) return; get.icon_handle = icon[0]; /* Get the icon state */ if (wimp_get_icon_state(&get)) return; /* Set the flags as unselected */ set.window_handle = get.window_handle; set.icon_handle = get.icon_handle; set.EOR_word = get.icon.flags &~ WimpIcon_Selected; set.clear_word = 0xffffffff; wimp_set_icon_state(&set); } /*************************************************/ /* copy_toolaction_info() */ /* */ /* Copies the internal details of a given */ /* ToolAction gadget to another. */ /* */ /* Ident off, ident on, ident faded, select */ /* action, adjust action and click-show details */ /* are copied with ToolAction SWIs; the help */ /* text is copied with gadget library calls. */ /* */ /* This does *not* copy state info, such as */ /* on/off or greyed. */ /* */ /* Parameters: Object ID the source gadget is */ /* in; */ /* Component ID of the source; */ /* Object ID the destination gadget */ /* is in; */ /* Component ID of the destination. */ /*************************************************/ _kernel_oserror * copy_toolaction_info(ObjectId src_o, ComponentId src_c, ObjectId dst_o, ComponentId dst_c) { _kernel_oserror * e; char ident[2048], help[MaxHelpLen]; int adjust_act, select_act; int adjust_cs, select_cs; unsigned int flags; /* Off state ident string */ e = _swix(Toolbox_ObjectMiscOp, _INR(0,5), toolaction_SET_IDENT_OFF, src_o, ToolAction_GetIdent, src_c, ident, sizeof(ident)); if (e) return e; e = _swix(Toolbox_ObjectMiscOp, _INR(0,4), toolaction_SET_IDENT_OFF, dst_o, ToolAction_SetIdent, dst_c, ident); if (e) return e; /* On state ident string */ e = _swix(Toolbox_ObjectMiscOp, _INR(0,5), toolaction_SET_IDENT_ON, src_o, ToolAction_GetIdent, src_c, ident, sizeof(ident)); if (e) return e; e = _swix(Toolbox_ObjectMiscOp, _INR(0,4), toolaction_SET_IDENT_ON, dst_o, ToolAction_SetIdent, dst_c, ident); if (e) return e; /* Faded state ident string */ e = _swix(Toolbox_ObjectMiscOp, _INR(0,5), toolaction_SET_IDENT_FADE, src_o, ToolAction_GetIdent, src_c, ident, sizeof(ident)); if (e) return e; e = _swix(Toolbox_ObjectMiscOp, _INR(0,4), toolaction_SET_IDENT_FADE, dst_o, ToolAction_SetIdent, dst_c, ident); if (e) return e; /* Adjust and select actions */ e = _swix(Toolbox_ObjectMiscOp, _INR(0,3) | _OUTR(0,1), 0, src_o, ToolAction_GetAction, src_c, &select_act, &adjust_act); if (e) return e; e = _swix(Toolbox_ObjectMiscOp, _INR(0,5), 0, dst_o, ToolAction_SetAction, dst_c, select_act, adjust_act); if (e) return e; /* Adjust and select click-shows */ e = _swix(Toolbox_ObjectMiscOp, _INR(0,3) | _OUTR(0,1), 0, src_o, ToolAction_GetClickShow, src_c, &select_cs, &adjust_cs); if (e) return e; e = _swix(Toolbox_ObjectMiscOp, _INR(0,5), 0, dst_o, ToolAction_SetClickShow, dst_c, select_cs, adjust_cs); if (e) return e; /* The gadget flags */ e = gadget_get_flags(0, src_o, src_c, &flags); if (e) return e; e = gadget_set_flags(flags, dst_o, dst_c, flags); if (e) return e; /* Finally, the help text */ e = gadget_get_help_message(0, src_o, src_c, help, sizeof(help), NULL); if (e) return e; return gadget_set_help_message(0, dst_o, dst_c, help); } /*************************************************/ /* set_window_flags() */ /* */ /* Sets the flags of a given window, assuming */ /* the nested Wimp is available... */ /* */ /* Parameters: Window handle; */ /* EOR word; */ /* Clear word. */ /* */ /* Assumes: That a window manager that */ /* supports extended Wimp_OpenWindow */ /* calls (R2 = 'TASK') is present. */ /* */ /* The flags are set according to */ /* */ /* new = (old BIC clear word) EOR EOR word */ /* */ /* i.e.: */ /* */ /* C E Effect */ /* ------------ */ /* 0 0 Preserve bit */ /* 0 1 Toggle bit */ /* 1 0 Clear bit */ /* 1 1 Set bit */ /*************************************************/ _kernel_oserror * set_window_flags(int window_handle, unsigned int clear_word, unsigned int eor_word) { /* Block required for the extended Wimp_OpenWindow */ typedef struct { WimpOpenWindowBlock open; unsigned int flags; } ExtendedOpenBlock; _kernel_oserror * e; WimpGetWindowStateBlock s; unsigned int parent, align; unsigned int new_flags; ExtendedOpenBlock ext_o; /* Get the current window details */ s.window_handle = window_handle; e = _swix(Wimp_GetWindowState, _INR(1, 2) | _OUTR(3, 4), &s, Magic_Word_TASK, /* See MiscDefs.h */ &parent, &align); if (e) return e; /* Obtain the new flags word */ new_flags = (s.flags & ~clear_word) ^ eor_word; /* Fill in the new open block and reopen the window with it */ ext_o.open.window_handle = s.window_handle; ext_o.open.visible_area = s.visible_area; ext_o.open.xscroll = s.xscroll; ext_o.open.yscroll = s.yscroll; ext_o.open.behind = s.behind; ext_o.flags = new_flags; return _swix(Wimp_OpenWindow, _INR(1,4), &ext_o, Magic_Word_TASK, parent, align | Alignment_NewFlagsGiven); } /*************************************************/ /* debounce_keypress() */ /* */ /* For some key presses (e.g. function keys), it */ /* is not desirable to let the key autorepeat. */ /* This function sits in a tight loop waiting */ /* for all keys to be released before exitting. */ /* */ /* Returns: 1 if a key was being pressed and the */ /* function waited for its release, */ /* else 0. */ /*************************************************/ int debounce_keypress(void) { int key, waited = 0; _kernel_oserror * e; do { e = _swix(OS_Byte, _INR(0,1) | _OUT(1), 121, /* Keyboard scan */ 0, /* Scan all keys */ &key); if (key != 255) waited = 1; } while (!e && key != 255); if (waited) _swix(OS_Byte, _INR(0,1), 21, 0); /* Flush keyboard buffer */ return waited; } /*************************************************/ /* task_from_window() */ /* */ /* Returns the task handle of the owner of a */ /* given window. */ /* */ /* Parameters: A window handle. */ /* */ /* Returns: Task handle of the window owner. */ /*************************************************/ int task_from_window (int window_handle) { WimpMessage m; int handle; m.hdr.size = 20; m.hdr.your_ref = 0; m.hdr.action_code = 0; if ( wimp_send_message(Wimp_EUserMessageAcknowledge, &m, window_handle, 0, &handle) ) return 0; return handle; } /*************************************************/ /* is_known_browser() */ /* */ /* Finds out if the given browser_data struct is */ /* in the list of known structures. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* to check. */ /* */ /* Returns: 1 if the structure is in the list */ /* or 0 if it isn't. */ /*************************************************/ int is_known_browser(browser_data * b) { browser_data * check = last_browser; int found = 0; /* If b is NULL, can't be a valid browser_data structure! */ if (!b) return 0; /* Search the list */ while (check && !found) { if (check == b) found = 1; else check = check->previous; } /* Return the search results */ return found; } /*************************************************/ /* encode_base64() */ /* */ /* Passed a pointer to data and its length, this */ /* will fill the output buffer with Base64- */ /* encoded data, returning the length of the */ /* output data (this is not terminated). */ /* */ /* The length of the output will be - */ /* */ /* (length of input, rounded up to next multiple */ /* of 3) times 4 */ /* */ /* - so make sure you have a big enough output */ /* buffer. */ /* */ /* Parameters: Pointer to the data to encode; */ /* */ /* Length of the data to encode; */ /* */ /* Pointer to the output buffer. */ /* */ /* Assumes: That the output buffer is big */ /* enough (see above). */ /*************************************************/ int encode_base64(const char * in, int len, char * out) { char * out_ptr = out; int i; unsigned long chunk; int p = 0; while (p < len) { chunk = 0; for (i = 0; i < 3; i++, p++) { if (p < len) chunk = (chunk << 8) | in[p]; else chunk = (chunk << 8); } *out++ = base64_table[chunk >> 18]; *out++ = base64_table[(chunk >> 12) & 0x3f]; if (p <= len + 1) { *out++ = base64_table[(chunk >> 6) & 0x3f]; if (p <= len) *out++ = base64_table[chunk & 0x3f]; else *out++ = '='; } else { *out++ = '='; *out++ = '='; } } return out - out_ptr; } /*************************************************/ /* utils_strncasecmp() */ /* */ /* Case insensitive comparisson of n chars of */ /* two given strings. */ /* */ /* Parameters: As strncmp */ /* */ /* Returns: As strncmp */ /*************************************************/ int utils_strncasecmp(const char * a, const char * b, unsigned int n) { while(*a && *b && n--) { if (tolower(*a++) != tolower(*b++)) return 1; } return 0; } /*************************************************/ /* utils_stop_webserv() */ /* */ /* Stops the WebServ application by sending it */ /* an AppControl message. */ /*************************************************/ _kernel_oserror * utils_stop_webserv(void) { WimpMessage msg; _kernel_oserror * e; char * c; int * p; int buffer [32]; char taskname[128]; int * notused; int t; int next = 0; int handle = 0; /* First, get WebServ's task handle */ do { e = _swix(TaskManager_EnumerateTasks, _INR(0,2) | _OUTR(0,1), next, buffer, sizeof(buffer), &next, ¬used); if (e) return e; /* Go through as much of the buffer as the call said it used */ for (p = buffer; p < notused && handle == 0; p += 4) { c = (char *) p[1]; t = 0; memset(taskname, 0, sizeof(taskname)); while (*c > 31 && t < sizeof(taskname) - 1) taskname[t++] = *c++; if (!strcmp(taskname, "Acorn WebServe")) handle = p[0]; } } while (next >= 0 && handle == 0); #ifdef TRACE if (!handle) { /* Didn't find WebServ, so complain and exit */ erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, "WebServe is not present"); show_error_ret(&erb); return NULL; } #else if (!handle) { /* Didn't find WebServ, so exit */ return NULL; } #endif /* If WebServ is present, send the message */ msg.hdr.size = 32; msg.hdr.sender = task_handle; msg.hdr.my_ref = 0; msg.hdr.your_ref = 0; msg.hdr.action_code = Wimp_MAppControl; msg.data.app_control.version = 1; msg.data.app_control.flags = Wimp_MAppControl_ImmediateAction; msg.data.app_control.reason = Wimp_MAppControl_Stop; return wimp_send_message(Wimp_EUserMessage, &msg, handle, -1, NULL); } /*************************************************/