1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
/*
* Cif export helper stuff
*
* (c) 2016 Schrodinger, Inc.
*/
#include "os_std.h"
#include "CifDataValueFormatter.h"
#include "strcasecmp.h"
/**
* Simplified whitespace test. Returns true if string `s` contains any character
* between 0x01 and 0x20 (this range contains all whitespace characters and
* no printable characters)
*/
static
bool has_whitespace(const char * s) {
for (; *s; ++s)
if (*s <= ' ')
return true;
return false;
}
/**
* Return true if `s` contains the given quote character followed by white space
*/
static
bool has_quotespace(const char * s, char quote) {
for (; (s = strchr(s, quote)); ++s)
if (s[1] && s[1] <= ' ')
return true;
return false;
}
/**
* Return true if `s` is a "simple data value" according to the CIF
* syntax specification
*/
static
bool cif_is_simpledatavalue(const char * s) {
return (
// first character is special
!strchr("_#$'\"[];", s[0]) &&
// whitespace
!has_whitespace(s) &&
// special values '.' (inapplicable) and '?' (unknown)
!((s[0] == '.' || s[0] == '?') && !s[1]) &&
// prefix is special
strncasecmp("data_", s, 5) &&
strncasecmp("save_", s, 5) &&
// reserved words
strcasecmp("loop_", s) &&
strcasecmp("stop_", s) &&
strcasecmp("global_", s));
}
std::string & CifDataValueFormatter::nextbuf() {
// advance circular pointer
m_i = (m_i + 1) % m_buf.size();
return m_buf[m_i];
}
const char * CifDataValueFormatter::quoted(const char * s) {
const char * quote = nullptr;
if (!strchr(s, '\n')) {
if (!has_quotespace(s, '\'')) {
quote = "'";
} else if (!has_quotespace(s, '"')) {
quote = "\"";
}
}
if (!quote) {
quote = "\n;";
if (strstr(s, quote)) {
printf(" CIF-Warning: data value contains unquotable <newline><semicolon>\n");
return "<UNQUOTABLE>";
}
}
return nextbuf().assign(quote).append(s).append(quote).c_str();
}
const char * CifDataValueFormatter::operator() (const char * s, const char * d) {
if (!s[0])
return d;
if (cif_is_simpledatavalue(s))
return s;
return quoted(s);
}
const char * CifDataValueFormatter::operator() (char c, const char * d) {
return (*this)(nextbuf().assign(1, c).c_str(), d);
}
|