/* * 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; }