Close fd in CMD_Exec
[fvwm.git] / libs / Module.c
blob3543d03c607ef84f4ea6b02ecddc8480c73f3f3c
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ** Module.c: code for modules to communicate with fvwm
20 #include "config.h"
21 #include <stdio.h>
22 #include <ctype.h>
23 #include "libs/defaults.h"
24 #include "Module.h"
25 #include "Parse.h"
28 * Loop until count bytes are read, unless an error or end-of-file
29 * condition occurs.
31 inline
32 static int positive_read(int fd, char *buf, int count)
34 while (count > 0)
36 int n_read = read(fd, buf, count);
37 if (n_read <= 0)
39 return -1;
41 buf += n_read;
42 count -= n_read;
44 return 0;
49 * Reads a single packet of info from fvwm.
50 * The packet is stored in static memory that is reused during
51 * the next call.
54 FvwmPacket *ReadFvwmPacket(int fd)
56 static unsigned long buffer[FvwmPacketMaxSize];
57 FvwmPacket *packet = (FvwmPacket *)buffer;
58 unsigned long length;
60 /* The `start flag' value supposedly exists to synchronize the
61 * fvwm -> module communication. However, the communication goes
62 * through a pipe. I don't see how any data could ever get lost,
63 * so how would fvwm & the module become unsynchronized?
67 if (positive_read(fd, (char *)buffer, sizeof(unsigned long))
68 < 0)
70 return NULL;
72 } while (packet->start_pattern != START_FLAG);
74 /* Now read the rest of the header */
75 if (positive_read(fd, (char *)(&buffer[1]), 3 * sizeof(unsigned long))
76 < 0)
78 return NULL;
80 length = FvwmPacketBodySize_byte(*packet);
81 if (length > FvwmPacketMaxSize_byte - FvwmPacketHeaderSize_byte)
83 /* packet too long */
84 return NULL;
86 /* Finally, read the body, and we're done */
87 if (positive_read(fd, (char *)(&buffer[4]), length) < 0)
89 return NULL;
92 return packet;
98 * SendFinishedStartupNotification - informs fvwm that the module has
99 * finished its startup procedures and is fully operational now.
102 void SendFinishedStartupNotification(int *fd)
104 SendText(fd, ModuleFinishedStartupResponse, 0);
109 * SendUnlockNotification - informs fvwm that the module has
110 * finished it's procedures and fvwm may proceed.
113 void SendUnlockNotification(int *fd)
115 SendText(fd, ModuleUnlockResponse, 0);
120 * SendQuitNotification - informs fvwm that the module has
121 * finished and may be killed.
124 static unsigned long ModuleContinue = 1;
125 void SendQuitNotification(int *fd)
127 ModuleContinue = 0;
128 SendText(fd, ModuleUnlockResponse, 0); /* unlock just in case */
133 * SendText - Sends arbitrary text/command back to fvwm
136 void SendText(int *fd, const char *message, unsigned long window)
138 char *p, *buf;
139 unsigned int len;
141 if (!message)
143 return;
146 /* Get enough memory to store the entire message. */
147 len = strlen(message);
148 p = buf = alloca(sizeof(long) * (3 + 1 + (len / sizeof(long))));
150 /* Put the message in the buffer, and... */
151 *((unsigned long *)p) = window;
152 p += sizeof(unsigned long);
154 *((unsigned long *)p) = len;
155 p += sizeof(unsigned long);
157 strcpy(p, message);
158 p += len;
160 memcpy(p, &ModuleContinue, sizeof(unsigned long));
161 p += sizeof(unsigned long);
163 /* Send it! */
164 write(fd[0], buf, p - buf);
169 * SendFvwmPipe - Sends message to fvwm: The message is a comma-delimited
170 * string separated into its component sections and sent one by one to fvwm.
171 * It is discouraged to use this function with a "synchronous" module.
172 * (Form FvwmIconMan)
175 void SendFvwmPipe(int *fd, const char *message, unsigned long window)
177 const char *hold = message;
178 const char *temp;
180 while ((temp = strchr(hold, ',')) != NULL)
182 char *temp_msg = (char*)alloca(temp - hold + 1);
184 strncpy(temp_msg, hold, (temp - hold));
185 temp_msg[(temp - hold)] = '\0';
186 hold = temp + 1;
188 SendText(fd, temp_msg, window);
192 * Send the last part of the string :
193 * we don't need to copy this into separate
194 * storage because we don't need to modify it ...
196 * NOTE: this makes this second call to SendText()
197 * distinct from the first call. Two calls is
198 * cleaner than hacking the loop to make only
199 * one call.
201 SendText(fd, hold, window);
204 void SetMessageMask(int *fd, unsigned long mask)
206 char set_mask_mesg[50];
208 sprintf(set_mask_mesg, "SET_MASK %lu", mask);
209 SendText(fd, set_mask_mesg, 0);
212 void SetSyncMask(int *fd, unsigned long mask)
214 char set_syncmask_mesg[50];
216 sprintf(set_syncmask_mesg, "SET_SYNC_MASK %lu", mask);
217 SendText(fd, set_syncmask_mesg, 0);
220 void SetNoGrabMask(int *fd, unsigned long mask)
222 char set_nograbmask_mesg[50];
224 sprintf(set_nograbmask_mesg, "SET_NOGRAB_MASK %lu", mask);
225 SendText(fd, set_nograbmask_mesg, 0);
229 * Optional routine that sets the matching criteria for config lines
230 * that should be sent to a module by way of the GetConfigLine function.
232 * If this routine is not called, all module config lines are sent.
234 static int first_pass = 1;
236 void InitGetConfigLine(int *fd, char *match)
238 char *buffer = (char *)alloca(strlen(match) + 32);
239 first_pass = 0; /* make sure get wont do this */
240 sprintf(buffer, "Send_ConfigInfo %s", match);
241 SendText(fd, buffer, 0);
246 * Gets a module configuration line from fvwm. Returns NULL if there are
247 * no more lines to be had. "line" is a pointer to a char *.
249 * Changed 10/19/98 by Dan Espen:
251 * - The "isspace" call was referring to memory beyond the end of the
252 * input area. This could have led to the creation of a core file. Added
253 * "body_size" to keep it in bounds.
255 void GetConfigLine(int *fd, char **tline)
257 FvwmPacket *packet;
258 int body_count;
260 if (first_pass)
262 SendText(fd, "Send_ConfigInfo", 0);
263 first_pass = 0;
268 packet = ReadFvwmPacket(fd[1]);
269 if (packet == NULL || packet->type == M_END_CONFIG_INFO)
271 *tline = NULL;
272 return;
274 } while (packet->type != M_CONFIG_INFO);
276 /* For whatever reason CONFIG_INFO packets start with three
277 * (unsigned long) zeros. Skip the zeros and any whitespace that
278 * follows */
279 *tline = (char *)&(packet->body[3]);
280 body_count = FvwmPacketBodySize(*packet) * sizeof(unsigned long);
282 while (body_count > 0 && isspace((unsigned char)**tline))
284 (*tline)++;
285 --body_count;
290 ModuleArgs *ParseModuleArgs(int argc, char *argv[], int use_arg6_as_alias)
292 static ModuleArgs ma;
294 /* Need at least six arguments:
295 [0] name of executable
296 [1] file descriptor of module->fvwm pipe (write end)
297 [2] file descriptor of fvwm->module pipe (read end)
298 [3] pathname of last config file read (ignored, use Send_ConfigInfo)
299 [4] application window context
300 [5] window decoration context
302 Optionally (left column used if use_arg6_as_alias is true):
303 [6] alias or user argument 0
304 [7] user arg 0 or user arg 1
307 if (argc < 6)
309 return NULL;
312 /* Module name is (last component of) argv[0] or possibly an alias
313 passed on the command line. */
314 if (use_arg6_as_alias && argc >= 7)
316 ma.name = argv[6];
317 ma.user_argc = argc - 7;
318 ma.user_argv = &(argv[7]);
320 else
322 char *p = strrchr(argv[0], '/');
323 if (p == NULL)
325 ma.name = argv[0];
327 else
329 ma.name = ++p;
331 ma.user_argc = argc - 6;
332 ma.user_argv = &(argv[6]);
335 ma.namelen=strlen(ma.name);
337 if (ma.user_argc == 0)
339 ma.user_argv = NULL;
342 /* File descriptors for the pipes */
343 ma.to_fvwm = atoi(argv[1]);
344 ma.from_fvwm = atoi(argv[2]);
346 /* Ignore argv[3] */
348 /* These two are generated as long hex strings */
349 ma.window = strtoul(argv[4], NULL, 16);
350 ma.decoration = strtoul(argv[5], NULL, 16);
352 return &ma;
355 /* expands certain variables in a command to be sent by a module */
356 char *module_expand_action(
357 Display *dpy, int screen , char *in_action, rectangle *r,
358 char *forecolor, char *backcolor)
360 char *variables[] =
362 "$",
363 "fg",
364 "bg",
365 "left",
366 "-left",
367 "right",
368 "-right",
369 "top",
370 "-top",
371 "bottom",
372 "-bottom",
373 "width",
374 "height",
375 NULL
377 char *action = NULL;
378 char *src;
379 char *dest;
380 char *string = NULL;
381 char *rest;
382 int val = 0;
383 int offset;
384 int i;
385 char *dest_org;
386 Bool is_string;
387 Bool is_value;
388 Bool has_geom;
389 Bool has_fg;
390 Bool has_bg;
391 rectangle tmpr = { 0, 0, 0, 0 };
393 has_geom = (r == NULL) ? False : True;
394 has_fg = (forecolor == NULL) ? False : True;
395 has_bg = (backcolor == NULL) ? False : True;
396 if (r == NULL)
398 r = &tmpr;
400 /* create a temporary storage for expanding */
401 action = (char *)safemalloc(MAX_MODULE_INPUT_TEXT_LEN);
402 for (src = in_action, dest = action; *src != 0; src++)
404 if (*src != '$')
406 *(dest++) = *src;
407 continue;
409 /* it's a variable */
410 dest_org = dest;
411 is_string = False;
412 is_value = False;
413 *(dest++) = *(src++);
414 i = GetTokenIndex(src, variables, -1, &rest);
415 if (i == -1)
417 src--;
418 continue;
420 switch (i)
422 case 0: /* $ */
423 continue;
424 case 1: /* fg */
425 string = forecolor;
426 is_string = has_fg;
427 break;
428 case 2: /* bg */
429 if (backcolor == NULL)
431 continue;
433 string = backcolor;
434 is_string = has_bg;
435 break;
436 case 3: /* left */
437 val = r->x;
438 is_value = has_geom;
439 break;
440 case 4: /* -left */
441 val = DisplayWidth(dpy, screen) - r->x - 1;
442 is_value = has_geom;
443 break;
444 case 5: /* right */
445 val = r->x + r->width;
446 is_value = has_geom;
447 break;
448 case 6: /* -right */
449 val = DisplayWidth(dpy, screen) - r->x - r->width - 1;
450 is_value = has_geom;
451 break;
452 case 7: /* top */
453 val = r->y;
454 is_value = has_geom;
455 break;
456 case 8: /* -top */
457 val = DisplayHeight(dpy, screen) - r->y - 1;
458 is_value = has_geom;
459 break;
460 case 9: /* bottom */
461 val = r->y + r->height;
462 is_value = has_geom;
463 break;
464 case 10: /* -bottom */
465 val = DisplayHeight(dpy, screen) - r->y - r->height - 1;
466 is_value = has_geom;
467 break;
468 case 11: /* width */
469 val = r->width;
470 is_value = has_geom;
471 break;
472 case 12: /* height */
473 val = r->height;
474 is_value = has_geom;
475 break;
476 default: /* unknown */
477 src--;
478 continue;
479 } /* switch */
480 if (is_value == False && is_string == False)
482 src--;
483 continue;
485 dest = dest_org;
486 src = --rest;
487 if (is_value)
489 if (MAX_MODULE_INPUT_TEXT_LEN - (dest - action) <= 16)
491 /* out of space */
492 free(action);
493 return NULL;
495 /* print the number into the string */
496 sprintf(dest, "%d%n", val, &offset);
497 dest += offset;
499 else if (is_string)
501 if (MAX_MODULE_INPUT_TEXT_LEN - (dest - action) <=
502 strlen(string))
504 /* out of space */
505 free(action);
506 return NULL;
508 /* print the colour name into the string */
509 if (string)
511 sprintf(dest, "%s%n", string, &offset);
512 dest += offset;
515 } /* for */
516 *dest = 0;
518 return action;