/*
* NAME: string.c
* DESCRIPTION: handy string functions
*/
# include "string.h"
/*
* NAME: space()
* DESCRIPTION: return a string of indicated length (default to " ")
*/
static varargs
string space(int len, string fill)
{
int m;
if (fill == 0)
fill = " ";
if (fill != " ")
{
fill = fill + fill;
fill = fill + fill;
fill = fill + fill;
}
else if ((len = (len > 0 ? len : -len)) <= 80)
return (" " +
" ")[.. len - 1];
else
fill = " " +
" ";
m = (len - 1) / strlen(fill);
while (m)
{
fill = fill + fill;
m = m / 2;
}
return (len > 0) ? fill[0 .. len - 1] :
fill[(m = strlen(fill)) + len .. m - 1];
}
/*
* NAME: strchr()
* DESCRIPTION: return first index of char in string, or -1
*/
static
int strchr(string str, int char)
{
int i, sz;
for (i = 0, sz = strlen(str); i < sz; ++i)
if (str[i] == char)
return i;
return -1;
}
/*
* NAME: strrchr()
* DESCRIPTION: return last index of char in string, or -1
*/
static
int strrchr(string str, int char)
{
int i;
for (i = strlen(str) - 1; i >= 0; --i)
if (str[i] == char)
return i;
return -1;
}
/*
* NAME: column_list()
* DESCRIPTION: return a string formatted with the given elements in columns
*/
static
varargs string column_list(string *items, int maxwidth, int pad)
{
int rows, cols; /* number of rows and columns in output */
int longest; /* length of the longest line */
int i, sz, len, j;
string *lines;
if (maxwidth == 0)
maxwidth = 79;
if (pad == 0)
pad = 2;
for (i = 0, sz = sizeof(items); i < sz; ++i)
if ((len = strlen(items[i])) > longest)
longest = len;
longest += pad;
cols = maxwidth / longest;
if (cols == 0)
cols = 1;
rows = sz / cols + (sz % cols ? 1 : 0);
lines = allocate(rows);
for (i = 0; i < rows; ++i) {
lines[i] = "";
for (j = 0; j < cols; ++j) {
int index;
index = i + rows * j;
if (index < sz)
lines[i] += (items[index] + SPACES)[0 .. longest - 1];
}
}
return implode(lines, "\n") + "\n";
}
/*
* NAME: toupper()
* DESCRIPTION: return a string in all uppercase
*/
static
string toupper(string str)
{
string map;
int i;
map =
"\000\001\002\003\004\005\006\007" +
"\010\011\012\013\014\015\016\017" +
"\020\021\022\023\024\025\026\027" +
"\030\031\032\033\034\035\036\037" +
"\040\041\042\043\044\045\046\047" +
"\050\051\052\053\054\055\056\057" +
"\060\061\062\063\064\065\066\067" +
"\070\071\072\073\074\075\076\077" +
"\100\101\102\103\104\105\106\107" +
"\110\111\112\113\114\115\116\117" +
"\120\121\122\123\124\125\126\127" +
"\130\131\132\133\134\135\136\137" +
"\140\101\102\103\104\105\106\107" +
"\110\111\112\113\114\115\116\117" +
"\120\121\122\123\124\125\126\127" +
"\130\131\132\173\174\175\176\177" +
"\200\201\202\203\204\205\206\207" +
"\210\211\212\213\214\215\216\217" +
"\220\221\222\223\224\225\226\227" +
"\230\231\232\233\234\235\236\237" +
"\240\241\242\243\244\245\246\247" +
"\250\251\252\253\254\255\256\257" +
"\260\261\262\263\264\265\266\267" +
"\270\271\272\273\274\275\276\277" +
"\300\301\302\303\304\305\306\307" +
"\310\311\312\313\314\315\316\317" +
"\320\321\322\323\324\325\326\327" +
"\330\331\332\333\334\335\336\337" +
"\340\341\342\343\344\345\346\347" +
"\350\351\352\353\354\355\356\357" +
"\360\361\362\363\364\365\366\367" +
"\370\371\372\373\374\375\376\377";
for (i = strlen(str); i--; )
str[i] = map[str[i]];
return str;
}
/*
* NAME: tolower()
* DESCRIPTION: return a string in all lowercase
*/
static
string tolower(string str)
{
string map;
int i;
map =
"\000\001\002\003\004\005\006\007" +
"\010\011\012\013\014\015\016\017" +
"\020\021\022\023\024\025\026\027" +
"\030\031\032\033\034\035\036\037" +
"\040\041\042\043\044\045\046\047" +
"\050\051\052\053\054\055\056\057" +
"\060\061\062\063\064\065\066\067" +
"\070\071\072\073\074\075\076\077" +
"\100\141\142\143\144\145\146\147" +
"\150\151\152\153\154\155\156\157" +
"\160\161\162\163\164\165\166\167" +
"\170\171\172\133\134\135\136\137" +
"\140\141\142\143\144\145\146\147" +
"\150\151\152\153\154\155\156\157" +
"\160\161\162\163\164\165\166\167" +
"\170\171\172\173\174\175\176\177" +
"\200\201\202\203\204\205\206\207" +
"\210\211\212\213\214\215\216\217" +
"\220\221\222\223\224\225\226\227" +
"\230\231\232\233\234\235\236\237" +
"\240\241\242\243\244\245\246\247" +
"\250\251\252\253\254\255\256\257" +
"\260\261\262\263\264\265\266\267" +
"\270\271\272\273\274\275\276\277" +
"\300\301\302\303\304\305\306\307" +
"\310\311\312\313\314\315\316\317" +
"\320\321\322\323\324\325\326\327" +
"\330\331\332\333\334\335\336\337" +
"\340\341\342\343\344\345\346\347" +
"\350\351\352\353\354\355\356\357" +
"\360\361\362\363\364\365\366\367" +
"\370\371\372\373\374\375\376\377";
for (i = strlen(str); i--; )
str[i] = map[str[i]];
return str;
}
/*
* NAME: subst()
* DESCRIPTION: substitute a substring with another string
*/
static
string subst(string str, int index, int len, string newsubst)
{
int last;
last = strlen(str) - 1;
if (last < 0 || index < 0 || index > last)
return str;
return (index > 0 ? str[.. index - 1] : "") + newsubst +
(index + len <= last ? str[index + len ..] : "");
}
/*
* NAME: strip_whitespace()
* DESCRIPTION: remove whitespace from the beginning and end of a string
*/
static
string strip_whitespace(string str)
{
int beg, end, sz;
sz = strlen(str);
beg = 0;
end = sz - 1;
while (beg < end &&
(str[beg] == ' ' || str[beg] == '\t' || str[beg] == '\n'))
++beg;
while (end >= beg &&
(str[end] == ' ' || str[end] == '\t' || str[end] == '\n'))
--end;
return (end < beg ? "" : str[beg .. end]);
}
/*
* NAME: escape_sscanf_str()
* DESCRIPTION: render an arbitrary string harmless as sscanf's 2nd argument
*/
static
string escape_sscanf_str(string str)
{
int i, sz;
/* double all %'s */
for (i = 0, sz = strlen(str); i < sz; ++i)
{
if (str[i] == '%')
{
str = subst(str, i, 1, "%%");
++i, ++sz;
}
}
return str;
}
/*
* NAME: leftstr()
* DESCRIPTION: return leftmost characters from a string
*/
static
string leftstr(string str, int many)
{ return (many > strlen(str)) ? str : ((many < 0) ? "" : str[.. many - 1]); }
/*
* NAME: rightstr()
* DESCRIPTION: return rightmost characters from a string
*/
static
string rightstr(string str, int many)
{
int sz;
sz = strlen(str);
return (many > sz) ? str : ((many < 0) ? "" : str[sz - many ..]);
}
/*
* NAME: midstr()
* DESCRIPTION: return characters from middle of a string
*/
static
string midstr(string str, int start, int many)
{
if (start < 0)
{
many += start;
start = 0;
}
if (start >= strlen(str) || many <= 0)
return "";
if (start + many > strlen(str))
many = strlen(str) - start;
return str[start .. start + many - 1];
}
/*
* NAME: escape_str()
* DESCRIPTION: insert backslash escapes into a string
*/
static
string escape_str(string str)
{
int i, sz, j, newsz;
string newstr;
mapping map;
string subst;
if (str == 0)
return 0;
map = ([ '\n' : "\\n",
'\t' : "\\t",
'\b' : "\\b",
'\r' : "\\r",
'\0' : "\\0",
'\"' : "\\\"",
'\\' : "\\\\",
]);
newstr = str;
newsz = sz = strlen(str);
for (i = 0, j = 0; i < sz; ++i, ++j)
if ((subst = map[str[i]]) != 0)
{
newstr = (j > 0 ? newstr[.. j - 1] : "") + subst +
(j < newsz++ - 1 ? newstr[j + 1 ..] : "");
++j;
}
return newstr;
}
/*
* NAME: unescape_str()
* DESCRIPTION: remove backslash escapes, substituting their real values
*/
static
string unescape_str(string str)
{
int i, sz, j, newsz;
string newstr;
mapping map;
int subst;
map = ([ "\\n" : '\n',
"\\t" : '\t',
"\\b" : '\b',
"\\r" : '\r',
"\\0" : '\0',
"\\\"" : '\"',
"\\\\" : '\\',
]);
newstr = str;
newsz = sz = strlen(str);
for (j = 0, i = 0; i < sz; ++i, ++j)
if (str[i] == '\\' && (i < sz - 1) &&
(subst = map[str[i .. i + 1]]) != 0)
{
newstr[j] = subst;
newstr = newstr[.. j] + (j < --newsz - 1 ? newstr[j + 2 ..] : "");
++i;
}
return newstr;
}