/* */
This source file includes following definitions.
- exec_line_limit
- repeat_find_read
- repeat_find_next
- execute_command
- xargs_open_generic
- xargs_open_with_file
- xargs_open_with_argv
- xargs_open_with_strbuf
- xargs_open_with_find
- xargs_read
- xargs_unread
- xargs_close
1 /*
2 * Copyright (c) 2005 Tama Communications Corporation
3 *
4 * This file is part of GNU GLOBAL.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <assert.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #ifdef HAVE_LIMITS_H
27 #include <limits.h>
28 #endif
29
30 #include "checkalloc.h"
31 #include "die.h"
32 #include "env.h"
33 #include "find.h"
34 #include "gpathop.h"
35 #include "locatestring.h"
36 #include "strbuf.h"
37 #include "test.h"
38 #include "xargs.h"
39
40 #if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
41 /* FIXME: in theory sysconf() can return -1L for unlimited */
42 #define ARG_MAX sysconf(_SC_ARG_MAX)
43 #endif
44
45 static int exec_line_limit(int);
46 static char *repeat_find_read(void);
47 static void repeat_find_next(void);
48 static FILE *execute_command(XARGS *);
49 static XARGS *xargs_open_generic(const char *, int);
50
51 /**
52 @file
53 *
54 * @details
55 * usage: a piece of code to achieve the following command line.
56 *
57 * @code{.sh}
58 * find . -type f -print | xargs grep pattern
59 * @endcode
60 *
61 * @code
62 * char *p;
63 * FILE *ip = popen("find . -type f -print", "r");
64 * XARGS *xp = xargs_open_with_file("grep pattern", ip)
65 * xp->ignore_error = 1;
66 * while ((p = xargs_read(xp)) != NULL)
67 * puts(p);
68 * xargs_close(xp);
69 * @endcode
70 */
71 /**
72 * exec_line_limit: upper limit of bytes of exec line.
73 *
74 * @param[in] length command line length
75 * @return 0: unknown or cannot afford long line. <br>
76 * \> 0: upper limit of exec line
77 */
78 static int
79 exec_line_limit(int length)
80 {
81 long limit = 0;
82
83 #ifdef ARG_MAX
84 /*
85 * POSIX.2 limits the exec(2) line length to ARG_MAX - 2048.
86 */
87 limit = ARG_MAX - 2048;
88 /*
89 * The reason is unknown but the xargs(1) in GNU findutils
90 * use this limit.
91 */
92 if (limit > 20 * 1024)
93 limit = 20 * 1024;
94 /*
95 * Add the command line length.
96 * We estimates additional 80 bytes for popen(3).
97 *
98 * for "/bin/sh -c " 11bytes
99 * reserve 69bytes
100 * ----------------------------------------------------
101 * Total 80 bytes
102 */
103 limit -= length + 80;
104
105 limit -= env_size();
106 #endif
107 #if !defined(ARG_MAX) && defined(_WIN32)
108 /*
109 * The limit lenght of the command line of cmd.exe is 2047
110 * characters on Windows 2000 or 8191 characters on Windows XP
111 * and later. The 80 below is for safety.
112 */
113 limit = 2047 - length - 80;
114 #endif
115 if (limit < 0)
116 die("Negative exec line limit = %ld", limit);
117
118 return limit;
119 }
120 /**
121 * @fn static char *repeat_find_read(void)
122 *
123 * repeatable find_read
124 */
125 static char *repeat_lastpath;
126 static char *
127 repeat_find_read(void)
128 {
129 if (repeat_lastpath)
130 return repeat_lastpath;
131 return repeat_lastpath = find_read();
132 }
133 static void
134 repeat_find_next(void)
135 {
136 repeat_lastpath = NULL;
137 }
138
139 /**
140 * Specified limitation by user. (e.g. @CODE{gtags --max-args})
141 */
142 #define LT_MAX ((xp->max_args == 0 || count < xp->max_args))
143
144 /**
145 * Common processing for each @NAME{XARGS_XXXX} type.
146 */
147 #ifdef _WIN32
148 #define QUOTE '"'
149 #else
150 #define QUOTE '\''
151 #endif
152 #define APPEND_ARGUMENT(p) {\
153 char *path = (p);\
154 length = strlen(path);\
155 if (*path == ' ') {\
156 if (xp->put_gpath && !test("b", ++path))\
157 gpath_put(path, GPATH_OTHER);\
158 continue;\
159 }\
160 if (strbuf_getlen(comline) + length + 2 > limit)\
161 break;\
162 xp->seqno++;\
163 if (xp->put_gpath)\
164 gpath_put(path, GPATH_SOURCE);\
165 if (xp->skip_assembly && locatestring(path, ".s", MATCH_AT_LAST|IGNORE_CASE) != NULL) {\
166 if (xp->verbose)\
167 xp->verbose(path + 2, xp->seqno, 1);\
168 } else {\
169 if (xp->verbose)\
170 xp->verbose(path + 2, xp->seqno, 0);\
171 strbuf_putc(comline, ' ');\
172 strbuf_putc(comline, QUOTE);\
173 strbuf_puts(comline, path);\
174 strbuf_putc(comline, QUOTE);\
175 count++;\
176 }\
177 }
178
179 /**
180 * execute_command
181 *
182 * @param[in] xp xargs structure
183 * @return !=NULL: file pointer <br>
184 * ==NULL: end of argument
185 *
186 * This function constructs command line from the following, <br>
187 * @STRONG{command}: @CODE{xp-\>command} <br>
188 * @STRONG{argument}: each argument provider <br>
189 * execute it on a pipe line, and return the file pointer.
190 */
191 static FILE *
192 execute_command(XARGS *xp)
193 {
194 int limit;
195 STRBUF *comline = strbuf_open(0);
196 int count = 0;
197 int length;
198 FILE *pipe = NULL;
199 char *p, *meta_p;
200
201 #if defined(_WIN32) && !defined(__CYGWIN__)
202 /*
203 * If the command starts with a quote, CMD.EXE requires the entire
204 * command line to be quoted.
205 */
206 if (*xp->command == '"')
207 strbuf_putc(comline, '"');
208 #endif
209 /*
210 * Copy the part before '%s' of the command skeleton.
211 * The '%s' in the skeleton is replaced with given arguments.
212 */
213 meta_p = locatestring(xp->command, "%s", MATCH_FIRST);
214 if (meta_p) {
215 strbuf_nputs(comline, xp->command, meta_p - xp->command);
216 limit = exec_line_limit(strlen(meta_p + 2));
217 } else {
218 strbuf_puts(comline, xp->command);
219 limit = exec_line_limit(0);
220 }
221 /*
222 * Append arguments as many as possible.
223 */
224 switch (xp->type) {
225 case XARGS_FILE:
226 for (
227 /* initial */
228 fseek(xp->ip, xp->fptr, SEEK_SET)
229 ;
230 /* continuation condition */
231 (LT_MAX &&
232 ((p = (strbuf_getlen(xp->path) > 0 ?
233 strbuf_value(xp->path) :
234 strbuf_fgets(xp->path, xp->ip, STRBUF_NOCRLF))) != NULL))
235 ;
236 /* preparation */
237 strbuf_reset(xp->path)
238 )
239 APPEND_ARGUMENT(p);
240 xp->fptr = ftell(xp->ip);
241 break;
242 case XARGS_ARGV:
243 for (; LT_MAX && xp->argc > 0; xp->argc--, xp->argv++)
244 APPEND_ARGUMENT(xp->argv[0])
245 break;
246 case XARGS_STRBUF:
247 for (; LT_MAX && xp->curp < xp->endp; xp->curp += length + 1)
248 APPEND_ARGUMENT(xp->curp)
249 break;
250 case XARGS_FIND:
251 for (; LT_MAX && (p = repeat_find_read()) != NULL; repeat_find_next())
252 APPEND_ARGUMENT(p)
253 break;
254 }
255 /*
256 * Copy the left part of the command skeleton.
257 */
258 if (meta_p) {
259 strbuf_putc(comline, ' ');
260 strbuf_puts(comline, meta_p + 2);
261 }
262 #if defined(_WIN32) && !defined(__CYGWIN__)
263 if (*xp->command == '"')
264 strbuf_putc(comline, '"');
265 #endif
266 if (count > 0) {
267 pipe = popen(strbuf_value(comline), "r");
268 if (pipe == NULL)
269 die("cannot execute command '%s'.", strbuf_value(comline));
270 }
271 strbuf_close(comline);
272 return pipe;
273 }
274 /**
275 * xargs_open_generic: allocate generic part of xargs structure.
276 *
277 * @param[in] command command line except for the arguments.
278 * @param[in] max_args 0: no limit, \>0: max argument
279 * @return xargs structure
280 */
281 static XARGS *
282 xargs_open_generic(const char *command, int max_args)
283 {
284 XARGS *xp;
285
286 xp = check_calloc(sizeof(XARGS), 1);
287 xp->command = check_strdup(command);
288 xp->type = 0;
289 xp->pipe = NULL;
290 xp->result = strbuf_open(0);
291 xp->end_of_arg = 0;
292 xp->unread = 0;
293 xp->max_args = max_args;
294 xp->seqno = 0;
295 xp->skip_assembly = 0;
296 /*
297 * Procedure to display verbose message.
298 * proc(path, seqno, skip)
299 */
300 xp->verbose = NULL;
301 /*
302 * By default, the error status returned by pclose() is not ignored,
303 * because global(1) doesn't return error code when the target
304 * was not found.
305 * Some commands like grep(1) return error code when the target
306 * was not found. If you would like to use such command, set the
307 * flag to 1.
308 */
309 xp->ignore_error = 0;
310 /*
311 * By default, we doesn't put the path to GPATH.
312 * This option is prepared for createtags() and updatetags().
313 */
314 xp->put_gpath = 0;
315 /*
316 * By default, we don't cut off the blanks at the tail of the line.
317 */
318 xp->trim_line = 0;
319
320 return xp;
321 }
322 /**
323 * xargs_open_with_file: open xargs stream using file
324 *
325 * @param[in] command command skeleton.
326 * @param[in] max_args 0: no limit, \>0: max argument
327 * @param[in] ip file pointer
328 * @return xargs structure
329 *
330 * The @CODE{'\%s'} in the command skeleton is replaced with given arguments. <br>
331 * If @CODE{'\%s'} doesn't exist, the arguments is appended to the tail of the
332 * skeleton.
333 */
334 XARGS *
335 xargs_open_with_file(const char *command, int max_args, FILE *ip)
336 {
337 XARGS *xp = xargs_open_generic(command, max_args);
338
339 xp->type = XARGS_FILE;
340 xp->ip = ip;
341 xp->path = strbuf_open(0);
342 xp->fptr = 0;
343 return xp;
344 }
345 /**
346 * xargs_open_with_argv: open xargs stream using @a argv
347 *
348 * @param[in] command command skeleton.
349 * @param[in] max_args 0: no limit, \>0: max argument
350 * @param[in] argc argument number
351 * @param[in] argv argument array
352 * @return xargs structure
353 *
354 * The @CODE{'\%s'} in the command skeleton is replaced with given arguments. <br>
355 * If @CODE{'\%s'} doesn't exist, the arguments is appended to the tail of the
356 * skeleton.
357 */
358 XARGS *
359 xargs_open_with_argv(const char *command, int max_args, int argc, char *const *argv)
360 {
361 XARGS *xp = xargs_open_generic(command, max_args);
362
363 xp->type = XARGS_ARGV;
364 xp->argc = argc;
365 xp->argv = argv;
366 return xp;
367 }
368 /**
369 * xargs_open_with_strbuf: open xargs stream using string buffer
370 *
371 * @param[in] command command skeleton.
372 * @param[in] max_args 0: no limit, \>0: max argument
373 * @param[in] sb string buffer
374 * @return xargs structure
375 *
376 * The @CODE{'\%s'} in the command skeleton is replaced with given arguments. <br>
377 * If @CODE{'\%s'} doesn't exist, the arguments is appended to the tail of the
378 * skeleton.
379 */
380 XARGS *
381 xargs_open_with_strbuf(const char *command, int max_args, STRBUF *sb)
382 {
383 XARGS *xp = xargs_open_generic(command, max_args);
384
385 xp->type = XARGS_STRBUF;
386 xp->curp = strbuf_value(sb);
387 xp->endp = xp->curp + strbuf_getlen(sb);
388 return xp;
389 }
390 /**
391 * xargs_open_with_find: open xargs stream using @NAME{find()}.
392 *
393 * @param[in] command command skeleton.
394 * @param[in] max_args 0: no limit, \>0: max argument
395 * @return xargs structure
396 *
397 * The @CODE{'\%s'} in the command skeleton is replaced with given arguments. <br>
398 * If @CODE{'\%s'} doesn't exist, the arguments is appended to the tail of the
399 * skeleton.
400 */
401 XARGS *
402 xargs_open_with_find(const char *command, int max_args)
403 {
404 XARGS *xp = xargs_open_generic(command, max_args);
405
406 xp->type = XARGS_FIND;
407 return xp;
408 }
409 /**
410 * xargs_read: read a record from xargs stream
411 *
412 * @param[in] xp xargs structure
413 * @return result line
414 */
415 char *
416 xargs_read(XARGS *xp)
417 {
418 assert(xp != NULL);
419 if (xp->end_of_arg)
420 return NULL;
421 if (xp->unread) {
422 xp->unread = 0;
423 return strbuf_value(xp->result);
424 }
425 if (xp->pipe && strbuf_fgets(xp->result, xp->pipe, STRBUF_NOCRLF) != NULL) {
426 if (xp->trim_line)
427 strbuf_trim(xp->result);
428 return strbuf_value(xp->result);
429 }
430 if (xp->pipe)
431 if (pclose(xp->pipe) != 0 && !xp->ignore_error)
432 die("command failed in xargs_read().");
433 /*
434 * Switch to the next segment.
435 */
436 do {
437 xp->pipe = execute_command(xp);
438 if (xp->pipe && strbuf_fgets(xp->result, xp->pipe, STRBUF_NOCRLF) != NULL) {
439 if (xp->trim_line)
440 strbuf_trim(xp->result);
441 return strbuf_value(xp->result);
442 }
443 if (xp->pipe) {
444 if (pclose(xp->pipe) != 0 && !xp->ignore_error)
445 die("command failed in xargs_read().");
446 } else {
447 xp->end_of_arg = 1;
448 }
449 } while (!xp->end_of_arg);
450
451 return NULL;
452 }
453 /**
454 * xargs_unread: push back a record to xargs stream
455 *
456 * @param[in] xp xargs structure
457 */
458 void
459 xargs_unread(XARGS *xp)
460 {
461 assert(xp != NULL);
462 xp->unread = 1;
463 }
464 /**
465 * xargs_close(xp)
466 *
467 * @param[in] xp xargs structure
468 */
469 int
470 xargs_close(XARGS *xp)
471 {
472 int count;
473
474 assert(xp != NULL);
475 count = xp->seqno;
476 assert(xp->pipe == NULL);
477 free(xp->command);
478 strbuf_close(xp->result);
479
480 switch (xp->type) {
481 case XARGS_FILE:
482 strbuf_close(xp->path);
483 break;
484 case XARGS_ARGV:
485 case XARGS_STRBUF:
486 /* Nothing to do */
487 break;
488 }
489 free(xp);
490 return count;
491 }
/* */