1 /* -*-c-*- */
2 /* This module, and the entire FvwmM4 program, and the concept for
3 * interfacing this module to the Window Manager, are all original work
4 * by Robert Nation
5 */
6
7 /* This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see: <http://www.gnu.org/licenses/>
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <signal.h>
25 #include <fcntl.h>
26 #include <sys/wait.h>
27 #include "libs/ftime.h"
28 #include <unistd.h>
29 #include <ctype.h>
30 #include <pwd.h>
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <netdb.h>
34
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37 #include <X11/Xproto.h>
38 #include <X11/Xatom.h>
39 #include <X11/Intrinsic.h>
40
41 #include "libs/Module.h"
42 #include "libs/Strings.h"
43 #include "libs/System.h"
44 #include "libs/fvwm_sys_stat.h"
45
46 #include "FvwmM4.h"
47 #include "libs/fvwmlib.h"
48 #include "libs/FShape.h"
49 #include "libs/PictureBase.h"
50 #include "libs/FSMlib.h"
51 #include <X11/StringDefs.h>
52 #include <X11/Shell.h>
53 #define Resolution(pixels, mm) ((((pixels) * 2000 / (mm)) + 1) / 2)
54
55 char *MyName;
56 int fd[2];
57
58 long Vx, Vy;
59 static char *MkDef(char *name, char *def);
60 static char *MkNum(char *name,int def);
61 static char *m4_defs(Display *display, const char *host, char *m4_options, char *config_file);
62 #define MAXHOSTNAME 255
63 #define EXTRA 56
64
65 int m4_enable; /* use m4? */
66 int m4_prefix; /* Do GNU m4 prefixing (-P) */
67 int m4_prefix_defines; /* Add "m4_" to the names of the defines */
68 char m4_options[BUFSIZ]; /* Command line options to m4 */
69 char m4_outfile[BUFSIZ] = ""; /* The output filename for m4 */
70 char *m4_prog = "/usr/local/bin/gm4"; /* Name of the m4 program */
71 int m4_default_quotes; /* Use default m4 quotes */
72 char *m4_startquote = "`"; /* Left quote characters for m4 */
73 char *m4_endquote = "'"; /* Right quote characters for m4 */
74
75
76 /*
77 *
78 * Procedure:
79 * main - start of module
80 *
81 */
main(int argc,char ** argv)82 int main(int argc, char **argv)
83 {
84 Display *dpy; /* which display are we talking to */
85 char *temp, *s;
86 char *display_name = NULL;
87 char *filename = NULL;
88 char *tmp_file;
89 int i;
90 int debug = 0;
91 int lock = 0;
92 int noread = 0;
93 char *user_dir;
94 char *m4path;
95
96 /* Figure out the working directory and go to it */
97 user_dir = getenv("FVWM_USERDIR");
98 if (user_dir != NULL)
99 {
100 if (chdir(user_dir) < 0)
101 fprintf(stderr, "%s: <<Warning>> chdir to %s failed in m4_defs",
102 MyName, user_dir);
103 }
104
105 m4_enable = True;
106 m4_prefix = False;
107 m4_prefix_defines = False;
108 sprintf(m4_options, " ");
109 m4_default_quotes = 1;
110 /* add FVWM_DATADIR to the include path. Can't use the -I option here because
111 * it is incompatible with the System V version of m4. Instead, append it to
112 * the front of the M4PATH environment variable. */
113 m4path = getenv("M4PATH");
114 if (m4path == NULL)
115 {
116 m4path = safemalloc(sizeof("M4PATH=") + strlen(FVWM_DATADIR) + 1);
117 sprintf(m4path, "M4PATH=%s", FVWM_DATADIR);
118 }
119 else
120 {
121 char *s;
122
123 s = safemalloc(
124 sizeof("M4PATH=") + strlen(FVWM_DATADIR) + strlen(m4path) + 2);
125 sprintf(s, "M4PATH=%s:%s", FVWM_DATADIR, m4path);
126 m4path = s;
127 }
128 putenv(m4path);
129
130 /* Record the program name for error messages */
131 temp = argv[0];
132
133 s=strrchr(argv[0], '/');
134 if (s != NULL)
135 temp = s + 1;
136
137 MyName = safemalloc(strlen(temp)+2);
138 strcpy(MyName,"*");
139 strcat(MyName, temp);
140
141 if(argc < 6)
142 {
143 fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",MyName,
144 VERSION);
145 exit(1);
146 }
147
148 /* We should exit if our fvwm pipes die */
149 signal (SIGPIPE, DeadPipe);
150
151 fd[0] = atoi(argv[1]);
152 fd[1] = atoi(argv[2]);
153
154 for(i=6;i<argc;i++)
155 {
156 if(strcasecmp(argv[i],"-m4-prefix") == 0)
157 {
158 m4_prefix = True;
159 }
160 else if(strcasecmp(argv[i],"-m4-prefix-defines") == 0)
161 {
162 m4_prefix_defines = True;
163 }
164 else if(strcasecmp(argv[i],"-m4opt") == 0)
165 {
166 /* leaving this in just in case-- any option starting with '-'
167 will get passed on to m4 anyway */
168 strcat(m4_options, argv[++i]);
169 strcat(m4_options, " ");
170 }
171 else if(strcasecmp(argv[i],"-m4-squote") == 0)
172 {
173 m4_startquote = argv[++i];
174 m4_default_quotes = 0;
175 }
176 else if(strcasecmp(argv[i],"-m4-equote") == 0)
177 {
178 m4_endquote = argv[++i];
179 m4_default_quotes = 0;
180 }
181 else if (strcasecmp(argv[i], "-m4prog") == 0)
182 {
183 m4_prog = argv[++i];
184 }
185 else if(strcasecmp(argv[i], "-outfile") == 0)
186 {
187 strcpy(m4_outfile,argv[++i]);
188 }
189 else if(strcasecmp(argv[i], "-debug") == 0)
190 {
191 debug = 1;
192 }
193 else if(strcasecmp(argv[i], "-lock") == 0)
194 {
195 lock = 1;
196 }
197 else if(strcasecmp(argv[i], "-noread") == 0)
198 {
199 noread = 1;
200 }
201 else if (strncasecmp(argv[i],"-",1) == 0)
202 {
203 /* pass on any other arguments starting with '-' to m4 */
204 strcat(m4_options, argv[i]);
205 strcat(m4_options, " ");
206 }
207 else
208 filename = argv[i];
209 }
210
211 if (!filename)
212 {
213 fprintf(stderr, "%s: no file specified.\n", MyName);
214 exit(1);
215 }
216 for(i=0;i<strlen(filename);i++)
217 if((filename[i] == '\n')||(filename[i] == '\r'))
218 {
219 filename[i] = 0;
220 }
221
222 if (!(dpy = XOpenDisplay(display_name)))
223 {
224 fprintf(stderr,"FvwmM4: can't open display %s",
225 XDisplayName(display_name));
226 exit (1);
227 }
228
229 /* set up G */
230 PictureInitCMap(dpy);
231
232 /* tell fvwm we're running if -lock is not used */
233 if (!lock)
234 SendFinishedStartupNotification(fd);
235
236 tmp_file = m4_defs(dpy, display_name,m4_options, filename);
237
238 if (!noread)
239 {
240 char *read_string = CatString3("Read '", tmp_file, "'");
241 SendText(fd, read_string, 0);
242 }
243
244 /* tell fvwm to continue if -lock is used */
245 if (lock)
246 SendFinishedStartupNotification(fd);
247
248 /* For a debugging version, we may wish to omit this part. */
249 /* I'll let some m4 advocates clean this up */
250 if (!debug)
251 {
252 char *delete_string;
253 char *delete_file = tmp_file;
254 if (tmp_file[0] != '/' && user_dir != NULL)
255 {
256 delete_file = safestrdup(CatString3(user_dir, "/", tmp_file));
257 }
258 delete_string = CatString3("Exec exec /bin/rm '", delete_file, "'");
259 SendText(fd, delete_string, 0);
260 }
261
262 return 0;
263 }
264
265
266
m4_defs(Display * display,const char * host,char * m4_options,char * config_file)267 static char *m4_defs(
268 Display *display, const char *host, char *m4_options, char *config_file)
269 {
270 Screen *screen;
271 Visual *visual;
272 char client[MAXHOSTNAME], server[MAXHOSTNAME], *colon;
273 char ostype[BUFSIZ];
274 char options[BUFSIZ];
275 static char tmp_name[BUFSIZ];
276 struct hostent *hostname;
277 char *vc; /* Visual Class */
278 FILE *tmpf;
279 struct passwd *pwent;
280 int fd;
281 int Mscreen;
282
283 /* Generate a temporary filename. Honor the TMPDIR environment variable,
284 if set. Hope nobody deletes this file! */
285
286 if (strlen(m4_outfile) == 0)
287 {
288 if ((vc = getenv("TMPDIR")))
289 {
290 strcpy(tmp_name, vc);
291 }
292 else
293 {
294 strcpy(tmp_name, "/tmp");
295 }
296 strcat(tmp_name, "/fvwmrcXXXXXX");
297 fd = fvwm_mkstemp(tmp_name);
298 if (fd == -1)
299 {
300 fprintf(
301 stderr,
302 "[FvwmM4][m4_def] fvwm_mkstemp failed %s\n",
303 tmp_name);
304 exit(0377);
305 }
306 }
307 else
308 {
309 strcpy(tmp_name, m4_outfile);
310 /*
311 * check to make sure it doesn't exist already, to prevent
312 * security hole
313 */
314 /* first try to unlink it */
315 unlink(tmp_name);
316 fd = open(
317 tmp_name, O_WRONLY|O_EXCL|O_CREAT,
318 FVWM_S_IRUSR | FVWM_S_IWUSR);
319 if (fd < 0)
320 {
321 fprintf(
322 stderr,
323 "[FvwmM4][m4_defs] error opening file %s\n",
324 tmp_name);
325 exit(0377);
326 }
327 }
328
329 close(fd);
330
331 /*
332 * Create the appropriate command line to run m4, and
333 * open a pipe to the command.
334 */
335
336 if(m4_prefix)
337 {
338 sprintf(
339 options, "%s --prefix-builtins %s > %s\n",
340 m4_prog,
341 m4_options, tmp_name);
342 }
343 else
344 {
345 sprintf(options, "%s %s > %s\n",
346 m4_prog,
347 m4_options, tmp_name);
348 }
349 tmpf = popen(options, "w");
350 if (tmpf == NULL)
351 {
352 fprintf(
353 stderr,
354 "[FvwmM4][m4_defs] Cannot open pipe to m4\n");
355 exit(0377);
356 }
357
358 gethostname(client,MAXHOSTNAME);
359 getostype (ostype, sizeof ostype);
360
361 /* Change the quoting characters, if specified */
362
363 if (!m4_default_quotes)
364 {
365 fprintf(
366 tmpf, "%schangequote(%s, %s)%sdnl\n",
367 (m4_prefix) ? "m4_" : "",
368 m4_startquote, m4_endquote,
369 (m4_prefix) ? "m4_" : "");
370 }
371
372 hostname = gethostbyname(client);
373 strcpy(server, XDisplayName(host));
374 colon = strchr(server, ':');
375 if (colon != NULL) *colon = '\0';
376 if ((server[0] == '\0') || (!strcmp(server, "unix")))
377 strcpy(server, client); /* must be connected to :0 or unix:0 */
378
379 /* TWM_TYPE is fvwm, for completeness */
380
381 fputs(MkDef("TWM_TYPE", "fvwm"), tmpf);
382
383 /* The machine running the X server */
384 fputs(MkDef("SERVERHOST", server), tmpf);
385 /* The machine running the window manager process */
386 fputs(MkDef("CLIENTHOST", client), tmpf);
387 if (hostname)
388 fputs(MkDef("HOSTNAME", (char *)hostname->h_name), tmpf);
389 else
390 fputs(MkDef("HOSTNAME", (char *)client), tmpf);
391
392 fputs(MkDef("OSTYPE", ostype), tmpf);
393
394 pwent=getpwuid(geteuid());
395 fputs(MkDef("USER", pwent->pw_name), tmpf);
396
397 fputs(MkDef("HOME", getenv("HOME")), tmpf);
398 fputs(MkNum("VERSION", ProtocolVersion(display)), tmpf);
399 fputs(MkNum("REVISION", ProtocolRevision(display)), tmpf);
400 fputs(MkDef("VENDOR", ServerVendor(display)), tmpf);
401 fputs(MkNum("RELEASE", VendorRelease(display)), tmpf);
402
403 Mscreen= DefaultScreen(display);
404 fputs(MkNum("SCREEN", Mscreen), tmpf);
405
406 fputs(MkNum("WIDTH", DisplayWidth(display,Mscreen)), tmpf);
407 fputs(MkNum("HEIGHT", DisplayHeight(display,Mscreen)), tmpf);
408
409 screen = ScreenOfDisplay(display, Mscreen);
410 fputs(MkNum(
411 "X_RESOLUTION",Resolution(screen->width,screen->mwidth)),
412 tmpf);
413 fputs(MkNum(
414 "Y_RESOLUTION",Resolution(screen->height,screen->mheight)),
415 tmpf);
416 fputs(MkNum("PLANES",DisplayPlanes(display, Mscreen)), tmpf);
417
418 visual = DefaultVisualOfScreen(screen);
419 fputs(MkNum("BITS_PER_RGB", visual->bits_per_rgb), tmpf);
420
421 switch(visual->class)
422 {
423 case(StaticGray):
424 vc = "StaticGray";
425 break;
426 case(GrayScale):
427 vc = "GrayScale";
428 break;
429 case(StaticColor):
430 vc = "StaticColor";
431 break;
432 case(PseudoColor):
433 vc = "PseudoColor";
434 break;
435 case(TrueColor):
436 vc = "TrueColor";
437 break;
438 case(DirectColor):
439 vc = "DirectColor";
440 break;
441 default:
442 vc = "NonStandard";
443 break;
444 }
445 fputs(MkDef("CLASS", vc), tmpf);
446
447 switch(Pvisual->class)
448 {
449 case(StaticGray):
450 vc = "StaticGray";
451 break;
452 case(GrayScale):
453 vc = "GrayScale";
454 break;
455 case(StaticColor):
456 vc = "StaticColor";
457 break;
458 case(PseudoColor):
459 vc = "PseudoColor";
460 break;
461 case(TrueColor):
462 vc = "TrueColor";
463 break;
464 case(DirectColor):
465 vc = "DirectColor";
466 break;
467 default:
468 vc = "NonStandard";
469 break;
470 }
471 fputs(MkDef("FVWM_CLASS", vc), tmpf);
472
473 if (visual->class != StaticGray && visual->class != GrayScale)
474 fputs(MkDef("COLOR", "Yes"), tmpf);
475 else
476 fputs(MkDef("COLOR", "No"), tmpf);
477
478 if (Pvisual->class != StaticGray && Pvisual->class != GrayScale)
479 fputs(MkDef("FVWM_COLOR", "Yes"), tmpf);
480 else
481 fputs(MkDef("FVWM_COLOR", "No"), tmpf);
482
483 fputs(MkDef("FVWM_VERSION", VERSION), tmpf);
484
485 /* Add options together */
486 *options = '\0';
487 if (FHaveShapeExtension)
488 strcat(options, "SHAPE ");
489
490 if (XpmSupport)
491 strcat(options, "XPM ");
492
493 strcat(options, "M4 ");
494
495 fputs(MkDef("OPTIONS", options), tmpf);
496
497 fputs(MkDef("FVWM_MODULEDIR", FVWM_MODULEDIR), tmpf);
498 fputs(MkDef("FVWM_DATADIR", FVWM_DATADIR), tmpf);
499
500 if ((vc = getenv("FVWM_USERDIR")))
501 fputs(MkDef("FVWM_USERDIR", vc), tmpf);
502
503 if (SessionSupport && (vc = getenv("SESSION_MANAGER")))
504 fputs(MkDef("SESSION_MANAGER", vc), tmpf);
505
506 /*
507 * At this point, we've sent the definitions to m4. Just include
508 * the fvwmrc file now.
509 */
510
511 fprintf(tmpf, "%sinclude(%s%s%s)\n",
512 (m4_prefix) ? "m4_": "",
513 m4_startquote,
514 config_file,
515 m4_endquote);
516
517 pclose(tmpf);
518 return(tmp_name);
519 }
520
521
522 /*
523 *
524 * Procedure:
525 * SIGPIPE handler - SIGPIPE means fvwm is dying
526 *
527 */
DeadPipe(int nonsense)528 RETSIGTYPE DeadPipe(int nonsense)
529 {
530 exit(0);
531 SIGNAL_RETURN;
532 }
533
MkDef(char * name,char * def)534 static char *MkDef(char *name, char *def)
535 {
536 char *cp = NULL;
537 int n;
538
539 /* Get space to hold everything, if needed */
540
541 n = EXTRA + strlen(name) + strlen(def);
542 cp = safemalloc(n);
543
544 if (m4_prefix)
545 strcpy(cp, "m4_define(");
546 else
547 strcpy(cp, "define(");
548
549 if (m4_prefix_defines)
550 strcat(cp, "m4_");
551 strcat(cp, name);
552
553 /* Tack on "," and 2 sets of starting quotes */
554 strcat(cp, ",");
555 strcat(cp, m4_startquote);
556 strcat(cp, m4_startquote);
557
558 /* The definition itself */
559 strcat(cp, def);
560
561 /* Add 2 sets of closing quotes */
562 strcat(cp, m4_endquote);
563 strcat(cp, m4_endquote);
564
565 /* End the definition, appropriately */
566 strcat(cp, ")");
567 if (m4_prefix)
568 strcat(cp, "m4_");
569
570 strcat(cp, "dnl\n");
571
572 return(cp);
573 }
574
MkNum(char * name,int def)575 static char *MkNum(char *name,int def)
576 {
577 char num[20];
578
579 sprintf(num, "%d", def);
580
581 return(MkDef(name, num));
582 }
583