| /* Iterate over arguments from argv or --files0-from=FILE |
| Copyright (C) 2008-2020 Free Software Foundation, Inc. |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| |
| /* Written by Jim Meyering. */ |
| |
| #include <config.h> |
| #include "argv-iter.h" |
| |
| #include <stdlib.h> |
| #include <string.h> |
| |
| struct argv_iterator |
| { |
| /* Test FP to determine whether in read-mode or argv-mode. */ |
| /* file-mode: fp records position */ |
| FILE *fp; |
| size_t item_idx; |
| char *tok; |
| size_t buf_len; |
| |
| /* argv-mode: record just argv and current pointer */ |
| char **arg_list; |
| char **p; |
| }; |
| |
| struct argv_iterator * |
| argv_iter_init_argv (char **argv) |
| { |
| struct argv_iterator *ai = malloc (sizeof *ai); |
| if (!ai) |
| return NULL; |
| ai->fp = NULL; |
| ai->arg_list = argv; |
| ai->p = argv; |
| return ai; |
| } |
| |
| /* Initialize to read from the stream, FP. |
| The input is expected to contain a list of NUL-delimited tokens. */ |
| struct argv_iterator * |
| argv_iter_init_stream (FILE *fp) |
| { |
| struct argv_iterator *ai = malloc (sizeof *ai); |
| if (!ai) |
| return NULL; |
| ai->fp = fp; |
| ai->tok = NULL; |
| ai->buf_len = 0; |
| |
| ai->item_idx = 0; |
| ai->arg_list = NULL; |
| return ai; |
| } |
| |
| char * |
| argv_iter (struct argv_iterator *ai, enum argv_iter_err *err) |
| { |
| if (ai->fp) |
| { |
| ssize_t len = getdelim (&ai->tok, &ai->buf_len, '\0', ai->fp); |
| if (len < 0) |
| { |
| *err = feof (ai->fp) ? AI_ERR_EOF : AI_ERR_READ; |
| return NULL; |
| } |
| |
| *err = AI_ERR_OK; |
| ai->item_idx++; |
| return ai->tok; |
| } |
| else |
| { |
| if (*(ai->p) == NULL) |
| { |
| *err = AI_ERR_EOF; |
| return NULL; |
| } |
| else |
| { |
| *err = AI_ERR_OK; |
| return *(ai->p++); |
| } |
| } |
| } |
| |
| size_t |
| argv_iter_n_args (struct argv_iterator const *ai) |
| { |
| return ai->fp ? ai->item_idx : ai->p - ai->arg_list; |
| } |
| |
| void |
| argv_iter_free (struct argv_iterator *ai) |
| { |
| if (ai->fp) |
| free (ai->tok); |
| free (ai); |
| } |