You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tellico/src/translators/pilotdb/strop.cpp

590 lines
16 KiB

/*
* palm-db-tools: Support Library: String Parsing Utility Functions
* Copyright (C) 1999-2000 by Tom Dyas (tdyas@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifh Floor, Boston, MA 02110-1301 USA
*/
#include <string>
#include <vector>
#include <algorithm>
#include <cctype>
#include <sstream>
#include "strop.h"
#include <kdebug.h>
extern std::ostream* err;
void StrOps::lower(std::string& str)
{
for (std::string::iterator p = str.begin(); p != str.end(); ++p) {
if (isupper(*p))
*p = tolower(*p);
}
}
bool StrOps::string2boolean(const std::string& str)
{
std::string value(str);
StrOps::lower(value);
if (value == "on") return true;
else if (str == "off") return false;
else if (str == "true") return true;
else if (str == "t") return true;
else if (str == "false") return false;
else if (str == "f") return false;
else {
int num = 0;
std::istringstream(str.c_str()) >> num;
return num != 0 ? true : false;
}
}
std::string StrOps::type2string(PalmLib::FlatFile::Field::FieldType t)
{
switch (t) {
case PalmLib::FlatFile::Field::STRING:
return "string";
case PalmLib::FlatFile::Field::BOOLEAN:
return "boolean";
case PalmLib::FlatFile::Field::INTEGER:
return "integer";
case PalmLib::FlatFile::Field::FLOAT:
return "float";
case PalmLib::FlatFile::Field::DATE:
return "date";
case PalmLib::FlatFile::Field::TIME:
return "time";
case PalmLib::FlatFile::Field::DATETIME:
return "datetime";
case PalmLib::FlatFile::Field::NOTE:
return "note";
case PalmLib::FlatFile::Field::LIST:
return "list";
case PalmLib::FlatFile::Field::LINK:
return "link";
case PalmLib::FlatFile::Field::CALCULATED:
return "calculated";
case PalmLib::FlatFile::Field::LINKED:
return "linked";
default:
// If we don't support the field type, then fake it as a string.
return "string";
}
}
PalmLib::FlatFile::Field::FieldType StrOps::string2type(std::string typestr)
{
StrOps::lower(typestr);
if (typestr == "string")
return PalmLib::FlatFile::Field::STRING;
else if (typestr == "str")
return PalmLib::FlatFile::Field::STRING;
else if (typestr == "note")
return PalmLib::FlatFile::Field::NOTE;
else if (typestr == "bool")
return PalmLib::FlatFile::Field::BOOLEAN;
else if (typestr == "boolean")
return PalmLib::FlatFile::Field::BOOLEAN;
else if (typestr == "integer")
return PalmLib::FlatFile::Field::INTEGER;
else if (typestr == "int")
return PalmLib::FlatFile::Field::INTEGER;
else if (typestr == "float")
return PalmLib::FlatFile::Field::FLOAT;
else if (typestr == "date")
return PalmLib::FlatFile::Field::DATE;
else if (typestr == "time")
return PalmLib::FlatFile::Field::TIME;
else if (typestr == "datetime")
return PalmLib::FlatFile::Field::DATETIME;
else if (typestr == "list")
return PalmLib::FlatFile::Field::LIST;
else if (typestr == "link")
return PalmLib::FlatFile::Field::LINK;
else if (typestr == "linked")
return PalmLib::FlatFile::Field::LINKED;
else if (typestr == "calculated")
return PalmLib::FlatFile::Field::CALCULATED;
else
kdDebug() << "unknown field type" << endl;
return PalmLib::FlatFile::Field::STRING;
}
std::string StrOps::strip_back(const std::string& str, const std::string& what)
{
std::string result(str);
std::string::reverse_iterator p = result.rbegin();
while (p != result.rend()
&& (std::find(what.begin(), what.end(), *p) != what.end())) ++p;
result.erase(p.base(), result.end());
return result;
}
std::string StrOps::strip_front(const std::string& str,const std::string& what)
{
std::string result(str);
std::string::iterator p = result.begin();
while (p != result.end()
&& (std::find(what.begin(), what.end(), *p) != what.end())) ++p;
result.erase(result.begin(), p);
return result;
}
StrOps::string_list_t StrOps::csv_to_array(const std::string& str, char delim, bool quoted_string)
{
enum { STATE_NORMAL, STATE_QUOTES } state;
StrOps::string_list_t result;
std::string elem;
state = STATE_NORMAL;
for (std::string::const_iterator p = str.begin(); p != str.end(); ++p) {
switch (state) {
case STATE_NORMAL:
if (quoted_string && *p == '"') {
state = STATE_QUOTES;
} else if (*p == delim) {
result.push_back(elem);
elem = "";
} else {
elem += *p;
}
break;
case STATE_QUOTES:
if (quoted_string && *p == '"') {
if ((p + 1) != str.end() && *(p+1) == '"') {
++p;
elem += '"';
} else {
state = STATE_NORMAL;
}
} else {
elem += *p;
}
break;
}
}
switch (state) {
case STATE_NORMAL:
result.push_back(elem);
break;
case STATE_QUOTES:
kdDebug() << "unterminated quotes" << endl;
break;
}
return result;
}
StrOps::string_list_t
StrOps::str_to_array(const std::string& str, const std::string& delim,
bool multiple_delim, bool handle_comments)
{
enum { STATE_NORMAL, STATE_COMMENT, STATE_QUOTE_DOUBLE, STATE_QUOTE_SINGLE,
STATE_BACKSLASH, STATE_BACKSLASH_DOUBLEQUOTE } state;
StrOps::string_list_t result;
std::string elem;
state = STATE_NORMAL;
for (std::string::const_iterator p = str.begin(); p != str.end(); ++p) {
switch (state) {
case STATE_NORMAL:
if (*p == '"') {
state = STATE_QUOTE_DOUBLE;
} else if (*p == '\'') {
state = STATE_QUOTE_SINGLE;
} else if (std::find(delim.begin(), delim.end(), *p) != delim.end()) {
if (multiple_delim) {
++p;
while (p != str.end()
&& std::find(delim.begin(), delim.end(), *p) != delim.end()) {
++p;
}
--p;
}
result.push_back(elem);
elem = "";
} else if (*p == '\\') {
state = STATE_BACKSLASH;
} else if (handle_comments && *p == '#') {
state = STATE_COMMENT;
} else {
elem += *p;
}
break;
case STATE_COMMENT:
break;
case STATE_QUOTE_DOUBLE:
if (*p == '"')
state = STATE_NORMAL;
else if (*p == '\\')
state = STATE_BACKSLASH_DOUBLEQUOTE;
else
elem += *p;
break;
case STATE_QUOTE_SINGLE:
if (*p == '\'')
state = STATE_NORMAL;
else
elem += *p;
break;
case STATE_BACKSLASH:
elem += *p;
state = STATE_NORMAL;
break;
case STATE_BACKSLASH_DOUBLEQUOTE:
switch (*p) {
case '\\':
elem += '\\';
break;
case 'n':
elem += '\n';
break;
case 'r':
elem += '\r';
break;
case 't':
elem += '\t';
break;
case 'v':
elem += '\v';
break;
case '"':
elem += '"';
break;
case 'x':
{
char buf[3];
// Extract and check the first hexadecimal character.
if ((p + 1) == str.end())
kdDebug() << "truncated escape" << endl;
if (! isxdigit(*(p + 1)))
kdDebug() << "invalid hex character" << endl;
buf[0] = *++p;
// Extract and check the second (if any) hex character.
if ((p + 1) != str.end() && isxdigit(*(p + 1))) {
buf[1] = *++p;
buf[2] = '\0';
} else {
buf[1] = buf[2] = '\0';
}
std::istringstream stream(buf);
stream.setf(std::ios::hex, std::ios::basefield);
unsigned value;
stream >> value;
elem += static_cast<char> (value & 0xFFu);
}
break;
}
// Escape is done. Go back to the normal double quote state.
state = STATE_QUOTE_DOUBLE;
break;
}
}
switch (state) {
case STATE_NORMAL:
result.push_back(elem);
break;
case STATE_QUOTE_DOUBLE:
kdDebug() << "unterminated double quotes" << endl;
break;
case STATE_QUOTE_SINGLE:
kdDebug() << "unterminated single quotes" << endl;
break;
case STATE_BACKSLASH:
case STATE_BACKSLASH_DOUBLEQUOTE:
kdDebug() << "an escape character must follow a backslash" << endl;
break;
default:
break;
}
return result;
}
PalmLib::pi_uint32_t
StrOps::get_current_time(void)
{
time_t now;
time(&now);
return static_cast<PalmLib::pi_uint32_t> (now) + PalmLib::pi_uint32_t(2082844800);
}
char *
StrOps::strptime(const char *s, const char *format, struct tm *tm)
{
char *data = (char *)s;
char option = false;
while (*format != 0) {
if (*data == 0)
return NULL;
switch (*format) {
case '%':
option = true;
format++;
break;
case 'd':
if (option) {
tm->tm_mday = strtol(data, &data, 10);
if (tm->tm_mday < 1 || tm->tm_mday > 31)
return NULL;
} else if (*data != 'd') {
return data;
}
option = false;
format++;
break;
case 'm':
if (option) {
/* tm_mon between 0 and 11 */
tm->tm_mon = strtol(data, &data, 10) - 1;
if (tm->tm_mon < 0 || tm->tm_mon > 11)
return NULL;
} else if (*data != 'm') {
return data;
}
option = false;
format++;
break;
case 'y':
if (option) {
tm->tm_year = strtol(data, &data, 10);
if (tm->tm_year < 60) tm->tm_year += 100;
} else if (*data != 'y') {
return data;
}
option = false;
format++;
break;
case 'Y':
if (option) {
tm->tm_year = strtol(data, &data, 10) - 1900;
} else if (*data != 'Y') {
return data;
}
option = false;
format++;
break;
case 'H':
if (option) {
tm->tm_hour = strtol(data, &data, 10);
if (tm->tm_hour < 0 || tm->tm_hour > 23)
return NULL;
} else if (*data != 'H') {
return data;
}
option = false;
format++;
break;
case 'M':
if (option) {
tm->tm_min = strtol(data, &data, 10);
if (tm->tm_min < 0 || tm->tm_min > 59)
return NULL;
} else if (*data != 'M') {
return data;
}
option = false;
format++;
break;
default:
if (option)
return data;
if (*data != *format)
return data;
format++;
data++;
}
}
return data;
}
// Read a line from an istream w/o concern for buffer limitations.
std::string
StrOps::readline(std::istream& stream)
{
std::string line;
char buf[1024];
while (1) {
// Read the next line (or part thereof) from the stream.
stream.getline(buf, sizeof(buf));
// Bail out of the loop if the stream has reached end-of-file.
if ((stream.eof() && !buf[0]) || stream.bad())
break;
// Append the data read to the result string.
line.append(buf);
// If the stream is good, then stop. Otherwise, clear the
// error indicator so that getline will work again.
if ((stream.eof() && buf[0]) || stream.good())
break;
stream.clear();
}
return line;
}
std::string
StrOps::quote_string(std::string str, bool extended_mode)
{
std::string result;
std::ostringstream error;
if (extended_mode) {
result += '"';
for (std::string::iterator c = str.begin(); c != str.end(); ++c) {
switch (*c) {
case '\\':
result += '\\';
result += '\\';
break;
case '\r':
result += '\\';
result += 'r';
break;
case '\n':
result += '\\';
result += 'n';
break;
case '\t':
result += '\\';
result += 't';
break;
case '\v':
result += '\\';
result += 'v';
break;
case '"':
result += '\\';
result += '"';
break;
default:
if (isprint(*c)) {
result += *c;
} else {
std::ostringstream buf;
buf.width(2);
buf.setf(std::ios::hex, std::ios::basefield);
buf.setf(std::ios::left);
buf << ((static_cast<unsigned> (*c)) & 0xFF) << std::ends;
result += "\\x";
result += buf.str();
}
break;
}
}
result += '"';
} else {
result += '"';
for (std::string::iterator c = str.begin(); c != str.end(); ++c) {
if (*c == '"') {
result += "\"\"";
} else if (*c == '\n' || *c == '\r') {
error << "use extended csv mode for newlines\n";
*err << error.str();
kdDebug() << error.str().c_str() << endl;
} else {
result += *c;
}
}
result += '"';
}
return result;
}
std::string
StrOps::concatenatepath(std::string p_Path,
std::string p_FileName, std::string p_Ext)
{
std::string l_FilePath;
#ifdef WIN32
if (p_FileName[1] == ':' || p_FileName[0] == '\\')
return p_FileName;
else if (p_Path.empty())
l_FilePath = p_FileName;
else
l_FilePath = p_Path + std::string("\\") + p_FileName;
#else
if (p_FileName[0] == '/')
return p_FileName;
else if (p_Path.empty())
l_FilePath = p_FileName;
else
l_FilePath = p_Path + std::string("/") + p_FileName;
#endif
if (!p_Ext.empty() && (p_FileName.rfind(p_Ext) == std::string::npos))
l_FilePath += p_Ext;
return l_FilePath;
}