cstring.cpp

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

CPP
929
字号
 * 's' - string is expected (argument must be string*)
 * 'S' - read everything until the end of line or whitespace into string* argument
 * 'i' - integer is expected (argument must be int*)
 * '=' - '=' is expected (no argument is needed).
 * ':' - semicolon is expected (no argument is needed).
 * ',' - comma is expected (no argument is needed).
 * '.' - dot is expected (no argument is needed).
 *
 * parsing is stopped when all fields have been read or when it is impossible
 * to obtain value of next field.
 *
 * parameters:
 *    s [IN] string to parse
 *    pattern [IN] parse pattern
 *    additional arguments correspond to pattern symbols
 *
 * return value:
 *    number of fields actually read, including punctuation.
 * 
 */
int string::split(const char* s, const char* pattern, va_list ap)
{
    const char* p = pattern; char picture;
    const char* src = s;
    int count = 0;

    while((picture = *p++) != '\0')
    {
        while(*src && isspace(*src)) src++;
        if (*src == '\0') break;
        
        const char* field_start = src;

        char nextpic = *p;
        if (isalpha(nextpic)) nextpic = '\0';

        if (picture == 's')  // string
        {
            string* field = va_arg(ap, string*);
            src = field->set_from_quoted(src, nextpic, true);
            count++;

        }
        else if (picture == 'S')
        {
            string* field = va_arg(ap, string*);
            src = field->set_from_quoted(field_start, nextpic, false);
            field->rtrim();
            count++;
        }
        else if (picture == '*')
        {
            string* field = va_arg(ap, string*);
            field->set(field_start);
            field->rtrim();
            src = field_start + strlen(field_start);
            count++;
        }
        else if (picture == 'i')
        {
            int* field = va_arg(ap, int*);
            string part;
            while(*src && !isspace(*src) && *src != nextpic) src++;
            part.set(field_start, src-field_start);
            *field = atoi(part);
            count++;
        }
        else if (strchr("=:;,|!/-", picture) != NULL)  
        {
            if (*src != picture) break;
            src++;
            count++;
        }
    }

    return count;
}


/**
 * iterates through all lines in the string.
 */
const char* string::next_line(void** position, bool skip_leading_spaces)
{
    char** pos = (char**) position;
    if (*pos == NULL) *pos = m_buffer;
    if (*pos < m_buffer || (*pos - m_buffer) >= m_length) return NULL;
    if (*pos == '\0') return NULL;
    
    char* line = *pos;
    char* eol = strchr(*pos, '\n');
    if (eol != NULL) {
        *eol = '\0';
        *pos = eol + 1;
    } else {
        *pos = *pos + strlen(*pos);
    }
    
    if (line != NULL && skip_leading_spaces)
    {
        while(*line && isspace(*line)) line++;
    }

    return line;
}

    
int string::save_to_file(const char* filename)
{
    int omode = O_WRONLY|O_CREAT|O_TRUNC;
#ifdef WIN32    
    omode |= O_BINARY;
#endif
    int fd = ::open(filename, omode, 0644);
    if (fd < 0) return errno;
    int n_write = ::write(fd, m_buffer, m_length);
    close(fd);
    if (n_write < m_length) { return -1; }
    return 0;
}


bool string::load_from_file(const char *filename) 
{
    int e;
    int flags = O_RDONLY;

#ifdef WIN32
    flags |= O_BINARY;
#endif

    int fd = ::open(filename, flags);
    if (fd < 0) 
        throw new ShhException(1094, "Cannot open file \"%s\": %s", filename, strerror(errno));

    struct stat stinfo;
    if (fstat(fd, &stinfo) != 0) 
    { 
        e = errno; close(fd); 
        throw new ShhException(1095, "Cannot determine size of file \"%s\": %s", filename, strerror(e));
    }
    int new_size = stinfo.st_size;
    ensure_capacity(new_size + 1);
    int n_read = read(fd, m_buffer, new_size); e = errno;
    close(fd);
    if (n_read < new_size)
        throw new ShhException(1096, "Read operation on file \"%s\" failed", filename);

    m_length = new_size;
    m_buffer[new_size] = '\0';
    
    return true;
}


// returns number pattern that matches this string;
// patterns are given as "pattern1\0pattern2\0\pattern3\0....\0\0"
int string::index(const char* pattern, int default_index, bool case_sensitive)
{
    int i = 0;
    const char* p = pattern;
    while(true)
    {
        if (*p == '\0') break;
        const char* next = strend(p)+1;
        if (case_sensitive)
        {
            if (strcmp(m_buffer, p) == 0) return i;
        }
        else
        {
            if (stricmp(m_buffer, p) == 0) return i;
        }
            
        p = next;
        i++;
    }
    return default_index;
}


// removes speficied prefix from the string (if it begins with it)
bool string::remove_prefix(const char* prefix, bool case_sensitive)
{
    int n = strlen(prefix);
    if (n > m_length) return false;
    int diff = case_sensitive ? 
        strncmp(m_buffer, prefix, n) : strnicmp(m_buffer, prefix, n);
    if (diff != 0) return false;
    if (n == m_length)
        clear();
    else
    {
        memmove(m_buffer, m_buffer + n, m_length - n + 1);
        m_length -= n;
    }
    return true;

}

// reports whether or not string string contains any of the 
// specified characters
bool string::haschars(const char* s, const char* chars)
{
    const char* ch = chars;
    while(*ch)
    {
        if (strchr(s, *ch) != NULL) return true;
        ch++;
    }
    return false;
}


// parses RFC-822 e-mail address 
bool string::parse_email(string& name, string& address)
{
    return parse_email(m_buffer, name, address);
}


// parses RFC-822 e-mail address 
bool string::parse_email(const char* spec, string& name, string& address)
{
    while(*spec && isspace(*spec)) spec++;
    name.clear();  address.clear();
    
    bool has_spaces = strchr(spec, ' ') != NULL;
    bool has_quotes = strchr(spec, '\"') != NULL;
    const char* address_ptr = spec;


    const char* lt = strrchr(spec, '<');
    if (lt != NULL)
    {
        address_ptr = name.set_from_quoted(spec, '<', false);
        name.rtrim();

    }
    else if (has_spaces)
    {
        address_ptr = name.set_from_quoted(spec, '<', true);
        name.rtrim();
    }

    while(*address_ptr && isspace(*address_ptr)) address_ptr ++;
    if (*address_ptr == '<') address_ptr++;
    while(*address_ptr && isspace(*address_ptr)) address_ptr ++;

    const char* gt = strrchr(address_ptr, '>');
    if (gt == NULL) gt = strend(address_ptr);

    address.set(address_ptr, gt - address_ptr);
    address.rtrim();

    return true;
}


bool string::begins_with(const char* s, bool case_sensitive) const
{
    if (case_sensitive)
        return strncmp(m_buffer, s, strlen(s)) == 0;
    else
        return strnicmp(m_buffer, s, strlen(s)) == 0;
}

bool string::ends_with(const char* s, bool case_sensitive) const
{
    int n = strlen(s);
    if (m_length < n) return false;
    char* ptr = m_buffer + (m_length - n);
    if (case_sensitive)
        return strncmp(ptr, s, strlen(s)) == 0;
    else
        return strnicmp(ptr, s, strlen(s)) == 0;

}

bool string::contains(const char* s, bool case_sensitive) const
{
    char first = tolower(s[0]);
    int length = strlen(s);
    if (length > m_length) return false;
    for(int i=0,n=m_length-length+1; i<n; i++)
    {
        if (tolower(m_buffer[i] == first))
        {
            int diff = case_sensitive ?
                strncmp(m_buffer + i, s, length) : strnicmp(m_buffer + i, s, length);
            if (diff == 0) return true;
        }
    }
    return false;
}

int string::translate(char ch1, char ch2)
{
    int count = 0;
    for(int i=0,n=m_length; i<n; i++)
    {
        if (m_buffer[i] == ch1) { m_buffer[i] = ch2; count++; }
    }
    return count;
}


/**
 * Reports length of the buffer necessary for printf-style format and arguments.
 */
int vawidth(const char* format, va_list* args) 
{
    register const char *p = format;
    int total_width = strlen (format) + 1;
    va_list ap;

    memcpy((void*)&ap, (void*)args, sizeof (va_list));

    while (*p != '\0')  
    {
        if (*p++ == '%') 
        {
            while (strchr ("-+ #0", *p)) ++p;
            if (*p == '*')  
            {
                ++p;
                total_width += abs (va_arg (ap, int));
            } 
            else
                total_width += strtoul (p, (char**)&p, 10);
            if (*p == '.') 
            {
                ++p;
                if (*p == '*') 
                {
                    ++p; total_width += abs (va_arg (ap, int));
                } 
                else
                    total_width += strtoul (p, (char**)&p, 10);
            }
            while (strchr ("hlL", *p))  ++p;
            total_width += 30;
            switch (*p) 
            {
            case 'd':  case 'i':  case 'o':
            case 'u':  case 'x':  case 'X':
            case 'c':
                (void) va_arg (ap, int);
                break;
            case 'f':  case 'e':  case 'E':
            case 'g':  case 'G':
                (void) va_arg (ap, double);
                break;
            case 's': {
                char* s = va_arg(ap, char*);
                total_width += strlen (s);
                }
                break;
            case 'p': case 'n':
                (void) va_arg (ap, char *);
                break;
            }
        }
    }
    return total_width;
}

char string::char_at(int index) const
{
    return (index >= 0 && index <= m_length) ? m_buffer[index] : '\0';
}

void string::set_at(int index, char ch)
{
    if (index >= 0 && index <= m_length) 
        m_buffer[index] = ch;
}


char string::last() const
{
    return (m_length > 0) ? m_buffer[m_length-1] : '\0';
}

char string::first() const
{
    return (m_length > 0) ? m_buffer[0] : '\0';
}


int string::strpos(char ch, int start_index) const
{
    if (m_length == 0) return -1;
    start_index = i_max(0, i_min(start_index, m_length));
    const char* match = strchr(m_buffer+start_index, ch);
    return match != NULL ? (match - m_buffer) : -1;
}

int string::strpos(const char* str, int start_index) const
{
    if (m_length == 0) return -1;
    start_index = i_max(0, i_min(start_index, m_length));
    const char* match = strstr(m_buffer+start_index, str);
    return match != NULL ? (match - m_buffer) : -1;
}

// replaces a range of characters within this string by another string
// return value is true if offset and length were valid
bool string::replace_range(int offset, int length, const char* replacement)
{
    if (offset > m_length || offset + length > m_length) return false;
    if (replacement == NULL) replacement = "";
    int re_length = strlen(replacement);
    int required_length = m_length + re_length - length;
    if (required_length > m_length)
        ensure_capacity(required_length+1);
    int after = offset + length;
    int delta = re_length - length;
    if (delta < 0)
    {
        memmove(m_buffer + offset + re_length, m_buffer + after, m_length - after + 1);
    }
    else if (delta > 0)
    {
        memmove(m_buffer + after + delta, m_buffer + after, m_length - after + 1);
    }
    memmove(m_buffer + offset, replacement, re_length);
    m_length += delta;
    return true;
}

// replaces every occurance of substring within this string
// return value is number of replacements actually performed
int string::replace_all(const char* pattern, const char* replacement)
{
    int re_count = 0;
    int pos;
    int off = 0;
    int pattern_length = strlen(pattern);
    int re_length = replacement ? strlen(replacement) : 0;
    while((pos = strpos(pattern, off)) != -1)
    {
        replace_range(pos, pattern_length, replacement);
        off += re_length;
        re_count++;
    }
    return re_count;
}

// replaces every occurance of the character by another character
int string::replace_char(char pattern, char replacement)
{
    int re_count = 0;
    for(int i=0,n=m_length; i<n; i++)
    {
        if (m_buffer[i] == pattern) 
        {
            m_buffer[i] = replacement;
            re_count++;
        }
    }
    return re_count;
}

⌨️ 快捷键说明

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