]> Zhao Yanbai Git Server - minix.git/commitdiff
Importing usr.bin/menuc 21/1121/1
authorThomas Cort <tcort@minix3.org>
Wed, 6 Nov 2013 15:44:51 +0000 (10:44 -0500)
committerThomas Cort <tcort@minix3.org>
Wed, 6 Nov 2013 15:44:51 +0000 (10:44 -0500)
No Minix-specific changes needed.

Change-Id: Ie663e08a515a393efaaeecacea15ef807aa8ecfb

19 files changed:
distrib/sets/lists/minix/mi
releasetools/nbsd_ports
usr.bin/Makefile
usr.bin/menuc/Makefile [new file with mode: 0644]
usr.bin/menuc/avl.c [new file with mode: 0644]
usr.bin/menuc/defs.h [new file with mode: 0644]
usr.bin/menuc/main.c [new file with mode: 0644]
usr.bin/menuc/mdb.c [new file with mode: 0644]
usr.bin/menuc/mdb.h [new file with mode: 0644]
usr.bin/menuc/menu_sys.def [new file with mode: 0644]
usr.bin/menuc/menuc.1 [new file with mode: 0644]
usr.bin/menuc/parse.y [new file with mode: 0644]
usr.bin/menuc/pathnames.h [new file with mode: 0644]
usr.bin/menuc/scan.l [new file with mode: 0644]
usr.bin/menuc/testm/Makefile [new file with mode: 0644]
usr.bin/menuc/testm/main.c [new file with mode: 0644]
usr.bin/menuc/testm/menus.mc [new file with mode: 0644]
usr.bin/menuc/testm/menus.msg [new file with mode: 0644]
usr.bin/menuc/util.c [new file with mode: 0644]

index 4c271587cbca5824d51feb82220fb0febfcf7b5e..17cbcb62fe90cefd1928515979653ee2934fd24f 100644 (file)
 ./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
 ./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
 ./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
index c18b5956577768b07786a1742855319057959be4..fbe0e53493b68dbf619a86228da759f184417cfb 100644 (file)
 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
index 5d226c90ea855fdb8369250a1e8967d68067bc1d..983e398e86a6016690fae5e9d07686432c3914cb 100644 (file)
@@ -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 (file)
index 0000000..c44a97b
--- /dev/null
@@ -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 <bsd.own.mk>
+
+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 <bsd.prog.mk>
diff --git a/usr.bin/menuc/avl.c b/usr.bin/menuc/avl.c
new file mode 100644 (file)
index 0000000..7e79274
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+#if defined(__RCSID) && !defined(lint)
+__RCSID("$NetBSD: avl.c,v 1.7 2005/02/11 06:21:22 simonb Exp $");
+#endif
+
+
+#include <string.h>
+
+#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 (file)
index 0000000..e35cb90
--- /dev/null
@@ -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 <stdio.h>
+
+#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 (file)
index 0000000..d70df7d
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+#if defined(__RCSID) && !defined(lint)
+__RCSID("$NetBSD: main.c,v 1.11 2012/03/06 16:55:18 mbalmer Exp $");
+#endif
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..cb7633e
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+#if defined(__RCSID) && !defined(lint)
+__RCSID("$NetBSD: mdb.c,v 1.46 2012/03/06 16:55:18 mbalmer Exp $");
+#endif
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 <stdlib.h>\n"
+               "#include <string.h>\n"
+               "#include <ctype.h>\n"
+               "#include <curses.h>\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 (file)
index 0000000..e4ce820
--- /dev/null
@@ -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 (file)
index 0000000..4bebc16
--- /dev/null
@@ -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 <string.h>
+#include <ctype.h>
+
+#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;
+}
+
+\f/* 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 (file)
index 0000000..37bb4ba
--- /dev/null
@@ -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 (file)
index 0000000..868c132
--- /dev/null
@@ -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 <stdio.h>
+#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 <i_value> X Y W H NO BOX SUB HELP MENU NEXT EXIT ACTION ENDWIN OPTION 
+%token <i_value> TITLE DEFAULT DISPLAY ERROR EXITSTRING ALLOW DYNAMIC MENUS
+                SCROLLABLE SHORTCUT CLEAR MESSAGES ALWAYS SCROLL
+%token <s_value> STRING NAME CODE INT_CONST CHAR_CONST
+
+%type <s_value> init_code system helpstr text
+%type <optn_value> option option_list
+%type <i_value> act_opt
+%type <a_value> 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 (file)
index 0000000..3e6c71e
--- /dev/null
@@ -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 (file)
index 0000000..f75d309
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#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; }
+
+<COMMENT>"/*" { level++; }
+
+<COMMENT>"*/" { if (level-- == 1) BEGIN 0; }
+
+<COMMENT>"\n" { line_no++; }
+
+<COMMENT><<EOF>> {
+               yyerror ("EOF inside a comment that started at line %d",
+                        comstart);
+               exit (1);
+       }
+
+<COMMENT>.  {/* eat character */}
+
+"{"    { level = 1; BEGIN BRACE; }
+
+<BRACE>"{"     { buff_add_ch(yytext[0]); level++; }
+
+<BRACE>"}"     { if (level-- == 1)  {
+                       BEGIN 0;
+                       yylval.s_value = buff_copy();
+                       return CODE;
+                 } else
+                       buff_add_ch (yytext[0]);
+               }
+
+<BRACE>"\n"    { buff_add_ch (yytext[0]); line_no++; }
+
+<BRACE>.       { 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 (file)
index 0000000..821bb06
--- /dev/null
@@ -0,0 +1,27 @@
+#      $NetBSD: Makefile,v 1.17 2012/04/21 12:27:29 roy Exp $
+
+NOMAN= # defined
+
+.include <bsd.own.mk>
+
+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 <bsd.prog.mk>
diff --git a/usr.bin/menuc/testm/main.c b/usr.bin/menuc/testm/main.c
new file mode 100644 (file)
index 0000000..69fe39d
--- /dev/null
@@ -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 (file)
index 0000000..c8c3ff1
--- /dev/null
@@ -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 (file)
index 0000000..9640bbf
--- /dev/null
@@ -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 (file)
index 0000000..602dc1a
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+#if defined(__RCSID) && !defined(lint)
+__RCSID("$NetBSD: util.c,v 1.5 2012/03/06 16:55:18 mbalmer Exp $");
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#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;
+}