458 lines
11 KiB
C
458 lines
11 KiB
C
/****************************************************************************
|
|
* apps/interpreters/bas/bas_str.c
|
|
* Dynamic strings.
|
|
*
|
|
* Copyright (c) 1999-2014 Michael Haardt
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Adapted to NuttX and re-released under a 3-clause BSD license:
|
|
*
|
|
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
|
* Authors: Alan Carvalho de Assis <Alan Carvalho de Assis>
|
|
* Gregory Nutt <gnutt@nuttx.org>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "bas_str.h"
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
int cistrcmp(const char *s, const char *r)
|
|
{
|
|
assert(s != (char *)0);
|
|
assert(r != (char *)0);
|
|
while (*s && tolower(*s) == tolower(*r))
|
|
{
|
|
++s;
|
|
++r;
|
|
}
|
|
|
|
return ((tolower(*s) - tolower(*r)));
|
|
}
|
|
|
|
struct String *String_new(struct String *this)
|
|
{
|
|
assert(this != (struct String *)0);
|
|
this->length = 0;
|
|
this->character = (char *)0;
|
|
this->field = (struct StringField *)0;
|
|
return this;
|
|
}
|
|
|
|
void String_destroy(struct String *this)
|
|
{
|
|
assert(this != (struct String *)0);
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
if (this->length)
|
|
{
|
|
free(this->character);
|
|
}
|
|
}
|
|
|
|
int String_joinField(struct String *this, struct StringField *field,
|
|
char *character, size_t length)
|
|
{
|
|
struct String **n;
|
|
|
|
assert(this != (struct String *)0);
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
this->field = field;
|
|
if ((n =
|
|
(struct String **)realloc(field->refStrings,
|
|
sizeof(struct String *) * (field->refCount +
|
|
1))) ==
|
|
(struct String **)0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
field->refStrings = n;
|
|
field->refStrings[field->refCount] = this;
|
|
++field->refCount;
|
|
if (this->length)
|
|
{
|
|
free(this->character);
|
|
}
|
|
|
|
this->character = character;
|
|
this->length = length;
|
|
return 0;
|
|
}
|
|
|
|
void String_leaveField(struct String *this)
|
|
{
|
|
struct StringField *field;
|
|
int i;
|
|
struct String **ref;
|
|
|
|
assert(this != (struct String *)0);
|
|
field = this->field;
|
|
assert(field != (struct StringField *)0);
|
|
for (i = 0, ref = field->refStrings; i < field->refCount; ++i, ++ref)
|
|
{
|
|
if (*ref == this)
|
|
{
|
|
int further = --field->refCount - i;
|
|
|
|
if (further)
|
|
{
|
|
memmove(ref, ref + 1, further * sizeof(struct String **));
|
|
}
|
|
|
|
this->character = (char *)0;
|
|
this->length = 0;
|
|
this->field = (struct StringField *)0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
assert(0);
|
|
}
|
|
|
|
struct String *String_clone(struct String *this, const struct String *original)
|
|
{
|
|
assert(this != (struct String *)0);
|
|
String_new(this);
|
|
String_appendString(this, original);
|
|
return this;
|
|
}
|
|
|
|
int String_size(struct String *this, size_t length)
|
|
{
|
|
char *n;
|
|
|
|
assert(this != (struct String *)0);
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
if (length)
|
|
{
|
|
if (length > this->length)
|
|
{
|
|
if ((n = realloc(this->character, length + 1)) == (char *)0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
this->character = n;
|
|
}
|
|
|
|
this->character[length] = '\0';
|
|
}
|
|
else
|
|
{
|
|
if (this->length)
|
|
{
|
|
free(this->character);
|
|
}
|
|
|
|
this->character = (char *)0;
|
|
}
|
|
|
|
this->length = length;
|
|
return 0;
|
|
}
|
|
|
|
int String_appendString(struct String *this, const struct String *app)
|
|
{
|
|
size_t oldlength = this->length;
|
|
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
if (app->length == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (String_size(this, this->length + app->length) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
memcpy(this->character + oldlength, app->character, app->length);
|
|
return 0;
|
|
}
|
|
|
|
int String_appendChar(struct String *this, char ch)
|
|
{
|
|
size_t oldlength = this->length;
|
|
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
if (String_size(this, this->length + 1) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
this->character[oldlength] = ch;
|
|
return 0;
|
|
}
|
|
|
|
int String_appendChars(struct String *this, const char *ch)
|
|
{
|
|
size_t oldlength = this->length;
|
|
size_t chlen = strlen(ch);
|
|
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
if (String_size(this, this->length + chlen) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
memcpy(this->character + oldlength, ch, chlen);
|
|
return 0;
|
|
}
|
|
|
|
int String_appendPrintf(struct String *this, const char *fmt, ...)
|
|
{
|
|
char buf[1024];
|
|
size_t l, j;
|
|
va_list ap;
|
|
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
va_start(ap, fmt);
|
|
l = vsprintf(buf, fmt, ap);
|
|
va_end(ap);
|
|
j = this->length;
|
|
if (String_size(this, j + l) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
memcpy(this->character + j, buf, l);
|
|
return 0;
|
|
}
|
|
|
|
int String_insertChar(struct String *this, size_t where, char ch)
|
|
{
|
|
size_t oldlength = this->length;
|
|
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
assert(where < oldlength);
|
|
if (String_size(this, this->length + 1) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
memmove(this->character + where + 1, this->character + where,
|
|
oldlength - where);
|
|
this->character[where] = ch;
|
|
return 0;
|
|
}
|
|
|
|
int String_delete(struct String *this, size_t where, size_t len)
|
|
{
|
|
size_t oldlength = this->length;
|
|
|
|
if (this->field)
|
|
{
|
|
String_leaveField(this);
|
|
}
|
|
|
|
assert(where < oldlength);
|
|
assert(len > 0);
|
|
if ((where + len) < oldlength)
|
|
{
|
|
memmove(this->character + where, this->character + where + len,
|
|
oldlength - where - len);
|
|
}
|
|
|
|
this->character[this->length -= len] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
void String_ucase(struct String *this)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < this->length; ++i)
|
|
{
|
|
this->character[i] = toupper(this->character[i]);
|
|
}
|
|
}
|
|
|
|
void String_lcase(struct String *this)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < this->length; ++i)
|
|
{
|
|
this->character[i] = tolower(this->character[i]);
|
|
}
|
|
}
|
|
|
|
int String_cmp(const struct String *this, const struct String *s)
|
|
{
|
|
size_t pos;
|
|
int res;
|
|
const char *thisch, *sch;
|
|
|
|
for (pos = 0, thisch = this->character, sch = s->character;
|
|
pos < this->length && pos < s->length; ++pos, ++thisch, ++sch)
|
|
{
|
|
if ((res = (*thisch - *sch)))
|
|
{
|
|
return res;
|
|
}
|
|
}
|
|
|
|
return (this->length - s->length);
|
|
}
|
|
|
|
void String_lset(struct String *this, const struct String *s)
|
|
{
|
|
size_t copy;
|
|
|
|
copy = (this->length < s->length ? this->length : s->length);
|
|
if (copy)
|
|
{
|
|
memcpy(this->character, s->character, copy);
|
|
}
|
|
|
|
if (copy < this->length)
|
|
{
|
|
memset(this->character + copy, ' ', this->length - copy);
|
|
}
|
|
}
|
|
|
|
void String_rset(struct String *this, const struct String *s)
|
|
{
|
|
size_t copy;
|
|
|
|
copy = (this->length < s->length ? this->length : s->length);
|
|
if (copy)
|
|
{
|
|
memcpy(this->character + this->length - copy, s->character, copy);
|
|
}
|
|
|
|
if (copy < this->length)
|
|
{
|
|
memset(this->character, ' ', this->length - copy);
|
|
}
|
|
}
|
|
|
|
void String_set(struct String *this, size_t pos, const struct String *s,
|
|
size_t length)
|
|
{
|
|
if (this->length >= pos)
|
|
{
|
|
if (this->length < (pos + length))
|
|
{
|
|
length = this->length - pos;
|
|
}
|
|
|
|
if (length)
|
|
{
|
|
memcpy(this->character + pos, s->character, length);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct StringField *StringField_new(struct StringField *this)
|
|
{
|
|
this->refStrings = (struct String **)0;
|
|
this->refCount = 0;
|
|
return this;
|
|
}
|
|
|
|
void StringField_destroy(struct StringField *this)
|
|
{
|
|
int i;
|
|
|
|
for (i = this->refCount; i > 0;)
|
|
{
|
|
String_leaveField(this->refStrings[--i]);
|
|
}
|
|
|
|
this->refCount = -1;
|
|
free(this->refStrings);
|
|
}
|