cstring.cpp

来自「Shorthand是一个强大的脚本语言」· C++ 代码 · 共 929 行 · 第 1/2 页

CPP
929
字号
/////////////////////////////////////////////////////////////////////////////
// $Header: /shorthand/src/cstring.cpp 8     2/14/03 4:20a Arm $
//---------------------------------------------------------------------------
// This file is part of "libAndrix" library - a collection of classes
// and functions developed by Andrei Remenchuk.
//---------------------------------------------------------------------------
// While you may own complete copyright on the project with which you have
// received this file, the author reserves the right to use code contained
// in this very file for any purposes, including publishing and usage in
// any free or commercial software.
//
// You may re-distribute this file or re-use it in your own free or
// commercial software provided that this text is included in the file.
// If you change this file you must include clear notice stating that
// you changed this file and the date of change.
//
// This statement doesn't apply to other files that are part of the same
// package unless otherwise noted.
//---------------------------------------------------------------------------
// (c) 1998-2002 Andrei Remenchuk <andrei@remenchuk.com>
//---------------------------------------------------------------------------
// cstring.cpp - string class implementation
/////////////////////////////////////////////////////////////////////////////
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <ctype.h>

#ifdef WIN32
#include <io.h>
#else
#include <iostream.h>
#include <unistd.h>
#include <errno.h>
#endif


#include "cstring.h"
#include "except.h"
#include "utils.h"

#pragma hdrstop

void string::ctor()
{
    m_capacity = 0;
    m_increment = 64;
    m_length = 0;
    m_buffer = 0;
}


string::string()
{
    ctor();
    m_capacity = 24;
    m_buffer = (char*) malloc(m_capacity);
    m_buffer[0] = '\0';
}

string::string(const char* s, int length)
{
    ctor();
    if (s == NULL) s = "";
    if (length == -1) length = strlen(s);
    m_length = length;
    ensure_capacity(length+1);
    memcpy(m_buffer, s, length);
    m_buffer[length] = '\0'; 
}

string::string(const string& s)
{
    ctor();
    m_length = s.length();
    ensure_capacity(m_length+1);
    memcpy(m_buffer, s.m_buffer, m_length+1);
}

string* string::clone() const
{
    return new string(*this);
}


void string::ensure_capacity(int n)
{
    if (n > m_capacity)
    {
        if (m_increment == 0) m_increment = 64;
        m_capacity = (n/m_increment+1)*m_increment;
        if (m_buffer == NULL) m_buffer = (char*) malloc(m_capacity);
        else m_buffer = (char*) realloc(m_buffer, m_capacity);
    }
}

char* string::provide_window(int length)
{
    ensure_capacity(length + 1);
    return m_buffer;
}


// truncates string length (if within range)
int string::set_length(int n)
{
    if (n >= 0 && n < m_length)
    {
        m_buffer[n] = '\0'; 
        m_length = n;
    }
    return m_length;
}


void string::printf(const char* format, ...)
{
    va_list args; va_start(args, format);
    int w = vawidth(format, &args);
    ensure_capacity(w+1);
    ::vsprintf(m_buffer, format, args);
    m_length = strlen(m_buffer);
}


void string::vprintf(const char* format, va_list args)
{
    int w = vawidth(format, &args);
    ensure_capacity(w+1);
    ::vsprintf(m_buffer, format, args);
    m_length = strlen(m_buffer);
}


void string::append(const char* s, int length)
{
    if (length == -1) length = strlen(s);
    int n = m_length + length;
    ensure_capacity(n+1);
    memcpy(m_buffer + m_length, s, length);
    m_buffer[m_length + length] = '\0';
    m_length += length;
}

void string::append(char ch)
{
    ensure_capacity(m_length + 2);
    m_buffer[m_length] = ch;
    m_buffer[m_length+1] = '\0';
    m_length++;
}


// formats text and appends it to this string
void string::appendf(const char* format, ...)
{
    string text; 
    va_list args; va_start(args, format);
    text.vprintf(format, args);
    append(text.m_buffer, text.m_length);
}


void string::clear()
{
    m_length = 0;
    m_buffer[0] = '\0';
}


const string& string::operator = (const char* s)
{
    if (s == NULL) s = "";
    m_length = strlen(s);
    ensure_capacity(m_length+1);
    memcpy(m_buffer, s, m_length+1);
    return *this;
}

const string& string::operator = (const string& s)
{
    m_length = s.m_length;
    ensure_capacity(m_length+1);
    memcpy(m_buffer, s.m_buffer, m_length+1);
    return *this;
}


void string::set(const char *s, int length)
{
    if (s == NULL) s = "";
    if (length == -1) length = strlen(s);
    ensure_capacity(length+1);
    memcpy(m_buffer, s, length);
    m_buffer[length] = '\0';
    m_length = length;
}


// pastes a piece of another string 
void string::paste(const char* s, int start, int end)
{
    set(s+start, end-start);
}


const char* string::nv() const
{
    if (m_length == 0) return NULL;
    else return m_buffer;
}




static char* hexs = "0123456789ABCDEF";

static int hex2c(char ch)
{
    const char* p = strchr(hexs, toupper(ch));
    if (p == NULL) return -1;
    else return p - hexs;
}

void string::urldecode(string& target) const
{
    target.clear();
    for(int i=0,n=m_length; i<n; i++)
    {
        char ch = m_buffer[i];
        if (ch == '%') {
            if (i + 2 < m_length)
            {
                unsigned int hi = hex2c(m_buffer[i+1])&0xf; 
                unsigned int lo = hex2c(m_buffer[i+2])&0xf;
                if (hi >= 0 && lo >= 0)
                {
                    target.append((unsigned char)((hi<<4) | lo));
                }
            }
            i += 2;
        } else if (ch == '+') {
            target.append(' '   );
        } else {
            target.append(ch);
        }
    }
}

void string::urlencode(const char* source, string& target)
{
    target.clear();
    const char* p = source;
    while(*p)
    {
        char ch = *p++;
        if (ch == ' ') 
        {
            target.append('+');
        }
        else if (isalnum(ch) || strchr("._,", ch) != NULL)
        {
            target.append(ch);
        }
        else 
        {
            target.appendf("%%%02x", ch&0xff);
        }
    }
}

void string::urlencode(string& target) const
{
    urlencode(m_buffer, target);
}


void string::rtrim()
{
    for(int i=m_length-1; i>=0; i--)
    {
        if (isspace(m_buffer[i]))
        {
            m_buffer[i] = '\0';
            m_length--;
        }
        else 
            break;
    }
}

// removes all leading whitespace characters 
void string::ltrim()
{
    int i=0;
    while(i<m_length && isspace(m_buffer[i])) i++;
    if (i == m_length) clear();
    else if (i > 0) 
    {
        memmove(m_buffer, m_buffer+i, m_length-i+1);
        m_length -= i;
    }
}

void string::trim()
{
    rtrim();
    ltrim();
}


// converts string to lowercase
void string::lowercase()
{
    for(int i=0,n=m_length; i<n; i++)
        m_buffer[i] = tolower(m_buffer[i]);
}

// converts string to lowercase
void string::uppercase()
{
    for(int i=0,n=m_length; i<n; i++)
        m_buffer[i] = toupper(m_buffer[i]);
}



bool string::ieq(const char* s) const
{
    return stricmp(m_buffer, s) == 0;
}

bool string::operator == (const char* s) const
{
    return strcmp(m_buffer, s) == 0;
}

bool string::operator != (const char* s) const
{
    return strcmp(m_buffer, s) != 0;
}


string::~string()
{
    if (m_buffer != NULL) free(m_buffer);
}


const char* string::set_from_quoted(const char* s, char stopchar, bool stop_on_space)
{
    clear();
    const char* src = s;

    bool quoted = (*src == '"');
    if (quoted)
    {
        src++;
        while(*src && *src != '"' && *src != stopchar) 
        {
            char c = *src;
            if (c == '\\') 
            {
                src++;
                c = *src;
                switch(c)
                {
                case 'n': c = '\n'; break;
                case 'r': c = '\r'; break;
                case 't': c = '\t'; break;
                }
            }
            append(c);
            src++;
        }
        if (*src == '"') src++;
        return src;
    }
    else if (stop_on_space)
    {
        const char* field_start = src;
        while(*src && !isspace(*src) && *src != stopchar) src++;
        set(field_start, src-field_start);
        return src;
    }
    else 
    {
        const char* field_start = src;
        while(*src && *src != stopchar) src++;
        set(field_start, src-field_start);
        return src;
    }
}

// removes last character
const char* string::chop()
{
    if (m_length > 0) m_buffer[--m_length] = '\0';
    return m_buffer;
}

// removes last character if it is one of specified characters
const char* string::chop(const char* pat)
{
    while (m_length > 1 && strchr(pat, m_buffer[m_length-1])) 
    {
        m_buffer[--m_length] = '\0';
    }
    return m_buffer;
}


int string::split(string_array& list)
{
    return split(m_buffer, list);
}

int string::split(const char* s, array<string, true>& list)
{
    return split(s, list, NULL);
}


int string::split(const char* s, array<string, true>& list, const char* separators)
{
    int count = 0;
    list.clear();

    const char* src = s;
    while(*src)
    {
        while(*src && (separators == NULL && isspace(*src) || separators != NULL && strchr(separators, *src) != NULL))
            src++;
        if (*src == '\0') break;
        string* s = new string();
        src = s->set_from_quoted(src, '\0', true);
        list.add(s);
        count++;
    }

    return count;
}

int string::split(const char* pattern, ...)
{
    va_list ap; va_start(ap, pattern);
    return split(m_buffer, pattern, ap);
}

int string::split(const char* s, const char* pattern, ...)
{
    va_list ap; va_start(ap, pattern);
    return split(s, pattern, ap);
}


/**
 * Divides text string into numeric and/or string fields according to the specified 
 * pattern.
 *
 * pattern consists of one or more following characters:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?