/* This file is part of Ping903 Copyright (C) 2020 Sergey Poznyakoff Ping903 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, or (at your option) any later version. Ping903 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 Ping903. If not, see . */ #include #include #include #include "defs.h" void argcv_free(int ac, char **av) { int i; for (i = 0; i < ac; i++) free(av[i]); free(av); } int strsplit(char const *str, int max, int *ret_ac, char ***ret_av, char **endp) { char **av = NULL; int ac; char const *p; enum { Stop, Error, Inspace, Inquote, Inword } state; av = calloc(max+1, sizeof(*av)); if (!av) return STRSPLIT_NOMEM; ac = 0; #define ISWS(c) ((c)==' '||(c)=='\t') #define UNESCAPE(p) ((p)[0] == '\\' && ((p)[1] == '\\' || (p)[1] == '"')) if (ISWS(*str)) state = Inspace; else if (*str == '"') { state = Inquote; str++; } else state = Inword; p = str; while (state != Stop && state != Error) { switch (state) { case Inquote: if (*p == 0) { p = str; state = Error; } else if (UNESCAPE(p)) p += 2; else if (*p == '"') { char *q; size_t len = p - str; av[ac] = malloc(len + 1); if (!av[ac]) goto err; q = av[ac]; while (str < p) { if (UNESCAPE(str)) str++; *q++ = *str++; } *q = 0; ac++; str++; p = str; if (*p == 0) state = Stop; else if (ISWS(*str)) state = Inspace; else state = Error; } else p++; break; case Inword: if (*p == 0 || ISWS(*p)) { size_t len = p - str; av[ac] = malloc(len + 1); if (!av[ac]) goto err; memcpy(av[ac], str, len); av[ac][len] = 0; ac++; state = *p ? Inspace : Stop; } else p++; break; case Inspace: if (*p == 0) { state = Stop; break; } else if (*p == '"') { state = Inquote; p++; str = p; } else if (!ISWS(*p)) { state = Inword; str = p; } else p++; if (ac == max && state != Inspace) { state = Stop; } break; default: abort(); } } av[ac] = NULL; *ret_av = av; *ret_ac = ac; *endp = (char*) p; return state == Stop ? STRSPLIT_OK : STRSPLIT_ERR; err: argcv_free(ac, av); return STRSPLIT_NOMEM; }