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 + -
显示快捷键?