/* Copyright 1996 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. */ /* * ctl.c * * User interface Control file handling. * * Author: Ran Mokady. * * History: * 09-Feb-90 Linked into Risc_OSLib. * */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include "kernel.h" #include "swis.h" #include "msgs.h" #include "wimp.h" #include "wimpt.h" #include "win.h" #include "werr.h" #include "event.h" #include "res.h" #include "menu.h" #include "dbox.h" #include "akbd.h" #include "template.h" #include "colourmenu.h" #include "ctl.h" #ifdef LOG static FILE *logfile; #endif #ifndef Wimp_GetMenuState #define Wimp_GetMenuState 0x400f4 #endif #define MAX(a,b) a>b?a:b #define MIN(a,b) a<b?a:b /****************************** Data types *********************************/ typedef enum { ctl_ACT_FUNCTION = 1, ctl_ACT_STRING = 2, ctl_ACT_LABEL = 3 } ctl__actiontype; typedef enum { ctl_TOK_STRING = -4, ctl_TOK_NUMBER = -3, ctl_TOK_ACTION = -2, ctl_TOK_UNKNOWN = -1, ctl_TOK_EOF = 0, ctl_TOK_CTL = 1, ctl_TOK_MENU = 2, ctl_TOK_ENTRY = 3, ctl_TOK_ENDMENU = 4, ctl_TOK_ONOPEN = 5, ctl_TOK_ONCLOSE = 6, ctl_TOK_DBOX = 7, ctl_TOK_ICON = 8, ctl_TOK_ENDDBOX = 9, ctl_TOK_ONKEY = 10, ctl_TOK_EOL = 11, ctl_TOK_OPENBLOCK = 12, ctl_TOK_CLOSEBLOCK = 13, ctl_TOK_ENDCTL = 14, ctl_TOK_SUBMENU = 15, ctl_TOK_COMMENT = 16, ctl_TOK_WARNING = 17, ctl_TOK_ONREOPEN = 18, ctl_TOK_TEMPLATE = 19, ctl_TOK_HELP = 20, ctl_TOK_TOKEN = 21, ctl_TOK_HELPACTION = 22, ctl_TOK_COLOURMENU = 23, ctl_TOK_EXTERNAL = 24, ctl_TOK_NOREOPEN = 25, ctl_TOK_ONCLICK = 26 } ctl__token; typedef enum { ctl_ST_PRELOAD = 0, ctl_ST_LOADING = 1, ctl_ST_LOADED = 2, ctl_ST_CTLDEF = 3, ctl_ST_MENUDEF = 4, ctl_ST_DBOXDEF = 5, ctl_ST_GETACTION = 6, ctl_ST_GETACTIONBLOCK = 7 } ctl__state; typedef struct ctl__actstr { char *name; char *syntax; BOOL internal; BOOL disabled; struct{ ctl_action_proc function; void *handle; }function; struct ctl__actstr *next; }ctl__actionstr; typedef struct ctl__act { ctl__actiontype type; union { char *name; ctl__actionstr *address; } action; char *args; int line; int nest; struct ctl__act *next; }ctl__action; typedef union { ctl__action action; int num; char *string; }ctl__tokenstr; typedef struct ctl__mentry { int num; int disabled; ctl__action *action; ctl__action *help_action; struct ctl__mentry *next; } ctl__menu_entry; typedef struct ctl__mnu { char *name; ctl__action *onopen; ctl__action *onreopen; ctl__menu_entry *entries; menu menu_body; char *mih_token; int entrycount; BOOL external; wimp_menuitem *parent; struct ctl__mnu *next; } ctl__menu; typedef struct ctl__icn { int num; int disabled; BOOL ticked; BOOL writeable; /*for possible future error chk when dbox is opened*/ ctl__action *action; ctl__action *help_action; struct ctl__icn *next; } ctl__icon; typedef union { ctl__menu_entry *menu_entry; ctl__icon *icon; }ctl__entry; typedef struct ctl__dbx { char *name; char *template; ctl__action *onopen; ctl__action *onreopen; ctl__action *onclose; ctl__icon *icons; dbox dbox_body; char *mih_token; int iconcount; BOOL displayed; struct ctl__dbx *next; }ctl__dbox; typedef union { ctl__menu *parent_menu; ctl__dbox *parent_dbox; }ctl__parent; typedef struct ctl_ky { int keycode; ctl__action *action; struct ctl_ky *next; BOOL disabled; }ctl__key; typedef struct ctl_ctl { char *name; ctl__menu *menus; ctl__dbox *dboxes; ctl__key *keys; ctl__action *onclick; struct ctl_ctl *next; }ctl; typedef struct hndl { event_w w; void *user_handle; ctl *the_ctl; ctl__menu *mnu; ctl__dbox *the_dbox; char *help_token; struct hndl *next; }ctl__handlestr; typedef struct { char *name; int code; } ctl__keyvalstr; typedef struct { ctl__state state; ctl *ctls; ctl__actionstr *actions; ctl__handlestr *handles; ctl__handlestr *current_handle; ctl__menu *current_menu; ctl__menu *top_menu; ctl__dbox *current_dbox; int current_char; int current_icon; FILE *file; int line; int nest; int return_code; char last_menu_hit[30]; char external_hit[30]; int skip; } ctl__statestr; #define Argbuf_LEN 256 typedef union { int words[Argbuf_LEN]; char text[Argbuf_LEN*4]; } ctl__argbuf; typedef struct { char *buffer; int len; char *valid; int flag; }ctl__indirectstr; /*************************** Constants ************************************/ static ctl__keyvalstr ctl__keynames(int indx) { ctl__keyvalstr tmp; tmp.name="ENDLIST"; tmp.code=-1; switch (indx) { case 0: tmp.name="<f1>"; tmp.code= akbd_Fn+1; break; case 1: tmp.name="<f2>"; tmp.code= akbd_Fn+2; break; case 2: tmp.name="<f3>"; tmp.code= akbd_Fn+3; break; case 3: tmp.name="<f4>"; tmp.code= akbd_Fn+4; break; case 4: tmp.name="<f5>"; tmp.code= akbd_Fn+5; break; case 5: tmp.name="<f6>"; tmp.code= akbd_Fn+6; break; case 6: tmp.name="<f7>"; tmp.code= akbd_Fn+7; break; case 7: tmp.name="<f8>"; tmp.code= akbd_Fn+8; break; case 8: tmp.name="<f9>"; tmp.code= akbd_Fn+9; break; case 9: tmp.name="<f10>"; tmp.code= akbd_Fn10; break; case 10: tmp.name="<f11>"; tmp.code= akbd_Fn11; break; case 11: tmp.name="<f12>"; tmp.code= akbd_Fn12; break; case 12: tmp.name="<Print>"; tmp.code= akbd_Fn+0; break; case 13: tmp.name="<Esc>"; tmp.code= 27; break; case 14: tmp.name="<Insert>"; tmp.code=akbd_InsertK; break; case 15: tmp.name="<Home>"; tmp.code= 30; break; case 16: tmp.name="<PageUp>"; tmp.code=akbd_PageUpK; break; case 17: tmp.name="<PageDown>"; tmp.code=akbd_PageDownK; break; case 18: tmp.name="<Delete>"; tmp.code= 127; break; case 19: tmp.name="<<-|>"; tmp.code= 8; break; case 20: tmp.name="<Return>"; tmp.code= 13; break; case 21: tmp.name="<Up>"; tmp.code= akbd_UpK; break; case 22: tmp.name="<Down>"; tmp.code= akbd_DownK; break; case 23: tmp.name="<Left>"; tmp.code= akbd_LeftK; break; case 24: tmp.name="<Right>"; tmp.code= akbd_UpK; break; case 25: tmp.name="<Tab>"; tmp.code= akbd_TabK; break; case 26: tmp.name="<Break>"; tmp.code= 27; break; case 27: tmp.name="<Copy>"; tmp.code= akbd_CopyK; break; case 28: tmp.name="<Default>"; tmp.code= -1; break; case 29: tmp.name="ENDLIST"; tmp.code= -1; break; } return tmp; } static char * ctl__tokens(int indx) { switch (indx) { case 0: return "ctl"; case 1: return "menu"; case 2: return "entry"; case 3: return "endmenu"; case 4: return "onopen"; case 5: return "onclose"; case 6: return "dbox"; case 7: return "icon"; case 8: return "enddbox"; case 9: return "onkey"; case 10: return "\n"; case 11: return "{"; case 12: return "}"; case 13: return "endctl"; case 14: return "submenu"; case 15: return "#"; case 16: return "warning"; case 17: return "onreopen"; case 18: return "template"; case 19: return "help"; case 20: return "token"; case 21: return "action"; case 22: return "colourmenu"; case 23: return "external"; case 24: return "noreopen"; case 25: return "onclick"; case 26: return "ENDLIST"; } return "ENDLIST"; } /*************************** Variables ************************************/ static ctl__statestr *ctls=NULL; /******************************* Errors ***********************************/ static char * ctl__errtxt(int num) { switch (num) { case 0: return "ctsyntx:Syntax error in Control file at line %i: %s"; /* 0 */ case 1: return "ctnosp:Control: Not enough space."; /* 1 */ case 2: return "ctinit:ctl_init called twice."; /* 2 */ case 3: return "ctdupact:Duplicate definision for action %s."; /* 3 */ case 4: return "ctdupld:ctl_load called twice."; /* 4 */ case 5: return "ctnofil:Unable to open Control file."; /* 5 */ case 6: return "ctlngth:Token too long."; /* 6 */ case 7: return "cteof:Expected arguments but found EOF."; /* 7 */ case 8: return "ctlnlng:Line too long."; /* 8 */ case 9: return "ctunxeof:Unexpected EOF in Control file."; /* 9 */ case 10: return "ctunxctl:Ctl not at top level."; /* 10 */ case 11: return "ctmisctln:Ctl name not found."; /* 11 */ case 12: return "ctunxmnu:Menu not in ctl top level."; /* 12 */ case 13: return "ctmismnam:Menu name not found."; /* 13 */ case 14: return "ctunxono:Onopen not in Menu or Dbox."; /* 14 */ case 15: return "ctdupono:Duplicate Onopen in Menu or Dbox %s."; /* 15 */ case 16: return "ctunxopb:command expected but found '{'"; /* 16 */ case 17: return "ctunxedbx:enddbox not in dbox."; /* 17 */ case 18: return "ctunxemnu:endmenu not in menu."; /* 18 */ case 19: return "ctunxectl:endctl not in ctl."; /* 19 */ case 20: return "ctunxeblk:unexpected '}'."; /* 20 */ case 21: return "ctunxeact:command expected but found action."; /* 21 */ case 22: return "ctunxestr:command expected but found string."; /* 22 */ case 23: return "ctundfact:Undefined action."; /* 23 */ case 24: return "ctunxent:entry not in menu."; /* 24 */ case 25: return "ctbadent:bad entry number."; /* 25 */ case 26: return "ctbadentn:invalid entry number (n<1 or n>last entry)."; /* 26 */ case 27: return "ctdupent:duplicate entry number."; /* 27 */ case 28: return "ctunxnst:'}' found at top level."; /* 28 */ case 29: return "ctuexpnst:'}' expected."; /* 29 */ case 30: return "ctunxdbx:dbox not in ctl top level."; /* 30 */ case 31: return "ctmisdbxn:dbox name not found."; /* 31 */ case 32: return "ctbaddbx:Unable to create dbox %s."; /* 32 */ case 33: return "ctunxonc:onclose not in dbox."; /* 33 */ case 34: return "ctduponc:duplicate onclose in dbox %s."; /* 34 */ case 35: return "ctunxicn:icon not in dbox."; /* 35 */ case 36: return "ctbadicn:bad icon number."; /* 36 */ case 37: return "ctbadicnn:invalid icon number (n<0 or n>last icon)."; /* 37 */ case 38: return "ctdupicn:duplicate icon number."; /* 38 */ case 39: return "ctunxkey:onkey not in ctl top level."; /* 39 */ case 40: return "ctbadkey:bad key name."; /* 40 */ case 41: return "ctdupkey:duplicate hot key."; /* 41 */ case 42: return "ctctlmis:Ctl %s not defined."; /* 42 */ case 43: return "ctunksubm:Unknown submenu type."; /* 43 */ case 44: return "ctunkact:Unknown action %s"; /* 44 */ case 45: return "ctquoeof:EOF found in quoted string."; /* 45 */ case 46: return "ctquoeol:EOL found in quoted string."; /* 46 */ case 47: return "ctunsmnu:Dbox menus not supported by this wimp version.";/* 47 */ case 48: return "ctnotact:'%s' is not an action."; /* 48 */ case 49: return "ctnotact:dbox %s already displayed."; /* 49 */ case 50: return "ctnotact:Unknown action %s in enable/disable action."; /* 50 */ case 51: return "ctnotact:Unknown action %s in make action writeable."; /* 51 */ case 52: return "ctunxtmp:Template not in dbox."; /* 52 */ case 53: return "ctmistmpn:Template %s not found."; /* 53 */ case 54: return "ctmistmp:missing template name."; /* 54 */ case 55: return "ctmistmpd:No template defined for dbox %s."; /* 55 */ case 56: return "ctduptmp:Duplicate template defined for dbox %s."; /* 56 */ case 57: return "ctmismnut:Missing menu title."; /* 57 */ case 58: return "ctmistbdy:Missing menu body."; /* 58 */ case 59: return "ctmistmpd:Help not in menu / dbox."; /* 59 */ case 60: return "ctmistmpd:Duplicate help token."; /* 60 */ case 61: return "ctmistmpd:Missing help token."; /* 61 */ case 62: return "ctmistmpd:Invalid help type."; /* 62 */ case 63: return "ctdupcart:Duplicate entries for writeable action %s."; /* 63 */ case 64: return "ctdupcart:External menu %s not defined by application."; /* 64 */ case 65: return "ctexpextm:Menu %s should be an external menu."; /* 65 */ case 66: return "ctdupcart:Main attached menu %s cannot be external."; /* 66 */ case 67: return "ctdbxndisp:Dbox %s not displayed in make writable."; /* 67 */ case 68: return "ctunxclk:onclick not in ctl top level."; /* 68 */ case 69: return "ctdupclk:Duplicate onclick action."; /* 69 */ case 70: return "ctunxels:else without if."; /* 70 */ case 71: return "ctdupenth:duplicate help entry number."; /* 71 */ } return "Internal error."; } static void ctl__syntax_error(int errnum,BOOL fatal) { if (fatal) fclose(ctls->file); werr(fatal,msgs_lookup(ctl__errtxt(0)),ctls->line, msgs_lookup(ctl__errtxt(errnum))); } static void ctl__error(int errnum,char *arg,BOOL fatal) { if (fatal) fclose(ctls->file); if ((ctls==NULL) || (ctls->line==0)) werr(fatal,msgs_lookup(ctl__errtxt(errnum)),arg); else { char errbuf[100]; sprintf(errbuf,msgs_lookup("ctlat: %s in Control line %%i"), msgs_lookup(ctl__errtxt(errnum))); werr(fatal,errbuf,arg,ctls->line); } } /****************************** General Functions *************************/ static void *ctl__malloc(int size) { void *result=malloc(size); if (result == NULL) ctl__error(1,NULL,TRUE); return result; } static void ctl__free(void *ptr) { free(ptr); } /* * ctl__iconcount(dbox *d) * * return number of icons in the dbox. * */ static int ctl__iconcount(dbox *d) { wimp_i buffer[256]; wimp_which_block blk; int i; blk.window=dbox_syshandle(*d); blk.bit_mask=0; blk.bit_set=0; wimp_which_icon(&blk,buffer); for (i=0;buffer[i]!=-1;i++); return i; } /* * ctl__keynum(char *c) * * return number of a key from its name. * */ static int ctl__keynum(char *c) { int shift=0,i=0,keynum; for (i=0;i<2;i++) { if (*c=='S') { shift+=akbd_Sh; c++; } if (*c=='C') { shift+=akbd_Ctl; c++; } } /* now we have the shift factor and c points to the name */ /* first try to find as special name */ i=0; for (i=0;strcmp(ctl__keynames(i).name,"ENDLIST")!=0;i++) { if (strcmp(ctl__keynames(i).name,c)==0) return ctl__keynames(i).code+shift; } if (*(c+1)!='\0') return -1; /* More than one char must be bad name */ keynum=*c; if (shift & akbd_Sh) { if ((keynum & 32)==0) return -1; else keynum&=~32; } if (shift & akbd_Ctl){ if ((keynum & 64)==0) return -1; else keynum&=~96; } return keynum; } static wimp_menuitem *ctl__menu_item(menu m,int entry) { wimp_menuitem *item; item=(wimp_menuitem *)((int)menu_syshandle(m)+sizeof(wimp_menuhdr)); return item+(entry-1); } static int ctl__count_menu_entries(wimp_menustr *m) { int count=1; wimp_menuitem *item; item=(wimp_menuitem *)((int)m+sizeof(wimp_menuhdr)); for (count=1;(item->flags & wimp_MLAST)==0;count++) item++; return count; } static void ctl__read_args(char *syntax,char *line,ctl__argbuf *buffer) { _kernel_swi_regs r; _kernel_oserror *e; r.r[0]=(int)syntax; r.r[1]=(int)line; r.r[2]=(int)buffer; r.r[3]=Argbuf_LEN*4; if (e=_kernel_swi(XOS_Bit | OS_ReadArgs,&r,&r),e!=NULL) werr(TRUE,msgs_lookup(ctl__errtxt(0)),ctls->line,e->errmess); } /* some things we need but need us. */ static void ctl__run(ctl__action *act); static ctl__icon *ctl__find_icon(int num,ctl__dbox *a_dbox); static BOOL ctl__process_event(wimp_eventstr *e); static ctl__menu_entry *ctl__find_entry(int num,ctl__menu *a_menu); static ctl__dbox *ctl__find_dbox(char *name,ctl *a_ctl); /*************************** Internal action handlers**********************/ static ctl__handlestr *ctl__add_handle(event_w w, void *userhandle,ctl *ct,ctl__menu *mnu) { ctl__handlestr *a_handle; #ifdef LOG fprintf(logfile,"New handle:\n"); #endif if (ctls->handles==NULL) a_handle = (ctls->handles=ctl__malloc(sizeof(ctl__handlestr))); else { for(a_handle=ctls->handles; (a_handle->next !=NULL) && (a_handle->w != w); a_handle=a_handle->next); if (a_handle->w!=w) a_handle = (a_handle->next=ctl__malloc(sizeof(ctl__handlestr))); } a_handle->w=w; a_handle->mnu=mnu; a_handle->the_ctl=ct; a_handle->user_handle=userhandle; a_handle->help_token=NULL; a_handle->next=NULL; a_handle->the_dbox=NULL; return a_handle; } static void ctl__remove_handle(event_w w) { ctl__handlestr *a_handle,*tmp; if (ctls->handles==NULL) return; if (ctls->handles->w==w) { a_handle=ctls->handles->next; ctl__free(ctls->handles); ctls->handles=a_handle; return; } for(a_handle=ctls->handles; (a_handle->next != NULL) && (a_handle->next->w != w); a_handle=a_handle->next); if (a_handle->next==NULL) return; tmp=a_handle->next; a_handle->next=a_handle->next->next; ctl__free(tmp); } static ctl__handlestr *ctl__find_handle(event_w w) { ctl__handlestr *a_handle; for(a_handle=ctls->handles;a_handle!=NULL;a_handle=a_handle->next) if (a_handle->w==w) return a_handle; return NULL; } static void ctl__dbox_event_handler(dbox d,ctl__dbox *a_dbox) { int inum=ctls->current_icon; ctl__icon *icon; d=d; if ((inum==-1) && (wimpt_last_event()->e==wimp_EKEY)) return; if ((inum==-1) && (wimpt_last_event()->e==wimp_EBUT) && (inum=wimpt_last_event()->data.but.m.i,inum<0)) return; if (inum==-1) return; icon=ctl__find_icon(inum,a_dbox); ctls->return_code=inum; if (icon!=NULL) ctl__run(icon->action); else if (icon=ctl__find_icon(-1,a_dbox),icon!=NULL) ctl__run(icon->action); } static BOOL ctl__dbox_raw_event_handler(dbox d,wimp_eventstr *e,ctl__dbox *handle) { wimp_eventstr ev; wimp_caretstr c,c1; ctls->current_icon=-1; if ((e->e==wimp_EKEY) && (e->data.key.chcode==13)) { wimp_get_caret_pos(&c); ctls->current_icon=e->data.key.c.i; ctl__dbox_event_handler(d,handle); wimp_get_caret_pos(&c1); if ((c.w==c1.w) && (c.i==c1.i)) { ctls->current_icon=-1; return FALSE; } else return TRUE; } else if ((e->e==wimp_ESEND) || (e->e==wimp_ESENDWANTACK)) return (ctl__process_event(e)); else if (e->e!=wimp_EBUT) return FALSE; ctls->current_icon=-1; if (e->data.but.m.bbits!=2) return FALSE; ctls->current_icon=e->data.but.m.i; ev.e=wimp_ESEND; ev.data.msg.hdr.action=wimp_MMENUWARN; ev.data.msg.data.words[1]=e->data.but.m.x; ev.data.msg.data.words[2]=e->data.but.m.y; wimpt_fake_event(&ev); wimpt_poll(0,&ev); ctl__dbox_event_handler(d,handle); return TRUE; } static int ctl__quit_action(void *handle,void *type,void *arg,int rc) { handle=handle; type=type; arg=arg; exit(0); return rc; } static int ctl__showdbox(void *handle,void *type,void *arg,int rc) { ctl__argbuf *buf=(ctl__argbuf *)arg; char dbox_name[20]; int len,i; /* wimp_eventstr e; */ wimp_mousestr m; ctl__dbox *a_dbox; dbox d; BOOL flag; wimp_icon icn; ctl__icon *icon; handle=handle; type=type; wimp_create_menu((wimp_menustr *)-1,0,0); len=*(char *)(buf->words[0]); strncpy(dbox_name,(char *)(buf->words[0])+2,MIN(19,len)); dbox_name[MIN(len,20)]='\0'; a_dbox=ctl__find_dbox(dbox_name,ctls->current_handle->the_ctl); if (a_dbox->displayed) { ctl__error(49,a_dbox->name,FALSE); return 0; } d=dbox_new(a_dbox->template); if (d==NULL) ctl__error(32,a_dbox->name,TRUE); icon=ctl__find_icon(-1,a_dbox); /* reflect state of actions on the icons. */ for (i=0;i<a_dbox->iconcount;i++) { wimp_get_icon_info(dbox_syshandle(d),i,&icn); if ((icon!=NULL) || ((icn.flags & (0xf<<12))==wimp_BIGNORE)) dbox_unfadefield(d,i); else dbox_fadefield(d,i); } for (icon=a_dbox->icons;icon!=NULL;icon=icon->next) { dbox_unfadefield(d,icon->num); if (icon->ticked) wimp_set_icon_state( dbox_syshandle(d),icon->num,wimp_ISELECTED,wimp_ISELECTED); else wimp_set_icon_state(dbox_syshandle(d), icon->num,0,wimp_ISELECTED); if (icon->disabled) wimp_set_icon_state( dbox_syshandle(d),icon->num,wimp_INOSELECT,wimp_INOSELECT); else wimp_set_icon_state(dbox_syshandle(d), icon->num,0,wimp_INOSELECT); } dbox_raw_eventhandler(d, (dbox_raw_handler_proc) ctl__dbox_raw_event_handler, a_dbox); dbox_eventhandler(d, (dbox_handler_proc) ctl__dbox_event_handler,a_dbox); a_dbox->displayed=TRUE; a_dbox->dbox_body=d; ctls->current_dbox=a_dbox; if (a_dbox->mih_token!=NULL) { ctl__handlestr *handle= ctl__add_handle(dbox_syshandle(d),(void *) NULL,NULL,NULL); handle->help_token=a_dbox->mih_token; handle->the_ctl=NULL; handle->the_dbox=a_dbox; } ctl__run(a_dbox->onopen); wimp_get_point_info(&m); dbox_show(d); do { ctls->current_icon=-1; if (dbox_fillin(d)==-1) break; flag=dbox_persist(); if (flag) ctl__run(a_dbox->onreopen); } while (flag); ctl__run(a_dbox->onclose); dbox_eventhandler(d,(dbox_handler_proc)0,a_dbox); dbox_raw_eventhandler(d,(dbox_raw_handler_proc) 0,a_dbox); a_dbox->displayed=FALSE; if (a_dbox->mih_token!=NULL) ctl__remove_handle(dbox_syshandle(d)); dbox_dispose(&d); ctls->current_dbox=NULL; return rc; } static int ctl__if_action(void *handle,void *type,void *arg,int rc) { ctl__argbuf *buf=(ctl__argbuf *)arg; handle=handle; type=type; arg=arg; if (rc!=*((int *) ( (char *) (buf->words[0])+1) ) ) { ctls->skip=-2; } else ctls->skip=-3; return rc; } static int ctl__else_action(void *handle,void *type,void *arg,int rc) { handle=handle; type=type; arg=arg; if (ctls->skip==-1) ctl__syntax_error(70,TRUE); if (ctls->skip==-3) ctls->skip=-2; else ctls->skip=-1; return rc; } static int ctl__error_action(void *handle,void *type,void *arg,int rc) { handle=handle; type=type; werr(0,(char *)arg); return rc; } static int ctl__oscli_action(void *handle,void *type,void *arg,int rc) { handle=handle; type=type; arg=arg; _kernel_oscli((char *)arg); return rc; } static int ctl__number_action(void *handle,void *type,void *arg,int status) { handle=handle; type=type; status=status; ctls->return_code=(int)arg; return (int)arg; } static int ctl__processkey_action(void *handle,void *type,void *arg,int status) { handle=handle; type=type; arg=arg; wimp_processkey(status); ctls->return_code=status; return status; } static int ctl__submenu_request(void *handle,void *type,void *arg,int status) { int i,stat; ctl__icon *icon; stat=(int)type; handle=handle; status=status; if (wimpt_last_event()->e!=wimp_ESEND) return status; switch ((int)type) { case 1: case 3: ctl__run(((ctl__menu *)arg)->onopen); if ((((ctl__menu *)arg)->external) && (((ctl__menu *)arg)->menu_body==NULL)) ctl__error(64,((ctl__menu *)arg)->name,TRUE); if (((ctl__menu *)arg)->external) { ((ctl__menu *)arg)->parent->submenu= (wimp_menustr *)(((ctl__menu *)arg)->menu_body); wimp_create_submenu( (wimp_menustr *)(((ctl__menu *)arg)->menu_body), wimpt_last_event()->data.msg.data.words[1], wimpt_last_event()->data.msg.data.words[2]); } else wimp_create_submenu( menu_syshandle(((ctl__menu *)arg)->menu_body), wimpt_last_event()->data.msg.data.words[1], wimpt_last_event()->data.msg.data.words[2]); ctls->current_menu=(ctl__menu *)arg; break; case 2: case 4: { dbox d; BOOL flag; wimp_icon icn; ctl__handlestr *handle; ctl__dbox *a_dbox=(ctl__dbox *)arg; if (a_dbox->displayed) { ctl__error(49,a_dbox->name,FALSE); return 0; } d=dbox_new(a_dbox->template); if (d==NULL) ctl__error(32,a_dbox->name,TRUE); icon=ctl__find_icon(-1,a_dbox); /* reflect state of actions on the icons. */ for (i=0;i<a_dbox->iconcount;i++) { wimp_get_icon_info(dbox_syshandle(d),i,&icn); if ((icon!=NULL) || ((icn.flags & (0xf<<12))==wimp_BIGNORE)) dbox_unfadefield(d,i); else dbox_fadefield(d,i); } for (icon=a_dbox->icons;icon!=NULL;icon=icon->next) { dbox_unfadefield(d,icon->num); if (icon->ticked) wimp_set_icon_state( dbox_syshandle(d),icon->num,wimp_ISELECTED,wimp_ISELECTED); else wimp_set_icon_state(dbox_syshandle(d), icon->num,0,wimp_ISELECTED); if (icon->disabled) wimp_set_icon_state( dbox_syshandle(d),icon->num,wimp_INOSELECT,wimp_INOSELECT); else wimp_set_icon_state(dbox_syshandle(d), icon->num,0,wimp_INOSELECT); } dbox_raw_eventhandler(d, (dbox_raw_handler_proc) ctl__dbox_raw_event_handler, a_dbox); dbox_eventhandler(d, (dbox_handler_proc) ctl__dbox_event_handler,a_dbox); a_dbox->displayed=TRUE; a_dbox->dbox_body=d; ctls->current_dbox=a_dbox; handle=ctl__add_handle(dbox_syshandle(d),(void *) NULL,NULL,NULL); handle->help_token=a_dbox->mih_token; handle->the_ctl=NULL; ctl__run(a_dbox->onopen); dbox_show(d); do { ctls->current_icon=-1; if (dbox_fillin(d)==-1) break; flag=dbox_persist(); if (flag) { ctl__menu *mnu=ctls->current_handle->mnu; ctl__menu_entry *entry; char *c; for (c=ctls->last_menu_hit;*(c+1);c++) { ctl__run(mnu->onreopen); entry=ctl__find_entry(*c,mnu); if (entry==NULL) entry=ctl__find_entry(-1,mnu); mnu=(ctl__menu *) entry->action->args; } ctl__run(mnu->onreopen); if (!mnu->external) ctl__menu_item(mnu->menu_body,*c)->submenu= ((a_dbox->onreopen)==(ctl__action *)-1) ? (wimp_menustr *) 1 : (wimp_menustr *) dbox_syshandle(d); else ((wimp_menuitem *) (((wimp_menustr *)mnu->menu_body)+1)+*c-1) ->submenu= ((a_dbox->onreopen)==(ctl__action *)-1) ? (wimp_menustr *) 1 : (wimp_menustr *) dbox_syshandle(d); wimp_create_menu( menu_syshandle(ctls->current_handle->mnu->menu_body),0,0); ctl__run(((ctl__dbox *)arg)->onreopen); } } while (flag); ctl__run(a_dbox->onclose); dbox_eventhandler(d,(dbox_handler_proc)0,a_dbox); dbox_raw_eventhandler(d,(dbox_raw_handler_proc) 0,a_dbox); a_dbox->displayed=FALSE; ctl__remove_handle(dbox_syshandle(d)); dbox_dispose(&d); ctls->current_dbox=NULL; } break; default: break; } return status; } /*************************** Internal functions ***************************/ /* * ctl__find_ctl(char *name): * * find named ctl. * */ static ctl *ctl__find_ctl(char *name) { ctl *a_ctl; for (a_ctl=ctls->ctls;a_ctl!=NULL;a_ctl=a_ctl->next) if (strcmp(a_ctl->name,name)==0) return a_ctl; ctl__error(42,name,TRUE); /* NEVER */ return NULL; } /* * ctl__find_menu(char *name,ctl *a_ctl): * * find named menu in given ctl. * */ static ctl__menu *ctl__find_menu(char *name,ctl *a_ctl) { ctl__menu *a_menu; for (a_menu=a_ctl->menus;a_menu!=NULL;a_menu=a_menu->next) if (strcmp(a_menu->name,name)==0) return a_menu; if (ctls->line==0) werr(TRUE,msgs_lookup("mismnu:Menu %s mot defined in Ctl %s.") ,name,a_ctl->name); else werr(TRUE, msgs_lookup("mismnu1:Menu %s mot defined in Ctl %s. at line %i.") ,name,a_ctl->name,ctls->line); /* NEVER */ return NULL; } /* * ctl__find_dbox(char *name,ctl *a_ctl): * * find named dbox in given ctl. * */ static ctl__dbox *ctl__find_dbox(char *name,ctl *a_ctl) { ctl__dbox *a_dbox; for (a_dbox=a_ctl->dboxes;a_dbox!=NULL;a_dbox=a_dbox->next) if (strcmp(a_dbox->name,name)==0) return a_dbox; if (ctls->line==0) werr(TRUE,msgs_lookup("misdbx:Dbox %s mot defined in Ctl %s.") ,name,a_ctl->name); else werr(TRUE, msgs_lookup("misdbx1:Dbox %s mot defined in Ctl %s. at line %i.") ,name,a_ctl->name,ctls->line); /* NEVER */ return NULL; } /* * ctl__find_entry(int num,ctl__menu *a_menu): * * find an entry in given menu return NULL if not found. * */ static ctl__menu_entry *ctl__find_entry(int num,ctl__menu *a_menu) { ctl__menu_entry *an_entry; for (an_entry=a_menu->entries;an_entry!=NULL;an_entry=an_entry->next) if (an_entry->num==num) return an_entry; return NULL; } /* * ctl__find_icon(int num,ctl__dbox *a_dbox): * * find an icon in given dbox return NULL if not found. * */ static ctl__icon *ctl__find_icon(int num,ctl__dbox *a_dbox) { ctl__icon *an_icon; for (an_icon=a_dbox->icons;an_icon!=NULL;an_icon=an_icon->next) if (an_icon->num==num) return an_icon; return NULL; } static ctl__actionstr *ctl__find_action(ctl__actionstr *action, ctl__actionstr *list,BOOL add,BOOL internal) { if (add && ctls->actions==NULL) { #ifdef LOG fprintf(logfile,"New action %s:\n",action->name); #endif ctls->actions=(ctl__actionstr *)ctl__malloc(sizeof(ctl__actionstr)); *ctls->actions=*action; return NULL; } if (list==NULL) return NULL; else if ( (*(list->name)==*(action->name)) && (strcmp(list->name,action->name)==0) && (internal || !list->internal)) return list; if (add && (list->next==NULL)) { #ifdef LOG fprintf(logfile,"New action %s:\n",action->name); #endif list->next=(ctl__actionstr *)ctl__malloc(sizeof(ctl__actionstr)); *list->next=*action; return NULL; } return ctl__find_action(action,list->next,add,internal); } static void ctl__add_action(char *name,char *syntax,ctl_action_proc func,void *arg, BOOL internal) { ctl__actionstr act; act.name=name; act.syntax=syntax; act.next=NULL; act.function.function=func; act.function.handle=arg; act.internal=internal; act.disabled=FALSE; if (ctl__find_action(&act,ctls->actions,TRUE,internal)!=NULL) ctl__error(3,name,TRUE); } static void ctl__init(void) { if (ctls!=NULL) ctl__error(2,NULL,TRUE); #ifdef LOG logfile=fopen("adfs::0.$.ctllog","w"); fprintf(logfile,"Init:\n"); #endif ctls=(ctl__statestr *)ctl__malloc(sizeof(ctl__statestr)); /* Space for state */ ctls->state=ctl_ST_PRELOAD; ctls->ctls=NULL; ctls->actions=NULL; ctls->current_char=' '; ctls->handles=NULL; ctls->current_handle=NULL; ctls->current_menu=NULL; ctls->top_menu=NULL; ctls->current_dbox=NULL; ctls->line=1; ctls->return_code=0; ctls->current_icon=-1; ctls->external_hit[0]='\0'; /* Define stanfard actions. */ /* Name Sntx Function Handle Intern? */ ctl__add_action("<submenu>" ,NULL, ctl__submenu_request, (void *) 1,TRUE); ctl__add_action("<subdbox>" ,NULL, ctl__submenu_request, (void *) 2,TRUE); ctl__add_action("<dsubmenu>" ,NULL, ctl__submenu_request, (void *) 3,TRUE); ctl__add_action("<dsubdbox>" ,NULL, ctl__submenu_request, (void *) 4,TRUE); ctl__add_action("<number>" ,NULL, ctl__number_action , (void *) 0,TRUE); ctl__add_action("process" ,NULL, ctl__processkey_action,(void *) 0,FALSE); ctl__add_action("quit" ,NULL, ctl__quit_action ,(void *) 0,FALSE); ctl__add_action("if" ,"/e", ctl__if_action ,(void *) 0,FALSE); ctl__add_action("else" ,NULL, ctl__else_action ,(void *) 0,FALSE); ctl__add_action("error" ,NULL, ctl__error_action ,(void *) 0,FALSE); ctl__add_action("oscli" ,NULL, ctl__oscli_action ,(void *) 0,FALSE); ctl__add_action("*" ,NULL, ctl__oscli_action ,(void *) 0,FALSE); ctl__add_action("showdbox" ,"/g", ctl__showdbox ,(void *) 0,FALSE); } #define TOKENLEN 256 #define LINELEN 255 /* ctl__skip_toeol: * skip this line in input file. * checks for length and eof. */ static void ctl__skip_toeol(void) { char c; if (ctls->current_char==EOF) ctl__syntax_error(7,TRUE); do { c=ctls->current_char; ctls->current_char=fgetc(ctls->file); if ((ctls->current_char=='\n') && (c=='\\')) { ctls->line++; ctls->current_char=' '; } } while ((ctls->current_char!='\n') && (ctls->current_char!=EOF)); } /* ctl__readtoeol: * read next word from input file. skip any leading spaces * and tabs. * checks for length and eof. */ static void ctl__readtoeol(char *buffer) { char *c=buffer; if (ctls->current_char==EOF) ctl__syntax_error(7,TRUE); do { *c++=ctls->current_char; if (ctls->current_char=='\n') break; if ((c-buffer)==LINELEN) ctl__syntax_error(8,TRUE); ctls->current_char=fgetc(ctls->file); if ((ctls->current_char=='\n') && (*(c-1)=='\\')) { *(c-1)=ctls->current_char=' '; ctls->line++; } } while ((ctls->current_char!='\n') && (ctls->current_char!=EOF)); *c++='\n'; *c='\0'; } /* ctl__readword: * read next word from input file. skip any leading spaces * and tabs. * checks for length and eof. */ static int ctl__readword(char *buffer) { char *c=buffer,sep; if (ctls->current_char==EOF) { return EOF; } while (((ctls->current_char==' ') || (ctls->current_char=='\t')) && !feof(ctls->file)) ctls->current_char=fgetc(ctls->file); if (ctls->current_char=='"') { sep='"'; ctls->current_char=fgetc(ctls->file); } else sep=' '; do { *c++=ctls->current_char; if (c-buffer==TOKENLEN) ctl__syntax_error(6,TRUE); ctls->current_char=fgetc(ctls->file); } while ((ctls->current_char!=sep) && (ctls->current_char!=EOF) && (ctls->current_char!='\n') && (*(c-1)!='\n') ); *c='\0'; if (sep=='"') switch(ctls->current_char) { case EOF: ctl__syntax_error(45,TRUE); break; case '\n': ctl__syntax_error(46,TRUE); break; default: ctls->current_char=fgetc(ctls->file); break; } return 0; } /* read next token. * Reads in the next token from the file return token id. */ static ctl__token ctl__read_next_token(ctl__tokenstr *value) { char buffer[TOKENLEN]; int n; if (ctl__readword(buffer)==EOF) return ctl_TOK_EOF; n=0; while (strcmp(ctl__tokens(n),"ENDLIST")!=0) { if (strcmp(ctl__tokens(n),buffer)==0) return n+1; n++; } if (sscanf(buffer,"%i",&value->num)==1) { if ((ctls->state!=ctl_ST_GETACTION) && (ctls->state!=ctl_ST_GETACTIONBLOCK)) return ctl_TOK_NUMBER; else { ctl__actionstr act; act.name="<number>"; value->action.args=(char *)(value->num); value->action.type=ctl_ACT_FUNCTION; value->action.action.address= ctl__find_action(&act,ctls->actions,FALSE,TRUE); return ctl_TOK_ACTION; } } else { ctl__actionstr act; act.name=buffer; if ( (value->action.action.address= ctl__find_action(&act,ctls->actions,FALSE,FALSE))!=NULL) { value->action.type=ctl_ACT_FUNCTION; ctl__readtoeol(buffer); #ifdef LOG fprintf(logfile,"Action arguments:\n"); #endif value->action.args=ctl__malloc(strlen(buffer)+1); strcpy(value->action.args,buffer); return ctl_TOK_ACTION; } else { #ifdef LOG fprintf(logfile,"String:\n"); #endif value->string=ctl__malloc(strlen(buffer)+1); strcpy(value->string,buffer); return ctl_TOK_STRING; } } /* SHOULD NEVER GET HERE !!!!! */ return ctl_TOK_UNKNOWN; } /* * ctl__new_ctl(): * Define a new ctl. */ static ctl *ctl__new_ctl(void) { ctl *a_ctl; ctl__tokenstr tokenval; #ifdef LOG fprintf(logfile,"New ctl:\n"); #endif if (ctls->ctls==NULL) /* First one */ { ctls->ctls=(ctl *)ctl__malloc(sizeof(ctl)); a_ctl=ctls->ctls; } else { a_ctl=ctls->ctls; while (a_ctl->next != NULL) a_ctl=a_ctl->next; a_ctl->next=(ctl *)ctl__malloc(sizeof(ctl)); a_ctl=a_ctl->next; } /* Now a_ctl points to new space. */ if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING) ctl__syntax_error(11,TRUE); a_ctl->name=tokenval.string; a_ctl->menus=NULL; a_ctl->dboxes=NULL; a_ctl->keys=NULL; a_ctl->onclick=NULL; a_ctl->next=NULL; return a_ctl; } /* ctl__new_menu(ctl *current_ctl) * * define a new menu in the given ctl. * */ static ctl__menu *ctl__new_menu(ctl *cctl) { ctl__menu *a_menu; char *c,*body,*title; ctl__tokenstr tokenval; ctl__token token; int i; BOOL external=FALSE; #ifdef LOG fprintf(logfile,"New Menu:\n"); #endif if (cctl->menus==NULL) /* First one */ { cctl->menus=(ctl__menu *)ctl__malloc(sizeof(ctl__menu)); a_menu=cctl->menus; } else { a_menu=cctl->menus; while (a_menu->next != NULL) a_menu=a_menu->next; a_menu->next=(ctl__menu *)ctl__malloc(sizeof(ctl__menu)); a_menu=a_menu->next; } /* Now a_menu points to new space. */ if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING) ctl__syntax_error(13,TRUE); a_menu->name=tokenval.string; a_menu->onopen=NULL; a_menu->onreopen=NULL; a_menu->entries=NULL; a_menu->next=NULL; a_menu->mih_token=NULL; if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_EXTERNAL) { a_menu->menu_body=NULL; a_menu->entrycount=0; external=TRUE; a_menu->external=external; return a_menu; } else if (token!=ctl_TOK_STRING) ctl__syntax_error(57,TRUE); title=tokenval.string; if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_COLOURMENU) { a_menu->menu_body=colourmenu_make(msgs_lookup(title),FALSE); a_menu->entrycount=16; ctl__free(title); } else if (token!=ctl_TOK_STRING) ctl__syntax_error(58,TRUE); else { body=tokenval.string; a_menu->menu_body=menu_new(msgs_lookup(title),msgs_lookup(body)); a_menu->entrycount=1; for(c=msgs_lookup(body);*c!='\0';c++) if ((*c==',') || (*c=='|')) a_menu->entrycount++; ctl__free(title); ctl__free(body); } a_menu->external=external; if (!external) for (i=1;i<=a_menu->entrycount;i++) menu_setflags(a_menu->menu_body,i,0,1); return a_menu; } /* ctl__new_dbox(ctl *current_ctl) * * define a new dbox in the given ctl. * */ static ctl__dbox *ctl__new_dbox(ctl *cctl) { ctl__dbox *a_dbox; ctl__tokenstr tokenval; #ifdef LOG fprintf(logfile,"New Dbox:\n"); #endif if (cctl->dboxes==NULL) /* First one */ { cctl->dboxes=(ctl__dbox *)ctl__malloc(sizeof(ctl__dbox)); a_dbox=cctl->dboxes; } else { a_dbox=cctl->dboxes; while (a_dbox->next != NULL) a_dbox=a_dbox->next; a_dbox->next=(ctl__dbox *)ctl__malloc(sizeof(ctl__dbox)); a_dbox=a_dbox->next; } /* Now a_dbox points to new space. */ if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING) ctl__syntax_error(31,TRUE); a_dbox->name=tokenval.string; a_dbox->onopen =NULL; a_dbox->onreopen =NULL; a_dbox->onclose =NULL; a_dbox->icons =NULL; a_dbox->next =NULL; a_dbox->mih_token=NULL; a_dbox->displayed=FALSE; a_dbox->template=NULL; return a_dbox; } /* ctl__add_to_actionlist * * add an action at the end of an action list. * */ static ctl__action *ctl__add_to_actionlist(ctl__action *list,ctl__tokenstr *act) { if (list->action.name!=NULL) { #ifdef LOG fprintf(logfile,"New action in action list:\n"); #endif list->next=ctl__malloc(sizeof(ctl__action)); list=list->next; } *list=act->action; list->line=ctls->line; list->nest=ctls->nest; list->next=NULL; return list; } /* * ctl__add_string_to_actionlist * * add a string as an action at the end of the actionlist. * */ static ctl__action *ctl__add_string_to_actionlist(ctl__action *list, ctl__tokenstr *act) { char buffer[LINELEN]; #ifdef LOG fprintf(logfile,"String in action list:\n"); #endif ctl__readtoeol(buffer); act->action.action.name=act->string; act->action.args=ctl__malloc(strlen(buffer)+1); strcpy(act->action.args,buffer); if ((act->string[0]=='(') && (act->string[strlen(act->string)-1]==')')) act->action.type=ctl_ACT_LABEL; else act->action.type=ctl_ACT_STRING; return ctl__add_to_actionlist(list,act); } /* * ctl__new_entry * * add new entry to given menu. * return pointer to action list for the new entry. * */ static ctl__action *ctl__new_entry(ctl__menu *menu,int entry) { ctl__menu_entry *an_entry; int i; #ifdef LOG fprintf(logfile,"New Menu Entry:\n"); #endif if ( (entry!=-1) && (!menu->external) && ((entry<1) || (entry>menu->entrycount)) ) ctl__syntax_error(26,TRUE); else if (!menu->external) { if (entry>0) menu_setflags(menu->menu_body,entry,0,0); else for (i=1;i<=menu->entrycount;i++) menu_setflags(menu->menu_body,i,0,0); } if (menu->entries==NULL) /* first entry */ { menu->entries=(ctl__menu_entry *)ctl__malloc(sizeof(ctl__menu_entry)); an_entry=menu->entries; } else { an_entry=menu->entries; if (an_entry->num==entry) { if (an_entry->action->action.name!=NULL) ctl__syntax_error(27,TRUE); else return an_entry->action; } while (an_entry->next != NULL) { an_entry=an_entry->next; if (an_entry->num==entry) { if (an_entry->action->action.name!=NULL) ctl__syntax_error(27,TRUE); else return an_entry->action; } } an_entry->next=(ctl__menu_entry *)ctl__malloc(sizeof(ctl__menu_entry)); an_entry=an_entry->next; } an_entry->num=entry; an_entry->action=(ctl__action *)ctl__malloc(sizeof(ctl__action)); an_entry->action->action.name=NULL; an_entry->disabled=0; an_entry->next=NULL; an_entry->help_action=NULL; return an_entry->action; } /* add a new entry help action entry number is next token in file. * * * */ static ctl__action *ctl__add_entry_help(ctl__menu *menu) { ctl__tokenstr tokenval; ctl__menu_entry *an_entry; #ifdef LOG fprintf(logfile,"New Entry Help Action:\n"); #endif if (ctl__read_next_token(&tokenval)!=ctl_TOK_NUMBER) ctl__syntax_error(25,TRUE); if ((an_entry=ctl__find_entry(tokenval.num,menu))==NULL) { ctl__new_entry(menu,tokenval.num); an_entry=ctl__find_entry(tokenval.num,menu); } if (an_entry->help_action==NULL) { an_entry->help_action=(ctl__action *)ctl__malloc(sizeof(ctl__action)); an_entry->help_action->action.name=NULL; return an_entry->help_action; } else ctl__syntax_error(71,TRUE); /* Should never get here. */ return NULL; } /* add a new entry, entry number is next token in file. * * * */ static ctl__action *ctl__add_new_entry_from_file(ctl__menu *menu) { ctl__tokenstr tokenval; ctl__token token; if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_HELP) return ctl__add_entry_help(menu); if (token!=ctl_TOK_NUMBER) ctl__syntax_error(25,TRUE); return ctl__new_entry(menu,tokenval.num); } /* * ctl__new_icon * * add new icon to given dbox. * */ static ctl__action *ctl__new_icon(ctl__dbox *dbox,int inum) { ctl__icon *an_icon; #ifdef LOG fprintf(logfile,"New Icon:\n"); #endif if ((inum!=-1) && ((inum<0) || (inum>=dbox->iconcount))) ctl__syntax_error(37,TRUE); if (dbox->icons==NULL) /* first icon */ { dbox->icons=(ctl__icon *)ctl__malloc(sizeof(ctl__icon)); an_icon=dbox->icons; } else { an_icon=dbox->icons; if (an_icon->num==inum) { if (an_icon->action->action.name!=NULL) ctl__syntax_error(38,TRUE); else return an_icon->action; } while (an_icon->next != NULL) { an_icon=an_icon->next; if (an_icon->num==inum) { if (an_icon->action->action.name!=NULL) ctl__syntax_error(38,TRUE); else return an_icon->action; } } an_icon->next=(ctl__icon *)ctl__malloc(sizeof(ctl__icon)); an_icon=an_icon->next; } an_icon->num=inum; an_icon->action=(ctl__action *)ctl__malloc(sizeof(ctl__action)); an_icon->action->action.name=NULL; an_icon->disabled=0; an_icon->ticked=FALSE; an_icon->help_action=NULL; an_icon->next=NULL; return an_icon->action; } static ctl__action *ctl__add_icon_help(ctl__dbox *dbox) { ctl__tokenstr tokenval; ctl__icon *an_icon; #ifdef LOG fprintf(logfile,"New Icon Help:\n"); #endif if (ctl__read_next_token(&tokenval)!=ctl_TOK_NUMBER) ctl__syntax_error(36,TRUE); if ((an_icon=ctl__find_icon(tokenval.num,dbox))==NULL) { ctl__new_icon(dbox,tokenval.num); an_icon=ctl__find_icon(tokenval.num,dbox); } if (an_icon->help_action==NULL) { an_icon->help_action=(ctl__action *) ctl__malloc(sizeof(ctl__action)); an_icon->help_action->action.name=NULL; return an_icon->help_action; } else ctl__syntax_error(71,TRUE); /* Should never get here. */ return NULL; } /* * ctl__add_new_icon_from_file * * add new icon to given dbox. icon number is next token in file. * */ static ctl__action *ctl__add_new_icon_from_file(ctl__dbox *dbox) { ctl__tokenstr tokenval; ctl__token token; /* get icon number */ if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_HELP) return ctl__add_icon_help(dbox); if (token!=ctl_TOK_NUMBER) ctl__syntax_error(36,TRUE); return ctl__new_icon(dbox,tokenval.num); } /* * ctl__new_key * * add new entry to given ctl. * */ static ctl__action *ctl__new_key(ctl *cctl) { ctl__tokenstr tokenval; ctl__key *a_key; int keynum; ctl__token token; #ifdef LOG fprintf(logfile,"New Hot Key:\n"); #endif /* get entry number */ keynum=-1; if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_NUMBER) keynum=tokenval.num; else if (token==ctl_TOK_STRING) keynum=ctl__keynum(tokenval.string); if (keynum==-1) ctl__syntax_error(40,TRUE); if (cctl->keys==NULL) /* first entry */ { cctl->keys=(ctl__key *)ctl__malloc(sizeof(ctl__key)); a_key=cctl->keys; } else { a_key=cctl->keys; if (a_key->keycode==keynum) ctl__syntax_error(41,TRUE); while (a_key->next != NULL) { a_key=a_key->next; if (a_key->keycode==keynum) ctl__syntax_error(41,TRUE); } a_key->next=(ctl__key *)ctl__malloc(sizeof(ctl__key)); a_key=a_key->next; } a_key->keycode=keynum; a_key->action=(ctl__action *)ctl__malloc(sizeof(ctl__action)); a_key->action->action.name=NULL; a_key->action->next=NULL; a_key->disabled=FALSE; a_key->next=NULL; return a_key->action; } /* * ctl__submenu * * attach submenu to given menu. * */ static ctl__action *ctl__submenu(ctl *cctl,ctl__menu *a_menu) { ctl__token token; ctl__tokenstr tokenval; ctl__action *actionlist; ctl__actionstr act; int entry; ctl__menu *submenu; ctl__dbox *a_dbox; /* get entry number */ if (ctl__read_next_token(&tokenval)!=ctl_TOK_NUMBER) ctl__syntax_error(25,TRUE); if ( (tokenval.num!=-1) && (!a_menu->external) && ((tokenval.num<1) || (tokenval.num>a_menu->entrycount)) ) ctl__syntax_error(26,TRUE); if (ctl__find_entry(tokenval.num,a_menu)!=NULL) ctl__syntax_error(27,TRUE); entry=tokenval.num; if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_MENU) { if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING) ctl__syntax_error(13,TRUE); submenu=ctl__find_menu(tokenval.string,cctl); if (!a_menu->external) { int en; for (en=((entry==-1)?1:entry); en<=((entry==-1)?a_menu->entrycount:entry); en++) { ctl__menu_item(a_menu->menu_body,en)->flags|=wimp_MSUBLINKMSG; ctl__menu_item(a_menu->menu_body,en)->submenu= (submenu->external ? (wimp_menustr *)1 : menu_syshandle(submenu->menu_body)); if (submenu->external) submenu->parent=ctl__menu_item(a_menu->menu_body,en); menu_setflags(a_menu->menu_body,en,0,0); } } actionlist=ctl__new_entry(a_menu,entry); actionlist->type=ctl_ACT_FUNCTION; act.name="<submenu>"; actionlist->action.address= ctl__find_action(&act,ctls->actions,FALSE,TRUE); actionlist->args=(char *)submenu; actionlist->line=ctls->line; actionlist->nest=ctls->nest; actionlist->next=NULL; return actionlist; } else if (token==ctl_TOK_DBOX) { if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING) ctl__syntax_error(31,TRUE); a_dbox=ctl__find_dbox(tokenval.string,cctl); if (!a_menu->external) { int en; for (en=((entry==-1)?1:entry); en<=((entry==-1)?a_menu->entrycount:entry); en++) { ctl__menu_item(a_menu->menu_body,en)->submenu=(wimp_menustr *) a_dbox; ctl__menu_item(a_menu->menu_body,en)->flags|=wimp_MSUBLINKMSG; menu_setflags(a_menu->menu_body,en,0,0); } } actionlist=ctl__new_entry(a_menu,entry); actionlist->type=ctl_ACT_FUNCTION; act.name="<subdbox>"; actionlist->action.address= ctl__find_action(&act,ctls->actions,FALSE,TRUE); actionlist->args=(char *)a_dbox; actionlist->line=ctls->line; actionlist->nest=ctls->nest; actionlist->next=NULL; return actionlist; } else if (token==ctl_TOK_WARNING) { if (!a_menu->external) { int en; for (en=((entry==-1)?1:entry); en<=((entry==-1)?a_menu->entrycount:entry); en++) { ctl__menu_item(a_menu->menu_body,en)->flags|=wimp_MSUBLINKMSG; menu_setflags(a_menu->menu_body,en,0,0); ctl__menu_item(a_menu->menu_body,en)->submenu=(wimp_menustr *)1; } } return ctl__new_entry(a_menu,entry); } else ctl__syntax_error(43,TRUE); /*NEVER */ return NULL; } /* * ctl__subdboxmenu * * attach submenu to given dbox. * */ static ctl__action *ctl__subdboxmenu(ctl *cctl,ctl__dbox *dbx) { ctl__token token; ctl__tokenstr tokenval; ctl__action *actionlist; ctl__actionstr act; int icon; ctl__dbox *a_dbox; #ifdef DBOXSUBMENUS ctl__menu *submenu; #endif /* get icon number */ if (ctl__read_next_token(&tokenval)!=ctl_TOK_NUMBER) ctl__syntax_error(25,TRUE); if ((tokenval.num!=-1) && ((tokenval.num<0) || (tokenval.num>=dbx->iconcount))) ctl__syntax_error(26,TRUE); if (ctl__find_icon(tokenval.num,dbx)!=NULL) ctl__syntax_error(27,TRUE); icon=tokenval.num; if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_MENU) { #ifndef DBOXMENUS ctl__syntax_error(47,TRUE); #else if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING) ctl__syntax_error(13,TRUE); submenu=ctl__find_menu(tokenval.string,cctl); actionlist=ctl__new_icon(dbx,icon); actionlist->type=ctl_ACT_FUNCTION; act.name="<dsubmenu>"; actionlist->action.address= ctl__find_action(&act,ctls->actions,FALSE,TRUE); actionlist->args=(char *)submenu; actionlist->line=ctls->line; actionlist->nest=ctls->nest; actionlist->next=NULL; return actionlist; #endif /* DBOXMENUS */ } else if (token==ctl_TOK_DBOX) { if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING) ctl__syntax_error(31,TRUE); a_dbox=ctl__find_dbox(tokenval.string,cctl); actionlist=ctl__new_icon(dbx,icon); actionlist->type=ctl_ACT_FUNCTION; act.name="<dsubdbox>"; actionlist->action.address= ctl__find_action(&act,ctls->actions,FALSE,TRUE); actionlist->args=(char *)a_dbox; actionlist->line=ctls->line; actionlist->nest=ctls->nest; actionlist->next=NULL; return actionlist; } else ctl__syntax_error(43,TRUE); /*NEVER */ return NULL; } static int ctl__exec(ctl__action *action) { ctl__argbuf argbuf; if (action->type==ctl_ACT_FUNCTION) { if (action->action.address->syntax==NULL) return (int) (action->action.address->function.function( ctls->current_handle->user_handle, action->action.address->function.handle, action->args, ctls->return_code)); else { ctl__read_args(action->action.address->syntax,action->args,&argbuf); return (int)(action->action.address->function.function( ctls->current_handle->user_handle, action->action.address->function.handle, (char *) &argbuf, ctls->return_code)); } } else { ctl__actionstr act,*actpos; act.name=action->action.name; actpos=ctl__find_action(&act,ctls->actions,FALSE,FALSE); if (actpos==NULL) { if (action->type==ctl_ACT_LABEL) return 0; ctls->line=action->line; ctl__error(44,act.name,FALSE); return 0; } else { if (actpos->syntax==NULL) return (int)(actpos->function.function( ctls->current_handle->user_handle, actpos->function.handle, action->args, ctls->return_code)); else { ctl__read_args(actpos->syntax,action->args,&argbuf); return (int)(actpos->function.function( ctls->current_handle->user_handle, actpos->function.handle, (char *) &argbuf, ctls->return_code)); } } } return 0; } static void ctl__run(ctl__action *action) { BOOL submenu=(wimpt_last_event()->e!=wimp_EMENU); BOOL skipflag=FALSE; ctl__action *an_action=action; int tmp_skip=ctls->skip; #ifdef LOG if (logfile!=NULL) { fclose(logfile); logfile=NULL; } #endif if ((action==NULL) || (action==(ctl__action *)-1)) return; ctls->skip=-1; for (an_action=action;an_action!=NULL;an_action=an_action->next) { if (skipflag) { skipflag=FALSE; continue; } if ((ctls->skip<0) || (ctls->skip>=an_action->nest)) { ctls->return_code=ctl__exec(an_action); if (ctls->skip==-2) { ctls->skip=an_action->nest; skipflag=TRUE; } else if (ctls->skip!=-3) ctls->skip=-1; if ((an_action->type==ctl_ACT_FUNCTION) && (an_action->action.address->function.function==ctl__submenu_request) && (submenu) ) break; } } ctls->skip=tmp_skip; } static void ctl__get_template(ctl__dbox *a_dbox) { ctl__tokenstr token; if (ctl__read_next_token(&token)!=ctl_TOK_STRING) ctl__syntax_error(54,TRUE); if (template_find(token.string)==NULL) ctl__error(53,token.string,TRUE); a_dbox->template=token.string; a_dbox->dbox_body=dbox_new(token.string); if (a_dbox->dbox_body==NULL) ctl__error(32,a_dbox->name,TRUE); a_dbox->iconcount=ctl__iconcount(&a_dbox->dbox_body); dbox_dispose(&a_dbox->dbox_body); } static void ctl__get_dbox_help(ctl__dbox *a_dbox) { ctl__tokenstr token; ctl__token type; type=ctl__read_next_token(&token); if (type==ctl_TOK_HELPACTION) werr(1,"Action help not implemented."); if (type!=ctl_TOK_TOKEN) ctl__syntax_error(62,TRUE); if (a_dbox->mih_token!=NULL) ctl__syntax_error(60,TRUE); if (ctl__read_next_token(&token)!=ctl_TOK_STRING) ctl__syntax_error(61,TRUE); a_dbox->mih_token=token.string; } static void ctl__get_menu_help(ctl__menu *a_menu) { ctl__tokenstr token; ctl__token type; type=ctl__read_next_token(&token); if (type==ctl_TOK_HELPACTION) werr(1,"Action help not implemented."); if (type!=ctl_TOK_TOKEN) ctl__syntax_error(62,TRUE); if (a_menu->mih_token!=NULL) ctl__syntax_error(60,TRUE); if (ctl__read_next_token(&token)!=ctl_TOK_STRING) ctl__syntax_error(61,TRUE); a_menu->mih_token=token.string; } /* ctl__load : * open and load the control file. * if errors is TRUE generate errors for non exsistant actions. */ static void ctl__load(BOOL errors) { FILE *control; ctl__token token; ctl__tokenstr value; ctl *current_ctl=NULL; ctl__menu *current_menu=NULL; ctl__dbox *current_dbox=NULL; ctl__action *action_list=NULL; ctl__state saved_state=ctl_ST_LOADING; if (control=res_openfile("Control","r"),control==NULL) { ctl__error(5,NULL,TRUE); return; } ctls->file=control; ctls->state=ctl_ST_LOADING; ctls->nest=0; do { token=ctl__read_next_token(&value); switch(token) { case ctl_TOK_EOF: fclose(ctls->file); if (ctls->state!=ctl_ST_LOADING) ctl__error(9,NULL,TRUE); if (ctls->nest!=0) ctl__syntax_error(29,TRUE); break; case ctl_TOK_CTL: if (ctls->state!=ctl_ST_LOADING) ctl__syntax_error(10,TRUE); if (ctls->nest!=0) ctl__syntax_error(29,TRUE); current_ctl=ctl__new_ctl(); ctls->state=ctl_ST_CTLDEF; break; case ctl_TOK_MENU: if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(10,TRUE); if (ctls->nest!=0) ctl__syntax_error(29,TRUE); current_menu=ctl__new_menu(current_ctl); ctls->state=ctl_ST_MENUDEF; break; case ctl_TOK_DBOX: if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(30,TRUE); if (ctls->nest!=0) ctl__syntax_error(29,TRUE); current_dbox=ctl__new_dbox(current_ctl); ctls->state=ctl_ST_DBOXDEF; break; case ctl_TOK_ONOPEN: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if ((ctls->state!=ctl_ST_MENUDEF) && (ctls->state!=ctl_ST_DBOXDEF)) ctl__syntax_error(14,TRUE); if (((ctls->state==ctl_ST_MENUDEF) && (current_menu->onopen!=NULL)) ||((ctls->state==ctl_ST_DBOXDEF) && (current_dbox->onopen!=NULL))) ctl__error(15,(ctls->state==ctl_ST_MENUDEF)? current_menu->name:current_dbox->name,TRUE); #ifdef LOG fprintf(logfile,"Onopen action:\n"); #endif action_list=(ctl__action *)ctl__malloc(sizeof(ctl__action)); action_list->action.name=NULL; if (ctls->state==ctl_ST_MENUDEF) current_menu->onopen=action_list; else current_dbox->onopen=action_list; saved_state=ctls->state; ctls->state=ctl_ST_GETACTION; break; case ctl_TOK_ONREOPEN: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if ((ctls->state!=ctl_ST_MENUDEF) && (ctls->state!=ctl_ST_DBOXDEF)) ctl__syntax_error(14,TRUE); if (((ctls->state==ctl_ST_MENUDEF) && (current_menu->onreopen!=NULL)) ||((ctls->state==ctl_ST_DBOXDEF) && (current_dbox->onreopen!=NULL))) ctl__error(15,(ctls->state==ctl_ST_MENUDEF)? current_menu->name:current_dbox->name,TRUE); #ifdef LOG fprintf(logfile,"Onreopen action:\n"); #endif action_list=(ctl__action *)ctl__malloc(sizeof(ctl__action)); action_list->action.name=NULL; if (ctls->state==ctl_ST_MENUDEF) current_menu->onreopen=action_list; else current_dbox->onreopen=action_list; saved_state=ctls->state; ctls->state=ctl_ST_GETACTION; break; case ctl_TOK_NOREOPEN: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(14,TRUE); if (current_dbox->onreopen!=NULL) ctl__error(15,current_dbox->name,TRUE); current_dbox->onreopen=(ctl__action *)-1; break; case ctl_TOK_ONCLOSE: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(33,TRUE); if (current_dbox->onclose!=NULL) ctl__error(34,current_dbox->name,TRUE); #ifdef LOG fprintf(logfile,"Onclose action:\n"); #endif action_list=(ctl__action *)ctl__malloc(sizeof(ctl__action)); action_list->action.name=NULL; current_dbox->onclose=action_list; saved_state=ctls->state; ctls->state=ctl_ST_GETACTION; break; case ctl_TOK_ENDDBOX: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(17,TRUE); ctls->state=ctl_ST_CTLDEF; break; case ctl_TOK_ENDMENU: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if ((ctls->state!=ctl_ST_MENUDEF) && (ctls->state!=ctl_ST_GETACTION)) ctl__syntax_error(18,TRUE); ctls->state=ctl_ST_CTLDEF; break; case ctl_TOK_ENDCTL: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(19,TRUE); ctls->state=ctl_ST_LOADING; break; case ctl_TOK_OPENBLOCK: if ((ctls->state!=ctl_ST_GETACTION) && (ctls->state!=ctl_ST_GETACTIONBLOCK)) ctl__syntax_error(16,TRUE); ctls->nest++; ctls->state=ctl_ST_GETACTIONBLOCK; break; case ctl_TOK_CLOSEBLOCK: if (ctls->state!=ctl_ST_GETACTIONBLOCK) ctl__syntax_error(20,TRUE); if (--ctls->nest<0) ctl__syntax_error(28,TRUE); if (ctls->nest==0) ctls->state=saved_state; break; case ctl_TOK_ENTRY: if (ctls->state==ctl_ST_GETACTION) ctls->state=saved_state; if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_MENUDEF) ctl__syntax_error(24,TRUE); action_list=ctl__add_new_entry_from_file(current_menu); saved_state=ctls->state; ctls->state=ctl_ST_GETACTION; break; case ctl_TOK_SUBMENU: if (ctls->state==ctl_ST_GETACTION) ctls->state=saved_state; if (ctls->nest!=0) ctl__syntax_error(29,TRUE); else if (ctls->state==ctl_ST_MENUDEF) action_list=ctl__submenu(current_ctl,current_menu); else if (ctls->state==ctl_ST_DBOXDEF) action_list=ctl__subdboxmenu(current_ctl,current_dbox); else ctl__syntax_error(24,TRUE); if (action_list!=NULL) { saved_state=ctls->state; ctls->state=ctl_ST_GETACTION; } break; case ctl_TOK_ONKEY: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(39,TRUE); action_list=ctl__new_key(current_ctl); saved_state=ctls->state; ctls->state=ctl_ST_GETACTION; break; case ctl_TOK_ONCLICK: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(68,TRUE); if (current_ctl->onclick!=NULL) ctl__syntax_error(69,TRUE); #ifdef LOG fprintf(logfile,"Onclick action list:\n"); #endif action_list=(current_ctl->onclick= (ctl__action *)ctl__malloc(sizeof(ctl__action))); action_list->action.name=NULL; action_list->next=NULL; saved_state=ctls->state; ctls->state=ctl_ST_GETACTION; break; case ctl_TOK_ICON: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(35,TRUE); if (current_dbox->template==NULL) ctl__error(55,current_dbox->name,TRUE); action_list=ctl__add_new_icon_from_file(current_dbox); saved_state=ctls->state; ctls->state=ctl_ST_GETACTION; break; case ctl_TOK_ACTION: if (ctls->state==ctl_ST_GETACTION) ctls->nest++; if ((ctls->state!=ctl_ST_GETACTION) && (ctls->state!=ctl_ST_GETACTIONBLOCK)) ctl__syntax_error(21,TRUE); action_list=ctl__add_to_actionlist(action_list,&value); if (ctls->state==ctl_ST_GETACTION) { ctls->state=saved_state; ctls->nest--; } break; case ctl_TOK_STRING: if ((ctls->state!=ctl_ST_GETACTION) && (ctls->state!=ctl_ST_GETACTIONBLOCK)) ctl__syntax_error(22,TRUE); if ((errors) && ((value.string[0] != '(') || (value.string[strlen(value.string)-1] != ')') ) ) ctl__syntax_error(23,TRUE); if (ctls->state==ctl_ST_GETACTION) ctls->nest++; action_list=ctl__add_string_to_actionlist(action_list,&value); if (ctls->state==ctl_ST_GETACTION) { ctls->state=saved_state; ctls->nest--; } break; case ctl_TOK_TEMPLATE: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(52,TRUE); if (current_dbox->template!=NULL) ctl__error(56,current_dbox->name,TRUE); ctl__get_template(current_dbox); break; case ctl_TOK_HELP: if (ctls->nest!=0) ctl__syntax_error(29,TRUE); if ((ctls->state!=ctl_ST_DBOXDEF) && (ctls->state!=ctl_ST_MENUDEF)) ctl__syntax_error(59,TRUE); switch(ctls->state) { case ctl_ST_DBOXDEF: ctl__get_dbox_help(current_dbox); break; case ctl_ST_MENUDEF: ctl__get_menu_help(current_menu); break; } break; case ctl_TOK_COMMENT: ctl__skip_toeol(); break; case ctl_TOK_EOL: ctls->line++; if (ctls->current_char=='#') ctl__skip_toeol(); break; } } while (token!=ctl_TOK_EOF); ctls->state=ctl_ST_LOADED; ctls->line=0; } static menu ctl__menu_maker(ctl__handlestr *handle) { ctls->current_handle=handle; ctls->current_menu=handle->mnu; ctls->top_menu=handle->mnu; ctls->return_code=(wimpt_last_event()->data.but.m.i); if (!event_is_menu_being_recreated()) ctl__run(handle->mnu->onopen); return handle->mnu->menu_body; } static void ctl__menu_select(ctl__handlestr *handle,char *hit) { ctl__menu *mnu; ctl__menu_entry *entry; char *c; BOOL recreate=event_is_menu_being_recreated(); if (wimpt_last_event()->e!=wimp_EMENU) recreate=FALSE; else { wimp_mousestr m; wimp_get_point_info(&m); recreate=((m.bbits & wimp_BRIGHT) != 0); } ctls->current_menu=handle->mnu; for (c=hit;*(c+1);c++) { if (ctls->current_menu->external) { if ((wimpt_last_event()->e==wimp_ESEND) && !*(c+2)) *(c+1)='\0'; strcpy(ctls->external_hit,c); } if ((wimpt_last_event()->e==wimp_ESEND) && !*(c+2)) { *(c+1)='\0'; break; } entry=ctl__find_entry(*c,ctls->current_menu); if (entry==NULL) entry=ctl__find_entry(-1,ctls->current_menu); if (entry==NULL) break; if (entry->action->action.address->function.function!= ctl__submenu_request) break; ctls->current_menu=(ctl__menu *) entry->action->args; } strcpy(ctls->last_menu_hit,hit); entry=ctl__find_entry(*c,ctls->current_menu); ctls->return_code=*c; if (entry!=NULL) ctl__run(entry->action); else if (entry=ctl__find_entry(-1,ctls->current_menu),entry!=NULL) ctl__run(entry->action); if (recreate) { mnu=handle->mnu; for (c=ctls->last_menu_hit;*(c+1);c++) { entry=ctl__find_entry(*c,mnu); if (entry==NULL) entry=ctl__find_entry(-1,ctls->current_menu); if (entry==NULL) break; if (mnu->external) break; ctl__run(mnu->onreopen); mnu=(ctl__menu *) entry->action->args; } ctl__run(mnu->onreopen); wimp_create_menu(menu_syshandle(handle->mnu->menu_body),0,0); } } /* ctl__find_action_in_list. * * given an action name and an action list returns * TRUE if action is in the list, FALSE if not. * * */ static BOOL ctl__find_action_in_list(char *name,ctl__action *list) { ctl__action *act; static ctl__actionstr the_action,*the_action_address; if (the_action.name!=name) { the_action.name=name; the_action_address= ctl__find_action(&the_action,ctls->actions,FALSE,FALSE); } if (list==NULL) return FALSE; else if (list==(ctl__action *)-1) return FALSE; for (act=list;act!=NULL;act=act->next) { if ((act->type==ctl_ACT_LABEL) && (strcmp(act->action.name,the_action.name)==0)) return TRUE; if ((act->type==ctl_ACT_STRING) && (strcmp(act->action.name,the_action.name)==0)) { act->type=ctl_ACT_LABEL; return TRUE; } if (act->type!=ctl_ACT_FUNCTION) continue; if (act->action.address==the_action_address) return TRUE; if (act->action.address->function.function!=ctl__submenu_request) continue; if ( ( (act->action.address->function.handle==(void *) 1) || (act->action.address->function.handle==(void *) 3) ) && ( (ctl__find_action_in_list(name,((ctl__menu *)act->args)->onopen)) || (ctl__find_action_in_list(name,((ctl__menu *)act->args)->onreopen)) ) ) return TRUE; if ( ( (act->action.address->function.handle==(void *) 2) || (act->action.address->function.handle==(void *) 4) ) && ( (ctl__find_action_in_list(name,((ctl__dbox *)act->args)->onopen)) || (ctl__find_action_in_list(name,((ctl__dbox *)act->args)->onreopen)) || (ctl__find_action_in_list(name,((ctl__dbox *)act->args)->onclose)) ) ) return TRUE; } return FALSE; } /* * ctl__find action. * * Find all places in given ctl where the action given is executed * for every place call func with arg arg, pointer to entry/icon, * entry/icon flag. * */ static void ctl__find_action_in_ctl(ctl *a_ctl,char *name,void (func()),void *arg) { ctl__menu_entry *entry; ctl__menu *a_menu; ctl__dbox *a_dbox; ctl__icon *icon; /*Must do dboxes first because of writeable icons */ for (a_dbox=a_ctl->dboxes;a_dbox!=NULL;a_dbox=a_dbox->next) for (icon=a_dbox->icons;icon!=NULL;icon=icon->next) { if ((icon->action!=NULL) && (ctl__find_action_in_list(name,icon->action))) { func(arg,a_dbox,icon,ctl_ENTRY_ICON,a_dbox->displayed); } } for (a_menu=a_ctl->menus;a_menu!=NULL;a_menu=a_menu->next) for (entry=a_menu->entries;entry!=NULL;entry=entry->next) { if ((entry->action!=NULL)&&(ctl__find_action_in_list(name,entry->action))) { func(arg,a_menu,entry,ctl_ENTRY_MENUENTRY,FALSE); } } } /* ctl__tick_entry * * Tick the given entry / select icons if in a displayed dbox. * */ static void ctl__tick_entry(void *arg,void *parent, void *entry,ctl_entrytype type,BOOL displayed) { switch(type) { case ctl_ENTRY_MENUENTRY: if ((BOOL)arg) ctl__menu_item(((ctl__menu *)parent)->menu_body, ((ctl__menu_entry *)entry)->num)->flags|=wimp_MTICK; else ctl__menu_item(((ctl__menu *)parent)->menu_body, ((ctl__menu_entry *)entry)->num)->flags&=~wimp_MTICK; break; case ctl_ENTRY_ICON: if (displayed) { if ((BOOL)arg) wimp_set_icon_state( dbox_syshandle(((ctl__dbox *)parent)->dbox_body), ((ctl__icon *)entry)->num,wimp_ISELECTED,wimp_ISELECTED); else wimp_set_icon_state( dbox_syshandle(((ctl__dbox *)parent)->dbox_body), ((ctl__icon *)entry)->num,0,wimp_ISELECTED); } ((ctl__icon *)entry)->ticked=(BOOL)arg; break; } } /* ctl__apply_function * * Apply the given function on the given action entries / icons. * */ static void ctl__apply_function(void (arg()),void *parent, void *entry,ctl_entrytype type,BOOL displayed) { ctl_parentstr the_parent; switch(type) { case ctl_ENTRY_MENUENTRY: the_parent.parent_menu= menu_syshandle(((ctl__menu *)parent)->menu_body); arg(the_parent, ((ctl__menu_entry *)entry)->num,ctl_ENTRY_MENUENTRY); break; case ctl_ENTRY_ICON: the_parent.parent_window= dbox_syshandle(((ctl__dbox *)parent)->dbox_body); if (displayed) arg(the_parent, ((ctl__icon *)entry)->num,ctl_ENTRY_ICON); break; } } /* ctl__make_entry_writeable * * Make the given entry /icon writeable. * */ static void ctl__make_entry_writeable(void *arg,void *parent, void *entry,ctl_entrytype type,BOOL displayed) { ctl__indirectstr *data=(ctl__indirectstr *)arg; switch(type) { case ctl_ENTRY_MENUENTRY: if (data->flag) /* already created buffer */ menu_make_writeable(((ctl__menu *)parent)->menu_body, ((ctl__menu_entry *)entry)->num,data->buffer,data->len,data->valid); else /* This is the first menu entry and there were no icons ! We know this because we know the order find_action_in_ctl works which is very important !! */ { data->buffer=ctl__malloc(data->len+5); *data->buffer='\0'; menu_make_writeable(((ctl__menu *)parent)->menu_body, ((ctl__menu_entry *)entry)->num,data->buffer,data->len,data->valid); data->flag=TRUE; } break; case ctl_ENTRY_ICON: ((ctl__icon *)entry)->writeable=TRUE; if (data->flag) werr(TRUE, msgs_lookup( "ctdupind:Duplicate writeable action icon (Icon %i in dbox %s)"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name); if (displayed) { wimp_icon icon; wimp_get_icon_info(dbox_syshandle(((ctl__dbox *)parent)->dbox_body), ((ctl__icon *)entry)->num,&icon); if (((icon.flags & wimp_ITEXT)==0) || ((icon.flags & wimp_INDIRECT)==0)) werr(TRUE, msgs_lookup( "ctindicn:Icon %i in dbox %s should be an indirected text icon"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name); if ((icon.flags & (wimp_BWRITABLE<<12))!=(wimp_BWRITABLE<<12)) werr(TRUE, msgs_lookup( "ctwrticn:Icon %i in dbox %s should be a writeable icon"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name); if (icon.data.indirecttext.bufflen<data->len) werr(TRUE, msgs_lookup( "cticnbuf:Icon %i in dbox %s should have a buffer of at least %i positions."), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name,data->len); if ( ((int)icon.data.indirecttext.validstring>0) && (strncmp(icon.data.indirecttext.validstring,data->valid, strlen(data->valid))!=0)) werr(TRUE, msgs_lookup( "cticnval:Icon %i in dbox %s should have a validation string of %s"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name,data->valid); data->buffer=icon.data.indirecttext.buffer; data->flag=TRUE; } else { wimp_wind *the_template= template_syshandle(((ctl__dbox *)parent)->template); wimp_icon *iconptr=(wimp_icon *)((int)the_template+sizeof(wimp_wind)); iconptr+=((ctl__icon *)entry)->num; ctl__error(67,((ctl__dbox *)parent)->name,TRUE); if (((iconptr->flags & wimp_ITEXT)==0) || ((iconptr->flags & wimp_INDIRECT)==0)) werr(TRUE, msgs_lookup( "ctindicn:Icon %i in dbox %s should be an indirected text icon"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name); if ((iconptr->flags & (wimp_BWRITABLE<<12))!=(wimp_BWRITABLE<<12)) werr(TRUE, msgs_lookup( "ctwrticn:Icon %i in dbox %s should be a writeable icon"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name); if (iconptr->data.indirecttext.bufflen<data->len) werr(TRUE, msgs_lookup( "cticnbuf:Icon %i in dbox %s should have a buffer of at least %i positions."), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name,data->len); if ( ((int)(iconptr->data.indirecttext.validstring)>0) && (strncmp(iconptr->data.indirecttext.validstring,data->valid, strlen(data->valid))!=0)) werr(TRUE, msgs_lookup( "cticnval:Icon %i in dbox %s should have a validation string of %s"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name,data->valid); data->buffer=iconptr->data.indirecttext.buffer; data->flag=TRUE; } break; } } /* ctl__set_entry_text * * Set the given entry /icon text. * */ static void ctl__set_entry_text(void *arg,void *parent, void *entry,ctl_entrytype type,BOOL displayed) { switch(type) { case ctl_ENTRY_MENUENTRY: { wimp_menuitem *item; item=ctl__menu_item(((ctl__menu *)parent)->menu_body, ((ctl__menu_entry *)entry)->num); item->iconflags|=wimp_INDIRECT | wimp_ITEXT; item->data.indirecttext.buffer=(char *)arg; item->data.indirecttext.bufflen=strlen((char *)arg+1); item->data.indirecttext.validstring=""; } break; case ctl_ENTRY_ICON: if (displayed) { wimp_icon icon; wimp_get_icon_info(dbox_syshandle(((ctl__dbox *)parent)->dbox_body), ((ctl__icon *)entry)->num,&icon); if (((icon.flags & wimp_ITEXT)==0) || ((icon.flags & wimp_INDIRECT)==0)) werr(TRUE, msgs_lookup( "ctindicn:Icon %i in dbox %s should be an indirected text icon"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name); dbox_setfield(((ctl__dbox *)parent)->dbox_body, ((ctl__icon *)entry)->num, (char *)arg); } else { wimp_wind *the_template= template_syshandle(((ctl__dbox *)parent)->template); wimp_icon *iconptr=(wimp_icon *)((int)the_template+sizeof(wimp_wind)); iconptr+=((ctl__icon *)entry)->num; if (((iconptr->flags & wimp_ITEXT)==0) || ((iconptr->flags & wimp_INDIRECT)==0)) werr(TRUE, msgs_lookup( "ctindicn:Icon %i in dbox %s should be an indirected text icon"), ((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name); strncpy(iconptr->data.indirecttext.buffer, (char *)arg, iconptr->data.indirecttext.bufflen); } break; } } /* ctl__set_caret_in_entry * * Set the caret in the given entry /icon. * */ static void ctl__set_caret_in_entry(void *arg,void *parent, void *entry,ctl_entrytype type,BOOL displayed) { if ((*(int *)arg)++) return; if ((type==ctl_ENTRY_ICON) && (displayed)) { wimp_caretstr c; c.w=dbox_syshandle(((ctl__dbox *)parent)->dbox_body); c.i=((ctl__icon *)entry)->num; c.height=-1; c.index=0; wimp_set_caret_pos(&c); } } /* * * BOOL ctl__chk_disabled(ctl__action *list) * * Return true if any of the actions on the list are disabled. * */ static BOOL ctl__chk_disabled(ctl__action *list) { ctl__actionstr act,*actadr; if (list==NULL) return FALSE; if ((list->type==ctl_ACT_FUNCTION) && ((list->action.address)->disabled)) return TRUE; else if ((list->type==ctl_ACT_STRING) || (list->type==ctl_ACT_LABEL)) { act.name=list->action.name; actadr=ctl__find_action(&act,ctls->actions,FALSE,FALSE); if ((actadr!=NULL) && (actadr->disabled)) return TRUE; } return ctl__chk_disabled(list->next); } /* ctl__enable_entry * * Fade the given entry / icon if in a displayed dbox. * */ static void ctl__enable_entry(void *arg,void *parent, void *entry,ctl_entrytype type,BOOL displayed) { switch(type) { case ctl_ENTRY_MENUENTRY: if (!(BOOL)arg) { ctl__menu_item(((ctl__menu *)parent)->menu_body, ((ctl__menu_entry *)entry)->num)->iconflags|=wimp_INOSELECT; } else if (!ctl__chk_disabled(((ctl__menu_entry *)entry)->action)) ctl__menu_item(((ctl__menu *)parent)->menu_body, ((ctl__menu_entry *)entry)->num)->iconflags&=~wimp_INOSELECT; break; case ctl_ENTRY_ICON: if (!(BOOL)arg) if (displayed) { if ((BOOL)arg) wimp_set_icon_state( dbox_syshandle(((ctl__dbox *)parent)->dbox_body), ((ctl__icon *)entry)->num,wimp_INOSELECT,wimp_INOSELECT); else if (!ctl__chk_disabled(((ctl__icon *)entry)->action)) wimp_set_icon_state( dbox_syshandle(((ctl__dbox *)parent)->dbox_body), ((ctl__icon *)entry)->num,0,wimp_INOSELECT); } ((ctl__icon *)entry)->disabled=(BOOL)arg; break; } } static BOOL ctl__process_help_event(wimp_eventstr *e) { ctl__handlestr *handle=ctl__find_handle(e->data.msg.data.helprequest.m.w); if (e->data.msg.data.helprequest.m.w<0) return FALSE; if (handle==NULL) /* Not in a window is it in our menu ? */ { _kernel_swi_regs r; wimp_msgstr m; char token[50]; int buf[30],i; ctl__menu *a_menu; ctl__menu_entry *an_entry; r.r[0]=1; r.r[1]=(int)buf; r.r[2]=e->data.msg.data.helprequest.m.w; r.r[3]=e->data.msg.data.helprequest.m.i; _kernel_swi(XOS_Bit | Wimp_GetMenuState,&r,&r); if (buf[0]==-1) return FALSE; /* No Menu Open */ a_menu=ctls->top_menu; for (i=0;buf[i+1]!=-1;i++) a_menu=(ctl__menu *)(ctl__find_entry(buf[i]+1,a_menu)->action->args); an_entry=ctl__find_entry(buf[i]+1,a_menu); if (an_entry==NULL) an_entry=ctl__find_entry(-1,a_menu); if ((an_entry!=NULL) && (an_entry->help_action!=NULL)) { ctl__run(an_entry->help_action); return TRUE; } if (a_menu->mih_token==NULL) return FALSE; sprintf(token,"%s%i\0",a_menu->mih_token,1+buf[i]); strcpy(m.data.helpreply.text,msgs_lookup(token)); m.hdr.action=wimp_MHELPREPLY; m.hdr.your_ref=e->data.msg.hdr.my_ref; m.hdr.my_ref=0; m.hdr.size=220; wimp_sendmessage(wimp_ESEND,&m,e->data.msg.hdr.task); return TRUE; } else if (handle->help_token==NULL) return FALSE; else { wimp_msgstr m; char token[50]; int inum; if ((inum=e->data.msg.data.helprequest.m.i)>=0) { if (handle->the_dbox!=NULL) { ctl__icon *an_icon=ctl__find_icon(inum,handle->the_dbox); if (an_icon==NULL) an_icon=ctl__find_icon(-1,handle->the_dbox); if ((an_icon!=NULL) && (an_icon->help_action!=NULL)) { ctl__run(an_icon->help_action); return TRUE; } } sprintf(token,"%s%i\0",handle->help_token,inum); strcpy(m.data.helpreply.text,msgs_lookup(token)); } else strcpy(m.data.helpreply.text,msgs_lookup(handle->help_token)); m.hdr.action=wimp_MHELPREPLY; m.hdr.your_ref=e->data.msg.hdr.my_ref; m.hdr.my_ref=0; m.hdr.size=220; wimp_sendmessage(wimp_ESEND,&m,e->data.msg.hdr.task); } return TRUE; } static BOOL ctl__process_key_event(wimp_eventstr *e) { ctl__handlestr *handle; ctl__key *key; if (handle=ctl__find_handle(e->data.key.c.w),handle==NULL) return FALSE; ctls->current_handle=handle; if (ctls->current_handle->the_ctl==NULL) return FALSE; for (key=ctls->current_handle->the_ctl->keys;key!=NULL;key=key->next) if (key->keycode==e->data.key.chcode) { ctls->return_code=e->data.key.chcode; if (!key->disabled) ctl__run(key->action); return TRUE; } else if (key->keycode==-1) { ctls->return_code=e->data.key.chcode; if (!key->disabled) ctl__run(key->action); return TRUE; } return FALSE; } static BOOL ctl__process_mouse_event(wimp_eventstr *e) { ctl__handlestr *handle; if (e->data.but.m.bbits & 2) return FALSE; handle=ctl__find_handle((e->data.but.m.w<0)?win_ICONBAR:e->data.but.m.w); if (handle==NULL) return FALSE; ctls->current_handle=handle; if (ctls->current_handle->the_ctl==NULL) return FALSE; if (ctls->current_handle->the_ctl->onclick==NULL) return FALSE; if (!ctl__chk_disabled(ctls->current_handle->the_ctl->onclick)) { ctls->return_code=e->data.but.m.bbits; ctl__run(ctls->current_handle->the_ctl->onclick); return TRUE; } return FALSE; } static BOOL ctl__process_event(wimp_eventstr *e) { switch (e->e) { default: return FALSE; case wimp_EKEY: return ctl__process_key_event(e); case wimp_EBUT: return ctl__process_mouse_event(e); case wimp_ESEND: case wimp_ESENDWANTACK: if (e->data.msg.hdr.action==wimp_MHELPREQUEST) return ctl__process_help_event(e); else return FALSE; } } /************************* External functions ****************************/ /* ctl_init(): * BOOL load - if true load control file and ignore any * undefined actions. * */ void ctl_init(BOOL load) { ctl__init(); if (load) ctl__load(FALSE); } /* ctl_load() * Load control file (Can only be called if ctl_init was * called with FALSE. Generate FATAL error if undefined action * in control file. */ void ctl_load() { if (ctls->state!=ctl_ST_PRELOAD) ctl__error(4,NULL,TRUE); ctl__load(TRUE); } /* * BOOL ctl_attach_menu(event_w,char ctlname,char menuname); * * * */ BOOL ctl_attach_menu(event_w w,char *ctlname,char *menuname,void *userhandle) { ctl *the_ctl; ctl__menu *the_menu; ctl__handlestr *handle; the_ctl=ctl__find_ctl(ctlname); the_menu=ctl__find_menu(menuname,the_ctl); if (the_menu->external) ctl__error(66,menuname,TRUE); handle=ctl__add_handle(w,userhandle,the_ctl,the_menu); return event_attachmenumaker(w, (event_menu_maker) ctl__menu_maker, (event_menu_proc) ctl__menu_select, handle); } void ctl_add_action(char *name,char *syntax,ctl_action_proc func,void *arg) { ctl__add_action(name,syntax,func,arg,FALSE); } void ctl_tick_action(char *ctlname,char *actname) { ctl *a_ctl; a_ctl=ctl__find_ctl(ctlname); ctl__find_action_in_ctl(a_ctl,actname,ctl__tick_entry,(void *)TRUE); } void ctl_untick_action(char *ctlname,char *actname) { ctl *a_ctl; a_ctl=ctl__find_ctl(ctlname); ctl__find_action_in_ctl(a_ctl,actname,ctl__tick_entry,(void *)FALSE); } void ctl_set_action_text(char *ctlname,char *actname,char *text) { ctl *a_ctl; a_ctl=ctl__find_ctl(ctlname); ctl__find_action_in_ctl(a_ctl,actname,ctl__set_entry_text,(void *)text); } void ctl_set_caret_in_action(char *ctlname,char *actname) { int f=0; ctl *a_ctl; a_ctl=ctl__find_ctl(ctlname); ctl__find_action_in_ctl(a_ctl,actname,ctl__set_caret_in_entry,(void *)&f); if (f>1) ctl__error(63,actname,TRUE); } void ctl_enable_action(char *ctlname,char *actname) { ctl *a_ctl; ctl__key *key; ctl__actionstr the_action,*the_address; a_ctl=ctl__find_ctl(ctlname); the_action.name=actname; the_address=ctl__find_action(&the_action,ctls->actions,FALSE,FALSE); if (the_address==NULL) ctl__error(50,actname,TRUE); the_address->disabled=FALSE; ctl__find_action_in_ctl(a_ctl,actname,ctl__enable_entry,(void *)TRUE); for (key=a_ctl->keys;key!=NULL;key=key->next) key->disabled=ctl__chk_disabled(key->action); } void ctl_disable_action(char *ctlname,char *actname) { ctl *a_ctl; ctl__actionstr the_action,*the_address; ctl__key *key; a_ctl=ctl__find_ctl(ctlname); the_action.name=actname; the_address=ctl__find_action(&the_action,ctls->actions,FALSE,FALSE); if (the_address==NULL) ctl__error(50,actname,TRUE); the_address->disabled=TRUE; ctl__find_action_in_ctl(a_ctl,actname,ctl__enable_entry,(void *)FALSE); for (key=a_ctl->keys;key!=NULL;key=key->next) if (ctl__find_action_in_list(actname,key->action)) key->disabled=TRUE; } char *ctl_make_action_writeable( char *ctlname, char *actname, int len, char *valid) { ctl *a_ctl; ctl__actionstr the_action /*,*the_address*/; ctl__indirectstr data; data.len=len; data.valid=valid; data.buffer=NULL; data.flag=FALSE; a_ctl=ctl__find_ctl(ctlname); the_action.name=actname; /* the_address=ctl__find_action(&the_action,ctls->actions,FALSE,FALSE); if (the_address==NULL) ctl__error(51,actname,TRUE); */ ctl__find_action_in_ctl(a_ctl,actname,ctl__make_entry_writeable, (void *)&data); return data.buffer; } void ctl_find_entries(char *ctlname,char *actname,void ((*func)())) { ctl *a_ctl; a_ctl=ctl__find_ctl(ctlname); ctl__find_action_in_ctl(a_ctl,actname,ctl__apply_function,(void *)func); } void ctl_process(void) { wimp_eventstr e; wimpt_poll(event_getmask(),&e); if (!ctl__process_event(&e)) { wimpt_fake_event(&e); event_process(); } } void ctl_attach_external_menu(char *ctlname,char *menuname,wimp_menustr *m) { ctl *a_ctl; ctl__menu *a_menu; ctl__menu_entry *an_entry; wimp_menuitem *item; a_ctl=ctl__find_ctl(ctlname); a_menu=ctl__find_menu(menuname,a_ctl); if (!a_menu->external) ctl__error(65,menuname,TRUE); a_menu->menu_body=(menu)m; a_menu->entrycount=ctl__count_menu_entries(m); an_entry=ctl__find_entry(-1,a_menu); item=(wimp_menuitem *)(m+1); do { if (an_entry==NULL) item->iconflags|=wimp_INOSELECT; else { /* item->iconflags&=~wimp_INOSELECT; */ if ((an_entry->action != NULL) && (an_entry->action->type==ctl_ACT_FUNCTION) && (an_entry->action->action.address->function.function== ctl__submenu_request) ) { item->flags|=wimp_MSUBLINKMSG; if ((an_entry->action->action.address->function.handle==(void *)1) || (an_entry->action->action.address->function.handle==(void *)3) ) item->submenu= menu_syshandle(((ctl__menu *)an_entry->action->args)->menu_body); else item->submenu=(wimp_menustr *)1; } } if ((item->flags & wimp_MLAST)!=0) break; item++; } while (TRUE); item=(wimp_menuitem *)(m+1); for (an_entry=a_menu->entries;an_entry!=NULL;an_entry=an_entry->next) { if ((an_entry->num!=-1) && ((an_entry->num<0) || (an_entry->num>a_menu->entrycount))) werr(TRUE, msgs_lookup("inveent:Invalid entry number (%i) in external menu %s.") ,an_entry->num,menuname); if (an_entry->num>0) { (item+an_entry->num-1)->iconflags&=~wimp_INOSELECT; if ((an_entry->action != NULL) && (an_entry->action->action.name!=NULL) && (an_entry->action->type==ctl_ACT_FUNCTION) && (an_entry->action->action.address->function.function== ctl__submenu_request) && ((an_entry->action->action.address->function.handle==(void *)1) || (an_entry->action->action.address->function.handle==(void *)3) ) ) { ctl__menu *submenu=(ctl__menu *) an_entry->action->args; if ((submenu->external) && (submenu->menu_body==NULL)) { submenu->parent=(item+an_entry->num-1); } else { (item+an_entry->num-1)->submenu=menu_syshandle(submenu->menu_body); } } } } } char * ctl_return_external_hit(void) { return ctls->external_hit; } void ctl_help_reply(char *text) { wimp_msgstr m; strcpy(m.data.helpreply.text,text); m.hdr.action=wimp_MHELPREPLY; m.hdr.your_ref=wimpt_last_event()->data.msg.hdr.my_ref; m.hdr.my_ref=0; m.hdr.size=220; wimp_sendmessage(wimp_ESEND,&m,wimpt_last_event()->data.msg.hdr.task); }