~ctwm/ctwm/trunk

387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
1
/*
2
 * Parser -- M4 specific routines.  Some additional stuff from parse.c
3
 * should probably migrate here over time.
4
 */
5
395.1.1 by Matthew Fuller
Move ctwm.h to always be included first.
6
#include "ctwm.h"
7
429.1.19 by Matthew Fuller
Try a little harder to figure out the username.
8
#include <sys/types.h>
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
9
#include <stdio.h>
429.1.1 by Matthew Fuller
mkstemp() is technically in stdlib.h; we're getting it via pollution
10
#include <stdlib.h>
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
11
#include <unistd.h>
12
#include <netdb.h>
429.1.19 by Matthew Fuller
Try a little harder to figure out the username.
13
#include <pwd.h>
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
14
15
#include "screen.h"
16
#include "parse.h"
17
#include "parse_int.h"
18
#include "version.h"
19
20
597.1.4 by Matthew Fuller
Trivial arg const-ification.
21
static char *m4_defs(Display *display, const char *host);
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
22
23
24
/*
25
 * Primary entry point to do m4 parsing of a startup file
26
 */
597.1.3 by Matthew Fuller
Break function definitions as long as I'm in here.
27
FILE *
28
start_m4(FILE *fraw)
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
29
{
30
	int fids[2];
431.1.3 by Matthew Fuller
Add some comments and whitespace around start_m4() to make the flow
31
	int fres;
431.1.4 by Matthew Fuller
Pull writing of the defs file out of the post-fork child, and be sure
32
	char *defs_file;
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
33
431.1.4 by Matthew Fuller
Pull writing of the defs file out of the post-fork child, and be sure
34
	/* Write our our standard definitions into a temp file */
35
	defs_file = m4_defs(dpy, CLarg.display_name);
36
431.1.3 by Matthew Fuller
Add some comments and whitespace around start_m4() to make the flow
37
	/* We'll read back m4's output over a pipe */
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
38
	pipe(fids);
431.1.3 by Matthew Fuller
Add some comments and whitespace around start_m4() to make the flow
39
40
	/* Fork off m4 as a child */
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
41
	fres = fork();
42
	if(fres < 0) {
43
		perror("Fork for " M4CMD " failed");
431.1.4 by Matthew Fuller
Pull writing of the defs file out of the post-fork child, and be sure
44
		unlink(defs_file);
597.1.5 by Matthew Fuller
Switch to allocating this string on the heap instead of using a static
45
		free(defs_file);
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
46
		exit(23);
47
	}
431.1.3 by Matthew Fuller
Add some comments and whitespace around start_m4() to make the flow
48
49
	/*
50
	 * Child: setup and spawn m4, and have it write its output into one
51
	 * end of our pipe.
52
	 */
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
53
	if(fres == 0) {
431.1.6 by Matthew Fuller
Comment.
54
		/* Setup file descriptors */
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
55
		close(0);               /* stdin */
56
		close(1);               /* stdout */
597.1.2 by Matthew Fuller
This var is only used once, so just inline the fileno() call.
57
		dup2(fileno(fraw), 0);  /* stdin = fraw */
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
58
		dup2(fids[1], 1);       /* stdout = pipe to parent */
431.1.5 by Matthew Fuller
Spell out more explicitly what the m4 command is doing, so we don't
59
60
		/*
61
		 * Kick off m4, telling it both our file of definitions, and
62
		 * stdin (dup of the .[c]twmrc file descriptor above) as input.
63
		 * It writes to stdout (one end of our pipe).
64
		 */
431.1.4 by Matthew Fuller
Pull writing of the defs file out of the post-fork child, and be sure
65
		execlp(M4CMD, M4CMD, "-s", defs_file, "-", NULL);
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
66
67
		/* If we get here we are screwed... */
68
		perror("Can't execlp() " M4CMD);
431.1.4 by Matthew Fuller
Pull writing of the defs file out of the post-fork child, and be sure
69
		unlink(defs_file);
597.1.5 by Matthew Fuller
Switch to allocating this string on the heap instead of using a static
70
		free(defs_file);
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
71
		exit(124);
72
	}
431.1.3 by Matthew Fuller
Add some comments and whitespace around start_m4() to make the flow
73
74
	/*
75
	 * Else we're the parent; hand back our reading end of the pipe.
76
	 */
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
77
	close(fids[1]);
597.1.5 by Matthew Fuller
Switch to allocating this string on the heap instead of using a static
78
	free(defs_file);
431.1.3 by Matthew Fuller
Add some comments and whitespace around start_m4() to make the flow
79
	return (fdopen(fids[0], "r"));
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
80
}
81
82
429.1.5 by Matthew Fuller
Add a comment about how we're cheaping out here.
83
/* Technically should sysconf() this, but good enough for our purposes */
429.1.4 by Matthew Fuller
Move this #define down closer to where it's used.
84
#define MAXHOSTNAME 255
429.1.5 by Matthew Fuller
Add a comment about how we're cheaping out here.
85
429.1.6 by Matthew Fuller
Add a few gross flow comments.
86
/*
87
 * Writes out a temp file of all the m4 defs appropriate for this run,
88
 * and returns the file name
89
 */
597.1.3 by Matthew Fuller
Break function definitions as long as I'm in here.
90
static char *
597.1.4 by Matthew Fuller
Trivial arg const-ification.
91
m4_defs(Display *display, const char *host)
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
92
{
597.1.6 by Matthew Fuller
Pull server/colon vars into an inner scope, since we only need them
93
	char client[MAXHOSTNAME];
429.1.18 by Matthew Fuller
Build up color in the switch() that determines vc, rather than in a
94
	char *vc, *color;
597.1.5 by Matthew Fuller
Switch to allocating this string on the heap instead of using a static
95
	char *tmp_name;
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
96
	FILE *tmpf;
97
	char *user;
98
429.1.6 by Matthew Fuller
Add a few gross flow comments.
99
	/* Create temp file */
597.1.5 by Matthew Fuller
Switch to allocating this string on the heap instead of using a static
100
	{
101
		char *td = getenv("TMPDIR");
102
		if(!td || strlen(td) < 2 || *td != '/') {
103
			td = "/tmp";
104
		}
105
		asprintf(&tmp_name, "%s/ctwmrc.XXXXXXXX", td);
106
		if(!tmp_name) {
107
			perror("asprintf failed in m4_defs");
108
			exit(1);
109
		}
110
111
		int fd = mkstemp(tmp_name);
112
		if(fd < 0) {
113
			perror("mkstemp failed in m4_defs");
114
			exit(377);
115
		}
116
		tmpf = fdopen(fd, "w+");
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
117
	}
429.1.8 by Matthew Fuller
Shuffle around a little and comment up the code figuring out hostname
118
119
120
	/*
121
	 * Now start writing the defs into it.
122
	 */
597.1.1 by Matthew Fuller
The whole Mk{Def,Num} dance is pointless; those exist purely to
123
#define WR_DEF(k, v) fprintf(tmpf, "define(`%s', `%s')\n", (k), (v))
124
#define WR_NUM(k, v) fprintf(tmpf, "define(`%s', `%d')\n", (k), (v))
429.1.8 by Matthew Fuller
Shuffle around a little and comment up the code figuring out hostname
125
126
	/*
127
	 * The machine running the window manager process (and, presumably,
128
	 * most of the other clients the user is running)
129
	 */
429.1.2 by Matthew Fuller
gethostname() is long defined in POSIX, so use it instead of
130
	if(gethostname(client, MAXHOSTNAME) < 0) {
131
		perror("gethostname failed in m4_defs");
132
		exit(1);
133
	}
429.1.8 by Matthew Fuller
Shuffle around a little and comment up the code figuring out hostname
134
	WR_DEF("CLIENTHOST", client);
429.1.6 by Matthew Fuller
Add a few gross flow comments.
135
136
	/*
429.1.8 by Matthew Fuller
Shuffle around a little and comment up the code figuring out hostname
137
	 * A guess at the machine running the X server.  We take the full
138
	 * $DISPLAY and chop off the screen specification.
429.1.6 by Matthew Fuller
Add a few gross flow comments.
139
	 */
597.1.6 by Matthew Fuller
Pull server/colon vars into an inner scope, since we only need them
140
	{
141
		char *server, *colon;
142
143
		server = strdup(XDisplayName(host));
144
		if(!server) {
145
			server = strdup("unknown");
146
		}
147
		colon = strchr(server, ':');
148
		if(colon != NULL) {
149
			*colon = '\0';
150
		}
151
152
		/* :0 or unix socket connection means it's the same as CLIENTHOST */
153
		if((server[0] == '\0') || (!strcmp(server, "unix"))) {
154
			free(server);
155
			server = strdup(client);
156
		}
157
		WR_DEF("SERVERHOST", server);
158
159
		free(server);
160
	}
429.1.8 by Matthew Fuller
Shuffle around a little and comment up the code figuring out hostname
161
598.2.1 by Matthew Fuller
Stick HOSTNAME lookup stuff inside an #ifdef temporarily.
162
#ifdef HISTORICAL_HOSTNAME_IMPL
598.2.2 by Matthew Fuller
Expand comment a little.
163
	/*
164
	 * Historical attempt to use DNS to figure a canonical name.  This is
165
	 * left inside this #ifdef for easy restoration if somebody finds a
166
	 * need; enabling it is not supported or documented.  Unless somebody
167
	 * comes up with a good reason to revive it, it will be removed after
621.1.2 by Matthew Fuller
Sub in 4.0.2 for %%NEXT%% now that we're about to release it.
168
	 * 4.0.2.
598.2.2 by Matthew Fuller
Expand comment a little.
169
	 */
598.2.1 by Matthew Fuller
Stick HOSTNAME lookup stuff inside an #ifdef temporarily.
170
	{
171
		struct hostent *hostname = gethostbyname(client);
172
		if(hostname) {
173
			WR_DEF("HOSTNAME", hostname->h_name);
174
		}
175
		else {
176
			WR_DEF("HOSTNAME", client);
177
		}
178
	}
179
#else
180
	/*
181
	 * Just leave HOSTNAME as a copy of CLIENTHOST for backward
182
	 * compat.
183
	 */
184
	WR_DEF("HOSTNAME", client);
185
#endif
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
186
429.1.9 by Matthew Fuller
Slightly reorder defs so they're grouped with related bits, and
187
	/*
188
	 * Info about the user and their environment
189
	 */
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
190
	if(!(user = getenv("USER")) && !(user = getenv("LOGNAME"))) {
429.1.19 by Matthew Fuller
Try a little harder to figure out the username.
191
		struct passwd *pwd = getpwuid(getuid());
192
		if(pwd) {
193
			user = pwd->pw_name;
194
		}
195
	}
196
	if(!user) {
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
197
		user = "unknown";
198
	}
429.1.7 by Matthew Fuller
Factor out a bunch of repetititive code into some macros. No
199
	WR_DEF("USER", user);
639.1.1 by Matthew Fuller
We go through all the trouble of coming up with a global Home. Use it
200
	WR_DEF("HOME", Home);
429.1.9 by Matthew Fuller
Slightly reorder defs so they're grouped with related bits, and
201
202
	/*
203
	 * ctwm meta
204
	 */
205
	WR_DEF("TWM_TYPE", "ctwm");
206
	WR_DEF("TWM_VERSION", VersionNumber);
438.1.4 by Matthew Fuller
Add split out major/minor/patch/addl defines into the m4 output.
207
	WR_DEF("CTWM_VERSION_MAJOR", VersionNumber_major);
208
	WR_DEF("CTWM_VERSION_MINOR", VersionNumber_minor);
209
	WR_DEF("CTWM_VERSION_PATCH", VersionNumber_patch);
210
	WR_DEF("CTWM_VERSION_ADDL",  VersionNumber_addl);
429.1.9 by Matthew Fuller
Slightly reorder defs so they're grouped with related bits, and
211
212
	/*
213
	 * X server meta
214
	 */
644.2.23 by Matthew Fuller
Make m4_defs() work fine without a display connection. Several values
215
	if(display) {
216
		WR_NUM("VERSION", ProtocolVersion(display));
217
		WR_NUM("REVISION", ProtocolRevision(display));
218
		WR_DEF("VENDOR", ServerVendor(display));
219
		WR_NUM("RELEASE", VendorRelease(display));
220
	}
221
	else {
222
		// Standin numbers
223
		WR_NUM("VERSION", 11);
224
		WR_NUM("REVISION", 0);
225
		WR_DEF("VENDOR", "Your Friendly Local Ctwm");
226
		WR_NUM("RELEASE", 123456789);
227
	}
429.1.9 by Matthew Fuller
Slightly reorder defs so they're grouped with related bits, and
228
229
	/*
230
	 * Information about the display
231
	 */
644.2.23 by Matthew Fuller
Make m4_defs() work fine without a display connection. Several values
232
	WR_NUM("WIDTH", Scr->rootw);
233
	WR_NUM("HEIGHT", Scr->rooth);
429.1.17 by Matthew Fuller
Move #define down to where it's used, and #undef it when we're done.
234
#define Resolution(pixels, mm)  ((((pixels) * 100000 / (mm)) + 50) / 100)
644.2.23 by Matthew Fuller
Make m4_defs() work fine without a display connection. Several values
235
	WR_NUM("X_RESOLUTION", Resolution(Scr->rootw, Scr->mm_w));
236
	WR_NUM("Y_RESOLUTION", Resolution(Scr->rooth, Scr->mm_h));
429.1.17 by Matthew Fuller
Move #define down to where it's used, and #undef it when we're done.
237
#undef Resolution
644.2.23 by Matthew Fuller
Make m4_defs() work fine without a display connection. Several values
238
	WR_NUM("PLANES", Scr->d_depth);
239
	WR_NUM("BITS_PER_RGB", Scr->d_visual->bits_per_rgb);
429.1.18 by Matthew Fuller
Build up color in the switch() that determines vc, rather than in a
240
	color = "Yes";
644.2.23 by Matthew Fuller
Make m4_defs() work fine without a display connection. Several values
241
	switch(Scr->d_visual->class) {
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
242
		case(StaticGray):
243
			vc = "StaticGray";
429.1.18 by Matthew Fuller
Build up color in the switch() that determines vc, rather than in a
244
			color = "No";
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
245
			break;
246
		case(GrayScale):
247
			vc = "GrayScale";
429.1.18 by Matthew Fuller
Build up color in the switch() that determines vc, rather than in a
248
			color = "No";
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
249
			break;
250
		case(StaticColor):
251
			vc = "StaticColor";
252
			break;
253
		case(PseudoColor):
254
			vc = "PseudoColor";
255
			break;
256
		case(TrueColor):
257
			vc = "TrueColor";
258
			break;
259
		case(DirectColor):
260
			vc = "DirectColor";
261
			break;
262
		default:
263
			vc = "NonStandard";
264
			break;
265
	}
429.1.7 by Matthew Fuller
Factor out a bunch of repetititive code into some macros. No
266
	WR_DEF("CLASS", vc);
429.1.18 by Matthew Fuller
Build up color in the switch() that determines vc, rather than in a
267
	WR_DEF("COLOR", color);
429.1.9 by Matthew Fuller
Slightly reorder defs so they're grouped with related bits, and
268
269
	/*
270
	 * Bits of "how this ctwm invocation is being run" data
271
	 */
692.1.5 by Matthew Fuller
Add ifdef's around references to Screen and CLargs members that are
272
	if(0) {
273
		// Dummy
274
	}
275
#ifdef CAPTIVE
276
	else if(CLarg.is_captive && Scr->captivename) {
429.1.9 by Matthew Fuller
Slightly reorder defs so they're grouped with related bits, and
277
		WR_DEF("TWM_CAPTIVE", "Yes");
278
		WR_DEF("TWM_CAPTIVE_NAME", Scr->captivename);
279
	}
692.1.5 by Matthew Fuller
Add ifdef's around references to Screen and CLargs members that are
280
#endif
429.1.9 by Matthew Fuller
Slightly reorder defs so they're grouped with related bits, and
281
	else {
282
		WR_DEF("TWM_CAPTIVE", "No");
283
	}
284
285
	/*
286
	 * Various compile-time options.
287
	 */
288
#ifdef PIXMAP_DIRECTORY
289
	WR_DEF("PIXMAP_DIRECTORY", PIXMAP_DIRECTORY);
290
#endif
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
291
#ifdef XPM
429.1.7 by Matthew Fuller
Factor out a bunch of repetititive code into some macros. No
292
	WR_DEF("XPM", "Yes");
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
293
#endif
294
#ifdef JPEG
429.1.7 by Matthew Fuller
Factor out a bunch of repetititive code into some macros. No
295
	WR_DEF("JPEG", "Yes");
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
296
#endif
297
#ifdef SOUNDS
429.1.7 by Matthew Fuller
Factor out a bunch of repetititive code into some macros. No
298
	WR_DEF("SOUNDS", "Yes");
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
299
#endif
429.1.16 by Matthew Fuller
Add a m4 def for whether ctwm is built with EWMH support.
300
#ifdef EWMH
301
	WR_DEF("EWMH", "Yes");
302
#endif
614.1.125 by Matthew Fuller
Add XRANDR to the m4 desf for our compile options.
303
#ifdef XRANDR
304
	WR_DEF("XRANDR", "Yes");
305
#endif
429.1.15 by Matthew Fuller
Make up the I18N def in the docs, and mark it in docs and code as to
306
	/* Since this is no longer an option, it should be removed in the future */
429.1.7 by Matthew Fuller
Factor out a bunch of repetititive code into some macros. No
307
	WR_DEF("I18N", "Yes");
429.1.6 by Matthew Fuller
Add a few gross flow comments.
308
429.1.7 by Matthew Fuller
Factor out a bunch of repetititive code into some macros. No
309
#undef WR_NUM
310
#undef WR_DEF
429.1.6 by Matthew Fuller
Add a few gross flow comments.
311
429.1.9 by Matthew Fuller
Slightly reorder defs so they're grouped with related bits, and
312
429.1.6 by Matthew Fuller
Add a few gross flow comments.
313
	/*
314
	 * We might be keeping it, in which case tell the user where it is;
315
	 * this is mostly a debugging option.  Otherwise, delete it by
316
	 * telling m4 to do so when it reads it; this is fairly fugly, and I
317
	 * have more than half a mind to dike it out and properly clean up
318
	 * ourselves.
319
	 */
389.1.31 by Matthew Fuller
Switch these 3 M4-related command line args into the CLargs structure
320
	if(CLarg.KeepTmpFile) {
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
321
		fprintf(stderr, "Left file: %s\n", tmp_name);
322
	}
323
	else {
324
		fprintf(tmpf, "syscmd(/bin/rm %s)\n", tmp_name);
325
	}
429.1.6 by Matthew Fuller
Add a few gross flow comments.
326
327
328
	/* Close out and hand it back */
387.1.1 by Matthew Fuller
Bust out a lot of the m4 parsing handling from parse.c into a separate
329
	fclose(tmpf);
330
	return(tmp_name);
331
}