/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */ /* NAME infocmp - compare terminfo descriptions, or dump a terminfo description AUTHOR Tony Hansen, February 23, 1984. */ #include "curses.h" #include "term.h" #include "print.h" #include #include /* externs from libcurses */ extern char *boolnames[]; extern char *boolcodes[]; extern char *boolfnames[]; extern char *numnames[]; extern char *numcodes[]; extern char *numfnames[]; extern char *strnames[]; extern char *strcodes[]; extern char *strfnames[]; extern char ttytype[]; extern int tgetflag(); extern int tgetnum(); extern char *tgetstr(); /* externs from libc */ extern void exit(); extern void qsort(); extern char *getenv(); extern int getopt(); extern int optind; extern char *optarg; extern char *strncpy(), *strcpy(); extern int strcmp(), strlen(); /* data structures for this program */ struct boolstruct { char *infoname; /* the terminfo capability name */ char *capname; /* the termcap capability name */ char *fullname; /* the long C variable name */ char *secondname; /* the use= terminal w/ this value */ char val; /* the value */ char secondval; /* the value in the use= terminal */ char changed; /* a use= terminal changed the value */ char seenagain; /* a use= terminal had this entry */ }; struct numstruct { char *infoname; /* ditto from above */ char *capname; char *fullname; char *secondname; short val; short secondval; char changed; char seenagain; }; struct strstruct { char *infoname; /* ditto from above */ char *capname; char *fullname; char *secondname; char *val; char *secondval; char changed; char seenagain; }; /* globals for this file */ char *progname; /* argv[0], the name of the program */ static struct boolstruct *ibool; /* array of char information */ static struct numstruct *num; /* array of number information */ static struct strstruct *str; /* array of string information */ static char *used; /* usage statistics */ static int numbools; /* how many booleans there are */ static int numnums; /* how many numbers there are */ static int numstrs; /* how many strings there are */ #define TTYLEN 255 static char *firstterm; /* the name of the first terminal */ static char *savettytype; /* the synonyms of the first terminal */ static char _savettytype[TTYLEN+1]; /* the place to save those names */ static int devnull; /* open("/dev/null") for setupterm */ #define trace stderr /* send trace messages to stderr */ /* options */ static int verbose = 0; /* debugging printing level */ static int diff = 0; /* produce diff listing, the default */ static int common = 0; /* produce common listing */ static int neither = 0; /* list caps in neither entry */ static int use = 0; /* produce use= comparison listing */ static enum printtypes printing /* doing any of above printing at all */ = pr_none; enum { none, by_database, by_terminfo, by_longnames, by_cap } sortorder = none; /* sort the fields for printing */ static char *term1info, *term2info; /* $TERMINFO settings */ static int Aflag = 0, Bflag = 0; /* $TERMINFO was set with -A/-B */ #define EQUAL(s1, s2) (((s1 == NULL) && (s2 == NULL)) || \ ((s1 != NULL) && (s2 != NULL) && \ (strcmp(s1, s2) == 0))) static void sortnames(); int numcompare(const void *, const void *); int boolcompare(const void *, const void *); int strcompare(const void *, const void *); static void check_nth_terminal(char *, int); void badmalloc() { (void) fprintf(stderr, "%s: malloc is out of space!\n", progname); exit(-1); } /* Allocate and initialize the global data structures and variables. */ void allocvariables(int argc, int firstoptind) { register int i, nullseen; /* find out how many names we are dealing with */ for (numbools = 0; boolnames[numbools]; numbools++) ; for (numnums = 0; numnames[numnums]; numnums++) ; for (numstrs = 0; strnames[numstrs]; numstrs++) ; if (verbose) { (void) fprintf(trace, "There are %d boolean capabilities.\n", numbools); (void) fprintf(trace, "There are %d numeric capabilities.\n", numnums); (void) fprintf(trace, "There are %d string capabilities.\n", numstrs); } /* Allocate storage for the names and their values */ ibool = (struct boolstruct *) malloc((unsigned) numbools * sizeof (struct boolstruct)); num = (struct numstruct *) malloc((unsigned) numnums * sizeof (struct numstruct)); str = (struct strstruct *) malloc((unsigned) numstrs * sizeof (struct strstruct)); /* Allocate array to keep track of which names have been used. */ if (use) used = (char *) malloc((unsigned) (argc - firstoptind) * sizeof (char)); if ((ibool == NULL) || (num == NULL) || (str == NULL) || (use && (used == NULL))) badmalloc(); /* Fill in the names and initialize the structures. */ nullseen = FALSE; for (i = 0; i < numbools; i++) { ibool[i].infoname = boolnames[i]; ibool[i].capname = boolcodes[i]; /* This is necessary until fnames.c is */ /* incorporated into standard curses. */ if (nullseen || (boolfnames[i] == NULL)) { ibool[i].fullname = "unknown_boolean"; nullseen = TRUE; } else ibool[i].fullname = boolfnames[i]; ibool[i].changed = FALSE; ibool[i].seenagain = FALSE; } nullseen = 0; for (i = 0; i < numnums; i++) { num[i].infoname = numnames[i]; num[i].capname = numcodes[i]; if (nullseen || (numfnames[i] == NULL)) { ibool[i].fullname = "unknown_number"; nullseen = TRUE; } else num[i].fullname = numfnames[i]; num[i].changed = FALSE; num[i].seenagain = FALSE; } nullseen = 0; for (i = 0; i < numstrs; i++) { str[i].infoname = strnames[i]; str[i].capname = strcodes[i]; if (nullseen || (strfnames[i] == NULL)) { str[i].fullname = "unknown_string"; nullseen = TRUE; } else str[i].fullname = strfnames[i]; str[i].changed = FALSE; str[i].seenagain = FALSE; } } /* Routines to be passed to qsort(3) for comparison of the structures. */ int boolcompare(const void *x, const void *y) { struct boolstruct *a; struct boolstruct *b; a = (struct boolstruct *)x; b = (struct boolstruct *)y; switch ((int) sortorder) { case (int) by_terminfo: return (strcmp(a->infoname, b->infoname)); case (int) by_cap: return (strcmp(a->capname, b->capname)); case (int) by_longnames: return (strcmp(a->fullname, b->fullname)); default: return (0); } } int numcompare(const void *x, const void *y) { struct numstruct *a; struct numstruct *b; a = (struct numstruct *)x; b = (struct numstruct *)y; switch ((int) sortorder) { case (int) by_terminfo: return (strcmp(a->infoname, b->infoname)); case (int) by_cap: return (strcmp(a->capname, b->capname)); case (int) by_longnames: return (strcmp(a->fullname, b->fullname)); default: return (0); } } int strcompare(const void *x, const void *y) { struct strstruct *a; struct strstruct *b; a = (struct strstruct *)x; b = (struct strstruct *)y; switch ((int) sortorder) { case (int) by_terminfo: return (strcmp(a->infoname, b->infoname)); case (int) by_cap: return (strcmp(a->capname, b->capname)); case (int) by_longnames: return (strcmp(a->fullname, b->fullname)); default: return (0); } } /* Sort the entries by their terminfo name. */ static void sortnames() { if (sortorder != by_database) { qsort((char *) ibool, (unsigned) numbools, sizeof (struct boolstruct), boolcompare); qsort((char *) num, (unsigned) numnums, sizeof (struct numstruct), numcompare); qsort((char *) str, (unsigned) numstrs, sizeof (struct strstruct), strcompare); } return; } /* Print out a string, or "NULL" if it's not defined. */ void PR(FILE *stream, char *string) { if (string == NULL) (void) fprintf(stream, "NULL"); else tpr(stream, string); } /* Output the 'ko' termcap string. This is a list of all of the input keys that input the same thing as the corresponding output strings. */ int kncounter; char kobuffer[512]; char *addko(char *output, char *input, char *koptr) { char *inptr, *outptr, padbuffer[512]; inptr = tgetstr(input, (char **)0); if (inptr == NULL) return (koptr); outptr = tgetstr(output, (char **)0); if (outptr == NULL) return (koptr); outptr = rmpadding(outptr, padbuffer, (int *) 0); if (strcmp(inptr, outptr) == 0) { *koptr++ = *output++; *koptr++ = *output++; *koptr++ = ','; kncounter++; } return (koptr); } void setupknko() { char *koptr; kncounter = 0; koptr = kobuffer; koptr = addko("bs", "kb", koptr); /* key_backspace */ koptr = addko("bt", "kB", koptr); /* key_btab */ koptr = addko("cl", "kC", koptr); /* key_clear */ koptr = addko("le", "kl", koptr); /* key_left */ koptr = addko("do", "kd", koptr); /* key_down */ koptr = addko("nd", "kr", koptr); /* key_right */ koptr = addko("up", "ku", koptr); /* key_up */ koptr = addko("dc", "kD", koptr); /* key_dc */ koptr = addko("dl", "kL", koptr); /* key_dl */ koptr = addko("cd", "kS", koptr); /* key_eos */ koptr = addko("ce", "kE", koptr); /* key_eol */ koptr = addko("ho", "kh", koptr); /* key_home */ koptr = addko("st", "kT", koptr); /* key_stab */ koptr = addko("ic", "kI", koptr); /* key_ic */ koptr = addko("im", "kI", koptr); /* key_ic */ koptr = addko("al", "kA", koptr); /* key_il */ koptr = addko("sf", "kF", koptr); /* key_sf */ koptr = addko("ll", "kH", koptr); /* key_ll */ koptr = addko("sr", "kR", koptr); /* key_sr */ koptr = addko("ei", "kM", koptr); /* key_eic */ koptr = addko("ct", "ka", koptr); /* key_catab */ /* get rid of comma */ if (koptr != kobuffer) *(--koptr) = '\0'; } void pr_kn() { if (kncounter > 0) pr_number((char *)0, "kn", (char *)0, kncounter); } void pr_ko() { if (kncounter > 0) pr_string((char *)0, "ko", (char *)0, kobuffer); } void pr_bcaps() { char *retptr; char padbuffer[512]; if (verbose) (void) fprintf(trace, "looking at 'bs'\n"); retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0)); if (strcmp("\\b", retptr) == 0) pr_boolean((char *)0, "bs", (char *)0, 1); if (verbose) (void) fprintf(trace, "looking at 'pt'\n"); retptr = cconvert(rmpadding(tab, padbuffer, (int *) 0)); if (strcmp("\\t", retptr) == 0) pr_boolean((char *)0, "pt", (char *)0, 1); if (verbose) (void) fprintf(trace, "looking at 'nc'\n"); retptr = cconvert(rmpadding(carriage_return, padbuffer, (int *) 0)); if (strcmp("\\r", retptr) != 0) pr_boolean((char *)0, "nc", (char *)0, 1); if (verbose) (void) fprintf(trace, "looking at 'ns'\n"); if (scroll_forward == NULL) pr_boolean((char *)0, "ns", (char *)0, 1); /* Ignore "xr": Return acts like ce \r \n (Delta Data) */ } void pr_ncaps() { char padbuffer[512]; int padding; if (verbose) (void) fprintf(trace, "looking at 'ug'\n"); /* Duplicate sg for ug: Number of blank chars left by us or ue */ if (magic_cookie_glitch > -1) pr_number((char *)0, "ug", (char *)0, magic_cookie_glitch); if (verbose) (void) fprintf(trace, "looking at 'dB'\n"); /* Number of millisec of bs delay needed */ (void) rmpadding(cursor_left, padbuffer, &padding); if (padding > 0) pr_number((char *)0, "dB", (char *)0, padding); if (verbose) (void) fprintf(trace, "looking at 'dC'\n"); /* Number of millisec of cr delay needed */ (void) rmpadding(carriage_return, padbuffer, &padding); if (padding > 0) pr_number((char *)0, "dC", (char *)0, padding); if (verbose) (void) fprintf(trace, "looking at 'dF'\n"); /* Number of millisec of ff delay needed */ (void) rmpadding(form_feed, padbuffer, &padding); if (padding > 0) pr_number((char *)0, "dF", (char *)0, padding); if (verbose) (void) fprintf(trace, "looking at 'dN'\n"); /* Number of millisec of nl delay needed */ (void) rmpadding(cursor_down, padbuffer, &padding); if (padding > 0) pr_number((char *)0, "dN", (char *)0, padding); if (verbose) (void) fprintf(trace, "looking at 'dT'\n"); /* Number of millisec of tab delay needed */ (void) rmpadding(tab, padbuffer, &padding); if (padding > 0) pr_number((char *)0, "dT", (char *)0, padding); /* Handle "kn": Number of "other" keys */ setupknko(); pr_kn(); } void pr_scaps() { char *retptr; char padbuffer[512]; /* Backspace if not "^H" */ if (verbose) (void) fprintf(trace, "looking at 'bc'\n"); retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0)); if (strcmp("\\b", retptr) != 0) pr_string((char *)0, "bc", (char *)0, cursor_left); /* Newline character (default "\n") */ if (verbose) (void) fprintf(trace, "looking at 'nl'\n"); retptr = cconvert(rmpadding(cursor_down, padbuffer, (int *) 0)); if (strcmp("\\n", retptr) != 0) pr_string((char *)0, "nl", (char *)0, cursor_down); /* Handle "ko" here: Termcap entries for other non-function keys */ pr_ko(); /* Ignore "ma": Arrow key map, used by vi version 2 only */ } /* Set up the first terminal and save the values from it. */ void initfirstterm(char *term) { register int i; if (verbose) (void) fprintf(trace, "setting up terminal type '%s'.\n", term); (void) setupterm(term, devnull, (int *) 0); /* Save the name for later use. */ if (use) { register unsigned int length; savettytype = _savettytype; if ((length = strlen(ttytype)) >= TTYLEN) { savettytype = malloc(length); if (savettytype == NULL) { (void) fprintf(stderr, "%s: malloc is out " "of space\n", progname); (void) strncpy(_savettytype, ttytype, TTYLEN-1); _savettytype[TTYLEN] = '\0'; savettytype = _savettytype; } } else (void) strcpy(_savettytype, ttytype); } if (printing != pr_none) { pr_heading(term, ttytype); pr_bheading(); } /* Save the values for the first terminal. */ for (i = 0; i < numbools; i++) { if ((ibool[i].val = tgetflag(ibool[i].capname)) && printing != pr_none) pr_boolean(ibool[i].infoname, ibool[i].capname, ibool[i].fullname, 1); if (verbose) (void) fprintf(trace, "%s=%d.\n", ibool[i].infoname, ibool[i].val); } if (printing != pr_none) { if (printing == pr_cap) pr_bcaps(); pr_bfooting(); pr_nheading(); } for (i = 0; i < numnums; i++) { if (((num[i].val = tgetnum(num[i].capname)) > -1) && printing != pr_none) pr_number(num[i].infoname, num[i].capname, num[i].fullname, num[i].val); if (verbose) (void) fprintf(trace, "%s=%d.\n", num[i].infoname, num[i].val); } if (printing != pr_none) { if (printing == pr_cap) pr_ncaps(); pr_nfooting(); pr_sheading(); } for (i = 0; i < numstrs; i++) { str[i].val = tgetstr(str[i].capname, (char **)0); if ((str[i].val != NULL) && printing != pr_none) pr_string(str[i].infoname, str[i].capname, str[i].fullname, str[i].val); if (verbose) { (void) fprintf(trace, "%s='", str[i].infoname); PR(trace, str[i].val); (void) fprintf(trace, "'.\n"); } } if (printing == pr_cap) pr_scaps(); if (printing != pr_none) pr_sfooting(); } /* Set up the n'th terminal. */ static void check_nth_terminal(char *nterm, int n) { register char boolval; register short numval; register char *strval; register int i; if (use) used[n] = FALSE; if (verbose) (void) fprintf(trace, "adding in terminal type '%s'.\n", nterm); (void) setupterm(nterm, devnull, (int *) 0); if (printing != pr_none) { pr_heading(nterm, ttytype); pr_bheading(); } if (diff || common || neither) { if (Aflag && Bflag) (void) printf("comparing %s (TERMINFO=%s) to %s " "(TERMINFO=%s).\n", firstterm, term1info, nterm, term2info); else if (Aflag) (void) printf("comparing %s (TERMINFO=%s) to %s.\n", firstterm, term1info, nterm); else if (Bflag) (void) printf("comparing %s to %s (TERMINFO=%s).\n", firstterm, nterm, term2info); else (void) printf("comparing %s to %s.\n", firstterm, nterm); (void) printf(" comparing booleans.\n"); } /* save away the values for the nth terminal */ for (i = 0; i < numbools; i++) { boolval = tgetflag(ibool[i].capname); if (use) { if (ibool[i].seenagain) { /* ** We do not have to worry about this impossible case ** since booleans can have only two values: true and ** false. ** if (boolval && (boolval != ibool[i].secondval)) ** { ** (void) fprintf(trace, "use= order dependency" ** "found:\n"); ** (void) fprintf(trace, " %s: %s has %d, %s has" ** " %d.\n", ** ibool[i].capname, ibool[i].secondname, ** ibool[i].secondval, nterm, boolval); ** } */ } else { if (boolval == TRUE) { ibool[i].seenagain = TRUE; ibool[i].secondval = boolval; ibool[i].secondname = nterm; if (ibool[i].val != boolval) ibool[i].changed = TRUE; else used[n] = TRUE; } } } if (boolval) { if (printing != pr_none) pr_boolean(ibool[i].infoname, ibool[i].capname, ibool[i].fullname, 1); if (common && (ibool[i].val == boolval)) (void) printf("\t%s= T.\n", ibool[i].infoname); } else if (neither && !ibool[i].val) (void) printf("\t!%s.\n", ibool[i].infoname); if (diff && (ibool[i].val != boolval)) (void) printf("\t%s: %c:%c.\n", ibool[i].infoname, ibool[i].val?'T':'F', boolval?'T':'F'); if (verbose) (void) fprintf(trace, "%s: %d:%d, changed=%d, " "seen=%d.\n", ibool[i].infoname, ibool[i].val, boolval, ibool[i].changed, ibool[i].seenagain); } if (printing != pr_none) { if (printing == pr_cap) pr_bcaps(); pr_bfooting(); pr_nheading(); } if (diff || common || neither) (void) printf(" comparing numbers.\n"); for (i = 0; i < numnums; i++) { numval = tgetnum(num[i].capname); if (use) { if (num[i].seenagain) { if ((numval > -1) && (numval != num[i].secondval)) { (void) fprintf(stderr, "%s: use = order dependency " "found:\n", progname); (void) fprintf(stderr, " %s: %s " "has %d, %s has %d.\n", num[i].capname, num[i].secondname, num[i].secondval, nterm, numval); } } else { if (numval > -1) { num[i].seenagain = TRUE; num[i].secondval = numval; num[i].secondname = nterm; if ((numval > -1) && (num[i].val != numval)) num[i].changed = TRUE; else used[n] = TRUE; } } } if (numval > -1) { if (printing != pr_none) pr_number(num[i].infoname, num[i].capname, num[i].fullname, numval); if (common && (num[i].val == numval)) (void) printf("\t%s= %d.\n", num[i].infoname, numval); } else if (neither && (num[i].val == -1)) (void) printf("\t!%s.\n", num[i].infoname); if (diff && (num[i].val != numval)) (void) printf("\t%s: %d:%d.\n", num[i].infoname, num[i].val, numval); if (verbose) (void) fprintf(trace, "%s: %d:%d, " "changed = %d, seen = %d.\n", num[i].infoname, num[i].val, numval, num[i].changed, num[i].seenagain); } if (printing != pr_none) { if (printing == pr_cap) pr_ncaps(); pr_nfooting(); pr_sheading(); } if (diff || common || neither) (void) printf(" comparing strings.\n"); for (i = 0; i < numstrs; i++) { strval = tgetstr(str[i].capname, (char **)0); if (use) { if (str[i].seenagain && (strval != NULL)) { if (!EQUAL(strval, str[i].secondval)) { (void) fprintf(stderr, "use= order dependency" " found:\n"); (void) fprintf(stderr, " %s: %s has '", str[i].capname, str[i].secondname); PR(stderr, str[i].secondval); (void) fprintf(stderr, "', %s has '", nterm); PR(stderr, strval); (void) fprintf(stderr, "'.\n"); } } else { if (strval != NULL) { str[i].seenagain = TRUE; str[i].secondval = strval; str[i].secondname = nterm; if (!EQUAL(str[i].val, strval)) str[i].changed = TRUE; else used[n] = TRUE; } } } if (strval != NULL) { if (printing != pr_none) pr_string(str[i].infoname, str[i].capname, str[i].fullname, strval); if (common && EQUAL(str[i].val, strval)) { (void) printf("\t%s= '", str[i].infoname); PR(stdout, strval); (void) printf("'.\n"); } } else if (neither && (str[i].val == NULL)) (void) printf("\t!%s.\n", str[i].infoname); if (diff && !EQUAL(str[i].val, strval)) { (void) printf("\t%s: '", str[i].infoname); PR(stdout, str[i].val); (void) printf("','"); PR(stdout, strval); (void) printf("'.\n"); } if (verbose) { (void) fprintf(trace, "%s: '", str[i].infoname); PR(trace, str[i].val); (void) fprintf(trace, "':'"); PR(trace, strval); (void) fprintf(trace, "',changed=%d,seen=%d.\n", str[i].changed, str[i].seenagain); } } if (printing == pr_cap) pr_scaps(); if (printing != pr_none) pr_sfooting(); return; } /* A capability gets an at-sign if it no longer exists, but one of the relative entries contains a value for it. It gets printed if the original value is not seen in ANY of the relative entries, or if the FIRST relative entry that has the capability gives a DIFFERENT value for the capability. */ void dorelative(int firstoptind, int argc, char **argv) { register int i; /* turn off printing of termcap and long names */ pr_init(pr_terminfo); /* print out the entry name */ pr_heading((char *)0, savettytype); pr_bheading(); /* Print out all bools that are different. */ for (i = 0; i < numbools; i++) if (!ibool[i].val && ibool[i].changed) pr_boolean(ibool[i].infoname, (char *)0, (char *)0, -1); else if (ibool[i].val && (ibool[i].changed || !ibool[i].seenagain)) pr_boolean(ibool[i].infoname, (char *)0, (char *)0, 1); pr_bfooting(); pr_nheading(); /* Print out all nums that are different. */ for (i = 0; i < numnums; i++) if (num[i].val < 0 && num[i].changed) pr_number(num[i].infoname, (char *)0, (char *)0, -1); else if (num[i].val >= 0 && (num[i].changed || !num[i].seenagain)) pr_number(num[i].infoname, (char *)0, (char *)0, num[i].val); pr_nfooting(); pr_sheading(); /* Print out all strs that are different. */ for (i = 0; i < numstrs; i++) if (str[i].val == NULL && str[i].changed) pr_string(str[i].infoname, (char *)0, (char *)0, (char *)0); else if ((str[i].val != NULL) && (str[i].changed || !str[i].seenagain)) pr_string(str[i].infoname, (char *)0, (char *)0, str[i].val); pr_sfooting(); /* Finish it up. */ for (i = firstoptind; i < argc; i++) if (used[i - firstoptind]) (void) printf("\tuse=%s,\n", argv[i]); else (void) fprintf(stderr, "%s: 'use=%s' did not add anything to the " "description.\n", progname, argv[i]); } void local_setenv(char *termNinfo) { extern char **environ; static char *newenviron[2] = { 0, 0 }; static unsigned int termsize = BUFSIZ; static char _terminfo[BUFSIZ]; static char *terminfo = &_terminfo[0]; register int termlen; if (termNinfo && *termNinfo) { if (verbose) (void) fprintf(trace, "setting TERMINFO=%s.\n", termNinfo); termlen = strlen(termNinfo); if (termlen + 10 > termsize) { termsize = termlen + 20; terminfo = (char *) malloc(termsize * sizeof (char)); } if (terminfo == (char *) NULL) badmalloc(); (void) sprintf(terminfo, "TERMINFO=%s", termNinfo); newenviron[0] = terminfo; } else newenviron[0] = (char *) 0; environ = newenviron; } int main(int argc, char **argv) { int i, c, firstoptind; char *tempargv[2]; char *term = getenv("TERM"); term1info = term2info = getenv("TERMINFO"); progname = argv[0]; /* parse options */ while ((c = getopt(argc, argv, "ducnILCvV1rw:s:A:B:")) != EOF) switch (c) { case 'v': verbose++; break; case '1': pr_onecolumn(1); break; case 'w': pr_width(atoi(optarg)); break; case 'd': diff++; break; case 'c': common++; break; case 'n': neither++; break; case 'u': use++; break; case 'L': pr_init(printing = pr_longnames); break; case 'I': pr_init(printing = pr_terminfo); break; case 'C': pr_init(printing = pr_cap); break; case 'A': term1info = optarg; Aflag++; break; case 'B': term2info = optarg; Bflag++; break; case 'r': pr_caprestrict(0); break; case 's': if (strcmp(optarg, "d") == 0) sortorder = by_database; else if (strcmp(optarg, "i") == 0) sortorder = by_terminfo; else if (strcmp(optarg, "l") == 0) sortorder = by_longnames; else if (strcmp(optarg, "c") == 0) sortorder = by_cap; else goto usage; break; case 'V': (void) printf("%s: version %s\n", progname, "@(#)curses:screen/infocmp.c 1.13"); exit(0); case '?': usage: (void) fprintf(stderr, "usage: %s [-ducn] [-ILC] [-1Vv] " "[-s d|i|l|c] [-A directory] " "[-B directory] term-names ...\n", progname); (void) fprintf(stderr, "\t-d\tprint " "differences (the default for >1 " "term-name)\n"); (void) fprintf(stderr, "\t-u\tproduce " "relative description\n"); (void) fprintf(stderr, "\t-c\tprint common " "entries\n"); (void) fprintf(stderr, "\t-n\tprint entries " "in neither\n"); (void) fprintf(stderr, "\t-I\tprint terminfo " "entries (the default for 1 term-name)\n"); (void) fprintf(stderr, "\t-C\tprint termcap " "entries\n"); (void) fprintf(stderr, "\t-L\tprint long C " "variable names\n"); (void) fprintf(stderr, "\t-1\tsingle column " "output\n"); (void) fprintf(stderr, "\t-V\tprint program " "version\n"); (void) fprintf(stderr, "\t-v\tverbose " "debugging output\n"); (void) fprintf(stderr, "\t-s\tchange sort " "order\n"); (void) fprintf(stderr, "\t-A\tset $TERMINFO " "for first term-name\n"); (void) fprintf(stderr, "\t-B\tset $TERMINFO " "for other term-names\n"); exit(-1); } argc -= optind; argv += optind; optind = 0; /* Default to $TERM for -n, -I, -C and -L options. */ /* This is done by faking argv[][], argc and optind. */ if (neither && (argc == 0 || argc == 1)) { if (argc == 0) tempargv[0] = term; else tempargv[0] = argv[optind]; tempargv[1] = term; argc = 2; argv = tempargv; optind = 0; } else if ((printing != pr_none) && (argc == 0)) { tempargv[0] = term; argc = 1; argv = tempargv; optind = 0; } /* Check for enough names. */ if ((use || diff || common) && (argc <= 1)) { (void) fprintf(stderr, "%s: must have at least two terminal names for a " "comparison to be done.\n", progname); goto usage; } /* Set the default of diff -d or print -I */ if (!use && (printing == pr_none) && !common && !neither) { if (argc == 0 || argc == 1) { if (argc == 0) { tempargv[0] = term; argc = 1; argv = tempargv; optind = 0; } pr_init(printing = pr_terminfo); } else diff++; } /* Set the default sorting order. */ if (sortorder == none) switch ((int) printing) { case (int) pr_cap: sortorder = by_cap; break; case (int) pr_longnames: sortorder = by_longnames; break; case (int) pr_terminfo: case (int) pr_none: sortorder = by_terminfo; break; } firstterm = argv[optind++]; firstoptind = optind; allocvariables(argc, firstoptind); sortnames(); devnull = open("/dev/null", O_RDWR); local_setenv(term1info); initfirstterm(firstterm); local_setenv(term2info); for (i = 0; optind < argc; optind++, i++) check_nth_terminal(argv[optind], i); if (use) dorelative(firstoptind, argc, argv); return (0); }