Add reminder to investigate recursive commands for 2.6
[fvwm.git] / fvwm / read.c
blob75340d798bf22f5cc5003867f8812846f526d081
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 * This module is all original code
19 * by Rob Nation
20 * Copyright 1993, Robert Nation
21 * You may use this code for any purpose, as long as the original
22 * copyright remains in the source code and all documentation
24 * Changed 09/24/98 by Dan Espen:
25 * - remove logic that processed and saved module configuration commands.
26 * Its now in "modconf.c".
28 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
35 #include "libs/Parse.h"
36 #include "libs/Strings.h"
37 #include "fvwm.h"
38 #include "externs.h"
39 #include "cursor.h"
40 #include "functions.h"
41 #include "events.h"
42 #include "misc.h"
43 #include "screen.h"
45 #define MAX_READ_DEPTH 40
46 static char *curr_read_file = NULL;
47 static char *curr_read_dir = NULL;
48 static int curr_read_depth = 0;
49 static char *prev_read_files[MAX_READ_DEPTH];
51 static int push_read_file(const char *file)
53 if (curr_read_depth >= MAX_READ_DEPTH)
55 fvwm_msg(
56 ERR, "Read", "Nested Read limit %d is reached",
57 MAX_READ_DEPTH);
58 return 0;
60 prev_read_files[curr_read_depth++] = curr_read_file;
61 curr_read_file = safestrdup(file);
62 if (curr_read_dir)
64 free(curr_read_dir);
66 curr_read_dir = NULL;
68 return 1;
71 static void pop_read_file(void)
73 if (curr_read_depth == 0)
75 return;
77 if (curr_read_file)
79 free(curr_read_file);
81 curr_read_file = prev_read_files[--curr_read_depth];
82 if (curr_read_dir)
84 free(curr_read_dir);
86 curr_read_dir = NULL;
88 return;
91 const char *get_current_read_file(void)
93 return curr_read_file;
96 const char *get_current_read_dir(void)
98 if (!curr_read_dir)
100 char *dir_end;
101 if (!curr_read_file)
103 return ".";
105 /* it should be a library function parse_file_dir() */
106 dir_end = strrchr(curr_read_file, '/');
107 if (!dir_end)
109 dir_end = curr_read_file;
111 curr_read_dir = safemalloc(dir_end - curr_read_file + 1);
112 strncpy(curr_read_dir, curr_read_file,
113 dir_end - curr_read_file);
114 curr_read_dir[dir_end - curr_read_file] = '\0';
116 return curr_read_dir;
121 * Read and execute each line from stream.
123 void run_command_stream(
124 cond_rc_t *cond_rc, FILE *f, const exec_context_t *exc)
126 char *tline;
127 char line[1024];
129 /* Set close-on-exec flag */
130 fcntl(fileno(f), F_SETFD, 1);
132 /* Update window decorations in case we were called from a menu that
133 * has now popped down. */
134 handle_all_expose();
136 tline = fgets(line, (sizeof line) - 1, f);
137 while (tline)
139 int l;
140 while (tline && (l = strlen(line)) < sizeof(line) && l >= 2 &&
141 line[l-2]=='\\' && line[l-1]=='\n')
143 tline = fgets(line+l-2,sizeof(line)-l+1,f);
145 tline=line;
146 while (isspace((unsigned char)*tline))
148 tline++;
150 l = strlen(tline);
151 if (l > 0 && tline[l - 1] == '\n')
153 tline[l - 1] = '\0';
155 execute_function(cond_rc, exc, tline, 0);
156 tline = fgets(line, (sizeof line) - 1, f);
159 return;
164 * Parse the action string. We expect a filename, and optionally,
165 * the keyword "Quiet". The parameter `cmdname' is used for diagnostic
166 * messages only.
168 * Returns true if the parse succeeded.
169 * The filename and the presence of the quiet flag are returned
170 * using the pointer arguments.
172 static int parse_filename(
173 char *cmdname, char *action, char **filename, int *quiet_flag)
175 char *rest;
176 char *option;
178 /* fvwm_msg(INFO,cmdname,"action == '%s'",action); */
180 /* read file name arg */
181 rest = GetNextToken(action,filename);
182 if (*filename == NULL)
184 fvwm_msg(ERR, cmdname, "missing filename parameter");
185 return 0;
187 /* optional "Quiet" argument -- flag defaults to `off' (noisy) */
188 *quiet_flag = 0;
189 rest = GetNextToken(rest,&option);
190 if (option != NULL)
192 *quiet_flag = strncasecmp(option, "Quiet", 5) == 0;
193 free(option);
196 return 1;
201 * Returns 0 if file not found
203 int run_command_file(
204 char *filename, const exec_context_t *exc)
206 char *full_filename;
207 FILE* f = NULL;
209 /* We attempt to open the filename by doing the following:
211 * - If the file does start with a "/" then it's treated as an
212 * absolute path.
214 * - Otherwise, it's assumed to be in FVWM_USERDIR OR FVWM_DATADIR,
215 * whichever comes first.
217 * - If the file starts with "./" or "../" then try and
218 * open the file exactly as specified which means
219 * things like:
221 * ../.././foo is catered for. At this point, we just try and open
222 * the specified file regardless.
224 * - *Hidden* files in the CWD would have to be specified as:
226 * ./.foo
228 full_filename = filename;
230 if (full_filename[0] == '/')
232 /* It's an absolute path */
233 f = fopen(full_filename,"r");
234 } else {
235 /* It's a relative path. Check in either FVWM_USERDIR or
236 * FVWM_DATADIR.
237 * */
238 full_filename = CatString3(fvwm_userdir, "/", filename);
240 if((f = fopen(full_filename, "r")) == NULL)
242 full_filename = CatString3(
243 FVWM_DATADIR, "/", filename);
244 f = fopen(full_filename, "r");
248 if ((f == NULL) &&
249 (f = fopen(filename, "r")) == NULL) {
250 /* We really couldn't open the file. */
251 return 0;
254 if (push_read_file(full_filename) == 0)
256 return 0;
258 run_command_stream(NULL, f, exc);
259 fclose(f);
260 pop_read_file();
262 return 1;
266 * Busy Cursor Stuff for Read
268 static void cursor_control(Bool grab)
270 static int read_depth = 0;
271 static Bool need_ungrab = False;
273 if (!(Scr.BusyCursor & BUSY_READ) && !need_ungrab)
275 return;
277 if (grab)
279 if (!read_depth && GrabEm(CRS_WAIT, GRAB_BUSY))
281 need_ungrab = True;
283 if (need_ungrab)
285 read_depth++;
288 else if (need_ungrab)
290 read_depth--;
291 if (!read_depth || !(Scr.BusyCursor & BUSY_READ))
293 UngrabEm(GRAB_BUSY);
294 need_ungrab = False;
295 read_depth = 0;
299 return;
302 void CMD_Read(F_CMD_ARGS)
304 char* filename;
305 int read_quietly;
307 DoingCommandLine = False;
309 if (cond_rc != NULL)
311 cond_rc->rc = COND_RC_OK;
313 if (!parse_filename("Read", action, &filename, &read_quietly))
315 if (cond_rc != NULL)
317 cond_rc->rc = COND_RC_ERROR;
319 return;
321 cursor_control(True);
322 if (!run_command_file(filename, exc))
324 if (!read_quietly)
326 if (filename[0] == '/')
328 fvwm_msg(
329 ERR, "Read",
330 "file '%s' not found", filename);
332 else
334 fvwm_msg(
335 ERR, "Read",
336 "file '%s' not found in %s or "
337 FVWM_DATADIR, filename, fvwm_userdir);
340 if (cond_rc != NULL)
342 cond_rc->rc = COND_RC_ERROR;
345 free(filename);
346 cursor_control(False);
348 return;
351 void CMD_PipeRead(F_CMD_ARGS)
353 char* command;
354 int read_quietly;
355 FILE* f;
357 DoingCommandLine = False;
359 if (cond_rc != NULL)
361 cond_rc->rc = COND_RC_OK;
363 if (!parse_filename("PipeRead", action, &command, &read_quietly))
365 if (cond_rc != NULL)
367 cond_rc->rc = COND_RC_ERROR;
369 return;
371 cursor_control(True);
372 f = popen(command, "r");
373 if (f == NULL)
375 if (cond_rc != NULL)
377 cond_rc->rc = COND_RC_ERROR;
379 if (!read_quietly)
381 fvwm_msg(
382 ERR, "PipeRead", "command '%s' not run",
383 command);
385 free(command);
386 cursor_control(False);
387 return;
389 free(command);
391 run_command_stream(cond_rc,f, exc);
392 pclose(f);
393 cursor_control(False);
395 return;