/* This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* Copyright (c) 2006 Clive Nicolson clive@bedroom.gen.nz */ /* See: http://ou800doc.caldera.com/en/SDK_charm/CONTENTS.html */ /* Need to FIX: *"RET" *Inline the Object stuff. *Casts. eg const, vary *All the interrupt stuff. *Make sure TMP_FMLI_PIPE is deleted on crash etc. *Test vsig and co* routines. *More of the blt*_* functions. ie blt2_pathconv blt_fmlcut blt_fmlexpr blt_fmlgrep blt2_set blt2_unset *Many other problems! */ #define TEST 1 #define DEBUGSTDDBG 1 #define DEBUG_MOUSE 0 #define HACK_Form_Choice #define FIX_SUB_MOVE /*#define MY_MOUSE*/ #define MY_POPEN 0 /* 0,1 1 does not work correctly yet! */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fmli.h" #define SLK_MAX 16 #define TMP_FMLI_PIPE "/tmp/FMLIpipe." #define TMP_FMLI_SEMI "/tmp/FMLIsem." #if MY_POPEN >= 1 #define TMP_FMLI_STDEVAL "/tmp/FMLIstdeval." #endif #ifdef __linux__ #include #include #include static char * getexename(const char *argv0) { char *buf; size_t size; for (size = 32; ; size *= 2) { int ret; buf = malloc(size); ret = readlink("/proc/self/exe", buf, size); if (ret == -1) { free(buf); buf = !argv0 ? NULL : strdup(argv0); /* This s/b ok */ break; } else if (ret >= size) free(buf); else { buf[ret] = 0; break; } } return buf; } #else static char * getexename(const char *argv0) { return !argv0 ? NULL : strdup(argv0); /* This s/b ok */ } #endif FILE *stddbg; /* Object stuff begin */ struct Class; typedef struct Class *Class; struct id { Class isa; }; typedef struct id *id; struct Class { Class isa; /**/ long instance_size; /**/ void *(* init)(id); void (* free)(id); }; struct Vary; typedef struct Vary *Vary; struct vary { Vary isa; /**/ void *vary_data; size_t count; size_t allocated; }; typedef struct vary *vary; typedef const struct vary *const_vary; static void * VD_REALLOC(void *ptr, size_t size) { ptr = realloc(ptr, size); return ptr; } static void VD_FREE(void *ptr) { free(ptr); } struct Vary { Class isa; /**/ long instance_size; /**/ vary (* init)(vary); void (* free)(vary); /**/ size_t (* count)(const_vary); void *(* at)(const_vary, size_t); }; static vary init_vary(vary self); static void free_vary_char(vary self); static void free_vary_id(vary self); static size_t count_vary(const_vary self); static void *at_vary(const_vary self, size_t i); static vary init_vary(vary self) { self->vary_data = NULL; self->count = 0; self->allocated = 0; return self; } static void * NNEW(Class klass) { id self; self = malloc(klass->instance_size); self->isa = klass; if (self) klass->init(self); return self; } static void free_vary_char(vary self) { if (self) { if (self->vary_data) VD_FREE(self->vary_data); free(self); } } static void FFREE(id self) { if (self) self->isa->free(self); } static size_t count_vary(const_vary self) { return !self ? 0 : self->count; } static size_t CCOUNT(const_vary self) { return !self ? 0 : self->isa->count(self); } static void * at_vary(const_vary self, size_t i) { return (!self || !self->vary_data) ? NULL : ((void **)self->vary_data)[i]; } static void * AAT(const_vary self, size_t i) { return !self ? NULL : self->isa->at(self, i); } static void free_vary_id(vary self) { if (self) { if (self->vary_data) { size_t j; size_t k; k = CCOUNT((const_vary)self); for (j = 0; j < k; j++) FFREE(AAT(self, j)); VD_FREE(self->vary_data); } free(self); } } static vary add_vary(vary self, id p1) { if (!self->vary_data || (self->allocated < (self->count+1))) { self->allocated = self->count+1; self->vary_data = VD_REALLOC(self->vary_data, sizeof(p1)*self->allocated); } ((id *)self->vary_data)[self->count++] = p1; return self; } /* vary_char */ #define vary_char vary static struct Vary Vary_char = { .isa = NULL, /**/ .instance_size = sizeof(struct vary_char), /**/ .init = init_vary, .free = free_vary_char, .count = count_vary, .at = at_vary, }; static Vary Class_vary_char = &Vary_char; static char * str_vary_char(const vary_char self) { return !self ? NULL : self->vary_data; } /* Caller must: if (result) free(result); */ static char * str_vary_char_dup(const vary_char self) { char *s; s = str_vary_char(self); s = !s ? NULL : strdup(s); FFREE((id)self); return s; } static vary_char add_vary_char_n(vary_char self, const char *s, size_t l) { if (!self) self = NNEW((Class)Class_vary_char); if (s) { if (!self->vary_data || (self->allocated < (self->count+(l+1)))) { self->allocated = self->count+(l+1); self->vary_data = VD_REALLOC(self->vary_data, sizeof(char)*self->allocated); ((char *)self->vary_data)[self->count] = '\0'; } if (l) { strncat(self->vary_data, s, l); self->count += l; ((char *)self->vary_data)[self->count] = '\0'; } } return self; } static vary_char add_vary_char(vary_char self, const char *s) { return add_vary_char_n(self, s, !s ? 0 : strlen(s)); } /* vary_dict */ struct dict { Class isa; /**/ char *key; char *value; }; typedef struct dict *dict; static dict init_dict(dict self); static void free_dict(dict self); static struct Class _Class_dict = { .isa = NULL, /**/ .instance_size = sizeof(struct dict), /**/ .init = (void *(*)(id))init_dict, .free = (void (*)(id))free_dict, }; static Class Class_dict = &_Class_dict; static dict init_dict(dict self) { self->key = NULL; self->value = NULL; return self; } static void free_dict(dict self) { if (self) { free(self->key); free(self->value); free(self); } } /**/ #define vary_dict vary static struct Vary Vary_dict = { .isa = NULL, /**/ .instance_size = sizeof(struct vary_dict), /**/ .init = init_vary, .free = free_vary_id, /*was char*/ .count = count_vary, .at = at_vary, }; static Vary Class_vary_dict = &Vary_dict; static const char * value_vary_dict(const vary_dict self, const char *key) { if (self) { if (self->vary_data) { int (*strxcmp)(const char *s1, const char *s2); int caseinsensitive = 1; size_t i; size_t k; strxcmp = caseinsensitive ? &strcasecmp : &strcmp; k = CCOUNT((const_vary)self); for (i = 0; i < self->count; i++) { dict dict; dict = AAT(self, i); if (!(*strxcmp)(dict->key, key)) return (const char *)dict->value; } } } return NULL; } static vary_dict add_vary_dict(vary_dict self, dict d) { int found = 0; size_t i; if (self->vary_data) { for (i = 0; i < self->count; i++) if (!strcmp(((dict *)self->vary_data)[i]->key, d->key)) { FFREE((id)((dict *)self->vary_data)[i]); ((dict *)self->vary_data)[i] = NULL; found = 1; break; } } else i = 0; if (!found) { if (!self->vary_data || (self->allocated < (self->count+1))) { self->allocated = self->count+1; self->vary_data = VD_REALLOC(self->vary_data, sizeof(d)*self->allocated); } i = self->count; self->count += 1; } ((dict *)self->vary_data)[i] = d; return self; } /* vary_dicts */ typedef vary_dict *dicts; #define vary_dicts vary static struct Vary Vary_dicts = { .isa = NULL, /**/ .instance_size = sizeof(struct vary_dicts), /**/ .init = init_vary, .free = free_vary_char, .count = count_vary, .at = at_vary, }; static Vary Class_vary_dicts = &Vary_dicts; static vary_dicts add_vary_dicts(vary_dicts self, vary_dict dict) { return add_vary(self, (id)dict); } /* Object stuff end */ #define SIZEOF(p) (sizeof(p)/sizeof(p[0])) /***********************************************************************/ struct KV { char *key; char *value; }; typedef struct KV KV; /* Defaults and globals */ #define xxstr(s) xstr(s) #define xstr(s) #s static const KV defs_color[COLOR_WHITE+1] = { {"black",xxstr(COLOR_BLACK)}, {"red",xxstr(COLOR_RED)}, {"green",xxstr(COLOR_GREEN)}, {"yellow",xxstr(COLOR_YELLOW)}, {"blue",xxstr(COLOR_BLUE)}, {"magenta",xxstr(COLOR_MAGENTA)}, {"cyan",xxstr(COLOR_CYAN)}, {"white",xxstr(COLOR_WHITE)}, }; #undef xxstr #undef xstr static const KV defs_form_slk[] = { {"name","HELP"}, {"button","1"}, {"action","help"}, {"name","CHOICES"}, {"button","2"}, {"action","choices"}, {"name","SAVE"}, {"button","3"}, {"action","done"}, {"name","PREV-FRM"}, {"button","4"}, {"action","prev-frm"}, {"name","NEXT-FRM"}, {"button","5"}, {"action","next-frm"}, {"name","CANCEL"}, {"button","6"}, {"action","cancel"}, {"name","CMD-MENU"}, {"button","7"}, {"action","cmd-menu"}, }; static const KV defs_menu_user_slk[] = { {"name","HELP"}, {"button","1"}, {"action","help"}, {"name","MARK"}, {"button","2"}, {"action","mark"}, {"name","ENTER"}, {"button","3"}, {"action","enter"}, {"name","PREV-FRM"}, {"button","4"}, {"action","prev-frm"}, {"name","NEXT-FRM"}, {"button","5"}, {"action","next-frm"}, {"name","CANCEL"}, {"button","6"}, {"action","cancel"}, {"name","CMD-MENU"}, {"button","7"}, {"action","cmd-menu"}, }; static const KV defs_menu_choices_slk[] = { {"name","ENTER"}, {"button","3"}, {"action","enter"}, {"name","CANCEL"}, {"button","6"}, {"action","cancel"}, }; static const KV defs_menu_cmd_slk[] = { {"name","HELP"}, {"button","1"}, {"action","help"}, {"name","ENTER"}, {"button","3"}, {"action","enter"}, {"name","CANCEL"}, {"button","6"}, {"action","cancel"}, }; static const KV defs_text_slk[] = { {"name","HELP"}, {"button","1"}, {"action","help"}, {"name","PREVPAGE"}, {"button","2"}, {"action","prevpage"}, {"name","NEXTPAGE"}, {"button","3"}, {"action","nextpage"}, {"name","PREV-FRM"}, {"button","4"}, {"action","prev-frm"}, {"name","NEXT-FRM"}, {"button","5"}, {"action","next-frm"}, {"name","CANCEL"}, {"button","6"}, {"action","cancel"}, {"name","CMD-MENU"}, {"button","7"}, {"action","cmd-menu"}, }; static const KV defs_chg_keys_slk[] = { {"name","CHG-KEYS"}, {"button","8"}, {"action","togslk"}, {"name","CHG-KEYS"}, {"button","16"}, {"action","togslk"}, }; static const KV defs_alias[] = { {"??????",""}, }; static const KV defs_init[] = { {"active_border","white"}, {"active_title_bar","black"}, {"active_title_text","white"}, {"autolayout","false"}, {"bancol","center"}, {"banner_text","white"}, {"columns","50"}, {"highlight_bar","black"}, {"highlight_bar_text","white"}, {"inactive_border","white"}, {"inactive_title_bar","black"}, {"inactive_title_text","white"}, {"interrupt","false"}, {"nobang","false"}, {"oninterrupt","\"`message Operation Interrupted!`\"nop"}, {"rows","10"}, {"screen","black"}, {"slk_bar","black"}, {"slk_text","white"}, {"slk_layout","3-2-3"}, {"toggle","3"}, {"use_incorrect_pre4.0_behavior","false"}, {"window_text","white"}, {"working","Working"}, #if 0 {"permanentmsg",""}, #endif }; static const KV defs_cmd[] = { {"menu","Command Menu"}, {"autosort","true"}, {"lifetime","shortterm"}, {"help","help $NAME"}, {"name","cancel"}, {"name","checkworld"}, {"show","false"}, {"name","choices"}, {"show","false"}, {"name","cleanup"}, {"name","close"}, {"show","false"}, {"name","cmd-menu"}, {"show","false"}, {"name","done"}, {"show","false"}, {"name","enter"}, {"show","false"}, {"name","exit"}, {"name","frm-mgmt"}, {"name","goto"}, {"name","help"}, {"name","mark"}, {"show","false"}, {"name","next-frm"}, {"name","nextpage"}, {"show","false"}, {"name","nop"}, {"show","false"}, {"name","open"}, {"show","false"}, {"name","prev-frm"}, {"name","prevpage"}, {"show","false"}, {"name","refresh"}, {"name","release"}, {"show","false"}, {"name","reset"}, {"show","false"}, {"name","textframe"}, /* A sco addition */ {"show","false"}, {"name","togslk"}, {"show","false"}, {"name","unix-system"}, {"name","update"}, }; enum c_pairs { c_0, c_slk, c_active_title, c_inactive_title, c_highlight_bar, c_banner, c_window, c_active_border, c_inactive_border /**/ #define c_MAX (c_inactive_border+1) }; static struct color_pairs { const char *f; const char *b; } color_pairs[c_MAX] = { /*c_0*/ {NULL, NULL}, /*c_slk*/ {"slk_text", "slk_bar"}, /*c_active_title*/ {"active_title_text", "active_title_bar"}, /*c_inactive_title*/ {"inactive_title_text", "inactive_title_bar"}, /*c_highlight_bar*/ {"highlight_bar_text", "highlight_bar"}, /*c_banner*/ {"banner_text", "screen"}, /*c_window*/ {"window_text", "screen"}, /*c_active_border*/ {"active_border", "screen"}, /*c_inactive_border*/ {"inactive_border", "screen"}, }; enum frm_type { FRMt_form, FRMt_text, FRMt_menu, /**/ #define FRMt_MAX (FRMt_menu+1) }; static const char *fmt_spelling[FRMt_MAX] = { "Form", "Text", "Menu", }; static const char *fmt_title[FRMt_MAX] = { "form", "title", "menu", }; enum frm_type_sub_menu { FRMts_menu_user, FRMts_menu_choices, FRMts_menu_cmd, /**/ #define FRMt_MENU_MAX (FRMts_menu_cmd+1) }; enum def_type { DEF_alias, DEF_init, DEF_cmd, /**/ #define DEF_MAX (DEF_cmd+1) WWW_color, WWW_chg_keys_slk, /**/ #define WWW_MAX (WWW_chg_keys_slk+1) UUU_form_slk, /* FRMt_form */ UUU_text_slk = (UUU_form_slk+FRMt_text), UUU_menu_user_slk = (UUU_form_slk+FRMt_menu+FRMts_menu_user), UUU_menu_choices_slk = (UUU_menu_user_slk+FRMts_menu_choices), UUU_menu_cmd_slk = (UUU_menu_user_slk+FRMts_menu_cmd), /**/ #define UUU_MAX (UUU_menu_cmd_slk+1) }; struct zzzz { const char *name; const KV *kv; const size_t kv_cnt; }; #define ZZZZ(n) {# n, n, SIZEOF(n)} static const struct zzzz defs[UUU_MAX] = { /*DEF_*/ ZZZZ(defs_alias), ZZZZ(defs_init), ZZZZ(defs_cmd), /*WWW_*/ ZZZZ(defs_color), ZZZZ(defs_chg_keys_slk), /*UUU_*/ ZZZZ(defs_form_slk), ZZZZ(defs_text_slk), ZZZZ(defs_menu_user_slk), ZZZZ(defs_menu_choices_slk), ZZZZ(defs_menu_cmd_slk), }; static const KV frm_mgmt_OpenFrames[] = { {"menu","Open Frames"}, {"lifetime","shortterm"}, {"action","`set -l Form_Choice=\"goto $LININFO\"`close"}, }; static const struct zzzz frm_mgmt_OpenFrames_defs = ZZZZ(frm_mgmt_OpenFrames); static const KV frm_mgmt_FrameManagement[] = { {"menu","Frame Management"}, {"lifetime","shortterm"}, {"action","`set -l Form_Choice=\"frm-mgmt $NAME\"`close"}, {"name","list"}, {"description","list all frames"}, {"name","move"}, {"description","move a frame"}, {"name","reshape"}, {"description","reshape a frame"}, }; static const struct zzzz frm_mgmt_FrameManagement_defs = ZZZZ(frm_mgmt_FrameManagement); static const KV choices_list[] = { {"menu","Choices"}, {"lifetime","shortterm"}, {"action","`set -l Form_Choice=\"$NAME\"`close"}, }; static const struct zzzz choices_list_defs = ZZZZ(choices_list); static const KV help_list[] = { {"title","Help Facility: $ARG1"}, {"lifetime","shortterm"}, {"rows","12"}, {"columns","72"}, {"begrow","distinct"}, {"begcol","distinct"}, }; static const struct zzzz help_list_defs = ZZZZ(help_list); static const KV defs_cmd_help[] = { {"cancel","The cancel command\n"}, {"checkworld","The checkworld command\n"}, {"choices","The choices command\n"}, {"cleanup","The cleanup command\n"}, {"close","The close command\n"}, {"cmd-menu","The cmd-menu command\n"}, {"done","The done command\n"}, {"enter","The enter command\n"}, {"exit","The exit command\n"}, {"frm-mgmt","The frm-mgmt command\n"}, {"goto","The goto command\n"}, {"help","The help command\n"}, {"mark","The mark command\n"}, {"next-frm","The next-frm command\n"}, {"nextpage","The nextpage command\n"}, {"nop","The nop command\n"}, {"open","The open command\n"}, {"prev-frm","The prev-frm command\n"}, {"prevpage","The prevpage command\n"}, {"refresh","The refresh command\n"}, {"release","The release command\n"}, {"reset","The reset command\n"}, {"textframe","The textframe command\n"}, {"togslk","The togslk command\n"}, {"unix-system","The unix-system command\n"}, {"update","The update command\n"}, }; static const struct zzzz cmd_help_defs = ZZZZ(defs_cmd_help); #define DEF2FILE(DEF_n) (FRMt_MAX+DEF_n) #define FRM2FILE(FRMt_n) (FRMt_n) enum file_type { FILE_form = FRM2FILE(FRMt_form), FILE_text = FRM2FILE(FRMt_text), FILE_menu = FRM2FILE(FRMt_menu), FILE_alias = DEF2FILE(DEF_alias), FILE_init = DEF2FILE(DEF_init), FILE_cmd = DEF2FILE(DEF_cmd), /**/ #define FILE_MAX (FILE_cmd+1) }; static const char *file_type_spelling[FILE_MAX] = { "form", "text", "menu", "alias", "initialization", "command", }; enum toggle { tg_unknown=-3, /**/ tg_always=-2, tg_never=-1, /**/ #define tg_MAX (tg_never+1) }; static const char *gyh_toggle[] = { /*tg_unknown*/ "", /*tg_always*/ "always", /*tg_never*/ "never", }; enum position { p_unknown=-7, /* Neither known keyword nor integer */ p_right=-6, /**/ p_any=-5, p_center=-4, p_current=-3, p_distinct=-2, /**/ #define p_MAX (p_distinct+1) }; static const char *gyh_position[] = { /*p_noninteger*/ "", /*p_right*/ "right", /**/ /*p_any*/ "any", /*p_center*/ "center", /*p_current*/ "current", /*p_distinct*/ "distinct", }; enum a_lifetime{ l_shortterm, l_longterm, l_permanent, l_immortal, #define l_MAX (l_immortal+1) }; typedef enum a_lifetime fmli_lifetime; static const char *gyx[] = { /*l_shortterm*/ "shortterm", /*l_longterm*/ "longterm", /*l_permanent*/ "permanent", /*l_immortal*/ "immortal", }; enum slk_layout_type { lo_323, lo_44, lo_444, lo_444p, /**/ #define lo_MAX (lo_444p+1) }; typedef enum slk_layout_type fmli_layout; static const char *vbvb[lo_MAX] = { /*lo_323*/ "3-2-3", /*lo_44*/ "4-4", /*lo_444*/ "4-4-4", /*lo_444p*/ "4-4-4+", }; typedef int fmli_boolean; typedef char *fmli_color; typedef char *fmli_command; typedef int fmli_integer; typedef int fmli_position; typedef char *fmli_string; #define fmli_string_acs fmli_string typedef int fmli_toggle; enum fmli_types { t_fmli_null, t_fmli_boolean, t_fmli_color, t_fmli_command, t_fmli_integer, t_fmli_layout, t_fmli_position, t_fmli_string, t_fmli_toggle, /**/ #define t_MAX (t_fmli_toggle+1) }; static const char *fmli_types_names[t_MAX] = { /*t_fmli_null*/ "null", /*t_fmli_boolean*/ "boolean", /*t_fmli_color*/ "color", /*t_fmli_command*/ "command", /*t_fmli_integer*/ "integer", /*t_fmli_layout*/ "layout", /*t_fmli_position*/ "position", /*t_fmli_string*/ "string", /*t_fmli_toggle*/ "toggle", }; static const char *null_s[] = { "close", NULL }; static const char *boolean_s[] = { "altslks", "autoadvance", "autolayout", "autosort", "edit", "inactive", "init", "interrupt", "menuonly", "multiselect", "nobang", "noecho", "reread", "selected", "scroll", "show", "use_incorrect_pre4.0_behavior", "valid", "validOnDone", "wrap", NULL }; static const char *color_s[] = { "active_border", "active_title_bar", "active_title_text", "banner_text", "highlight_bar", "highlight_bar_text", "inactive_border", "inactive_title_bar", "inactive_title_text", "screen", "slk_bar", "slk_text", "window_text", NULL }; static const char *command_s[] = { "action", "done", "help", "oninterrupt", "rmenu", NULL }; static const char *integer_s[] = { "button", "columns", "fcol", "frow", "ncol", "nrow", "page", "rows", "toggle", NULL }; static const char *layout_s[] = { "slk_layout", NULL }; static const char *position_s[] = { "columns", "rows", "bancol", "begcol", "begrow", NULL }; static const char *string_s[] = { "banner", "choicemsg", "description", "fieldmsg", "form", "framemsg", "header", "invalidmsg", "invalidOnDoneMsg", "itemmsg", "lifetime", "lineinfo", "lininfo", "menu", "name", "permanentmsg", "text", "title", "value", "working", NULL }; static const char *toggle_s[] = { "toggle", NULL }; static const char **all_s[t_MAX] = { null_s, boolean_s, color_s, command_s, integer_s, layout_s, position_s, string_s, toggle_s, }; /*****************************/ enum cs_type { cs_desc, cs_cmd_line, cs_cmd_menu, /**/ #define cs_MAX (cs_cmd_menu+1) }; #define SRC(the_frm) ((the_frm)->flags & MASK(fm_cmd_menu) ? cs_cmd_menu : cs_desc) struct descs { vary_dict globals; vary_dicts locals; #if 0 vary_dicts slks; #else #define slks locals #define SLKS_LOCALS #endif }; typedef struct descs *descs; /*****************************/ typedef struct node NODE; struct node { NODE *prev; NODE *next; }; typedef NODE *LIST; #define THELIST(s) (s)->frm_list #define FRM_FIRST(s) (FRM *)THELIST(s) #define FRM_PAST(f,s) ((f) == FRM_FIRST(s)) #define LNK(f) (f)->links #define PREV_FRM(f) (FRM *)(LNK(f).prev) #define NEXT_FRM(f) (FRM *)(LNK(f).next) static void insertafternode(LIST *lst, NODE *newnode, NODE *priornode) { if (priornode == NULL) { newnode->prev = newnode; newnode->next = newnode; *lst = newnode; } else { newnode->prev = priornode; newnode->next = priornode->next; priornode->next->prev = newnode; priornode->next = newnode; } } static void removenode(LIST *lst, NODE *currentnode) { if (currentnode->next == currentnode) *lst = NULL; else { NODE *priornode; priornode = currentnode->prev; priornode->next = currentnode->next; currentnode->next->prev = priornode; if (currentnode == *lst) *lst = priornode; } } /*****************************/ typedef struct frm FRM; enum co_str { co_action, /* -z */ co_proc_id, /* -i Defaults to command */ co_refname, /* -R */ co_rpath, /* -r Default: /var/tmp/ */ co_wpath, /* -w Default: /var/tmp/ */ co_send_string, /* -s Defaults to "\n" */ co_expect_string /* -e Defaults to "\n" */ /**/ #define co_MAX (co_expect_string+1) }; static const char *co_letters[co_MAX] = { "-z", "-i", "-r", "-w", "-s", "-e", "-R" }; struct co_struct { struct co_struct *next; /**/ char *strs[co_MAX]; #define action strs[co_action] #define proc_id strs[co_proc_id] #define rpath strs[co_rpath] #define wpath strs[co_wpath] #define send_string strs[co_send_string] #define expect_string strs[co_expect_string] #define refname strs[co_refname] /**/ int refnames_cnt; char **refnames; /**/ FILE *fp_write; }; typedef struct co_struct CO; #define PIPE_FDC (STDERR_FILENO+1) struct msgs_fds { int fdc; int fdv[PIPE_FDC]; }; enum cvbu { CN_LOWER, CN_RIGHT }; enum corners { CNR_UL = 0, CNR_LL = (1 << CN_LOWER), CNR_UR = (1 << CN_RIGHT), CNR_LR = (1 << CN_LOWER) | (1 << CN_RIGHT), /**/ #define corners_MAX (CNR_LR+1) }; enum msg_type { b_permanent, b_frame, b_transient, /**/ #define b_MAX (b_transient+1) }; #define MASK(b) (1 << (b)) struct pt { int y; int x; }; struct msg { fmli_string_acs msg; int acs; }; struct all { SCREEN *screen; #if defined(HACK_Form_Choice) char *local_Form_Choice; #else char **local_environ; #endif struct descs def[UUU_MAX]; int num_colors; int num_slks; /**/ struct pt displayhw; int has_colors; WINDOW *ban; WINDOW *msg; WINDOW *cmd; fmli_toggle toggle; const char *msg_msg; struct msg msg_permanent; /*struct msg msg_frame;*//* Lives in frame! */ struct msg msg_transient; unsigned int frm_num; /* Last num used */ unsigned int frm_cnt; LIST frm_list; FRM *current_frm; /**/ enum cs_type src; int argc; char **argv; /**/ struct shell_co { #if DEBUGSTDDBG int popen_cnt; #endif int shell_open; #if MY_POPEN >= 1 int eval_out_fd; char *tmp_fmli_stdevalPath; int eval_in_fd; #endif } shell_co; /**/ struct inter { fmli_boolean able; fmli_string on; int ed; } interrupt; struct msgs_fds fds; pid_t pid; int vsig_interrupted; char *appSocketPath; int listen_fd; FRM *arg_owner_frm; int arg_lininfo_set; int arg_name_set; int arg_text_set; CO *co_list; int readfile_val; }; typedef struct all *all; static all g_my_all; enum fm_type { fm_static_descs, fm_extended, fm_cmd_menu, fm_immortal, fm_closing, fm_choices, fm_choices_action, /* action rather than value */ /**/ #define fm_MAX (fm_choices_action+1) }; struct scroller { int len; /* 3 is min height of a frame */ int plusy; /* 0 or 1 */ struct pt top; }; enum scr_type { scr_page, scr_field, /**/ #define scr_MAX (scr_field+1) }; struct frm { NODE links; all my_all; /* Below here from open or updated from file */ unsigned int frm_num; char *name; /**/ int title_x; char num[12+1]; fmli_string title; /**/ int argc; char **argv; enum frm_type frm_type; union frmtype { int f; int t; enum frm_type_sub_menu m; } frm_type_sub; int flags; /*MASK(fm_ | )*/ descs descs; /* Below here from file or descs */ struct timespec mtime; PANEL *panel; int posted; struct scroller scroll[scr_MAX]; vary_dict slk_dict[SLK_MAX]; /*Just a copy*/ fmli_boolean altslks; unsigned int slkEnabled; struct msg msg_frame; union frmtyp { struct f { /* Form/Text vars */ FORM *form; FIELD **fields; int fmode; } f; struct t { /* Text vars (currently not used, text uses a form! */ int junk; } t; struct m { /* Menu vars */ MENU *menu; ITEM **items; } m; } u; }; static descs init_desc(descs descs) { descs->globals = NNEW((Class)Class_vary_dict); descs->locals = NNEW((Class)Class_vary_dicts); #ifdef SLKS_LOCALS if (&descs->locals != &descs->slks) #endif descs->slks = NNEW((Class)Class_vary_dicts); return descs; } static descs new_desc(void) { return init_desc(malloc(sizeof(struct descs))); } static void dump_desc(const vary_dict self) { size_t j; size_t k; k = CCOUNT((const_vary)self); for (j = 0; j < k; j++) { dict dict; dict = AAT(self, j); fprintf(stddbg, "%s=", dict->key); if (dict->value) fprintf(stddbg, "%s", dict->value); fprintf(stddbg, "\n"); fflush(stddbg); } } static void dump_descriptors(descs descs, const char *name) { fprintf(stddbg, "#$%p:%s\n", (void *)descs, name); dump_desc(descs->globals); { size_t l; size_t i; l = CCOUNT(descs->locals); for (i = 0; i < l; i++) { fprintf(stddbg, "#[%d]\n", i); dump_desc(AAT(descs->locals, i)); } } fprintf(stddbg, "\n"); } /* Caller must not: free(key) or free(value); */ static void add_descriptor(descs descs, char *key, char *value, int lower, vary_dict *desc_c) { const char *prim_key = "name"; vary_dict desc = *desc_c; if (!strcmp(key, prim_key)) { desc = NNEW((Class)Class_vary_dict); add_vary_dicts(descs->locals, desc); } else if (!desc) desc = descs->globals; if (lower) { size_t l; size_t i; l = strlen(key); for (i = 0; i < l; i++) key[i] = tolower(key[i]); } { dict dict = NNEW((Class)Class_dict); dict->key = key; dict->value = value; if (!add_vary_dict(desc, dict)) fprintf(stderr, "Key %s not added\n", key); } *desc_c = desc; } static void add_descriptor_dup(descs descs, const char *key, const char *value, int lower, vary_dict *desc_c) { add_descriptor(descs, !key ? NULL : strdup(key), !value ? NULL : strdup(value), lower, desc_c); } static void add_descriptors(descs descs, const struct zzzz *kvc, int lower) { size_t i; vary_dict desc; desc = NULL; for (i = 0; i < kvc->kv_cnt; i++) add_descriptor_dup(descs, kvc->kv[i].key, kvc->kv[i].value, lower, &desc); } static void free_descs(descs descs) { FFREE((id)descs->globals); { size_t i; size_t k; k = CCOUNT(descs->locals); for (i = 0; i < k; i++) FFREE(AAT(descs->locals, i)); } FFREE((id)descs->locals); #ifdef SLKS_LOCALS if (&descs->locals != &descs->slks) #endif FFREE((id)descs->slks); } /***********************************************************************/ extern int yyparse(void *p1); extern void yyrestart(FILE *f); #define CTRL(x) ((x) & 0x1f) #define DO_OK (MAX_COMMAND+1) static void setup_keypad(WINDOW *window) { if (window) { notimeout(window, 1); /* no time limit for Fkey sequences */ keypad(window, 1); } } static void init_win(WINDOW *win, chtype ch) { wbkgdset(win, ch); werase(win); wrefresh(win); } static WINDOW * newwin_input(unsigned rows, unsigned cols, unsigned srow, unsigned scol) { WINDOW *window; window = newwin(rows, cols, srow, scol); init_win(window, COLOR_PAIR(c_window)); setup_keypad(window); return window; } /***************************/ static void dump_argv(const char *p, int argc, char **argv) { if (p) { fprintf(stddbg, "%s", p); fflush(stddbg); } if (argc && argv) { int i; for (i = 0; i < argc && argv[i]; i++) fprintf(stddbg, "%d:<%s>\n", i, argv[i]); } else if (p) fprintf(stddbg, "\n"); fflush(stddbg); } static int set_argv(char *p, char ***x_argv, int headroom) { int argc; char **argv; int i; argv = NULL; /* To quieten compiler */ for (i = 0; i < 2; i++) { int inspace; char *s; argc = 0; inspace = 1; for (s = p; *s; s++) if (!inspace != !isspace(*s)) { /* Logical XOR */ inspace = !inspace; if (!inspace) { if (i) argv[argc] = s; argc++; } else if (i) *s = '\0'; } if (i) { argv[argc] = NULL; if (DEBUGSTDDBG && stddbg) dump_argv("set_argv:\n", argc, argv); } else argv = malloc(sizeof(*argv)*(argc+1+headroom)); } *x_argv = argv; return argc; } static int dup_argv(int argc, char **argv, char ***argv_o) { if (argc && argv) { int i; char **x_argv; for (i = 0; i < argc && argv[i]; i++) ; argc = i; x_argv = malloc(sizeof(argv[0])*(argc+1)); for (i = 0; i < argc && argv[i]; i++) x_argv[i] = strdup(argv[i]); x_argv[i] = NULL; argv = x_argv; } *argv_o = argv; return argc; } static void free_argv(int argc, char **argv) { if (argv) { int i; for (i = 0; i < argc && argv[i]; i++) free(argv[i]); free(argv); } } /* Caller must: if (result) free(result); */ static char * argv2char(const char *msg1, int argc, char **argv, const char *msg2) { char *str; char *s; size_t l; int cnt; int c; l = 0; if (msg1) l += strlen(msg1); for (cnt = 0; cnt < argc && argv[cnt]; cnt++) { l += strlen(argv[cnt]); if (cnt) l += 1; } if (msg2) l += strlen(msg2); str = malloc(l+1); s = str; if (msg1) s += sprintf(s, "%s", msg1); for (c = 0; c < argc && argv[c]; c++) { if (c) s += sprintf(s, " "); s += sprintf(s, "%s", argv[c]); } if (msg2) s += sprintf(s, "%s", msg2); return str; } static char * trim(char *buffer) { char *s; size_t l; for (s = buffer; isspace(*s); s++) ; for (l = strlen(s); l && isspace(s[l-1]); l--) ; s[l] = '\0'; return s; } /***************************/ #if 1 static const char map2acs[128] = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" " !\"a$%&`()*n,q./" "0wuvt56789:;,=+?" "@ABCDEFGHiJKLMNO" "PQRSTUVWXYZ[\\]-_" "`kjmlefghijklmno" "pqrstu.wxyz{x}~\x7f"; #define fmli2acs(ch) \ ((((ch) & A_ALTCHARSET) && isprint((ch) & (chtype)A_CHARTEXT)) ? \ (map2acs[(ch) & (chtype)A_CHARTEXT] | ((ch) & (chtype)A_ATTRIBUTES)) : (ch)) #else #define fmli2acs(ch) (ch) #endif static int is_acs(const char *s, int control) { const char *first; const char *second; if (control) { first = "\\\b\n\t\r"; second = "bntr+-"; } else { first = "\\"; second = "+-"; } while ((s = strpbrk(s, first))) { if (s[0] == '\\') if (s[1]) { s++; if (strchr(second, s[0])) return (s[0] != 'n' || s[1]); } else return 0; else return (s[0] != '\n' || s[1]); s++; } return 0; } static int strlen_acs(const char *s/*, int *h, int *w*/) { /*CLN FIX*/ return strlen(s); } static void waddnstr_acs(WINDOW *win, const char *s, int n) { char *ss; chtype attrs; /*CLN FIX*/ if (n >= 0 && n < strlen_acs(s)) { ss = malloc(n+1); strncpy(ss, s, n); ss[n] = '\0'; s = ss; } else ss = NULL; attrs = A_NORMAL; while (*s) { char ch = *s; if (ch == '\\') switch (s[1]) { case '-': case '+': { struct dfg { const char *xx; chtype attr; }; static struct dfg dfgv[] = { {"so", A_STANDOUT}, {"ul", A_UNDERLINE}, {"rv", A_REVERSE}, {"bk", A_BLINK}, {"dm", A_DIM}, {"bd", A_BOLD}, {"ac", A_ALTCHARSET}, {"nm", A_NORMAL}, }; int i; for (i = 0; i < SIZEOF(dfgv); i++) if (!strncmp(s+2, dfgv[i].xx, 2)) { /* +2 => over /+ or /- */ chtype my_attrs = dfgv[i].attr; if (s[1] == '+') if (my_attrs == A_NORMAL) attrs = my_attrs; else attrs |= my_attrs; else attrs &= ~my_attrs; s += 3; goto cont; } } break; case 'b': ch = '\b'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\0': goto ret; } waddch(win, fmli2acs(ch | attrs)); cont: s++; } ret: if (ss) free(ss); } static struct msg * msg_stack(all my_all, enum msg_type msg_type) { struct msg *v; switch (msg_type) { case b_permanent: v = &my_all->msg_permanent; break; case b_frame: v = !my_all->current_frm ? NULL : &my_all->current_frm->msg_frame; break; case b_transient: v = &my_all->msg_transient; break; } return v; } static void msg_stack_sync(all my_all) { WINDOW *window; enum msg_type msg_type; window = my_all->msg; msg_type = b_transient; do { struct msg *msgX; msgX = msg_stack(my_all, msg_type); if (msgX && (msgX->msg || msg_type == b_permanent)) { if (msgX->msg != my_all->msg_msg) { wmove(window, 0, 0); if (msgX->msg) { if (msgX->acs) waddnstr_acs(window, msgX->msg, -1); else waddstr(window, msgX->msg); } my_all->msg_msg = msgX->msg; wclrtobot(window); wrefresh(window); update_panels();/*CLN Why*/ doupdate(); } break; } } while (msg_type--); } static void msg_put(all my_all, enum msg_type msg_type, char *msg, int maybe) { if (my_all && my_all->screen && my_all->msg) { struct msg *msgX; msgX = msg_stack(my_all, msg_type); if (msgX) { int sync; sync = msgX->msg != NULL; if (sync) free(msgX->msg); msgX->msg = msg; if (msgX->msg) { msgX->acs = !maybe ? maybe : is_acs(msgX->msg, 0); sync = 1; } if (sync) msg_stack_sync(my_all); } } else if (msg) fprintf(stderr, "%s\n", msg); } static void message_dup(all my_all, const char *msg, int maybe) { msg_put(my_all, b_transient, strdup(msg), maybe); } static void message_dyn(all my_all, char *msg, int maybe) { msg_put(my_all, b_transient, msg, maybe); } static void message_va(all my_all, const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); static void message_va(all my_all, const char *format, ...) { va_list ap; char msg[1024+1]; /* formatted error message */ va_start(ap, format); vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); message_dup(my_all, msg, 0); } #define MAX_FKEYS 10 #define ENABLE_F(n) (1 << ((n)-1)) static void press_enter(void) { do { printf("\n"); printf("Press ENTER to continue"); fflush(stdout); } while (getchar() != '\n'); } /* Caller must: if (result) free(result); */ static char * read_fd(int fd) { char buf[200]; ssize_t nread; vary_char s_out; s_out = add_vary_char(NULL, ""); while ((nread = read(fd, buf, sizeof(buf)-1)) > 0) add_vary_char_n(s_out, buf, nread); return str_vary_char_dup(s_out); } #define MAX_CONN_REQ 5 /* maximum number of outstanding connection requests * the kernel will queue for the server. */ static socklen_t set_addr(struct sockaddr_un *unix_addr, const char *name) { memset(unix_addr, 0, sizeof(*unix_addr)); unix_addr->sun_family = AF_UNIX; strcpy(unix_addr->sun_path, name); return strlen(unix_addr->sun_path)+sizeof(unix_addr->sun_family); } static int serv_listen(const char *name) { int fd; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd >= 0) { struct sockaddr_un unix_addr; socklen_t len; fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); unlink(name); len = set_addr(&unix_addr, name); if (bind(fd, (struct sockaddr*)&unix_addr, len) < 0) fd = -2; else if (listen(fd, MAX_CONN_REQ) < 0) fd = -3; } return fd; } static int serv_accept(int listen_fd) { struct sockaddr_un unix_addr; socklen_t len; int clifd; len = sizeof(unix_addr); clifd = accept(listen_fd, (struct sockaddr *)&unix_addr, &len); return clifd; } static void set_fd(int fd, fd_set *allset, int *maxfd, unsigned int *allset_cnt) { FD_SET(fd, allset); *allset_cnt += 1; if (fd > *maxfd) *maxfd = fd; } static void clr_fd(int fd, fd_set *allset, int *maxfd, unsigned int *allset_cnt) { FD_CLR(fd, allset); *allset_cnt -= 1; if (fd == *maxfd) { if (*allset_cnt == 0) fd = -1; else while (--fd >= 0) if (FD_ISSET(fd, allset)) break; *maxfd = fd; } } #define VPID "VPID" #define FMLI_PIPE "FMLI_PIPE" struct msgs_0 { size_t totlen; int fdc; }; struct msgs_args { int argc; char *argv[1]; /* char str[1]; */ }; struct msgs_ret { int res; }; static void dump_msg(const char *p, struct msgs_args *pargs) { if (pargs) dump_argv(p, pargs->argc, (char **)&pargs->argv); } static ssize_t send_msgs(int fd, int argc, char **argv, int fd_0, int fdc) { struct msgs_0 msg_0; struct msgs_args *pargs; ssize_t res; int c; if (DEBUGSTDDBG && stddbg) { dump_argv("send_msgs:\n", argc, argv); fprintf(stddbg, "fd_0=%i fdc=%i\n", fd_0, fdc); fflush(stddbg); } msg_0.totlen = sizeof(*pargs)-sizeof(pargs->argv); for (c = 0; c < argc && argv[c]; c++) { msg_0.totlen += sizeof(pargs->argv[0]); msg_0.totlen += strlen(argv[c])+1; } msg_0.totlen += sizeof(pargs->argv[0]); /* For NULL ptr */ argc = c; msg_0.fdc = fdc; res = write(fd, &msg_0, sizeof(msg_0)); if (res >= 0) { pargs = malloc(msg_0.totlen); if (pargs) { struct msghdr my_msghdr; struct iovec my_iovec; struct cmsghdr *my_msg_control; size_t l; char *strptr; my_iovec.iov_base = pargs; my_iovec.iov_len = msg_0.totlen; pargs->argc = argc; strptr = (char *)(pargs->argv+argc+1); for (c = 0; c < argc && argv[c]; c++) { pargs->argv[c] = (char *)(strptr-(char *)pargs); strcpy(strptr, argv[c]); strptr += strlen(strptr)+1; } pargs->argv[c] = NULL; if (msg_0.fdc) { l = CMSG_SPACE(sizeof(int)*msg_0.fdc); my_msg_control = malloc(l); if (my_msg_control) { size_t n; n = sizeof(int)*msg_0.fdc; my_msg_control->cmsg_len = CMSG_LEN(n); my_msg_control->cmsg_level = SOL_SOCKET; my_msg_control->cmsg_type = SCM_RIGHTS; for (c = 0; c < msg_0.fdc; c++) ((int *)CMSG_DATA(my_msg_control))[c] = c+fd_0; } } else { l = 0; my_msg_control = NULL; } my_msghdr.msg_name = NULL; my_msghdr.msg_namelen = 0; my_msghdr.msg_iov = &my_iovec; my_msghdr.msg_iovlen = 1; my_msghdr.msg_control = my_msg_control; my_msghdr.msg_controllen = l; my_msghdr.msg_flags = 0; res = sendmsg(fd, &my_msghdr, 0); if (my_msg_control) free(my_msg_control); free(pargs); } else res = -1; } return res; } static ssize_t recv_msgs(int fd, struct msgs_args **p_pargs, struct msgs_fds **p_pfds) { struct msgs_0 msg_0; ssize_t res; res = read(fd, &msg_0, sizeof(msg_0)); if (res >= 0) { struct msgs_args *pargs; struct msghdr my_msghdr; struct iovec my_iovec; struct cmsghdr *my_msg_control; size_t l; pargs = malloc(msg_0.totlen); my_iovec.iov_base = pargs; my_iovec.iov_len = msg_0.totlen; if (msg_0.fdc) { l = CMSG_SPACE(sizeof(int)*msg_0.fdc); my_msg_control = malloc(l); } else { l = 0; my_msg_control = NULL; } my_msghdr.msg_name = NULL; my_msghdr.msg_namelen = 0; my_msghdr.msg_iov = &my_iovec; my_msghdr.msg_iovlen = 1; my_msghdr.msg_control = my_msg_control; my_msghdr.msg_controllen = l; my_msghdr.msg_flags = 0; res = recvmsg(fd, &my_msghdr, 0); if (res >= 0) { if (my_msghdr.msg_flags & MSG_TRUNC) res = -1; else { if (p_pargs) { int c; for (c = 0; pargs->argv[c]; c++) pargs->argv[c] += (int)pargs; *p_pargs = pargs; } if (msg_0.fdc && (my_msghdr.msg_flags & MSG_CTRUNC)) res = -1; else { if (p_pfds) { size_t n; n = sizeof(int)*msg_0.fdc; if (n && (my_msg_control->cmsg_len < CMSG_LEN(n) || my_msg_control->cmsg_level != SOL_SOCKET || my_msg_control->cmsg_type != SCM_RIGHTS)) res = -1; else { *p_pfds = malloc(sizeof(*(*p_pfds))-sizeof((*p_pfds)->fdv)+n); if (*p_pfds) { (*p_pfds)->fdc = msg_0.fdc; if (n) memcpy((*p_pfds)->fdv, ((int *)CMSG_DATA(my_msg_control)), n); } else res = -1; } } } } } if (my_msg_control) free(my_msg_control); if (res < 0) if (pargs) free(pargs); } if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "recv_msgs:res=%i\n", res); if (res >= 0) { if (p_pargs) dump_argv("recv_msgs:\n", (*p_pargs)->argc, (*p_pargs)->argv); if (msg_0.fdc && p_pfds) { int c; for (c = 0; c < (*p_pfds)->fdc; c++) fprintf(stddbg, "fd[%i]=%i\n", c, (*p_pfds)->fdv[c]); } } fflush(stddbg); } return res; } static ssize_t send_exit(int fd, int res) { struct msgs_ret msg_ret; msg_ret.res = res; if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "send_exit=%i\n", msg_ret.res); fflush(stddbg); } return write(fd, &msg_ret, sizeof(msg_ret)); } static int recv_exit(int fd) { struct msgs_ret msg_ret; if (read(fd, &msg_ret, sizeof(msg_ret)) < sizeof(msg_ret)) msg_ret.res = EXIT_FAILURE; if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "recv_exit=%i\n", msg_ret.res); fflush(stddbg); } return msg_ret.res; } static int blt_rpc(int argc, char **argv, int fd_0, int fdc) { int res = EXIT_FAILURE; char *appSocketPath = getenv(FMLI_PIPE); if (appSocketPath) { int fd; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd >= 0) { struct sockaddr_un unix_addr; socklen_t len; len = set_addr(&unix_addr, appSocketPath); if (connect(fd, (struct sockaddr *)&unix_addr, len) < 0) fd = -3; } if (fd >= 0) { if (send_msgs(fd, argc, argv, fd_0, fdc) >= 0) res = recv_exit(fd); close(fd); } } return res; } /***************************/ static void executecommand(all my_all, char *p); static fmli_integer get_integer(all my_all, vary_dict desc, const char *key, fmli_integer def); static fmli_boolean get_boolean(all my_all, vary_dict desc, const char *key, fmli_boolean def); static fmli_string get_string(all my_all, vary_dict desc, const char *key); #define get_string_acs get_string static fmli_integer get_colorinteger(all my_all, const char *key, int def); static int my_mkfifo(const char *name) { int res; if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "my_mkfifo:\"%s\"\n", name); fflush(stddbg); } res = mkfifo(name, (S_IRGRP | S_IWGRP | S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH)); if (res) if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "my_mkfifo:failed\n"); fflush(stddbg); } return res; } #if MY_POPEN >= 1 static ssize_t shell_write(all my_all, const char *buf) { return write(my_all->shell_co.eval_out_fd, buf, strlen(buf)); } #endif static int setenv_string(all my_all, const char *name, const char *value) { if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "setenv_string:name=<%s>", name); if (value) fprintf(stddbg, " value=<%s>", value); fprintf(stddbg, "\n"); fflush(stddbg); } #if MY_POPEN >= 1 if (my_all && my_all->shell_co.shell_open) { if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "setenv_string:write to shell\n"); fflush(stddbg); } shell_write(my_all, "builtin export "); if (!value) { shell_write(my_all, "-n "); shell_write(my_all, name); } else { shell_write(my_all, name); shell_write(my_all, "="); if (strpbrk(value, "#&*?[]()=|^;<>`$\"' \t\n")) {/* Works for Posix/Bash */ const char *p0; /* replace any run of ' (say ''') by '"'''"' and surround the whole string by ' . */ for (p0 = value; *p0; ) { const char *p1; for (p1 = p0; *p1 && (*p1 != '\''); p1++) ; if (p1 != p0) { shell_write(my_all, "'"); write(my_all->shell_co.eval_out_fd, p0, p1-p0); shell_write(my_all, "'"); p0 = p1; } if (*p1 == '\'') { for (p1 = p0; *p1 && (*p1 == '\''); p1++) ; shell_write(my_all, "\""); write(my_all->shell_co.eval_out_fd, p0, p1-p0); shell_write(my_all, "\""); p0 = p1; } } } else shell_write(my_all, value); } shell_write(my_all, "\n"); fsync(my_all->shell_co.eval_out_fd); } #endif return !value ? unsetenv(name) : setenv(name, value, 1); } static void setenv_std(all my_all, const char *name, int fd) { const char *value; value = ttyname(fd); if (!value) value = "/dev/null"; setenv_string(my_all, name, value); } static void setenv_integer(all my_all, const char *name, int value) { char val[24+1]; snprintf(val, sizeof(val), "%d", value); setenv_string(my_all, name, val); } static void setenv_boolean(all my_all, const char *name, int value) { setenv_string(my_all, name, value ? "true" : "false"); } static void * frm_args(all my_all, FRM *the_frm, int set_them) { void *res; res = the_frm; if (the_frm) { int argc; char **argv; argc = the_frm->argc; argv = the_frm->argv; if (set_them) res = argv; if (argv) { int i; for (i = 1; i < argc && argv[i]; i++) { char name[12+1]; snprintf(name, sizeof(name), "ARG%d", i); setenv_string(my_all, name, !set_them ? NULL : argv[i]); } } } return res; } static vary_dict get_local_desc(FRM *the_frm) { vary_dict desc; switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: desc = field_userptr(current_field(the_frm->u.f.form)); break; case FRMt_menu: desc = item_userptr(current_item(the_frm->u.m.menu)); break; } return desc; } static void frm_item_args(all my_all, int mask, const char *u, const char *l, int *b) { if (my_all->current_frm) { if (mask & (1 << my_all->current_frm->frm_type)) { fmli_string s; s = get_string(my_all, get_local_desc(my_all->current_frm), l); setenv_string(my_all, u, s); if (s) { if (b) *b = 1; free(s); } } else if (b && *b) { setenv_string(my_all, u, NULL); if (b) *b = 0; } } } static void setup_frm_args(all my_all) { if (my_all->arg_owner_frm != my_all->current_frm) { if (my_all->arg_owner_frm) if (frm_args(my_all, my_all->arg_owner_frm, 0)) my_all->arg_owner_frm = NULL; if (my_all->current_frm) if (frm_args(my_all, my_all->current_frm, 1)) my_all->arg_owner_frm = my_all->current_frm; } } static int whichof(const char *p, const char **x, size_t l) { int res; for (res = 0; res < l; res++) if (!strcasecmp(p, x[res])) return res; return -1; } static void run_begin(void) { endwin(); } static void run_end(void) { touchwin(curscr); update_panels(); doupdate(); } /******XXXXXXXXXX*************/ static void indicator_acs_maybe(all my_all, int c, const char *s, size_t l) { int acs; acs = is_acs(s, 0); if (l == -1) { #if 0 if (acs) { int h = 0; int w = 0; strlen_acs(s/*,&h, &w*/); } else #endif l = strlen(s); } if (c == p_center) c = (my_all->displayhw.x-l)/2; else if (c == p_right) c = my_all->displayhw.x-l; if (c < 0) c = 0; if ((my_all->displayhw.x-c) < l) l = my_all->displayhw.x-c; wmove(my_all->ban, 0, c); if (acs) waddnstr_acs(my_all->ban, s, l); else waddstr(my_all->ban, s); } static void working(int p) { /*CLN FIX*/ } static void indicator_w(all my_all) { fmli_string_acs s; s = get_string_acs(my_all, my_all->def[DEF_init].globals, "working"); if (s) { indicator_acs_maybe(my_all, p_right, s, -1); free(s); } } static void indicator_flash(all my_all) { /*CLN FIX*/ } static int readfile(all my_all, int argc, char **argv, int fdc, int *fdv, int output) { int res = EXIT_FAILURE; if (argc > 1) { FILE *fp; fp = fopen(argv[1], "r"); if (fp) { int maxcount; int c; int count; maxcount = 0; for (count = 0; (c = getc(fp)) != EOF; count++) { if (c == '\n') { if (count > maxcount) maxcount = count; count = -1; } if (output) { char s[1]; s[0] = c; write(fdv[STDOUT_FILENO], s, 1); } } fclose(fp); if (count > maxcount) maxcount = count; my_all->readfile_val = maxcount+1; goto writeit; } } else { writeit: if (!output) { size_t s_len; char s[12+1]; s_len = snprintf(s, sizeof(s), "%u", my_all->readfile_val); write(fdv[STDOUT_FILENO], s, s_len); } res = EXIT_SUCCESS; } return res; } static void setup_pairs(all my_all) { if (my_all->has_colors) { enum c_pairs pair; for (pair = c_slk; pair < c_MAX; pair++) { fmli_integer fg, bg; fg = get_colorinteger(my_all, color_pairs[pair].f, COLOR_WHITE); bg = get_colorinteger(my_all, color_pairs[pair].b, COLOR_WHITE); init_pair(pair, fg, bg); } slk_attroff(A_REVERSE | A_STANDOUT);/* So we know what we've got */ slk_attron(COLOR_PAIR(c_slk)); } } struct fgfg { all my_all; /**/ descs descs; int lower; vary_dict desc_c; }; static descs read_descs(all my_all, enum file_type file_type, const char *name, struct timespec *mtime) { const char *bname; descs descs; bname = strrchr(name, '/'); bname = bname ? bname+1 : name; descs = NULL; { FILE *f; f = fopen(name, "r"); if (f) { struct stat sb; if (mtime && (fstat(fileno(f), &sb) == 0)) { mtime->tv_sec = sb.st_mtime; mtime->tv_nsec = sb.st_atim.tv_nsec; } switch (file_type) { case FILE_form: case FILE_text: case FILE_menu: descs = new_desc(); break; case FILE_alias: case FILE_init: case FILE_cmd: descs = &my_all->def[file_type-FILE_alias]; break; } { struct fgfg p1; p1.my_all = my_all; p1.descs = descs; p1.lower = file_type != FILE_alias; p1.desc_c = NULL; yyrestart(f); if (yyparse(&p1)) ; /*Error*/ } fclose(f); } else message_va(my_all, "Can't open %s object \"%s\"", file_type_spelling[file_type], name); } return descs; } static int build_def_descs(all my_all, enum def_type def_type, const char *filename) { add_descriptors(&my_all->def[def_type], &defs[def_type], def_type != DEF_alias); if (DEBUGSTDDBG && stddbg) dump_descriptors(&my_all->def[def_type], defs[def_type].name); return (!(def_type < DEF_MAX) || !filename || read_descs(my_all, DEF2FILE(def_type), filename, NULL)); } static int local_setenv_string(all my_all, const char *name, const char *value) { /*CLN FIX*/ #if defined(HACK_Form_Choice) { const char *ln = "Form_Choice"; if (name == ln || !strcmp(name, ln)) { if (my_all->local_Form_Choice) free(my_all->local_Form_Choice); my_all->local_Form_Choice = !value ? NULL : strdup(value); } } #endif return EXIT_SUCCESS; } static char * local_getenv(all my_all, const char *name) { /*CLN FIX*/ #if defined(HACK_Form_Choice) { const char *ln = "Form_Choice"; return ((name != ln) && strcmp(name, ln)) ? NULL : my_all->local_Form_Choice; } #else return NULL; #endif } static char * basename(char *name) { char *n; return !(n = strrchr(name, '/')) ? name : n+1; } static char *mk_temp_pid(all my_all, const char *format, const char *s); static void co_free(CO *co, int free_all) { if (co->fp_write) { fclose(co->fp_write); co->fp_write = NULL; } unlink(co->wpath); unlink(co->rpath); if (co->refnames) { int i; for (i = 0; i < co->refnames_cnt; i++) if (co->refnames[i]) free(co->refnames[i]); free(co->refnames); } { enum co_str i; for (i = 0; i < co_MAX; i++) if (co->strs[i]) free(co->strs[i]); } if (free_all) free(co); } static void get_co_args(CO *co, int argc, char **argv) { int ch; optind = 0; opterr = 0; while ((ch = getopt(argc, argv, "e:i:r:R:s:w:z:")) != EOF) switch (ch) { case 'e': co->expect_string = optarg; break; case 'i': co->proc_id = optarg; break; case 'r': co->rpath = optarg; break; case 'R': co->refname = optarg; break; case 's': co->send_string = optarg; break; case 'w': co->wpath = optarg; break; case 'z': co->action = optarg; break; default: break; } } /******BEG blt2_?*************/ static int blt2_co_helper(all my_all, int argc, char **argv, int fdc, int *fdv) { CO co; int res; /* co_helper [-r rpath] [-w wpath] [-i proc_id] [-R refname] [-s send_string] [-e expect_string] [-z [+|-|=|?][e][i][r][s][w][z]] */ memset(&co, 0, sizeof(co)); res = EXIT_FAILURE; get_co_args(&co, argc, argv); if ((argc-optind) == 1 && co.proc_id) { CO **l_co_p; CO *l_co; l_co_p = &my_all->co_list; for (l_co = *l_co_p; l_co; l_co_p = &l_co->next) if (!strcmp(l_co->proc_id, co.proc_id)) break; res = EXIT_SUCCESS; switch (co.action[0]) { case '+': /* blt_cocreate */ if (l_co) { if (co.refname && l_co->refnames_cnt) { int i; for (i = 0; (i < l_co->refnames_cnt) && strcmp(l_co->refnames[i], co.refname); i++) ; if (l_co->refnames_cnt-(i+1) < 0) { l_co->refnames_cnt++; l_co->refnames = realloc(l_co->refnames, (i+1)*sizeof(l_co->refnames[0])); l_co->refnames[i] = strdup(co.refname); } } l_co->action = "0"; } else { if (co.refname) { co.refnames_cnt = 1; co.refnames = malloc(sizeof(co.refnames[0])); co.refnames[0] = strdup(co.refname); } { enum co_str i; for (i = 0; i < co_MAX; i++) if (co.strs[i]) co.strs[i] = strdup(co.strs[i]); for (i = co_rpath; i <= co_wpath; i++) { if (!co.strs[i]) co.strs[i] = mk_temp_pid(my_all, i == co_wpath ? "/tmp/w%s.%u" : "/tmp/r%s.%u", co.proc_id); my_mkfifo(co.strs[i]); } } co.fp_write = fopen(co.wpath, "w"); if (!co.fp_write) ; co.next = my_all->co_list; co.refname = NULL; l_co = malloc(sizeof(*l_co)); *l_co = co; my_all->co_list = l_co; l_co->action = "1"; } break; case '-': /* blt_codestroy 1 */ if (l_co) { if (co.refnames && l_co->refnames_cnt) { int i; for (i = 0; (i < l_co->refnames_cnt) && strcmp(l_co->refnames[i], co.refname); i++) ; free(l_co->refnames[i]); if (l_co->refnames_cnt-(i+1) > 0) memcpy(&l_co->refnames[i], &l_co->refnames[i+1], (l_co->refnames_cnt-(i+1))*sizeof(l_co->refnames[0])); l_co->refnames_cnt--; } l_co->action = l_co->refnames_cnt == 0 ? "0" : "1"; if (l_co->refnames_cnt == 0) { size_t s_len; s_len = sizeof(l_co)*2+2+2+1; l_co->proc_id = realloc(l_co->proc_id, s_len); snprintf(l_co->proc_id, s_len, "<%p>", (void *)l_co); co.proc_id = NULL; if (my_all->co_list != l_co) { *l_co_p = l_co->next; l_co->next = my_all->co_list; my_all->co_list = l_co; } } } break; case '=': /* blt_codestroy 2 */ *l_co_p = l_co->next; co_free(l_co, 1); break; case '?': default: break; } if (fdc) { char *res; int fd; fd = fdv[STDOUT_FILENO]; for (res = co.action+1; *res; res++) { enum co_str i; for (i = 0; i < co_MAX; i++) if (co_letters[i][1] == *res) { if (!co.strs[i] && l_co->strs[i]) { write(fd, co_letters[i], strlen(co_letters[i])+1); write(fd, l_co->strs[i], strlen(l_co->strs[i])+1); } break; } } write(fd, "", 1); } } return res; } static int blt2_getfrm(all my_all, int argc, char **argv, int fdc, int *fdv) { FRM *the_frm; /* getfrm */ the_frm = my_all->current_frm; write(fdv[STDOUT_FILENO], the_frm->num, strlen(the_frm->num)); write(fdv[STDOUT_FILENO], "\n", 1); return EXIT_SUCCESS; } static int blt2_getitems(all my_all, int argc, char **argv, int fdc, int *fdv) { int res = EXIT_FAILURE; FRM *the_frm; /* getitems [delimiter_string] */ the_frm = my_all->current_frm; if (the_frm->frm_type == FRMt_menu && the_frm->u.m.items && the_frm->u.m.items[0]) { const char *delim; size_t delim_len; int i; ITEM *item; delim = (argc >= 1) ? argv[1] : "\n"; delim_len = strlen(delim); for (i = 0; (item = the_frm->u.m.items[i]); i++) if (item_value(item)) { vary_dict desc; fmli_string s; desc = item_userptr(item); s = get_string(my_all, desc, "lininfo"); if (!s) s = get_string(my_all, desc, "name"); write(fdv[STDOUT_FILENO], s, strlen(s)); write(fdv[STDOUT_FILENO], delim, delim_len); if (s) free(s); } res = EXIT_SUCCESS; } return res; } static int blt2_longline(all my_all, int argc, char **argv, int fdc, int *fdv) { /* longline [file] */ return readfile(my_all, argc, argv, fdc, fdv, 0); } static int blt2_message(all my_all, int argc, char **argv, int fdc, int *fdv) { int is_message; int ch; const char *optstring; int b; int c; size_t l; int o; int w; enum msg_type msg_type; char *s; /* indicator [-b [num]] [-c column] [-l length] [-o] [-w] [string ...] */ /* message [-b [num]] [-t|-f|-p] [-o] [-w] [string ...] */ is_message = !strcmp(argv[0], "message"); optstring = is_message ? "tfpb:ow:" : "c:l:b:ow:"; b = 0; c = 0; l = my_all->displayhw.x; o = 0; w = 0; msg_type = b_transient; optind = 0; opterr = 0; while ((ch = getopt(argc, argv, optstring)) != EOF) switch (ch) { case 'o': o = 1; break; case 'b': if (optarg && isdigit(optarg[0])) { b = atoi(optarg); if (b <= 0) b = 1; else if (b > 10) b = 10; } else b = 1; break; case 'c': c = atoi(optarg); if (c < 0) c = 0; break; case 'l': l = atoi(optarg); if (l < 0) l = 0; break; case 'f': msg_type = b_frame; break; case 'p': msg_type = b_permanent; break; case 't': msg_type = b_transient; break; case 'w': w = 1; break; default: break; } if ((argc-optind) > 0) s = argv2char(NULL, argc-optind, argv+optind, NULL); else s = read_fd(fdv[STDIN_FILENO]); if (o) write(fdv[STDOUT_FILENO], s, strlen(s)); if (is_message) msg_put(my_all, msg_type, s, 1); else { indicator_acs_maybe(my_all, c, s, l); free(s); } if (w) indicator_w(my_all); if (w || !is_message) wrefresh(my_all->ban); update_panels();/*CLN Why*/ doupdate(); while (b > 0) { beep(); b--; } return EXIT_SUCCESS; } #if 0 static int blt2_pathconv(all my_all, int argc, char **argv, int fdc, int *fdv) { /* pathconv [-f] [-v alias] */ /* pathconv [-t] [-l] [-nnum] [-v string] */ /*CLN FIX*/ return EXIT_SUCCESS; } #endif static int blt2_readfile(all my_all, int argc, char **argv, int fdc, int *fdv) { /* readfile file */ return readfile(my_all, argc, argv, fdc, fdv, 1); } static int blt2_reinit(all my_all, int argc, char **argv, int fdc, int *fdv) { int res; /* reinit file */ /*CLN FIX*/ if (argv[1] /*&& can I read it*/) { free_descs(&my_all->def[DEF_init]); build_def_descs(my_all, DEF_init, argv[1]); setup_pairs(my_all); /*statusline();*/ /* Be carefull that we have not free-ed something which is in use!!! */ res = EXIT_SUCCESS; } else res = EXIT_FAILURE; return res; } static int blt2_run_begin(all my_all, int argc, char **argv, int fdc, int *fdv) { /* run_begin [-s] [-e] [-n] */ run_begin(); return EXIT_SUCCESS; } static int blt2_run_end(all my_all, int argc, char **argv, int fdc, int *fdv) { /* if (!argv[2] || strcmp(argv[2], "-s")) */ run_end(); return EXIT_SUCCESS; } static int blt2_set(all my_all, int argc, char **argv, int fdc, int *fdv) { int ch; char efl; char *f; /*CLN FIX*/ /* set [-e variable[=value ]] ... */ /* set [-ffile variable[=value ]] ... */ /* set [-l variable[=value]] ... */ optind = 0; opterr = 0; /*This is gnu not posix getopt !!! */ while ((ch = getopt(argc, argv, "-ef:l")) != EOF) switch (ch) { case 'e': efl = ch; break; case 'f': efl = ch; f = optarg; break; case 'l': efl = ch; break; case 1: { char *sv; char *name_end; name_end = strchr(optarg, '='); if (!name_end) sv = read_fd(fdv[STDIN_FILENO]); else { *name_end = '\0'; sv = name_end+1; } switch (efl) { case 'e': if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "set -e <%s>=<%s>\n", optarg, sv); fflush(stddbg); } setenv_string(my_all, optarg, sv); break; case 'f': if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "set -f<%s> <%s>=<%s>\n", f, optarg, sv); fflush(stddbg); } break; case 'l': if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "set -l <%s>=<%s>\n", optarg, sv); fflush(stddbg); } local_setenv_string(my_all, optarg, sv); break; } if (!name_end && sv) free(sv); } break; default: break; } return EXIT_SUCCESS; } static int blt2_setcolor(all my_all, int argc, char **argv, int fdc, int *fdv) { int res = EXIT_FAILURE; /* setcolor color red_level green_level blue_level */ if (can_change_color() && argc == 5) { fmli_integer i; i = get_integer(my_all, my_all->def[WWW_color].globals, argv[1], -1); if (i < 0 && my_all->num_colors < COLORS) { vary_dict desc; char val[24+1]; i = my_all->num_colors++; snprintf(val, sizeof(val), "%u", i); desc = NULL; add_descriptor_dup(&my_all->def[WWW_color], argv[1], val, 1, &desc); } if (i >= 0) if (init_color(i, atoi(argv[2]), atoi(argv[3]), atoi(argv[4])) != ERR) { write(fdv[STDOUT_FILENO], argv[1], strlen(argv[1])); res = EXIT_SUCCESS; } } return res; } static int blt2_unset(all my_all, int argc, char **argv, int fdc, int *fdv) { int ch; char efl; char *f; /*CLN FIX*/ /* unset -e variable ... *//* A cln addition */ /* unset -ffile variable ... */ /* unset -l variable ... */ optind = 0; opterr = 0; /*This is gnu not posix getopt !!! */ while ((ch = getopt(argc, argv, "-ef:l")) != EOF) switch (ch) { case 'e': efl = ch; break; case 'f': efl = ch; f = optarg; break; case 'l': efl = ch; break; case 1: switch (efl) { case 'e': if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "unset -e <%s>\n", optarg); fflush(stddbg); } setenv_string(my_all, optarg, NULL); break; case 'f': if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "unset -f<%s> <%s>\n", f, optarg); fflush(stddbg); } break; case 'l': if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "unset -l <%s>\n", optarg); fflush(stddbg); } local_setenv_string(my_all, optarg, NULL); break; } break; default: break; } return EXIT_SUCCESS; } /******END blt2_?*************/ static void sig_handler(int arg) { g_my_all->interrupt.ed = 1; } #if MY_POPEN >= 1 struct popen_list_item { struct popen_list_item *next; int fd; pid_t pid; }; static struct popen_list_item *popen_list /* = NULL (bss initialized) */; #include static int my_popen(void) { struct popen_list_item *pi; if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "my_popen:\n"); fflush(stddbg); } pi = malloc(sizeof(struct popen_list_item)); if (pi) { int pipe_fd[2]; if (!pipe(pipe_fd)) { pid_t pid; pid = fork(); if (pid == 0) { /* Child of fork */ close(pipe_fd[STDOUT_FILENO]); if (pipe_fd[STDIN_FILENO] != STDIN_FILENO) { dup2(pipe_fd[STDIN_FILENO], STDIN_FILENO); close(pipe_fd[STDIN_FILENO]); } { struct popen_list_item *po; /* SUSv3 requires that any previously popen()'d streams in the * parent shall be closed in the child. */ for (po = popen_list ; po ; po = po->next) if (po->fd >= 0) close(po->fd); } execl("/bin/sh", "sh", (char *)0); /* SUSv3 mandates an exit code of 127 for the child if the * command interpreter can not be invoked. */ _exit(127); } else { close(pipe_fd[STDIN_FILENO]); if (pid > 0) { /* Parent of fork. */ pi->pid = pid; pi->fd = pipe_fd[STDOUT_FILENO]; pi->next = popen_list; popen_list = pi; return pipe_fd[STDOUT_FILENO]; } else /* fork failed, still in parent */ close(pipe_fd[STDOUT_FILENO]); } } free(pi); } return -1; } static int my_pclose(int pipe_fd) { struct popen_list_item *p; int stat; pid_t pid; if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "my_pclose:\n"); fflush(stddbg); } /* First, find the list entry corresponding to stream and remove it * from the list. Set p to the list item (NULL if not found). */ if ((p = popen_list) != NULL) { if (p->fd == pipe_fd) popen_list = p->next; else { struct popen_list_item *t; do { t = p; if (!(p = t->next)) { errno = EINVAL; /* Not required by SUSv3. */ break; } if (p->fd == pipe_fd) { t->next = p->next; break; } } while (1); } } if (p) { pid = p->pid; /* Save the pid we need */ free(p); /* and free the list item. */ close(pipe_fd); /* SUSv3 specificly requires that pclose not return before the child * terminates, in order to disallow pclose from returning on EINTR. */ do { if (waitpid(pid, &stat, 0) >= 0) return stat; if (errno != EINTR) break; } while (1); } return -1; } #endif static void setup_args(all my_all) { if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "setup_args:\n"); fflush(stddbg); } setup_frm_args(my_all); frm_item_args(my_all, -1, "LININFO", "lininfo", &my_all->arg_lininfo_set); frm_item_args(my_all, -1, "NAME", "name", &my_all->arg_name_set); /* A cln addition */ frm_item_args(my_all, (1 << FRMt_text), "TEXT", "text", &my_all->arg_text_set); #if 0 "NR"; "SELECTED"; #endif } static char * eval_in_shell(all my_all, const char *s) { #if MY_POPEN == 0 FILE *pipefp; #endif char *s_out; if (DEBUGSTDDBG && stddbg) { my_all->shell_co.popen_cnt++; fprintf(stddbg, "eval_in_shell:i:%d\n", my_all->shell_co.popen_cnt); fflush(stddbg); } { static const char shell_macros[] = "cocheck() { $FMLI_HELPER cocheck \"$@\";}\n" "cocreate() { $FMLI_HELPER cocreate \"$@\";}\n" "codestroy() { $FMLI_HELPER codestroy \"$@\";}\n" "coreceive() { $FMLI_HELPER coreceive \"$@\";}\n" "cosend() { $FMLI_HELPER cosend \"$@\";}\n" "fmlcut() { $FMLI_HELPER fmlcut \"$@\";}\n" "fmlexpr() { $FMLI_HELPER fmlexpr \"$@\";}\n" "fmlgrep() { $FMLI_HELPER fmlgrep \"$@\";}\n" "getfrm() { $FMLI_HELPER getfrm \"$@\";}\n" "getitems() { $FMLI_HELPER getitems \"$@\";}\n" "indicator() { $FMLI_HELPER indicator \"$@\";}\n" "longline() { $FMLI_HELPER longline \"$@\";}\n" "message() { $FMLI_HELPER message \"$@\";}\n" "readfile() { $FMLI_HELPER readfile \"$@\";}\n" "regex_lesse() { $FMLI_HELPER regex_lesse \"$@\";}\n" "regex() {\n" "local e_=0\n" "for i in \"$@\"; do\n" "case \"$i\" in\n" "-e) e_=1;break;;\n" "-*) ;;\n" "*) break;;\n" "esac\n" "done\n" "if (($e_)); then\n" "$(regex_lesse \"$@\")\n" "else\n" "regex_lesse \"$@\"\n" "fi\n" "}\n" "run() {\n" "local end_arg=\n" "while [ $# -gt 0 ]; do\n" "case \"$1\" in\n" "-[sen]) end_arg=\"$1\";;\n" "-*) ;;\n" "*) break;;\n" "esac\n" "done\n" "run_begin $end_arg\n" "\"$@\"\n" "run_end $? $end_arg\n" "} <$FMLI_STDIN >$FMLI_STDOUT\n" "run_begin() { $FMLI_HELPER run_begin \"$@\";}\n" "run_end() { $FMLI_HELPER run_end \"$@\";}\n" "set() { $FMLI_HELPER set \"$@\";}\n" "setcolor() { $FMLI_HELPER setcolor \"$@\";}\n" "shell() { ${SHELL:-/usr/bin/sh} -c \"$*\";}\n" "unset() { $FMLI_HELPER unset \"$@\";}\n" "vsig() { $FMLI_HELPER vsig \"$@\";}\n" "enable -n set unset\n"; #if MY_POPEN >= 1 static const char shell_echo[] = "builtin echo >$FMLI_STDEVAL -E -n "; if (!my_all->shell_co.shell_open) { my_all->shell_co.tmp_fmli_stdevalPath = mk_temp_pid(my_all, "%s%u", TMP_FMLI_STDEVAL); setenv_string(my_all, "FMLI_STDEVAL", my_all->shell_co.tmp_fmli_stdevalPath); my_mkfifo(my_all->shell_co.tmp_fmli_stdevalPath); my_all->shell_co.eval_out_fd = my_popen(); if (my_all->shell_co.eval_out_fd >= 0) { my_all->shell_co.shell_open = 1; shell_write(my_all, shell_macros); fsync(my_all->shell_co.eval_out_fd); } } setup_args(my_all); my_all->shell_co.eval_in_fd = open(my_all->shell_co.tmp_fmli_stdevalPath, O_RDONLY | O_NONBLOCK); shell_write(my_all, shell_echo); shell_write(my_all, s); shell_write(my_all, "\n"); fsync(my_all->shell_co.eval_out_fd); #else static const char shell_echo[] = "builtin echo -E -n "; size_t l_m; size_t l_e; size_t l_s; size_t l; char *s_in; l_m = strlen(shell_macros); l_e = strlen(shell_echo); l_s = strlen(s); l = l_m+l_e+l_s+1; s_in = malloc(l); strcpy(s_in, shell_macros); strncpy(s_in+l_m, shell_echo, l_e); strncpy(s_in+l_m+l_e, s, l_s); s_in[l-1] = '\0'; setup_args(my_all); pipefp = popen(s_in, "r"); if (pipefp) my_all->shell_co.shell_open = 1; free(s_in); #endif s = NULL; } if (my_all->shell_co.shell_open) { int evalfd; int maxfd; int clifd; fd_set allset; unsigned int allset_cnt; vary_char s_tmp; #if MY_POPEN >= 1 evalfd = my_all->shell_co.eval_in_fd; #else evalfd = fileno(pipefp); #endif FD_ZERO(&allset); allset_cnt = 0; maxfd = -1; set_fd(my_all->listen_fd, &allset, &maxfd, &allset_cnt); set_fd(evalfd, &allset, &maxfd, &allset_cnt); s_tmp = add_vary_char(NULL, ""); while (allset_cnt > 1) { /* More than just the my_all->listen_fd socket */ int n; fd_set rset; rset = allset; n = select(maxfd+1, &rset, NULL, NULL, NULL); if (n < 0) { if (errno == EINTR) continue; /* Interrupted by signal. Select again. */ else { message_dup(my_all, "select error", 0); FFREE((id)s_tmp); s_out = NULL; goto leave; } } if (FD_ISSET(my_all->listen_fd, &rset)) { clifd = serv_accept(my_all->listen_fd); if (clifd < 0) message_va(my_all, "serv_accept error: %d", clifd); else { set_fd(clifd, &allset, &maxfd, &allset_cnt); FD_CLR(my_all->listen_fd, &rset); } } for (clifd = 0; clifd <= maxfd; clifd++) { if (FD_ISSET(clifd, &rset)) { if (clifd == evalfd) { char buf[200]; ssize_t nread; nread = read(clifd, buf, sizeof(buf)-1); if (nread < 0) { message_va(my_all, "read error on fd %d", clifd); FFREE((id)s_tmp); s_out = NULL; goto leave; } else if (nread == 0) { /* The client was terminated or closed the stream pipe. */ clr_fd(clifd, &allset, &maxfd, &allset_cnt); } else add_vary_char_n(s_tmp, buf, nread); } else { struct msgs_args *pargs = NULL; struct msgs_fds *pfds = NULL; if (recv_msgs(clifd, &pargs, &pfds) >= 0) { struct zxzx_blt2 { const char *name; int (*blt_fnc)(all my_all, int argc, char **argv, int fdc, int *fd); }; static struct zxzx_blt2 zx_blt2[] = { {"co_helper", blt2_co_helper}, {"getfrm", blt2_getfrm}, {"getitems", blt2_getitems}, {"indicator", blt2_message}, {"longline", blt2_longline}, {"message", blt2_message}, #if 0 {"pathconv", blt2_pathconv}, #endif {"readfile", blt2_readfile}, {"reinit", blt2_reinit}, {"run_begin", blt2_run_begin}, {"run_end", blt2_run_end}, {"set", blt2_set}, {"setcolor", blt2_setcolor}, {"unset", blt2_unset}, }; int i; int res = EXIT_FAILURE; if (DEBUGSTDDBG && stddbg) dump_msg("eval_in_shell:x:\n", pargs); for (i = 0; i < SIZEOF(zx_blt2); i++) if (!strcmp(pargs->argv[0], zx_blt2[i].name)) { res = (*zx_blt2[i].blt_fnc)(my_all, pargs->argc, pargs->argv, pfds->fdc, pfds->fdv); errno = 0; break; } if (pfds) { while (pfds->fdc) { pfds->fdc--; fdatasync(pfds->fdv[pfds->fdc]); close(pfds->fdv[pfds->fdc]); } free(pfds); } if (pargs) free(pargs); send_exit(clifd, res); } clr_fd(clifd, &allset, &maxfd, &allset_cnt); close(clifd); } } } } s_out = str_vary_char_dup(s_tmp); leave: ; #if MY_POPEN >= 1 if (my_all->shell_co.eval_in_fd >= 0) { close(my_all->shell_co.eval_in_fd); my_all->shell_co.eval_in_fd = -1; } #else if (pipefp) { pclose(pipefp); my_all->shell_co.shell_open = 0; } #endif } else { message_dup(my_all, "Can't *popen", 0); s_out = NULL; } if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "eval_in_shell:o:%d\n", my_all->shell_co.popen_cnt); fflush(stddbg); my_all->shell_co.popen_cnt--; } return s_out; } /* Caller must: if (result) free(result); */ static char * eval(all my_all, const char *s) { char *s_out; size_t l; simple: if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "eval:i:<%s>\n", s); fflush(stddbg); } /*CLN Try and handle simple cases without calling popen */ l = strlen(s); if (!l) s_out = NULL; else if ((*s == '\'' && strpbrk(s+1, "'") == (s+(l-1))) || (*s == '"' && strpbrk(s+1, "'`$\"") == (s+(l-1)))) { s_out = strdup(s+1); s_out[(l-1)-1] = '\0'; } else if (!strpbrk(s, "'`$\"")) s_out = strdup(s); else { struct sigaction new_act, old_act; if (my_all->interrupt.able) { my_all->interrupt.ed = 0; #if defined(__linux__) || defined(__cygwin__) memset(&new_act, 0, sizeof(new_act)); new_act.sa_handler = sig_handler; if (sigaction(SIGINT, &new_act, &old_act)) ; #else sigset(SIGINT, sig_handler); #endif } s_out = eval_in_shell(my_all, s); if (my_all->interrupt.able) { #if defined(__linux__) if (sigaction(SIGINT, &old_act, NULL)) ; #endif if (my_all->interrupt.ed) { my_all->interrupt.ed = 0; my_all->interrupt.able = 0; s = my_all->interrupt.on; if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "eval:o:interrupted"); fflush(stddbg); } goto simple; } } } if (my_all->interrupt.on) { free(my_all->interrupt.on); my_all->interrupt.on = NULL; } if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "eval:o:"); if (s_out) fprintf(stddbg, "<%s>", s_out); fprintf(stddbg, "\n"); fflush(stddbg); } return s_out; } static const char * check_value_vary_dict(const vary_dict self, const char *key, all my_all, enum fmli_types fmli_type) { if (DEBUGSTDDBG && stddbg && (self != my_all->def[WWW_color].globals)) { const char **x; /* Does not contain user defined keys */ for (x = all_s[fmli_type]; *x; x++) if (*x == key || !strcasecmp(*x, key)) goto found; message_va(my_all, "What:%s is not a %s", key, fmli_types_names[fmli_type]); found: ; } return value_vary_dict(self, key); } static int whichof_all(all my_all, vary_dict desc, const char *key, int def, enum fmli_types fmli_type, const char **x, size_t l) { const char *valuex; valuex = check_value_vary_dict(desc, key, my_all, fmli_type); if (valuex) { char *p; p = eval(my_all, valuex); if (p) { int r; r = whichof(p, x, l); if (r != -1) def = r; free(p); } } return def; } /* Caller must: if (result) free(result); */ /* Returns NULL if key not found, otherwise a string, which maybe empty. */ static char * get_(all my_all, vary_dict desc, const char *key, enum fmli_types fmli_type) { char *valuex; if (desc) { const char *s; s = check_value_vary_dict(desc, key, my_all, fmli_type); valuex = !s ? NULL : eval(my_all, s); } else valuex = NULL; return valuex; } /* Caller must: if (result) free(result); */ /* Returns NULL if key not found, otherwise a string, which maybe empty. */ static fmli_string get_string(all my_all, vary_dict desc, const char *key) { return get_(my_all, desc, key, t_fmli_string); } /* Caller must: if (result) free(result); */ /* Returns NULL if key not found, otherwise a string, which maybe empty. */ static fmli_string get_command(all my_all, vary_dict desc, const char *key) { return get_(my_all, desc, key, t_fmli_command); } static vary_dict follow_list(vary_dict *desc_list, const char *key) { vary_dict *desc_p; for (desc_p = desc_list; *desc_p && !value_vary_dict(*desc_p, key); desc_p++) ; if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "follow_list:<%s> %i %p\n", key, desc_p-desc_list, (void *)*desc_p); fflush(stddbg); } return *desc_p; } /* see get_command */ static fmli_string get_action_done(all my_all, vary_dict desc, vary_dict globals, int try_globals, const char *key) { fmli_string s; for (; !(s = get_command(my_all, desc, key)) && try_globals; desc = globals) try_globals = 0; if (s) { vary_dict desc_list[3+1]; vary_dict d; vary_dict *pd; pd = &desc_list[0]; *pd++ = desc; if (globals && desc != globals) *pd++ = globals; *pd++ = my_all->def[DEF_init].globals; *pd++ = NULL; d = follow_list(desc_list, "interrupt"); my_all->interrupt.able = get_boolean(my_all, d, "interrupt", false); if (my_all->interrupt.able) { d = follow_list(desc_list, "oninterrupt"); my_all->interrupt.on = get_command(my_all, d, "oninterrupt"); } } return s; } static int is_action_nop(vary_dict desc) { const char *namex; namex = value_vary_dict(desc, "action"); if (namex) { const char *s = namex; if (s && !strcmp(s, "nop")) /*CLN allow \"nop\" ??? */ return 1; } return 0; } static int istrue(const char *p) { return !p || strcasecmp(p, "false"); } static fmli_boolean get_boolean(all my_all, vary_dict desc, const char *key, fmli_boolean def) { if (desc) { const char *valuex; valuex = check_value_vary_dict(desc, key, my_all, t_fmli_boolean); if (valuex) { char *p; p = eval(my_all, valuex); if (p) { def = istrue(p); free(p); } } } return def; } static fmli_integer get_integer(all my_all, vary_dict desc, const char *key, fmli_integer def) { if (desc) { const char *valuex; valuex = check_value_vary_dict(desc, key, my_all, t_fmli_integer); if (valuex) { char *p; p = eval(my_all, valuex); if (p) { def = atoi(p); free(p); } } } return def; } /* get_position returns: == def if no descriptor key --------------------------------------------- < p_unknown integer < -1 == p_unknown neither known keyword nor integer == p_right..p_distinct known keyword > p_distinct integer >= -1 */ #define position_is_integer(p) ((p) < p_unknown || (p) > p_distinct) #define position_is_valid_integer(p,l) (position_is_integer(p) && (p) >= 0 && (p) < l) /**/ static fmli_position get_position(all my_all, vary_dict desc, const char *key, fmli_position def) { const char *valuex; valuex = check_value_vary_dict(desc, key, my_all, t_fmli_position); if (valuex) { char *p; p = eval(my_all, valuex); if (p) { def = whichof(p, gyh_position, SIZEOF(gyh_position)); if (def == -1) { char *p_end; def = strtol(p, &p_end, 10); if (p_end[0]) def = p_unknown; else { if ((def >= p_unknown) && (def <= p_distinct)) def = p_unknown-1; } } else def += p_unknown; free(p); } } return def; } static void get_null(all my_all, vary_dict desc, const char *key) { char *s; s = get_(my_all, desc, key, t_fmli_null); if (s) free(s); } static fmli_layout get_layout(all my_all, vary_dict desc, const char *key, fmli_layout def) { return whichof_all(my_all, desc, key, def, t_fmli_layout, vbvb, SIZEOF(vbvb)); } /* Caller must: if (result) free(result); */ static fmli_color get_color(all my_all, vary_dict desc, const char *key, const fmli_color def) { fmli_color color; color = get_(my_all, desc, key, t_fmli_color); if (!color && def) color = strdup(def); return color; } /* get_toggle returns: == def if no descriptor key --------------------------------------------- < tg_always integer < -1 == tg_unknown neither known keyword nor integer == tg_always..tg_never known keyword > tg_never integer >= 0 */ #define toggle_is_integer(p) ((p) < tg_unknown || (p) > tg_never) /**/ static fmli_toggle get_toggle(all my_all, vary_dict desc, const char *key, fmli_toggle def) { const char *valuex; valuex = check_value_vary_dict(desc, key, my_all, t_fmli_toggle); if (valuex) { char *p; p = eval(my_all, valuex); if (p) { def = whichof(p, gyh_toggle, SIZEOF(gyh_toggle)); if (def == -1) { char *p_end; def = strtol(p, &p_end, 10); if (p_end[0]) def = tg_unknown; else { if ((def >= tg_unknown) && (def <= tg_never)) def = tg_unknown-1; } } else def += tg_unknown; free(p); } } return def; } /**/ static fmli_integer get_colorinteger(all my_all, const char *key, int def) { fmli_integer i; fmli_color c; c = get_color(my_all, my_all->def[DEF_init].globals, key, "black"); i = get_integer(my_all, my_all->def[WWW_color].globals, c, def); free(c); return i; } static fmli_lifetime get_lifetime(all my_all, vary_dict desc, const char *key, fmli_lifetime def) { return whichof_all(my_all, desc, key, def, t_fmli_string, gyx, SIZEOF(gyx)); } /*******************/ static vary_dict find_button(all my_all, vary_dicts items, fmli_integer keyIx) { size_t j; for (j = CCOUNT(items); j; j--) { vary_dict desc; desc = AAT(items, j-1); if (value_vary_dict(desc, "button")) if (keyIx == get_integer(my_all, desc, "button", 0/**/)) return desc; } return NULL; } static enum def_type uuu(FRM *the_frm) { enum def_type i; i = UUU_form_slk+the_frm->frm_type; switch (the_frm->frm_type) { case FRMt_form: i += the_frm->frm_type_sub.f; break; case FRMt_text: i += the_frm->frm_type_sub.t; break; case FRMt_menu: i += the_frm->frm_type_sub.m; break; } return i; } static void restore_cursor(all my_all) { FRM *the_frm; the_frm = my_all->current_frm; if (the_frm) { switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: pos_form_cursor(the_frm->u.f.form); break; case FRMt_menu: pos_menu_cursor(the_frm->u.m.menu); break; } } } static int on_scroller(MEVENT pt, const struct scroller *where, int delta) { if (where->len == 0) return 0; else if (delta) return (pt.x == where->top.x+(where->len-1-where->plusy*(where->len-1)) && pt.y == where->top.y+( where->plusy*(where->len-1))); else return (pt.x == where->top.x && pt.y == where->top.y); } static void update_ud(FRM *the_frm, enum scr_type scr, int u, int d, const chtype *ud_ch) { struct scroller *scroll; scroll = &the_frm->scroll[scr]; if (scroll->len != 0) { WINDOW *window; struct pt xy; window = panel_window(the_frm->panel); xy = scroll->top; wmove(window, xy.y, xy.x); waddch(window, (winch(window) & ~A_CHARTEXT) | (u ? ud_ch[0] : ' ')); if (scroll->plusy) xy.y += scroll->len-1; else xy.x += scroll->len-1; wmove(window, xy.y, xy.x); waddch(window, (winch(window) & ~A_CHARTEXT) | (d ? ud_ch[1] : ' ')); } } static void update_scroll(FRM *the_frm, enum scr_type scr, int ud, int u, int d) { if (u || d) { WINDOW *window; window = panel_window(the_frm->panel); if ((mvwinch(window, 0, 0) & A_CHARTEXT) != ' ') { chtype ud_ch[2]; if (ud) { ud_ch[0] = ACS_UARROW; ud_ch[1] = ACS_DARROW; } else { ud_ch[0] = ACS_LARROW; ud_ch[1] = ACS_RARROW; } update_ud(the_frm, scr, u, d, ud_ch); } } } static void update_form_scroll_page(FORM *form) { int page; page = form_page(form); /*CLN FIX OPAQUE:maxpage*/ update_scroll(form_userptr(form), scr_page, 1, page != 0, page != form->maxpage-1); } static void update_menu_scroll_page(MENU *menu) { int row; row = top_row(menu); /*CLN FIX OPAQUE:rows,arows*/ update_scroll(menu_userptr(menu), scr_page, 1, row != 0, row != menu->rows-menu->arows); } static void update_form_scroll_field(FORM *form) { int rows; int nrow; if (field_info(current_field(form), &rows, NULL, NULL, NULL, &nrow, NULL) == E_OK) update_scroll(form_userptr(form), scr_field, (rows+nrow) != 1, data_behind(form), data_ahead(form)); } static void border_title(all my_all, int active) { FRM *the_frm; the_frm = my_all->current_frm; if (the_frm) { WINDOW *window; window = panel_window(the_frm->panel); if (window) { { struct pt maxyx; int cp_border; maxyx.y = getmaxy(window); maxyx.x = getmaxx(window); cp_border = COLOR_PAIR(active ? c_active_border : c_inactive_border); wattrset(window, cp_border); box(window, 0, 0); wattron(window, cp_border); mvwaddch(window, 0, the_frm->title_x-1, ACS_RTEE); mvwaddch(window, 0, maxyx.x-1-(the_frm->title_x-1), ACS_LTEE); { enum scr_type scr; wattron(window, A_REVERSE); for (scr = scr_page; scr < scr_MAX; scr++) if (the_frm->scroll[scr].len != 0) { int i; struct pt xy; xy = the_frm->scroll[scr].top; wmove(window, xy.y, xy.x); for (i = 0; i < the_frm->scroll[scr].len; i++) { waddch(window, ' '); if (the_frm->scroll[scr].plusy) wmove(window, ++xy.y, xy.x); } } } switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: update_form_scroll_page(the_frm->u.f.form); break; case FRMt_menu: update_menu_scroll_page(the_frm->u.m.menu); break; } } { int cp_title; cp_title = COLOR_PAIR(active ? c_active_title : c_inactive_title); wattron(window, cp_title); wmove(window, 0, the_frm->title_x); waddstr(window, the_frm->num); waddch(window, ' '); waddstr(window, the_frm->title); waddch(window, ' '); if (getcurx(window) < getmaxx(window)-the_frm->title_x) waddch(window, ' '); } } } } static void display_slks_x(all my_all, int keyIx, int chg_keys) { FRM *the_frm; vary_dict top_desc; fmli_string nam; int toIx; the_frm = my_all->current_frm; if (chg_keys) top_desc = find_button(my_all, my_all->def[WWW_chg_keys_slk].locals, keyIx+1); else { top_desc = find_button(my_all, the_frm->descs->locals, keyIx+1); if (!top_desc) if (!(keyIx == (8-1) || keyIx == (16-1))) top_desc = find_button(my_all, my_all->def[uuu(the_frm)].locals, keyIx+1); } toIx = keyIx; if (the_frm->altslks) toIx -= 8; if (toIx >= 0 && (toIx < my_all->num_slks)) { if (top_desc) { nam = get_string(my_all, top_desc, "name"); if (!nam || !nam[0]) top_desc = NULL; } else nam = NULL; slk_set(toIx+1, nam, 1); if (nam) free(nam); } if (top_desc) the_frm->slkEnabled |= ENABLE_F(keyIx+1); the_frm->slk_dict[keyIx] = top_desc; } static void clear_slks(all my_all) { FRM *the_frm; the_frm = my_all->current_frm; if (the_frm) { int keyIx; for (keyIx = 0; (keyIx < SLK_MAX) && the_frm->slkEnabled; keyIx++) { unsigned int slkMask; slkMask = ENABLE_F(keyIx+1); if (the_frm->slkEnabled & slkMask) { int toIx; toIx = keyIx; if (the_frm->altslks) toIx -= 8; if (toIx >= 0 && (toIx < my_all->num_slks)) slk_set(toIx+1, NULL, 1); the_frm->slkEnabled &= ~slkMask; } } slk_noutrefresh(); doupdate(); } } static void display_slks(all my_all, int toggle_altslks) { FRM *the_frm; the_frm = my_all->current_frm; if (the_frm) { int keyIx; if (toggle_altslks) the_frm->altslks = !the_frm->altslks; else the_frm->altslks = get_boolean(my_all, the_frm->descs->globals, "altslks", 0); the_frm->slkEnabled = 0; for (keyIx = 0; keyIx < SLK_MAX; keyIx++) display_slks_x(my_all, keyIx, 0); if (the_frm->slkEnabled & (ENABLE_F(9) | ENABLE_F(10) | ENABLE_F(11) | ENABLE_F(12) | ENABLE_F(13) | ENABLE_F(14) | ENABLE_F(15) | ENABLE_F(16))) { if (!(the_frm->slkEnabled & ENABLE_F(8))) display_slks_x(my_all, 8-1, 1); if (!(the_frm->slkEnabled & ENABLE_F(16))) display_slks_x(my_all, 16-1, 1); } slk_noutrefresh(); doupdate(); } } static void start_goto_frm(all my_all, FRM *the_frm) { clear_slks(my_all); border_title(my_all, 0); my_all->current_frm = the_frm; msg_stack_sync(my_all); } static void finish_goto_frm(all my_all) { FRM *the_frm; the_frm = my_all->current_frm; if (the_frm) { msg_stack_sync(my_all); border_title(my_all, 1); restore_cursor(my_all); if (the_frm->descs) display_slks(my_all, 0); if (the_frm->panel) top_panel(the_frm->panel); } } static void goto_frm(all my_all, FRM *the_frm) { if (my_all->current_frm != the_frm) { start_goto_frm(my_all, the_frm); finish_goto_frm(my_all); } } static int close_frm(all my_all, FRM *the_frm, int cancel, int force); static void navigate_away(all my_all) { FRM *the_frm; the_frm = my_all->current_frm; if (the_frm) if (!(the_frm->flags & MASK(fm_immortal))) if (get_lifetime(my_all, the_frm->descs->globals, "lifetime", l_longterm) == l_shortterm) close_frm(my_all, the_frm, 0, 0); } static void navigate_to(all my_all, FRM *the_frm) { if (the_frm) { navigate_away(my_all); goto_frm(my_all, the_frm); } } static unsigned int alloc_frm_num(all my_all) { ++my_all->frm_cnt; return ++my_all->frm_num; } static void free_frm_num(all my_all, unsigned int frm_num) { if (frm_num == my_all->frm_num) --my_all->frm_num; if (my_all->frm_num != --my_all->frm_cnt) { FRM *the_frm; unsigned int frm_num_max; frm_num_max = 0; if ((the_frm = FRM_FIRST(my_all))) do { if (the_frm->frm_num == my_all->frm_num) return; if (the_frm->frm_num > frm_num_max) frm_num_max = the_frm->frm_num; } while (!FRM_PAST((the_frm = NEXT_FRM(the_frm)), my_all)); my_all->frm_num = frm_num_max; } } static void my_free_item(ITEM *Item) { const char *p; p = item_name(Item); if (p) free((char *)p); p = item_description(Item); if (p) free((char *)p); free_item(Item); } static size_t count_elements(vary_dicts items, size_t *n) { size_t i; size_t j; i = CCOUNT(items); if (n) *n = i; for (j = i; j; j--) if (value_vary_dict(AAT(items, j-1), "button")) i--; return i; } static WINDOW * setup_ui(all my_all, FRM *the_frm, int rows, int cols) { size_t num_len; int begrow, begcol; int title_space; WINDOW *window; WINDOW *subwindow; if (the_frm->frm_num == 0) { if (sizeof(the_frm->num) >= 1) the_frm->num[0] = '\0'; num_len = 0; } else num_len = snprintf(the_frm->num, sizeof(the_frm->num), "%u", the_frm->frm_num); the_frm->title = get_string(my_all, the_frm->descs->globals, fmt_title[the_frm->frm_type]); if (!the_frm->title) the_frm->title = strdup(fmt_spelling[the_frm->frm_type]); title_space = strlen(the_frm->title); if (title_space > (my_all->displayhw.x-6)) { title_space = (my_all->displayhw.x-6); the_frm->title[title_space] = '\0'; } title_space += num_len+4; if ((cols-title_space) < 0) cols = title_space; else if ((cols-title_space) & 1) title_space += 1; cols += 2; rows += 2; the_frm->title_x = (cols-title_space)/2+1; begrow = get_position(my_all, the_frm->descs->globals, "begrow", p_any); begcol = get_position(my_all, the_frm->descs->globals, "begcol", p_any); if (begrow == p_center) { if (!(begcol == p_center || position_is_valid_integer(begcol, my_all->displayhw.x))) begcol = p_center; } else if (begcol == p_center) { if (!(begrow == p_center || position_is_valid_integer(begrow, my_all->displayhw.y))) begrow = p_center; } else if (!position_is_valid_integer(begrow, my_all->displayhw.y)) { begrow = p_any; begcol = p_any; } else if (!(begcol == p_any || begcol == p_current || begcol == p_distinct || position_is_valid_integer(begcol, my_all->displayhw.x))) begcol = p_any; /* Workout the position */ switch (begrow) { case p_any: begrow = (my_all->displayhw.y-rows)/2;/*CLN FIX*/ break; case p_center: begrow = (my_all->displayhw.y-rows)/2; break; case p_current: begrow = getbegy(panel_window(my_all->current_frm->panel)); begrow--; break; case p_distinct: begrow = (my_all->displayhw.y-rows)/2;/*CLN FIX*/ break; default: break; } switch (begcol) { case p_any: begcol = (my_all->displayhw.x-cols)/2;/*CLN FIX*/ break; case p_center: begcol = (my_all->displayhw.x-cols)/2; break; case p_current: begcol = getbegx(panel_window(my_all->current_frm->panel)); break; case p_distinct: begcol = (my_all->displayhw.x-cols)/2;/*CLN FIX*/ break; default: break; } window = newwin_input(rows, cols, begrow, begcol); if (!window) { message_dup(my_all, "error return from newwin_input", 0); exit(EXIT_FAILURE); } the_frm->panel = new_panel(window); { struct scroller *scroll; scroll = &the_frm->scroll[scr_page]; scroll->len = 3; /* 3 is min height of a frame */ scroll->plusy = 1; scroll->top.y = (getmaxy(window)-scroll->len)/2; scroll->top.x = getmaxx(window)-1; } switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: { struct scroller *scroll; scroll = &the_frm->scroll[scr_field]; scroll->len = 2; scroll->plusy = 0; scroll->top.y = getmaxy(window)-1; scroll->top.x = getmaxx(window)-1-scroll->len; } break; case FRMt_menu: break; } set_panel_userptr(the_frm->panel, the_frm); subwindow = derwin(window, rows-2, cols-2, 1, 1); return subwindow; } static char * get_text_acs(all my_all, vary_dict desc, const char *key) { fmli_string_acs val; val = get_string_acs(my_all, desc, key); if (val && !val[0]) { free(val); val = NULL; } return val; } static int rowsof(const char *s, int columns) { int cntnl; /*CLN FIX*/ if (!s || !s[0]) cntnl = 0; else { cntnl = 1; while (*s) { if (*s == '\n') cntnl++; s++; } } return cntnl; } static void fillfield(FIELD *Field, int rows, int columns, const char *s, int wrap) { char *f; int r, c; c = 0; r = 0; f = field_buffer(Field, 0); /* _alt */ /*CLN FIX*/ while (*s) { char ch; ch = *s; if (ch == '\\') { ch = *(++s); switch (ch) { case 'b': ch = '\b'; break; case 'n': ch = '\n'; break; case 't': ch = '\t'; break; case 'r': ch = '\r'; break; default: break; } } switch (ch) { case '\n': { int n; n = columns-c; if (n) { memset(f, ' ', n); f += n; } } if (r == rows) goto done; r++; c = 0; break; case '\b': if (c != 0) --c; break; case '\t': { int n; n = 8-(c & 7); if (n) { memset(f, ' ', n); f += n; } } break; default: *(f++) = ch; c++; break; } /*CLN FIX*/ #if 0 if (c > columns) { if (r == rows) { } } #else if (c > columns) { c = 1; r++; } if (r >= rows) { if (c) --f; goto done; } #endif s++; } done: *(f++) = '\0'; } static void def_descs(FRM *the_frm, void *param) { the_frm->descs = param; } static void file_descs(FRM *the_frm, void *param) { the_frm->descs = read_descs(the_frm->my_all, the_frm->frm_type, the_frm->argv[0], &the_frm->mtime); } static void frm_mgmt_FrameManagement_descs(FRM *the_frm, void *param) { the_frm->descs = new_desc(); add_descriptors(the_frm->descs, &frm_mgmt_FrameManagement_defs, 1); } static void frm_mgmt_list_descs(FRM *the_frm, void *param) { all my_all; vary_dict desc; FRM *a_frm; my_all = the_frm->my_all; the_frm->descs = new_desc(); add_descriptors(the_frm->descs, &frm_mgmt_OpenFrames_defs, 1); desc = NULL; if ((a_frm = FRM_FIRST(my_all))) do { if (!(a_frm->flags & MASK(fm_closing)) && a_frm->title && a_frm->frm_num) { add_descriptor_dup(the_frm->descs, "name", a_frm->title, 1, &desc); add_descriptor_dup(the_frm->descs, "lininfo", a_frm->num, 1, &desc); } } while (!FRM_PAST((a_frm = NEXT_FRM(a_frm)), my_all)); } static void cmd_help_descs(FRM *the_frm, void *param) { struct KV *kv; vary_dict desc; kv = param; the_frm->descs = new_desc(); add_descriptors(the_frm->descs, &help_list_defs, 1); desc = NULL; add_descriptor_dup(the_frm->descs, "text", kv->value, 1, &desc); } struct arg { int argc; char **argv; }; static void menu_choices_value_descs(FRM *the_frm, void *param) { vary_dict desc; struct arg *args; int i; args = param; the_frm->descs = new_desc(); add_descriptors(the_frm->descs, &choices_list_defs, 1); desc = NULL; for (i = 0; i < args->argc-2; i++) add_descriptor_dup(the_frm->descs, "name", args->argv[i+1], 1, &desc); } static int comp_menu_name(const void *a, const void *b) { return strcmp(item_name(*(const ITEM **)a), item_name(*(const ITEM **)b)); } static void hook_form_init(FORM *form) { update_form_scroll_page(form); } static void hook_field_init(FORM *form) { FRM *the_frm; all my_all; vary_dict desc; the_frm = form_userptr(form); my_all = the_frm->my_all; desc = field_userptr(current_field(form)); message_dyn(my_all, get_string(my_all, desc, "fieldmsg"), 0); update_form_scroll_field(form); } static void hook_item_init(MENU *menu) { FRM *the_frm; all my_all; vary_dict desc; the_frm = menu_userptr(menu); my_all = the_frm->my_all; desc = item_userptr(current_item(menu)); message_dyn(my_all, get_string(my_all, desc, "itemmsg"), 0); update_menu_scroll_page(menu); } struct dfrt { int page; int index; }; static int comp_els(const void *a, const void *b) { int diff; diff = ((struct dfrt *)a)->page - ((struct dfrt *)b)->page; return diff ? diff : ((struct dfrt *)a)->index - ((struct dfrt *)b)->index; } static FRM * open_frm_descs(all my_all, FRM *the_frm, void (*get_descs)(FRM *the_frm, void *param), void *param) { const char *res; if (!(the_frm->flags & MASK(fm_choices))) navigate_away(my_all);/*CLN FIX*//*This is too early??*/ start_goto_frm(my_all, the_frm); if (get_descs) { #if 0 if (get_descs != file_descs) /* If non-user frm *//*?????*/ my_all->current_frm = the_frm; #endif (*get_descs)(the_frm, param); } if (!the_frm->descs) { res = ""; goto close_it; } else res = NULL; if (DEBUGSTDDBG && stddbg) dump_descriptors(the_frm->descs, the_frm->name); if (get_boolean(my_all, the_frm->descs->globals, "init", 1)) { the_frm->msg_frame.msg = get_string(my_all, the_frm->descs->globals, "framemsg"); if (the_frm->msg_frame.msg) the_frm->msg_frame.acs = is_acs(the_frm->msg_frame.msg, 0); switch (the_frm->frm_type) { case FRMt_form: { fmli_boolean autolayout; autolayout = get_boolean(my_all, the_frm->descs->globals, "autolayout", 0); the_frm->u.f.fmode = REQ_INS_MODE; { struct dfrt *els; int field_cnt; size_t i; size_t j; FIELD **Field; int cur_page; i = count_elements(the_frm->descs->locals, &j); { int inorder; els = malloc(sizeof(*els)*i); inorder = 1; cur_page = 0; field_cnt = 0; for (i = 0; i < j; i++) { vary_dict desc = AAT(the_frm->descs->locals, i); if (!value_vary_dict(desc, "button") && get_boolean(my_all, desc, "show", 1)) { fmli_integer page; page = get_integer(my_all, desc, "page", 1); if (page > 0) { els[field_cnt].page = page; els[field_cnt].index = i; if (inorder) { if (page == cur_page) ; else if (page > cur_page) cur_page = page; else inorder = 0; } field_cnt++; } } if (!inorder) qsort(els, field_cnt, sizeof(els[0]), comp_els); } } Field = malloc(sizeof(*Field)*(field_cnt*2+1)); the_frm->u.f.fields = Field; cur_page = 0; for (i = 0; i < field_cnt; i++) { vary_dict desc = AAT(the_frm->descs->locals, els[i].index); fmli_string nam; nam = get_string_acs(my_all, desc, "name"); if (!nam) message_va(my_all, "What! no name for item %d", els[i].index+1); else { int frow, fcol; int frows, fcolumns; int deffrows, deffcolumns; int nrow, ncol; int nrows, ncolumns; int acs; if (0) { /*TODO*/ get_string(my_all, desc, "invalidmsg"); get_string(my_all, desc, "invalidOnDoneMsg"); get_boolean(my_all, desc, "menuonly", 0); get_boolean(my_all, desc, "valid", 1); get_boolean(my_all, desc, "validOnDone", 1); } nrow = get_integer(my_all, desc, "nrow", 0); if (nrow >= 5) nrow -= 2; ncol = get_integer(my_all, desc, "ncol", 0); /* name can be _alt */ /*CLN FIX*/ acs = is_acs(nam, 0); if (acs) { /*CLN FIX*/ nrows = 1; ncolumns = strlen(nam); } else { nrows = 1; ncolumns = strlen(nam); } #if 0 if (acs) { wmove(form_sub(the_frm->u.f.form), nrow, ncol); waddnstr_acs(form_sub(the_frm->u.f.form), nam, -1); } #if 1 *Field = new_field(1, 1, 0, 0, 0, 0); if (*Field) { if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "cur_page:%i %i %i <%s>\n", i, cur_page, els[i].page, nam); fflush(stddbg); } set_new_page(*Field, els[i].page != cur_page); cur_page = els[i].page; } #endif #else *Field = new_field(nrows, ncolumns, nrow, ncol, 0, 0); if (*Field) { if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "cur_page:%i %i %i <%s>\n", i, cur_page, els[i].page, nam); fflush(stddbg); } set_new_page(*Field, els[i].page != cur_page); cur_page = els[i].page; set_field_buffer(*Field, 0, nam); field_opts_off(*Field, O_ACTIVE); if (get_boolean(my_all, desc, "scroll", 0)) field_opts_off(*Field, O_STATIC); set_field_fore(*Field, COLOR_PAIR(c_window)); set_field_userptr(*Field, (void *)desc); } #endif free(nam); nam = NULL; Field++; deffrows = 1; if (0) deffcolumns = !autolayout ? -1 : (i == 0) ? 4 : 90; else deffcolumns = 0; frows = get_integer(my_all, desc, "rows", deffrows); fcolumns = get_integer(my_all, desc, "columns", deffcolumns); frow = get_integer(my_all, desc, "frow", 0); if (frow >= 5) frow -= 2; fcol = get_integer(my_all, desc, "fcol", 0); *Field = new_field(frows, fcolumns, frow, fcol, 0, 0); if (*Field) { char *val; set_new_page(*Field, 0); val = get_string(my_all, desc, "value"); if (val) { if (strlen(val) > (fcolumns*frows)) val[fcolumns*frows] = '\0'; #if 1 strcpy(field_buffer(*Field, 0), val); #else set_field_buffer(*Field, 0, val); #endif free(val); } if (!get_boolean(my_all, desc, "wrap", 0)) field_opts_off(*Field, O_WRAP); if (!get_boolean(my_all, desc, "autoadvance", 0)) field_opts_off(*Field, O_AUTOSKIP); if (get_boolean(my_all, desc, "noecho", 0)) field_opts_off(*Field, O_PUBLIC); #if 0 /* allow to enter A-Z, a-z and 0-9 */ set_field_type(*Field, TYPE_REGEXP, "^[ *a-zA-Z0-9]+ *$"); #endif set_field_back(*Field, COLOR_PAIR(c_window) | A_STANDOUT); set_field_userptr(*Field, (void *)desc); } Field++; } } *Field = NULL; free(els); } finalise_form: if (the_frm->u.f.fields) { int rows, cols; WINDOW *subwindow; the_frm->u.f.form = new_form(the_frm->u.f.fields); set_form_userptr(the_frm->u.f.form, the_frm); if (the_frm->frm_type == FRMt_form) { set_form_init(the_frm->u.f.form, hook_form_init); set_field_init(the_frm->u.f.form, hook_field_init); } scale_form(the_frm->u.f.form, &rows, &cols); subwindow = setup_ui(my_all, the_frm, rows, cols); set_form_win(the_frm->u.f.form, panel_window(the_frm->panel)); set_form_sub(the_frm->u.f.form, subwindow); if (post_form(the_frm->u.f.form) != E_OK) { res = "error return from post_form"; goto close_it; } else { the_frm->posted = 1; the_frm->u.f.fmode ^= REQ_INS_MODE ^ REQ_OVL_MODE; form_driver(the_frm->u.f.form, the_frm->u.f.fmode); } } } break; case FRMt_text: { int trows, tcolumns; int nrow; int r1; size_t i; FIELD **Field; vary_dict desc; char *header; char *text; desc = the_frm->descs->globals; the_frm->u.f.fmode = REQ_INS_MODE; nrow = 0; r1 = 0; i = 0; header = get_text_acs(my_all, desc, "header"); if (header) i++; text = get_text_acs(my_all, desc, "text"); if (text) i++; Field = malloc(sizeof(*Field)*(i+1)); the_frm->u.f.fields = Field; trows = get_integer(my_all, desc, "rows", 10); tcolumns = get_integer(my_all, desc, "columns", 30); if (header) { r1 = rowsof(header, tcolumns);/*strlen_acs*/ if (r1 > (trows-2)) r1 = trows-2; *Field = new_field(r1, tcolumns, nrow, 0, 0, 0); if (*Field) { fillfield(*Field, r1, tcolumns, header, 0); field_opts_off(*Field, O_ACTIVE); if (0) set_field_back(*Field, COLOR_PAIR(c_window)); set_field_userptr(*Field, (void *)desc); } free(header); Field++; nrow += 1; } if (text) { int r2; int offscreen; r2 = rowsof(text, tcolumns); offscreen = r2-(trows-r1); if (offscreen < 0) offscreen = 0; *Field = new_field(r2, tcolumns, nrow, 0, offscreen, 0); if (*Field) { fmli_boolean wrap; wrap = get_boolean(my_all, desc, "wrap", 1); fillfield(*Field, r2, tcolumns, text, wrap); if (!get_boolean(my_all, desc, "edit", 0)) field_opts_off(*Field, O_EDIT); else field_opts_off(*Field, O_STATIC | O_BLANK); if (!wrap) field_opts_off(*Field, O_WRAP); if (get_boolean(my_all, desc, "inactive", 0)) field_opts_off(*Field, O_ACTIVE); set_field_userptr(*Field, (void *)desc); } free(text); Field++; } *Field = NULL; } goto finalise_form; break; case FRMt_menu: { int has_description; fmli_boolean multiselect; int item_cnt; int max_nam_width; has_description = 0; max_nam_width = 0; { size_t i; size_t j; ITEM **items; multiselect = get_boolean(my_all, the_frm->descs->globals, "multiselect", 0); item_cnt = count_elements(the_frm->descs->locals, &j); items = malloc(sizeof(*items)*(item_cnt+1)); the_frm->u.m.items = items; item_cnt = 0; for (i = 0; i < j; i++) { vary_dict desc = AAT(the_frm->descs->locals, i); if (!value_vary_dict(desc, "button")) { if (get_boolean(my_all, desc, "show", 1)) { int item_ok; char *nam; nam = get_string(my_all, desc, "name"); if (!nam) message_va(my_all, "What! no name for item %d", i+1); else { if (my_all->current_frm->descs == &my_all->def[DEF_cmd]) { ITEM **myitems; for (myitems = items; myitems != the_frm->u.m.items; ) { myitems--; if (!strcmp(item_name(*myitems), nam)) { size_t l; my_free_item(*myitems); items--; item_cnt--; l = items-myitems; if (l) memmove(myitems, myitems+1, l*sizeof(myitems)); break; } } item_ok = !is_action_nop(desc); } else item_ok = 1; if (item_ok) { fmli_string descr; descr = get_string(my_all, desc, "description"); *items = new_item(nam, descr); if (*items) { if (get_boolean(my_all, desc, "inactive", 0)) item_opts_off(*items, O_SELECTABLE); if (multiselect && get_boolean(my_all, desc, "selected", 0)) set_item_value(*items, 1); set_item_userptr(*items, (void *)desc); if (descr && descr[0]) has_description = 1; if (strlen(nam) > max_nam_width) max_nam_width = strlen(nam); items++; item_cnt++; } } else free(nam); } } } } *items = NULL; } if (the_frm->u.m.items && the_frm->u.m.items[0]) { vary_dict desc; int rows, cols; WINDOW *subwindow; desc = the_frm->descs->globals; if (get_boolean(my_all, desc, "autosort", 0)) qsort(the_frm->u.m.items, item_cnt, sizeof(the_frm->u.m.items[0]), comp_menu_name); the_frm->u.m.menu = new_menu(the_frm->u.m.items); set_menu_userptr(the_frm->u.m.menu, the_frm); set_item_init(the_frm->u.m.menu, hook_item_init); set_menu_mark(the_frm->u.m.menu, ">"); if (multiselect) { #if 0 set_menu_marker(the_frm->u.m.menu, "*"); #endif menu_opts_off(the_frm->u.m.menu, O_ONEVALUE); } menu_opts_off(the_frm->u.m.menu, O_NONCYCLIC | O_ROWMAJOR); set_menu_fore(the_frm->u.m.menu, COLOR_PAIR(c_highlight_bar)); set_menu_back(the_frm->u.m.menu, COLOR_PAIR(c_window)); if (has_description) { set_menu_pad(the_frm->u.m.menu, '-'); rows = get_integer(my_all, desc, "rows", 10); cols = get_integer(my_all, desc, "columns", 0); cols = 1; if (item_cnt < rows) rows = item_cnt; if (my_all->displayhw.y-2 < rows) rows = my_all->displayhw.y-2; } else if (!value_vary_dict(desc, "columns")) { int fC; fC = (my_all->displayhw.x-2) / (max_nam_width+1); if (!value_vary_dict(desc, "rows")) { /* Find cols=min(fC, ceil(sqrt(3*item_cnt/(max_nam_width+1)))) */ for (cols = 1; (cols < fC) && (cols*cols*(max_nam_width+1) < 3*item_cnt); cols++) ; rows = (item_cnt+cols-1)/cols; /*CLN FIX*/ } else { int pC; rows = get_integer(my_all, desc, "rows", 10);/*10?*/ if (item_cnt < rows) rows = item_cnt; if (my_all->displayhw.y-2 < rows) rows = my_all->displayhw.y-2; pC = ((item_cnt-1) % rows)+1; cols = (pC > fC) ? 1 : pC; } } else { rows = get_integer(my_all, desc, "rows", 10); cols = get_integer(my_all, desc, "columns", 0); /*CLN FIX*/ } if (rows > 0 || cols > 0) set_menu_format(the_frm->u.m.menu, rows, cols); scale_menu(the_frm->u.m.menu, &rows, &cols); subwindow = setup_ui(my_all, the_frm, rows, cols); set_menu_win(the_frm->u.m.menu, panel_window(the_frm->panel)); set_menu_sub(the_frm->u.m.menu, subwindow); if (post_menu(the_frm->u.m.menu) != E_OK) { res = "error return from post_menu"; goto close_it; } else the_frm->posted = 1; } else { res = "no active items in menu"; goto close_it; } } break; } finish_goto_frm(my_all); update_panels(); doupdate(); } else { res = ""; close_it: if (res && res[0]) message_dup(my_all, res, 0); close_frm(my_all, the_frm, 1, 1); the_frm = NULL; } return the_frm; } static void del_win(WINDOW **window) { if (*window) { delwin(*window); *window = NULL; } } static void del_winpanel(PANEL *panel) { if (panel) { WINDOW *window; window = panel_window(panel); del_panel(panel); del_win(&window); update_panels(); doupdate(); } } static void teardown_ui(FRM *the_frm, WINDOW *subwindow) { if (subwindow) delwin(subwindow); del_winpanel(the_frm->panel); the_frm->panel = NULL; #if 0 if (curscr/*stdscr*/) { wstandend(curscr/*stdscr*/); #endif update_panels(); doupdate(); #if 0 } #endif } static void close_frm_descs(all my_all, FRM *the_frm) { if (the_frm->msg_frame.msg) free(the_frm->msg_frame.msg); switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: if (the_frm->posted) { unpost_form(the_frm->u.f.form); the_frm->posted = 0; } if (the_frm->u.f.form) { teardown_ui(the_frm, form_sub(the_frm->u.f.form)); free_form(the_frm->u.f.form); the_frm->u.f.form = NULL; } if (the_frm->u.f.fields) { int i; for (i = 0; the_frm->u.f.fields[i]; i++) free_field(the_frm->u.f.fields[i]); free(the_frm->u.f.fields); the_frm->u.f.fields = NULL; } break; case FRMt_menu: if (the_frm->posted) { unpost_menu(the_frm->u.m.menu); the_frm->posted = 0; } if (the_frm->u.m.menu) { teardown_ui(the_frm, menu_sub(the_frm->u.m.menu)); free_menu(the_frm->u.m.menu); the_frm->u.m.menu = NULL; } if (the_frm->u.m.items) { ITEM *item; int i; for (i = 0; (item = the_frm->u.m.items[i]); i++) my_free_item(item); free(the_frm->u.m.items); the_frm->u.m.items = NULL; } break; } if (!(the_frm->flags & MASK(fm_static_descs)) && the_frm->descs) { free_descs(the_frm->descs); free(the_frm->descs); } } static FRM * alloc_frm(all my_all, enum frm_type frm_type, int frm_type_sub, int argc, char **argv, void (*get_descs)(FRM *the_frm, void *param), void *param, int flags) { FRM *the_frm; if (DEBUGSTDDBG && stddbg) dump_argv("alloc_frm:\n", argc, argv); the_frm = calloc(1, sizeof(*the_frm)); insertafternode(&THELIST(my_all), &LNK(the_frm), &LNK(my_all->current_frm)); if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "insertafternode:%p\n", (void *)the_frm); fflush(stddbg); } the_frm->my_all = my_all; if (!(flags & (MASK(fm_choices) | MASK(fm_cmd_menu)))) the_frm->frm_num = alloc_frm_num(my_all); the_frm->name = (!argv || !argv[0]) ? NULL : strdup(argv[0]); the_frm->argc = dup_argv(argc, argv, &the_frm->argv); the_frm->frm_type = frm_type; switch (the_frm->frm_type) { case FRMt_form: the_frm->frm_type_sub.f = frm_type_sub; break; case FRMt_text: the_frm->frm_type_sub.t = frm_type_sub; break; case FRMt_menu: the_frm->frm_type_sub.m = frm_type_sub; break; } the_frm->flags = flags; return open_frm_descs(my_all, the_frm, get_descs, param); } static void free_frm(all my_all, FRM *the_frm) { int im_current; im_current = the_frm == my_all->current_frm; if (im_current) start_goto_frm(my_all, (PREV_FRM(the_frm) == the_frm) ? NULL : PREV_FRM(the_frm)); close_frm_descs(my_all, the_frm); removenode(&THELIST(my_all), &LNK(the_frm)); if (im_current) finish_goto_frm(my_all); if (the_frm->title) free(the_frm->title); if (the_frm->name) free(the_frm->name); if (my_all->arg_owner_frm == the_frm) if (frm_args(my_all, my_all->arg_owner_frm, 0)) my_all->arg_owner_frm = NULL; if (the_frm->frm_num) free_frm_num(my_all, the_frm->frm_num); free_argv(the_frm->argc, the_frm->argv); the_frm->my_all = NULL; free(the_frm); } static int close_frm(all my_all, FRM *the_frm, int cancel, int force) { if (!(the_frm->flags & MASK(fm_closing))) { if (force || (!(the_frm->flags & MASK(fm_immortal)) && get_lifetime(my_all, the_frm->descs->globals, "lifetime", -1) != l_immortal)) { the_frm->flags |= MASK(fm_closing); if (!cancel) { fmli_string s; s = get_action_done(my_all, the_frm->descs->globals, NULL, false, "done"); if (s) { my_all->src = SRC(the_frm); executecommand(my_all, s); } } if (the_frm->descs) get_null(my_all, the_frm->descs->globals, "close"); free_frm(my_all, the_frm); return 1; } else message_dup(my_all, "Can't close this frame", 0); } return 0; } static unsigned int isfrm_init(const char *a, int *valid) { char *e; unsigned int frm_num; frm_num = strtoul(a, &e, 10); if (valid) *valid = *e == '\0'; return frm_num; } static FRM * frm_from_id(all my_all, const char *s) { FRM *the_frm; unsigned int frm_num; int frm_num_valid; frm_num = isfrm_init(s, &frm_num_valid); if ((the_frm = FRM_FIRST(my_all))) { do { if (the_frm->frm_num) if ((frm_num_valid && the_frm->frm_num == frm_num) || (the_frm->name && !strcmp(s, the_frm->name))) return the_frm; } while (!FRM_PAST((the_frm = NEXT_FRM(the_frm)), my_all)); the_frm = NULL; } message_dup(my_all, "Unable to find a frame with that name", 0); return the_frm; } static void cancel_close_frm(all my_all, int argc, char **argv, int cancel, int force) { if (argc < 2) { int flags; int res; flags = my_all->current_frm->flags; res = close_frm(my_all, my_all->current_frm, cancel, force); if (res && !cancel && !force && (flags & MASK(fm_choices))) { char *s; s = local_getenv(my_all, "Form_Choice"); if (s) { if (s[0]) { FRM *the_frm; the_frm = my_all->current_frm; if (flags & MASK(fm_choices_action)) { my_all->src = SRC(the_frm); executecommand(my_all, strdup(s)); } else ; } local_setenv_string(my_all, "Form_Choice", NULL); } } } else { int c; for (c = 1; c < argc && argv[c]; c++) { FRM *the_frm; the_frm = frm_from_id(my_all, argv[c]); if (the_frm) close_frm(my_all, the_frm, cancel, force); } } } void fgfgfg_kv(fgfg_param p1, char *key, char *value) { add_descriptor(p1->descs, key, value, p1->lower, &p1->desc_c); } void fgfgfg_msg(fgfg_param p1, const char *p3) { message_dup(p1->my_all, p3, 0); } char * fgfgfg_eval(fgfg_param p1, const char *p3) { return eval(p1->my_all, p3); } static long mtimecmp(const char *fname, struct timespec *mtime) { struct stat sb; if (stat(fname, &sb) == 0) { struct timespec sb_mtime; sb_mtime.tv_sec = sb.st_mtime; sb_mtime.tv_nsec = sb.st_atim.tv_nsec; if ((sb_mtime.tv_sec-mtime->tv_sec) == 0) return sb_mtime.tv_sec-mtime->tv_sec; else return sb_mtime.tv_nsec-mtime->tv_nsec; } else return 1; } static int do_update(all my_all, FRM *the_frm, int mkcurr) { int res; int changed; res = 0; if (!the_frm->name) goto reset; changed = 0; switch (the_frm->frm_type) { case FRMt_text: if (!get_boolean(my_all, the_frm->descs->globals, "edit", 0)) break; case FRMt_form: { FIELD **pfield; /*res = form_driver(the_frm->u.f.form, REQ_VALIDATION);*/ for (pfield = the_frm->u.f.fields; *pfield; pfield++) { if ((field_opts(*pfield) & O_ACTIVE) && field_status(*pfield)) { changed = 1; break; } } } break; case FRMt_menu: break; } if (changed || mtimecmp(the_frm->name, &the_frm->mtime) != 0) { if (0) { close_frm_descs(my_all, the_frm); open_frm_descs(my_all, the_frm, file_descs, NULL); res = 1; } } else { reset: switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: form_driver(the_frm->u.f.form, REQ_FIRST_FIELD); break; case FRMt_menu: menu_driver(the_frm->u.m.menu, REQ_FIRST_ITEM); break; } } if (mkcurr) goto_frm(my_all, the_frm); return res; } static FRM * open_frm(all my_all, int argc, char **argv, int flags) { FRM *the_frm; the_frm = NULL; if (argc < 2) message_dup(my_all, "Can't find frame", 0); else { int argv_offset; int found_type; enum frm_type frm_type; argv_offset = 1; /* over open */ found_type = 0; for (frm_type = FRMt_form; frm_type < FRMt_MAX; frm_type++) if (!strcasecmp(argv[argv_offset], fmt_spelling[frm_type])) { argv_offset++; /* over the cast */ found_type = 1; break; } if (!found_type) { const char *bname; bname = strrchr(argv[argv_offset], '/'); bname = bname ? bname+1 : argv[argv_offset]; for (frm_type = FRMt_form; frm_type < FRMt_MAX; frm_type++) { size_t l; l = strlen(fmt_spelling[frm_type]); if (!strncmp(bname, fmt_spelling[frm_type], l) && bname[l] == '.') { found_type = 1; break; } } if (!found_type) message_va(my_all, "%s not recognized (use naming rules)", argv[argv_offset]); } if (found_type) { if ((the_frm = FRM_FIRST(my_all))) { do { if (the_frm->frm_num && the_frm->name && !strcmp(argv[argv_offset], the_frm->name)) goto out; } while (!FRM_PAST((the_frm = NEXT_FRM(the_frm)), my_all)); the_frm = NULL; out: ; } if (!(the_frm)) the_frm = NULL; else if (the_frm->frm_type == frm_type && the_frm->argc == argc-argv_offset) { int i; for (i = 1; i < the_frm->argc; i++) if (strcmp(the_frm->argv[i], argv[argv_offset+i])) { the_frm = NULL; break; } } else the_frm = NULL; } if (the_frm) navigate_to(my_all, the_frm); else the_frm = alloc_frm(my_all, frm_type, 0, argc-argv_offset, argv+argv_offset, file_descs, NULL, flags & ~MASK(fm_static_descs)); } return the_frm; } static void unix_system(all my_all, const char *cmd) { run_begin(); fflush(NULL); setup_frm_args(my_all); system(cmd); press_enter(); run_end(); } static int checkbang(all my_all, const char *cmd) { int res; res = (my_all->src != cs_cmd_line) || !get_boolean(my_all, my_all->def[DEF_init].globals, "nobang", 0); if (!res) message_va(my_all, "Command ignored: %s is disabled in this application", cmd); return res; } static size_t wget_line(WINDOW *window, const char *prompt, const char *pre, char *buffer, int length) { int code; size_t prompt_len; if (pre) { size_t l; for (l = strlen(pre); l; l--) ungetch(pre[l-1]); } if (prompt) { wprintw(window, prompt); prompt_len = strlen(prompt); } else prompt_len = 0; echo(); code = mvwgetnstr(window, 0, prompt_len, buffer, length); noecho(); wmove(window, 0, 0); wclrtoeol(window); wrefresh(window); doupdate(); return code; } static FRM * which_frm(all my_all) { return (my_all->argc == 3) ? frm_from_id(my_all, my_all->argv[2]) : my_all->current_frm; } #ifdef NCURSES_MOUSE_VERSION static const struct cvgtr { mmask_t m; const char *s; } cder[] = { #define SHOW(m) {m, # m} SHOW(BUTTON1_RELEASED), SHOW(BUTTON1_PRESSED), SHOW(BUTTON1_CLICKED), SHOW(BUTTON1_DOUBLE_CLICKED), SHOW(BUTTON1_TRIPLE_CLICKED), #if NCURSES_MOUSE_VERSION == 1 SHOW(BUTTON1_RESERVED_EVENT), #endif SHOW(BUTTON2_RELEASED), SHOW(BUTTON2_PRESSED), SHOW(BUTTON2_CLICKED), SHOW(BUTTON2_DOUBLE_CLICKED), SHOW(BUTTON2_TRIPLE_CLICKED), #if NCURSES_MOUSE_VERSION == 1 SHOW(BUTTON2_RESERVED_EVENT), #endif SHOW(BUTTON3_RELEASED), SHOW(BUTTON3_PRESSED), SHOW(BUTTON3_CLICKED), SHOW(BUTTON3_DOUBLE_CLICKED), SHOW(BUTTON3_TRIPLE_CLICKED), #if NCURSES_MOUSE_VERSION == 1 SHOW(BUTTON3_RESERVED_EVENT), #endif SHOW(BUTTON4_RELEASED), SHOW(BUTTON4_PRESSED), SHOW(BUTTON4_CLICKED), SHOW(BUTTON4_DOUBLE_CLICKED), SHOW(BUTTON4_TRIPLE_CLICKED), #if NCURSES_MOUSE_VERSION == 1 SHOW(BUTTON4_RESERVED_EVENT), #endif #if NCURSES_MOUSE_VERSION == 2 SHOW(BUTTON5_RELEASED), SHOW(BUTTON5_PRESSED), SHOW(BUTTON5_CLICKED), SHOW(BUTTON5_DOUBLE_CLICKED), SHOW(BUTTON5_TRIPLE_CLICKED), #endif SHOW(BUTTON_CTRL), SHOW(BUTTON_SHIFT), SHOW(BUTTON_ALT), SHOW(ALL_MOUSE_EVENTS), SHOW(REPORT_MOUSE_POSITION), #undef SHOW }; static void show_mouse_nmem(char *buf, mmask_t m) { int comma; int i; comma = 0; for (i = 0; i < SIZEOF(cder); i++) if ((m & cder[i].m) == cder[i].m) { if (!comma) comma = 1; else strcat(buf, ", "); strcat(buf, cder[i].s); } } static void show_mouse(const MEVENT *ep) { if (ep->bstate != REPORT_MOUSE_POSITION) { char buf[80+(5*10)+(32*15)]; sprintf(buf, "id %2d at (%2d, %2d, %2d) state %4lx = {", ep->id, ep->x, ep->y, ep->z, (unsigned long)ep->bstate); show_mouse_nmem(buf, ep->bstate); strcat(buf, "}"); fprintf(stddbg, "%s\n", buf); fflush(stddbg); } } #endif static int wgetkey(WINDOW *window) { int UserInput; UserInput = wgetch(window); if (UserInput == CTRL('F')) { UserInput = wgetch(window); switch (UserInput) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': UserInput = KEY_F(UserInput-'0'); break; case 'b': UserInput = KEY_HOME; break; case 'c': UserInput = KEY_COMMAND; break; case 'd': UserInput = KEY_SF; break; case 'e': UserInput = KEY_LL; break; case 'm': UserInput = KEY_MARK; break; case 'r': UserInput = KEY_RESET; break; case 'u': UserInput = KEY_SR; break; case 'y': UserInput = KEY_EOL; break; } } else switch (UserInput) { case CTRL('A'): UserInput = KEY_IC; break; case CTRL('B'): UserInput = KEY_BEG; break; case CTRL('D'): UserInput = KEY_DOWN; break; case CTRL('E'): UserInput = KEY_END; break; case CTRL('H'): case 0x7F: UserInput = KEY_BACKSPACE; break; case CTRL('J'): UserInput = KEY_COMMAND; break; case CTRL('K'): UserInput = KEY_DL; break; case CTRL('L'): UserInput = KEY_LEFT; break; case CTRL('M'): UserInput = KEY_ENTER; break; case CTRL('N'): UserInput = KEY_NEXT; break; case CTRL('O'): UserInput = KEY_IL; break; case CTRL('P'): UserInput = KEY_PREVIOUS; break; case CTRL('R'): UserInput = KEY_RIGHT; break; case CTRL('T'): UserInput = KEY_BTAB; break; case CTRL('U'): UserInput = KEY_UP; break; case CTRL('V'): UserInput = KEY_PPAGE; break; case CTRL('W'): UserInput = KEY_NPAGE; break; case CTRL('X'): UserInput = KEY_DC; break; case CTRL('Y'): UserInput = KEY_CLEAR; break; default: break; } return UserInput; } static void my_move_panel(FRM *the_frm, int y, int x) { #if defined(FIX_SUB_MOVE) && defined(NCURSES_VERSION) int dy, dx; dy = y - getbegy(panel_window(the_frm->panel)); dx = x - getbegx(panel_window(the_frm->panel)); #endif move_panel(the_frm->panel, y, x); #if defined(FIX_SUB_MOVE) && defined(NCURSES_VERSION) { WINDOW *subwindow; switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: subwindow = form_sub(the_frm->u.f.form); break; case FRMt_menu: subwindow = menu_sub(the_frm->u.m.menu); break; } /*CLN FIX OPAQUE:_begy,_begx*/ subwindow->_begy += dy; subwindow->_begx += dx; } #endif update_panels(); doupdate(); } static int getnewxy(FRM *the_frm, int resizeit, int *y, int *x, int lower_lim_y, int lower_lim_x, int upper_lim_y, int upper_lim_x) { struct pt cur, delta; enum corners which; PANEL *side[corners_MAX]; WINDOW *window; int res; int ch; message_dup(the_frm->my_all, !resizeit ? "Position top-left corner and press Enter" : "Position bottom-right corner and press Enter", 0); cur.y = *y; cur.x = *x; { struct pt start, end; if (resizeit) { start.y = lower_lim_y; start.x = lower_lim_x; end = cur; } else { start = cur; end.y = start.y+(the_frm->my_all->displayhw.y-1-upper_lim_y); end.x = start.x+(the_frm->my_all->displayhw.x-1-upper_lim_x); } for (which = CNR_UL; which < corners_MAX; which++) { enum corners corner; corner = resizeit ? which : (corners_MAX-1) - which; { struct pt rc; rc.y = (corner & (1 << CN_LOWER)) ? end.y : start.y; rc.x = (corner & (1 << CN_RIGHT)) ? end.x : start.x; window = newwin(1, 1, rc.y, rc.x); if (!window) side[corner] = NULL; else { chtype acs; setup_keypad(window); scrollok(window, 0); side[corner] = new_panel(window); switch (corner) { case CNR_UL: acs = ACS_ULCORNER; if (resizeit) acs |= A_REVERSE; break; case CNR_LL: acs = ACS_LLCORNER | A_REVERSE; break; case CNR_UR: acs = ACS_URCORNER | A_REVERSE; break; case CNR_LR: acs = ACS_LRCORNER; if (!resizeit) acs |= A_REVERSE; break; } waddch(window, acs); } } } update_panels(); doupdate(); } delta.y = 0; delta.x = 0; res = 0; while ((ch = wgetkey(panel_window(the_frm->panel))) != KEY_DC) { switch (ch) { #ifdef NCURSES_MOUSE_VERSION case KEY_MOUSE: { MEVENT event; if (getmouse(&event) == OK) { if (DEBUGSTDDBG && stddbg) show_mouse(&event); if (event.bstate & BUTTON1_PRESSED) continue; else if (event.bstate & (BUTTON1_RELEASED | BUTTON1_CLICKED)) if (mouse_trafo(&event.y, &event.x, FALSE) && event.x >= lower_lim_x && event.x <= upper_lim_x && event.y >= lower_lim_y && event.y <= upper_lim_y) { delta.y = event.y-cur.y; delta.x = event.x-cur.x; } } } break; #endif case KEY_ENTER: *y = cur.y; *x = cur.x; res = 1; goto leave; case KEY_BACKSPACE: case KEY_LEFT: if (cur.x > lower_lim_x) delta.x = -1; break; case KEY_RIGHT: if (cur.x < upper_lim_x) delta.x = 1; break; case KEY_UP: if (cur.y > lower_lim_y) delta.y = -1; break; case KEY_DOWN: if (cur.y < upper_lim_y) delta.y = 1; break; case KEY_BTAB: if (((cur.x-1) & ~7) >= lower_lim_x) delta.x = ((cur.x-1) & ~7)-cur.x; break; case CTRL('I'): if (((cur.x+8) & ~7) <= upper_lim_x) delta.x = ((cur.x+8) & ~7)-cur.x; break; } if (delta.y || delta.x) { for (which = CNR_UL; which < corners_MAX; which++) { struct pt start; getbegyx(panel_window(side[which]), start.y, start.x); if (!resizeit || (which & (1 << CN_LOWER))) start.y += delta.y; if (!resizeit || (which & (1 << CN_RIGHT))) start.x += delta.x; move_panel(side[which], start.y, start.x); } update_panels();/*CLN CLN*/ doupdate(); if (delta.y) { cur.y += delta.y; delta.y = 0; } if (delta.x) { cur.x += delta.x; delta.x = 0; } } else beep(); } leave: for (which = CNR_UL; which < corners_MAX; which++) del_winpanel(side[which]); return res; } static void do_frm_mgmt_list(all my_all) { alloc_frm(my_all, FRMt_menu, FRMts_menu_choices, 0, NULL, frm_mgmt_list_descs, NULL, MASK(fm_extended) | MASK(fm_choices) | MASK(fm_choices_action)); } static void do_frm_mgmt_move(all my_all) { FRM *the_frm; the_frm = which_frm(my_all); if (the_frm) { struct pt cur, curhw, new; WINDOW *window; window = panel_window(the_frm->panel); getbegyx(window, cur.y, cur.x); getmaxyx(window, curhw.y, curhw.x); new = cur; if (getnewxy(the_frm, 0, &new.y, &new.x, 0, 0, my_all->displayhw.y-curhw.y, my_all->displayhw.x-curhw.x)) if (cur.y != new.y || cur.x != new.x) my_move_panel(the_frm, new.y, new.x); } } static void do_frm_mgmt_reshape(all my_all) { FRM *the_frm; the_frm = which_frm(my_all); if (the_frm && the_frm->frm_type == FRMt_menu) { struct pt cur, curhw, new; WINDOW *window; window = panel_window(the_frm->panel); getbegyx(window, cur.y, cur.x); getmaxyx(window, curhw.y, curhw.x); new = cur; if (getnewxy(the_frm, 0, &new.y, &new.x, 0, 0, my_all->displayhw.y-curhw.y, my_all->displayhw.x-curhw.x)) { struct pt br; br.y = new.y+curhw.y-1; br.x = new.x+curhw.x-1; if (getnewxy(the_frm, 1, &br.y, &br.x, new.y, new.x, my_all->displayhw.y-1, my_all->displayhw.x-1)) { struct pt newhw; newhw.y = br.y-new.y+1; newhw.x = br.x-new.x+1; if (curhw.y == newhw.y && curhw.x == newhw.x) { if (curhw.y != newhw.y || curhw.x != newhw.x) my_move_panel(the_frm, new.y, new.x); } else if (curhw.y != newhw.y || curhw.x != newhw.x) { #if 0 WINDOW *temp_win, *old_win; old_win = panel_window(top); temp_win = newwin_input(newhw.y, newhw.x, new.y, new.x); replace_panel(top, temp_win); win_show(temp_win, the_frm->label, the_frm->label_color); delwin(old_win); #endif } } } } } enum tf_fields { tf_title, tf_lifetime, tf_rows, tf_columns, tf_begrow, tf_begcol, tf_framemsg, tf_altslks, tf_text, #define tf_MAX (tf_text+1) }; static void textframe_descs(FRM *the_frm, void *param) { static const char *gyh_tf[tf_MAX] = { /*tf_title*/ "title", /*tf_lifetime*/ "lifetime", /*tf_rows*/ "rows", /*tf_columns*/ "columns", /*tf_begrow*/ "begrow", /*tf_begcol*/ "begcol", /*tf_framemsg*/ "framemsg", /*tf_altslks*/ "altslk", /*tf_text*/ "text", }; all my_all; vary_dict desc; const char **tf; int i; my_all = the_frm->my_all; the_frm->descs = new_desc(); desc = NULL; tf = param; for (i = tf_title; i < tf_MAX; i++) if (tf[i]) add_descriptor_dup(the_frm->descs, gyh_tf[i], tf[i], 1, &desc); } /*Begin fmli commands*/ static void fmli_notimplemented(all my_all) { beep(); message_dyn(my_all, argv2char("Not implemented <", my_all->argc, my_all->argv, ">."), 0); } static void fmli_cancel(all my_all) { /* cancel [frameID ...] */ cancel_close_frm(my_all, my_all->argc, my_all->argv, 1, 0); } static void fmli_checkworld(all my_all) { FRM *the_frm; /* checkworld */ /* clear message line? */ again: if ((the_frm = FRM_FIRST(my_all))) do { if (get_boolean(my_all, the_frm->descs->globals, "reread", 0)) if (do_update(my_all, the_frm, 0)) goto again; } while (!FRM_PAST((the_frm = NEXT_FRM(the_frm)), my_all)); } static void fmli_choices(all my_all) { FRM *the_frm; /* choices */ /*CLN FIX*/ the_frm = my_all->current_frm; if (the_frm->frm_type == FRMt_form) { vary_dict desc; char *m; desc = field_userptr(current_field(the_frm->u.f.form)); m = get_command(my_all, desc, "rmenu"); if (m) { fmli_string s; struct arg args; int hadmsg; if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "fmli_choices:rmenu<%s>\n", m); fflush(stddbg); } s = get_string(my_all, desc, "choicemsg"); if (s) { message_dyn(my_all, s, 0); hadmsg = *s; } else hadmsg = 0; args.argv = NULL; args.argc = set_argv(m, &args.argv, 0); if (args.argc == 0 || (args.argc <= 2 && args.argv[0][0] == '{')) { if (!hadmsg) message_dup(my_all, "There are no choices available", 0); } else if (args.argv[0][0] == '{') { if (my_all->toggle != tg_never && (my_all->toggle == tg_always || (args.argc-2) <= my_all->toggle)) { /*toggle*/; } else alloc_frm(my_all, FRMt_menu, FRMts_menu_choices, 0, NULL, menu_choices_value_descs, &args, MASK(fm_extended) | MASK(fm_choices)); } else open_frm(my_all, args.argc, args.argv, MASK(fm_choices)); if (args.argv) free(args.argv); free(m); } } else beep(); } static void fmli_cleanup(all my_all) { FRM *the_frm; /* cleanup */ again: if ((the_frm = FRM_FIRST(my_all))) do { if (!(the_frm->flags & (MASK(fm_immortal) | MASK(fm_closing)))) { fmli_lifetime s; s = get_lifetime(my_all, the_frm->descs->globals, "lifetime", -1); if (s == -1 || s == l_shortterm || s == l_longterm) if (close_frm(my_all, the_frm, 0, 0)) goto again; } } while (!FRM_PAST((the_frm = NEXT_FRM(the_frm)), my_all)); } static void fmli_close(all my_all) { /* close [frameID ...] */ cancel_close_frm(my_all, my_all->argc, my_all->argv, 0, 0); } static void fmli_cmd_menu(all my_all) { /* cmd-menu */ alloc_frm(my_all, FRMt_menu, FRMts_menu_cmd, 0, NULL, def_descs, &my_all->def[DEF_cmd], MASK(fm_static_descs) | MASK(fm_extended) | MASK(fm_cmd_menu)); } static void fmli_done(all my_all) { FRM *the_frm; /* done */ the_frm = my_all->current_frm; switch (the_frm->frm_type) { case FRMt_form: { int res; res = form_driver(the_frm->u.f.form, REQ_VALIDATION); if (res != E_OK) { } else { int ctrLines; for (ctrLines = 0; the_frm->u.f.fields[ctrLines*2]; ctrLines++) { char *value = field_buffer(the_frm->u.f.fields[ctrLines*2+1], 0); size_t l; for (l = strlen(value); l && isspace(value[l-1]); l--) ; value[l] = '\0'; for (l = 0; value[l] && value[l] != '\n'; l++) if (!isalnum(*value) && (*value != ' ')) break; value[l] = '\0'; { char name[24+1]; snprintf(name, sizeof(name), "F%d", ctrLines+1); setenv_string(my_all, name, value); } } } } break; case FRMt_text: case FRMt_menu: beep(); break; } { fmli_string s; s = get_action_done(my_all, the_frm->descs->globals, NULL, false, "done"); if (!s) s = strdup("close"); my_all->src = SRC(the_frm); executecommand(my_all, s); } } static void fmli_enter(all my_all) { FRM *the_frm; /* enter */ the_frm = my_all->current_frm; switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: beep(); break; case FRMt_menu: { fmli_string s; if (!(menu_opts(the_frm->u.m.menu) & O_ONEVALUE)) s = get_action_done(my_all, the_frm->descs->globals, NULL, false, "done"); else { vary_dict desc; desc = item_userptr(current_item(the_frm->u.m.menu)); s = get_action_done(my_all, desc, the_frm->descs->globals, the_frm->flags & MASK(fm_extended), "action"); if (!s && the_frm->flags & MASK(fm_cmd_menu)) s = get_string(my_all, desc, "name"); } if (s) { if (!strcasecmp(s, "enter")) { free(s); beep(); } else { my_all->src = SRC(the_frm);/*May set cs_cmd_menu*/ if (DEBUGSTDDBG && stddbg) if (my_all->src == cs_cmd_menu) { fprintf(stddbg, "fmli_enter:cs_cmd_menu####<%s>\n", s); fflush(stddbg); } executecommand(my_all, s); } } } break; } } static void fmli_exit(all my_all) { FRM *the_frm; /* exit */ again: if ((the_frm = FRM_FIRST(my_all))) do { if (close_frm(my_all, the_frm, 1, 1)) goto again; } while (!FRM_PAST((the_frm = NEXT_FRM(the_frm)), my_all)); } static void fmli_frm_mgmt(all my_all) { enum sub_frm_mgmt_type { sfm_list, sfm_move, sfm_reshape, }; static const char *sub_frm_mgmt[] = { "list", "move", "reshape" }; /* frm-mgmt [list] */ /* frm-mgmt [move [frameID]] */ /* frm-mgmt [reshape [frameID]] */ if (my_all->argc < 2) alloc_frm(my_all, FRMt_menu, FRMts_menu_choices, 0, NULL, frm_mgmt_FrameManagement_descs, NULL, MASK(fm_extended) | MASK(fm_choices) | MASK(fm_choices_action)); else switch (whichof(my_all->argv[1], sub_frm_mgmt, SIZEOF(sub_frm_mgmt))) { case sfm_list: do_frm_mgmt_list(my_all); break; case sfm_move: do_frm_mgmt_move(my_all); break; case sfm_reshape: do_frm_mgmt_reshape(my_all); break; default: break; } } static void fmli_goto(all my_all) { char buffer[120+1]; const char *s; /* goto [frameID] */ s = my_all->argv[1]; if (my_all->argc < 2) if (wget_line(my_all->cmd, "Enter a frame number or path: ", NULL, buffer, sizeof(buffer)-1) != ERR) s = trim(buffer); if (s && s[0]) { #if 1 navigate_to(my_all, frm_from_id(my_all, s)); #else FRM *the_frm; navigate_away(my_all); the_frm = frm_from_id(my_all, s); if (the_frm) goto_frm(my_all, the_frm); #endif } } static void fmli_help(all my_all) { /* help [command_name] */ if (my_all->argc < 2) { FRM *the_frm; fmli_string s; the_frm = my_all->current_frm; if (1) { vary_dict desc; desc = (the_frm->flags & MASK(fm_cmd_menu)) ? item_userptr(current_item(the_frm->u.m.menu)) : the_frm->descs->globals; if (!value_vary_dict(desc, "help") && (the_frm->flags & MASK(fm_cmd_menu))) desc = the_frm->descs->globals; s = get_command(my_all, desc, "help"); } else { int both; both = the_frm->flags & MASK(fm_cmd_menu); s = !both ? NULL : get_command(my_all, get_local_desc(the_frm), "help"); if (!s) s = get_command(my_all, the_frm->descs->globals, "help"); } if (s) { my_all->src = SRC(the_frm);/*May set cs_cmd_menu*/ if (DEBUGSTDDBG && stddbg) if (my_all->src == cs_cmd_menu) { fprintf(stddbg, "fmli_help:cs_cmd_menu####\n"); fflush(stddbg); } executecommand(my_all, s); } else indicator_flash(my_all); } else { const struct zzzz *kvc = &cmd_help_defs; size_t i; for (i = 0; i < kvc->kv_cnt; i++) { if (!strcasecmp(kvc->kv[i].key, my_all->argv[1])) { alloc_frm(my_all, FRMt_text, 0, my_all->argc, my_all->argv, cmd_help_descs, (void *)&kvc->kv[i], MASK(fm_extended)); return; } } message_dup(my_all, "Could not find help on that command", 0); } } static void fmli_mark(all my_all) { FRM *the_frm; /* mark */ the_frm = my_all->current_frm; if (the_frm->frm_type == FRMt_menu && !(menu_opts(the_frm->u.m.menu) & O_ONEVALUE)) { ITEM *item; int on; item = current_item(the_frm->u.m.menu); on = !item_value(item); set_item_value(item, on); if (on) { fmli_string s; s = get_action_done(my_all, item_userptr(item), the_frm->descs->globals, the_frm->flags & MASK(fm_extended), "action"); if (s) free(s); } } else beep(); } static void fmli_nextpage(all my_all) { FRM *the_frm; /* nextpage */ the_frm = my_all->current_frm; if (the_frm) { int res; switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: res = set_form_page(the_frm->u.f.form, form_page(the_frm->u.f.form)+1); break; case FRMt_menu: res = menu_driver(the_frm->u.m.menu, REQ_SCR_DPAGE); break; } if (res != E_OK) beep(); } } static void fmli_next_frm(all my_all) { /* next-frm */ navigate_to(my_all, NEXT_FRM(my_all->current_frm)); } static void fmli_nop(all my_all) { /* nop */ } static void fmli_open(all my_all) { /* open [type] filename [arg ...] */ if (checkbang(my_all, my_all->argv[0])) open_frm(my_all, my_all->argc, my_all->argv, 0); } static void fmli_prev_frm(all my_all) { /* prev-frm */ navigate_to(my_all, PREV_FRM(my_all->current_frm)); } static void fmli_prevpage(all my_all) { FRM *the_frm; /* prevpage */ the_frm = my_all->current_frm; if (the_frm) { int res; switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: res = set_form_page(the_frm->u.f.form, form_page(the_frm->u.f.form)-1); break; case FRMt_menu: res = menu_driver(the_frm->u.m.menu, REQ_SCR_UPAGE); break; } if (res != E_OK) beep(); } } static void fmli_refresh(all my_all) { /* refresh */ /*CLN FIX*/ update_panels(); doupdate(); } static void fmli_release(all my_all) { int argc; char *argv[2+1]; /* release */ argv[0] = "message"; argv[1] = "FMLI Release 4.2 Pn"; /*CLN FIX*/ argv[2] = NULL; argc = 2; blt2_message(my_all, argc, argv, my_all->fds.fdc, my_all->fds.fdv); } static void fmli_reset(all my_all) { /* reset */ /*CLN FIX*/ beep(); } /* textframe: A sco addition */ static void fmli_textframe(all my_all) { const char *tf[tf_MAX]; int ch; int i; /* textframe [options] text options: descriptor: default: -t title title -l lifetime lifetime shortterm -f text framemsg -r integer rows -c integer columns -p postion begrow center or current -a altslks */ for (i = tf_title; i < tf_MAX; i++) tf[i] = NULL; tf[tf_lifetime] = "shortterm"; optind = 0; opterr = 0; while ((ch = getopt(my_all->argc, my_all->argv, "ac:f:l:p:r:t:")) != EOF) switch (ch) { case 'a': tf[tf_altslks] = "true"; break; case 'c': tf[tf_columns] = optarg; break; case 'f': tf[tf_framemsg] = optarg; break; case 'l': tf[tf_lifetime] = optarg; break; case 'p': tf[tf_begrow] = optarg; break; case 'r': tf[tf_rows] = optarg; break; case 't': tf[tf_title] = optarg; break; default: break; } if ((my_all->argc-optind) > 0) tf[tf_text] = argv2char(NULL, my_all->argc-optind, my_all->argv+optind, NULL); alloc_frm(my_all, FRMt_text, 0, 0, NULL, textframe_descs, tf, 0); if (tf[tf_text]) free((char *)tf[tf_text]); } static void fmli_togslk(all my_all) { /* togslk */ display_slks(my_all, 1); } static void fmli_unix_system(all my_all) { /* unix-system */ working(1); unix_system(my_all, "echo \"To return, type 'exit' or control-d\n" "You are in `pwd`\"; exec ${SHELL:-/bin/sh}"); fmli_checkworld(my_all);/*But force!!!*/ } static void fmli_update(all my_all) { /* update [frameID [mkcurr]] */ if (my_all->argc < 2) do_update(my_all, my_all->current_frm, 0); else { FRM *the_frm; the_frm = frm_from_id(my_all, my_all->argv[1]); if (the_frm) do_update(my_all, the_frm, (my_all->argc == 3) ? istrue(my_all->argv[2]) : 0); } } struct zxzx_fmli { const char *name; void (*fmli_fnc)(all my_all); }; static struct zxzx_fmli zx_fmli[] = { {"cancel", fmli_cancel}, {"checkworld", fmli_checkworld}, {"choices", fmli_choices}, {"cleanup", fmli_cleanup}, {"close", fmli_close}, {"cmd-menu", fmli_cmd_menu}, {"done", fmli_done}, {"enter", fmli_enter}, /* enter appears to be a hidden command! */ {"exit", fmli_exit}, {"frm-mgmt", fmli_frm_mgmt}, {"goto", fmli_goto}, {"help", fmli_help}, {"mark", fmli_mark}, {"next-frm", fmli_next_frm}, {"nextpage", fmli_nextpage}, {"nop", fmli_nop}, {"open", fmli_open}, {"prev-frm", fmli_prev_frm}, {"prevpage", fmli_prevpage}, {"refresh", fmli_refresh}, {"release", fmli_release}, {"reset", fmli_reset}, {"textframe", fmli_textframe}, /* A sco addition */ {"togslk", fmli_togslk}, {"unix-system", fmli_unix_system}, {"update", fmli_update}, }; static int executecommand_argv(all my_all, int argc, char **argv, int must) { void (*fmli_fnc)(all my_all); fmli_string val; fmli_fnc = NULL; val = NULL; if (argv[0]) { descs descs = &my_all->def[DEF_cmd]; size_t i; for (i = CCOUNT(descs->locals); i; i--) { vary_dict desc; desc = AAT(descs->locals, i-1); if (!value_vary_dict(desc, "button")) { fmli_string nam; nam = get_string(my_all, desc, "name"); if (!nam) message_va(my_all, "What! %s:%d", __FILE__, __LINE__); if (!strcasecmp(argv[0], nam)) { val = get_action_done(my_all, desc, descs->globals, false, "action"); if (!val) val = nam; else free(nam); break; } else free(nam); } } /*======*/ if (val) { argv[0] = val; { size_t i; for (i = 0; i < SIZEOF(zx_fmli); i++) if (!strcasecmp(argv[0], zx_fmli[i].name)) { fmli_fnc = zx_fmli[i].fmli_fnc; break; } } } } else if (1) /* Allow empty cmd */ fmli_fnc = fmli_nop; if (DEBUGSTDDBG && stddbg) dump_argv("fmli_fnc:\n", argc, argv); if (fmli_fnc || must) { if (DEBUGSTDDBG && stddbg) { const char *s; switch (my_all->src) { case cs_desc: s = "cs_desc"; break; case cs_cmd_line: s = "cs_cmd_line"; break; case cs_cmd_menu: s = "cs_cmd_menu"; break; default: s = "?"; } fprintf(stddbg, "source=%s\n", s); fflush(stddbg); } if (!fmli_fnc) fmli_fnc = fmli_notimplemented; if (my_all->src == cs_cmd_menu) navigate_to(my_all, PREV_FRM(my_all->current_frm)); my_all->argc = argc; my_all->argv = argv; (*fmli_fnc)(my_all); /* Uninterruptable */ my_all->argc = 0; my_all->argv = NULL; run_end(); if (my_all->current_frm) touchwin(panel_window(my_all->current_frm->panel)); } if (val) free(val); return fmli_fnc != NULL; } static void executecommand(all my_all, char *p) { /* We will free(p)) */ int argc; char **argv; argv = NULL; argc = set_argv(p, &argv, 0); executecommand_argv(my_all, argc, argv, 1); free(argv); free(p); } /*End fmli commands*/ static void x_driver_error(all my_all, const char *x, int err, int UserInput) { const char *e_msg; update_panels(); doupdate(); /*touchwin(the_frm->panel.window);*/ switch (err) { case E_OK: e_msg = "E_OK"; break; case E_SYSTEM_ERROR: e_msg = "E_SYSTEM_ERROR"; break; case E_BAD_ARGUMENT: e_msg = "E_BAD_ARGUMENT"; break; case E_POSTED: e_msg = "E_POSTED"; break; case E_CONNECTED: e_msg = "E_CONNECTED"; break; case E_BAD_STATE: e_msg = "E_BAD_STATE"; break; case E_NO_ROOM: e_msg = "E_NO_ROOM"; break; case E_NOT_POSTED: e_msg = "E_NOT_POSTED"; break; case E_UNKNOWN_COMMAND: e_msg = "E_UNKNOWN_COMMAND"; break; case E_NO_MATCH: e_msg = "E_NO_MATCH"; break; case E_NOT_SELECTABLE: e_msg = "E_NOT_SELECTABLE"; break; case E_NOT_CONNECTED: e_msg = "E_NOT_CONNECTED"; break; case E_REQUEST_DENIED: e_msg = "E_REQUEST_DENIED"; break; case E_INVALID_FIELD: e_msg = "E_INVALID_FIELD"; break; case E_CURRENT: e_msg = "E_CURRENT"; break; default: e_msg = "E_?"; break; } beep(); if (DEBUGSTDDBG) { int l; char msg[100+1]; l = snprintf(msg, sizeof(msg), "%s %s (%d):", x, e_msg, err); if (UserInput > KEY_MAX) snprintf(msg+l, sizeof(msg)-l, "KEY_MAX+%04o", UserInput-KEY_MAX); else snprintf(msg+l, sizeof(msg)-l, "%s", keyname(UserInput)); if (stddbg) { fprintf(stddbg, "x_driver_error:%s\n", msg); fflush(stddbg); } else message_dup(my_all, msg, 0); } } static void do_slk(all my_all, unsigned int keyIx) { FRM *the_frm; the_frm = my_all->current_frm; if (the_frm->altslks) { keyIx += 8; if (keyIx >= SLK_MAX) keyIx -= SLK_MAX; } if ((keyIx < SLK_MAX) && (the_frm->slkEnabled & ENABLE_F(keyIx+1)) && the_frm->slk_dict[keyIx]) { fmli_string s; s = get_action_done(my_all, the_frm->slk_dict[keyIx], the_frm->descs->globals, false, "action"); if (s) { my_all->src = cs_desc; executecommand(my_all, s); } } else beep(); } static void do_cmdline(all my_all, const char *pre) { char buffer[120+1]; navigate_away(my_all); if (wget_line(my_all->cmd, "-->", pre, buffer, sizeof(buffer)-1) != ERR) { char *s = trim(buffer); if (s[0]) { char *s0; s0 = s; if (*s == '!') s += 1; else if (!strcmp(s, "run ")) s += 4; my_all->src = cs_cmd_line; if (s0 != s) { if (checkbang(my_all, *s0 == '!' ? "!" : "run")) unix_system(my_all, s); } else { int argc; char **argv; argv = NULL; argc = set_argv(s, &argv, 1); if (!executecommand_argv(my_all, argc, argv, 0)) { memmove(&argv[1], &argv[0], sizeof(*argv)*(argc+1)); argc += 1; argv[0] = isdigit(argv[1][0]) ? "goto" : "open"; executecommand_argv(my_all, argc, argv, 1); } free(argv); } } } restore_cursor(my_all); wmove(my_all->cmd, 0, 0); wclrtoeol(my_all->cmd); wrefresh(my_all->cmd); doupdate(); } static int req_x_field(FORM *form, int up) { int cnt; FIELD **fields; int index; cnt = field_count(form); fields = form_fields(form); index = field_index(current_field(form)); do { if (up) { index++; if (index >= cnt) index = 0; } else { index--; if (index < 0) index += cnt; } } while (!(field_opts(fields[index]) & O_ACTIVE)); return set_current_field(form, fields[index]); } #if !defined(NCURSES_SLK_ENCLOSE) static int slk_enclose(int y, int x) { return 0; } #endif static void run(all my_all) { if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "NCURSES_MOUSE_VERSION=%i\n", NCURSES_MOUSE_VERSION); fflush(stddbg); } #ifdef NCURSES_MOUSE_VERSION { mmask_t m; m = mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); if (DEBUG_MOUSE && DEBUGSTDDBG && stddbg) { char buf[80+(5*10)+(32*15)]; sprintf(buf, "mousemask=%4lx = {", (unsigned long)m); show_mouse_nmem(buf, m); strcat(buf, "}"); fprintf(stddbg, "%s\n", buf); fflush(stddbg); } } #endif while (my_all->current_frm) { int UserInput; FRM *the_frm; int res; if (my_all->vsig_interrupted) { my_all->vsig_interrupted = 0; fmli_checkworld(my_all); } res = E_OK; UserInput = wgetkey(panel_window(my_all->current_frm->panel)); msg_put(my_all, b_transient, NULL, 0); #ifdef NCURSES_MOUSE_VERSION if (UserInput == KEY_MOUSE) { MEVENT event; if (getmouse(&event) == OK) { if (DEBUG_MOUSE && DEBUGSTDDBG && stddbg) show_mouse(&event); if (event.bstate & (BUTTON1_RELEASED | BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON1_TRIPLE_CLICKED)) { int key; if (wenclose(my_all->ban, event.y, event.x)) UserInput = DO_OK; /* No mouse meaning for banner window */ else if (wenclose(my_all->msg, event.y, event.x)) UserInput = DO_OK; /* No mouse meaning for message window */ else if (wenclose(my_all->cmd, event.y, event.x)) UserInput = KEY_COMMAND; else if ((key = slk_enclose(event.y, event.x))) { if (key > 0) UserInput = KEY_F(key); else { beep(); UserInput = DO_OK; } } else { PANEL *p; p = NULL; if (wenclose(stdscr, event.y, event.x)) while ((p = panel_below(p)) && !wenclose(panel_window(p), event.y, event.x)) ; if (p) { FRM *the_frm; the_frm = panel_userptr(p); if (the_frm) { WINDOW *windows[2]; int in; if (my_all->current_frm != the_frm) { navigate_to(my_all, the_frm); update_panels(); doupdate(); the_frm = my_all->current_frm; } switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: windows[0] = form_win(the_frm->u.f.form); windows[1] = form_sub(the_frm->u.f.form); break; case FRMt_menu: windows[0] = menu_win(the_frm->u.m.menu); windows[1] = menu_sub(the_frm->u.m.menu); break; } in = !!wenclose(windows[1], event.y, event.x); mouse_trafo(&event.y, &event.x, FALSE); event.y -= getbegy(windows[in]); event.x -= getbegx(windows[in]); if (in == 0) { if (event.y == 0 && event.x >= the_frm->title_x && event.x <= getmaxx(windows[in])-1-the_frm->title_x) UserInput = DO_OK; else if (on_scroller(event, &the_frm->scroll[scr_page], 0)) switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: UserInput = REQ_PREV_PAGE; break; case FRMt_menu: UserInput = REQ_PREV_ITEM; break; } else if (on_scroller(event, &the_frm->scroll[scr_page], 1)) switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: UserInput = REQ_NEXT_PAGE; break; case FRMt_menu: UserInput = REQ_NEXT_ITEM; break; } else if (on_scroller(event, &the_frm->scroll[scr_field], 0)) switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: UserInput = REQ_PREV_LINE; break; case FRMt_menu: break; } else if (on_scroller(event, &the_frm->scroll[scr_field], 1)) switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: UserInput = REQ_NEXT_LINE; break; case FRMt_menu: break; } } #if defined(MY_MOUSE) if (in == 0) ; else { switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: { FORM *form; _PAGE *curpage; FIELD **fields; int i; form = the_frm->u.f.form; /*CLN FIX OPAQUE:page*/ curpage = &form->page[form_page(form)]; fields = form_fields(form); /*CLN FIX OPAQUE:pmin,pmax*/ for (i = curpage->pmin; i <= curpage->pmax; i++) { int rows, cols; int frow, fcol; int nrow; int nbuf; FIELD *fieldi; fieldi = fields[i]; if (field_info(fieldi, &rows, &cols, &frow, &fcol, &nrow, &nbuf) == E_OK) { if (event.y >= frow && event.y < frow+rows-nrow && event.x >= fcol && event.x < fcol+cols) { event.y -= frow; event.x -= fcol; if (field_opts(fieldi) & O_ACTIVE) { if (set_current_field(form, fieldi)) ; break; } } } } } break; case FRMt_menu: { struct pt rc, RC, n, curhw; int toprow, rm, spc_rows, i, ic; curhw.y = getmaxy(windows[1]); curhw.x = getmaxx(windows[1]); menu_format(the_frm->u.m.menu, &rc.y, &rc.x); toprow = top_row(the_frm->u.m.menu); rm = menu_opts(the_frm->u.m.menu) & O_ROWMAJOR; ic = item_count(the_frm->u.m.menu); /*CLN FIX*/ spc_rows = 1; #if defined(NCURSES_EVENT_VERSION) if (menu_spacing(the_frm->u.m.menu, NULL, &spc_rows, NULL) == E_OK) if (!spc_rows) spc_rows = 1; #endif RC.y = event.y; RC.x = event.x*rc.x/curhw.x; n.y = (ic-1)/rc.x+1; n.x = rc.x; i = rm ? RC.x+(toprow+RC.y)*n.x : (toprow+RC.y)+n.y*RC.x; if (i < ic) { ITEM *item; item = menu_items(the_frm->u.m.menu)[i]; if (item) { event.y = 0;/*CLN FIX*//* y offset within xitem area */ event.x = 0;/*CLN FIX*//* x offset within xitem area */ if (item_opts(item) & O_SELECTABLE) { if (set_current_item(the_frm->u.m.menu, item)) ; } else beep(); } } } break; } UserInput = DO_OK; } #endif } } } } } } #endif the_frm = my_all->current_frm; switch (the_frm->frm_type) { case FRMt_form: case FRMt_text: { switch (UserInput) { case KEY_BACKSPACE: /* The following sequence is correct in OVL mode, make shorter! */ form_driver(the_frm->u.f.form, REQ_LEFT_CHAR); form_driver(the_frm->u.f.form, ' '); UserInput = REQ_LEFT_CHAR; break; case KEY_BTAB: case KEY_PREVIOUS: UserInput = REQ_PREV_FIELD; break; case KEY_BEG: UserInput = REQ_FIRST_FIELD; break; case KEY_CLEAR: UserInput = REQ_DEL_LINE; break; case KEY_EOL: UserInput = REQ_CLR_EOL; break; case KEY_COMMAND: do_cmdline(my_all, NULL); UserInput = DO_OK; break; case KEY_DC: UserInput = REQ_DEL_CHAR; break; case KEY_DL: UserInput = REQ_DEL_LINE; break; case KEY_DOWN: { int r; field_info(current_field(the_frm->u.f.form), &r, NULL, NULL, NULL, NULL, NULL); if (r == 1) { res = req_x_field(the_frm->u.f.form, 1);/* like REQ_NEXT_FIELD */ UserInput = DO_OK; } else UserInput = REQ_NEXT_LINE; } break; case KEY_END: UserInput = REQ_LAST_FIELD; break; case KEY_ENTER: /* validate current field */ if (form_driver(the_frm->u.f.form, REQ_VALIDATION) == E_OK) { int r; field_info(current_field(the_frm->u.f.form), &r, NULL, NULL, NULL, NULL, NULL); UserInput = (r == 1) ? REQ_NEXT_FIELD : REQ_NEXT_LINE; /* ? then wrap fields : then beeps */ /*CLN FIX*//*Cycle page*/ } else { beep(); UserInput = DO_OK; } break; case KEY_HOME: UserInput = REQ_BEG_FIELD; break; case KEY_LL: UserInput = REQ_END_FIELD; break; case KEY_IC: /* The following sequence is correct in OVL mode, make shorter! */ form_driver(the_frm->u.f.form, REQ_LEFT_CHAR); UserInput = ' '; break; case KEY_IL: UserInput = REQ_INS_LINE; break; case KEY_LEFT: UserInput = REQ_LEFT_CHAR; /* does not wrap to prev field or line */ break; case KEY_NPAGE: UserInput = REQ_NEXT_PAGE; break; case KEY_PPAGE: UserInput = REQ_PREV_PAGE; break; case KEY_RESET: /*UserInput = -1;*//*CLN FIX*/ break; case KEY_RIGHT: UserInput = REQ_RIGHT_CHAR; break; case KEY_F(1): case KEY_F(2): case KEY_F(3): case KEY_F(4): case KEY_F(5): case KEY_F(6): case KEY_F(7): case KEY_F(8): case KEY_F(9): case KEY_F(10): case KEY_F(11): case KEY_F(12): case KEY_F(13): case KEY_F(14): case KEY_F(15): case KEY_F(16): do_slk(my_all, UserInput-KEY_F(1)); UserInput = DO_OK; break; case KEY_SF: UserInput = REQ_SCR_FPAGE; break; case KEY_SR: UserInput = REQ_SCR_BPAGE; break; case KEY_NEXT: case CTRL('I'): UserInput = REQ_NEXT_FIELD; break; case KEY_UP: { int r; field_info(current_field(the_frm->u.f.form), &r, NULL, NULL, NULL, NULL, NULL); if (r == 1) { res = req_x_field(the_frm->u.f.form, 0);/* like REQ_PREV_FIELD */ UserInput = DO_OK; } else UserInput = REQ_PREV_LINE; } break; case CTRL('['): the_frm->u.f.fmode ^= REQ_INS_MODE ^ REQ_OVL_MODE; UserInput = DO_OK; break; default: break; } if (UserInput != DO_OK) res = form_driver(the_frm->u.f.form, UserInput); if (res != E_OK && UserInput != KEY_MOUSE) x_driver_error(my_all, "form", res, UserInput); } break; case FRMt_menu: { switch (UserInput) { case KEY_BACKSPACE: case KEY_BTAB: case KEY_LEFT: UserInput = REQ_LEFT_ITEM; break; case KEY_DOWN: case KEY_NEXT: UserInput = REQ_NEXT_ITEM; break; case KEY_BEG: UserInput = REQ_FIRST_ITEM; break; case KEY_COMMAND: do_cmdline(my_all, the_frm->descs == &my_all->def[DEF_cmd] ? item_name(current_item(the_frm->u.m.menu)) : NULL); UserInput = DO_OK; break; case KEY_END: UserInput = REQ_LAST_ITEM; break; case KEY_ENTER: my_all->src = cs_desc; executecommand(my_all, strdup("enter")); UserInput = DO_OK; break; case KEY_HOME: UserInput = REQ_FIRST_ITEM; break; case KEY_LL: UserInput = REQ_LAST_ITEM; break; case KEY_MARK: my_all->src = cs_desc; executecommand(my_all, strdup("mark")); UserInput = DO_OK; break; case KEY_NPAGE: UserInput = REQ_SCR_DPAGE; break; case KEY_PPAGE: UserInput = REQ_SCR_UPAGE; break; case KEY_RIGHT: case ' ': case CTRL('I'): UserInput = REQ_RIGHT_ITEM; break; case KEY_F(1): case KEY_F(2): case KEY_F(3): case KEY_F(4): case KEY_F(5): case KEY_F(6): case KEY_F(7): case KEY_F(8): case KEY_F(9): case KEY_F(10): case KEY_F(11): case KEY_F(12): case KEY_F(13): case KEY_F(14): case KEY_F(15): case KEY_F(16): do_slk(my_all, UserInput-KEY_F(1)); UserInput = DO_OK; break; case KEY_SF: UserInput = REQ_SCR_DLINE; break; case KEY_SR: UserInput = REQ_SCR_ULINE; break; case KEY_PREVIOUS: case KEY_UP: UserInput = REQ_PREV_ITEM; break; case KEY_CLEAR: case KEY_EOL: case KEY_DC: case KEY_DL: case KEY_IC: case KEY_IL: case KEY_RESET: UserInput = DO_OK; break; default: break; } if (UserInput != DO_OK) res = menu_driver(the_frm->u.m.menu, UserInput); if (res != E_OK && UserInput != KEY_MOUSE) x_driver_error(my_all, "menu", res, UserInput); } break; } } } static char * mk_temp_pid(all my_all, const char *format, const char *s) { size_t l; char *p; /* Assume %s %u */ l = strlen(format)+strlen(s)+16-2-2+1; p = malloc(l); snprintf(p, l, format, s, !my_all ? getpid() : my_all->pid); return p; } static all init_all(all my_all) { { enum def_type def_type; for (def_type = 0; def_type < UUU_MAX; def_type++) init_desc(&my_all->def[def_type]); } my_all->toggle = 3; THELIST(my_all) = NULL; { int i; my_all->fds.fdc = PIPE_FDC; for (i = 0; i < my_all->fds.fdc; i++) my_all->fds.fdv[i] = i; } my_all->pid = getpid(); my_all->appSocketPath = mk_temp_pid(my_all, "%s%u", TMP_FMLI_PIPE); my_all->listen_fd = serv_listen(my_all->appSocketPath); if (my_all->listen_fd < 0) { unlink(my_all->appSocketPath); message_dup(my_all, "serv_listen error", 0); return NULL; } return my_all; } static void free_all(all my_all) { if (DEBUGSTDDBG && stddbg) { fprintf(stddbg, "free_all:\n"); fflush(stddbg); } { enum def_type def_type; for (def_type = 0; def_type < UUU_MAX; def_type++) free_descs(&my_all->def[def_type]); } if (my_all->listen_fd >= 0) { close(my_all->listen_fd); my_all->listen_fd = -1; } if (my_all->appSocketPath) { unlink(my_all->appSocketPath); free(my_all->appSocketPath); my_all->appSocketPath = NULL; } #if MY_POPEN >= 1 if (my_all->shell_co.shell_open) { my_pclose(my_all->shell_co.eval_out_fd); my_all->shell_co.eval_out_fd = -1; my_all->shell_co.shell_open = 0; } if (my_all->shell_co.eval_in_fd >= 0) { close(my_all->shell_co.eval_in_fd); my_all->shell_co.eval_in_fd = -1; } if (my_all->shell_co.tmp_fmli_stdevalPath) { unlink(my_all->shell_co.tmp_fmli_stdevalPath); free(my_all->shell_co.tmp_fmli_stdevalPath); my_all->shell_co.tmp_fmli_stdevalPath = NULL; } #endif } static void try_intro_frm(all my_all) { if (value_vary_dict(my_all->def[DEF_init].globals, "title") || value_vary_dict(my_all->def[DEF_init].globals, "text")) { FRM *the_frm; the_frm = alloc_frm(my_all, FRMt_text, 0, 0, NULL, def_descs, &my_all->def[DEF_init], MASK(fm_static_descs) | MASK(fm_extended)); if (the_frm) { update_panels(); doupdate(); sleep(2); close_frm(my_all, the_frm, 1, 1); } } } static int set_ban(WINDOW *win, int width) { g_my_all->ban = win; return 1; } static int set_msg(WINDOW *win, int width) { g_my_all->msg = win; return 1; } static int set_cmd(WINDOW *win, int width) { g_my_all->cmd = win; return 1; } static void my_atexit(all my_all) { fmli_exit(my_all); #ifdef NCURSES_MOUSE_VERSION mousemask(0, NULL); #endif msg_put(my_all, b_permanent, NULL, 0); #if defined(HACK_Form_Choice) if (my_all->local_Form_Choice) free(my_all->local_Form_Choice); #endif del_win(&my_all->ban); del_win(&my_all->msg); del_win(&my_all->cmd); if (my_all->screen) { if (0) { flushinp(); wclear(stdscr); update_panels(); doupdate(); slk_clear(); } reset_prog_mode(); endwin(); delscreen(my_all->screen); my_all->screen = NULL; } while (my_all->co_list) { CO *co; co = my_all->co_list; my_all->co_list = co->next; co_free(co, 1); } { char *semi; semi = mk_temp_pid(my_all, "%s%u", TMP_FMLI_SEMI); unlink(semi); free(semi); } free_all(my_all); free(my_all); if (stddbg) { fclose(stddbg); stddbg = NULL; } } static void screen_atexit(void) { if (g_my_all) { my_atexit(g_my_all); g_my_all = NULL; } #if 1 { extern int *_nc_oldnums; if (_nc_oldnums) free(_nc_oldnums); } #endif } static void vsig_handler(int arg) { g_my_all->vsig_interrupted++; } static int main_fmli(int argc, char **argv) { int ret = EXIT_FAILURE; all my_all = NULL; const char *filename[DEF_MAX] = {NULL,NULL,NULL}; int opt_err = 0; int c; #if 0 /*Signals caught:*/ -SIGABRT X SIGALRM SIGBUS SIGEMT SIGFPE -SIGHUP SIGILL -SIGIOT X-SIGINT -SIGPIPE -SIGQUIT SIGSEGV SIGSYS -SIGTERM X SIGTSTP X SIGTTIN X SIGTTOU X SIGUSR1 X SIGUSR2 /* May want to catch and resignal this later when safe. SIGUSR2 causes FMLI to call checkworld which causes all posted objects with reread == TRUE to be reread. */ SIGXCPU SIGXFSZ message_va(my_all, "%s terminated by signal:%s\n", basename(argv[0]), psignal()); #endif setlocale(LC_ALL, ""); optind = 0; while ((c = getopt(argc, argv, "a:c:hi:")) != EOF) { enum def_type df; switch (c) { case 'a': df = DEF_alias; goto setit; break; case 'i': df = DEF_init; goto setit; break; case 'c': df = DEF_cmd; setit: filename[df] = optarg; break; default: opt_err |= 1; break; } } if (opt_err || (optind > argc)) { fprintf(stderr, "usage: fmli [-h] [-i init-file] [-c command-file] [-a alias-file] frame-definition-file ...\n"); goto getout; } if (optind >= argc) { fprintf(stderr, "Initial object must be specified\n"); goto getout; } { const char suffix_d[] = " -d"; const char suffix_x[] = " -x"; char val[PATH_MAX+sizeof(suffix_d)+sizeof(suffix_x)]; char *path; path = getexename(argv[0]); if (!path) { if (errno != ERANGE) perror("getexename() failed"); message_dup(my_all, "Can't get path to executable", 0); goto getout; } strcpy(val, path); free(path); if (DEBUGSTDDBG && stddbg) strcat(val, suffix_d); strcat(val, suffix_x); setenv_string(my_all, "FMLI_HELPER", val); } setenv_std(my_all, "FMLI_STDIN", STDIN_FILENO); setenv_std(my_all, "FMLI_STDOUT", STDOUT_FILENO); setenv_std(my_all, "FMLI_STDERR", STDERR_FILENO); atexit(screen_atexit); my_all = calloc(1, sizeof(*my_all)); g_my_all = my_all; if (!init_all(my_all)) goto getout; setenv_integer(my_all, VPID, my_all->pid); setenv_string(my_all, FMLI_PIPE, my_all->appSocketPath); { char *semi; semi = mk_temp_pid(my_all, "%s%u", TMP_FMLI_SEMI); my_mkfifo(semi); free(semi); } #if defined(__linux__) { struct sigaction new_act, old_act; memset(&new_act, 0, sizeof(new_act)); new_act.sa_handler = SIG_IGN; if (sigaction(SIGINT, &new_act, &old_act)) ; } { struct sigaction new_act, old_act; memset(&new_act, 0, sizeof(new_act)); new_act.sa_handler = vsig_handler; if (sigaction(SIGUSR2, &new_act, &old_act)) ; } #else sigignore(SIGINT); sigset(SIGUSR2, vsig_handler); #endif { enum def_type def_type; for (def_type = 0; def_type < UUU_MAX; def_type++) if (!build_def_descs(my_all, def_type, filename[def_type])) goto getout; } my_all->num_colors = COLOR_WHITE+1; { fmli_layout i; i = get_layout(my_all, my_all->def[DEF_init].globals, "slk_layout", lo_323); my_all->num_slks = (i <= 1) ? 8 : 12; slk_init(i); } ripoffline( 1, set_ban); ripoffline(-1, set_cmd); ripoffline(-1, set_msg); my_all->screen = newterm(NULL, stdout, stdin); if (!my_all->screen) { message_dup(my_all, "Error opening terminal: $TERM", 0); goto getout; } def_prog_mode(); setup_keypad(stdscr); nonl(); cbreak(); noecho(); bkgdset(' '); my_all->displayhw.x = COLS; my_all->displayhw.y = LINES; setenv_integer(my_all, "DISPLAYW", my_all->displayhw.x); setenv_integer(my_all, "DISPLAYH", my_all->displayhw.y); my_all->has_colors = has_colors(); setenv_boolean(my_all, "HAS_COLORS", my_all->has_colors); if (my_all->has_colors) { start_color(); setup_pairs(my_all); init_win(my_all->ban, COLOR_PAIR(c_banner)); init_win(stdscr, COLOR_PAIR(c_window)); init_win(my_all->msg, COLOR_PAIR(c_window)); init_win(my_all->cmd, COLOR_PAIR(c_window)); } wattron(my_all->ban, COLOR_PAIR(c_banner)); { fmli_string_acs s; s = get_string_acs(my_all, my_all->def[DEF_init].globals, "banner"); if (s) { int c; c = get_position(my_all, my_all->def[DEF_init].globals, "bancol", p_center); indicator_acs_maybe(my_all, c, s, -1); free(s); } } indicator_w(my_all); wrefresh(my_all->ban); update_panels();/*CLN Why*/ doupdate(); { fmli_toggle t; t = get_toggle(my_all, my_all->def[DEF_init].globals, "toggle", 3); my_all->toggle = (t == tg_unknown || (toggle_is_integer(t) && t <= 0)) ? 3 : t; } { fmli_string_acs s; s = get_string_acs(my_all, my_all->def[DEF_init].globals, "permanentmsg"); msg_put(my_all, b_permanent, s, 1); } try_intro_frm(my_all); while (optind < argc) { char *a = argv[optind]; { int argc; char *argv[2+1]; argv[0] = "open"; argv[1] = a; argv[2] = NULL; argc = 2; open_frm(my_all, argc, argv, MASK(fm_immortal)); } optind++; } update_panels(); doupdate(); run(my_all); try_intro_frm(my_all); if (msg_stack(my_all, b_transient)->msg) { wgetkey(stdscr); msg_put(my_all, b_transient, NULL, 0); } ret = EXIT_SUCCESS; getout: return ret; } static int co_helper(enum co_str m, CO *co, char **buf) { int argc; char **argv; int res; argc = 2; /* For command name and NULL */ { enum co_str i; for (i = 0; i < m; i++) if (co->strs[i]) argc += 2; } argv = malloc(argc*sizeof(argv[0])); argc = 0; argv[argc++] = "co_helper"; { enum co_str i; for (i = 0; i < co_MAX; i++) if (co->strs[i]) { argv[argc++] = (char *)co_letters[i]; argv[argc++] = co->strs[i]; } } argv[argc++] = NULL; { int filedes[2]; res = EXIT_FAILURE; if (pipe(filedes)) { res = blt_rpc(argc, argv, filedes[0], 2); free(argv); argv = NULL; if (buf) { size_t l; { struct stat sbuf; l = (fstat(filedes[0], &sbuf) >= 0) ? sbuf.st_size : 0; } if (l > 0) { *buf = malloc(l); if (*buf && read(filedes[0], *buf, l) == l) { int i; for (i = 0; i <= 1; i++) { char *s; argc = 0; for (s = *buf; ((s - *buf) < l) && (*s || argc & 1); s += strlen(s)+1) { if (i) argv[argc] = s; argc++; } if (i) argv[argc] = NULL; argc++; if (i == 0) argv = malloc(argc*sizeof(argv[0])); else { get_co_args(co, argc+1, argv-1); free(argv); argv = NULL; } } } } } close(filedes[0]); close(filedes[1]); } } return res; } static int co_check(const CO *co) { struct stat sbuf; return stat(co->rpath, &sbuf) >= 0 && sbuf.st_size > 0; } static void co_receive(const CO *co) { FILE *fp_read; fp_read = fopen(co->rpath, "r"); if (fp_read) { const char *exp; char buf[BUFSIZ]; exp = co->expect_string; if (!exp) { if (fgets(buf, sizeof(buf), fp_read)) fputs(buf, stdout); } else { size_t l; l = strlen(exp); while (fgets(buf, sizeof(buf), fp_read) && strncmp(buf, exp, l)) fputs(buf, stdout); } fclose(fp_read); } } static void co_send(const CO *co, int argc, char **argv) { FILE *fp_write; fp_write = fopen(co->wpath, "w"); if (fp_write) { struct sigaction new_act, old_act; int i; memset(&new_act, 0, sizeof(new_act)); new_act.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &new_act, &old_act)) ; for (i = optind+1; i < argc && argv[i]; i++) { if (i != optind+1) putc(' ', fp_write); fputs(argv[i], fp_write); } putc('\n', fp_write); if (co->send_string) { fputs(co->send_string, fp_write); putc('\n', fp_write); } fflush(fp_write); if (sigaction(SIGPIPE, &old_act, NULL)) ; fclose(fp_write); } } /* blt_* */ static int blt_cocheck(int argc, char **argv) { int res; /* cocheck proc_id */ /* cocheck command */ res = EXIT_FAILURE; if (argc != 2) { CO co; char *buf; memset(&co, 0, sizeof(co)); co.action = "?r"; co.proc_id = argv[1]; if (co_helper(co_proc_id+1, &co, &buf) == EXIT_SUCCESS) { if (co_check(&co)) res = EXIT_SUCCESS; if (buf) free(buf); } } return res; } static int blt_cocreate(int argc, char **argv) { int res; int ch; CO co; /* cocreate [-r rpath] [-w wpath] [-i proc_id] [-R refname] [-s send_string] [-e expect_string] command [arg ...] */ memset(&co, 0, sizeof(co)); res = EXIT_FAILURE; optind = 0; opterr = 0; while ((ch = getopt(argc, argv, "e:i:r:R:s:w:")) != EOF) switch (ch) { case 'e': co.expect_string = optarg; break; case 'i': co.proc_id = optarg; break; case 'r': co.rpath = optarg; break; case 'R': co.refname = optarg; break; case 's': co.send_string = optarg; break; case 'w': co.wpath = optarg; break; default: break; } if ((argc-optind) > 0) { char *buf; co.action = "+rwz"; if (!co.proc_id) co.proc_id = basename(argv[optind]); if (co_helper(co_MAX, &co, &buf) == EXIT_SUCCESS) { if (co.action[0] == '1') switch (fork()) { case -1: co.action = "-"; if (co_helper(co_proc_id+1, &co, NULL) == EXIT_SUCCESS) ; fprintf(stderr, "fork: %s", strerror(errno));/*NOFORK*/ res = errno; break; case 0: {/*-w:wpath, -r:rpath*/ const char *msg; errno = 0; if (!freopen(co.wpath, "w", stdout)) msg = "";/*NOPEN*/ else if (!freopen(co.rpath, "r", stdin)) msg = "";/*NOPEN*/ else if (!freopen("/dev/null", "w", stderr)) msg = "";/*NOPEN*/ else { { int fd; fd = fileno(stdin); fcntl(fd, F_SETFL, 0); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); } if (execvp(argv[optind], argv+optind) == -1) msg = "fork";/*NOFORK*/ } if (errno) fprintf(stderr, "%s: %s", strerror(errno), msg); res = errno; } break; default: break; } if (buf) free(buf); } } return res; } static int blt_codestroy(int argc, char **argv) { int res; int ch; CO co; /* codestroy [-R refname] proc_id [string] */ /* codestroy [-R refname] command [string] */ res = EXIT_FAILURE; memset(&co, 0, sizeof(co)); optind = 0; opterr = 0; while ((ch = getopt(argc, argv, "R:")) != EOF) switch (ch) { case 'R': co.refname = optarg; break; default: break; } if ((argc-optind) > 0) { co.action = "-iswz"; co.proc_id = argv[optind]; if (co_helper(co_refname+1, &co, NULL) == EXIT_SUCCESS) { co_send(&co, argc-optind-1, argv+optind+1);/*-s:send_string, -w:wpath*/ co.action = "="; res = co_helper(co_proc_id+1, &co, NULL); } } return res; } static int blt_coreceive(int argc, char **argv) { int res; /* coreceive proc_id */ /* coreceive command */ res = EXIT_FAILURE; if (argc == 2) { CO co; char *buf; memset(&co, 0, sizeof(co)); co.action = "?er"; co.proc_id = argv[1]; if (co_helper(co_proc_id+1, &co, &buf) == EXIT_SUCCESS) { if (co_check(&co)) {/*-r:rpath*/ co_receive(&co);/*-e:expect_string, -r:rpath*/ res = EXIT_SUCCESS; } if (buf) free(buf); } } return res; } static int blt_cosend(int argc, char **argv) { int ch; int n; /* cosend [-n] proc_id string */ /* cosend [-n] command string */ n = 0; optind = 0; opterr = 0; while ((ch = getopt(argc, argv, "n")) != EOF) switch (ch) { case 'n': n = 1; break; default: break; } if ((argc-optind) >= 3) { CO co; char *buf; memset(&co, 0, sizeof(co)); co.action = n ? "?sw" : "?ersw"; co.proc_id = argv[optind]; if (co_helper(co_proc_id+1, &co, &buf) == EXIT_SUCCESS) { co_send(&co, argc-optind-1, argv+optind+1);/*-s:send_string, -w:wpath*/ if (!n) co_receive(&co);/*-e:expect_string, -r:rpath*/ if (buf) free(buf); } } else return EXIT_FAILURE; return EXIT_SUCCESS; } static int blt_fmlcut(int argc, char **argv) { /* fmlcut -clist [file . . .] */ /* fmlcut -flist [-dchar] [-s] [file . . .] */ /*CLN FIX*/ return EXIT_SUCCESS; } static int blt_fmlexpr(int argc, char **argv) { /* fmlexpr arguments */ return EXIT_SUCCESS; } static int blt_fmlgrep(int argc, char **argv) { /* fmlgrep [options] limited_regular_expression [file . . .] */ return EXIT_SUCCESS; } static int blt_fmlmax(int argc, char **argv) { size_t c; int l; int ch; /* fmlmax [-c column | -l] field1 ... fieldn */ c = 1; l = 0; while ((ch = getopt(argc, argv, "c:l")) != EOF) switch (ch) { case 'c': c = atoi(optarg); if (c <= 0) c = 1; break; case 'l': l = 1; break; default: break; } if (optind >= argc) { size_t m; m = 0; while (optind < argc) { size_t len; len = strlen(argv[optind]); if (len > m) m = len; optind++; } printf("%u", l ? m : c+m+1); } else { fprintf(stderr, "fmlmax: wrong number of arguments\n"); printf("0"); } return EXIT_SUCCESS; } static int blt_regex(int argc, char **argv) { #include #include #include #include #include #include #define MAX_PATTERNS 32 #define TEN 10 char *ptr; char *value; char buf[BUFSIZ]; regmatch_t ret[TEN+1]; regex_t pattern[MAX_PATTERNS]; const char *template[MAX_PATTERNS]; static const char deftemplate[] = "$m0$m1$m2$m3$m4$m5$m6$m7$m8$m9"; int i; int numpatterns; int matches; /* regex [-e] [-v "string"] [pattern template] ... pattern [template] */ if (DEBUGSTDDBG && stddbg) dump_argv("regex:\n", argc, argv); value = NULL; for (i = 1; argv[i] && argv[i][0] == '-'; i++) switch (argv[i][1]) { case 'e': break; /* -e was handled by shell wrapper, ie rexep ... -e ... => $(rexep ... ...) */ case 'v': value = argv[i][2] ? &argv[i][2] : argv[++i]; break; default: break; } if ((argc-i)/2 > MAX_PATTERNS) ; numpatterns = 0; for (i = i; i < argc && argv[i]; i += 2) { if (!regcomp(&pattern[numpatterns], argv[i], REG_EXTENDED)) ; template[numpatterns++] = argv[i+1] ? argv[i+1] : deftemplate; } matches = 0; for ( ; ; ) { if (value) ptr = value; else if (fgets(buf, BUFSIZ, stdin)) { int ii; ptr = buf; ii = strlen(buf)-1; if (buf[ii] == '\n') buf[ii] = '\0'; } else break; for (i = 0; i < numpatterns; i++) { if (!regexec(&pattern[i], ptr, TEN+1, ret, 0)) { const char *p; matches = 1; for (p = template[i]; *p; p++) if (p[0] == '$' && p[1] == 'm' && isdigit(p[2])) { int k; p += 2; k = *p-'0'+1; fwrite(ptr+ret[k].rm_so, ret[k].rm_eo-ret[k].rm_so, 1, stdout); } else putchar(*p); if (template[i] == deftemplate) { putchar('\n'); break; } } } if (value) break; } for (i = 0; i < numpatterns; i++) regfree(&pattern[i]); return matches ? EXIT_SUCCESS : EXIT_FAILURE; } static int blt_run_begin(int argc, char **argv) { /* run_begin [-s] [-e] [-n] [-t string] */ return blt_rpc(argc, argv, STDIN_FILENO, 0); } static int blt_run_end(int argc, char **argv) { /* run_end $? [-s|-e|-n] [-t string] */ /* if (!argv[2] || (strcmp(argv[2], "-n") && !strcmp(argv[2], "-e") && atoi(argv[1]) != EXIT_SUCCESS)) */ press_enter(); return blt_rpc(argc, argv, STDIN_FILENO, 0); } static int blt_vsig(int argc, char **argv) { char *vpid; /* vsig */ vpid = getenv(VPID); if (vpid) { fflush(stdout); fflush(stderr); kill(atoi(vpid), SIGUSR2); } return !vpid ? EXIT_FAILURE : EXIT_SUCCESS; } static int blt_blt2(int argc, char **argv) { return blt_rpc(argc, argv, STDIN_FILENO, STDERR_FILENO+1); } static int blt_zzzz(int argc, char **argv) { return EXIT_FAILURE; } struct zxzx_blt { const char *name; int (*blt_fnc)(int argc, char **argv); }; static struct zxzx_blt zx_blt[] = { {"cocheck", blt_cocheck}, {"cocreate", blt_cocreate}, {"codestroy", blt_codestroy}, {"coreceive", blt_coreceive}, {"cosend", blt_cosend}, {"fmlcut", blt_fmlcut}, {"fmlexpr", blt_fmlexpr}, {"fmlgrep", blt_fmlgrep}, {"fmlmax", blt_fmlmax}, {"getfrm", blt_blt2}, {"getitems", blt_blt2}, {"indicator", blt_blt2}, {"longline", blt_blt2}, {"message", blt_blt2}, {"pathconv", blt_blt2}, {"readfile", blt_blt2}, {"regex_lesse", blt_regex}, {"reinit", blt_blt2}, {"run_begin", blt_run_begin}, {"run_end", blt_run_end}, {"set", blt_blt2}, {"setcolor", blt_blt2}, {"unset", blt_blt2}, {"vsig", blt_vsig}, }; int main(int argc, char **argv) { int res; int argc_o; int (*blt_fnc)(int argc, char **argv); argc_o = 0; if (argc >= 2 && !strcmp(argv[1], "-d")) { char *p; argc_o += 1; p = mk_temp_pid(NULL, "%s%u.txt", "fmli_debug_"); stddbg = fopen(p, "w"); free(p); } if (DEBUGSTDDBG && stddbg) dump_argv("main:\n", argc, argv); if ((argc-argc_o) >= 3 && !strcmp(argv[argc_o+1], "-x")) { size_t i; blt_fnc = blt_zzzz; for (i = 0; i < SIZEOF(zx_blt); i++) if (!strcmp(argv[argc_o+2], zx_blt[i].name)) { blt_fnc = zx_blt[i].blt_fnc; break; } argc_o += 2; } else blt_fnc = main_fmli; res = (*blt_fnc)(argc-argc_o, argv+argc_o); if (blt_fnc != main_fmli) /* done in my_atexit for main_fmli */ if (stddbg) { fclose(stddbg); stddbg = NULL; } return res; } /* End of fmli.c */