lpmoo-1.2/etc/
lpmoo-1.2/mudlib/
lpmoo-1.2/mudlib/etc/
lpmoo-1.2/mudlib/include/
lpmoo-1.2/mudlib/include/moo/
lpmoo-1.2/mudlib/lpc/
lpmoo-1.2/mudlib/std/auto/
lpmoo-1.2/mudlib/std/bfuns/
/*
 * 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;
}