On Mon, Aug 04, 2003 at 02:33:31AM +0200, Simon Barner wrote:
> Hi Terry,
> 
> > You need to add '\\' to the list of characters that can be escaped,
> > or you've just traded the inability to specify '\t' or ' ' for an
> > inability to speciy '\\'.
> 
> Oh yes, I have overlook this special case. I revised my patch in order
> to get this right.
> 
> Simon

helo.

imho - expensive algorithm... i want to see anything more simple... 
like "gtok()" instead "es_strsep() + remove_escapes()"?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *gtok(char **s, char const *delim)
{
        int quoted, escaped;
        static char const esc_set[] = {  't',  'r',  'n',  'a', 0 };
        static char const esc_rep[] = { '\t', '\r', '\n', '\a', 0 };
        char *tok, *r, *w, *p;

        if (!s || !*s || !*(tok = *s + strspn(*s, delim)) || *tok == '#')
                return NULL;

        for (quoted = escaped = 0, r = w = tok; *r; r++) {
                if (!escaped) {
                        if (*r == '\\') {
                                escaped = 1;
                                continue;
                        }
                        if (*r == '\"') {
                                quoted ^= -1;
                                continue;
                        }
                        if (!quoted && strchr(delim, *r)) {
                                r++;
                                break;
                        }
                } else {
                        escaped = 0;
                        if ((p = strchr(esc_set, *r)) != NULL) {
                                *w++ = esc_rep[p - esc_set];
                                continue;
                        }
                }
                *w++ = *r;
        }
        *w = 0;
        *s = r;

        return tok;
}

#if 0
main()
{
        char *s, *t, buf[0x1000];

        while (fgets(buf, sizeof buf, stdin))
                for (s = buf; t = gtok(&s, " \t\r\n"); )
                        printf("\"%s\"\n", t);

        return 0;
}
#endif

/swp

> --- fstab.c.orig      Fri Aug  1 17:18:00 2003
> +++ fstab.c   Mon Aug  4 01:46:55 2003
> @@ -49,6 +49,7 @@
>  #include <errno.h>
>  #include <fstab.h>
>  #include <paths.h>
> +#include <stdbool.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> @@ -84,6 +85,140 @@
>       _fs_fstab.fs_spec = buf;
>  }
>  
> +/*
> + * Get next token from string *stringp, where tokens are possibly-empty
> + * strings separated by characters from delim.
> + *
> + * Writes NULs into the string at *stringp to end tokens.
> + * delim need not remain constant from call to call.
> + * On return, *stringp points past the last NUL written (if there might
> + * be further tokens), or is NULL (if there are definitely no more tokens).
> + *
> + * If *stringp is NULL, es_strsep returns NULL.
> + *
> + * In contrast to strsep(3), es_strsep will allow escaped delimiters
> + * within a token. These escaped characters as well as the special case
> + * '\\' will be converted appropriately ('\<delim>' -> '<delim>, '\\' -> '\'
> + *
> + */
> +char *
> +es_strsep(char **stringp, const char *delim)
> +{
> +     bool    escaped=false;
> +     char    *s, *t, *u;
> +     int     i;
> +
> +
> +     if (*stringp == '\0')   /* empty string */
> +             return NULL;
> +     s = *stringp;
> +     s += strspn (s, delim); /* skip delimiters */
> +
> +     if (*s == '\0')         /* string consists only of delimiters */
> +             return NULL;
> +     
> +     /*
> +      * skip a string consisting of non-delimiters,
> +      * escapted delimiters or '\\'
> +     */
> +     for (t = s; *t != '\0'; ++t) {
> +             if (*t == '\\') {
> +                 if (escaped) {      /* convert \\ to \ */
> +                     --t;
> +                     u = t;
> +                     escaped = false;
> +                     while (u[0] != '\0') {
> +                         u[0] = u[1];
> +                         ++u;
> +                     }
> +                 } else              /* start \-Sequence */
> +                     escaped = true;
> +                 continue;
> +             }
> +             
> +             /* search for delimiter */
> +             for (i=0; delim[i] != '\0'; ++i) {
> +                 if (*t == delim[i])
> +                     break;
> +             }
> +             
> +             /* un-escaped delimiter found => end of token */
> +             if (!escaped && delim[i] != '\0')
> +                 break;
> +                 
> +             /* escaped delimiter found => remove / */
> +             if (escaped) {
> +                 --t;
> +                 u = t;
> +                    escaped = false;
> +                 while (u[0] != '\0') {
> +                     u[0] = u[1];
> +                     ++u;
> +                 }
> +             }
> +     }
> +
> +     if (*t != '\0') {
> +             *t = '\0';              /* end current token */
> +             *stringp = t+1;         /* *t != '\0' => *(t+1) is valid */
> +     } else
> +             *stringp = 0;           /* end of string reached */     
> +     
> +     return s;                       /* return current token */
> +}
> +
> +/*
> + * This function converts escaped characters:
> + * '\<delim>' -> '<delim>', '\\' -> '\'
> + * 
> + * If there are unescaped delimiters, 'false' will be return to indicate
> + * an error, otherwise remove_escape returns 'true'.
> + */
> +bool remove_escapes (char **s, const char* delim) {
> +     bool    escaped=false;
> +     char    *t, *u;
> +     int     i;
> +     
> +     for (t = *s; *t != '\0'; ++t) {
> +             if (*t == '\\') {
> +                 if (escaped) {      /* convert \\ to \ */
> +                     --t;
> +                     u = t;
> +                     escaped = false;
> +                     while (u[0] != '\0') {
> +                         u[0] = u[1];
> +                         ++u;
> +                     }
> +                 } else              /* start \-Sequence */
> +                     escaped = true;
> +                 continue;
> +             }
> +             
> +             /* search for delimiter */
> +             for (i=0; delim[i] != '\0'; ++i) {
> +                 if (*t == delim[i])
> +                     break;
> +             }
> +             
> +             /* un-escaped delimiter found => error */
> +             if (!escaped && delim[i] != '\0')
> +                     return false;
> +
> +             /* escaped delimiter found => remove / */
> +             if (escaped) {
> +                 --t;
> +                 u = t;
> +                    escaped = false;
> +                 while (u[0] != '\0') {
> +                     u[0] = u[1];
> +                     ++u;
> +                 }
> +             }
> +     }
> +     
> +     return true;
> +}
> +
>  static int
>  fstabscan()
>  {
> @@ -101,9 +236,19 @@
>               ++LineNo;
>               if (*line == '#' || *line == '\n')
>                       continue;
> -             if (!strpbrk(p, " \t")) {
> +
> +             /* escapted white-spaces only are allowed in old-style format */
> +             cp = p;
> +             while ((cp = strpbrk(cp, " \t")) != 0 &&
> +                     cp != p && cp[-1] == '\\')
> +                     ++cp;
> +             if (cp == 0) {
>                       _fs_fstab.fs_spec = strsep(&p, ":\n");
> +                     if (!remove_escapes (&_fs_fstab.fs_spec, " \t"))
> +                         goto bad;
>                       _fs_fstab.fs_file = strsep(&p, ":\n");
> +                     if (!remove_escapes (&_fs_fstab.fs_file, " \t"))
> +                         goto bad;
>                       fixfsfile();
>                       _fs_fstab.fs_type = strsep(&p, ":\n");
>                       if (_fs_fstab.fs_type) {
> @@ -124,13 +269,15 @@
>                       goto bad;
>               }
>  /* OLD_STYLE_FSTAB */
> -             while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
> +             while ((cp = es_strsep(&p, " \t\n")) != NULL && *cp == '\0')
>                       ;
>               _fs_fstab.fs_spec = cp;
>               if (!_fs_fstab.fs_spec || *_fs_fstab.fs_spec == '#')
>                       continue;
> -             while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
> +             while ((cp = es_strsep(&p, " \t\n")) != NULL && *cp == '\0')
>                       ;
> +             if (cp == 0)
> +                     goto bad;
>               _fs_fstab.fs_file = cp;
>               fixfsfile();
>               while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')



_______________________________________________
[EMAIL PROTECTED] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to