1 #include "lesstest.h"
2
3 extern TermInfo terminfo;
4
5 // EnvBuf has a char buffer (env_buf) which holds both the env var
6 // string table and also the array of pointers to individual strings (env_list).
7 // env_estr points to the end of the string table.
8 // The env_list array grows backwards from the end of env_buf.
9
env_init(EnvBuf * env)10 void env_init(EnvBuf* env) {
11 env->env_estr = (char*) env->env_buf;
12 env->env_list = env->env_buf + sizeof(env->env_buf)/sizeof(char*);
13 *--(env->env_list) = NULL;
14 }
15
env_check(EnvBuf * env)16 static void env_check(EnvBuf* env) {
17 if (env->env_estr >= (const char*) env->env_list) {
18 fprintf(stderr, "ENVBUF_SIZE too small!\n");
19 abort();
20 }
21 }
22
23 // Add a char to the string table.
env_addchar(EnvBuf * env,char ch)24 static void env_addchar(EnvBuf* env, char ch) {
25 *(env->env_estr)++ = ch;
26 env_check(env);
27 }
28
29 // Add a delimited string to the string table.
env_addlstr(EnvBuf * env,const char * str,int strlen)30 static void env_addlstr(EnvBuf* env, const char* str, int strlen) {
31 while (strlen-- > 0)
32 env_addchar(env, *str++);
33 }
34
35 // Add a null-terminated string to the string table.
env_addstr(EnvBuf * env,const char * str)36 static void env_addstr(EnvBuf* env, const char* str) {
37 env_addlstr(env, str, strlen(str));
38 }
39
40 // Add an env variable name/value pair to an EnvBuf.
41 // The name is delimited and the value is null-terminated.
env_addlpair(EnvBuf * env,const char * name,int namelen,const char * value)42 static void env_addlpair(EnvBuf* env, const char* name, int namelen, const char* value) {
43 *--(env->env_list) = env->env_estr;
44 env_check(env);
45 env_addlstr(env, name, namelen);
46 env_addstr(env, "=");
47 env_addstr(env, value);
48 env_addchar(env, '\0');
49 }
50
51 // Add an env variable name/value pair to an EnvBuf.
env_addpair(EnvBuf * env,const char * name,const char * value)52 void env_addpair(EnvBuf* env, const char* name, const char* value) {
53 env_addlpair(env, name, strlen(name), value);
54 }
55
56 // Add an env variable name/value pair to an EnvBuf where the value is an integer.
env_addintpair(EnvBuf * env,const char * name,int value)57 void env_addintpair(EnvBuf* env, const char* name, int value) {
58 char buf[64];
59 snprintf(buf, sizeof(buf), "%d", value);
60 env_addpair(env, name, buf);
61 }
62
63 // Is a given env var name one which should be passed to less?
is_less_env(const char * name,int name_len)64 static int is_less_env(const char* name, int name_len) {
65 static char* const less_names[] = {
66 "LESS*", "COLUMNS", "LINES", "LANG", "LC_CTYPE", "MORE", NULL
67 };
68 char* const* n;
69 for (n = less_names; *n != NULL; ++n) {
70 int ln = strlen(*n);
71 if (ln == name_len && strncmp(*n, name, ln) == 0)
72 return 1;
73 if ((*n)[ln-1] == '*' && strncmp(*n, name, ln-1) == 0)
74 return 1;
75 }
76 return 0;
77 }
78
79 // Create a list of env vars to be given to an instance of less,
80 // as an EnvBuf.
env_setup(EnvBuf * env,char * const * prog_env,int interactive)81 static void env_setup(EnvBuf* env, char* const* prog_env, int interactive) {
82 char* const* envp;
83 struct tcvar { char const* name; char const* value; } tcvars[] = {
84 { "LESS_TERMCAP_am", "1" },
85 { "LESS_TERMCAP_cd", "\33S" },
86 { "LESS_TERMCAP_ce", "\33L" },
87 { "LESS_TERMCAP_cl", "\33A" },
88 { "LESS_TERMCAP_cr", "\33<" },
89 { "LESS_TERMCAP_cm", "\33%p2%d;%p1%dj" },
90 { "LESS_TERMCAP_ho", "\33h" },
91 { "LESS_TERMCAP_ll", "\33l" },
92 { "LESS_TERMCAP_mb", "\33b" },
93 { "LESS_TERMCAP_md", "\33[1m" },
94 { "LESS_TERMCAP_me", "\33[m" },
95 { "LESS_TERMCAP_se", "\33[m" },
96 { "LESS_TERMCAP_so", "\33[7m" },
97 { "LESS_TERMCAP_sr", "\33r" },
98 { "LESS_TERMCAP_ue", "\33[24m" },
99 { "LESS_TERMCAP_us", "\33[4m" },
100 { "LESS_TERMCAP_vb", "\33g" },
101 { "LESS_TERMCAP_kr", terminfo.key_right },
102 { "LESS_TERMCAP_kl", terminfo.key_left },
103 { "LESS_TERMCAP_ku", terminfo.key_up },
104 { "LESS_TERMCAP_kd", terminfo.key_down },
105 { "LESS_TERMCAP_kh", terminfo.key_home },
106 { "LESS_TERMCAP_@7", terminfo.key_end },
107 };
108 if (interactive) {
109 int i;
110 for (i = 0; i < countof(tcvars); ++i) {
111 struct tcvar* tc = &tcvars[i];
112 env_addpair(env, tc->name, tc->value);
113 log_env(tc->name, strlen(tc->name), tc->value);
114 }
115 }
116 for (envp = prog_env; *envp != NULL; ++envp) {
117 const char* ename = *envp;
118 const char* eq = strchr(ename, '=');
119 if (eq == NULL) continue;
120 if (!interactive || is_less_env(ename, eq-ename)) {
121 env_addlpair(env, ename, eq-ename, eq+1);
122 log_env(ename, eq-ename, eq+1);
123 }
124 }
125 }
126
127 // Return the value of a named env var.
get_envp(char * const * envp,const char * name)128 const char* get_envp(char* const* envp, const char* name) {
129 for (; *envp != NULL; ++envp) {
130 const char* ename = *envp;
131 const char* eq = strchr(ename, '=');
132 if (eq != NULL && strlen(name) == eq-ename && strncmp(name, ename, eq-ename) == 0)
133 return eq+1;
134 }
135 return NULL;
136 }
137
138 // Return a list of env vars to be given to an instance of less,
139 // as an array of strings.
less_envp(char * const * envp,int interactive)140 char* const* less_envp(char* const* envp, int interactive) {
141 static EnvBuf less_env;
142 static int init = 0;
143 if (!init) {
144 env_init(&less_env);
145 env_setup(&less_env, envp, interactive);
146 init = 1;
147 }
148 return less_env.env_list;
149 }
150