(root)/
Linux-PAM-1.5.3/
modules/
pam_namespace/
argv_parse.c
       1  /*
       2   * argv_parse.c --- utility function for parsing a string into a
       3   * 	argc, argv array.
       4   *
       5   * This file defines a function argv_parse() which parsing a
       6   * passed-in string, handling double quotes and backslashes, and
       7   * creates an allocated argv vector which can be freed using the
       8   * argv_free() function.
       9   *
      10   * See argv_parse.h for the formal definition of the functions.
      11   *
      12   * Copyright 1999 by Theodore Ts'o.
      13   *
      14   * Permission to use, copy, modify, and distribute this software for
      15   * any purpose with or without fee is hereby granted, provided that
      16   * the above copyright notice and this permission notice appear in all
      17   * copies.  THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE
      18   * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
      19   * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
      20   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
      21   * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
      22   * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
      23   * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
      24   * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  (Isn't
      25   * it sick that the U.S. culture of lawsuit-happy lawyers requires
      26   * this kind of disclaimer?)
      27   *
      28   * Version 1.1, modified 2/27/1999
      29   */
      30  
      31  #include <stdlib.h>
      32  #include <ctype.h>
      33  #include <string.h>
      34  #include "argv_parse.h"
      35  
      36  #define STATE_WHITESPACE	1
      37  #define STATE_TOKEN		2
      38  #define STATE_QUOTED		3
      39  
      40  /*
      41   * Returns 0 on success, -1 on failure.
      42   */
      43  int argv_parse(const char *in_buf, int *ret_argc, char ***ret_argv)
      44  {
      45  	int	argc = 0, max_argc = 0;
      46  	char 	**argv, **new_argv, *buf, ch;
      47  	const char *cp = NULL;
      48  	char    *outcp = NULL;
      49  	int	state = STATE_WHITESPACE;
      50  
      51  	buf = malloc(strlen(in_buf)+1);
      52  	if (!buf)
      53  		return -1;
      54  
      55  	argv = NULL;
      56  	outcp = buf;
      57  	for (cp = in_buf; (ch = *cp); cp++) {
      58  		if (state == STATE_WHITESPACE) {
      59  			if (isspace((int) ch))
      60  				continue;
      61  			/* Not whitespace, so start a new token */
      62  			state = STATE_TOKEN;
      63  			if (argc >= max_argc) {
      64  				max_argc += 3;
      65  				new_argv = realloc(argv,
      66  						  (max_argc+1)*sizeof(char *));
      67  				if (!new_argv) {
      68  					if (argv) free(argv);
      69  					free(buf);
      70  					return -1;
      71  				}
      72  				argv = new_argv;
      73  			}
      74  			argv[argc++] = outcp;
      75  		}
      76  		if (state == STATE_QUOTED) {
      77  			if (ch == '"')
      78  				state = STATE_TOKEN;
      79  			else
      80  				*outcp++ = ch;
      81  			continue;
      82  		}
      83  		/* Must be processing characters in a word */
      84  		if (isspace((int) ch)) {
      85  			/*
      86  			 * Terminate the current word and start
      87  			 * looking for the beginning of the next word.
      88  			 */
      89  			*outcp++ = 0;
      90  			state = STATE_WHITESPACE;
      91  			continue;
      92  		}
      93  		if (ch == '"') {
      94  			state = STATE_QUOTED;
      95  			continue;
      96  		}
      97  		if (ch == '\\') {
      98  			ch = *++cp;
      99  			switch (ch) {
     100  			case '\0':
     101  				ch = '\\'; cp--; break;
     102  			case 'n':
     103  				ch = '\n'; break;
     104  			case 't':
     105  				ch = '\t'; break;
     106  			case 'b':
     107  				ch = '\b'; break;
     108  			}
     109  		}
     110  		*outcp++ = ch;
     111  	}
     112  	if (state != STATE_WHITESPACE)
     113  		*outcp++ = '\0';
     114  	if (ret_argv) {
     115  		if (argv == NULL) {
     116  			free(buf);
     117  			if ((argv=malloc(sizeof(char *))) == NULL)
     118  				return -1;
     119  		}
     120  		argv[argc] = NULL;
     121  		*ret_argv = argv;
     122  	} else {
     123  		free(buf);
     124  		free(argv);
     125  	}
     126  	if (ret_argc)
     127  		*ret_argc = argc;
     128  	return 0;
     129  }
     130  
     131  void argv_free(char **argv)
     132  {
     133  	if (argv) {
     134  		if (*argv)
     135  			free(*argv);
     136  		free(argv);
     137  	}
     138  }
     139  
     140  #ifdef DEBUG_ARGV_PARSE
     141  /*
     142   * For debugging
     143   */
     144  
     145  #include <stdio.h>
     146  
     147  int main(int argc, char **argv)
     148  {
     149  	int	ac, ret;
     150  	char	**av, **cpp;
     151  	char	buf[256];
     152  
     153  	while (!feof(stdin)) {
     154  		if (fgets(buf, sizeof(buf), stdin) == NULL)
     155  			break;
     156  		ret = argv_parse(buf, &ac, &av);
     157  		if (ret != 0) {
     158  			printf("Argv_parse returned %d!\n", ret);
     159  			continue;
     160  		}
     161  		printf("Argv_parse returned %d arguments...\n", ac);
     162  		for (cpp = av; *cpp; cpp++) {
     163  			if (cpp != av)
     164  				printf(", ");
     165  			printf("'%s'", *cpp);
     166  		}
     167  		printf("\n");
     168  		argv_free(av);
     169  	}
     170  	exit(0);
     171  }
     172  #endif