static bool allow_gpm_mouse(void) { bool result = FALSE; /* GPM does printf's without checking if stdout is a terminal */ if (isatty(fileno(stdout))) { char *list = getenv("NCURSES_GPM_TERMS"); char *env = getenv("TERM"); if (list != 0) { if (env != 0) { result = _nc_name_match(list, env, "|:"); } } else { /* GPM checks the beginning of the $TERM variable to decide if it * should pass xterm events through. There is no real advantage in * allowing GPM to do this. Recent versions relax that check, and * pretend that GPM can work with any terminal having the kmous * capability. Perhaps that works for someone. If so, they can * set the environment variable (above). */ if (env != 0 && strstr(env, "linux") != 0) { result = TRUE; } } } return result; }
static bool allow_gpm_mouse(SCREEN *sp) { bool result = FALSE; #if USE_WEAK_SYMBOLS /* Danger Robinson: do not use dlopen for libgpm if already loaded */ if ((Gpm_Wgetch)) { if (!sp->_mouse_gpm_loaded) { T(("GPM library was already dlopen'd, not by us")); } } else #endif /* GPM does printf's without checking if stdout is a terminal */ if (isatty(fileno(stdout))) { char *list = getenv("NCURSES_GPM_TERMS"); char *env = getenv("TERM"); if (list != 0) { if (env != 0) { result = _nc_name_match(list, env, "|:"); } } else { /* GPM checks the beginning of the $TERM variable to decide if it * should pass xterm events through. There is no real advantage in * allowing GPM to do this. Recent versions relax that check, and * pretend that GPM can work with any terminal having the kmous * capability. Perhaps that works for someone. If so, they can * set the environment variable (above). */ if (env != 0 && strstr(env, "linux") != 0) { result = TRUE; } } } return result; }
_nc_resolve_uses2(bool fullresolve, bool literal) /* try to resolve all use capabilities */ { ENTRY *qp, *rp, *lastread = 0; bool keepgoing; unsigned i; int unresolved, total_unresolved, multiples; DEBUG(2, ("RESOLUTION BEGINNING")); /* * Check for multiple occurrences of the same name. */ multiples = 0; for_entry_list(qp) { int matchcount = 0; for_entry_list(rp) { if (qp > rp && _nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) { matchcount++; if (matchcount == 1) { (void) fprintf(stderr, "Name collision between %s", _nc_first_name(qp->tterm.term_names)); multiples++; } if (matchcount >= 1) (void) fprintf(stderr, " %s", _nc_first_name(rp->tterm.term_names)); } } if (matchcount >= 1) (void) putc('\n', stderr); } if (multiples > 0) return (FALSE); DEBUG(2, ("NO MULTIPLE NAME OCCURRENCES")); /* * First resolution stage: compute link pointers corresponding to names. */ total_unresolved = 0; _nc_curr_col = -1; for_entry_list(qp) { unresolved = 0; for (i = 0; i < qp->nuses; i++) { bool foundit; char *child = _nc_first_name(qp->tterm.term_names); char *lookfor = qp->uses[i].name; long lookline = qp->uses[i].line; foundit = FALSE; _nc_set_type(child); /* first, try to resolve from in-core records */ for_entry_list(rp) { if (rp != qp && _nc_name_match(rp->tterm.term_names, lookfor, "|")) { DEBUG(2, ("%s: resolving use=%s (in core)", child, lookfor)); qp->uses[i].link = rp; foundit = TRUE; } } /* if that didn't work, try to merge in a compiled entry */ if (!foundit) { TERMTYPE thisterm; char filename[PATH_MAX]; memset(&thisterm, 0, sizeof(thisterm)); if (_nc_read_entry(lookfor, filename, &thisterm) == 1) { DEBUG(2, ("%s: resolving use=%s (compiled)", child, lookfor)); rp = typeMalloc(ENTRY, 1); if (rp == 0) _nc_err_abort(MSG_NO_MEMORY); rp->tterm = thisterm; rp->nuses = 0; rp->next = lastread; lastread = rp; qp->uses[i].link = rp; foundit = TRUE; } } /* no good, mark this one unresolvable and complain */ if (!foundit) { unresolved++; total_unresolved++; _nc_curr_line = lookline; _nc_warning("resolution of use=%s failed", lookfor); qp->uses[i].link = 0; } } } if (total_unresolved) { /* free entries read in off disk */ _nc_free_entries(lastread); return (FALSE); } DEBUG(2, ("NAME RESOLUTION COMPLETED OK")); /* * OK, at this point all (char *) references in `name' members * have been successfully converted to (ENTRY *) pointers in * `link' members. Time to do the actual merges. */ if (fullresolve) { do { TERMTYPE merged; keepgoing = FALSE; for_entry_list(qp) { if (qp->nuses > 0) { DEBUG(2, ("%s: attempting merge", _nc_first_name(qp->tterm.term_names))); /* * If any of the use entries we're looking for is * incomplete, punt. We'll catch this entry on a * subsequent pass. */ for (i = 0; i < qp->nuses; i++) if (qp->uses[i].link->nuses) { DEBUG(2, ("%s: use entry %d unresolved", _nc_first_name(qp->tterm.term_names), i)); goto incomplete; } /* * First, make sure there is no garbage in the * merge block. As a side effect, copy into * the merged entry the name field and string * table pointer. */ _nc_copy_termtype(&merged, &(qp->tterm)); /* * Now merge in each use entry in the proper * (reverse) order. */ for (; qp->nuses; qp->nuses--) _nc_merge_entry(&merged, &qp->uses[qp->nuses - 1].link->tterm); /* * Now merge in the original entry. */ _nc_merge_entry(&merged, &qp->tterm); /* * Replace the original entry with the merged one. */ FreeIfNeeded(qp->tterm.Booleans); FreeIfNeeded(qp->tterm.Numbers); FreeIfNeeded(qp->tterm.Strings); #if NCURSES_XNAMES FreeIfNeeded(qp->tterm.ext_Names); #endif qp->tterm = merged; _nc_wrap_entry(qp, TRUE); /* * We know every entry is resolvable because name resolution * didn't bomb. So go back for another pass. */ /* FALLTHRU */ incomplete: keepgoing = TRUE; } } } while (keepgoing); DEBUG(2, ("MERGES COMPLETED OK")); } /* * We'd like to free entries read in off disk at this point, but can't. * The merge_entry() code doesn't copy the strings in the use entries, * it just aliases them. If this ever changes, do a * free_entries(lastread) here. */ DEBUG(2, ("RESOLUTION FINISHED")); if (fullresolve) if (_nc_check_termtype != 0) { _nc_curr_col = -1; for_entry_list(qp) { _nc_curr_line = qp->startline; _nc_set_type(_nc_first_name(qp->tterm.term_names)); _nc_check_termtype2(&qp->tterm, literal); } DEBUG(2, ("SANITY CHECK FINISHED")); }
/* * Get an entry for terminal name in buffer _nc_termcap from the termcap * file. */ int _nc_read_termcap_entry(const char *const name, TERMTYPE *const tp) { ENTRY *ep; char *p; char *cp; char *dummy; char **fname; char *home; int i; char pathbuf[PBUFSIZ]; /* holds raw path of filenames */ char *pathvec[PVECSIZ]; /* to point to names in pathbuf */ char **pvec; /* holds usable tail of path vector */ char *termpath; _nc_termcap[0] = '\0'; /* in case */ dummy = NULL; fname = pathvec; pvec = pathvec; p = pathbuf; cp = getenv("TERMCAP"); /* * TERMCAP can have one of two things in it. It can be the * name of a file to use instead of /etc/termcap. In this * case it better start with a "/". Or it can be an entry to * use so we don't have to read the file. In this case it * has to already have the newlines crunched out. If TERMCAP * does not hold a file name then a path of names is searched * instead. The path is found in the TERMPATH variable, or * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists. */ if (!cp || *cp != '/') { /* no TERMCAP or it holds an entry */ if ( (termpath = getenv("TERMPATH")) ) strncpy(pathbuf, termpath, PBUFSIZ); else { if ( (home = getenv("HOME")) ) {/* set up default */ strncpy(pathbuf, home, PBUFSIZ - 1); /* $HOME first */ pathbuf[PBUFSIZ - 2] = '\0'; /* -2 because we add a slash */ p += strlen(pathbuf); /* path, looking in */ *p++ = '/'; } /* if no $HOME look in current directory */ strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf)); } } else /* user-defined name in TERMCAP */ strncpy(pathbuf, cp, PBUFSIZ); /* still can be tokenized */ /* For safety */ if (issetugid()) strcpy(pathbuf, _PATH_DEF_SEC); pathbuf[PBUFSIZ - 1] = '\0'; *fname++ = pathbuf; /* tokenize path into vector of names */ while (*++p) if (*p == ' ' || *p == ':') { *p = '\0'; while (*++p) if (*p != ' ' && *p != ':') break; if (*p == '\0') break; *fname++ = p; if (fname >= pathvec + PVECSIZ) { fname--; break; } } *fname = (char *) 0; /* mark end of vector */ if (cp && *cp && *cp != '/') if (cgetset(cp) < 0) return(-2); i = cgetent(&dummy, pathvec, (char *)name); if (i == 0) { char *pd, *ps, *tok, *s, *tcs; size_t len; pd = _nc_termcap; ps = dummy; if ((tok = strchr(ps, ':')) == NULL) { len = strlen(ps); if (len >= TBUFSIZ) i = -1; else strcpy(pd, ps); goto done; } len = tok - ps + 1; if (pd + len + 1 - _nc_termcap >= TBUFSIZ) { i = -1; goto done; } memcpy(pd, ps, len); ps += len; pd += len; *pd = '\0'; tcs = pd - 1; for (;;) { while ((tok = strsep(&ps, ":")) != NULL && *(tok - 2) != '\\' && (*tok == '\0' || *tok == '\\' || !isgraph(UChar(*tok)))) ; if (tok == NULL) break; for (s = tcs; s != NULL && s[1] != '\0'; s = strchr(s, ':')) { s++; if (s[0] == tok[0] && s[1] == tok[1]) goto skip_it; } len = strlen(tok); if (pd + len + 1 - _nc_termcap >= TBUFSIZ) { i = -1; break; } memcpy(pd, tok, len); pd += len; *pd++ = ':'; *pd = '\0'; skip_it: ; } } done: if (dummy) free(dummy); /* * From here on is ncurses-specific glue code */ if (i < 0) return(TGETENT_ERR); _nc_set_source("TERMCAP"); _nc_read_entry_source((FILE *)NULL, _nc_termcap, FALSE, TRUE, NULLHOOK); if (_nc_head == (ENTRY *)NULL) return(TGETENT_ERR); /* resolve all use references */ _nc_resolve_uses2(TRUE, FALSE); for_entry_list(ep) if (_nc_name_match(ep->tterm.term_names, name, "|:")) { /* * Make a local copy of the terminal capabilities, delinked * from the list. */ memcpy(tp, &ep->tterm, sizeof(TERMTYPE)); _nc_delink_entry(_nc_head, &(ep->tterm)); free(ep); _nc_free_entries(_nc_head); _nc_head = _nc_tail = NULL; /* do not reuse! */ return TGETENT_YES; /* OK */ } _nc_free_entries(_nc_head); _nc_head = _nc_tail = NULL; /* do not reuse! */ return(TGETENT_NO); /* not found */ }
int _nc_read_termcap_entry(const char *const tn, TERMTYPE *const tp) { int found = FALSE; ENTRY *ep; #if USE_GETCAP_CACHE char cwd_buf[PATH_MAX]; #endif #if USE_GETCAP char tc[TBUFSIZ]; static char *source; static int lineno; /* we're using getcap(3) */ if (_nc_tgetent(tc, &source, &lineno, tn) < 0) return (ERR); _nc_curr_line = lineno; _nc_set_source(source); _nc_read_entry_source((FILE *)0, tc, FALSE, FALSE, NULLHOOK); #else /* * Here is what the 4.4BSD termcap(3) page prescribes: * * It will look in the environment for a TERMCAP variable. If found, * and the value does not begin with a slash, and the terminal type * name is the same as the environment string TERM, the TERMCAP string * is used instead of reading a termcap file. If it does begin with a * slash, the string is used as a path name of the termcap file to * search. If TERMCAP does not begin with a slash and name is * different from TERM, tgetent() searches the files $HOME/.termcap and * /usr/share/misc/termcap, in that order, unless the environment * variable TERMPATH exists, in which case it specifies a list of file * pathnames (separated by spaces or colons) to be searched instead. * * It goes on to state: * * Whenever multiple files are searched and a tc field occurs in the * requested entry, the entry it names must be found in the same file * or one of the succeeding files. * * However, this restriction is relaxed in ncurses; tc references to * previous files are permitted. * * This routine returns 1 if an entry is found, 0 if not found, and -1 * if the database is not accessible. */ FILE *fp; char *tc, *termpaths[MAXPATHS]; int filecount = 0; bool use_buffer = FALSE; char tc_buf[1024]; char pathbuf[PATH_MAX]; termpaths[filecount] = 0; if ((tc = getenv("TERMCAP")) != 0) { if (is_pathname(tc)) /* interpret as a filename */ { ADD_TC(tc, 0); } else if (_nc_name_match(tc, tn, "|:")) /* treat as a capability file */ { use_buffer = TRUE; (void) sprintf(tc_buf, "%.*s\n", (int)sizeof(tc_buf)-2, tc); } else if ((tc = getenv("TERMPATH")) != 0) { char *cp; for (cp = tc; *cp; cp++) { if (*cp == ':') *cp = '\0'; else if (cp == tc || cp[-1] == '\0') { ADD_TC(cp, filecount); } } } } else /* normal case */ { char envhome[PATH_MAX], *h; filecount = 0; /* * Probably /etc/termcap is a symlink to /usr/share/misc/termcap. * Avoid reading the same file twice. */ if (_nc_access("/etc/termcap", F_OK) == 0) ADD_TC("/etc/termcap", filecount); else ADD_TC("/usr/share/misc/termcap", filecount); if ((h = getenv("HOME")) != NULL && strlen(h) + 9 < PATH_MAX) { /* user's .termcap, if any, should override it */ (void) strcpy(envhome, h); (void) sprintf(pathbuf, "%s/.termcap", envhome); ADD_TC(pathbuf, filecount); } } /* parse the sources */ if (use_buffer) { _nc_set_source("TERMCAP"); /* * We don't suppress warning messages here. The presumption is * that since it's just a single entry, they won't be a pain. */ _nc_read_entry_source((FILE *)0, tc_buf, FALSE, FALSE, NULLHOOK); } else { int i; for (i = 0; i < filecount; i++) { T(("Looking for %s in %s", tn, termpaths[i])); if ((fp = fopen(termpaths[i], "r")) != (FILE *)0) { _nc_set_source(termpaths[i]); /* * Suppress warning messages. Otherwise you * get 400 lines of crap from archaic termcap * files as ncurses complains about all the * obsolete capabilities. */ _nc_read_entry_source(fp, (char*)0, FALSE, TRUE, NULLHOOK); (void) fclose(fp); } } } #endif /* USE_GETCAP */ if (_nc_head == 0) return(ERR); /* resolve all use references */ _nc_resolve_uses(); /* find a terminal matching tn, if we can */ #if USE_GETCAP_CACHE if (getcwd(cwd_buf, sizeof(cwd_buf)) != 0) { _nc_set_writedir((char *)0); /* note: this does a chdir */ #endif for_entry_list(ep) { if (_nc_name_match(ep->tterm.term_names, tn, "|:")) { /* * Make a local copy of the terminal * capabilities. Free all entry storage except * the string table for the loaded type (which * we disconnected from the list by NULLing out * ep->tterm.str_table above). */ memcpy(tp, &ep->tterm, sizeof(TERMTYPE)); ep->tterm.str_table = (char *)0; /* * OK, now try to write the type to user's * terminfo directory. Next time he loads * this, it will come through terminfo. * * Advantage: Second and subsequent fetches of * this entry will be very fast. * * Disadvantage: After the first time a * termcap type is loaded by its user, editing * it in the /etc/termcap file, or in TERMCAP, * or in a local ~/.termcap, will be * ineffective unless the terminfo entry is * explicitly removed. */ #if USE_GETCAP_CACHE (void) _nc_write_entry(tp); #endif found = TRUE; break; } } #if USE_GETCAP_CACHE chdir(cwd_buf); }