tts/str.c
2014-03-08 00:30:40 +00:00

135 lines
2.5 KiB
C

/*
* TTS - track your time.
* Copyright (c) 2012-2014 Felicity Tarnell.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely. This software is provided 'as-is', without any express or implied
* warranty.
*/
#include "str.h"
size_t
tokenise(str, res)
const wchar_t *str;
wchar_t ***res;
{
int ntoks = 0;
const wchar_t *p, *q;
wchar_t *r;
*res = NULL;
p = str;
for (;;) {
ptrdiff_t sz;
int qskip = 0;
int isbsl = 0;
/* Skip leading whitespace */
while (iswspace(*p))
p++;
/* End of string - no more arguments */
if (!*p)
break;
q = p;
if (*q == '"') {
/* Quoted string - scan for end of string */
p++;
while (*++q) {
/* Handle escaping with backslash; currently works but the \ isn't
* removed from the string.
*/
if (!isbsl && (*q == '\\')) {
isbsl = 1;
continue;
}
if (!isbsl && (*q == '"'))
break;
isbsl = 0;
}
/* At this point, *q == '"'. If it's NUL instead, then the
* string was not terminated with a closing '"' before the end
* of the line. We could give an error here, but it seems
* more useful to just accept it.
*/
if (*q == '"')
qskip = 1;
} else {
/* Not quoted - just find the next whitespace */
while (!iswspace(*q) && *q)
q++;
}
/* Copy the argument (which is sz bytes long) into the result array */
sz = (q - p);
*res = realloc(*res, sizeof(wchar_t *) * (ntoks + 1));
(*res)[ntoks] = malloc(sizeof(wchar_t) * (sz + 1));
wmemcpy((*res)[ntoks], p, sz);
/* Handle \ escapes */
for (r = (*res)[ntoks]; r < ((*res)[ntoks] + sz);) {
if (!isbsl) {
if (*r == '\\') {
wmemmove(r, r + 1, sz - (r - (*res)[ntoks]));
sz--;
isbsl = 1;
continue;
}
r++;
continue;
}
switch (*r) {
case 't': *r = '\t'; break;
case 'n': *r = '\n'; break;
case 'r': *r = '\r'; break;
case 'v': *r = '\v'; break;
case '\\': *r = '\\'; break;
}
isbsl = 0;
r++;
}
(*res)[ntoks][sz] = 0;
ntoks++;
if (qskip)
q += qskip;
while (iswspace(*q))
q++;
/*
* q is the start of the next token (with leading whitespace); reset
* p to process the next argument.
*/
if (!*q)
break;
p = q;
}
*res = realloc(*res, sizeof(wchar_t *) * (ntoks + 1));
(*res)[ntoks] = NULL;
return ntoks;
}
void
tokfree(vec)
wchar_t ***vec;
{
wchar_t **p;
for (p = (*vec); *p; p++)
free(*p);
free(*vec);
}