/* Copyright 1998 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 : About.c */ /* */ /* Purpose: Compile an HTML 'About' page which */ /* describes available Plug-Ins. */ /* */ /* Author : Piers Wombwell */ /* This source adapted by A.D.Hodgkinson */ /* */ /* History: 30-Jan-98: Adaptation complete (ADH) */ /***************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.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 "svcprint.h" #include "Global.h" #include "Utils.h" /* Local statics and definitions */ #define FLAGS_IMAGE (1u<<0) static struct _abouts { char * dirname; unsigned int count; unsigned int flags; unsigned int width; unsigned int height; struct _abouts * next; } * abouts = NULL; /* Static function prototypes */ static void about_free_abouts (void); static char * about_html_fname (const char * dirname, unsigned int count, unsigned int width, unsigned int height); static int about_copy_info_file (char ** output, int output_size, const char * dirname, unsigned int count); /*************************************************/ /* about_free_abouts() */ /* */ /* Free all of the temporary structures used to */ /* compile the About page. */ /*************************************************/ static void about_free_abouts(void) { struct _abouts * next; if (abouts) { while (abouts) { next = abouts->next; free(abouts->dirname); free(abouts); abouts = next; } } } /*************************************************/ /* about_html_fname() */ /* */ /* Creates a URL to point to an About item logo. */ /* */ /* Parameters: Directory to look in; */ /* */ /* Number of the file; */ /* */ /* Item width; */ /* */ /* Item height (the last two form */ /* part of the filename). */ /* */ /* Returns: Pointer to the URL in a *global* */ /* malloc block - if you need a */ /* local copy before calling the */ /* function again, you must take it */ /* there and then. */ /*************************************************/ static char * about_html_fname(const char * dirname, unsigned int count, unsigned int width, unsigned int height) { static char * fname = NULL; char * s; int len; if (fname) free(fname); fname = NULL; if (width == 0 && height == 0) { len = strlen(dirname) + sizeof("file:/.00"); fname = malloc(len); if (!fname) return ""; sprintf(fname, "file:/%s.%02d", dirname, count); } else { len = strlen(dirname) + sizeof("file:/.0000000000"); fname = malloc(len); if (!fname) return ""; sprintf(fname, "file:/%s.%02d%04d%04d", dirname, count, width, height); } if (fname && *fname) { for (s = fname + sizeof("file:/"); *s != '\0'; s++) { if (*s == '.') *s = '/'; } } return fname; } /*************************************************/ /* about_copy_info_file */ /* */ /* Copy the 'About' info file into the given */ /* flex block. */ /* */ /* Paramters: Pointer to the flex block; */ /* */ /* Size of the block so far; */ /* */ /* Name of the directory to look in; */ /* */ /* Number of the 'About' file to */ /* read (will cope with just 'About' */ /* rather than 'AboutXX'). */ /* */ /* Returns: Size of block after addition of */ /* the file. */ /*************************************************/ static int about_copy_info_file(char ** output, int output_size, const char * dirname, unsigned int count) { FILE * input; char fname[Limits_OS_Pathname]; int length; int old_state; /* Write 'AboutXX' as a leafname if it'll fit */ if (strlen(dirname) + sizeof(".About00") <= sizeof(fname)) { sprintf(fname, "%s.About%02d", dirname, count); } else return output_size; /* Try to open it */ input = fopen(fname, "r"); /* If this fails, write just 'About' (we know it'll fit */ /* if 'AboutXX' did!) */ if (input == NULL && count == 0) { sprintf(fname, "%s.About", dirname); input = fopen(fname, "r"); } /* If this fails, bail out */ if (input == NULL) return output_size; fseek(input, 0L, SEEK_END); length = (int) ftell(input); rewind(input); /* Try to get the amount of memory the file requires */ if (flex_extend((void **) output, output_size + length + 1) != 1) /* + 1 for the terminator */ { fclose(input); return output_size; } /* Read the file, zero terminate it in the block, and close the file */ old_state = flex_set_budge(0); fread(*output + output_size, length, 1, input); *(*output + output_size + length) = '\0'; flex_set_budge(old_state); fclose(input); /* Return the original size plus the added data */ return output_size + length; } /*************************************************/ /* about_build_page() */ /* */ /* Builds an 'About' page enumerating Plug-Ins */ /* to a given flex anchor. */ /* */ /* There may already be data in the flex block, */ /* or not. If the function bails out due to lack */ /* of memory or some other error, the flex block */ /* won't be freed and may have been added to. */ /* */ /* Parameters: The flex anchor (as a void **). */ /*************************************************/ _kernel_oserror * about_build_page(void ** block) { _kernel_swi_regs regs; /* OS_ReadVarVal doesn't work with _swix */ struct _abouts * about; int plugin_count = -1; int max_width = 0; int output_size = 0; int len; int start; if (!block) return NULL; regs.r[3] = 0; /* Count */ do { plugin_count++; regs.r[0] = (int) "Plugin$About_*"; regs.r[1] = NULL; /* No buffer */ regs.r[2] = -1; /* Verify whether it exists */ regs.r[4] = 0; /* Returned unexpanded string */ _kernel_swi(OS_ReadVarVal, ®s, ®s); if (regs.r[2] != 0) { /* Got directory name - let's enumerate About files... */ char leafname[Limits_OS_Pathname]; int nobjs, index = 0; while (index != -1) { /* Read full info on the one 'About[XX]' file in */ /* the directory. */ if ( _swix(OS_GBPB, _INR(0,6) | _OUTR(3,4), 12, getenv((const char*) regs.r[3]), leafname, 1, index, sizeof(leafname), "About*", &nobjs, /* No. objects read so far */ &index) /* Where to continue */ ) break; /* We may have nothing left to read (index == -1) */ /* or have read no object this time */ if (index == -1) break; if (nobjs == 0) continue; /* Build an 'about' structure for the entry */ about = malloc(sizeof(struct _abouts)); if (!about) { about_free_abouts(); return make_no_cont_memory_error(12); } about->dirname = malloc(~regs.r[2] + 1); if (!about->dirname) { about_free_abouts(); return make_no_cont_memory_error(12); } /* Read the expanded path into the buffer */ _kernel_getenv((const char *) regs.r[3], about->dirname, (unsigned int) ~regs.r[2] + 1); /* We may have an 'About' file or an 'AboutXX' file */ if (!strcmp(leafname + 24, "About")) about->count = 0; else about->count = atoi(leafname + 24 + sizeof("About")); about->flags = 0; about->next = abouts; abouts = about; } } } while (regs.r[2] != 0); /* Now we've got all the 'About' files, we can look for the logos */ for (about = abouts; about != NULL; about = about->next) { char leafname[Limits_OS_Pathname]; int nobjs, index = 0; while (index != -1) { sprintf(leafname, "%02d*", about->count); /* Similar to the above code, only the files are */ /* identified as 'XXWWWWHHHH' (Ws = width, Hs = */ /* height). */ if ( _swix(OS_GBPB, _INR(0,6) | _OUTR(3,4), 12, about->dirname, leafname, 1, index, sizeof(leafname), leafname, &nobjs, &index) ) break; if (index == -1) break; if (nobjs == 0) continue; /* Check if leafname is just two digits long, and therefore */ /* has no width and height */ if (strlen(leafname + 24) == 2) { about->width = about->height = 0; about->flags = FLAGS_IMAGE; break; } /* Break up leafname into width & height */ strncpy(leafname, leafname + 24 + 2, 4); leafname[5] = '\0'; about->width = atoi(leafname); strncpy(leafname, leafname + 24 + 6, 4); leafname[5] = '\0'; about->height = atoi(leafname); if (about->width > max_width) max_width = about->width; /* We now have the sprite widths. Mark About object as good */ about->flags = FLAGS_IMAGE; } } /* Build the HTML - first the header */ output_size = strlen(lookup_token("pabouthdr",1,0)) + 1; { int success; if (!*block) start = 0, success = flex_alloc (block, output_size); else start = flex_size (block), success = flex_extend(block, start + output_size); if (!success) goto panic; sprintf(((char *) *block) + start, tokens); output_size += start - 1; /* (Next item should overwrite the terminator) */ } /* Next the browser's own entry. We need to substitute one a Messages */ /* file entry into another Messages file entry, so some juggling */ /* about of buffers is needed - we'll store the string to substitute */ /* at block + output_size, compile the final string above this, then */ /* move the final string down into place. */ len = strlen(lookup_token("paboutbrw",1,0)) + 1; len += strlen(lookup_token("Version", 1,0)) * 2 + 1; if (!flex_extend(block, output_size + len)) goto panic; sprintf(((char *) *block) + output_size, tokens); len = strlen(tokens) + 1; sprintf(((char *) *block) + output_size + len, lookup_token("paboutbrw",1,0), ((char *) *block) + output_size); memmove(((char *) *block) + output_size, ((char *) *block) + output_size + len, strlen(((char *) *block) + output_size + len) + 1); output_size = start + strlen(((char *) *block) + start); /* Now the individual items */ for (about = abouts; about != NULL; about = about->next) { if (!(about->flags & FLAGS_IMAGE)) { len = strlen(lookup_token("paboutpl1",1,0)) + 1; if (!flex_extend(block, output_size + len)) goto panic; sprintf(((char *) *block) + output_size, tokens); output_size = start + strlen(((char *) *block) + start); } else if (about->width == 0 && about->height == 0) { len = strlen(about_html_fname(about->dirname, about->count, 0, 0)) + strlen(lookup_token("paboutpl2",1,0)) + 1; if (!flex_extend(block, output_size + len)) goto panic; sprintf(((char *) *block) + output_size, tokens, about_html_fname(about->dirname, about->count, 0, 0)); output_size = start + strlen(((char *) *block) + start); } else { len = strlen(about_html_fname(about->dirname, about->count, about->width, about->height)) + 4 + /* Width and height are 4 characters or less as numbers, */ 4 + /* due to the way the filenames encode them. */ strlen(lookup_token("paboutpl3",1,0)) + 1; if (!flex_extend(block, output_size + len)) goto panic; sprintf(((char *) *block) + output_size, tokens, about_html_fname(about->dirname, about->count, about->width, about->height), about->width, about->height); output_size = start + strlen(((char *) *block) + start); } /* Copy in HTML About file */ output_size = about_copy_info_file((char **) block, output_size, about->dirname, about->count); /* Write the item footer */ len = strlen(lookup_token("paboutift",1,0)) + 1; if (!flex_extend(block, output_size + len)) goto panic; sprintf(((char *) *block) + output_size, tokens); output_size = start + strlen(((char *) *block) + start); } /* Write the page footer; then we're finished */ len = strlen(lookup_token("paboutpft",1,0)) + 1; if (!flex_extend(block, output_size + len)) goto panic; sprintf(((char *) *block) + output_size, tokens); output_size = start + strlen(((char *) *block) + start); /* Ensure the block is clipped to exactly the right size (we're */ /* building HTML, so it shouldn't have a zero terminator!) */ if (!flex_extend(block, output_size)) goto panic; /* Clean up and exit without error */ about_free_abouts(); return NULL; panic: /* Clean up and exit with an error */ about_free_abouts(); /* This was *almost* certainly the error...! */ return make_no_cont_memory_error(12); }