From 525a267e81017258ec78fc0d6187a56590d0989d Mon Sep 17 00:00:00 2001 From: Thomas Cort Date: Wed, 6 Nov 2013 10:44:51 -0500 Subject: [PATCH] Importing usr.bin/menuc No Minix-specific changes needed. Change-Id: Ie663e08a515a393efaaeecacea15ef807aa8ecfb --- distrib/sets/lists/minix/mi | 3 + releasetools/nbsd_ports | 1 + usr.bin/Makefile | 2 +- usr.bin/menuc/Makefile | 22 + usr.bin/menuc/avl.c | 217 +++++++++ usr.bin/menuc/defs.h | 102 +++++ usr.bin/menuc/main.c | 115 +++++ usr.bin/menuc/mdb.c | 431 ++++++++++++++++++ usr.bin/menuc/mdb.h | 98 ++++ usr.bin/menuc/menu_sys.def | 827 ++++++++++++++++++++++++++++++++++ usr.bin/menuc/menuc.1 | 544 ++++++++++++++++++++++ usr.bin/menuc/parse.y | 228 ++++++++++ usr.bin/menuc/pathnames.h | 5 + usr.bin/menuc/scan.l | 196 ++++++++ usr.bin/menuc/testm/Makefile | 27 ++ usr.bin/menuc/testm/main.c | 126 ++++++ usr.bin/menuc/testm/menus.mc | 277 ++++++++++++ usr.bin/menuc/testm/menus.msg | 12 + usr.bin/menuc/util.c | 107 +++++ 19 files changed, 3339 insertions(+), 1 deletion(-) create mode 100644 usr.bin/menuc/Makefile create mode 100644 usr.bin/menuc/avl.c create mode 100644 usr.bin/menuc/defs.h create mode 100644 usr.bin/menuc/main.c create mode 100644 usr.bin/menuc/mdb.c create mode 100644 usr.bin/menuc/mdb.h create mode 100644 usr.bin/menuc/menu_sys.def create mode 100644 usr.bin/menuc/menuc.1 create mode 100644 usr.bin/menuc/parse.y create mode 100644 usr.bin/menuc/pathnames.h create mode 100644 usr.bin/menuc/scan.l create mode 100644 usr.bin/menuc/testm/Makefile create mode 100644 usr.bin/menuc/testm/main.c create mode 100644 usr.bin/menuc/testm/menus.mc create mode 100644 usr.bin/menuc/testm/menus.msg create mode 100644 usr.bin/menuc/util.c diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 4c271587c..17cbcb62f 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -402,6 +402,7 @@ ./usr/bin/md2 minix-sys ./usr/bin/md4 minix-sys ./usr/bin/md5 minix-sys +./usr/bin/menuc minix-sys ./usr/bin/mesg minix-sys ./usr/bin/mined minix-sys ./usr/bin/ministat minix-sys @@ -1993,6 +1994,7 @@ ./usr/man/man1/md2.1 minix-sys ./usr/man/man1/md4.1 minix-sys ./usr/man/man1/md5.1 minix-sys +./usr/man/man1/menuc.1 minix-sys ./usr/man/man1/mesg.1 minix-sys ./usr/man/man1/ministat.1 minix-sys ./usr/man/man1/mixer.1 minix-sys @@ -4669,6 +4671,7 @@ ./usr/share/misc/magic.mgc minix-sys ./usr/share/misc/man.template minix-sys ./usr/share/misc/mdoc.template minix-sys +./usr/share/misc/menu_sys.def minix-sys ./usr/share/misc/na.phone minix-sys ./usr/share/misc/na.postal minix-sys ./usr/share/misc/NetBSD.el minix-sys diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index c18b59565..fbe0e5349 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -189,6 +189,7 @@ 2012/10/17 12:00:00,usr.bin/Makefile 2012/10/17 12:00:00,usr.bin/Makefile.inc 2010/07/07 21:24:34,usr.bin/man +2012/10/17 12:00:00,usr.bin/menuc 2013/10/25 12:00:00,usr.bin/mesg 2010/10/15 05:46:48,usr.bin/mkdep 2012/10/17 12:00:00,usr.bin/mkstr diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 5d226c90e..983e398e8 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -15,7 +15,7 @@ SUBDIR= asa \ head hexdump indent infocmp join \ lam ldd leave \ lock login logname lorder m4 \ - machine make man mesg \ + machine make man menuc mesg \ mkdep mkstr mktemp \ \ nbperf newgrp nice nl nohup nvi \ diff --git a/usr.bin/menuc/Makefile b/usr.bin/menuc/Makefile new file mode 100644 index 000000000..c44a97b07 --- /dev/null +++ b/usr.bin/menuc/Makefile @@ -0,0 +1,22 @@ +# $NetBSD: Makefile,v 1.14 2009/10/29 14:36:14 christos Exp $ + +WARNS?= 1 # XXX -Wshadow -Wcast-qual issues + +.include + +PROG= menuc +SRCS= main.c parse.y scan.l avl.c mdb.c util.c +CPPFLAGS+= -I. -I${.CURDIR} +YHEADER= + +.if ${MKSHARE} != "no" +FILES= menu_sys.def +FILESDIR= /usr/share/misc +.endif + +.ifndef HOSTPROG +LDADD+= -ll +DPADD+= ${LIBL} +.endif + +.include diff --git a/usr.bin/menuc/avl.c b/usr.bin/menuc/avl.c new file mode 100644 index 000000000..7e79274af --- /dev/null +++ b/usr.bin/menuc/avl.c @@ -0,0 +1,217 @@ +/* $NetBSD: avl.c,v 1.7 2005/02/11 06:21:22 simonb Exp $ */ + +/* + * Copyright (c) 1997 Philip A. Nelson. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Philip A. Nelson. + * 4. The name of Philip A. Nelson may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY PHILIP NELSON ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL PHILIP NELSON BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* avl.c: Routines for manipulation an avl tree. + * + * an include file should define the following minimum struct.: + * (Comments must be made into real comments.) + * + * typedef struct id_rec { + * / * The balanced binary tree fields. * / + * char *id; / * The name. * / + * short balance; / * For the balanced tree. * / + * struct id_rec *left, *right; / * Tree pointers. * / + * + * / * Other information fields. * / + * } id_rec; + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include + +#if defined(__RCSID) && !defined(lint) +__RCSID("$NetBSD: avl.c,v 1.7 2005/02/11 06:21:22 simonb Exp $"); +#endif + + +#include + +#include "defs.h" + +/* find_id returns a pointer to node in TREE that has the correct + ID. If there is no node in TREE with ID, NULL is returned. */ + +id_rec * + find_id (id_rec *tree, char *id) +{ + int cmp_result; + + /* Check for an empty tree. */ + if (tree == NULL) + return NULL; + + /* Recursively search the tree. */ + cmp_result = strcmp (id, tree->id); + if (cmp_result == 0) + return tree; /* This is the item. */ + else if (cmp_result < 0) + return find_id (tree->left, id); + else + return find_id (tree->right, id); +} + + +/* insert_id inserts a NEW_ID rec into the tree whose ROOT is + provided. insert_id returns TRUE if the tree height from + ROOT down is increased otherwise it returns FALSE. This is a + recursive balanced binary tree insertion algorithm. */ + +int insert_id (id_rec **root, id_rec *new_id) +{ + id_rec *A, *B; + + /* If root is NULL, this where it is to be inserted. */ + if (*root == NULL) + { + *root = new_id; + new_id->left = NULL; + new_id->right = NULL; + new_id->balance = 0; + return (TRUE); + } + + /* We need to search for a leaf. */ + if (strcmp (new_id->id, (*root)->id) < 0) + { + /* Insert it on the left. */ + if (insert_id (&((*root)->left), new_id)) + { + /* The height increased. */ + (*root)->balance--; + + switch ((*root)->balance) + { + case 0: /* no height increase. */ + return (FALSE); + case -1: /* height increase. */ + return (TRUE); + case -2: /* we need to do a rebalancing act. */ + A = *root; + B = (*root)->left; + if (B->balance <= 0) + { + /* Single Rotate. */ + A->left = B->right; + B->right = A; + *root = B; + A->balance = 0; + B->balance = 0; + } + else + { + /* Double Rotate. */ + *root = B->right; + B->right = (*root)->left; + A->left = (*root)->right; + (*root)->left = B; + (*root)->right = A; + switch ((*root)->balance) + { + case -1: + A->balance = 1; + B->balance = 0; + break; + case 0: + A->balance = 0; + B->balance = 0; + break; + case 1: + A->balance = 0; + B->balance = -1; + break; + } + (*root)->balance = 0; + } + } + } + } + else + { + /* Insert it on the right. */ + if (insert_id (&((*root)->right), new_id)) + { + /* The height increased. */ + (*root)->balance++; + switch ((*root)->balance) + { + case 0: /* no height increase. */ + return (FALSE); + case 1: /* height increase. */ + return (TRUE); + case 2: /* we need to do a rebalancing act. */ + A = *root; + B = (*root)->right; + if (B->balance >= 0) + { + /* Single Rotate. */ + A->right = B->left; + B->left = A; + *root = B; + A->balance = 0; + B->balance = 0; + } + else + { + /* Double Rotate. */ + *root = B->left; + B->left = (*root)->right; + A->right = (*root)->left; + (*root)->left = A; + (*root)->right = B; + switch ((*root)->balance) + { + case -1: + A->balance = 0; + B->balance = 1; + break; + case 0: + A->balance = 0; + B->balance = 0; + break; + case 1: + A->balance = -1; + B->balance = 0; + break; + } + (*root)->balance = 0; + } + } + } + } + + /* If we fall through to here, the tree did not grow in height. */ + return (FALSE); +} diff --git a/usr.bin/menuc/defs.h b/usr.bin/menuc/defs.h new file mode 100644 index 000000000..e35cb900b --- /dev/null +++ b/usr.bin/menuc/defs.h @@ -0,0 +1,102 @@ +/* $NetBSD: defs.h,v 1.9 2012/03/06 16:55:18 mbalmer Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* defs.h: definitions needed for the menu system. */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include + +#include "mdb.h" + +#ifdef MAIN +#define EXTERN +#define INIT(x) = x +#else +#define EXTERN extern +#define INIT(x) +#endif + +/* some constants */ +#define TRUE 1 +#define FALSE 0 + +/* Global variables .. to be defined in main.c, extern elsewhere. */ + +EXTERN char *prog_name; +EXTERN char *src_name; +EXTERN char *out_name INIT("menu_defs"); +EXTERN char *sys_name INIT("menu_sys.def"); + +EXTERN int do_dynamic INIT(0); +EXTERN int do_msgxlat INIT(0); +EXTERN int line_no INIT(1); +EXTERN int had_errors INIT(FALSE); +EXTERN int max_strlen INIT(1); + +EXTERN id_rec *root INIT(NULL); + +EXTERN struct menu_info default_info; +EXTERN id_rec default_menu; + +EXTERN action error_act INIT({NULL}); + +/* Prototypes. */ + +/* From util.c */ +void yyerror(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); +void buff_add_ch(char); +char *buff_copy(void); + +/* from scan.l */ +int yylex(void); + +/* from parse.y */ +int yyparse(void); + +/* Vars not defined in main.c */ +extern FILE *yyin; + +/* from avl.c */ +id_rec *find_id(id_rec *, char *); +int insert_id(id_rec **, id_rec *); + +/* from mdb.c */ +id_rec *get_menu(char *); +void check_defined(void); +void write_menu_file(char *); + diff --git a/usr.bin/menuc/main.c b/usr.bin/menuc/main.c new file mode 100644 index 000000000..d70df7db4 --- /dev/null +++ b/usr.bin/menuc/main.c @@ -0,0 +1,115 @@ +/* $NetBSD: main.c,v 1.11 2012/03/06 16:55:18 mbalmer Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* main.c - main program for menu compiler. */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include + +#if defined(__RCSID) && !defined(lint) +__RCSID("$NetBSD: main.c,v 1.11 2012/03/06 16:55:18 mbalmer Exp $"); +#endif + + +#include +#include +#include + +#define MAIN +#include "defs.h" + +/* Local prototypes */ +__dead void usage(void); + +int +main(int argc, char **argv) +{ + int ch; + + /* Process the arguments. */ + while ((ch = getopt(argc, argv, "o:")) != -1 ) { + switch (ch) { + case 'o': /* output file name */ + out_name = optarg; + break; + default: + usage(); + } + } + + if (optind != argc - 1) + usage(); + + src_name = argv[optind]; + + yyin = fopen(src_name, "r"); + if (yyin == NULL) { + (void)fprintf(stderr, "%s: could not open %s.\n", prog_name, + src_name); + exit(1); + } + + /* The default menu */ + default_menu.info = &default_info; + default_info.title = "\"\""; + default_info.helpstr = NULL; + default_info.exitstr = NULL; + default_info.mopt = 0; + default_info.x = -1; + default_info.y = 0; + default_info.h = 0; + default_info.w = 0; + default_info.numopt = 0; + default_info.optns = NULL; + default_info.postact.code = NULL; + default_info.postact.endwin = FALSE; + default_info.exitact.code = NULL; + default_info.exitact.endwin = FALSE; + + /* Do the parse */ + (void)yyparse(); + + return had_errors ? 1 : 0; +} + + +__dead void +usage(void) +{ + (void)fprintf (stderr, "%s [-o name] file\n", getprogname()); + exit(1); +} diff --git a/usr.bin/menuc/mdb.c b/usr.bin/menuc/mdb.c new file mode 100644 index 000000000..cb7633e7c --- /dev/null +++ b/usr.bin/menuc/mdb.c @@ -0,0 +1,431 @@ +/* $NetBSD: mdb.c,v 1.46 2012/03/06 16:55:18 mbalmer Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* mdb.c - menu database manipulation */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include + +#if defined(__RCSID) && !defined(lint) +__RCSID("$NetBSD: mdb.c,v 1.46 2012/03/06 16:55:18 mbalmer Exp $"); +#endif + + +#include +#include +#include +#include "mdb.h" +#include "defs.h" +#include "pathnames.h" + +/* Data */ +#undef MAX +#define MAX 1000 +static int menu_no = 0; +static id_rec *menus[MAX]; + +/* Other defines */ +#define OPT_SUB 1 +#define OPT_ENDWIN 2 +#define OPT_EXIT 4 + + +/* get_menu returns a pointer to a newly created id_rec or an old one. */ + +id_rec * +get_menu(char *name) +{ + id_rec *temp; + + temp = find_id (root, name); + + if (temp == NULL) { + if (menu_no < MAX) { + temp = (id_rec *)malloc(sizeof(id_rec)); + temp->id = strdup(name); + temp->info = NULL; + temp->menu_no = menu_no; + menus[menu_no++] = temp; + insert_id(&root, temp); + } else { + (void)fprintf(stderr, "Too many menus. " + "Increase MAX.\n"); + exit(1); + } + } + + return temp; +} + + +/* Verify that all menus are defined. */ +void +check_defined(void) +{ + int i; + + for (i = 0; i < menu_no; i++) + if (!menus[i]->info) + yyerror ("Menu '%s' undefined.", menus[i]->id); +} + + +/* Write out the menu file. */ +void +write_menu_file(char *initcode) +{ + FILE *out_file, *sys_file; + int i, j; + char hname[1024], cname[1024], sname[1024]; + char *sys_prefix, *tmpstr; + int name_is_code, nlen, ch; + optn_info *toptn; + + /* Generate file names */ + snprintf(hname, 1024, "%s.h", out_name); + nlen = strlen(hname); + if (hname[nlen-2] != '.' || hname[nlen-1] != 'h') { + (void)fprintf(stderr, "%s: name `%s` too long.\n", + prog_name, out_name); + exit(1); + } + snprintf(cname, 1024, "%s.c", out_name); + + /* Open the menu_sys file first. */ + sys_prefix = getenv("MENUDEF"); + if (sys_prefix == NULL) + sys_prefix = _PATH_DEFSYSPREFIX; + snprintf(sname, 1024, "%s/%s", sys_prefix, sys_name); + sys_file = fopen (sname, "r"); + if (sys_file == NULL) { + (void)fprintf(stderr, "%s: could not open %s.\n", + prog_name, sname); + exit(1); + } + + /* Output the .h file first. */ + out_file = fopen(hname, "w"); + if (out_file == NULL) { + (void)fprintf(stderr, "%s: could not open %s.\n", + prog_name, hname); + exit(1); + } + + /* Write it */ + (void)fprintf(out_file, "%s", + "/* menu system definitions. */\n" + "\n" + "#ifndef MENU_DEFS_H\n" + "#define MENU_DEFS_H\n" + "#include \n" + "#include \n" + "#include \n" + "#include \n\n" + ); + + if (do_msgxlat) + (void)fprintf(out_file, "#define MSG_XLAT(x) msg_string(x)\n"); + else + (void)fprintf(out_file, "#define MSG_XLAT(x) (x)\n"); + if (do_dynamic) + (void)fprintf(out_file, "#define DYNAMIC_MENUS\n"); + if (do_dynamic || do_msgxlat) + (void)fprintf(out_file, "\n"); + + (void)fprintf(out_file, + "typedef struct menudesc menudesc;\n" + "typedef struct menu_ent menu_ent;\n" + "struct menu_ent {\n" + " const char *opt_name;\n" + " int opt_menu;\n" + " int opt_flags;\n" + " int (*opt_action)(menudesc *, void *);\n" + "};\n\n" + "#define OPT_SUB 1\n" + "#define OPT_ENDWIN 2\n" + "#define OPT_EXIT 4\n" + "#define OPT_IGNORE 8\n" + "#define OPT_NOMENU -1\n\n" + "struct menudesc {\n" + " const char *title;\n" + " int y, x;\n" + " int h, w;\n" + " int mopt;\n" + " int numopts;\n" + " int cursel;\n" + " int topline;\n" + " menu_ent *opts;\n" + " WINDOW *mw;\n" + " WINDOW *sv_mw;\n" + " const char *helpstr;\n" + " const char *exitstr;\n" + " void (*post_act)(menudesc *, void *);\n" + " void (*exit_act)(menudesc *, void *);\n" + " void (*draw_line)(menudesc *, int, void *);\n" + "};\n" + "\n" + "/* defines for mopt field. */\n" +#define STR(x) #x +#define MC_OPT(x) "#define " #x " " STR(x) "\n" + MC_OPT(MC_NOEXITOPT) + MC_OPT(MC_NOBOX) + MC_OPT(MC_SCROLL) + MC_OPT(MC_NOSHORTCUT) + MC_OPT(MC_NOCLEAR) + MC_OPT(MC_DFLTEXIT) + MC_OPT(MC_ALWAYS_SCROLL) + MC_OPT(MC_SUBMENU) + MC_OPT(MC_VALID) +#undef MC_OPT +#undef STR + ); + + (void)fprintf(out_file, "%s", + "\n" + "/* Prototypes */\n" + "int menu_init(void);\n" + "void process_menu(int, void *);\n" + "__dead void __menu_initerror(void);\n" + ); + + if (do_dynamic) + (void)fprintf(out_file, "%s", + "int new_menu(const char *, menu_ent *, int, \n" + "\tint, int, int, int, int,\n" + "\tvoid (*)(menudesc *, void *), " + "void (*)(menudesc *, int, void *),\n" + "\tvoid (*)(menudesc *, void *), " + "const char *, const char *);\n" + "void free_menu(int);\n" + "void set_menu_numopts(int, int);\n" + ); + + (void)fprintf(out_file, "\n/* Menu names */\n"); + for (i = 0; i < menu_no; i++) + (void)fprintf(out_file, "#define MENU_%s\t%d\n", + menus[i]->id, i); + + if (do_dynamic) + (void)fprintf(out_file, "\n#define DYN_MENU_START\t%d", + menu_no); + + (void)fprintf (out_file, "\n#define MAX_STRLEN %d\n" + "#endif\n", max_strlen); + fclose(out_file); + + /* Now the C file */ + out_file = fopen(cname, "w"); + if (out_file == NULL) { + (void)fprintf(stderr, "%s: could not open %s.\n", + prog_name, cname); + exit(1); + } + + /* initial code */ + fprintf(out_file, "#include \"%s\"\n\n", hname); + fprintf(out_file, "%s\n\n", initcode); + + /* data definitions */ + + /* func defs */ + for (i = 0; i < menu_no; i++) { + if (strlen(menus[i]->info->postact.code)) { + (void)fprintf(out_file, "/*ARGSUSED*/\n" + "static void menu_%d_postact(menudesc *menu, void *arg)\n{\n", i); + if (menus[i]->info->postact.endwin) + (void)fprintf(out_file, "\tendwin();\n"); + (void)fprintf(out_file, "\t%s\n}\n\n", + menus[i]->info->postact.code); + } + if (strlen(menus[i]->info->exitact.code)) { + (void)fprintf(out_file, "/*ARGSUSED*/\n" + "static void menu_%d_exitact(menudesc *menu, void *arg)\n{\n", i); + if (menus[i]->info->exitact.endwin) + (void)fprintf(out_file, "\tendwin();\n"); + (void)fprintf(out_file, "\t%s\n}\n\n", + menus[i]->info->exitact.code); + } + j = 0; + toptn = menus[i]->info->optns; + for (; toptn != NULL; j++, toptn = toptn->next) { + if (strlen(toptn->optact.code) == 0) + continue; + + (void)fprintf(out_file, "/*ARGSUSED*/\n" + "static int opt_act_%d_%d(menudesc *m, void *arg)\n" + "{\n\t%s\n\treturn %s;\n}\n\n", + i, j, toptn->optact.code, + (toptn->doexit ? "1" : "0")); + } + + } + + /* optentX */ + for (i = 0; i < menu_no; i++) { + if (menus[i]->info->numopt > 53) { + (void)fprintf(stderr, "Menu %s has " + "too many options.\n", + menus[i]->info->title); + exit(1); + } + (void)fprintf(out_file, "static menu_ent optent%d[] = {\n", i); + name_is_code = 0; + for (j = 0, toptn = menus[i]->info->optns; toptn; + toptn = toptn->next, j++) { + name_is_code += toptn->name_is_code; + (void)fprintf(out_file, "\t{%s,%d,%d,", + toptn->name_is_code ? "0" : toptn->name, + toptn->menu, + (toptn->issub ? OPT_SUB : 0) + +(toptn->doexit ? OPT_EXIT : 0) + +(toptn->optact.endwin ? OPT_ENDWIN : 0)); + if (strlen(toptn->optact.code)) + (void)fprintf(out_file, "opt_act_%d_%d}", i, j); + else + (void)fprintf(out_file, "NULL}"); + (void)fprintf(out_file, "%s\n", + (toptn->next ? "," : "")); + } + (void)fprintf(out_file, "\t};\n\n"); + + if (name_is_code) { + menus[i]->info->name_is_code = 1; + fprintf(out_file, "static void menu_%d_legend(" + "menudesc *menu, int opt, void *arg)\n{\n" + "\tswitch (opt) {\n", i); + for (j = 0, toptn = menus[i]->info->optns; toptn; + toptn = toptn->next, j++) { + if (!toptn->name_is_code) + continue; + fprintf(out_file, "\tcase %d:\n\t\t{%s};\n" + "\t\tbreak;\n", j, toptn->name); + } + fprintf(out_file, "\t}\n}\n\n"); + } + } + + + /* menus */ + if (!do_dynamic) + (void)fprintf(out_file, "static int num_menus = %d;\n", + menu_no); + + (void)fprintf(out_file, "static struct menudesc menu_def[] = {\n"); + for (i = 0; i < menu_no; i++) { + (void)fprintf(out_file, + "\t{%s,%d,%d,%d,%d,%d,%d,0,0,optent%d,NULL,NULL,", + menus[i]->info->title, menus[i]->info->y, + menus[i]->info->x, menus[i]->info->h, + menus[i]->info->w, menus[i]->info->mopt, + menus[i]->info->numopt, i); + if (menus[i]->info->helpstr == NULL) + (void)fprintf(out_file, "NULL"); + else { + tmpstr = menus[i]->info->helpstr; + if (*tmpstr != '"') + (void)fprintf(out_file, "%s", tmpstr); + else { + /* Skip an initial newline. */ + if (tmpstr[1] == '\n') + *++tmpstr = '"'; + (void)fprintf(out_file, "\n"); + while (*tmpstr) { + if (*tmpstr != '\n') { + fputc(*tmpstr++, out_file); + continue; + } + (void)fprintf(out_file, "\\n\"\n\""); + tmpstr++; + } + } + } + (void)fprintf(out_file, ","); + if (menus[i]->info->mopt & MC_NOEXITOPT) + (void) fprintf (out_file, "NULL"); + else if (menus[i]->info->exitstr != NULL) + (void)fprintf(out_file, "%s", menus[i]->info->exitstr); + else + (void)fprintf(out_file, "\"Exit\""); + if (strlen(menus[i]->info->postact.code)) + (void)fprintf(out_file, ",menu_%d_postact", i); + else + (void)fprintf(out_file, ",NULL"); + if (strlen(menus[i]->info->exitact.code)) + (void)fprintf(out_file, ",menu_%d_exitact", i); + else + (void)fprintf(out_file, ",NULL"); + if (menus[i]->info->name_is_code) + (void)fprintf(out_file, ",menu_%d_legend", i); + else + (void)fprintf(out_file, ",NULL"); + + (void)fprintf(out_file, "},\n"); + + } + (void)fprintf(out_file, "{NULL, 0, 0, 0, 0, 0, 0, 0, 0, " + "NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};\n\n"); + + /* __menu_initerror: initscr failed. */ + (void)fprintf(out_file, + "/* __menu_initerror: initscr failed. */\n" + "void __menu_initerror (void) {\n"); + if (error_act.code == NULL) { + (void)fprintf(out_file, + "\t(void) fprintf (stderr, " + "\"%%s: Could not initialize curses\\n\", " + "getprogname());\n" + "\texit(1);\n" + "}\n"); + } else { + if (error_act.endwin) + (void)fprintf(out_file, "\tendwin();\n"); + (void)fprintf(out_file, "%s\n}\n", error_act.code); + } + + /* Copy menu_sys.def file. */ + while ((ch = fgetc(sys_file)) != '\014') /* Control-L */ + fputc(ch, out_file); + + if (do_dynamic) { + while ((ch = fgetc(sys_file)) != '\n') + /* skip it */; + while ((ch = fgetc(sys_file)) != EOF) + fputc(ch, out_file); + } + fclose(out_file); + fclose(sys_file); +} diff --git a/usr.bin/menuc/mdb.h b/usr.bin/menuc/mdb.h new file mode 100644 index 000000000..e4ce8208f --- /dev/null +++ b/usr.bin/menuc/mdb.h @@ -0,0 +1,98 @@ +/* $NetBSD: mdb.h,v 1.9 2012/03/06 16:55:18 mbalmer Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* mdb.h - definitions for the menu database. */ + +#ifndef MDB_H +#define MDB_H + +/* forward declaration */ +typedef struct menu_info menu_info; + +/* The declarations for the balanced binary trees. */ + +typedef struct id_rec { + /* The balanced binary tree fields. */ + char *id; /* The name. */ + short balance; /* For the balanced tree. */ + struct id_rec *left, *right; /* Tree pointers. */ + + /* Other information fields. */ + menu_info *info; + int menu_no; +} id_rec; + + +/* menu definitions records. */ + +typedef struct action { + char *code; + int endwin; +} action; + +typedef struct optn_info { + char *name; + int name_is_code; + int menu; + int issub; + int doexit; + action optact; + struct optn_info *next; +} optn_info; + +struct menu_info { + char *title; + char *helpstr; + char *exitstr; + int mopt; + int y, x; + int h, w; + int numopt; + int name_is_code; + optn_info *optns; + action postact; + action exitact; +}; + +/* defines for mopt */ +#define MC_NOEXITOPT 1 +#define MC_NOBOX 2 +#define MC_SCROLL 4 +#define MC_NOSHORTCUT 8 +#define MC_NOCLEAR 16 +#define MC_DFLTEXIT 32 +#define MC_ALWAYS_SCROLL 64 +#define MC_SUBMENU 128 +#define MC_VALID 0x10000 +#endif diff --git a/usr.bin/menuc/menu_sys.def b/usr.bin/menuc/menu_sys.def new file mode 100644 index 000000000..4bebc16e1 --- /dev/null +++ b/usr.bin/menuc/menu_sys.def @@ -0,0 +1,827 @@ +/* $NetBSD: menu_sys.def,v 1.59 2012/03/06 16:55:18 mbalmer Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* menu_sys.defs -- Menu system standard routines. */ + +#include +#include + +#define REQ_EXECUTE 1000 +#define REQ_NEXT_ITEM 1001 +#define REQ_PREV_ITEM 1002 +#define REQ_REDISPLAY 1003 +#define REQ_SCROLLDOWN 1004 +#define REQ_SCROLLUP 1005 +#define REQ_HELP 1006 + +/* Macros */ +#define MAX(x,y) ((x)>(y)?(x):(y)) +#define MIN(x,y) ((x)<(y)?(x):(y)) + +/* Initialization state. */ +static int __menu_init = 0; +static int max_lines = 0, max_cols = 0; +#ifndef scrolltext +static const char *scrolltext = " <: page up, >: page down"; +#endif + +#ifdef DYNAMIC_MENUS +static int num_menus = 0; +#define DYN_INIT_NUM 32 +static menudesc **menu_list; +#define MENUS(n) (*(menu_list[n])) +#else +#define MENUS(n) (menu_def[n]) +#endif + +/* prototypes for in here! */ +static void init_menu(menudesc *m); +static char opt_ch(menudesc *m, int op_no); +static void draw_menu(menudesc *m, void *arg); +static void process_help(menudesc *m); +static void process_req(menudesc *m, void *arg, int req); +static int menucmd(WINDOW *w); + +#ifndef NULL +#define NULL 0 +#endif + +/* menu system processing routines */ +#define mbeep() (void)fputc('\a', stderr) + +static int +menucmd(WINDOW *w) +{ + int ch; + + while (TRUE) { + ch = wgetch(w); + + switch (ch) { + case '\n': + return REQ_EXECUTE; + case '\016': /* Control-P */ + case KEY_DOWN: + return REQ_NEXT_ITEM; + case '\020': /* Control-N */ + case KEY_UP: + return REQ_PREV_ITEM; + case '\014': /* Control-L */ + return REQ_REDISPLAY; + case '<': + case '\010': /* Control-H (backspace) */ + case KEY_PPAGE: + case KEY_LEFT: + return REQ_SCROLLUP; + case '\026': /* Control-V */ + case '>': + case ' ': + case KEY_NPAGE: + case KEY_RIGHT: + return REQ_SCROLLDOWN; + case '?': + return REQ_HELP; + case '\033': /* esc-v is scroll down */ + ch = wgetch(w); + if (ch == 'v') + return REQ_SCROLLUP; + else + ch = 0; /* zap char so we beep */ + } + + if (isalpha(ch)) + return ch; + + mbeep(); + wrefresh(w); + } +} + +static void +init_menu(menudesc *m) +{ + int wmax; + int hadd, wadd, exithadd; + int i; + int x, y, w; + const char *title, *tp, *ep; + + x = m->x; + y = m->y; + w = m->w; + wmax = 0; + hadd = ((m->mopt & MC_NOBOX) ? 0 : 2); + wadd = ((m->mopt & MC_NOBOX) ? 2 : 4); + if (!(m->mopt & MC_NOSHORTCUT)) + wadd += 3; + + if (m->title && *(title = MSG_XLAT(m->title)) != 0) { + /* Allow multiple line titles */ + for (tp = title; (ep = strchr(tp, '\n')); tp = ep + 1) { + i = ep - tp; + wmax = MAX(wmax, i); + hadd++; + } + hadd++; + i = strlen(tp); + wmax = MAX(wmax, i); + if (i != 0) + hadd++; + } else { + m->title = NULL; + title = "untitled"; + } + exithadd = ((m->mopt & MC_NOEXITOPT) ? 0 : 1); + +#ifdef MSG_DEFS_H + if (y < 0) { + /* put menu box below message text */ + y = -y; + i = msg_row(); + if (i > y) + y = i; + } +#endif + + /* Calculate h? h == number of visible options. */ + if (m->h == 0) + m->h = m->numopts + exithadd; + + if (m->h > max_lines - y - hadd) { + /* Not enough space for all the options */ + if (m->h <= 4 || !(m->mopt & (MC_SCROLL | MC_ALWAYS_SCROLL))) { + /* move menu up screen */ + y = max_lines - hadd - m->h; + if (y < 0) + y = 0; + } + m->h = max_lines - y - hadd; + } + + if (m->h < m->numopts + exithadd || m->mopt & MC_ALWAYS_SCROLL) { + /* We need to add the scroll text... + * The used to be a check for MC_SCROLL here, but it is + * fairly pointless - you just don't want the program + * to exit on this sort of error. + */ + if (m->h < 3) { + endwin(); + (void)fprintf(stderr, + "Window too short (m->h %d, m->numopts %d, exithadd %d, y %d, max_lines %d, hadd %d) for menu \"%.30s\"\n", + m->h, m->numopts, exithadd, y, max_lines, hadd, + title); + exit(1); + } + hadd++; + m->h = MIN(m->h, max_lines - y - hadd); + i = strlen(scrolltext); + wmax = MAX(wmax, i); + } + + /* Calculate w? */ + if (w == 0) { + int l; + for (i = 0; i < m->numopts; i++) { + tp = MSG_XLAT(m->opts[i].opt_name); + if (tp == NULL) + continue; + l = strlen(tp); + wmax = MAX(wmax, l); + } + w = wmax; + } + + /* check and adjust for screen fit */ + if (w + wadd > max_cols) { + endwin(); + (void)fprintf(stderr, + "Screen too narrow (%d + %d > %d) for menu \"%s\"\n", + w, wadd, max_cols, title); + exit(1); + + } + + if (x == -1) + x = (max_cols - (w + wadd)) / 2; /* center */ + else if (x + w + wadd > max_cols) + x = max_cols - (w + wadd); /* right align */ + + if (y == 0) { + /* Center - rather than top */ + y = (max_lines - hadd - m->h) / 2; + } + + /* Get the windows. */ + m->mw = newwin(m->h + hadd, w + wadd, y, x); + + if (m->mw == NULL) { + endwin(); + (void)fprintf(stderr, + "Could not create window (%d + %d, %d + %d, %d, %d) for menu \"%s\"\n", + m->h, hadd, w, wadd, y, x, title); + exit(1); + } + keypad(m->mw, TRUE); /* enable multi-key assembling for win */ + + /* XXX is it even worth doing this right? */ + if (has_colors()) { + wbkgd(m->mw, COLOR_PAIR(1)); + wattrset(m->mw, COLOR_PAIR(1)); + } + + if (m->mopt & MC_SUBMENU) { + /* Keep a copy of what is on the screen under the window */ + m->sv_mw = newwin(m->h + hadd, w + wadd, y, x); + /* + * cursrc contains post-doupdate() data, not post-refresh() + * data so we must call doupdate to ensure we save the + * correct data. Avoids PR 26660. + */ + doupdate(); + if (m->sv_mw) + overwrite(curscr, m->sv_mw); + } +} + +static char +opt_ch(menudesc *m, int op_no) +{ + char c; + + if (op_no == m->numopts) + return 'x'; + + if (op_no < 25) { + c = 'a' + op_no; + if (c >= 'x') + c++; + } else + c = 'A' + op_no - 25; + return c; +} + +static void +draw_menu_line(menudesc *m, int opt, int cury, void *arg, const char *text) +{ + int hasbox = m->mopt & MC_NOBOX ? 0 : 1; + + if (m->cursel == opt) { + mvwaddstr(m->mw, cury, hasbox, ">"); + wstandout(m->mw); + } else + mvwaddstr(m->mw, cury, hasbox, " "); + if (!(m->mopt & MC_NOSHORTCUT)) + wprintw(m->mw, "%c: ", opt_ch(m, opt)); + + if (!text && m->draw_line) + m->draw_line(m, opt, arg); + else + waddstr(m->mw, MSG_XLAT(text)); + if (m->cursel == opt) + wstandend(m->mw); +} + +static void +draw_menu(menudesc *m, void *arg) +{ + int opt; + int hasbox, cury, maxy; + int tadd; + int hasexit = (m->mopt & MC_NOEXITOPT ? 0 : 1); + const char *tp, *ep; + + hasbox = (m->mopt & MC_NOBOX ? 0 : 1); + + /* Clear the window */ + wclear(m->mw); + + tadd = hasbox; + if (m->title) { + for (tp = MSG_XLAT(m->title); ; tp = ep + 1) { + ep = strchr(tp , '\n'); + mvwaddnstr(m->mw, tadd++, hasbox + 1, tp, + ep ? ep - tp : -1); + if (ep == NULL || *ep == 0) + break; + } + tadd++; + } + + cury = tadd; + maxy = getmaxy(m->mw) - hasbox; + if (m->numopts + hasexit > m->h) + /* allow for scroll text */ + maxy--; + + if (m->cursel == -1) { + m->cursel = m->numopts; + if (m->h <= m->numopts) + m->topline = m->numopts + 1 - m->h; + } + + while (m->cursel >= m->topline + m->h) + m->topline = MIN(m->topline + m->h, + m->numopts + hasexit - m->h); + while (m->cursel < m->topline) + m->topline = MAX(0, m->topline - m->h); + + for (opt = m->topline; opt < m->numopts; opt++) { + if (cury >= maxy) + break; + draw_menu_line(m, opt, cury++, arg, m->opts[opt].opt_name); + } + + /* Add the exit option. */ + if (!(m->mopt & MC_NOEXITOPT)) { + if (cury < maxy) + draw_menu_line(m, m->numopts, cury++, arg, m->exitstr); + else + opt = 0; + } + + /* Add the scroll line */ + if (opt != m->numopts || m->topline != 0) + mvwaddstr(m->mw, cury, hasbox, scrolltext); + + /* Add the box. */ + if (!(m->mopt & MC_NOBOX)) + box(m->mw, 0, 0); + + wmove(m->mw, tadd + m->cursel - m->topline, hasbox); + wrefresh(m->mw); +} + + +static void +/*ARGSUSED*/ +process_help(menudesc *m) +{ + const char *help = m->helpstr; + WINDOW *sv_curscr; + int lineoff = 0; + int curoff = 0; + int again; + int winin; + + /* Is there help? */ + if (!help) { + mbeep(); + return; + } + sv_curscr = newwin(getmaxy(curscr), getmaxx(curscr), 0, 0); + if (!sv_curscr) { + mbeep(); + return; + } + /* + * Save screen contents so we can restore before returning. + * cursrc contains post-doupdate() data, not post-refresh() + * data so we must call doupdate to ensure we save the + * correct data. Avoids PR 26660. + */ + doupdate(); + overwrite(curscr, sv_curscr); + touchwin(stdscr); + + help = MSG_XLAT(help); + /* Display the help information. */ + do { + if (lineoff < curoff) { + help = MSG_XLAT(m->helpstr); + curoff = 0; + } + while (*help && curoff < lineoff) { + if (*help == '\n') + curoff++; + help++; + } + + wclear(stdscr); + mvwaddstr(stdscr, 0, 0, + "Help: exit: x, page up: u <, page down: d >"); + mvwaddstr(stdscr, 2, 0, help); + wmove(stdscr, 1, 0); + wrefresh(stdscr); + + do { + winin = wgetch(stdscr); + if (winin < KEY_MIN) + winin = tolower(winin); + again = 0; + switch (winin) { + case '<': + case 'u': + case KEY_UP: + case KEY_LEFT: + case KEY_PPAGE: + if (lineoff) + lineoff -= max_lines - 2; + else + again = 1; + break; + case '>': + case 'd': + case KEY_DOWN: + case KEY_RIGHT: + case KEY_NPAGE: + if (*help) + lineoff += max_lines - 2; + else + again = 1; + break; + case 'q': + break; + case 'x': + winin = 'q'; + break; + default: + again = 1; + } + if (again) + mbeep(); + } while (again); + } while (winin != 'q'); + + /* Restore the original screen contents */ + touchwin(sv_curscr); + wnoutrefresh(sv_curscr); + delwin(sv_curscr); + + /* Some code thinks that wrefresh(stdout) is a good idea... */ + wclear(stdscr); +} + +static void +process_req(menudesc *m, void *arg, int req) +{ + int ch; + int hasexit = (m->mopt & MC_NOEXITOPT ? 0 : 1); + + switch(req) { + + case REQ_EXECUTE: + return; + + case REQ_NEXT_ITEM: + ch = m->cursel; + for (;;) { + ch++; + if (ch >= m->numopts + hasexit) { + mbeep(); + return; + } + if (hasexit && ch == m->numopts) + break; + if (!(m->opts[ch].opt_flags & OPT_IGNORE)) + break; + } + m->cursel = ch; + if (m->cursel >= m->topline + m->h) + m->topline = m->cursel - m->h + 1; + break; + + case REQ_PREV_ITEM: + ch = m->cursel; + for (;;) { + if (ch <= 0) { + mbeep(); + return; + } + ch--; + if (!(m->opts[ch].opt_flags & OPT_IGNORE)) + break; + } + m->cursel = ch; + if (m->cursel < m->topline) + m->topline = m->cursel; + break; + + case REQ_HELP: + process_help(m); + break; + + case REQ_REDISPLAY: + endwin(); + doupdate(); + break; + + case REQ_SCROLLUP: + if (m->cursel == 0) { + mbeep(); + return; + } + m->topline = MAX(0, m->topline - m->h); + m->cursel = MAX(0, m->cursel - m->h); + wclear(m->mw); + break; + + case REQ_SCROLLDOWN: + if (m->cursel >= m->numopts + hasexit - 1) { + mbeep(); + return; + } + m->topline = MIN(m->topline + m->h, + MAX(m->numopts + hasexit - m->h, 0)); + m->cursel = MIN(m->numopts + hasexit - 1, m->cursel + m->h); + wclear(m->mw); + break; + + default: + ch = req; + if (ch == 'x' && hasexit) { + m->cursel = m->numopts; + break; + } + if (m->mopt & MC_NOSHORTCUT) { + mbeep(); + return; + } + if (ch > 'z') + ch = 255; + if (ch >= 'a') { + if (ch > 'x') + ch--; + ch = ch - 'a'; + } else + ch = 25 + ch - 'A'; + if (ch < 0 || ch >= m->numopts) { + mbeep(); + return; + } + if (m->opts[ch].opt_flags & OPT_IGNORE) { + mbeep(); + return; + } + m->cursel = ch; + } + + draw_menu(m, arg); +} + +int +menu_init(void) +{ + int i; + + if (__menu_init) + return 0; + +#ifdef USER_MENU_INIT + if (USER_MENU_INIT) + return 1; +#endif + + if (initscr() == NULL) + return 1; + + cbreak(); + noecho(); + + /* XXX Should be configurable but it almost isn't worth it. */ + if (has_colors()) { + start_color(); + init_pair(1, COLOR_WHITE, COLOR_BLUE); + bkgd(COLOR_PAIR(1)); + attrset(COLOR_PAIR(1)); + } + + max_lines = getmaxy(stdscr); + max_cols = getmaxx(stdscr); + keypad(stdscr, TRUE); +#ifdef DYNAMIC_MENUS + num_menus = DYN_INIT_NUM; + while (num_menus < DYN_MENU_START) + num_menus *= 2; + menu_list = malloc(sizeof *menu_list * num_menus); + if (menu_list == NULL) + return 2; + (void)memset(menu_list, 0, sizeof *menu_list * num_menus); + for (i = 0; i < DYN_MENU_START; i++) + menu_list[i] = &menu_def[i]; +#endif + + __menu_init = 1; + return 0; +} + +void +process_menu(int num, void *arg) +{ + int sel = 0; + int req; + menu_ent *opt; + + menudesc *m; + + /* Initialize? */ + if (menu_init()) { + __menu_initerror(); + return; + } + + if (num < 0 || num >= num_menus) + return; + m = &MENUS(num); + if (m == NULL) + return; + + /* Default to select option 0 and display from 0 */ + m->topline = 0; + if ((m->mopt & (MC_DFLTEXIT | MC_NOEXITOPT)) == MC_DFLTEXIT) + m->cursel = -1; + else + m->cursel = 0; + + for (;;) { + if (isendwin()) + /* I'm not sure this is needed with netbsd's curses */ + doupdate(); + /* Process the display action */ + if (m->post_act) + (*m->post_act)(m, arg); + if (m->mw == NULL) + init_menu(m); + draw_menu(m, arg); + + while ((req = menucmd(m->mw)) != REQ_EXECUTE) + process_req(m, arg, req); + + sel = m->cursel; + if (!(m->mopt & MC_NOCLEAR)) { + wclear(m->mw); + if (m->sv_mw) + overwrite(m->sv_mw, m->mw); + wnoutrefresh(m->mw); + } + + /* Process the items */ + if (sel >= m->numopts) + /* exit option */ + break; + + opt = &m->opts[sel]; + if (opt->opt_flags & OPT_IGNORE) + continue; + if (opt->opt_flags & OPT_ENDWIN) + endwin(); + if (opt->opt_action && (*opt->opt_action)(m, arg)) + break; + + if (opt->opt_menu != -1) { + if (!(opt->opt_flags & OPT_SUB)) { + num = opt->opt_menu; + wclear(m->mw); + if (m->sv_mw) { + overwrite(m->sv_mw, m->mw); + delwin(m->sv_mw); + m->sv_mw = NULL; + } + wnoutrefresh(m->mw); + delwin(m->mw); + m->mw = NULL; + m = &MENUS(num); + continue; + } + process_menu(opt->opt_menu, arg); + } + if (opt->opt_flags & OPT_EXIT) + break; + } + + if (m->mopt & MC_NOCLEAR) { + wclear(m->mw); + if (m->sv_mw) + overwrite(m->sv_mw, m->mw); + wnoutrefresh(m->mw); + } + + /* Process the exit action */ + if (m->exit_act) + (*m->exit_act)(m, arg); + delwin(m->mw); + m->mw = NULL; + if (m->sv_mw) { + delwin(m->sv_mw); + m->sv_mw = NULL; + } +} + + +void +set_menu_numopts(int menu, int numopts) +{ + + MENUS(menu).numopts = numopts; +} + + /* Control L is end of standard routines, remaining only for dynamic. */ + +/* Beginning of routines for dynamic menus. */ + +static int +double_menus(void) +{ + menudesc **temp; + int sz = sizeof *menu_list * num_menus; + + temp = realloc(menu_list, sz * 2); + if (temp == NULL) + return 0; + (void)memset(temp + num_menus, 0, sz); + menu_list = temp; + num_menus *= 2; + + return 1; +} + +int +new_menu(const char *title, menu_ent *opts, int numopts, + int x, int y, int h, int w, int mopt, + void (*post_act)(menudesc *, void *), + void (*draw_line)(menudesc *, int, void *), + void (*exit_act)(menudesc *, void *), + const char *help, const char *exit_str) +{ + int ix; + menudesc *m; + + /* Find free menu entry. */ + for (ix = DYN_MENU_START; ; ix++) { + if (ix >= num_menus && !double_menus()) + return -1; + m = menu_list[ix]; + if (m == NULL) { + m = calloc(sizeof *m, 1); + if (m == NULL) + return -1; + menu_list[ix] = m; + break; + } + if (!(m->mopt & MC_VALID)) + break; + } + + /* Set Entries */ + m->title = title; + m->opts = opts; + m->numopts = numopts; + m->x = x; + m->y = y; + m->h = h; + m->w = w; + m->mopt = mopt | MC_VALID; + m->post_act = post_act; + m->draw_line = draw_line; + m->exit_act = exit_act; + m->helpstr = help; + m->exitstr = exit_str ? exit_str : "Exit"; + + return ix; +} + +void +free_menu(int menu_no) +{ + menudesc *m; + + if (menu_no < 0 || menu_no >= num_menus) + return; + + m = menu_list[menu_no]; + if (!(m->mopt & MC_VALID)) + return; + if (m->mw != NULL) + delwin(m->mw); + memset(m, 0, sizeof *m); +} diff --git a/usr.bin/menuc/menuc.1 b/usr.bin/menuc/menuc.1 new file mode 100644 index 000000000..37bb4ba33 --- /dev/null +++ b/usr.bin/menuc/menuc.1 @@ -0,0 +1,544 @@ +.\" $NetBSD: menuc.1,v 1.30 2012/03/06 16:55:18 mbalmer Exp $ +.\" +.\" Copyright 1997 Piermont Information Systems Inc. +.\" All rights reserved. +.\" +.\" Written by Philip A. Nelson for Piermont Information Systems Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of Piermont Information Systems Inc. may not be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' +.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +.\" THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 2, 2004 +.Dt MENUC 1 +.Os +.Sh NAME +.Nm menuc +.Nd menu compiler +.Sh SYNOPSIS +.Nm +.Op Fl o Ar name +.Ar file +.Sh DESCRIPTION +This implements a curses based menu system. +A source file that describes menus, their options, and how to process +the options is given to +.Nm +and produces both a .c and a .h file that implement the menu system. +The standard base name of the files is +.Pa menu_defs . +The +.Fl o Ar name +can be used to specify a different base name. +.Sh ENVIRONMENT +.Bl -tag -width MENUDEF +.It Ev MENUDEF +Can be set to point to a different set of definition files for +.Nm . +The current location defaults to +.Pa /usr/share/misc . +.El +.Sh MENU DESCRIPTIONS +The input +.Ar file +defines static menus and options for processing those menus. +It also contains comments, initial C code that is required to provide +for definitions and other code necessary for the menu system, and an +option declaration if dynamic menus are requested. +.Pp +Comments may appear anywhere in the input +.Ar file +and are like a space in the input. +They are like C comments starting with +.Em /* +and ending with +.Em */ . +They are unlike C comments in that they may be nested. +A comment does not end until a matching end comment is found. +.Pp +In many places, C code is included in the definition +.Ar file . +All C code is passed verbatim to the C output file. +.Nm +comments do not start in C code and comments in the C code are +passed verbatim to the output. +The C comments are not recognized by +.Nm . +In all cases, C code starts with a left brace +.Pq Em \&{ +and ends with the matching right brace +.Pq Em \&} . +It is important to recognize that in code segments, any brace +will be counted, even if it is in a C comment inside the code. +.Pp +The +.Ar file +contains an initial (and optional) code block followed by any +number of menu definition elements in any order. +The initial code block usually contains includes of header files used by +code in the menu code blocks later in the +.Ar file . +If +.Dv USER_MENU_INIT +is #defined, then it will be evaluated before the +rest of the menu is initialised, if it evaluates to a non-zero value +then the initialisation will fail. +The file is free format, so the actual formatting of the input +.Ar file +is to the taste of the programmer. +.Pp +All other C code that will appear in an +.Em action . +This will be specified as +.Aq Em action +in later text. +Such an action will appear as: +.Dl action \*[Lt]opt_endwin\*[Gt] \*[Lt]code\*[Gt] +in the +.Ar file . +The +.Aq Em opt_endwin , +if present is: +.Dl ( endwin ) +and specifies that the curses +.Fn endwin +function should be called before executing the code and +then reinstating the current curses window after the +code has been run. +The +.Aq Em code +is as described above. +.Pp +There are four kinds of menu definition elements. +The first one just declares whether the programmer wants dynamic menus +available. +The default is static menus only. +The static menus are the ones defined by the menu definitions and do not +change at run time. +The dynamic menus provide the programmer with a method to create and +modify menus during the running of the program. +To include dynamic menus, one needs only add the declaration: +.Dl allow dynamic menus ; +The semicolon is required to terminate this declaration. +This declaration may appear anywhere in the +.Ar file , +but usually appears before any menus are defined. +.Pp +The next element is a code block to execute if the curses +screen can not be successfully initialized. +The declaration +.Dl error code ; +tells the menu system to execute the associated code block +if the initialization fails. +If no code is provided, a default code block is used that prints +.Dl Could not initialize curses. +and exits. +This element may appear anywhere in the +.Ar file +but usually appears before any menus are defined. +.Pp +The next element defines default options for menus. +Each menu is built from a list of options. +These options include the location of the upper left corner of the menu, +whether there is a "box" drawn around the menu, whether the menu is +scrollable, the menu's title, whether shortcut letters are +allowed, whether a standard exit option should be included +in the menu and text associated with the standard exit option. +The general format is: +.Dl default \*[Lt]comma separated option list\*[Gt] ; +.Pp +The supported options are: +.Bl -tag -width ".Ic exitstring Va text" +.It Ic x = Va startx +The column number of the upper left corner of the menu window. +If +.Va startx +is -1 the menu will be centered horizontally. +.It Ic y = Va starty +The row number of the upper left corner of the menu window. +If +.Va starty +is negative then the menu will be placed below any message text, but +in at least row +.Va -starty . +.It Ic h = Va height +Specifies the number of menu entries to be displayed. +If zero, the height will be based on the number of entries. +.It Ic h = Va width +Specifies the width of the menu window. +If zero, the width will be that of the longest menu text line. +.It Ic title Va text +The specified +.Va text +will be displayed at the top of the menu window (inside any box). +.It Ic box +If specified, draw a box around the menu. +.It Ic clear +If specified, clear the window before performing the +.Va action . +.It Ic exit +If specified add an addition option to exit the menu. +.It Ic exitstring Va text +The menu label for the +.Va exit +option. +If not specified defaults to "exit". +.It Ic default exit +If specified, place the cursor on the +.Va exit +line of the menu, instead of the top line. +.It Ic shortcut +If specified, add alphabetic tags to each menu line. +.It Ic scrollable +If specified, and the menu has more lines than will fit in its window, then +only part of the menu will be displayed and the +.Sq \*[Lt] +and +.Sq \*[Gt] +keys will scroll the displayed menu lines. +.It Ic always scroll +If specified, allow for the scroll message line even if the menu doesn't +appear to have too many lines. +Useful for dynamic menus, when the number of entries isn't known when the +menu window is created.. +.It Ic sub menu +If specified, the screen contents that the menu window overwrites are saved +and restored when the menu exits. +.El +The +.Ic box , clear , exit , default exit , shortcut , scrollable , always scroll , +and +.Ic sub menu +options can be preceded by +.Ic no +in order to negate a default. +.Pp +The +.Va text +arguments can be either a quoted text string or a name #defined to something +suitable for initialising a const char * field. +.Pp +The default declaration may appear multiple times. +Each time, it sets the default values for menu definitions that follow +in the +.Ar file . +In each menu definition, any or all of these default definitions +may be overridden for that menu. +.Pp +The final element is the actual static menu definitions. +The format and order for a menu definition is: +.Bd -ragged -offset indent +menu \*[Lt]name\*[Gt] \*[Lt]options\*[Gt] ; + \*[Lt]display action\*[Gt] + \*[Lt]menu items\*[Gt] + \*[Lt]exit action\*[Gt] + \*[Lt]help text\*[Gt] +.Ed +.Pp +Names are unquoted strings of alpha-numeric and underscore +characters. +They must start with an alpha character. +In C source, a menu named +.Dq foo +is appears as +.Dq MENU_foo . +(Capitalization is important.) +This is important, because the menu is displayed and processed by +calling the function +.Dl process_menu (MENU_foo, arg) ; +.Pp +The options are a comma separated list of options as in the +.Dq default +declaration. +These override the options from the most recent default declaration. +.Pp +The display action is optional and provides C code to +execute at each and every time the menu is displayed for processing. +If it is included, the format is: +.Dl display \*[Lt]action\*[Gt] ; +.Pp +The bulk of the menu definition is the specification +of the menu items. +The general format of a menu item is: +.Dl option \*[Lt]string\*[Gt], \*[Lt]element_list\*[Gt] ; +The +.Aq Em string +is the text displayed for the menu item, this must be a quoted string +or a name #defined to something that will initialise a const char * field. +There may be an arbitrary number of these items. +(If there are shortcuts in the menu, a practical limit +of 51 should be recognized. +It produces shortcuts a to w, y, z, and A to Z. +x is the shortcut for the exit item.) +.Pp +The +.Aq Em element_list +is a comma separated list of what to do when the item is selected. +They may appear in any order. +.Pp +The first element processed when a menu item +is selected is the associated action. +The next element to be processed is the sub or next menu option. +They are declared as: +.Dl next menu \*[Lt]name\*[Gt] +.Dl sub menu \*[Lt]name\*[Gt] +The difference between these two is that a sub +menu will return to the current menu when exited. +The next menu will just replace the current +menu and when exited, will return to where the +current menu would have gone. +Only one of menu element may be used for each menu item. +Finally, after processing both the action and a sub menu, +the current menu will be exited if the element +.Dl exit +is specified. +.Em Note : +If +.Em exit +is specified, next menu will not work because +the menu system will exit the +.Em current +menu, even if current has been set by +.Em next menu . +.Pp +After all menu items, the final two menu definition +elements may appear. +The exit action is optional and provides C code to +execute in the process of exiting a menu. +If it is included, the format is: +.Dl exit \*[Lt]action\*[Gt] ; +.Pp +The final part of the menu definition is the optional +help string. +The format is: +.Dl help \*[Lt]text\*[Gt] ; +This text is displayed in a full page +help window if the question mark is typed. +The actual help text starts with a left brace +.Pq Em \&{ +and ends with the matching right brace +.Pq Em \&} . +The braces are not included in the +help string, but all other characters between +them are included. +Newlines in the code translate to newlines in the help text. +Alternatively, the name of a const char * variable may be given. +.Sh DYNAMIC MENUS +If requested, +.Nm +supports dynamic menus by allowing the user to create new +menus. +The related definitions for using dynamic menus are: +.Bd -literal +struct menudesc; + +typedef +struct menu_ent { + const char *opt_name; + int opt_menu; + int opt_flags; + int (*opt_action)(struct menudesc *, void *); +} menu_ent ; + +/* For opt_menu */ +#define OPT_NOMENU -1 + +/* For opt_flags */ +#define OPT_SUB 1 +#define OPT_ENDWIN 2 +#define OPT_EXIT 4 + +typedef +struct menudesc { + const char *title; + int y, x; + int h, w; + int mopt; + int numopts; + int cursel; + int topline; + menu_ent *opts; + WINDOW *mw; + WINDOW *sv_mw; + const char *helpstr; + const char *exitstr; + void (*post_act)(struct menudesc *, void *); + void (*exit_act)(struct menudesc *, void *); + void (*draw_line)(struct menudesc *, int, void *); +} menudesc ; + +/* defines for mopt field. */ +#define MC_NOEXITOPT 1 +#define MC_NOBOX 2 +#define MC_SCROLL 4 +#define MC_NOSHORTCUT 8 +#define MC_NOCLEAR 16 +#define MC_DFLTEXIT 32 +#define MC_ALWAYS_SCROLL 64 +#define MC_SUBMENU 128 + +int new_menu(const char *title, menu_ent *opts, int numopts, + int x, int y, int h, int w, int mopt, + void (*post_act)(struct menudesc *, void *), + void (*draw_line)(struct menudesc *, int, void *), + void (*exit_act)(struct menudesc *, void *), + const char *help, const char *exitstr); + +void free_menu (int menu_no); +.Ed +.Pp +The +.Ar title +is the title displayed at the top of the menu. +The +.Ar opts +is an array of menu entry definitions that has +.Ar numopts +elements. +The programmer must build this array and +fill in all of the fields before processing calling +.Fn process_menu +for the new menu. +The fields of the +.Ar opts +may change at any time. +For example, +.Em opt_name +may change as a result of selecting that option. +When the menu is redisplayed, the new text is printed. +Arguments, +.Ar x , y , h , +and +.Ar w +are the same as the options in the menu description. +.Ar mopt +is the boolean options. +Note, box, clear, exit and shortcuts are enabled by default. +You need to add option flags to turn them off or turn on scrollable menus. +The options +.Ar post_act , +and +.Ar exit_act +are function pointers to the display action and the exit action. +If they are +.Dv NULL , +no call will be made. +.Ar draw_line +will be called to display the menu line if the corresponding opt_name +field is +.Dv NULL . +.Ar help +is the text to display in a help screen. +And finally, +.Ar exitstr +is the text for the 'exit' line of the menu. +If +.Dv NULL , +"Exit" is used. +A +.Dv NULL +help pointer will disable the help feature for the menu. +.Sh FILES +.Bl -item +.It +.Pa /usr/share/misc/menu_sys.def +.El +.Sh EXAMPLES +The following is a simple menu definition file. +It is complete in that the output of +.Nm +may be compiled into a complete program. +For example, if the following was in a file called +.Pa example.mc , +an executable program could be produced by the following commands. +.Bd -literal -offset indent +menuc -o example example.mc +cc -o example example.c -lcurses +.Ed +A much more complete example is available with the source +distribution in a subdirectory called +.Em testm . +.Bd -literal +/* This is an example menu definition file for menuc. */ + +{ +#include \*[Lt]stdio.h\*[Gt] +#include \*[Lt]unistd.h\*[Gt] + +/* Main program! This is often in a different file. */ +int +main() + { + process_menu (MENU_main, NULL); + endwin(); + return 0; + } + +/* Example initialize function! */ +void +init_main() + { + } +} + +default x=20, y=10, box, scrollable, exit; + +error action { + fprintf (stderr, "Example Menu: Could not initialize curses."); + exit(1); +}; + +menu main, title "Main Menu", no exit, no shortcut; + display action { init_main(); }; + option "Option 1", + action (endwin) { + printf ("That was option 1!"); + sleep(3); + }; + option "Sub Menu", sub menu othermenu; + option "Next Menu", next menu othermenu; + option "Quit", exit; + help { +This is a simple help screen for an example menu definition file. +}; + +menu othermenu, title "Sub/Next Menu", x=5, y=5, no box; + option "Do Nothing!", action { }; +.Ed +.Sh SEE ALSO +.Xr msgc 1 +.Sh AUTHORS +.An Philip A. Nelson +for Piermont Information Systems Inc. +Initial ideas for this were developed and implemented in Pascal at the +Leiden University, Netherlands, in the summer of 1980. +.Sh BUGS +Both +.Nm +and +.Nm msgc +are probably only used by +.Nm sysinst . +The features of both have been tailored for +.Nm sysinst , +and further changes are likely to occur. diff --git a/usr.bin/menuc/parse.y b/usr.bin/menuc/parse.y new file mode 100644 index 000000000..868c13283 --- /dev/null +++ b/usr.bin/menuc/parse.y @@ -0,0 +1,228 @@ +/* $NetBSD: parse.y,v 1.16 2012/03/06 16:55:18 mbalmer Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +%{ + +#include +#include "defs.h" + +static id_rec *cur_menu; +static optn_info *cur_optn; + +%} + +%union { + char *s_value; + int i_value; + optn_info *optn_value; + action a_value; +} + + +%token X Y W H NO BOX SUB HELP MENU NEXT EXIT ACTION ENDWIN OPTION +%token TITLE DEFAULT DISPLAY ERROR EXITSTRING ALLOW DYNAMIC MENUS + SCROLLABLE SHORTCUT CLEAR MESSAGES ALWAYS SCROLL +%token STRING NAME CODE INT_CONST CHAR_CONST + +%type init_code system helpstr text +%type option option_list +%type act_opt +%type action exitact + +%start system + +%% + +system : init_code menu_list + { check_defined(); + if (!had_errors) + write_menu_file($1); + } + ; + +init_code : /* empty */ { $$ = ""; } + | CODE + ; + +menu_list : /* empty */ + | menu_list menu_def + | menu_list default_def + | menu_list initerror_def + | menu_list dynamic_def + | menu_list msgxlat_def + ; + +dynamic_def : ALLOW DYNAMIC MENUS ';' + { do_dynamic = 1; } + +msgxlat_def : ALLOW DYNAMIC MESSAGES ';' + { do_msgxlat = 1; } + +initerror_def : ERROR action ';' + { error_act = $2; } + +default_def : DEFAULT + { cur_menu = &default_menu; } + opt opt_list ";" + +menu_def : MENU NAME + { cur_menu = get_menu ($2); + if (cur_menu->info != NULL) + yyerror ("Menu %s defined twice", $2); + else { + cur_menu->info = + (menu_info *) malloc (sizeof (menu_info)); + *(cur_menu->info) = default_info; + } + } + opts ";" dispact option_list exitact helpstr + { optn_info *t; + cur_menu->info->optns = NULL; + while ($7 != NULL) { + t = $7; + $7 = $7->next; + t->next = cur_menu->info->optns; + cur_menu->info->optns = t; + cur_menu->info->numopt++; + } + } + ; + +opts : /* empty */ + | opt_list + ; + +opt_list : "," opt + | opt_list "," opt + ; + +text : NAME | STRING + +opt : NO EXIT { cur_menu->info->mopt |= MC_NOEXITOPT; } + | EXIT { cur_menu->info->mopt &= ~MC_NOEXITOPT; } + | NO BOX { cur_menu->info->mopt |= MC_NOBOX; } + | BOX { cur_menu->info->mopt &= ~MC_NOBOX; } + | NO SCROLLABLE { cur_menu->info->mopt &= ~MC_SCROLL; } + | SCROLLABLE { cur_menu->info->mopt |= MC_SCROLL; } + | NO SHORTCUT { cur_menu->info->mopt |= MC_NOSHORTCUT; } + | SHORTCUT { cur_menu->info->mopt &= ~MC_NOSHORTCUT; } + | NO CLEAR { cur_menu->info->mopt |= MC_NOCLEAR; } + | CLEAR { cur_menu->info->mopt &= ~MC_NOCLEAR; } + | NO DEFAULT EXIT { cur_menu->info->mopt &= ~MC_DFLTEXIT; } + | DEFAULT EXIT { cur_menu->info->mopt |= MC_DFLTEXIT; } + | NO ALWAYS SCROLL { cur_menu->info->mopt &= ~MC_ALWAYS_SCROLL; } + | ALWAYS SCROLL { cur_menu->info->mopt |= MC_ALWAYS_SCROLL; } + | NO SUB MENU { cur_menu->info->mopt &= ~MC_SUBMENU; } + | SUB MENU { cur_menu->info->mopt |= MC_SUBMENU; } + | X "=" INT_CONST { cur_menu->info->x = atoi($3); } + | Y "=" INT_CONST { cur_menu->info->y = atoi($3); } + | W "=" INT_CONST { cur_menu->info->w = atoi($3); } + | H "=" INT_CONST { cur_menu->info->h = atoi($3); } + | TITLE text { cur_menu->info->title = $2; } + | EXITSTRING text { cur_menu->info->exitstr = $2; + cur_menu->info->mopt &= ~MC_NOEXITOPT; } + ; + +option_list : option + | option_list option { $2->next = $1; $$ = $2; } + ; + +option : OPTION + { cur_optn = (optn_info *) malloc (sizeof(optn_info)); + cur_optn->menu = -1; + cur_optn->name = NULL; + cur_optn->name_is_code = FALSE; + cur_optn->issub = FALSE; + cur_optn->doexit = FALSE; + cur_optn->optact.code = ""; + cur_optn->optact.endwin = FALSE; + cur_optn->next = NULL; + } + option_legend "," + elem_list ";" + { $$ = cur_optn; } + ; + +option_legend : text { cur_optn->name = $1; } + | CODE { cur_optn->name = $1; cur_optn->name_is_code = TRUE;} + +elem_list : elem + | elem_list "," elem + ; + +elem : NEXT MENU NAME + { id_rec *t = get_menu ($3); + if (cur_optn->menu != -1) + yyerror ("Double sub/next menu definition"); + else { + cur_optn->menu = t->menu_no; + } + } + | SUB MENU NAME + { id_rec *t = get_menu ($3); + if (cur_optn->menu != -1) + yyerror ("Double sub/next menu definition"); + else { + cur_optn->menu = t->menu_no; + cur_optn->issub = TRUE; + } + } + | action { cur_optn->optact = $1; } + | EXIT { cur_optn->doexit = TRUE; } + ; + +action : ACTION act_opt CODE + { $$.code = $3; + $$.endwin = $2; + } + ; + +act_opt : /* empty */ { $$ = 0; } + | "(" ENDWIN ")" { $$ = 1; } + ; + +dispact : /* empty */ { cur_menu->info->postact.code = ""; } + | DISPLAY action ";" { cur_menu->info->postact = $2; } + ; + + +exitact : /* empty */ { cur_menu->info->exitact.code = ""; } + | EXIT action ";" { cur_menu->info->exitact = $2; } + ; + +helpstr : /* empty */ { cur_menu->info->helpstr = NULL; } + | HELP CODE ";" { asprintf(&cur_menu->info->helpstr, "\"%s\"", $2); } + | HELP text ";" { cur_menu->info->helpstr = $2; } + ; diff --git a/usr.bin/menuc/pathnames.h b/usr.bin/menuc/pathnames.h new file mode 100644 index 000000000..3e6c71e90 --- /dev/null +++ b/usr.bin/menuc/pathnames.h @@ -0,0 +1,5 @@ +/* $NetBSD: pathnames.h,v 1.1 2001/10/15 22:20:03 bjh21 Exp $ */ + +#ifndef _PATH_DEFSYSPREFIX +#define _PATH_DEFSYSPREFIX "/usr/share/misc" +#endif diff --git a/usr.bin/menuc/scan.l b/usr.bin/menuc/scan.l new file mode 100644 index 000000000..f75d30924 --- /dev/null +++ b/usr.bin/menuc/scan.l @@ -0,0 +1,196 @@ +/* $NetBSD: scan.l,v 1.16 2012/03/06 16:55:18 mbalmer Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +%{ +/* scan.l: scanner description for menu compiler. */ + +#include +#include +#include "defs.h" +#include "parse.h" + +static int level; /* For nested comments. */ +static int comstart; /* line number of comment start. */ + +%} + +%x COMMENT +%x BRACE + +%option noinput + +%% + +[ \t]+ { /* ignore spaces and tabs */ } + +[\n] { line_no++; } + +"="|";"|","|"("|")" { return (int)yytext[0]; } + +x { return X; } + +y { return Y; } + +w { return W; } + +h { return H; } + +no { return NO; } + +box { return BOX; } + +sub { return SUB; } + +help { return HELP; } + +menu { return MENU; } + +menus { return MENUS; } + +next { return NEXT; } + +exit { return EXIT; } + +exitstring { return EXITSTRING; } + +title { return TITLE; } + +action { return ACTION; } + +endwin { return ENDWIN; } + +option { return OPTION; } + +default { return DEFAULT; } + +display { return DISPLAY; } + +error { return ERROR; } + +allow { return ALLOW; } + +dynamic { return DYNAMIC; } + +messages { return MESSAGES; } + +scrollable { return SCROLLABLE; } + +shortcut { return SHORTCUT; } + +clear { return CLEAR; } + +always { return ALWAYS; } + +scroll { return SCROLL; } + +\"([^\"\n]*(\\\")?)*\" { + yylval.s_value = strdup (yytext); + max_strlen = max_strlen > strlen(yytext) + ? max_strlen : strlen(yytext) + 1; + return STRING; + } + +[a-zA-Z][a-zA-Z0-9_]* { + yylval.s_value = strdup(yytext); + return(NAME); + } + +0|[-1-9][0-9]* { + yylval.s_value = strdup(yytext); + return(INT_CONST); + } + +"'"[^'\\]|(\\[athrn])|(\\[0-9][0-9]?[0-9]?)"'" { + yylval.s_value = strdup(yytext); + return(CHAR_CONST); + } + +"/*" { level = 1; comstart = line_no; BEGIN COMMENT; } + +"/*" { level++; } + +"*/" { if (level-- == 1) BEGIN 0; } + +"\n" { line_no++; } + +<> { + yyerror ("EOF inside a comment that started at line %d", + comstart); + exit (1); + } + +. {/* eat character */} + +"{" { level = 1; BEGIN BRACE; } + +"{" { buff_add_ch(yytext[0]); level++; } + +"}" { if (level-- == 1) { + BEGIN 0; + yylval.s_value = buff_copy(); + return CODE; + } else + buff_add_ch (yytext[0]); + } + +"\n" { buff_add_ch (yytext[0]); line_no++; } + +. { buff_add_ch (yytext[0]); } + +. { + if (yytext[0] < ' ') + yyerror ("illegal character: ^%c",yytext[0] + '@'); + else + if (yytext[0] > '~') + yyerror ("illegal character: \\%3d", (int) yytext[0]); + else + yyerror ("illegal character: %s",yytext); + + /* To quiet the compiler */ + if (0) unput(0); + } +%% + +#ifdef SCAN +YYSTYPE yylval; + +main() +{ + int val; + + line_no = 1; + while ( (val = yylex()) != 0 ) + printf ("val = %d\n yytext = %s\n", val, yytext); +} +#endif diff --git a/usr.bin/menuc/testm/Makefile b/usr.bin/menuc/testm/Makefile new file mode 100644 index 000000000..821bb0684 --- /dev/null +++ b/usr.bin/menuc/testm/Makefile @@ -0,0 +1,27 @@ +# $NetBSD: Makefile,v 1.17 2012/04/21 12:27:29 roy Exp $ + +NOMAN= # defined + +.include + +MENUCDIR!= cd $(.CURDIR)/..; ${PRINTOBJDIR} +MENUC= ${MENUCDIR}/menuc +${MENUC}: + cd ${.CURDIR}/..; ${MAKE} + +PROG= testm +SRCS= msg_defs.c menu_defs.c main.c +CFLAGS+=-g +CPPFLAGS+=-I. +LDADD+= -lcurses -lterminfo +DPADD+= ${LIBCURSES} + +CLEANFILES+= menu_defs.c menu_defs.h msg_defs.c msg_defs.h + +menu_defs.c menu_defs.h: menus.mc ${MENUC} ${.CURDIR}/../menu_sys.def + MENUDEF=${.CURDIR}/.. ${MENUC} ${.CURDIR}/menus.mc + +msg_defs.c msg_defs.h: menus.msg + msgc ${.CURDIR}/menus.msg + +.include diff --git a/usr.bin/menuc/testm/main.c b/usr.bin/menuc/testm/main.c new file mode 100644 index 000000000..69fe39dc1 --- /dev/null +++ b/usr.bin/menuc/testm/main.c @@ -0,0 +1,126 @@ +/* $NetBSD: main.c,v 1.6 2004/09/17 18:16:44 wrstuden Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software develooped for the NetBSD Project by + * Piermont Information Systems Inc. + * 4. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* main sysinst program. */ + +#include "menu_defs.h" +#include "msg_defs.h" + +int main(void); + +int main(void) +{ + + /* Menu processing */ + process_menu (MENU_root, NULL); + + return 0; +} + +/* Dynamic menu suff! */ + +char ent_text[5][50] = {"name: ", "strt: ", "city: ", "opt 4", "NUM: "}; + +/* opt processing routines .. */ + +int opt_1 (struct menudesc *m, void *p); + +int opt_1 (struct menudesc *m, void *p) +{ + msg_clear(); + msg_prompt (MSG_name, "", &ent_text[0][6], 40); + msg_clear(); + return 0; +} + +int opt_2 (struct menudesc *m, void *p); + +int opt_2 (struct menudesc *m, void *p) +{ + msg_clear(); + msg_prompt (MSG_street, "", &ent_text[1][6], 40); + msg_clear(); + return 0; +} + +int opt_3 (struct menudesc *m, void *p); + +int opt_3 (struct menudesc *m, void *p) +{ + msg_clear(); + msg_prompt (MSG_city, "", &ent_text[2][6], 40); + msg_clear(); + return 0; +} + + +menu_ent mymenu [5] = { + { ent_text[0], OPT_NOMENU, 0, opt_1}, + { ent_text[1], OPT_NOMENU, 0, opt_2}, + { ent_text[2], OPT_NOMENU, 0, opt_3}, + { ent_text[3], OPT_NOMENU, 0, NULL}, + { ent_text[4], OPT_NOMENU, 0, NULL} }; + +int num = 0; + + +void do_dynamic(void); +void dyn_disp (struct menudesc *, void *); +void dyn_disp (struct menudesc *m, void *p) +{ + sprintf (&ent_text[4][5], "%d", num++); +} + +void do_dynamic(void) +{ + int menu_no; + + num = 0; + menu_no = new_menu (" A test dynamic menu! ", mymenu, 5, 10, 10, + 0, 55, MC_SCROLL, dyn_disp, NULL, NULL, + "Make sure you try at least one option before exiting.\n" + "Then look at what changes.\n", "Done now!"); + if (menu_no < 0) { + endwin(); + (void) fprintf (stderr, "Dynamic memu creation failure. \n"); + exit (1); + } + process_menu (menu_no, NULL); + free_menu (menu_no); +} + diff --git a/usr.bin/menuc/testm/menus.mc b/usr.bin/menuc/testm/menus.mc new file mode 100644 index 000000000..c8c3ff176 --- /dev/null +++ b/usr.bin/menuc/testm/menus.mc @@ -0,0 +1,277 @@ +/* $NetBSD: menus.mc,v 1.11 2004/09/17 18:16:31 wrstuden Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software develooped for the NetBSD Project by + * Piermont Information Systems Inc. + * 4. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +{ + +#include "msg_defs.h" + +/* Initial code for definitions and includes and prototypes. */ +void do_dynamic (void); +static int msg_init = 0; + +} + +default x=20, y=10; + +allow dynamic menus; + +error action { fprintf (stderr, "Testm: Could not initialize curses.\n"); + exit(1); }; + +menu root, title " Main Menu of Test System", x=10; + display action { + /* Message initialization */ + if (!msg_init) { + msg_window (stdscr); + msg_init = 1; + } + msg_display (MSG_welcome); + wrefresh(stdscr); }; + option "Do nothing option", + action { } + ; + option "Try a sub menu", + sub menu submenu + ; + option "A scrollable menu", + sub menu scrollit + ; + option "Another scrollable menu", + sub menu scrollit2 + ; + option "Big non-scrollable menu, bombs on small screens", + sub menu bigscroll + ; + option "A menu with no shortcuts", + sub menu noshort + ; + option "A dynamic menu ...", + action { do_dynamic (); } + ; + option "Run a shell...", + action (endwin) { system ("/bin/sh"); } + ; + exit action (endwin) { printf ("Thanks for playing\n"); }; + help { + Main Menu Help Screen + +This is help text for the main menu of the menu test system. This +text should appear verbatim when asked for by use of the ? key by +the user. This should allow scrolling, if needed. If the first +character in the help is the newline (as the case for this help), +then that newline is not included in the help text. + +Now this tests lines for scrolling: +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +}; + +menu submenu, title " submenu test"; + option "upper right", sub menu upperright; + option "lower left", sub menu lowerleft; + option "middle, no title", sub menu middle; + option "next menu", next menu nextmenu; + +menu upperright, title "upper right", y=2, x=60, no exit; + option "Just Exit!", exit; + +menu lowerleft, title "lower left", y=19, x=2, no exit; + option "Just Exit!", exit; + +menu middle, no box; + option "Just Exit!", exit; + +menu nextmenu, title " A next window! ? for comments", no exit; + option "Just Exit!:", exit; + +menu noshort, title " No shortcut characters!", no shortcut; + option "first", action {}; + option "second", action {}; + option "third", action {}; + +menu scrollit, scrollable, h=4, title " Scrollable Menu"; + option "option 1", action {}; + option "option 2", action {}; + option "option 3", action {}; + option "option 4", action {}; + option "option 5", action {}; + option "option 6", action {}; + +menu bigscroll, no scrollable, title " Non-scrollable Menu"; + option "option 1", action {}; + option "option 2", action {}; + option "option 3", action {}; + option "option 4", action {}; + option "option 5", action {}; + option "option 6", action {}; + option "option 7", action {}; + option "option 8", action {}; + option "option 9", action {}; + option "option 10", action {}; + option "option 11", action {}; + option "option 12", action {}; + option "option 13", action {}; + option "option 14", action {}; + option "option 15", action {}; + option "option 16", action {}; + option "option 17", action {}; + option "option 18", action {}; + option "option 19", action {}; + option "option 20", action {}; + +menu scrollit2, scrollable, title " Big scrollable Menu"; + option "option 1", action {}; + option "option 2", action {}; + option "option 3", action {}; + option "option 4", action {}; + option "option 5", action {}; + option "option 6", action {}; + option "option 7", action {}; + option "option 8", action {}; + option "option 9", action {}; + option "option 10", action {}; + option "option 11", action {}; + option "option 12", action {}; + option "option 13", action {}; + option "option 14", action {}; + option "option 15", action {}; + option "option 16", action {}; + option "option 17", action {}; + option "option 18", action {}; + option "option 19", action {}; + option "option 20", action {}; + option "option 21", action {}; + option "option 22", action {}; + option "option 23", action {}; + option "option 24", action {}; + option "option 25", action {}; + option "option 26", action {}; + option "option 27", action {}; + option "option 28", action {}; + option "option 29", action {}; + option "option 30", action {}; + option "option 31", action {}; + option "option 32", action {}; + option "option 33", action {}; + option "option 34", action {}; + option "option 35", action {}; + option "option 36", action {}; + option "option 37", action {}; + option "option 38", action {}; + option "option 39", action {}; + option "option 40", action {}; + option "option 41", action {}; + option "option 42", action {}; + option "option 43", action {}; + option "option 44", action {}; + option "option 45", action {}; + option "option 46", action {}; + option "option 47", action {}; + option "option 48", action {}; + option "option 49", action {}; + option "option 50", action {}; + option "option 51", action {}; diff --git a/usr.bin/menuc/testm/menus.msg b/usr.bin/menuc/testm/menus.msg new file mode 100644 index 000000000..9640bbf0c --- /dev/null +++ b/usr.bin/menuc/testm/menus.msg @@ -0,0 +1,12 @@ +/* $NetBSD: menus.msg,v 1.1 1998/07/16 07:08:26 phil Exp $ */ + +message welcome { + + Welcome to the menuc (and msg) test program! +} + +message name {name} + +message street {street address} + +message city {city, state zip} \ No newline at end of file diff --git a/usr.bin/menuc/util.c b/usr.bin/menuc/util.c new file mode 100644 index 000000000..602dc1a02 --- /dev/null +++ b/usr.bin/menuc/util.c @@ -0,0 +1,107 @@ +/* $NetBSD: util.c,v 1.5 2012/03/06 16:55:18 mbalmer Exp $ */ + +/* + * Copyright 1997 Piermont Information Systems Inc. + * All rights reserved. + * + * Written by Philip A. Nelson for Piermont Information Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Piermont Information Systems Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* util.c - utility routines. */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include + +#if defined(__RCSID) && !defined(lint) +__RCSID("$NetBSD: util.c,v 1.5 2012/03/06 16:55:18 mbalmer Exp $"); +#endif + +#include +#include +#include +#include +#include "defs.h" + +/* Error routine */ +void +yyerror(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printf("%s:%d: ", src_name, line_no); + vfprintf(stdout, fmt, args); + printf("\n"); + va_end(args); + had_errors = TRUE; +} + +/* Buffer routines */ +static char *mc_buff = NULL; +static int mc_size = 0; +static int mc_loc = 0; + +void +buff_add_ch(char ch) +{ + char *t; + + if (mc_loc >= mc_size-1) { + if (mc_size == 0) + mc_size = 80; + else + mc_size *= 2; + t = (char *)malloc(mc_size); + if (t == NULL) { + (void)fprintf(stderr, "%s:%d: Malloc error\n", + src_name, line_no); + exit(1); + } + if (mc_buff != NULL) { + strcpy(t, mc_buff); + free(mc_buff); + } + mc_buff = t; + } + mc_buff[mc_loc++] = ch; + mc_buff[mc_loc] = '\0'; +} + +/* get a copy of the string ! */ +char * +buff_copy(void) +{ + char *res = strdup(mc_buff); + + mc_loc = 0; + mc_buff[0] = '\0'; + return res; +} -- 2.44.0