Commit 758802b2 authored by ROOL's avatar ROOL 🤖
Browse files

Remove arbitrary limits on menu sizes

Detail:
  When RISC_OSLib is used to generate menus using menu_new and menu_extend
  there are two (undocumented?) limits on the total menu size:
  - 64 items on a menu. Any more are silently ignored.
  - 1024 bytes of indirect text. Above this, any items have
    several bytes of random rubbish displayed in the menu entry.

  rlib.c.menu (r4.6) has been changed to:
  - remove menu_workarea which was on the stack, and caused limits.
  - only use malloc'd storage areas for the menu.
  - reduce the data copied by at least 50% by changing processing
    from: copy; update; copy
    to  : realloc extend (& copy?); update; realloc shrink (no copy).
  - remove the limits by adding more storage dynamically.
  - simplify code, which reduces the object code size by about 7%.
Admin:
  The changes have been tested on an Iyonix running RO5.23, and VRPC
  running RO4.39, with a large C program with about 80 menus.
  The only noticeable effects were beneficial.
  It has also been tested with artificially low ADDITEMS and ADDBYTES.
  Submission from Martin Avison.

Version 5.87. Tagged as 'RISC_OSLib-5_87'
parent ec3972c5
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "5.86"
Module_Version SETA 586
Module_MajorVersion SETS "5.87"
Module_Version SETA 587
Module_MinorVersion SETS ""
Module_Date SETS "07 Feb 2016"
Module_ApplicationDate SETS "07-Feb-16"
Module_Date SETS "13 Feb 2016"
Module_ApplicationDate SETS "13-Feb-16"
Module_ComponentName SETS "RISC_OSLib"
Module_ComponentPath SETS "castle/RiscOS/Sources/Lib/RISC_OSLib"
Module_FullVersion SETS "5.86"
Module_HelpVersion SETS "5.86 (07 Feb 2016)"
Module_FullVersion SETS "5.87"
Module_HelpVersion SETS "5.87 (13 Feb 2016)"
END
/* (5.86)
/* (5.87)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 5.86
#define Module_MajorVersion_CMHG 5.87
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 07 Feb 2016
#define Module_Date_CMHG 13 Feb 2016
#define Module_MajorVersion "5.86"
#define Module_Version 586
#define Module_MajorVersion "5.87"
#define Module_Version 587
#define Module_MinorVersion ""
#define Module_Date "07 Feb 2016"
#define Module_Date "13 Feb 2016"
#define Module_ApplicationDate "07-Feb-16"
#define Module_ApplicationDate "13-Feb-16"
#define Module_ComponentName "RISC_OSLib"
#define Module_ComponentPath "castle/RiscOS/Sources/Lib/RISC_OSLib"
#define Module_FullVersion "5.86"
#define Module_HelpVersion "5.86 (07 Feb 2016)"
#define Module_LibraryVersionInfo "5:86"
#define Module_FullVersion "5.87"
#define Module_HelpVersion "5.87 (13 Feb 2016)"
#define Module_LibraryVersionInfo "5:87"
......@@ -47,7 +47,7 @@
#include "sprite.h"
#include "resspr.h"
#include "msgs.h"
#include "Verintern/messages.h"
#include "VerIntern/messages.h"
typedef struct menu__str {
wimp_menuhdr *m; /* the wimp-level menu that we've built. */
......@@ -55,6 +55,8 @@ typedef struct menu__str {
void *entryspace; /* for sub-menus, and entries with >12 chars */
int nbytes; /* bytes used in entryspace */
int maxentrywidth; /* used to set menu width */
int maxitems; /* max items for menu_new/extend */
int maxbytes; /* max bytes for menu_new/extend */
} menu__str;
/* concrete representation of abstract menu object */
......@@ -74,107 +76,88 @@ static wimp_menuitem *menu__itemptr(menu m, int n)
/* -------- Building RISC OS Menus. -------- */
/* The menu is assembled entry by entry in temporary workspace, then copied
to more precisely allocated store. The copying of menu structures is split
into the allocation of store and then the copying of data, so that the copy
into the larger buffer can share the latter half of the operation. */
/* The menu is assembled entry by entry in malloc'd storage.
The two main areas hold the menu block and the indirect data.
At the start of menu_new or menu_extend they are (re)allocated too
large, then shrunk using realloc before exit.
If realloc causes the indirect area to move, any indirect pointers
in the menu block are adjusted.
The total space is only limited by memory. */
/* The following set the amount of storage to be allocated in one go. */
#define ADDITEMS 32 /* items added in one chunk for menu block */
#define ADDBYTES 512 /* bytes added in one chunk for indirect text */
static void menu__disposespace(menu m)
{ /* Free two areas (header+icons & indirect data) for a complete menu */
if (m->m != 0) {
if (m->m != NULL) {
free(m->m);
m->m = 0;
}
if (m->entryspace != 0) { /* can only happen with very new menu__strs. */
if (m->entryspace != NULL) { /* can only happen with very new menu__strs. */
free(m->entryspace);
m->entryspace = 0;
}
}
static void menu__preparecopy(menu from, menu to)
{
/* Allocate space in the destination to suit the copy. */
to->m = malloc(sizeof(wimp_menuhdr) + from->nitems * sizeof(wimp_menuitem));
if (to->m == 0) {
werr(TRUE, msgs_lookup(MSGS_menu1));
}
if (from->nbytes != 0) {
to->entryspace = malloc(from->nbytes);
if (to->entryspace == 0) {
werr(TRUE, msgs_lookup(MSGS_menu1));
}
} else {
to->entryspace = 0;
}
}
static void menu__copydata(menu from, menu to)
/* Copy the data and lengths. Relocate indirection pointers. */
{
int moveoffset;
static void menu__checkmove(menu m, int moveoffset)
{ /* Move any indirect pointers in menu items by moveoffset */
int i;
to->maxentrywidth = from->maxentrywidth;
to->nitems = from->nitems;
(void) memmove(to->m, from->m,
sizeof(wimp_menuhdr) + from->nitems * sizeof(wimp_menuitem));
to->nbytes = from->nbytes;
moveoffset = ((char*)to->entryspace) - ((char*)from->entryspace);
(void) memmove(to->entryspace, from->entryspace, from->nbytes);
for (i=0;i<to->nitems;i++) {
wimp_menuitem *ptr = menu__itemptr(to, i);
if ((ptr->iconflags & wimp_INDIRECT) != 0) {
for (i=0;i<m->nitems;i++) {
wimp_menuitem *ptr = menu__itemptr(m, i);
if (ptr->iconflags & wimp_INDIRECT) {
ptr->data.indirecttext.buffer += moveoffset;
}
}
}
/* The work area is allocated on the stack, with the following limits: */
#define MAXITEMS 64 /* max size of a menu: surely OK. */
#define MAXENTRYSPACE 1024 /* space for building entries > 12 chars */
typedef struct {
menu__str m;
wimp_menuhdr menuhdr;
wimp_menuitem menuitems[MAXITEMS];
char entryspace[MAXENTRYSPACE];
} menu__workarea;
static void menu__initworkarea(menu__workarea *w)
static void menu__realloc(menu m, int items, int bytes)
/* Change sizes for more (or less) menu items and bytes indirect data.
Note areas may move when extended (or even shrunk?) */
{
w->m.m = &w->menuhdr;
w->m.nitems = 0;
w->m.entryspace = &w->entryspace;
w->m.maxentrywidth = 0;
/* insert a NIL in the entrySpace to distinguish sub-Menu pointers
from text space. */
w->m.nbytes = 4;
*((int*)w->entryspace) = 0;
}
static void menu__copytoworkarea(menu m /*in*/, menu__workarea *w /*out*/)
{
menu__initworkarea(w);
menu__copydata(m, &w->m);
menu__itemptr(&w->m, w->m.nitems-1)->flags &= ~wimp_MLAST;
}
int *oldesp; /* for old entryspace addr */
static void menu__copyworkarea(menu__workarea *w /*in*/, menu m /*out*/)
{
if (w->m.nitems > 0) {
menu__itemptr(&w->m, w->m.nitems-1)->flags |= wimp_MLAST;
if (items != 0) {
m->maxitems += items;
m->m = realloc(m->m, sizeof(wimp_menuhdr) + m->maxitems * sizeof(wimp_menuitem));
if (m->m == NULL)
werr(TRUE, msgs_lookup(MSGS_menu1)); /* not enough memory */
}
if (bytes != 0) {
m->maxbytes += bytes;
oldesp = m->entryspace;
m->entryspace = realloc(m->entryspace, m->maxbytes);
if (m->entryspace == NULL) {
werr(TRUE, msgs_lookup(MSGS_menu1)); /* not enough memory */
}
if ((oldesp != m->entryspace) && (m->nitems>0)) {
menu__checkmove(m, (int)m->entryspace - (int)oldesp);
}
}
menu__disposespace(m);
menu__preparecopy(&w->m, m);
menu__copydata(&w->m, m);
}
/* -------- Creating menu descriptions. -------- */
static void menu__initmenu(char *name, menu m /*out*/)
static menu menu__initmenu(char *name)
{ /* Create and initialise menu structure, block and entryspace */
menu m;
int i;
m = calloc(1,sizeof(menu__str));
if (m == NULL) {
werr(TRUE, msgs_lookup(MSGS_menu1));
}
menu__realloc(m, ADDITEMS, ADDBYTES);
/* insert a NIL in the entrySpace to distinguish sub-Menu pointers
from text space. */
m->nbytes = 4;
*((int*)m->entryspace) = 0;
for (i=0; i<12; i++) {
m->m->title[i] = name[i];
if (name[i]==0) {break;}
......@@ -186,25 +169,28 @@ static void menu__initmenu(char *name, menu m /*out*/)
m->m->width = i*16; /* minimum value */
m->m->height = 44; /* per entry */
m->m->gap = 0; /* gap between entries, in OS units */
return m;
}
static int menu__max(int a, int b)
{ if (a < b) {return(b);} else {return(a);} }
static wimp_menuitem *menu__additem(
menu__workarea *w /*out*/, char *name, int length)
menu m /*out*/, char *name, int length)
/* Add an item to the end of a menu */
/* The returned pointer can be used to set flags, etc. */
{
wimp_menuitem *ptr;
if (w->m.nitems == MAXITEMS) {return(menu__itemptr(&w->m, MAXITEMS-1));}
ptr = menu__itemptr(&w->m, w->m.nitems++);
if (m->nitems == m->maxitems) {
menu__realloc(m, ADDITEMS, 0);
}
ptr = menu__itemptr(m, m->nitems++);
ptr->flags = 0;
ptr->submenu = (wimp_menustr*) -1;
ptr->iconflags = wimp_ITEXT + wimp_IFILLED + wimp_IVCENTRE + (7*wimp_IFORECOL);
if (length > w->m.maxentrywidth) {
w->m.maxentrywidth = length;
w->m.m->width = menu__max(w->m.m->width, 16 + length * 16);
if (length > m->maxentrywidth) {
m->maxentrywidth = length;
m->m->width = menu__max(m->m->width, 16 + length * 16);
/* in OS units, 16 per char. */
}
if (length <= 12) {
......@@ -212,19 +198,20 @@ static wimp_menuitem *menu__additem(
int i;
for (i=0; i<length; i++) {ptr->data.text[i] = name[i];}
if (length < 12) {ptr->data.text[length] = 0;}
} else if (length+1+w->m.nbytes >= MAXENTRYSPACE) {
/* no room for the text: unlikely */
ptr = menu__itemptr(&w->m, w->m.nitems-1); /* fudge */
} else {
if (length+1+m->nbytes >= m->maxbytes) {
/* new length over current maximum, so add storage */
menu__realloc(m, 0, ADDBYTES);
}
/* space for length, so set up icon block to be indirect */
ptr->iconflags += wimp_INDIRECT;
ptr->data.indirecttext.buffer = ((char*)w->m.entryspace) + w->m.nbytes;
ptr->data.indirecttext.buffer = ((char*)m->entryspace) + m->nbytes;
ptr->data.indirecttext.validstring = (char*) -1;
ptr->data.indirecttext.bufflen = 100;
/* copy name into entryspace */
(void) memmove(((char*)w->m.entryspace) + w->m.nbytes, name, length);
w->m.nbytes += length + 1;
((char*)w->m.entryspace)[w->m.nbytes-1] = 0; /* terminate the string. */
(void) memmove(((char*)m->entryspace) + m->nbytes, name, length);
m->nbytes += length + 1;
((char*)m->entryspace)[m->nbytes-1] = 0; /* terminate the string. */
}
return(ptr);
}
......@@ -349,7 +336,7 @@ static toktype menu__gettoken(parser *p)
/* -------- Parsing and Extension. -------- */
static void menu__doextend(menu__workarea *w, char *descr)
static void menu__doextend(menu m, char *descr)
{
parser p;
toktype tok;
......@@ -361,11 +348,11 @@ static void menu__doextend(menu__workarea *w, char *descr)
/* do nothing */
} else {
if (tok==SEP) {
if (w->m.nitems == 0) {
if (m->nitems == 0) {
menu__syntax();
} else {
if (p.ch == '|') {
ptr = menu__itemptr(&w->m, w->m.nitems-1);
ptr = menu__itemptr(m, m->nitems-1);
ptr->flags |= wimp_MSEPARATE;
}
tok = menu__gettoken(&p);
......@@ -380,7 +367,7 @@ static void menu__doextend(menu__workarea *w, char *descr)
if (p.t != NAME) {
menu__syntax();
} else {
ptr = menu__additem(w, p.start, p.end - p.start);
ptr = menu__additem(m, p.start, p.end - p.start);
if ((TICK & p.opts) != 0) {
ptr->flags |= wimp_MTICK;
}
......@@ -412,20 +399,15 @@ static void menu__doextend(menu__workarea *w, char *descr)
menu menu_new(char *name, char *descr)
{ /* Create a new menu from the list of entries in descr */
menu m;
menu__workarea menu__w;
wimp_menuitem *ptr;
menu__initworkarea(&menu__w);
menu__initmenu(name, &(menu__w.m));
menu__doextend(&menu__w, descr);
m = malloc(sizeof(menu__str));
if (m == 0) {
werr(TRUE, msgs_lookup(MSGS_menu1));
m = menu__initmenu(name);
menu__doextend(m, descr); /* create menu entrie(s) from descr */
menu__realloc(m, m->nitems-m->maxitems, m->nbytes-m->maxbytes); /* shrink */
if (m->nitems > 0) {
menu__itemptr(m, m->nitems-1)->flags |= wimp_MLAST; /* set last */
}
m->m = 0;
m->entryspace = 0;
menu__copyworkarea(&menu__w, m);
if (strlen(name) > 12) {
if (strlen(name) > 12) { /* check title */
*(char **)m->m->title = name;
ptr = menu__itemptr(m, 0);
ptr->flags |= wimp_MINDIRECTED;
......@@ -449,10 +431,13 @@ void menu_dispose(menu *m, int recursive)
void menu_extend(menu m, char *descr)
{ /* Add one (or more) items from descr to existing menu. */
menu__workarea menu__w;
menu__copytoworkarea(m, &menu__w);
menu__doextend(&menu__w, descr);
menu__copyworkarea(&menu__w, m);
menu__realloc(m, ADDITEMS, ADDBYTES);
menu__itemptr(m, m->nitems-1)->flags &= ~wimp_MLAST; /* unset last */
menu__doextend(m, descr); /* add menu item(s) from descr */
menu__realloc(m, m->nitems-m->maxitems, m->nbytes-m->maxbytes); /* shrink */
if (m->nitems > 0) {
menu__itemptr(m, m->nitems-1)->flags |= wimp_MLAST; /* set new last */
}
}
void menu_setflags(menu m, int entry, int tick, int fade)
......@@ -519,26 +504,17 @@ void menu_make_sprite(menu m, int entry, char *spritename)
void menu_submenu(menu m, int place, menu submenu)
{ /* Link a submenu to an entry in a parent menu */
int i;
wimp_menuitem *p = menu__itemptr(m, place-1);
menu__workarea menu__w;
p->submenu = (wimp_menustr*) (submenu?submenu->m:NULL);
menu__copytoworkarea(m, &menu__w);
menu__realloc(m, 0, sizeof(menu*));
(void) memmove(
/* to */ ((menu*) menu__w.m.entryspace) + 1,
/* from */ ((menu*) menu__w.m.entryspace),
menu__w.m.nbytes);
menu__w.m.nbytes += sizeof(menu*);
*((menu__str**)(menu__w.m.entryspace)) = submenu;
for (i=0; i<menu__w.m.nitems; i++) {
p = menu__itemptr(&menu__w.m, i);
if (((p->iconflags)&wimp_INDIRECT) != 0) {
p->data.indirecttext.buffer += 4;
}
}
menu__copyworkarea(&menu__w, m);
/* to */ ((menu*) m->entryspace) + 1, /* +4 bytes */
/* from */ ((menu*) m->entryspace),
m->nbytes);
m->nbytes += sizeof(menu*);
*((menu__str**)(m->entryspace)) = submenu;
menu__checkmove(m, sizeof(menu*)); /* adjust indirect ptrs for insertion */
}
void *menu_syshandle(menu m)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment