/* Copyright (c) 1993 Stephen F. White */
#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>
#include "config.h"
#include "cool.h"
#include "proto.h"
#include "sys_proto.h"
#include "servers.h"
String *
string_new(int len)
{
String *new;
int newlen = MAX(len, STRING_INIT_SIZE);
new = (String *) cool_malloc(sizeof(String) + newlen + 1);
new->mem = newlen;
new->len = 0;
new->ref = 1;
new->str = (char *) new + sizeof(String);
new->str[0] = '\0';
return new;
}
#ifndef INLINE
String *
string_dup(String *s)
{
s->ref++;
return s;
}
void
string_free(String *s)
{
s->ref--;
if (s->ref == 0) {
FREE(s);
}
}
#endif
/*
* string_cpy() - copy a char * into a String struct
*/
String *
string_cpy(const char *s)
{
String *new;
new = string_new(strlen(s));
new = string_cat(new, s);
return new;
}
String *
string_ncpy(const char *s, int len)
{
String *new;
new = string_new(len + 1);
strncpy(new->str, s, len);
new->len = len;
new->str[len] = '\0';
return new;
}
static String *
string_extend_to(String *str, int mem)
{
String *new;
if (!str) return 0;
if (mem <= str->mem) {
return str;
}
#ifdef STRING_DOUBLING
while (mem > str->mem) {
str->mem = (str->mem + sizeof(String)) * 2 - sizeof(String);
}
#else
str->mem = (mem / STRING_GROW_BY + 1) * STRING_GROW_BY;
#endif
new = string_new(str->mem);
strcpy(new->str, str->str);
new->len = strlen(new->str);
FREE(str);
return new;
}
String *
string_catc(String *str, char c)
{
if (!str) return 0;
if (str->len + 2 > str->mem) {
str = string_extend_to(str, str->len + 2);
}
str->str[str->len++] = c;
str->str[str->len] = '\0';
return str;
}
String *
string_cat(String *str, const char *s)
{
int len;
if (!str) return 0;
len = str->len + strlen(s);
if (len + 1 > str->mem) {
str = string_extend_to(str, len + 1);
}
strcat(str->str + str->len, s);
str->len = len;
return str;
}
String *
string_catnum(String *str, int num)
{
int len;
if (!str) return 0;
len = str->len + INT_SIZE;
if (len + 1 > str->mem) {
str = string_extend_to(str, len + 1);
}
sprintf(str->str + str->len, "%d", num);
str->len = strlen(str->str);
return str;
}
String *
string_catobj(String *str, Objid obj, int full)
{
const char *servername;
int len;
if (!str) return 0;
len = str->len + INT_SIZE + 2 +
(full ? strlen(servername = serv_id2name(obj.server)) : 0);
if (len + 1 > str->mem) {
str = string_extend_to(str, len + 1);
}
if (full) {
sprintf(str->str + str->len, "#%d@%s", obj.id, servername);
} else {
sprintf(str->str + str->len, "#%d", obj.id);
}
str->len = strlen(str->str);
return str;
}
String *
string_indent_cat(String *str, int indent, const char *s)
{
int len;
char *c;
if (!str) return 0;
len = str->len + indent + strlen(s);
if (len + 1 > str->mem) {
str = string_extend_to(str, len + 1);
}
c = str->str + str->len;
for (; indent; indent--) {
*c++ = ' ';
}
strcpy(c, s);
str->len = len;
return str;
}
String *
string_backslash(String *str, const char *s)
{
int len;
const char *t;
char *r;
if (!str) return 0;
/*
* calculate required length, including backslashes
* NOTE: CR-LF turns into \n, both of which are two chars, so no
* length adjustment is needed
*/
len = str->len;
for (t = s; *t; t++, len++) {
if (*t == '\\' || *t == '"' || *t == '\t') {
len++;
}
}
/*
* extend string, if we have to
*/
if (len + 1 > str->mem) {
str = string_extend_to(str, len + 1);
}
r = str->str + str->len; /* skip to end of string */
do {
switch(*s) {
case '\r':
s++; /* ignore \r; handle \n instead */
case '\n':
*r++ = '\\';
*r++ = 'n';
break;
case '\t':
*r++ = '\\';
*r++ = 't';
break;
case '"':
case '\\':
*r++ = '\\';
default:
*r++ = *s;
break;
}
} while(*s++);
str->len = len;
return str;
}
String *
string_pad(String *str, int padlen, char tok)
{
int len;
char *s;
if (!str) return 0;
len = str->len + padlen;
if (len + 1 > str->mem) {
str = string_extend_to(str, len + 1);
}
s = str->str + str->len;
while (padlen--) {
*s++ = tok;
}
*s = '\0';
str->len = len;
return str;
}
String *
string_prepad(String *str, int padlen, char tok)
{
int len;
char *s, *d;
if (!str) return 0;
len = str->len + padlen;
if (len + 1 > str->mem) {
str = string_extend_to(str, len + 1);
}
for (s = str->str + str->len, d = s + padlen; s >= str->str;) {
*d-- = *s--;
}
s = str->str;
while (padlen--) {
*s++ = tok;
}
str->len = len;
return str;
}
String *
string_strip_cr(String *str)
{
char *s1, *s2;
if (!str) return 0;
for (s1 = s2 = str->str; *s1; s1++) {
if (*s1 != '\r') {
*s2++ = *s1;
}
}
*s2 = '\0'; /* terminate it */
str->len = s2 - str->str;
return str;
} /* string_strip_cr() */