/* * Modifications Copyright 1993, 1994, 1995, 1996, * 2000, 2001, 2002, 2004 by Paul Mattes. * Original X11 Port Copyright 1990 by Jeff Sparkes. * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332. * All Rights Reserved. GTRC hereby grants public use of this software. * Derivative works based on this software must incorporate this copyright * notice. * * x3270, c3270, s3270 and tcl3270 are distributed in the hope that they will * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file LICENSE * for more details. */ /* * glue.c * A displayless 3270 Terminal Emulator * Glue for missing parts. */ #include "globals.h" #include #include #include #include "appres.h" #include "3270ds.h" #include "resources.h" #include "actionsc.h" #include "ansic.h" #include "charsetc.h" #include "ctlrc.h" #include "gluec.h" #include "hostc.h" #include "keymapc.h" #include "kybdc.h" #include "macrosc.h" #include "menubarc.h" #include "popupsc.h" #include "screenc.h" #include "selectc.h" #include "tablesc.h" #include "telnetc.h" #include "togglesc.h" #include "trace_dsc.h" #include "utilc.h" extern void usage(char *); #define LAST_ARG "--" #if defined(C3270) /*[*/ extern void merge_profile(void); /* XXX */ extern Boolean any_error_output; #endif /*]*/ /* Statics */ static void no_minus(const char *arg); #if defined(LOCAL_PROCESS) /*[*/ static void parse_local_process(int *argcp, const char **argv, const char **cmds); #endif /*]*/ static void parse_options(int *argcp, const char **argv); static void parse_set_clear(int *argcp, const char **argv); static int parse_model_number(char *m); /* Globals */ const char *programname; char full_model_name[13] = "IBM-"; char *model_name = &full_model_name[4]; AppRes appres; int children = 0; Boolean exiting = False; char *command_string = CN; static Boolean sfont = False; Boolean *standard_font = &sfont; struct toggle_name toggle_names[N_TOGGLES] = { { ResMonoCase, MONOCASE }, { ResAltCursor, ALT_CURSOR }, { ResCursorBlink, CURSOR_BLINK }, { ResShowTiming, SHOW_TIMING }, { ResCursorPos, CURSOR_POS }, #if defined(X3270_TRACE) /*[*/ { ResDsTrace, DS_TRACE }, #else /*][*/ { ResDsTrace, -1 }, #endif /*]*/ { ResScrollBar, SCROLL_BAR }, #if defined(X3270_ANSI) /*[*/ { ResLineWrap, LINE_WRAP }, #else /*][*/ { ResLineWrap, -1 }, #endif /*]*/ { ResBlankFill, BLANK_FILL }, #if defined(X3270_TRACE) /*[*/ { ResScreenTrace, SCREEN_TRACE }, { ResEventTrace, EVENT_TRACE }, #else /*][*/ { ResScreenTrace, -1 }, { ResEventTrace, -1 }, #endif /*]*/ { ResMarginedPaste, MARGINED_PASTE }, { ResRectangleSelect, RECTANGLE_SELECT }, { ResCrosshair, -1 }, { ResVisibleControl, -1 }, #if defined(X3270_SCRIPT) || defined(TCL3270) /*[*/ { ResAidWait, AID_WAIT }, #else /*][*/ { ResAidWait, -1 }, #endif /*]*/ }; int parse_command_line(int argc, const char **argv, const char **cl_hostname) { int cl, i; int ovc, ovr; char junk; int hn_argc; int model_number; /* Figure out who we are */ programname = strrchr(argv[0], '/'); if (programname) ++programname; else programname = argv[0]; /* Save the command string. */ cl = strlen(programname); for (i = 0; i < argc; i++) { cl += 1 + strlen(argv[i]); } cl++; command_string = Malloc(cl); (void) strcpy(command_string, programname); for (i = 0; i < argc; i++) { (void) strcat(strcat(command_string, " "), argv[i]); } #if defined(LOCAL_PROCESS) /*[*/ /* Pick out the -e option. */ parse_local_process(&argc, argv, cl_hostname); #endif /*]*/ /* Parse command-line options. */ parse_options(&argc, argv); /* Pick out the remaining -set and -clear toggle options. */ parse_set_clear(&argc, argv); /* Now figure out if there's a hostname. */ for (hn_argc = 1; hn_argc < argc; hn_argc++) { if (!strcmp(argv[hn_argc], LAST_ARG)) break; } /* Verify command-line syntax. */ switch (hn_argc) { case 1: break; case 2: no_minus(argv[1]); *cl_hostname = argv[1]; break; case 3: no_minus(argv[1]); no_minus(argv[2]); *cl_hostname = xs_buffer("%s:%s", argv[1], argv[2]); break; default: usage(CN); break; } /* Delete the host name and any "--". */ if (argv[hn_argc] != CN && !strcmp(argv[hn_argc], LAST_ARG)) hn_argc++; if (hn_argc > 1) { for (i = 1; i < argc - hn_argc + 2; i++) { argv[i] = argv[i + hn_argc - 1]; } } /* * Sort out model and color modes, based on the model number resource. */ model_number = parse_model_number(appres.model); if (model_number < 0) { popup_an_error("Invalid model number: %s", appres.model); model_number = 0; } if (!model_number) { #if defined(RESTRICT_3279) /*[*/ model_number = 3; #else /*][*/ model_number = 4; #endif /*]*/ } if (appres.mono) { appres.m3279 = False; } if (!appres.extended) appres.oversize = CN; #if defined(RESTRICT_3279) /*[*/ if (appres.m3279 && model_number == 4) model_number = 3; #endif /*]*/ if (!appres.extended || appres.oversize == CN || sscanf(appres.oversize, "%dx%d%c", &ovc, &ovr, &junk) != 2) { ovc = 0; ovr = 0; } set_rows_cols(model_number, ovc, ovr); if (appres.termname != CN) termtype = appres.termname; else termtype = full_model_name; if (appres.apl_mode) appres.charset = Apl; if (*cl_hostname == CN) appres.once = False; if (appres.conf_dir == CN) appres.conf_dir = LIBX3270DIR; return argc; } static void no_minus(const char *arg) { if (arg[0] == '-') usage(xs_buffer("Unknown or incomplete option: %s", arg)); } #if defined(LOCAL_PROCESS) /*[*/ /* * Pick out the -e option. */ static void parse_local_process(int *argcp, const char **argv, const char **cmds) { int i, j; int e_len = -1; char *cmds_buf = NULL; for (i = 1; i < *argcp; i++) { if (strcmp(argv[i], OptLocalProcess)) continue; /* Matched. Copy 'em. */ e_len = strlen(OptLocalProcess) + 1; for (j = i+1; j < *argcp; j++) { e_len += 1 + strlen(argv[j]); } e_len++; cmds_buf = Malloc(e_len); (void) strcpy(cmds_buf, OptLocalProcess); for (j = i+1; j < *argcp; j++) { (void) strcat(strcat(cmds_buf, " "), argv[j]); } /* Stamp out the remaining args. */ *argcp = i; argv[i] = CN; break; } *cmds = cmds_buf; } #endif /*]*/ /* * Pick out command-line options and set up appres. */ static void parse_options(int *argcp, const char **argv) { int i, j; int argc_out = 0; const char **argv_out = (const char **) Malloc((*argcp + 1) * sizeof(char *)); # define offset(n) (void *)&appres.n # define toggle_offset(index) offset(toggle[index].value) static struct { const char *name; enum { OPT_BOOLEAN, OPT_STRING, OPT_XRM, OPT_SKIP2, OPT_NOP, OPT_DONE } type; Boolean flag; const char *res_name; void *aoff; } opts[] = { #if defined(C3270) /*[*/ { OptAllBold, OPT_BOOLEAN, True, ResAllBold, offset(all_bold_on) }, { OptAltScreen,OPT_STRING, False, ResAltScreen, offset(altscreen) }, #endif /*]*/ { OptAplMode, OPT_BOOLEAN, True, ResAplMode, offset(apl_mode) }, #if defined(C3270) /*[*/ { OptCbreak, OPT_BOOLEAN, True, ResCbreak, offset(cbreak_mode) }, #endif /*]*/ #if defined(HAVE_LIBSSL) /*[*/ { OptCertFile, OPT_STRING, False, ResCertFile, offset(cert_file) }, #endif /*]*/ { OptCharset, OPT_STRING, False, ResCharset, offset(charset) }, { OptClear, OPT_SKIP2, False, NULL, NULL }, #if defined(C3270) /*[*/ { OptDefScreen,OPT_STRING, False, ResDefScreen, offset(defscreen) }, #endif /*]*/ #if defined(X3270_TRACE) /*[*/ { OptDsTrace, OPT_BOOLEAN, True, ResDsTrace, toggle_offset(DS_TRACE) }, #endif /*]*/ { OptHostsFile,OPT_STRING, False, ResHostsFile, offset(hostsfile) }, #if defined(C3270) /*[*/ { OptKeymap, OPT_STRING, False, ResKeymap, offset(key_map) }, #endif /*]*/ #if defined(X3270_DBCS) /*[*/ { OptLocalEncoding,OPT_STRING,False,ResLocalEncoding,offset(local_encoding) }, #endif /*]*/ { OptModel, OPT_STRING, False, ResKeymap, offset(model) }, { OptMono, OPT_BOOLEAN, True, ResMono, offset(mono) }, { OptOnce, OPT_BOOLEAN, True, ResOnce, offset(once) }, { OptOversize, OPT_STRING, False, ResOversize, offset(oversize) }, { OptPort, OPT_STRING, False, ResPort, offset(port) }, #if defined(C3270) /*[*/ { OptPrinterLu,OPT_STRING, False, ResPrinterLu, offset(printer_lu) }, #endif /*]*/ #if defined(S3270) /*[*/ { OptScripted, OPT_NOP, False, ResScripted, NULL }, #endif /*]*/ #if defined(C3270) /*[*/ { OptSecure, OPT_BOOLEAN, True, ResSecure, offset(secure) }, #endif /*]*/ { OptSet, OPT_SKIP2, False, NULL, NULL }, { OptTermName, OPT_STRING, False, ResTermName, offset(termname) }, #if defined(X3270_TRACE) /*[*/ { OptTraceFile,OPT_STRING, False, ResTraceFile, offset(trace_file) }, { OptTraceFileSize,OPT_STRING,False,ResTraceFileSize,offset(trace_file_size) }, #endif /*]*/ { "-xrm", OPT_XRM, False, NULL, NULL }, { LAST_ARG, OPT_DONE, False, NULL, NULL }, { CN, OPT_SKIP2, False, NULL, NULL } }; /* Set the defaults. */ appres.mono = False; appres.extended = True; #if defined(C3270) /*[*/ appres.m3279 = True; #else /*][*/ appres.m3279 = False; #endif /*]*/ appres.modified_sel = False; appres.apl_mode = False; #if defined(C3270) || defined(TCL3270) /*[*/ appres.scripted = False; #else /*][*/ appres.scripted = True; #endif /*]*/ appres.numeric_lock = False; appres.secure = False; #if defined(C3270) /*[*/ appres.oerr_lock = True; #else /*][*/ appres.oerr_lock = False; #endif /*]*/ appres.typeahead = True; appres.debug_tracing = True; #if defined(C3270) /*[*/ appres.compose_map = "latin1"; #endif /*]*/ appres.model = "4"; appres.hostsfile = CN; appres.port = "telnet"; appres.charset = "bracket"; appres.termname = CN; appres.macros = CN; appres.trace_dir = "/tmp"; appres.oversize = CN; #if defined(C3270) /*[*/ appres.meta_escape = "auto"; appres.curses_keypad = True; appres.cbreak_mode = False; #endif /*]*/ #if defined(X3270_ANSI) /*[*/ appres.icrnl = True; appres.inlcr = False; appres.onlcr = True; appres.erase = "^H"; appres.kill = "^U"; appres.werase = "^W"; appres.rprnt = "^R"; appres.lnext = "^V"; appres.intr = "^C"; appres.quit = "^\\"; appres.eof = "^D"; #endif /*]*/ appres.unlock_delay = True; #if defined(X3270_FT) /*[*/ appres.dft_buffer_size = DFT_BUF; #endif /*]*/ #if defined(X3270_SCRIPT) || defined(TCL3270) /*[*/ appres.toggle[AID_WAIT].value = True; #endif /*]*/ #if defined(C3270) /*[*/ /* Merge in the profile. */ merge_profile(); #endif /*]*/ /* Parse the command-line options. */ argv_out[argc_out++] = argv[0]; for (i = 1; i < *argcp; i++) { for (j = 0; opts[j].name != CN; j++) { if (!strcmp(argv[i], opts[j].name)) break; } if (opts[j].name == CN) { argv_out[argc_out++] = argv[i]; continue; } switch (opts[j].type) { case OPT_BOOLEAN: *(Boolean *)opts[j].aoff = opts[j].flag; if (opts[j].res_name != CN) add_resource(NewString(opts[j].name), opts[j].flag? "True": "False"); break; case OPT_STRING: if (i == *argcp - 1) /* missing arg */ continue; *(const char **)opts[j].aoff = argv[++i]; if (opts[j].res_name != CN) add_resource(NewString(opts[j].name), NewString(argv[i])); break; case OPT_XRM: if (i == *argcp - 1) /* missing arg */ continue; parse_xrm(argv[++i], "-xrm"); break; case OPT_SKIP2: argv_out[argc_out++] = argv[i++]; if (i < *argcp) argv_out[argc_out++] = argv[i]; break; case OPT_NOP: break; case OPT_DONE: while (i < *argcp) argv_out[argc_out++] = argv[i++]; break; } } *argcp = argc_out; argv_out[argc_out] = CN; (void) memcpy((char *)argv, (char *)argv_out, (argc_out + 1) * sizeof(char *)); Free(argv_out); #if defined(X3270_TRACE) /*[*/ /* One isn't very useful without the other. */ if (appres.toggle[DS_TRACE].value) appres.toggle[EVENT_TRACE].value = True; #endif /*]*/ } /* * Pick out -set and -clear toggle options. */ static void parse_set_clear(int *argcp, const char **argv) { int i, j; int argc_out = 0; const char **argv_out = (const char **) Malloc((*argcp + 1) * sizeof(char *)); argv_out[argc_out++] = argv[0]; for (i = 1; i < *argcp; i++) { Boolean is_set = False; if (!strcmp(argv[i], OptSet)) is_set = True; else if (strcmp(argv[i], OptClear)) { argv_out[argc_out++] = argv[i]; continue; } if (i == *argcp - 1) /* missing arg */ continue; /* Delete the argument. */ i++; for (j = 0; j < N_TOGGLES; j++) if (toggle_names[j].index >= 0 && !strcmp(argv[i], toggle_names[j].name)) { appres.toggle[toggle_names[j].index].value = is_set; break; } if (j >= N_TOGGLES) usage("Unknown toggle name"); } *argcp = argc_out; argv_out[argc_out] = CN; (void) memcpy((char *)argv, (char *)argv_out, (argc_out + 1) * sizeof(char *)); Free(argv_out); } /* * Parse the model number. * Returns -1 (error), 0 (default), or the specified number. */ static int parse_model_number(char *m) { int sl; int n; sl = strlen(m); /* An empty model number is no good. */ if (!sl) { return 0; } if (sl > 1) { /* * If it's longer than one character, it needs to start with * '327[89]', and it sets the m3279 resource. */ if (!strncmp(m, "3278", 4)) { appres.m3279 = False; } else if (!strncmp(m, "3279", 4)) { appres.m3279 = True; } else { return -1; } m += 4; sl -= 4; /* Check more syntax. -E is allowed, but ignored. */ switch (m[0]) { case '\0': /* Use default model number. */ return 0; case '-': /* Model number specified. */ m++; sl--; break; default: return -1; } switch (sl) { case 1: /* n */ break; case 3: /* n-E */ if (strcasecmp(m + 1, "-E")) { return -1; } break; default: return -1; } } /* Check the numeric model number. */ n = atoi(m); if (n >= 2 && n <= 5) { return n; } else { return -1; } } /* * Parse '-xrm' options. * Understands only: * {c,s,tcl}3270.: value * Asterisks and class names need not apply. */ static struct { const char *name; void *address; enum resource_type { XRM_STRING, XRM_BOOLEAN, XRM_INT } type; } resources[] = { #if defined(C3270) /*[*/ { ResAllBold, offset(all_bold), XRM_STRING }, { ResAltScreen, offset(altscreen), XRM_STRING }, #endif /*]*/ { ResBsdTm, offset(bsd_tm), XRM_BOOLEAN }, #if defined(HAVE_LIBSSL) /*[*/ { ResCertFile, offset(cert_file), XRM_STRING }, #endif /*]*/ { ResCharset, offset(charset), XRM_STRING }, { ResColor8, offset(color8), XRM_BOOLEAN }, { ResConfDir, offset(conf_dir), XRM_STRING }, #if defined(C3270) /*[*/ { ResDefScreen, offset(defscreen), XRM_STRING }, #endif /*]*/ #if defined(X3270_ANSI) /*[*/ { ResEof, offset(eof), XRM_STRING }, { ResErase, offset(erase), XRM_STRING }, #endif /*]*/ { ResExtended, offset(extended), XRM_BOOLEAN }, #if defined(X3270_FT) /*[*/ { ResFtCommand, offset(ft_command), XRM_STRING }, { ResDftBufferSize,offset(dft_buffer_size),XRM_INT }, #endif /*]*/ { ResHostsFile, offset(hostsfile), XRM_STRING }, #if defined(X3270_ANSI) /*[*/ { ResIcrnl, offset(icrnl), XRM_BOOLEAN }, { ResInlcr, offset(inlcr), XRM_BOOLEAN }, { ResOnlcr, offset(onlcr), XRM_BOOLEAN }, { ResIntr, offset(intr), XRM_STRING }, #endif /*]*/ #if defined(C3270) && defined(X3270_SCRIPT) /*[*/ { ResIdleCommand,offset(idle_command), XRM_STRING }, { ResIdleCommandEnabled,offset(idle_command_enabled), XRM_BOOLEAN }, { ResIdleTimeout,offset(idle_timeout), XRM_STRING }, #endif /*]*/ #if defined(C3270) /*[*/ { ResKeymap, offset(key_map), XRM_STRING }, { ResMetaEscape,offset(meta_escape), XRM_STRING }, { ResCursesKeypad,offset(curses_keypad),XRM_BOOLEAN }, { ResCbreak, offset(cbreak_mode), XRM_BOOLEAN }, #endif /*]*/ #if defined(X3270_ANSI) /*[*/ { ResKill, offset(kill), XRM_STRING }, { ResLnext, offset(lnext), XRM_STRING }, #endif /*]*/ { ResM3279, offset(m3279), XRM_BOOLEAN }, { ResModel, offset(model), XRM_STRING }, { ResModifiedSel, offset(modified_sel), XRM_BOOLEAN }, { ResMono, offset(mono), XRM_BOOLEAN }, { ResNumericLock, offset(numeric_lock), XRM_BOOLEAN }, { ResOerrLock, offset(oerr_lock), XRM_BOOLEAN }, { ResOversize, offset(oversize), XRM_STRING }, { ResPort, offset(port), XRM_STRING }, #if defined(C3270) /*[*/ { ResPrinterLu, offset(printer_lu), XRM_STRING }, { ResPrintTextCommand, NULL, XRM_STRING }, #endif /*]*/ #if defined(X3270_ANSI) /*[*/ { ResQuit, offset(quit), XRM_STRING }, { ResRprnt, offset(rprnt), XRM_STRING }, #endif /*]*/ { ResSecure, offset(secure), XRM_BOOLEAN }, { ResTermName, offset(termname), XRM_STRING }, #if defined(X3270_TRACE) /*[*/ { ResTraceDir, offset(trace_dir), XRM_STRING }, { ResTraceFile, offset(trace_file), XRM_STRING }, { ResTraceFileSize,offset(trace_file_size),XRM_STRING }, #endif /*]*/ { ResTypeahead, offset(typeahead), XRM_BOOLEAN }, { ResUnlockDelay,offset(unlock_delay), XRM_BOOLEAN }, #if defined(X3270_ANSI) /*[*/ { ResWerase, offset(werase), XRM_STRING }, #endif /*]*/ { CN, 0, XRM_STRING } }; /* * Compare two strings, allowing the second to differ by uppercasing the * first character of the second. */ static int strncapcmp(const char *known, const char *unknown, unsigned unk_len) { if (unk_len != strlen(known)) return -1; if (!strncmp(known, unknown, unk_len)) return 0; if (unk_len > 1 && unknown[0] == toupper(known[0]) && !strncmp(known + 1, unknown + 1, unk_len - 1)) return 0; return -1; } #if !defined(ME) /*[*/ #if defined(C3270) /*[*/ #define ME "c3270" #elif defined(TCL3270) /*][*/ #define ME "tcl3270" #else /*][*/ #define ME "s3270" #endif /*]*/ #endif /*]*/ void parse_xrm(const char *arg, const char *where) { static char me_dot[] = ME "."; static char me_star[] = ME "*"; unsigned match_len; const char *s; unsigned rnlen; int i; char *t; void *address = NULL; enum resource_type type = XRM_STRING; #if defined(C3270) /*[*/ char *add_buf = CN; #endif /*]*/ /* Enforce "-3270." or "-3270*" or "*". */ if (!strncmp(arg, me_dot, sizeof(me_dot)-1)) match_len = sizeof(me_dot)-1; else if (!strncmp(arg, me_star, sizeof(me_star)-1)) match_len = sizeof(me_star)-1; else if (arg[0] == '*') match_len = 1; else { xs_warning("%s: Invalid resource syntax '%.*s', name must " "begin with '%s'", where, sizeof(me_dot)-1, arg, me_dot); return; } /* Separate the parts. */ s = arg + match_len; while (*s && *s != ':' && !isspace(*s)) s++; rnlen = s - (arg + match_len); if (!rnlen) { xs_warning("%s: Invalid resource syntax, missing resource " "name", where); return; } while (isspace(*s)) s++; if (*s != ':') { xs_warning("%s: Invalid resource syntax, missing ':'", where); return; } s++; while (isspace(*s)) s++; /* Look up the name. */ for (i = 0; resources[i].name != CN; i++) { if (!strncapcmp(resources[i].name, arg + match_len, rnlen)) { address = resources[i].address; type = resources[i].type; #if defined(C3270) /*[*/ if (address == NULL) { add_buf = Malloc(strlen(s) + 1); address = add_buf; } #endif /*]*/ break; } } if (address == NULL) { for (i = 0; i < N_TOGGLES; i++) { if (toggle_names[i].index >= 0 && !strncapcmp(toggle_names[i].name, arg + match_len, rnlen)) { address = &appres.toggle[toggle_names[i].index].value; type = XRM_BOOLEAN; break; } } } #if defined(C3270) /*[*/ if (address == NULL) { if (!strncasecmp(ResKeymap ".", arg + match_len, strlen(ResKeymap ".")) || !strncasecmp(ResCharset ".", arg + match_len, strlen(ResCharset ".")) || !strncasecmp(ResDisplayCharset ".", arg + match_len, strlen(ResDisplayCharset ".")) || !strncasecmp(ResCodepage ".", arg + match_len, strlen(ResCodepage ".")) || !strncasecmp("host.", arg + match_len, 5) || !strncasecmp("printer.", arg + match_len, 8)) { add_buf = Malloc(strlen(s) + 1); address = add_buf; type = XRM_STRING; } } #endif /*]*/ if (address == NULL) { xs_warning("%s: Unknown resource name: %.*s", where, (int)rnlen, arg + match_len); return; } switch (type) { case XRM_BOOLEAN: if (!strcasecmp(s, "true") || !strcasecmp(s, "t") || !strcmp(s, "1")) { *(Boolean *)address = True; } else if (!strcasecmp(s, "false") || !strcasecmp(s, "f") || !strcmp(s, "0")) { *(Boolean *)address = False; } else { xs_warning("%s: Invalid Boolean value: %s", where, s); } break; case XRM_STRING: t = Malloc(strlen(s) + 1); *(char **)address = t; if (*s == '"') { Boolean quoted = False; char c; s++; while ((c = *s++) != '\0') { if (quoted) { switch (c) { case 'n': *t++ = '\n'; break; case 'r': *t++ = '\r'; break; case 'b': *t++ = '\b'; break; default: *t++ = c; break; } quoted = False; } else if (c == '\\') { quoted = True; } else if (c == '"') { break; } else { *t++ = c; } } *t = '\0'; } else { (void) strcpy(t, s); } break; case XRM_INT: { long n; char *ptr; n = strtol(s, &ptr, 0); if (*ptr != '\0') { xs_warning("%s: Invalid Integer value: %s", where, s); } else { *(int *)address = (int)n; } break; } } #if defined(C3270) /*[*/ /* Add a new, arbitrarily-named resource. */ { char *rsname; rsname = Malloc(rnlen + 1); (void) strncpy(rsname, arg + match_len, rnlen); rsname[rnlen] = '\0'; add_resource(rsname, NewString(s)); } #endif /*]*/ } /* Read resources from a file. */ int read_resource_file(const char *filename, Boolean fatal) { FILE *f; int ilen; char buf[4096]; char *where; int lno = 0; f = fopen(filename, "r"); if (f == NULL) { if (fatal) xs_warning("Cannot open '%s': %s", filename, strerror(errno)); return -1; } /* Merge in what's in the file into the resource database. */ where = Malloc(strlen(filename) + 64); ilen = 0; while (fgets(buf + ilen, sizeof(buf) - ilen, f) != CN || ilen) { char *s, *t; unsigned sl; Boolean bsl; lno++; /* Stip any trailing newline. */ sl = strlen(buf + ilen); if (sl && (buf + ilen)[sl-1] == '\n') (buf + ilen)[--sl] = '\0'; /* * Translate backslash-n to real newline characters, and * remember if the last character is a backslash. */ for (bsl = False, s = buf + ilen, t = s; *s; s++) { if (bsl) { if (*s == 'n') *t++ = '\n'; else *t++ = *s; bsl = False; } else if (*s == '\\') bsl = True; else { *t++ = *s; bsl = False; } } *t = '\0'; /* Skip leading whitespace. */ s = buf; while (isspace(*s)) s++; /* Skip comments _before_ checking for line continuation. */ if (*s == '!') { ilen = 0; continue; } if (*s == '#') { (void) sprintf(where, "%s:%d: Invalid profile " "syntax ('#' ignored)", filename, lno); Warning(where); ilen = 0; continue; } /* If this line is a continuation, try again. */ if (bsl) { ilen += strlen(buf + ilen); if (ilen >= sizeof(buf) - 1) { (void) sprintf(where, "%s:%d: Line too long\n", filename, lno); Warning(where); break; } continue; } /* Strip trailing whitespace and check for empty lines. */ sl = strlen(s); while (sl && isspace(s[sl-1])) s[--sl] = '\0'; if (!sl) { ilen = 0; continue; } /* Digest it. */ (void) sprintf(where, "%s:%d", filename, lno); parse_xrm(s, where); /* Get ready for the next iteration. */ ilen = 0; } Free(where); return 0; } /* Screen globals. */ static int cw = 7; int *char_width = &cw; static int ch = 7; int *char_height = &ch; Boolean visible_control = False; Boolean flipped = False; /* Replacements for functions in popups.c. */ #include Boolean error_popup_visible = False; static char vmsgbuf[4096]; /* Pop up an error dialog. */ void popup_an_error(const char *fmt, ...) { va_list args; char *s; int sl; va_start(args, fmt); (void) vsprintf(vmsgbuf, fmt, args); va_end(args); /* * Multi-line messages are fine for X pop-ups, but they're no fun for * text applications. */ s = vmsgbuf; while ((s = strchr(s, '\n')) != NULL) { *s++ = ' '; } while ((sl = strlen(vmsgbuf)) > 0 && vmsgbuf[sl-1] == ' ') { vmsgbuf[--sl] = '\0'; } if (sms_redirect()) { sms_error(vmsgbuf); return; } else { #if defined(C3270) /*[*/ screen_suspend(); any_error_output = True; #endif /*]*/ (void) fprintf(stderr, "%s\n", vmsgbuf); macro_output = True; } } /* Pop up an error dialog, based on an error number. */ void popup_an_errno(int errn, const char *fmt, ...) { va_list args; char *s; va_start(args, fmt); (void) vsprintf(vmsgbuf, fmt, args); va_end(args); s = NewString(vmsgbuf); if (errn > 0) popup_an_error("%s:\n%s", s, strerror(errn)); else popup_an_error(s); Free(s); } void action_output(const char *fmt, ...) { va_list args; va_start(args, fmt); (void) vsprintf(vmsgbuf, fmt, args); va_end(args); if (sms_redirect()) { sms_info("%s", vmsgbuf); return; } else { FILE *aout; #if defined(C3270) /*[*/ screen_suspend(); aout = start_pager(); any_error_output = True; #else /*][*/ aout = stdout; #endif /*]*/ (void) fprintf(aout, "%s\n", vmsgbuf); macro_output = True; } }