1 /* $NetBSD: mdb.c,v 1.41 2004/08/02 21:29:07 dsl Exp $ */ 2 3 /* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software develooped for the NetBSD Project by 20 * Piermont Information Systems Inc. 21 * 4. The name of Piermont Information Systems Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35 * THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 */ 38 39 /* mdb.c - menu database manipulation */ 40 41 #if HAVE_NBTOOL_CONFIG_H 42 #include "nbtool_config.h" 43 #endif 44 45 #include <sys/cdefs.h> 46 47 #if defined(__RCSID) && !defined(lint) 48 __RCSID("$NetBSD: mdb.c,v 1.41 2004/08/02 21:29:07 dsl Exp $"); 49 #endif 50 51 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include "mdb.h" 56 #include "defs.h" 57 #include "pathnames.h" 58 59 /* Data */ 60 #undef MAX 61 #define MAX 1000 62 static int menu_no = 0; 63 static id_rec *menus[MAX]; 64 65 /* Other defines */ 66 #define OPT_SUB 1 67 #define OPT_ENDWIN 2 68 #define OPT_EXIT 4 69 70 71 /* get_menu returns a pointer to a newly created id_rec or an old one. */ 72 73 id_rec * 74 get_menu (char *name) 75 { 76 id_rec *temp; 77 78 temp = find_id (root, name); 79 80 if (temp == NULL) { 81 if (menu_no < MAX) { 82 temp = (id_rec *) malloc (sizeof(id_rec)); 83 temp->id = strdup(name); 84 temp->info = NULL; 85 temp->menu_no = menu_no; 86 menus[menu_no++] = temp; 87 insert_id (&root, temp); 88 } else { 89 (void) fprintf (stderr, "Too many menus. " 90 "Increase MAX.\n"); 91 exit(1); 92 } 93 } 94 95 return temp; 96 } 97 98 99 /* Verify that all menus are defined. */ 100 101 void 102 check_defined (void) 103 { 104 int i; 105 106 for (i=0; i<menu_no; i++) 107 if (!menus[i]->info) 108 yyerror ("Menu '%s' undefined.", menus[i]->id); 109 } 110 111 112 /* Write out the menu file. */ 113 void 114 write_menu_file (char *initcode) 115 { 116 FILE *out_file; 117 FILE *sys_file; 118 int i, j; 119 char hname[1024]; 120 char cname[1024]; 121 char sname[1024]; 122 char *sys_prefix; 123 char *tmpstr; 124 125 int nlen; 126 127 int ch; 128 129 optn_info *toptn; 130 131 /* Generate file names */ 132 snprintf (hname, 1024, "%s.h", out_name); 133 nlen = strlen(hname); 134 if (hname[nlen-2] != '.' || hname[nlen-1] != 'h') { 135 (void) fprintf (stderr, "%s: name `%s` too long.\n", 136 prog_name, out_name); 137 exit(1); 138 } 139 snprintf (cname, 1024, "%s.c", out_name); 140 141 /* Open the menu_sys file first. */ 142 sys_prefix = getenv ("MENUDEF"); 143 if (sys_prefix == NULL) 144 sys_prefix = _PATH_DEFSYSPREFIX; 145 snprintf (sname, 1024, "%s/%s", sys_prefix, sys_name); 146 sys_file = fopen (sname, "r"); 147 if (sys_file == NULL) { 148 (void) fprintf (stderr, "%s: could not open %s.\n", 149 prog_name, sname); 150 exit (1); 151 } 152 153 /* Output the .h file first. */ 154 out_file = fopen (hname, "w"); 155 if (out_file == NULL) { 156 (void) fprintf (stderr, "%s: could not open %s.\n", 157 prog_name, hname); 158 exit (1); 159 } 160 161 /* Write it */ 162 (void) fprintf (out_file, "%s", 163 "/* menu system definitions. */\n" 164 "\n" 165 "#ifndef MENU_DEFS_H\n" 166 "#define MENU_DEFS_H\n" 167 "#include <stdlib.h>\n" 168 "#include <string.h>\n" 169 "#include <ctype.h>\n" 170 "#include <curses.h>\n\n" 171 ); 172 173 if (do_msgxlat) 174 (void)fprintf(out_file, "#define MSG_XLAT(x) msg_string(x)\n"); 175 else 176 (void)fprintf(out_file, "#define MSG_XLAT(x) (x)\n"); 177 if (do_dynamic) 178 (void)fprintf(out_file, "#define DYNAMIC_MENUS\n"); 179 if (do_dynamic || do_msgxlat) 180 (void)fprintf(out_file, "\n"); 181 182 (void)fprintf(out_file, 183 "typedef struct menudesc menudesc;\n" 184 "typedef struct menu_ent menu_ent;\n" 185 "struct menu_ent {\n" 186 " const char *opt_name;\n" 187 " int opt_menu;\n" 188 " int opt_flags;\n" 189 " int (*opt_action)(menudesc *, void *);\n" 190 "};\n\n" 191 "#define OPT_SUB 1\n" 192 "#define OPT_ENDWIN 2\n" 193 "#define OPT_EXIT 4\n" 194 "#define OPT_IGNORE 8\n" 195 "#define OPT_NOMENU -1\n\n" 196 "struct menudesc {\n" 197 " const char *title;\n" 198 " int y, x;\n" 199 " int h, w;\n" 200 " int mopt;\n" 201 " int numopts;\n" 202 " int cursel;\n" 203 " int topline;\n" 204 " menu_ent *opts;\n" 205 " WINDOW *mw;\n" 206 " WINDOW *sv_mw;\n" 207 " const char *helpstr;\n" 208 " const char *exitstr;\n" 209 " void (*post_act)(menudesc *, void *);\n" 210 " void (*exit_act)(menudesc *, void *);\n" 211 " void (*draw_line)(menudesc *, int, void *);\n" 212 "};\n" 213 "\n" 214 "/* defines for mopt field. */\n" 215 #define STR(x) #x 216 #define MC_OPT(x) "#define " #x " " STR(x) "\n" 217 MC_OPT(MC_NOEXITOPT) 218 MC_OPT(MC_NOBOX) 219 MC_OPT(MC_SCROLL) 220 MC_OPT(MC_NOSHORTCUT) 221 MC_OPT(MC_NOCLEAR) 222 MC_OPT(MC_DFLTEXIT) 223 MC_OPT(MC_ALWAYS_SCROLL) 224 MC_OPT(MC_SUBMENU) 225 MC_OPT(MC_VALID) 226 #undef MC_OPT 227 #undef STR 228 ); 229 230 (void) fprintf (out_file, "%s", 231 "\n" 232 "/* Prototypes */\n" 233 "int menu_init(void);\n" 234 "void process_menu(int, void *);\n" 235 "void __menu_initerror(void);\n" 236 ); 237 238 if (do_dynamic) 239 (void) fprintf (out_file, "%s", 240 "int new_menu(const char *, menu_ent *, int, \n" 241 "\tint, int, int, int, int,\n" 242 "\tvoid (*)(menudesc *, void *), " 243 "void (*)(menudesc *, int, void *),\n" 244 "\tvoid (*)(menudesc *, void *), " 245 "const char *, const char *);\n" 246 "void free_menu(int);\n" 247 "void set_menu_numopts(int, int);\n" 248 ); 249 250 (void) fprintf (out_file, "\n/* Menu names */\n"); 251 for (i=0; i<menu_no; i++) { 252 (void) fprintf (out_file, "#define MENU_%s\t%d\n", 253 menus[i]->id, i); 254 } 255 256 if (do_dynamic) 257 (void) fprintf (out_file, "\n#define DYN_MENU_START\t%d", 258 menu_no); 259 260 (void) fprintf (out_file, "\n#define MAX_STRLEN %d\n" 261 "#endif\n", max_strlen); 262 fclose (out_file); 263 264 /* Now the C file */ 265 out_file = fopen (cname, "w"); 266 if (out_file == NULL) { 267 (void) fprintf (stderr, "%s: could not open %s.\n", 268 prog_name, cname); 269 exit (1); 270 } 271 272 /* initial code */ 273 fprintf (out_file, "#include \"%s\"\n\n", hname); 274 fprintf (out_file, "%s\n\n", initcode); 275 276 /* data definitions */ 277 278 /* func defs */ 279 for (i=0; i<menu_no; i++) { 280 if (strlen(menus[i]->info->postact.code)) { 281 (void) fprintf (out_file, 282 "/*ARGSUSED*/\n" 283 "static void menu_%d_postact(menudesc *menu, void *arg)\n{\n", i); 284 if (menus[i]->info->postact.endwin) 285 (void) fprintf (out_file, "\tendwin();\n"); 286 (void) fprintf (out_file, 287 "\t%s\n}\n\n", 288 menus[i]->info->postact.code); 289 } 290 if (strlen(menus[i]->info->exitact.code)) { 291 (void) fprintf (out_file, 292 "/*ARGSUSED*/\n" 293 "static void menu_%d_exitact(menudesc *menu, void *arg)\n{\n", i); 294 if (menus[i]->info->exitact.endwin) 295 (void) fprintf (out_file, "\tendwin();\n"); 296 (void) fprintf (out_file, "\t%s\n}\n\n", 297 menus[i]->info->exitact.code); 298 } 299 j = 0; 300 toptn = menus[i]->info->optns; 301 for (;toptn != NULL; j++, toptn = toptn->next) { 302 if (strlen(toptn->optact.code) == 0) 303 continue; 304 305 (void) fprintf (out_file, 306 "/*ARGSUSED*/\n" 307 "static int opt_act_%d_%d(menudesc *m, void *arg)\n" 308 "{\n\t%s\n\treturn %s;\n}\n\n", 309 i, j, toptn->optact.code, 310 (toptn->doexit ? "1" : "0")); 311 } 312 313 } 314 315 /* optentX */ 316 for (i=0; i<menu_no; i++) { 317 if (menus[i]->info->numopt > 53) { 318 (void) fprintf (stderr, "Menu %s has " 319 "too many options.\n", 320 menus[i]->info->title); 321 exit (1); 322 } 323 toptn = menus[i]->info->optns; 324 j = 0; 325 (void) fprintf (out_file, 326 "static menu_ent optent%d[] = {\n", i); 327 while (toptn != NULL) { 328 (void) fprintf (out_file, "\t{%s,%d,%d,", 329 toptn->name, toptn->menu, 330 (toptn->issub ? OPT_SUB : 0) 331 +(toptn->doexit ? OPT_EXIT : 0) 332 +(toptn->optact.endwin ? OPT_ENDWIN : 0)); 333 if (strlen(toptn->optact.code)) 334 (void) fprintf (out_file, "opt_act_%d_%d}", 335 i, j); 336 else 337 (void) fprintf (out_file, "NULL}"); 338 (void) fprintf (out_file, "%s\n", 339 (toptn->next ? "," : "")); 340 j++; 341 toptn = toptn->next; 342 } 343 (void) fprintf (out_file, "\t};\n\n"); 344 345 } 346 347 348 /* menus */ 349 (void) fprintf (out_file, "static struct menudesc menu_def[] = {\n"); 350 for (i=0; i<menu_no; i++) { 351 (void) fprintf (out_file, 352 "\t{%s,%d,%d,%d,%d,%d,%d,0,0,optent%d,NULL,NULL,", 353 menus[i]->info->title, menus[i]->info->y, 354 menus[i]->info->x, menus[i]->info->h, 355 menus[i]->info->w, menus[i]->info->mopt, 356 menus[i]->info->numopt, i); 357 if (menus[i]->info->helpstr == NULL) 358 (void) fprintf (out_file, "NULL"); 359 else { 360 tmpstr = menus[i]->info->helpstr; 361 if (*tmpstr != '"') 362 (void)fprintf(out_file, "%s", tmpstr); 363 else { 364 /* Skip an initial newline. */ 365 if (tmpstr[1] == '\n') 366 *++tmpstr = '"'; 367 (void) fprintf (out_file, "\n"); 368 while (*tmpstr) { 369 if (*tmpstr != '\n') { 370 fputc (*tmpstr++, out_file); 371 continue; 372 } 373 (void) fprintf (out_file, "\\n\"\n\""); 374 tmpstr++; 375 } 376 } 377 } 378 (void) fprintf (out_file, ","); 379 if (menus[i]->info->mopt & MC_NOEXITOPT) 380 (void) fprintf (out_file, "NULL"); 381 else if (menus[i]->info->exitstr != NULL) 382 (void) fprintf (out_file, "%s", 383 menus[i]->info->exitstr); 384 else 385 (void) fprintf (out_file, "\"Exit\""); 386 if (strlen(menus[i]->info->postact.code)) 387 (void) fprintf (out_file, ",menu_%d_postact", i); 388 else 389 (void) fprintf (out_file, ",NULL"); 390 if (strlen(menus[i]->info->exitact.code)) 391 (void) fprintf (out_file, ",menu_%d_exitact", i); 392 else 393 (void) fprintf (out_file, ",NULL"); 394 395 (void) fprintf (out_file, "},\n"); 396 397 } 398 (void) fprintf (out_file, "{NULL}};\n\n"); 399 400 /* __menu_initerror: initscr failed. */ 401 (void) fprintf (out_file, 402 "/* __menu_initerror: initscr failed. */\n" 403 "void __menu_initerror (void) {\n"); 404 if (error_act.code == NULL) { 405 (void) fprintf (out_file, 406 "\t(void) fprintf (stderr, " 407 "\"%%s: Could not initialize curses\\n\", " 408 "getprogname());\n" 409 "\texit(1);\n" 410 "}\n"); 411 } else { 412 if (error_act.endwin) 413 (void) fprintf (out_file, "\tendwin();\n"); 414 (void) fprintf (out_file, "%s\n}\n", error_act.code); 415 } 416 417 /* Copy menu_sys.def file. */ 418 while ((ch = fgetc(sys_file)) != '\014') /* Control-L */ 419 fputc(ch, out_file); 420 421 if (do_dynamic) { 422 while ((ch = fgetc(sys_file)) != '\n') 423 /* skip it */; 424 while ((ch = fgetc(sys_file)) != EOF) 425 fputc(ch, out_file); 426 } 427 428 fclose (out_file); 429 fclose (sys_file); 430 } 431