/* 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 : Main.c */ /* */ /* Purpose: To run. */ /* */ /* Author : A.D.Hodgkinson */ /* */ /* History: 12-Nov-96: Created. */ /***************************************************/ #include "setjmp.h" #include "signal.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include <math.h> #include "swis.h" #include "kernel.h" #include "flex.h" #include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */ #include "URI.h" /* URI handler API, in URILib:h */ #include "wimp.h" #include "wimplib.h" #include "event.h" #include "toolbox.h" #include "quit.h" #include "proginfo.h" #include "window.h" #include "menu.h" #include "saveas.h" #include "printdbox.h" #include "gadgets.h" #include "svcprint.h" #include "Global.h" #include "FromROSLib.h" #include "TBEvents.h" /* Which includes loads of stuff... */ #include "Utils.h" #include "Browser.h" #include "ChoiceDefs.h" #include "CtrlDefs.h" #include "Encoding.h" #include "FontManage.h" #include "Handlers.h" #include "History.h" #include "ImgHistory.h" #include "MiscDefs.h" #include "Mouse.h" #include "PlugIn.h" #include "Protocols.h" #include "RMA.h" #include "Save.h" #include "URLutils.h" #include "Windows.h" /* The following three are defined or undefined locally */ #undef INCLUDE_HEAPGRAPH #undef INCLUDE_HIERPROF #undef INCLUDE_MEMCHECK #ifdef INCLUDE_HEAPGRAPH #include "HeapGraph.HeapGraph.h" #endif #ifdef INCLUDE_HIERPROF #define HierProf_PROFILE #include "HierProf:HierProf.h" #endif #ifdef INCLUDE_MEMCHECK #include "MemCheck:MemCheck.h" #endif /* Finally, Main.h itself */ #include "Main.h" /* Static function prototypes */ static void initialise_app (void); static _kernel_oserror * open_messages_file (int which); static void close_messages_file (void * control); static void load_choices (void); #ifdef TRACE static void self_test (void); #endif static void termination (void); static void catch_errors (int signum); /* Make sure the stack starts at a reasonable size to prevent frequent */ /* stack extensions - this is a directive to the C run time system and */ /* can be removed on other systems which have no equivalent. */ int __root_stack_size = 16384; // /*************************************************/ // /* attach_event_handlers() */ // /* */ // /* Called when an object is autocreated by the */ // /* toolbox (see initialise_app). Used to get at */ // /* the ObjectID of things without needing a */ // /* specifically generated event to deliver it. */ // /*************************************************/ // // int attach_event_handlers(int eventcode,ToolboxEvent *event,IdBlock *idb,void *handle) // { // ObjectId temp; // // ToolboxObjectAutoCreatedEvent *c=(ToolboxObjectAutoCreatedEvent *) event; // // /* We extract the relevant object Id by comparing the template name */ // /* given in the event structure with something we know about and */ // /* proceeding as is relevant. */ // // if (!strcmp(c->template_name,"Browser")) // { // main_window_id = idb->self_id; // show_centred(main_window_id); // } // else if (!strcmp(c->template_name,"ButtonBar")) // { // temp = idb->self_id; // { // BBox b; // b.xmin=0; // b.ymin=-144; // b.xmax=16384; // b.ymax=0; // set_corrected_extent(0,temp,&b); // } // } // // return 1; // } /*************************************************/ /* initialise_app() */ /* */ /* Initialises application as a Toolbox task. */ /*************************************************/ static void initialise_app(void) { int module_version; show_error(event_initialise(&idb)); /* First handler registered is called last. This is a net to catch */ /* miscellaneous events that might occur. Useful when there is a */ /* range of event codes defined for something, rather than just */ /* one code, for example. */ show_error(event_register_toolbox_handler(-1, -1, handle_miscellaneous_event, NULL)); /* Register fundamental handlers and initialise as a Toolbox task */ show_error(event_register_message_handler(Wimp_MQuit, handle_messages, NULL)); show_error(event_register_toolbox_handler(-1, Toolbox_Error, report_toolbox_error, NULL)); /* Check the Wimp version; for window managers of 3.8 and above, */ /* declare a minimum version of 3.80 so borderless windows can */ /* still have tools. Otherwise, only ask for 3.1. */ _swix(Wimp_ReadSysInfo, _IN(0) | _OUT(0), 7, &module_version); if (module_version >= 387) nested_wimp = 1; else nested_wimp = 0; show_error(toolbox_initialise(0, nested_wimp ? WIMPMINH : WIMPMINL, messages_list, event_code_list, task_dir, &meb, &idb, &wimp_version, &task_handle, (void *) &sprite_block)); /* Open the Choices and Controls files */ cob = NULL; chb = NULL; show_error(open_messages_file(0)); show_error(open_messages_file(1)); /* If either failed, bomb out. Can't raise a custom error as we have no */ /* messages file to read it from... */ if (!cob || !chb) exit(EXIT_FAILURE); /* If the system variable 'Browse$IssueDesktopCommand' is set to 'yes', */ /* then the AcornURI and/or TaskModule modules were started in !Run and */ /* we must issue a *Desktop command to start their task components. */ { char combuf[96]; sprintf(combuf, "If \"<Browse$IssueDesktopCommand>\" = \"yes\" Then WimpTask Desktop\r\n"); _swix(OS_CLI, /* Don't want to hear about any errors */ _IN(0), combuf); } /* Quit menu items are set to give the Quit_Quit event type, as */ /* well as this event possibly being delivered by the Toolbox */ /* from elsewhere. */ show_error(event_register_toolbox_handler(-1, Quit_Quit, handle_quit, NULL)); /* Called before the application's Info box is shown */ show_error(event_register_toolbox_handler(-1, ProgInfo_AboutToBeShown, handle_show_info, NULL)); /* Opening and closing windows */ show_error(event_register_toolbox_handler(-1, EOpenNewWindow, windows_new_browser, NULL)); show_error(event_register_toolbox_handler(-1, ECloseWindow, windows_shut_browser, NULL)); /* Opening the Open URL dialogue */ show_error(event_register_toolbox_handler(-1, EOpenToBeShownMisc, openurl_to_be_shown, NULL)); show_error(event_register_toolbox_handler(-1, EOpenToBeShownMenu, openurl_to_show_from_menu, NULL)); /* Opening and closing the Choices dialogue */ show_error(event_register_toolbox_handler(-1, ECDToBeShown, choices_to_be_shown, NULL)); show_error(event_register_toolbox_handler(-1, ECDHidden, choices_hidden, NULL)); /* For the Find dialogue */ show_error(event_register_toolbox_handler(-1, EFindToBeShown, find_to_be_shown, NULL)); show_error(event_register_toolbox_handler(-1, EFindHidden, find_hidden, NULL)); /* Print and Print Style dialogues */ show_error(event_register_toolbox_handler(-1, EPSToBeShown, printstyle_to_be_shown, NULL)); show_error(event_register_toolbox_handler(-1, PrintDbox_AboutToBeShown, print_to_be_shown, NULL)); /* Called whenever a menu item is selected */ show_error(event_register_toolbox_handler(-1, Menu_Selection, menus_item_selected, NULL)); /* Support the Help menu */ show_error(event_register_toolbox_handler(-1, EHelpFromHelpString, menus_help_from_help_string, NULL)); show_error(event_register_toolbox_handler(-1, EHelpReleaseNotes, menus_help_release_notes, NULL)); show_error(event_register_toolbox_handler(-1, EHelpAboutPage, menus_help_about_page, NULL)); /* Before showing and after closing menus */ show_error(event_register_toolbox_handler(-1, EMainToBeShown, menus_show_main, NULL)); show_error(event_register_toolbox_handler(-1, EUtilsToBeShown, menus_show_utils, NULL)); show_error(event_register_toolbox_handler(-1, EExportToBeShown, menus_show_export, NULL)); show_error(event_register_toolbox_handler(-1, EChoicesToBeShown, menus_show_choices, NULL)); show_error(event_register_toolbox_handler(-1, EFileToBeShown, menus_show_file, NULL)); show_error(event_register_toolbox_handler(-1, ENavigateToBeShown, menus_show_navigate, NULL)); show_error(event_register_toolbox_handler(-1, EDocumentToBeShown, menus_show_document, NULL)); show_error(event_register_toolbox_handler(-1, EDocumentHidden, menus_hide_document, NULL)); show_error(event_register_toolbox_handler(-1, EEncodingToBeShown, encoding_show_menu, NULL)); show_error(event_register_toolbox_handler(-1, EHistoryToBeShown, menus_show_history, NULL)); /* Called when the 'Cache' option is chosen from the main menu. */ show_error(event_register_toolbox_handler(-1, EMainCache, menus_item_selected, NULL)); /* Called when a selection is made from the Encoding menu. */ show_error(event_register_toolbox_handler(-1, EEncodingSelect, encoding_select, NULL)); /* Called when the user selects "From document" in the */ /* Encoding menu. */ show_error(event_register_toolbox_handler(-1, EEncodingFromDocument, encoding_from_document_select, NULL)); /* General key press handler */ show_error(event_register_wimp_handler(-1, Wimp_EKeyPressed, handle_keys, NULL)); /* Wimp handler for menu selections in forms etc. */ show_error(event_register_wimp_handler(-1, Wimp_EMenuSelection, handle_menus, NULL)); /* LoseCaret event handler for grabbing the caret back */ show_error(event_register_wimp_handler(-1, Wimp_ELoseCaret, handle_lose_caret, NULL)); /* Pointer checking */ show_error(event_register_wimp_handler(-1, Wimp_EPointerEnteringWindow, browser_pointer_entering, NULL)); show_error(event_register_wimp_handler(-1, Wimp_EPointerLeavingWindow, browser_pointer_leaving, NULL)); /* Related to that, end of drag handling */ show_error(event_register_wimp_handler(-1, Wimp_EUserDrag, (WimpEventHandler *) handle_drags, NULL)); /* General Wimp message handling */ show_error(event_register_message_handler(Wimp_MModeChange, handle_messages, NULL)); show_error(event_register_message_handler(Wimp_MDataLoad, handle_messages, NULL)); show_error(event_register_message_handler(Wimp_MDataLoadAck, handle_messages, NULL)); show_error(event_register_message_handler(Wimp_MDataSave, handle_messages, NULL)); /* (DataSaveAck is registered in the Printing section below) */ show_error(event_register_message_handler(Wimp_MDataOpen, handle_messages, NULL)); show_error(event_register_message_handler(Wimp_MRAMFetch, handle_messages, NULL)); show_error(event_register_message_handler(Wimp_MRAMTransmit, handle_messages, NULL)); show_error(event_register_message_handler(Wimp_MMenusDeleted, handle_messages, NULL)); /* ANT protocols */ show_error(event_register_message_handler(Message_ANTOpenURL, handle_messages, NULL)); /* Plug-In protocol */ show_error(event_register_message_handler(Message_PlugIn_Open, handle_messages, NULL)); show_error(event_register_message_handler(Message_PlugIn_Opening, handle_messages, NULL)); show_error(event_register_message_handler(Message_PlugIn_Close, handle_messages, NULL)); show_error(event_register_message_handler(Message_PlugIn_Closed, handle_messages, NULL)); show_error(event_register_message_handler(Message_PlugIn_URLAccess, handle_messages, NULL)); show_error(event_register_message_handler(Message_PlugIn_StreamNew, handle_messages, NULL)); show_error(event_register_message_handler(Message_PlugIn_ReshapeRequest, handle_messages, NULL)); show_error(event_register_message_handler(Message_PlugIn_Status, handle_messages, NULL)); show_error(event_register_message_handler(Message_PlugIn_Busy, handle_messages, NULL)); /* URI handler message handling */ show_error(event_register_message_handler(URI_MDying, handle_messages, NULL)); show_error(event_register_message_handler(URI_MProcess, handle_messages, NULL)); show_error(event_register_message_handler(URI_MReturnResult, handle_messages, NULL)); /* AppControl message handling */ show_error(event_register_message_handler(Wimp_MAppControl, handle_messages, NULL)); /* Printing related message handlers */ show_error(event_register_message_handler(Browser_Message_PrintError, handle_messages, NULL)); show_error(event_register_message_handler(Browser_Message_PrintSave, handle_messages, NULL)); show_error(event_register_message_handler(Browser_Message_PrintTypeOdd, handle_messages, NULL)); show_error(event_register_message_handler(Wimp_MDataSaveAck, handle_messages, NULL)); /* For message bounces */ show_error(event_register_wimp_handler(-1, Wimp_EUserMessageAcknowledge, handle_ack, NULL)); /* Debug build event handlers */ #ifdef TRACE show_error(event_register_toolbox_handler(-1, ETraceTokenDumpByLine, trace_dump_tokens_by_line, NULL)); show_error(event_register_toolbox_handler(-1, ETraceTokenDumpByStream, trace_dump_tokens_by_stream, NULL)); #endif /* Event handlers for menu items that relate to toolbar buttons. */ /* This list needs to be kept in sync with the specific list in */ /* Windows.c, which allows buttons in specific windows to use */ /* the same event codes. */ show_error(event_register_toolbox_handler(-1, EButtonBarHome, handle_home, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarBack, handle_back, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarForward, handle_forwards, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarReload, handle_reload, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarStop, handle_stop, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarViewHotlist, handle_view_hotlist, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarAddToHotlist, handle_add_hotlist, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarViewResources, handle_view_resources, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarLoadImages, handle_load_images, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarViewSource, handle_view_source, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarGoTo, handle_go_to, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarGo, handle_go, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarCancel, handle_cancel, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarBistate, handle_bistate, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarTristate, handle_tristate, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarSaveSource, handle_save_source, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarPrint, handle_print, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarSaveAsText, handle_save_as_text, NULL)); show_error(event_register_toolbox_handler(-1, EButtonBarSaveAsDraw, handle_save_as_draw, NULL)); /* Miscellaneous event handlers for keyboard control of some functions */ show_error(event_register_toolbox_handler(-1, EURLBarClearURL, handle_clear_url, NULL)); show_error(event_register_toolbox_handler(-1, EURLBarToggleHistory, handle_show_history_menu, NULL)); /* Event handlers for saving (most are registered when the dialogue opens) */ show_error(event_register_toolbox_handler(-1, ESaveFileToBeShown, savefile_to_be_shown, NULL)); show_error(event_register_toolbox_handler(-1, ESaveObjectToBeShown, saveobject_to_be_shown, NULL)); /* Event handlers for the Item Information dialogue */ show_error(event_register_toolbox_handler(-1, EIIToBeShown, iteminfo_to_be_shown, NULL)); show_error(event_register_toolbox_handler(-1, EIIFollowLink, iteminfo_follow_link, NULL)); show_error(event_register_toolbox_handler(-1, EIIExportItem, iteminfo_export_item, NULL)); /* Wake up flex */ strncpy(program_name, lookup_token("_TaskName", 1, 0), sizeof(program_name)); program_name[sizeof(program_name) - 1] = 0; flex_init(program_name, NULL, 0x3000000); flex_set_budge(1); flex_set_deferred_compaction(1); /* Initialise the HTML library. This is to set up some initial */ /* data which can't be initialised in headers due to ROM build */ /* considerations. */ HtmlInit(); /* Similarly, initialise ImageLib */ ImageLib_Init(); /* Initialise FromROSLib routines */ wimpt_read(); /* Initialise Utils routines */ read_os_to_points(); #ifndef REMOTE_HOTLIST /* Initialise the hotlist */ show_error(hotlist_initialise()); #endif /* Initialise the encoding menu handler */ show_error(encoding_init()); /* Find the total number of animation frames for the status bar */ animation_frames = 0; { char v[10]; /* SpriteOp 40 is Read Info; it's just something that will give */ /* an error if the sprite doesn't exist. */ do { sprintf(v, "a%d\0", animation_frames ++); } while ( animation_frames < Limits_Misc_AnimFrames && !(_swix(OS_SpriteOp, _INR(0,2), 296, sprite_block, v)) ); /* animation_frames is incremented for every sprite looked at, */ /* including the last one, which must not be found. So need to */ /* subtract 1 now, to make it equal the number of frames. */ animation_frames --; } /* Similarly, find the number of bullets available */ bullets = 0; { char v[10]; do { sprintf(v,"b%d\0",bullets++); } while ( bullets < Limits_Misc_Bullets && !(_swix(OS_SpriteOp, _INR(0,2), 296, sprite_block, v)) ); bullets --; } /* Is the URI handler available? */ { int version; if (uri_version(0, &version)) uri_module_present = 0; else if (version >= 5) uri_module_present = 1; } /* Find out window tool sizes */ show_error(windows_initialise_tool_sizes()); } /*************************************************/ /* open_messages_file() */ /* */ /* Asks MessageTrans to open a Messages file. */ /* Looks through a system variable for the path */ /* to find the file in before going to a */ /* default - see the code comments for more */ /* information. */ /* */ /* Parameters: 0 to load the Choices file, or 1 */ /* to load the Controls file. */ /*************************************************/ static _kernel_oserror * open_messages_file(int which) { _kernel_oserror * e; MessagesFD * control; char * path = NULL; /* Work out what to open. */ path = save_build_messages_path(which); if (!path) goto open_messages_file_no_memory; /* Claim RMA for the control block and pathname */ e = rma_claim(NULL, sizeof(MessagesFD) + strlen(path) + 1, (void *) &control); if (e) { free(path); return e; } /* Update the relevant global. No need for a default case as */ /* save_build_messages_path will have caught that. */ switch (which) { case 0: chb = control; break; case 1: cob = control; break; } /* Register the block with MemCheck if required, and copy */ /* the pathname into it. */ #ifdef INCLUDE_MEMCHECK MemCheck_RegisterMiscBlock((void *) control, sizeof(MessagesFD) + strlen(path) + 1); #endif strcpy((char *) ((int) control + sizeof(MessagesFD)), path); /* Don't need the path now */ free(path); path = NULL; /* Open the file */ return _swix(MessageTrans_OpenFile, _INR(0,2), control, /* Pointer to control block */ (int) control + sizeof(MessagesFD), /* Filename */ 0); /* Buffer in RMA */ /* Error condition exit */ open_messages_file_no_memory: if (control) rma_release(NULL, control); if (path) free(path); return NULL; } /*************************************************/ /* close_messages_file() */ /* */ /* Closes a messges file and releases the RMA */ /* space claimed for it. */ /* */ /* Parameters: Pointer to the allocated chunk of */ /* RMA space holding the */ /* MessageTrans control block and */ /* Messages file pathname. */ /*************************************************/ static void close_messages_file(void * control) { /* If the file won't close for some reason, */ /* MessageTrans may still want to access it */ /* - so safest *not* to release the RMA */ /* holding the control block and filename. */ if ( _swix(MessageTrans_CloseFile, _IN(0), control) ) return; /* Release the claimed RMA space holding the */ /* control block and messages file name. */ rma_release(NULL, control); } /*************************************************/ /* colour_table_leaf_to_path() */ /* */ /* Called by ImageLib. Print a full lookup table */ /* file pathname into path given the leafname. */ /* */ /* Parameters: Pointer to output buffer for full */ /* pathname; */ /* */ /* Pointer to leaf name. */ /* */ /* Assumes: Output buffer big enough :) */ /*************************************************/ void colour_table_leaf_to_path(char *path, const char *leaf) { sprintf(path, "%s.%s", task_dir, leaf); } /*************************************************/ /* load_choices() */ /* */ /* Reads in the choices from the Messages file, */ /* filling in the global_choices structure, */ /* 'choices' (see Global.c and Global.h). */ /*************************************************/ static void load_choices(void) { /* First, the user-configurable options from the Choices file. */ /* Set the default home page */ choices.home_page = malloc(strlen(lookup_choice("HomePage:http://www.acorn.co.uk/", 0, 0)) + 1); if (choices.home_page) strcpy(choices.home_page, tokens); else show_error(make_no_memory_error(32)); /* Get the visit history, image history and hotlist paths */ /* by a similar mechanism. */ /* Image history */ choices.image_history_path = malloc(strlen(lookup_choice("ImageHistoryPath:Browse:User.Images", 0, 0)) + 1); if (choices.image_history_path) strcpy(choices.image_history_path, tokens); else show_error(make_no_memory_error(32)); /* Visit history */ choices.history_path = malloc(strlen(lookup_choice("HistoryPath:Browse:User.History", 0, 0)) + 1); if (choices.history_path) strcpy(choices.history_path, tokens); else show_error(make_no_memory_error(32)); /* Hotlist */ choices.hotlist_path = malloc(strlen(lookup_choice("HotlistPath:Browse:User.Hotlist",0,0)) + 1); if (choices.hotlist_path) strcpy(choices.hotlist_path, tokens); else show_error(make_no_memory_error(32)); /* Set the various default colours */ choices.background_colour = (unsigned int) strtoul(lookup_choice("BackColour:0xdddddd00", 0, 0), NULL, 16); choices.text_colour = (unsigned int) strtoul(lookup_choice("TextColour:0x00000000", 0, 0), NULL, 16); choices.link_colour = (unsigned int) strtoul(lookup_choice("LinkColour:0xff000000", 0, 0), NULL, 16); choices.used_colour = (unsigned int) strtoul(lookup_choice("UsedColour:0xbb008800", 0, 0), NULL, 16); choices.followed_colour = (unsigned int) strtoul(lookup_choice("FollColour:0x0000ff00", 0, 0), NULL, 16); choices.selected_colour = (unsigned int) strtoul(lookup_choice("SeleColour:0x00bb0000", 0, 0), NULL, 16); /* Tables */ if (!strcmp(lookup_choice("SupportTables:yes", 0, 0),"yes")) choices.support_tables = 1; if (!strcmp(lookup_choice("TableOuter", 0, 0), "2d")) choices.table_outer = Choices_TableOuter_Always2D; else if (!strcmp(lookup_choice("TableOuter", 0, 0), "3d")) choices.table_outer = Choices_TableOuter_Always3D; else if (!strcmp(lookup_choice("TableOuter", 0, 0), "never")) choices.table_outer = Choices_TableOuter_Never; else choices.table_outer = Choices_TableOuter_Auto; if (!strcmp(lookup_choice("TableInner", 0, 0), "2d")) choices.table_inner = Choices_TableInner_Always2D; else if (!strcmp(lookup_choice("TableInner", 0, 0), "3d")) choices.table_inner = Choices_TableInner_Always3D; else if (!strcmp(lookup_choice("TableInner", 0, 0), "never")) choices.table_inner = Choices_TableInner_Never; else choices.table_inner = Choices_TableInner_Auto; /* Font usage */ choices.font_size = atoi(lookup_choice("FontSize:12", 0, 0)); if (choices.font_size < 6 * 16) choices.font_size = 6 * 16; if (choices.font_size > 24 * 16) choices.font_size = 24 * 16; choices.tt_aspect = atoi(lookup_choice("TTAspect:90", 0, 0)); if (choices.tt_aspect < 50) choices.tt_aspect = 50; if (choices.tt_aspect > 150) choices.tt_aspect = 150; if (!strcmp(lookup_choice("SystemFont:no", 0, 0),"yes")) choices.system_font = 1; if (choices.system_font) choices.font_size = FM_Standard_Size; /* Wake up the font library */ fm_init(choices.system_font, choices.font_size); show_error(fm_define_default_typefaces()); /* Look up the typeface definitions */ { int face; char tokenname[12]; /* Arbitrary limit... Typeface1 to Typeface99 */ for (face = 1; face < 100; face ++) { sprintf(tokenname, "Typeface%d", face); /* Look up the token, exit if it fails */ lookup_choice(tokenname, 0, 0); if (*tokens == '!') break; /* Otherwise, define the typeface */ show_error(fm_define_typeface(tokens)); } } /* Claim basic typefaces based on the above */ fm_claim_basic_typefaces(choices.font_size); /* Default document encoding */ choices.encoding = atoi(lookup_choice("Encoding:4", 0, 0)); /* Page display */ if (!strcmp(lookup_choice("UnderlineLinks:yes", 0, 0), "yes")) choices.underline_links = 1; if (!strcmp(lookup_choice("UseSourceCols:yes", 0, 0), "yes")) choices.use_source_cols = 1; if (!strcmp(lookup_choice("ShowForeground:yes", 0, 0), "yes")) choices.show_foreground = 1; if (!strcmp(lookup_choice("ShowBackground:yes", 0, 0), "yes")) choices.show_background = 1; /* Page layout */ choices.left_margin = atoi(lookup_choice("LeftMargin:1600", 0, 0)); choices.right_margin = atoi(lookup_choice("RightMargin:6400", 0, 0)); choices.quote_margin = atoi(lookup_choice("QuoteMargin:19200", 0, 0)); choices.leading = atoi(lookup_choice("Leading:4", 0, 0)); choices.left_indent = atoi(lookup_choice("LeftIndent:12800", 0, 0)); /* Fetch controls */ /* Limit the number of simultaneous image fetches (I recommend */ /* a minimum of 2, rather than 1, as most efficient). */ choices.maximages = atoi(lookup_choice("MaxImages:5", 0, 0)); if (choices.maximages <= 0) choices.maximages = 1; if (!strcmp(lookup_choice("ClientPull:yes", 0, 0), "yes")) choices.client_pull = 1; if (!strcmp(lookup_choice("SupportFrames:yes", 0, 0), "yes")) choices.support_frames = 1; if (!strcmp(lookup_choice("SupportObject:yes", 0, 0), "yes")) choices.support_object = 1; if (!strcmp(lookup_choice("PlugInControl", 0, 0), "never")) choices.plugin_control = Choices_PlugIns_Never; else if (!strcmp(lookup_choice("PlugInControl", 0, 0), "viewed")) choices.plugin_control = Choices_PlugIns_Viewed; else choices.plugin_control = Choices_PlugIns_ASAP; if (!strcmp(lookup_choice("SeeFetches:no", 0, 0), "yes")) choices.see_fetches = 1; /* Hotlist controls */ if (!strcmp(lookup_choice("SaveHotlist", 0, 0), "never")) choices.save_hotlist = Choices_SaveHotlist_Never; else if (!strcmp(lookup_choice("SaveHotlist", 0, 0), "always")) choices.save_hotlist = Choices_SaveHotlist_Always; else choices.save_hotlist = Choices_SaveHotlist_Once; if (!strcmp(lookup_choice("AddHotlist", 0, 0), "bottom")) choices.add_hotlist = Choices_AddHotlist_Bottom; else choices.add_hotlist = Choices_AddHotlist_Top; if (!strcmp(lookup_choice("HotlistType", 0, 0), "urls")) choices.hotlist_show = Choices_HotlistType_URLs; else choices.hotlist_show = Choices_HotlistType_Descriptions; choices.auto_open_delay = atoi(lookup_choice("AutoOpenDelay:100", 0, 0)); if (choices.auto_open_delay > 1000) choices.auto_open_delay = 1000; if (choices.auto_open_delay < 0) choices.auto_open_delay = 0; choices.auto_scroll_delay = atoi(lookup_choice("AutoScrollDelay:50", 0, 0)); if (choices.auto_scroll_delay > 1000) choices.auto_scroll_delay = 1000; if (choices.auto_scroll_delay < 0) choices.auto_scroll_delay = 0; choices.auto_scroll_margin = atoi(lookup_choice("AutoScrollMargin:48", 0, 0)); if (choices.auto_scroll_margin > 256) choices.auto_scroll_margin = 256; if (choices.auto_scroll_margin < 0) choices.auto_scroll_margin = 0; /* History limits */ choices.max_size = atoi(lookup_choice("MaxSize:16", 0, 0)); choices.image_max_size = atoi(lookup_choice("ImageMaxSize:0", 0, 0)); choices.expiry_age = atoi(lookup_choice("ExpiryAge:604800", 0, 0)); choices.image_expiry_age = atoi(lookup_choice("ImageExpiryAge:1209600", 0, 0)); choices.max_size *= 1024; /* (Convert K to bytes) */ choices.image_max_size *= 1024; if (choices.max_size < 2048 && choices.max_size) choices.max_size = 2048; /* (NB, Note that there's no lower limit placed on image history details) */ if (choices.expiry_age < 60 && choices.expiry_age) choices.expiry_age = 60; if (!strcmp(lookup_choice("ShowURLs:no", 0, 0), "yes")) choices.show_urls = 1; if (!strcmp(lookup_choice("SaveHistory", 0, 0), "never")) choices.save_history = Choices_SaveHistory_Never; else if (!strcmp(lookup_choice("SaveHistory", 0, 0), "always")) choices.save_history = Choices_SaveHistory_Always; else choices.save_history = Choices_SaveHistory_Once; if (!strcmp(lookup_choice("SaveImageHistory", 0, 0), "never")) choices.save_image_history = Choices_SaveImageHistory_Never; else if (!strcmp(lookup_choice("SaveImageHistory", 0, 0), "always")) choices.save_image_history = Choices_SaveImageHistory_Always; else choices.save_image_history = Choices_SaveImageHistory_Once; /* Toolbar controls */ if (!strcmp(lookup_choice("URLbar:yes", 0, 0), "yes")) choices.url_bar = 1; if (!strcmp(lookup_choice("ButtonBar:yes", 0, 0), "yes")) choices.button_bar = 1; if (!strcmp(lookup_choice("StatusBar:yes", 0, 0), "yes")) choices.status_bar = 1; if (!strcmp(lookup_choice("MoveGadgets", 0, 0), "never")) choices.move_gadgets = Choices_MoveGadgets_Never; else if (!strcmp(lookup_choice("MoveGadgets", 0, 0), "at end")) choices.move_gadgets = Choices_MoveGadgets_AtEnd; else choices.move_gadgets = Choices_MoveGadgets_During; /* Window controls */ choices.width = atoi(lookup_choice("Width:1024", 0, 0)); choices.height = atoi(lookup_choice("Height:1280", 0, 0)); choices.override_x = atoi(lookup_choice("OverrideX:0", 0, 0)); choices.override_y = atoi(lookup_choice("OverrideY:0", 0, 0)); if (!strcmp(lookup_choice("SolidResize", 0, 0), "no")) choices.solid_resize = Choices_SolidResize_No; else if (!strcmp(lookup_choice("SolidResize", 0, 0), "always")) choices.solid_resize = Choices_SolidResize_Always; else choices.solid_resize = Choices_SolidResize_Yes; if (!strcmp(lookup_choice("FullScreen:no", 0, 0), "yes")) choices.full_screen = 1; if (!strcmp(lookup_choice("HScroll", 0, 0), "no")) choices.h_scroll = Choices_HScroll_No; else if (!strcmp(lookup_choice("HScroll", 0, 0), "yes")) choices.h_scroll = Choices_HScroll_Yes; else choices.h_scroll = Choices_HScroll_Auto; if (!strcmp(lookup_choice("VScroll", 0, 0), "no")) choices.v_scroll = Choices_HScroll_No; else if (!strcmp(lookup_choice("VScroll", 0, 0), "yes")) choices.v_scroll = Choices_HScroll_Yes; else choices.v_scroll = Choices_HScroll_Auto; /* Reformatter controls */ if (!strcmp(lookup_choice("RefoWait:no", 0, 0), "yes")) choices.refo_wait = 1; if (!strcmp(lookup_choice("RefoHang:no", 0, 0), "yes")) choices.refo_hang = 1; choices.refo_time = atoi(lookup_choice("RefoTime:500", 0, 0)); if (choices.refo_time < 25) choices.refo_time = 25; if (choices.refo_time > 2000) choices.refo_time = 2000; /* Input device controls */ if (!strcmp(lookup_choice("FixedPtr:yes", 0, 0), "yes")) choices.fixed_pointer = 1; if (!strcmp(lookup_choice("HighlightLks:no", 0, 0), "yes")) choices.highlight_links = 1; if (!strcmp(lookup_choice("KeyboardCtl:no", 0, 0), "yes")) choices.keyboard_ctrl = 1; /* Multiuser environments and proxying */ if (!strcmp(lookup_choice("UseProxy:no", 0, 0), "yes")) choices.use_proxy = 1; if (!strcmp(lookup_choice("StartProxy:no", 0, 0), "yes")) choices.start_proxy = 1; lookup_choice("ProxyAddress:http://127.0.0.1/", 0, 0); choices.proxy_address = malloc(strlen(tokens) + 1); if (choices.proxy_address) { strcpy(choices.proxy_address, tokens); } else { show_error(make_no_memory_error(103)); } if (!strcmp(lookup_choice("Clone:yes", 0, 0), "yes")) choices.clone = 1; #ifndef SINGLE_USER /* If compiling for a multiuser environment, set up */ /* a post_in and a post_out path. */ choices.post_in = malloc(strlen(lookup_choice("PostIn:<none>", 0, 0)) + 1); if (choices.post_in) strcpy(choices.post_in, tokens); else show_error(make_no_memory_error(32)); choices.post_out = malloc(strlen(lookup_choice("PostOut:<none>", 0, 0)) + 1); if (choices.post_out) strcpy(choices.post_out, tokens); else show_error(make_no_memory_error(32)); /* Set also the server timeout */ choices.log_in_timeout = atoi(lookup_choice("LITimeout:30", 0, 0)); if (choices.log_in_timeout < 20) choices.log_in_timeout = 20; if (choices.log_in_timeout > 120) choices.log_in_timeout = 120; #endif /* Non user-configurable options from the Controls file */ /* Animation controls */ controls.anim_delay = atoi(lookup_control("AnimSpeed:4", 0, 0)); if (!strcmp(lookup_control("AnimDrift:no", 0, 0), "yes")) controls.anim_drift = 1; if (!strcmp(lookup_control("DBoxAnims:no", 0, 0), "yes")) controls.dbox_anims = 1; /* Main window and general toolbar controls */ controls.minimum_convergence = atoi(lookup_control("MinConvergence:480", 0, 0)); if (!strcmp(lookup_control("DontGrey", 0, 0), "none")) controls.dont_grey = Controls_DontGrey_GreyNone; else if (!strcmp(lookup_control("DontGrey", 0, 0), "history")) controls.dont_grey = Controls_DontGrey_GreyHistoryOnly; else controls.dont_grey = Controls_DontGrey_GreyAll; if (!strcmp(lookup_control("SwapBars:no", 0, 0), "yes")) controls.swap_bars = 1; if (!strcmp(lookup_control("BackWindow:no", 0, 0), "yes")) controls.back_window = 1; if (!strcmp(lookup_control("UseSmall:yes", 0, 0), "yes")) controls.use_small = 1; /* Main and dialler status controls */ if (!strcmp(lookup_control("ClaimHelp:no", 0, 0), "yes")) controls.claim_help = 1; controls.show_help_for = atoi(lookup_control("ShowHelpFor:600", 0, 0)); controls.show_dstat_for = atoi(lookup_control("ShowDStatFor:300", 0, 0)); controls.show_links_for = atoi(lookup_control("ShowLinksFor:200", 0, 0)); controls.show_misc_for = atoi(lookup_control("ShowMiscFor:50", 0, 0)); controls.quantise = atoi(lookup_control("Quantise:5", 0, 0)); controls.progress_update_delay = atoi(lookup_control("ProgressDelay:50", 0, 0)); /* Progress indicator controls */ if (!strcmp(lookup_control("AppendStatus:no", 0, 0), "yes")) controls.append_status = 1; if (!strcmp(lookup_control("UseBrackets:yes", 0, 0), "yes")) controls.use_brackets = 1; /* The ColourProgress option in Controls is a little unusual; it holds */ /* 'no' (NotAColour, see CtrlDefs.h) or a Wimp colour number. Default */ /* to 11 (red, in the standard Wimp palette). */ if (!strcmp(lookup_control("ColourProgress:11", 0, 0), "no")) controls.colour_progress = Controls_ColourProgress_NotAColour; else { controls.colour_progress = atoi(lookup_control("ColourProgress:11", 0, 0)); if (controls.colour_progress > 15) controls.colour_progress = 11; } /* Frame controls */ controls.minimum_frame_height = atoi(lookup_control("MinFrmHeight:48", 0, 0)); controls.minimum_frame_width = atoi(lookup_control("MinFrmWidth:48", 0, 0)); if (!strcmp(lookup_control("KeepHighlight:no", 0, 0), "yes")) controls.keep_highlight = 1; /* Input device controls */ if (!strcmp(lookup_control("KeepCaret:no", 0, 0), "yes")) controls.keep_caret = 1; if (!strcmp(lookup_control("ClearFirst:yes", 0, 0), "yes")) controls.clear_first = 1; if (!strcmp(lookup_control("LockToLine:no", 0, 0), "yes")) controls.lock_to_line = 1; if (!strcmp(lookup_control("IgnoreAdjust:no", 0, 0), "yes")) controls.ignore_adjust = 1; /* Remote hotlist support */ if (!strcmp(lookup_control("AppendURLs:no", 0, 0), "yes")) controls.append_urls = 1; /* Fetch controls */ if (!strcmp(lookup_control("BrickWall:no", 0, 0), "yes")) controls.brick_wall = 1; if (!strcmp(lookup_control("StopWebProxy:no", 0, 0), "yes")) controls.stop_proxy = 1; if (!strcmp(lookup_control("RefoSingle:no", 0, 0), "yes")) controls.refo_single = 1; controls.back_off_at = atoi(lookup_control("BackOffAt:128", 0, 0)); /* Mouse pointer active point offsets */ { int offset; offset = atoi(lookup_control("PtrLnkActvX:5", 0,0)); controls.ptrlnkactvx = (char) offset; offset = atoi(lookup_control("PtrLnkActvY:1", 0,0)); controls.ptrlnkactvy = (char) offset; offset = atoi(lookup_control("PtrMapActvX:7", 0,0)); controls.ptrmapactvx = (char) offset; offset = atoi(lookup_control("PtrMapActvY:7", 0,0)); controls.ptrmapactvy = (char) offset; offset = atoi(lookup_control("PtrUDActvX:5", 0,0)); controls.ptrudactvx = (char) offset; offset = atoi(lookup_control("PtrUDActvY:8", 0,0)); controls.ptrudactvy = (char) offset; offset = atoi(lookup_control("PtrLRActvX:8", 0,0)); controls.ptrlractvx = (char) offset; offset = atoi(lookup_control("PtrLRActvY:5", 0,0)); controls.ptrlractvy = (char) offset; offset = atoi(lookup_control("PtrUDLRActvX:8",0,0)); controls.ptrudlractvx = (char) offset; offset = atoi(lookup_control("PtrUDLRActvY:5",0,0)); controls.ptrudlractvy = (char) offset; offset = atoi(lookup_control("PtrNoRActvX:7", 0,0)); controls.ptrnoractvx = (char) offset; offset = atoi(lookup_control("PtrNoRActvY:7", 0,0)); controls.ptrnoractvy = (char) offset; offset = atoi(lookup_control("PtrToSActvX:0", 0,0)); controls.ptrtosactvx = (char) offset; offset = atoi(lookup_control("PtrToSActvY:0", 0,0)); controls.ptrtosactvy = (char) offset; offset = atoi(lookup_control("PtrScrActvX:8", 0,0)); controls.ptrscractvx = (char) offset; offset = atoi(lookup_control("PtrScrActvY:8", 0,0)); controls.ptrscractvy = (char) offset; } #ifdef TRACE self_test(); #endif /* Install any general handlers that might be needed as a */ /* result of the choices just loaded. */ show_error(event_register_wimp_handler(-1, Wimp_ELoseCaret, handle_lose_caret, NULL)); if (controls.claim_help) { /* Interactive help support for showing help in the status bar */ register_null_claimant(Wimp_ENull, protocols_ih_send_help_request, NULL); show_error(event_register_message_handler(Wimp_MHelpReply, handle_messages, NULL)); } } #ifdef TRACE /*************************************************/ /* self_test() */ /* */ /* Run through a few standard startup trace */ /* build output routines. */ /*************************************************/ static void self_test(void) { /* This list is somewhat out of date...! Still, it served */ /* its purpose in the early days of the above routines, */ /* and gives a useful overview for the Rout debug option */ /* during startup. */ if (tl & (1u<<5)) { Printf("\nWidth: %d\n" "Height: %d\n", choices.width, choices.height); Printf("\nBack colour: %p\n" "Text colour: %p\n" "Link colour: %p\n" "Used colour: %p\n", (void *) choices.background_colour, (void *) choices.text_colour, (void *) choices.link_colour, (void *) choices.used_colour); Printf("\nSystem font: %d\n" "Show foreground images: %d\n" "Show background images: %d\n" "Fixed pointer: %d\n" "Underline links: %d\n" "Use document colours: %d\n" "URL bar: %d\n" "Button bar: %d\n" "Status bar: %d\n" "Move gadgets: %d\n" "Use a proxy: %d\n\n", choices.system_font, choices.show_foreground, choices.show_background, choices.fixed_pointer, choices.underline_links, choices.use_source_cols, choices.url_bar, choices.button_bar, choices.status_bar, choices.move_gadgets, choices.use_proxy); } /* Test URL to leafname translation */ if (tl & (1<<26)) { char leafname[1024]; char * canonicalised = NULL; #define TestLeaf(str) {urlutils_leafname_from_url((str), leafname, sizeof(leafname)); Printf("%s ", leafname);} Printf("Checking URL to Leafname translation\n"); Printf("====================================\n\n"); /* First, with protocols */ TestLeaf("http://www.acorn.com/"); TestLeaf("http://www.acorn.com"); TestLeaf("http:/www.acorn.com/"); TestLeaf("http:www.acorn.com/"); TestLeaf("http:www.acorn.com"); TestLeaf("http://www.acorn.com:80/"); TestLeaf("http://www.acorn.com:80"); TestLeaf("http:/www.acorn.com:80/"); TestLeaf("http:www.acorn.com:80/"); TestLeaf("http:www.acorn.com:80"); Printf("\n"); TestLeaf("http://www.acorn.com/thing1.html"); TestLeaf("http:/www.acorn.com/thing2.html"); TestLeaf("http:www.acorn.com/thing3.html"); TestLeaf("http://www.acorn.com:80/thing4.html"); TestLeaf("http:/www.acorn.com:80/thing5.html"); TestLeaf("http:www.acorn.com:80/thing6.html"); Printf("\n"); TestLeaf("http://www.acorn.com/dir/dthing1.html"); TestLeaf("http:/www.acorn.com/dir/dthing2.html"); TestLeaf("http:www.acorn.com/dir/dthing3.html"); TestLeaf("http://www.acorn.com:80/dir/dthing4.html"); TestLeaf("http:/www.acorn.com:80/dir/dthing5.html"); TestLeaf("http:www.acorn.com:80/dir/dthing6.html"); Printf("\n"); TestLeaf("http://www.acorn.com/dir/dthing1.tz.html"); TestLeaf("http:/www.acorn.com/dir/dthing2.tz.html"); TestLeaf("http:www.acorn.com/dir/dthing3.tz.html"); TestLeaf("http://www.acorn.com:80/dir/dthing4.tz.html"); TestLeaf("http:/www.acorn.com:80/dir/dthing5.tz.html"); TestLeaf("http:www.acorn.com:80/dir/dthing6.tz.html"); Printf("\n"); TestLeaf("http://www.acorn.com/dir1/"); TestLeaf("http:/www.acorn.com/dir2/"); TestLeaf("http:www.acorn.com/dir3/"); TestLeaf("http://www.acorn.com:80/dir4/"); TestLeaf("http:/www.acorn.com:80/dir5/"); TestLeaf("http:www.acorn.com:80/dir6/"); Printf("\n"); TestLeaf("http://www.acorn.com/dirs1"); TestLeaf("http:/www.acorn.com/dirs2"); TestLeaf("http:www.acorn.com/dirs3"); TestLeaf("http://www.acorn.com:80/dirs4"); TestLeaf("http:/www.acorn.com:80/dirs5"); TestLeaf("http:www.acorn.com:80/dirs6"); Printf("\n"); TestLeaf("http://www.acorn.com/dirs1#anc1"); TestLeaf("http:/www.acorn.com/dirs2#anc2"); TestLeaf("http:www.acorn.com/dirs3#anc3"); TestLeaf("http://www.acorn.com:80/dirs4#anc4"); TestLeaf("http:/www.acorn.com:80/dirs5#anc5"); TestLeaf("http:www.acorn.com:80/dirs6#anc6"); Printf("\n"); TestLeaf("http://www.acorn.com/d/irs1#danc1"); TestLeaf("http:/www.acorn.com/d/irs2#danc2"); TestLeaf("http:www.acorn.com/d/irs3#danc3"); TestLeaf("http://www.acorn.com:80/d/irs4#danc4"); TestLeaf("http:/www.acorn.com:80/d/irs5#danc5"); TestLeaf("http:www.acorn.com:80/d/irs6#danc6"); Printf("\n\n"); /* Now without protocols */ TestLeaf("//www.acorn.com/"); TestLeaf("//www.acorn.com"); TestLeaf("/www.acorn.com/"); TestLeaf("www.acorn.com/"); TestLeaf("www.acorn.com"); TestLeaf("//www.acorn.com:80/"); TestLeaf("//www.acorn.com:80"); TestLeaf("/www.acorn.com:80/"); TestLeaf("www.acorn.com:80/"); TestLeaf("www.acorn.com:80"); Printf("\n"); TestLeaf("//www.acorn.com/thing1.html"); TestLeaf("/www.acorn.com/thing2.html"); TestLeaf("www.acorn.com/thing3.html"); TestLeaf("//www.acorn.com:80/thing4.html"); TestLeaf("/www.acorn.com:80/thing5.html"); TestLeaf("www.acorn.com:80/thing6.html"); Printf("\n"); TestLeaf("//www.acorn.com/dir/dthing1.html"); TestLeaf("/www.acorn.com/dir/dthing2.html"); TestLeaf("www.acorn.com/dir/dthing3.html"); TestLeaf("//www.acorn.com:80/dir/dthing4.html"); TestLeaf("/www.acorn.com:80/dir/dthing5.html"); TestLeaf("www.acorn.com:80/dir/dthing6.html"); Printf("\n"); TestLeaf("//www.acorn.com/dir/dthing1.tz.html"); TestLeaf("/www.acorn.com/dir/dthing2.tz.html"); TestLeaf("www.acorn.com/dir/dthing3.tz.html"); TestLeaf("//www.acorn.com:80/dir/dthing4.tz.html"); TestLeaf("/www.acorn.com:80/dir/dthing5.tz.html"); TestLeaf("www.acorn.com:80/dir/dthing6.tz.html"); Printf("\n"); TestLeaf("//www.acorn.com/dir1/"); TestLeaf("/www.acorn.com/dir2/"); TestLeaf("www.acorn.com/dir3/"); TestLeaf("//www.acorn.com:80/dir4/"); TestLeaf("/www.acorn.com:80/dir5/"); TestLeaf("www.acorn.com:80/dir6/"); Printf("\n"); TestLeaf("//www.acorn.com/dirs1"); TestLeaf("/www.acorn.com/dirs2"); TestLeaf("www.acorn.com/dirs3"); TestLeaf("//www.acorn.com:80/dirs4"); TestLeaf("/www.acorn.com:80/dirs5"); TestLeaf("www.acorn.com:80/dirs6"); Printf("\n"); TestLeaf("//www.acorn.com/dirs1#anc1"); TestLeaf("/www.acorn.com/dirs2#anc2"); TestLeaf("www.acorn.com/dirs3#anc3"); TestLeaf("//www.acorn.com:80/dirs4#anc4"); TestLeaf("/www.acorn.com:80/dirs5#anc5"); TestLeaf("www.acorn.com:80/dirs6#anc6"); Printf("\n"); TestLeaf("//www.acorn.com/d/irs1#danc1"); TestLeaf("/www.acorn.com/d/irs2#danc2"); TestLeaf("www.acorn.com/d/irs3#danc3"); TestLeaf("//www.acorn.com:80/d/irs4#danc4"); TestLeaf("/www.acorn.com:80/d/irs5#danc5"); TestLeaf("www.acorn.com:80/d/irs6#danc6"); Printf("\n\n"); /* Minimal URLs */ TestLeaf("www"); TestLeaf("www/dirs"); TestLeaf("www:80/dirs"); TestLeaf("http:www"); TestLeaf("http:www/dirs"); TestLeaf("http:www:80/dirs"); TestLeaf("http:/www"); TestLeaf("http:/www/dirs"); TestLeaf("http:/www:80/dirs"); Printf("\n"); TestLeaf("www/"); TestLeaf("www/dirs/"); TestLeaf("www:80/dirs/"); TestLeaf("http:www/"); TestLeaf("http:www/dirs/"); TestLeaf("http:www:80/dirs/"); TestLeaf("http:/www/"); TestLeaf("http:/www/dirs/"); TestLeaf("http:/www:80/dirs/"); Printf("\n"); TestLeaf("http:///notahost"); TestLeaf("http:///notahost/"); TestLeaf("http:///notahost2.html"); TestLeaf("http:///notahost2.dir/"); TestLeaf("http:///notahost3/find"); Printf("\n\n"); /* Mixed and broken anchor specifications */ TestLeaf("http://www.acorn.com/#d/irs1#danc1"); TestLeaf("http:/www.acorn.com/#d/irs2#danc2"); TestLeaf("http:www.acorn.com/#d/irs3#danc3"); TestLeaf("http://www.acorn.com:80/#d/irs4#danc4"); TestLeaf("http:/www.acorn.com:80/#d/irs5#danc5"); TestLeaf("http:www.acorn.com:80/#d/irs6#danc6"); Printf("\n"); TestLeaf("http://www.acorn.com/#canc1"); TestLeaf("http:/www.acorn.com/#canc2"); TestLeaf("http:www.acorn.com/#canc3"); TestLeaf("http://www.acorn.com:80/#canc4"); TestLeaf("http:/www.acorn.com:80/#canc5"); TestLeaf("http:www.acorn.com:80/#canc6"); Printf("\n"); TestLeaf("http://www.acorn.com/#"); TestLeaf("http:/www.acorn.com/#"); TestLeaf("http:www.acorn.com/#"); TestLeaf("http://www.acorn.com:80/#"); TestLeaf("http:/www.acorn.com:80/#"); TestLeaf("http:www.acorn.com:80/#"); Printf("\n"); TestLeaf("http://www.acorn.com/pre1#"); TestLeaf("http:/www.acorn.com/pre2#"); TestLeaf("http:www.acorn.com/pre3#"); TestLeaf("http://www.acorn.com:80/pre4#"); TestLeaf("http:/www.acorn.com:80/pre5#"); TestLeaf("http:www.acorn.com:80/pre6#"); Printf("\n\n"); Printf("Checking pathname canonicalisation\n"); Printf("==================================\n\n"); #define TestCanonicalise(str) { \ strcpy(leafname, (str)); \ Printf("In : '%s'\n",leafname); \ \ utils_canonicalise_path(leafname, &canonicalised); \ \ if (canonicalised) \ { \ Printf("Out: '%s'\n\n", canonicalised); \ \ free(canonicalised); \ canonicalised = NULL; \ } \ else Printf("Out: (Error)\n\n"); \ } TestCanonicalise("<Browse$Dir>.User.Hotlist"); TestCanonicalise("Browse:User.Hotlist"); TestCanonicalise("<Choices$Write>.WWW.Browser.Hotlist"); TestCanonicalise("Choices:WWW.Browser.Hotlist"); /* * Maybe we don't want this every time...! * * Printf("\n\n"); * Printf("Checking path building\n"); * Printf("======================\n\n"); * * #define TestBuild(str) { \ * _kernel_oserror * e = utils_build_tree((str)); \ * \ * if (!e) Printf("OK : '%s'\n", (str)); \ * else \ * { \ * Printf("Err: '%s'\n", (str)); \ * Printf(" '%s'\n", e->errmess); \ * } \ * } * * TestBuild("Mem::Sprites.$.This"); * TestBuild("Mem::Sprites.$.This.That"); * TestBuild("Mem::Sprites.$.This.That.The.Other"); * TestBuild("ADFS::4.$.Hello.This.Is.A.Test"); * */ } } #endif /*************************************************/ /* termination() */ /* */ /* Called by registration through the atexit */ /* function. Shuts down core functions prior to */ /* the browser exitting (e.g. the Font Manager */ /* can get very tetchy about having font handles */ /* left claimed, so must release them). */ /*************************************************/ void termination(void) { #ifdef TRACE if (tl & (1u<<5)) Printf("termination() called\n"); #endif if (taskmodule_ds_registered) { /* Not interested in any errors, if it fails we can't really */ /* do anything about it at this stage. */ _swix(TaskModule_DeRegisterService, _INR(0,2), 0, 0, task_handle); } close_messages_file(cob); cob = NULL; close_messages_file(chb); chb = NULL; fm_shutdown(); plugin_shutdown(); rma_shutdown(); } /*************************************************/ /* main() */ /* */ /* That which runs before all others. */ /*************************************************/ int main(int argc, char * argv[]) { WimpPollBlock b; int eventcode, time; #ifdef SINGLE_USER int argp = 1; int done_one = 0; #endif #ifdef USE_MALLOC_REPLACEMENT MemHeap_Initialise("Blimey, does this work?"); #endif #ifdef INCLUDE_HEAPGRAPH HeapGraph_RedirectAllocFns(NULL); #endif #ifdef INCLUDE_HIERPROF HierProf_ProfileAllFunctions(); #endif #ifdef INCLUDE_MEMCHECK MemCheck_Init(); MemCheck_InterceptSCLStringFunctions(); MemCheck_RegisterArgs(argc, argv); MemCheck_SetStoreMallocFunctions(1); MemCheck_SetReportFrees(1); MemCheck_SetAutoOutputBlocksInfo(0); #endif #ifdef TRACE /* Non-debug builds have a WimpSlot close to the actual startup */ /* requirements. Debug builds have a huge slotsize because of */ /* all of the debug information, despite this being copied away */ /* by the debugger on startup. This leaves a very large free */ /* chunk within the WimpSlot size in which malloc may operate, */ /* and thus creates a distinctly different environment for the */ /* memory system in a debug build. */ /* */ /* To try and get closer to the non-debug memory usage, TRACE */ /* builds will malloc the following large block in an attempt */ /* to soak up that initial free space. */ malloc(2*1024*1024); #endif /* NB, don't forget to echo any changes here with the duplicate code */ /* just below the setjmp call later. */ signal(SIGOSERROR, catch_errors); /* OS error */ signal(SIGILL, catch_errors); /* Illegal instruction */ signal(SIGSEGV, catch_errors); /* Segment violation */ signal(SIGSTAK, catch_errors); /* Stack overflow */ signal(SIGFPE, catch_errors); /* FPE error */ /* Before initialisation, find out where we ran from - this */ /* software can support different application names, so the */ /* existance of a specific system variable cannot be relied */ /* upon (with the exception of ROM builds). */ { int len; char * item; /* Work out what path to go through */ #ifdef ROM item = "Resources:$.Resources.Browse"; len = strlen(item); #else item = argv[0]; len = strlen(item) - strlen(".!RunImage"); #endif /* Allocate the space, bomb out if it fails */ task_dir = malloc(len + 1); if (!task_dir) { erb.errnum = Utils_Error_Custom_Fatal; strcpy(erb.errmess, "There is insufficient memory to start the browser."); show_error(&erb); } /* Copy the information and ensure it is terminated correctly */ strncpy(task_dir, item, len); task_dir[len] = 0; } #ifdef TRACE malloccount = flexcount = 0; /* Handle -d[ebug] CLI switch; see Global.c for more information. */ /* This must be the first command line argument. */ if (argc >= argp + 1) { if (!strcmp(argv[argp],"-debug") | !strcmp(argv[argp],"-d")) { if (strstr(argv[argp + 1], "MsgT")) tl |= (1u<<0); if (strstr(argv[argp + 1], "TBar")) tl |= (1u<<1); if (strstr(argv[argp + 1], "Null")) tl |= (1u<<2); if (strstr(argv[argp + 1], "Wind")) tl |= (1u<<3); if (strstr(argv[argp + 1], "Menu")) tl |= (1u<<4); if (strstr(argv[argp + 1], "Rout")) tl |= (1u<<5); if (strstr(argv[argp + 1], "Fetc")) tl |= (1u<<6); if (strstr(argv[argp + 1], "Memo")) tl |= (1u<<7); if (strstr(argv[argp + 1], "Refo")) tl |= (1u<<8); if (strstr(argv[argp + 1], "Redr")) tl |= (1u<<9); if (strstr(argv[argp + 1], "Font")) tl |= (1u<<10); if (strstr(argv[argp + 1], "BBox")) tl |= (1u<<11); if (strstr(argv[argp + 1], "LMem")) tl |= (1u<<12); if (strstr(argv[argp + 1], "CMal")) tl |= (1u<<13); if (strstr(argv[argp + 1], "CFle")) tl |= (1u<<14); if (strstr(argv[argp + 1], "Imag")) tl |= (1u<<15); if (strstr(argv[argp + 1], "Hist")) tl |= (1u<<16); if (strstr(argv[argp + 1], "Fram")) tl |= (1u<<17); if (strstr(argv[argp + 1], "Stre")) tl |= (1u<<18); if (strstr(argv[argp + 1], "Circ")) tl |= (1u<<19); if (strstr(argv[argp + 1], "Tabl")) tl |= (1u<<20); if (strstr(argv[argp + 1], "URIH")) tl |= (1u<<21); if (strstr(argv[argp + 1], "KeyC")) tl |= (1u<<22); if (strstr(argv[argp + 1], "RBox")) tl |= (1u<<23); if (strstr(argv[argp + 1], "JScr")) tl |= (1u<<24); if (strstr(argv[argp + 1], "Hotl")) tl |= (1u<<25); if (strstr(argv[argp + 1], "Save")) tl |= (1u<<26); if (strstr(argv[argp + 1], "Drag")) tl |= (1u<<27); if (strstr(argv[argp + 1], "MsgP")) tl |= (1u<<28); if (strstr(argv[argp + 1], "Choi")) tl |= (1u<<29); if (strstr(argv[argp + 1], "Plug")) tl |= (1u<<30); if (strstr(argv[argp + 1], "All")) tl = 0xffffffff; argp += 2; } } if (tl & (1u<<5)) Printf("\nmain: Initialising\n"); #endif /* Now do the bulk of application initialisation */ initialise_app(); #ifdef TRACE if (tl & (1u<<5)) Printf("main: Loading choices\n"); #endif load_choices(); #ifndef SINGLE_USER /* Multiuser builds need a unique filename base. Do this */ /* checking Post_In / Post_Out as the Set Post_In / */ /* Post_Out dialogue box handler will expect to be able */ /* to go straight to multiuser_login(). */ multiuser_create_unique_postbox_filename(); /* Want to check for Post_On / Post_Out exist at least */ /* as readable directories or image files. If not, we */ /* should open the Set Post_In / Post_Out dialogue box */ /* rather than log in, and let that start up the */ /* log-in procedure for us. */ { int in_ok = 0; int out_ok = 0; setpboxes_check_boxes(&in_ok, &out_ok); if (!in_ok || !out_ok) show_error(setpboxes_show_dialogue()); else show_error(multiuser_login()); } #else /* Load the visit history, image history and hotlist */ /* (this will be the single user version of the login */ /* call). */ show_error(multiuser_login()); #endif /* Try to start the proxy server if necessary */ if (choices.start_proxy) { unsigned int handle = 0; utils_get_task_handle(lookup_token("ProxyName:Acorn WebServe",0,0), &handle); if (!handle) { #ifdef TRACE if (tl & (1u<<5)) Printf("main: Starting proxy server\n"); #endif _swix(Wimp_StartTask, _IN(0), lookup_token("ProxyComm:Filer_Run WebServe:!Run",0,0)); } #ifdef TRACE else { if (tl & (1u<<5)) Printf("main: Proxy server already running\n"); } #endif } #ifdef TRACE if (tl & (1u<<5)) Printf("main: Handling CLI arguments\n"); #endif /* If using keyboard control, watch the pointer for movement, */ /* turning it off if not moved for 5 seconds. */ if (choices.keyboard_ctrl) mouse_watch_pointer_control(1); /* Command line arguments aren't of interest to a multiuser build */ /* because it will never have logged in by this point, so it can't */ /* sensibly deal with fetching pages yet. */ #ifdef SINGLE_USER /* Keep advancing argp if the arguments are dealt with; */ /* only continue to check the arguments if we haven't */ /* pushed argp past argc, the total number of arguments. */ done_one = 1; while (argc >= argp && done_one) { done_one = 0; /* Handle -html (HTML files) */ if (argc >= argp + 1) { if (!strcmp(argv[argp], "-html")) { char url[Limits_URL]; #ifdef TRACE if (tl & (1u<<5)) Printf("main: Handling -html CLI argument\n"); #endif StrNCpy0(url, argv[argp + 1]); urlutils_pathname_to_url(url, sizeof(url)); windows_create_browser(url, NULL, NULL, NULL, Windows_CreateBrowser_Normal); argp += 2, done_one = 1; } } /* Handle -uri (URI files) */ if (argc >= argp + 1) { if (!strcmp(argv[argp], "-uri")) { char url[Limits_URL]; #ifdef TRACE if (tl & (1u<<5)) Printf("main: Handling -uri CLI argument\n"); #endif urlutils_load_uri_file(url, sizeof(url), NULL, 0, argv[argp + 1]); windows_create_browser(url, NULL, NULL, NULL, Windows_CreateBrowser_Normal); argp += 2, done_one = 1; } } /* Handle -url (URL strings) */ if (argc >= argp + 1) { if (!strcmp(argv[argp],"-url") || !strcmp(argv[argp],"-u")) { #ifdef TRACE if (tl & (1u<<5)) Printf("main: Handling -url CLI argument\n"); #endif windows_create_browser(argv[argp+1], NULL, NULL, NULL, Windows_CreateBrowser_Normal); argp += 2, done_one = 1; } } } #endif #ifdef TRACE if (tl & (1u<<5)) Printf("main: Polling\n"); #endif atexit(termination); /* Long jump handler - most nasty or generally unexpected */ /* errors will come back to here. The OS error abort */ /* handler jumps back here to deal with the error as we */ /* then have a clear stack; this is to avoid 'no stack */ /* for trap handler' errors caused by a SWI corrupting */ /* the value of R10. */ if (setjmp(env) == Main_FromCatchErrors) { char * tok = NULL; unsigned int * regdump = NULL; unsigned int * os_regdump = NULL; char pc[16]; print_abort_print(); /* Sort out the register dump */ _swix(OS_ChangeEnvironment, _INR(0,3) | _OUT(3), 7, /* Call back */ 0, 0, 0, ®dump); /* Where the C library put the registers */ _swix(OS_ChangeEnvironment, _INR(0,3) | _OUT(1), 13, /* Exception registers */ 0, 0, 0, &os_regdump); /* Where *ShowRegs gets them from */ /* Copy the C register dump into the OS space */ if (regdump && os_regdump) memcpy(os_regdump, regdump, 4 * 16); /* Store a more sensible error in the error block 'erb' where possible. */ switch (erb.errnum) { case 0x80000000: tok = "EZeros0"; break; case 0x80000001: tok = "EZeros1"; break; case 0x80000002: tok = "EZeros2"; break; case 0x80000003: tok = "EZeros3"; break; case 0x80000005: tok = "EZeros5"; break; } if (tok) { char * error; /* If we know the PC, put this in the message */ if (!regdump) sprintf(pc, "&deaddead"); else sprintf(pc, "&%08X", os_regdump[15] &~ 0xfc000003); error = lookup_token(tok, 0, pc); /* If the message token wasn't found, use the OS error, */ /* otherwise copy the new one into the error block. */ if (strcmp(error, "!")) StrNCpy0(erb.errmess, error); } /* Need to reinstall the signal handlers since the run-time */ /* system will have removed them 'for your saftey and */ /* convenience (TM)'. Don't forget to keep this list up to */ /* date with the code near the top of the function. */ signal(SIGOSERROR, catch_errors); /* OS error */ signal(SIGILL, catch_errors); /* Illegal instruction */ signal(SIGSEGV, catch_errors); /* Segment violation */ signal(SIGSTAK, catch_errors); /* Stack overflow */ signal(SIGFPE, catch_errors); /* FPE error */ show_error_cont(&erb); } while (!quit) { /* We use flex's deferred compaction, so ensure the */ /* heap is as small as possible. */ flex_compact(); /* What time is it? (For Wimp_PollIdle) */ _swix(OS_ReadMonotonicTime, _OUT(0), &time); /* Use PollIdle, but want drag events to be as responsive as possible */ ChkError(event_poll_idle(&eventcode, &b, time + !drag_in_progress, NULL)); } #ifdef TRACE if (tl & (1u<<5)) Printf("\nmain: Calling exit()\n\n"); if (tl & (1u<<13)) Printf("Near exit, malloccount: \0216%d\0217\n",malloccount); if (tl & (1u<<14)) Printf("Near exit, flexcount : %d\n",flexcount); #endif /* Save hotlist, histories etc., and logout if a multiuser build */ show_error_ret(multiuser_logout()); /* This will call the termination() function in passing */ exit(EXIT_SUCCESS); } /*************************************************/ /* catch_errors() */ /* */ /* Catch OS errors and report them with the */ /* opportunity to continue or quit (done inside */ /* main itself). */ /* */ /* This is the last function in the file since */ /* it plays around with stack checking, and you */ /* can't read the previous state. If this was in */ /* the middle of the source and someone wrote a */ /* #pragma above it, endless confusion could */ /* otherwise arise as to why the instruction had */ /* no effect on some of the functions here... */ /* */ /* Parameters: The signal number (ignored). */ /*************************************************/ #pragma no_check_stack static void catch_errors(int signum) { /* Store the error locally */ erb = *_kernel_last_oserror(); /* Go back to main to report the error */ longjmp(env, Main_FromCatchErrors); /* Just in case... */ exit(EXIT_FAILURE); }