/[radius]/radius/lib/argcv.c
ViewVC logotype

Diff of /radius/lib/argcv.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.3 by gray, Sun Jul 20 20:31:30 2003 UTC revision 1.4 by gray, Fri Nov 28 15:03:12 2003 UTC
# Line 1  Line 1 
1  /* argcv.c - simple functions for parsing input based on whitespace  /* argcv.c - simple functions for parsing input based on whitespace
2     Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.     Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3    
4     This program is free software; you can redistribute it and/or modify     This library is free software; you can redistribute it and/or
5     it under the terms of the GNU General Public License as published by     modify it under the terms of the GNU Lesser General Public
6     the Free Software Foundation; either version 2, or (at your option)     License as published by the Free Software Foundation; either
7     any later version.     version 2 of the License, or (at your option) any later version.
8    
9     This program is distributed in the hope that it will be useful,     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     GNU General Public License for more details.     Lesser General Public License for more details.
13    
14     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU Lesser General Public
15     along with GNU Radius; if not, write to the Free Software Foundation,     License along with this library; if not, write to the Free Software
16     Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA  */
17    
18  #include "argcv.h"  #ifdef HAVE_CONFIG_H
19    # include <config.h>
20    #endif
21    
22    #include <ctype.h>
23    #include <argcv.h>
24    
25  /*  /*
26   * takes a string and splits it into several strings, breaking at ' '   * takes a string and splits it into several strings, breaking at ' '
# Line 25  Line 30 
30   * returns 0 on success, nonzero on failure   * returns 0 on success, nonzero on failure
31   */   */
32    
33  #define isws(c) ((c)==' '||(c)=='\t')  #define isws(c) ((c)==' '||(c)=='\t'||(c)=='\n')
34  #define isdelim(c,delim) ((c)=='"'||strchr(delim,(c))!=NULL)  #define isdelim(c,delim) ((c)=='"'||strchr(delim,(c))!=NULL)
35    
36  static int  static int
37  argcv_scan (int len, const char *command, const char *delim,  argcv_scan (int len, const char *command, const char *delim, const char* cmnt,
38              int *start, int *end, int *save)              int *start, int *end, int *save)
39  {  {
40    int i = *save;    int i = 0;
41    
42    /* Skip initial whitespace */    for (;;)
43    while (i < len && isws (command[i]))      {
44      i++;        i = *save;
45    *start = i;  
46          if (i >= len)
47    switch (command[i])          return i + 1;
48      {  
49      case '"':        /* Skip initial whitespace */
50      case '\'':        while (i < len && isws (command[i]))
51        while (++i < len && command[i] != command[*start])          i++;
52          ;        *start = i;
53        if (i < len)  /* found matching quote */  
54          break;        switch (command[i])
55        /*FALLTHRU*/          {
56      default:          case '"':
57        if (isdelim (command [i], delim))          case '\'':
58          break;            while (++i < len
59        /* Skip until next whitespace character or end of line */                   && (command[i] != command[*start]
60        while (++i < len &&                       || command[i-1] == '\\'))
61               !(isws (command [i]) || isdelim (command [i], delim)))              ;
62          ;            if (i < len)          /* found matching quote */
63        i--;              break;
64             /*FALLTHRU*/ default:
65              if (isdelim (command[i], delim))
66                break;
67              /* Skip until next whitespace character or end of line */
68              while (++i < len &&
69                     !(isws (command[i]) || isdelim (command[i], delim)))
70                ;
71              i--;
72              break;
73            }
74    
75          *end = i;
76          *save = i + 1;
77    
78          /* If we have a token, and it starts with a comment character, skip
79             to the newline and restart the token search. */
80          if (*save <= len)
81            {
82              if (cmnt && strchr (cmnt, command[*start]) != NULL)
83                {
84                  i = *save;
85                  while (i < len && command[i] != '\n')
86                    i++;
87    
88                  *save = i;
89                  continue;
90                }
91            }
92        break;        break;
93      }      }
   
   *end = i;  
   *save = i+1;  
94    return *save;    return *save;
95  }  }
96    
97    static char quote_transtab[] = "\\\\a\ab\bf\fn\nr\rt\t";
98    
99    int
100    argcv_unquote_char (int c)
101    {
102      char *p;
103    
104      for (p = quote_transtab; *p; p += 2)
105        {
106          if (*p == c)
107            return p[1];
108        }
109      return c;
110    }
111    
112  int  int
113  argcv_get (const char *command, const char *delim, int *argc, char ***argv)  argcv_quote_char (int c)
114    {
115      char *p;
116      
117      for (p = quote_transtab + sizeof(quote_transtab) - 2;
118           p > quote_transtab; p -= 2)
119        {
120          if (*p == c)
121            return p[-1];
122        }
123      return -1;
124    }
125      
126    
127    static int
128    xtonum (const char *src, int base, size_t cnt)
129    {
130      int val;
131      char *p;
132      char tmp[4]; /* At most three characters + zero */
133      
134      /* Notice: No use to check `cnt'. It should be either 2 or 3 */
135      memcpy (tmp, src, cnt);
136      tmp[cnt] = 0;
137      val = strtoul (tmp, &p, base);
138      return (*p == 0) ? val : -1;
139    }
140    
141    size_t
142    argcv_quoted_length (const char *str, int *quote)
143    {
144      size_t len = 0;
145    
146      for (; *str; str++)
147        {
148          if (*str == ' ')
149            {
150              len++;
151              *quote = 1;
152            }
153          else if (*str == '"')
154            {
155              len += 2;
156              *quote = 1;
157            }
158          else if (isprint (*str))
159            len++;
160          else if (argcv_quote_char (*str) != -1)
161            len += 2;
162          else
163            len += 4;
164        }
165      return len;
166    }
167    
168    void
169    argcv_unquote_copy (char *dst, const char *src, size_t n)
170    {
171      int c;
172      
173      while (n > 0)
174        {
175          n--;
176          if (*src == '\\')
177            {
178              switch (*++src)
179                {
180                case 'x':
181                case 'X':
182                  ++src;
183                  --n;
184                  if (n == 0)
185                    {
186                      *dst++ = '\\';
187                      *dst++ = src[-1];
188                    }
189                  else
190                    {
191                      c = xtonum(src, 16, 2);
192                      if (c == -1)
193                        {
194                          *dst++ = '\\';
195                          *dst++ = src[-1];
196                        }
197                      else
198                        {
199                          *dst++ = c;
200                          src += 2;
201                          n -= 2;
202                        }
203                    }
204                  break;
205                  
206                case '0':
207                  ++src;
208                  --n;
209                  if (n == 0)
210                    {
211                      *dst++ = '\\';
212                      *dst++ = src[-1];
213                    }
214                  else
215                    {
216                      c = xtonum(src, 8, 3);
217                      if (c == -1)
218                        {
219                          *dst++ = '\\';
220                          *dst++ = src[-1];
221                        }
222                      else
223                        {
224                          *dst++ = c;
225                          src += 3;
226                          n -= 3;
227                        }
228                    }
229                  break;
230                  
231                default:
232                  *dst++ = argcv_unquote_char (*src++);
233                  n--;
234                }
235            }
236          else
237            {
238              *dst++ = *src++;
239            }
240        }
241      *dst = 0;
242    }
243    
244    void
245    argcv_quote_copy (char *dst, const char *src)
246    {
247      for (; *src; src++)
248        {
249          if (*src == '"')
250            {
251              *dst++ = '\\';
252              *dst++ = '"';
253            }
254          else if (*src != '\t' && isprint(*src))
255            *dst++ = *src;      
256          else
257            {
258              int c = argcv_quote_char (*src);
259              *dst++ = '\\';
260              if (c != -1)
261                *dst++ = c;
262              else
263                {
264                  char tmp[4];
265                  snprintf (tmp, sizeof tmp, "%03o", *(unsigned char*)src);
266                  memcpy (dst, tmp, 3);
267                  dst += 3;
268                }
269            }
270        }
271    }
272    
273    int
274    argcv_get (const char *command, const char *delim, const char* cmnt,
275               int *argc, char ***argv)
276  {  {
277    int len = strlen (command);    int len = strlen (command);
278    int i = 0;    int i = 0;
279    int start, end, save;    int start, end, save;
280    
   *argc = 0;  
281    *argv = NULL;    *argv = NULL;
282    
   while (len > 0 && isspace (command[len-1]))  
     len--;  
   if (len < 1)  
     return 1;  
   
283    /* Count number of arguments */    /* Count number of arguments */
284    *argc = 1;    *argc = 0;
285    save = 0;    save = 0;
286    while (argcv_scan (len, command, delim, &start, &end, &save) < len)  
287      while (argcv_scan (len, command, delim, cmnt, &start, &end, &save) <= len)
288        (*argc)++;        (*argc)++;
289    
290    *argv = calloc ((*argc + 1), sizeof (char *));    *argv = calloc ((*argc + 1), sizeof (char *));
# Line 92  argcv_get (const char *command, const ch Line 294  argcv_get (const char *command, const ch
294    for (i = 0; i < *argc; i++)    for (i = 0; i < *argc; i++)
295      {      {
296        int n;        int n;
297        argcv_scan (len, command, delim, &start, &end, &save);        argcv_scan (len, command, delim, cmnt, &start, &end, &save);
298    
299        if (command[start] == '"' && command[end] == '"')        if ((command[start] == '"' || command[end] == '\'')
300          {            && command[end] == command[start])
301            start++;          {
302            end--;            start++;
303          }            end--;
304        else if (command[start] == '\'' && command[end] == '\'')          }
         {  
           start++;  
           end--;  
         }  
305        n = end - start + 1;        n = end - start + 1;
306        (*argv)[i] = calloc (n+1,  sizeof (char));        (*argv)[i] = calloc (n+1,  sizeof (char));
307        if ((*argv)[i] == NULL)        if ((*argv)[i] == NULL)
308          return 1;          return 1;
309        memcpy ((*argv)[i], &command[start], n);        argcv_unquote_copy ((*argv)[i], &command[start], n);
310        (*argv)[i][n] = 0;        (*argv)[i][n] = 0;
311      }      }
312    (*argv)[i] = NULL;    (*argv)[i] = NULL;
# Line 135  argcv_free (int argc, char **argv) Line 333  argcv_free (int argc, char **argv)
333  int  int
334  argcv_string (int argc, char **argv, char **pstring)  argcv_string (int argc, char **argv, char **pstring)
335  {  {
336    int i;    size_t i, j, len;
   size_t len;  
337    char *buffer;    char *buffer;
338    
339    /* No need.  */    /* No need.  */
# Line 148  argcv_string (int argc, char **argv, cha Line 345  argcv_string (int argc, char **argv, cha
345      return 1;      return 1;
346    *buffer = '\0';    *buffer = '\0';
347    
348    for (len = i = 0; i < argc; i++)    for (len = i = j = 0; i < argc; i++)
349      {      {
350        int quote = 0;        int quote = 0;
351        char *p;        int toklen;
352    
353        for (p = argv[i]; *p; p++)        toklen = argcv_quoted_length (argv[i], &quote);
         if (isspace(*p))  
           {  
             quote = 1;  
             break;  
           }  
354                
355        len += strlen (argv[i]) + 2;        len += toklen + 2;
356        if (quote)        if (quote)
357          len += 2;          len += 2;
358                
359        buffer = realloc (buffer, len);        buffer = realloc (buffer, len);
360        if (buffer == NULL)        if (buffer == NULL)
361          return 1;          return 1;
362    
363        if (i != 0)        if (i != 0)
364          strcat (buffer, " ");          buffer[j++] = ' ';
365        if (quote)        if (quote)
366          strcat (buffer, "\"");          buffer[j++] = '"';
367        strcat (buffer, argv[i]);        argcv_quote_copy (buffer + j, argv[i]);
368          j += toklen;
369        if (quote)        if (quote)
370          strcat (buffer, "\"");          buffer[j++] = '"';
371      }      }
372    
373    /* Strip off trailing space.  */    for (; j > 0 && isspace (buffer[j-1]); j--)
374    if (*buffer != '\0')      ;
375      {    buffer[j] = 0;
       while (buffer[strlen (buffer) - 1] == ' ')  
         {  
           buffer[strlen (buffer) - 1] = '\0';  
         }  
     }  
376    if (pstring)    if (pstring)
377      *pstring = buffer;      *pstring = buffer;
378    return 0;    return 0;
379  }  }
380    
381  #if 0  #if 0
382  char *command = "set prompt=\"& \"   #comm";  char *command = "set prompt=\"& \a\\\"\" \\x25\\0145\\098\\ta";
383    
384  main()  main(int xargc, char **xargv)
385  {  {
386    int i, argc;    int i, argc;
387    char **argv;    char **argv;
388      char *s;
389    argcv_get (command, "=", &argc, &argv);    
390      argcv_get (xargv[1] ? xargv[1]:command, "=", "#", &argc, &argv);
391    printf ("%d args:\n", argc);    printf ("%d args:\n", argc);
392    for (i = 0; i < argc; i++)    for (i = 0; i < argc; i++)
393      printf ("%s\n", argv[i]);      printf ("%s\n", argv[i]);
394      printf ("===\n");
395      argcv_string (argc, argv, &s);
396      printf ("%s\n", s);
397  }  }
398  #endif  #endif

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.4

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26