root/libutil/xargs.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exec_line_limit
  2. repeat_find_read
  3. repeat_find_next
  4. execute_command
  5. xargs_open_generic
  6. xargs_open_with_file
  7. xargs_open_with_argv
  8. xargs_open_with_strbuf
  9. xargs_open_with_find
  10. xargs_read
  11. xargs_unread
  12. 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 }

/* [previous][next][first][last][top][bottom][index][help] */