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