/* 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 : History.c */ /* Purpose: History functions for the browser */ /* Author : A.D.Hodgkinson */ /* History: 07-Feb-97: Created */ /***************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include "kernel.h" #include "swis.h" #include "flex.h" #include "wimp.h" #include "wimplib.h" #include "event.h" #include "toolbox.h" #include "window.h" #include "gadgets.h" #include "menu.h" #include "svcprint.h" #include "Global.h" #include "FromROSLib.h" #include "TBEvents.h" #include "Utils.h" #include "Browser.h" #include "FetchPage.h" #include "Memory.h" #include "Toolbars.h" #include "Windows.h" #include "History.h" /* Static variables */ static void * global_history = NULL; static void * view_history_menu = NULL; /* Static function prototypes */ static char * history_title(char * url); // void browser_save_history(void) // { // char command[sizeof(user.historyfile)+32]; // // sprintf(command,"Save %s %p +%x",user.historyfile,global_history,flex_size(&global_history)); // os_cli(command); // } // // void browser_lose_history(void) // { // if(global_history) // { // flex_free(&global_history); // global_history=NULL; // } // if(authorise) // { // flex_free(&authorise); // authorise=NULL; // } // } // // /*----------------------------------------------------------------------*/ // void browser_load_history(void) // { // browser_lose_history(); // load_file_into_flex(user.historyfile,&global_history); // } // // // static int hotlist_make_history_file(int count,browser_data * b,char *filename) // { /* make the history export file or, if count is 1, just get its length. // If filename is set, write to it, otherwise use the save library. */ // int length,i; // char title[100]; // char buffer[200]; // char *p,*e; // FILE *f=NULL; // // length=0; // if(filename) // { // f=fopen(filename,"w"); // if(!f) // { // show_error_ret((_kernel_oserror *) _kernel_last_oserror()); // // return 0; // } // } // sprintf(title,msgs_lookup("HTITLEH:Browser history list for %s"),user.name); // sprintf(buffer,"<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n",title); // hotlist_output(buffer,count,&length,f); // sprintf(buffer,"<h1>%s</h1>\n<p><dl>\n",title); // hotlist_output(buffer,count,&length,f); // p=(char*)global_history; // e=p+flex_size(&global_history)-1; // while(p && p<e) // { // p+=sizeof(int); // hotlist_output(" <dt><a href=\"",count,&length,f); // hotlist_output(p,count,&length,f); // hotlist_output("\">",count,&length,f); // hotlist_output(p,count,&length,f); // p+=strlen(p)+1; // while((int)p&3) p++; /* word aligned */ // hotlist_output("</a>\n",count,&length,f); // } // hotlist_output("</dl><p>\n</body>\n</html>\n",count,&length,f); // if(!count) length=!length; // if(f) fclose(f); // return(length); // } // static int hotlist_history_saver(void *handle,char *pathname) // { // pathname=pathname; // return(hotlist_make_history_file(0,(browser*)handle,NULL)); // } // // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ // static int hotlist_file_history_size(browser_data * b) // { // return(hotlist_make_history_file(1,b,NULL)); // } // // /*----------------------------------------------------------------------*/ /*************************************************/ /* history_title() */ /* */ /* Returns a pointer to the title string for a */ /* given URL in the global history, or NULL if */ /* the URL can't be found / the global history */ /* is empty. NULL is also returned if the title */ /* string is of zero length. */ /* */ /* This pointer is in a flex block, so beware of */ /* flex block shifts when using it. */ /* */ /* Parameters: Pointer to the URL. */ /* */ /* Returns: Pointer to the title string, or */ /* NULL if the URL isn't found / the */ /* global history is empty / the */ /* title string is of zero length. */ /*************************************************/ static char * history_title(char * url) { int entry; #ifdef TRACE if (tl & (1u<<16)) Printf("history_title: Called with URL '%s'\n", url); #endif /* If history is empty, return NULL */ if (!global_history) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_title: Exitting, the history is empty\n", url); #endif return NULL; } /* Find the offset of the history entry */ entry = history_visited(url, 0); /* Return NULL if the URL wasn't found */ if (entry < 0) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_title: Exitting, the URL wasn't found\n", url); #endif return NULL; } /* Else calculate the offset of the title string */ entry += sizeof(int); entry += strlen((char *) ((int) global_history + entry)) + 1; /* If the string is zero length return NULL, else */ /* return a pointer to it. */ if (!strlen((char *) ((int) global_history + entry))) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_title: Exitting, the title was a null string\n", url); #endif return NULL; } #ifdef TRACE if (tl & (1u<<16)) Printf("history_title: Successful, pointing to '%s'\n", (char *) ((int) global_history + entry)); #endif return (char *) ((int) global_history + entry); } /*************************************************/ /* history_visited() */ /* */ /* Returns an offset into the global history if */ /* a given URL has been visited before (i.e. is */ /* in the global history), optionally */ /* timestamping it if it's there. */ /* */ /* Parameters: Pointer to the URL; */ /* 1 to timestamp it, else 0. */ /* */ /* Returns: -1 if the item is not in the */ /* global history, else an offset */ /* into the history of the item. */ /*************************************************/ int history_visited(char * url, int stamp) { int offset = 0; #ifdef TRACE if (tl & (1u<<16)) Printf("history_visited: Called with URL '%s'\n", url); #endif if (global_history) { int e; /* If the history exists, set e to the offset of the end */ e = flex_size(&global_history) - 1; /* Loop around inside the history list, searching for the given URL */ while (offset < e) { /* If the URL is found, timestamp it if required and exit, */ /* returning the offset of this entry. */ //Printf("comparing '%s'\n" // "to '%s'\n\n",url,(char *) global_history + offset + sizeof(int)); if (!strcmp((char *) global_history + offset + sizeof(int), url)) { if (stamp) *(int *) ((char *) global_history + offset) = time(NULL); #ifdef TRACE if (tl & (1u<<16)) Printf("history_visited: Succesful, found URL\n"); #endif return offset; } /* Jump past the current entry (i.e. a timestamp plus the two */ /* strings that follow including terminators, word aligned). */ offset += sizeof(int); offset += strlen((char *) global_history + offset) + 1; offset += strlen((char *) global_history + offset) + 1; offset = (int) WordAlign(offset); } } /* URL not found - return -1. */ #ifdef TRACE if (tl & (1u<<16)) Printf("history_visited: Successful, but URL was not found\n"); #endif return -1; } /*************************************************/ /* history_record_global() */ /* */ /* Records a URL in the global history. The URL */ /* must NOT be in a flex block, as this routine */ /* may allocate flex store which could lead to */ /* other blocks shifting, invalidating the URL */ /* pointer passed in. */ /* */ /* Parameters: Pointer to a URL, which is not in */ /* a flex block. */ /*************************************************/ _kernel_oserror * history_record_global(char * url) { /* Proceed if the URL isn't already in the history */ #ifdef TRACE if (tl & (1u<<16)) Printf("history_record_global: Called with URL '%s'\n", url); #endif if (history_visited(url, 1) < 0) { int len, oldsize, ok; // toolbars_hide_internal(url); #ifdef TRACE if (tl & (1u<<16)) Printf("history_record_global: Proceeding\n", url); #endif /* Set 'len' to the size of this entry; the */ /* URL plus terminator, null title string, */ /* and the timestamp, word aligned. */ len = strlen(url) + 1 + 1 + sizeof(int); len = (int) WordAlign(len); if (global_history) { /* If the history already exists, may need to ensure */ /* it hasn't got too long */ while ( flex_size(&global_history) > 4 && (flex_size(&global_history) + len) > choices.maxghistory * 1024 ) { /* As long as the history is oversized, delete the oldest entry */ int size, oldest = *(int *) global_history; char * e; char * f = NULL; char * p = (char *) global_history; e = p + flex_size(&global_history) - 1; f = p; /* Search for the oldest entry */ while (p < e) { if (*(int *) p < oldest) { oldest = *(int *) p; f = p; } p += sizeof(int); p += strlen(p) + 1; /* Get past URL */ p += strlen(p) + 1; /* Get past title */ p = WordAlign(p); } /* Get the size of this oldest entry */ size = strlen(f + sizeof(int)) + 1; /* Length of URL plus terminator */ size = sizeof(int) + size + strlen(f + sizeof(int) + size) + 1; size = (int) WordAlign(size); /* Copy entries above the entry down over it */ /* and shrink the flex block as appropriate */ memmove(f, f + size, (e - f) - size); #ifdef TRACE flexcount -= size; if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); #endif flex_extend(&global_history, flex_size(&global_history) - size); } /* Allocate space for the entry */ oldsize = flex_size(&global_history); ok = flex_extend(&global_history, oldsize + len); #ifdef TRACE if (ok) { flexcount += len; if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); } #endif } /* If the history doesn't exist, create it */ else { oldsize = 0; ok = flex_alloc(&global_history, len); #ifdef TRACE if (ok) { flexcount += len; if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); } #endif } if (!ok) { erb.errnum = Utils_Error_Custom_Normal; StrNCpy0(erb.errmess, lookup_token("NoMemGHi:There is not enough free memory to add the page to the global history.", 0, 0)); #ifdef TRACE if (tl & (1u<<16)) Printf("history_record_global: Exitting with error\n", url); #endif return &erb; } /* Add the entry */ *(int *) ((char *) global_history + oldsize) = time(NULL); /* Timestamp */ strcpy(((char *) global_history + oldsize) + sizeof(int), url); /* URL string */ strcpy(((char *) global_history + oldsize) + sizeof(int) + strlen(url) + 1, ""); /* Null title string */ } #ifdef TRACE if (tl & (1u<<16)) Printf("history_record_global: Successful\n", url); #endif return NULL; } /*************************************************/ /* history_record_local() */ /* */ /* Records a URL in the local (view) history. */ /* The URL must NOT be in a flex block, as this */ /* routine may allocate flex store which could */ /* lead to other blocks shifting, invalidating */ /* the URL Pointer passed in. */ /* */ /* If the URL pointer is NULL, then the current */ /* URL as returned by browser_current_url() in */ /* Windows.c will be added. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the history; */ /* Pointer to the URL, which must */ /* not be in a flex block. */ /*************************************************/ _kernel_oserror * history_record_local(browser_data * b, char * url) { _kernel_oserror * e; #ifdef TRACE if (tl & (1u<<16)) Printf("history_record_local: Called with %p\n", (void *) b); #endif if (!url) url = browser_current_url(b); /* If we're in the history, truncate it to avoid circular references. */ /* Don't bother freeing memory here, it'll be set to the required */ /* amount next time an addition is made anyway. */ if (b->hpos) { b->hnum = b->hpos; b->hpos = 0; } /* Otherwise, provided we've a URL, proceed. */ else if (url && *url) { int bytes, count, needed, len; char * p; char * last = NULL; bytes = 0; p = b->histdata; count = b->hnum; /* Point to the last entry */ while (count--) { /* Get past the URL */ len = strlen(p) + 1; last = p; bytes += len; p += len; } /* If the given URL matches the last one on the history list, */ /* there's nothing to add. */ #ifdef TRACE if (tl & (1u<<16)) Printf("history_record_local: Exitting with no action\n"); #endif if (last && !strcmp(last, url)) return NULL; /* Needed = space required to store URL plus terminator. */ needed = strlen(url) + 1; /* Allocate the memory and store the URL */ e = memory_set_chunk_size(b, NULL, CK_HIST, bytes + needed); if (e) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_record_local: Exitting (error from memory_set_chunk_size)\n", (void *) b); #endif return e; } strcpy(b->histdata + bytes, url); toolbars_hide_internal(b->histdata + bytes); b->hnum ++; bytes += strlen(b->histdata + bytes) + 1; while(b->hnum > choices.maxvhistory) { /* If the history is oversized, remove old entries. */ /* 'count' = length of the bottom (oldest) entry. */ count = strlen(b->histdata) + 1; /* Copy the newer entries down over the old and */ /* decrement the entries counter. Again, no need */ /* to free memory as the next history addition */ /* will allocate the required amount anyway. */ memmove(b->histdata, b->histdata + count, bytes - count); b->hnum--; } } #ifdef TRACE if (tl & (1u<<16)) Printf("history_record_local: Successful\n", (void *) b); #endif return NULL; } /*************************************************/ /* history_pull_local_last() */ /* */ /* Copies the last visited URL, according to the */ /* local history, to the given buffer. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the history; */ /* Pointer to the buffer (not in a */ /* flex block!); */ /* Size of the buffer. */ /* */ /* Assumes: That neither pointer is NULL. */ /*************************************************/ void history_pull_local_last(browser_data * b, char * last, int size) { char * p; int count; // This function doesn't work yet... =8*O #ifdef TRACE Printf("** history_pull_local_last: Not run\n"); #endif return; count = b->hnum; if (count <= 0) { *last = 0; return; } /* Get a pointer to the URL */ p = b->histdata; while(--count > 0) p += strlen(p) + 1; strncpy(last, p, size - 1); last[size - 1] = 0; return; } /*************************************************/ /* history_add_title() */ /* */ /* Adds a title for the given URL in the global */ /* history. The title must NOT be stored in a */ /* flex block as this routine may allocate flex */ /* store which could shift the block with the */ /* title in, invalidating the pointer to it. */ /* However, this occurs after the URL is dealt */ /* with, so the URL can be in a flex block. */ /* */ /* If the URL already has a title string, the */ /* existing title is kept. If the URL can't be */ /* found, the function will fail silently. */ /* */ /* Parameters: Pointer to the title string which */ /* is not in a flex block; */ /* Pointer to the URL with which it */ /* is to be associated. */ /* */ /* Assumes: That the title and URL pointers */ /* are not NULL. */ /*************************************************/ _kernel_oserror * history_add_title(char * title, char * url) { int offset, entrysize, pretitle, needed; #ifdef TRACE if (tl & (1u<<16)) Printf("history_add_title: Called with title '%s'\n" " and URL '%s'\n",title,url); #endif /* Exit with an error if the history is empty */ if (!global_history) { erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("EmptyHistE:The history list is empty.", 0, 0)); #ifdef TRACE if (tl & (1u<<16)) Printf("history_add_title: Exitting with error (history is empty)\n"); #endif return &erb; } /* Exit if the URL isn't there. */ offset = history_visited(url, 0); if (offset < 0) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_add_title: Exitting (couldn't find URL)\n"); #endif return NULL; } /* Otherwise, is there already a title string? */ offset += sizeof(int); /* Get past timestamp */ entrysize = strlen((char *) global_history + offset) + 1 + sizeof(int); offset += strlen((char *) global_history + offset) + 1; /* Get past URL */ /* Exit if there was already a title present */ if (strlen((char *) global_history + offset)) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_add_title: Exitting (URL already had a title)\n"); #endif return NULL; } /* Otherwise, extend the flex block. For 'needed', we already have */ /* the terminator of the (currently null) title string in the */ /* history, so don't need to add one to the string length here. */ pretitle = (int) WordAlign(entrysize + 1); /* Word aligned size of the history entry including null title string */ entrysize += strlen(title) + 1; entrysize = (int) WordAlign(entrysize); /* Word aligned size of the history entry including new title string */ needed = entrysize - pretitle; if (!flex_midextend(&global_history, offset, needed)) { erb.errnum = Utils_Error_Custom_Normal; StrNCpy0(erb.errmess, lookup_token("NoMemGHi:There is not enough free memory to add the page to the global history.", 0, 0)); #ifdef TRACE if (tl & (1u<<16)) Printf("history_add_title: Exitting with error\n", url); #endif return &erb; } #ifdef TRACE flexcount += needed; if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); #endif /* Copy in the URL */ strcpy((char *) global_history + offset, title); /* Success. */ #ifdef TRACE if (tl & (1u<<16)) Printf("history_add_title: Successful\n"); #endif return NULL; } /*************************************************/ /* history_fetch_forwards() */ /* */ /* When called, will fetch the next page in the */ /* history list (assuming we've moved into it */ /* with history_fetch_backwards()). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the history; */ /* 1 to open the URL in a new window */ /* or 0 to open it in the window to */ /* which the browser_data struct is */ /* relevant. */ /*************************************************/ _kernel_oserror * history_fetch_forwards(browser_data * b, int new_view) { /* Can only go forward if we're somewhere within */ /* the local history list... */ #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_forwards: Called with %p\n", (void *) b); #endif if (b->hpos > 0 && b->hpos < b->hnum) { int count; char * p; #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_forwards: Proceeding\n"); #endif /* Set 'count' to the next entry in the list */ count = ++b->hpos; /* Only set up this window to look as though it's gone forwards */ /* if the URL isn't to be opened in a new window. */ if (!new_view) { /* If the position now lies outside of the history, */ /* we've gone forward past its end; set hpos to 0 */ /* to show that we're not in the history and remove */ /* the last item, as that's what will be fetched */ /* now and 'back' shouldn't then go back to it */ /* again. */ if (b->hpos >= b->hnum) { b->hpos = 0; if (b->hnum > 0) b->hnum--; } } /* Get a pointer to the URL */ p = b->histdata; while (--count) p += strlen(p) + 1; /* Get the URL in either the same window or a new window. */ if (!new_view) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_forwards: Exitting through fetchpage_new()\n"); #endif /* Fetch the URL, flagging not to record this URL in the history */ return (fetchpage_new(b, p, 0)); } else { #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_forwards: Exitting through windows_create_browser()\n"); #endif return windows_create_browser(p, NULL, NULL, NULL); } } #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_forwards: Exitting with no action\n"); #endif return NULL; } /*************************************************/ /* history_fetch_backwards() */ /* */ /* When called, will fetch the previous page in */ /* the history list. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the history; */ /* 1 to open the URL in a new window */ /* or 0 to open it in the window to */ /* which the browser_data struct is */ /* relevant. */ /*************************************************/ _kernel_oserror * history_fetch_backwards(browser_data * b, int new_view) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_backwards: Called with %p\n", (void *) b); #endif /* Only proceed if we're not right at the start of the history */ /* (hpos > 1) or we're not in the history at all (hpos = 0). */ if ((b->hpos > 1 || b->hpos == 0) && b->hnum) { int count; char * p; #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_backwards: Proceeding\n"); #endif /* Need to be careful manipulating the history, as if the */ /* URL is to be opened in a new view then the position of */ /* this window in its history is unchanged. */ if (b->hpos == 0) { _kernel_oserror * e; /* If not already in the history list... */ if (!new_view) { /* Ensure the current URL is put at the top of the history */ e = history_record_local(b, NULL); if (e) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_backwards: Exitting with error\n"); #endif return e; } } /* Step backwards. */ count = b->hnum - 1; if (count < 1) count = 1; if (!new_view) b->hpos = count; } /* If already in the history list, just step back again. */ else { count = b->hpos - 1; if (!new_view) b->hpos--; } /* Get a pointer to the URL */ p = b->histdata; while(--count > 0) p += strlen(p) + 1; /* Get the URL in either the same window or a new window. */ if (!new_view) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_backwards: Exitting through fetchpage_new()\n"); #endif /* Fetch the URL, flagging not to record this URL in the history */ return (fetchpage_new(b, p, 0)); } else { #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_backwards: Exitting through windows_create_browser()\n"); #endif return windows_create_browser(p, NULL, NULL, NULL); } } #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_backwards: Exitting with no action\n"); #endif return NULL; } /*************************************************/ /* history_build_menu() */ /* */ /* Builds a history menu for the given browser, */ /* showing it at the specified coordinates. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the menu; */ /* */ /* x coordinate to show at; */ /* */ /* y coordinate to show at; */ /* */ /* Non-0 to only show URLs, 0 to */ /* allow titles in the menu; */ /* */ /* Non-0 to subtract the width of */ /* the menu from the given show x */ /* coordinate (e.g. to show to the */ /* left of a given position) else 0. */ /*************************************************/ _kernel_oserror * history_build_menu(browser_data * b, int x, int y, int show_urls, int subtract) { wimp_menuhdr * mhp; wimp_menuitem * mip; int size, i, offset, width, awidth, tempwidth, len, entry; int cspacing = 0, cwidth = 0; char * menudata; char * title; #ifdef TRACE if (tl & (1u<<16)) Printf("history_build_menu: Called with %p\n", (void *) b); #endif /* If there are no history items, flag an error. */ if (!b->hnum) { erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("EmptyHistE:The history list is empty.", 0, 0)); #ifdef TRACE if (tl & (1u<<16)) Printf("history_build_menu: Exitting (history is empty)\n"); #endif return &erb; } /* Work out the data size required for the menu structure. */ /* Can't just point the menu to the history list as it's a */ /* flex block, which may shift whilst the menu is open. */ size = sizeof(wimp_menuhdr); offset = 0; width = 8; awidth = 0; if (!nested_wimp) { /* Find out the spacing (start of one char to start of next) */ /* and width of the text the Wimp is using, assuming that if */ /* there is no nested wimp, Wimp_TextOp is unavailable. */ int vars[3] = {BBC_GCharSizeX, BBC_GCharSpaceX, -1}; _swix(OS_ReadVduVariables, _INR(0, 1), &vars, &vars); cwidth = vars[0]; cspacing = vars[1]; } /* Loop round finding the string length of the longest entry */ /* in 'width' and the OS unit width of it in 'awidth'. */ for (i = 0; i < b->hnum; i++) { len = strlen(b->histdata + offset) + 1; entry = history_visited(b->histdata + offset, 0); title = history_title(b->histdata + offset); /* If the URL isn't in the history or it has no title, */ /* or if the global choices dictate it, use the URL. */ if (entry < 0 || !title || show_urls) { size += len + sizeof(wimp_menuitem); if ((len - 1) > width) width = len - 1; /* Find the width of the entry in OS units. If nested_wimp */ /* is set assume Wimp_TextOp is available, else assume it */ /* is not available. */ if (nested_wimp) _swix(Wimp_TextOp, _INR(0,2) | _OUT(0), 1, b->histdata + offset, width, &tempwidth); /* Spacing is width of char plus the gap between it and the */ /* next one. String length is in 'width', so want to do */ /* (width - 1) lots of spacing plus the last char's width. */ else tempwidth = (width - 1) * cspacing + cwidth; } else { int tlen; tlen = strlen(title); size += tlen + 1 + sizeof(wimp_menuitem); if (tlen > width) width = tlen; /* See above code for comments */ if (nested_wimp) _swix(Wimp_TextOp, _INR(0,2) | _OUT(0), 1, title, width, &tempwidth); else tempwidth = (width - 1) * cspacing + cwidth; } /* If the string is wider than previously recorded, store the new width */ if (tempwidth > awidth) awidth = tempwidth; /* Move past the current URL in the local history */ offset += len; } size += 4; /* Deallocate any existing menu data and allocate the new required size. */ #ifdef TRACE if (tl & (1u<<16)) { if (view_history_menu) Printf("history_build_menu: Freeing existing store\n"); else Printf("history_build_menu: There is no existing store\n"); } #endif if (view_history_menu) free(view_history_menu); #ifdef TRACE if (tl & (1u<<16)) Printf("history_build_menu: Attempting to malloc %d bytes\n",size); #endif view_history_menu = malloc(size); if (!view_history_menu) { erb.errnum = Utils_Error_Custom_Normal; StrNCpy0(erb.errmess, lookup_token("NoMemLHi:There is not enough free memory to open the history menu.", 0, 0)); #ifdef TRACE if (tl & (1u<<16)) Printf("history_build_menu: Exitting (couldn't claim %d bytes for menu)\n", size); #endif return &erb; } /* Ensure the contents are zeroed. */ memset(view_history_menu, 0, size); /* Point mhp to the start of the menu header, and mip */ /* to the first menu item (straight after the header). */ mhp = (wimp_menuhdr *) view_history_menu; mip = (wimp_menuitem *) (((int) mhp) + sizeof(wimp_menuhdr)); /* Fill in the header. */ strncpy(mhp->title, lookup_token("HistMemT:History",0,0), 12); mhp->tit_fcol = 7; mhp->tit_bcol = 2; mhp->work_fcol = 7; mhp->work_bcol = 0; mhp->width = awidth; mhp->height = 44; mhp->gap = 0; /* Pointer arithmetic - mip + b->hnum adds b->hnum lots */ /* of sizeof(mip) to menudata, since the cast to char * */ /* is the last thing that happens. So menudata points */ /* past all the menu structure stuff to the data area. */ menudata = (char *) (mip + b->hnum); offset = 0; /* Fill in each menu item. */ for (i = 0; i < b->hnum; i++) { len = strlen(b->histdata + offset) + 1; entry = history_visited(b->histdata + offset, 0); title = history_title(b->histdata + offset); mip->flags = (i == b->hnum - 1 ? wimp_MLAST : 0); mip->submenu = (wimp_menuptr) -1; mip->iconflags = wimp_ITEXT | wimp_IFILLED | wimp_INDIRECT | (7<<24); mip->data.indirecttext.validstring = NULL; mip->data.indirecttext.bufflen = 0; mip->data.indirecttext.buffer = menudata; /* If the URL isn't in the global history, or it doesn't */ /* have a title string associated with it, or if the */ /* global choices dicate it, use the URL in the menu. */ if (entry < 0 || !title || show_urls) { /* Copy the history item into the data area */ strcpy(menudata, b->histdata + offset); /* Advance the data pointer, possibly removing any */ /* CGI information if HIDE_CGI is defined inside */ /* the compiler. */ #ifdef HIDE_CGI toolbars_hide_cgi(menudata); menudata += strlen(menudata) + 1; #else /* If not hiding all CGI information, still don't want to */ /* put all the CGI stuff in the menu or it can get far too */ /* wide. So leave an indicator to show there was CGI info. */ toolbars_hide_cgi(menudata); if (len > strlen(menudata) + 7) strcat(menudata, " (+CGI)"); else if (len > strlen(menudata) + 4) strcat(menudata, "?..."); menudata += strlen(menudata) + 1; #endif } else { /* Copy the title string in and advance the data pointer */ strcpy(menudata, title); menudata += strlen(title) + 1; } /* Next item... */ offset += len; mip ++; } #ifdef TRACE if (menudata > ((char *) view_history_menu) + size) { erb.errnum = 0; sprintf(erb.errmess,"Fatal error inside history_build_menu(): Overran menu buffer! Allocated %d bytes, then used %d.",size,(int) menudata - (int) view_history_menu); show_error(&erb); } #endif /* Finally, open the menu */ #ifdef TRACE if (tl & (1u<<16)) Printf("history_build_menu: Exitting through wimp_create_menu\n"); #endif menuhdl = (void *) b; menusrc = Menu_History; return wimp_create_menu(view_history_menu, x - (subtract ? (mhp->width + 64) : 0), y); } /*************************************************/ /* history_menu_selection() */ /* */ /* Jumps to a URL according to the item selected */ /* in a history menu. */ /* */ /* If Adjust is used the menu is not reopened as */ /* the fetch will occur in a new window (as with */ /* following page links) - it doesn't make sense */ /* to reopen the menu in this case. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the history; */ /* Pointer to a WimpPollBlock struct */ /* from which the menu item that was */ /* selected may be determined. */ /*************************************************/ _kernel_oserror * history_menu_selection(browser_data * b, WimpPollBlock * block) { int item, adj; char * p; item = block->menu_selection[0]; /* If the menu selection appears to be out of range, */ /* exit quietly. */ if (item < 0 || (item + 1) > b->hnum) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_menu_selection: Warning, menu selection out of range\n"); #endif return NULL; } /* Otherwise find out the button that was used. */ adj = fixed.ignoreadjust ? 0 : adjust(); /* If a new window isn't going to be opened, */ /* need to remember that we've just dived */ /* into the History list so that forwards / */ /* backwards work correctly. */ if (!adj) { /* If jumping from the top of the history, ensure that the */ /* page we're currently on is added to it first. */ if (!b->hpos) { _kernel_oserror * e; /* Ensure the current URL is put at the top of the history */ e = history_record_local(b, NULL); if (e) { #ifdef TRACE if (tl & (1u<<16)) Printf("history_fetch_backwards: Exitting with error\n", (void *) b); #endif return e; } } /* Set the position in the history */ b->hpos = item + 1; /* Is this the end of the history? */ if (b->hpos == b->hnum) b->hpos = 0; } /* Point to the required entry in the history. */ p = b->histdata; while (item--) { /* Get past each URL... */ p += strlen(p) + 1; } /* Flag that there is no known menu source anymore */ /* and fetch the new URL. */ menusrc = Menu_None; /* Somewhat non-standard behaviour to have an adjust-click */ /* open a new window instead of leaving the menu up, but */ /* this is more consistent with the rest of the browser UI. */ if (!adj) return fetchpage_new(b, p, 0); else return windows_create_browser(p, NULL, NULL, NULL); return NULL; } /*************************************************/