#include #include #include #include "misc.h" using namespace std; /* Copy one word from a string. A word is a sequence of non white space. Return a pointer on the first blank character after the word. If there were no word, dest[0] == '\0' */ char *str_copyword(char *dest, const char *str) { if (str != NULL){ str = str_skip(str); while (*str > ' ') *dest++ = *str++; } *dest = '\0'; return (char*) str; } char *str_copyword(char *dest, const char *str, int size) { if (str != NULL){ str = str_skip(str); size--; while (*str > ' ' && size > 0){ *dest++ = *str++; size--; } } *dest = '\0'; return (char*) str; } /* Check if a string start with a given word followed by a space or '\0'; Return != 0 if this is true. */ int str_isword (const char *str, const char *word) { int len = strlen (word); int ret = strncmp(str,word,len)==0; if (ret){ char car = str[len]; ret = (isspace(car) || car == '\0'); } return ret; } /* Like strncpy but make sure the '\0' is there size if the sizeof() of the destination. One byte is kept to put the '\0'; */ void strcpy_cut (char *dst, const char *src, int size) { if (size >= 0){ if (size > 0){ size--; strncpy (dst,src,size); } dst[size] = '\0'; } } /* Move over one word */ char *str_skipword(const char *str) { str = str_skip(str); while (*str > ' ') str++; str = str_skip(str); return (char*) str; } /* Copy one word from a string. A word is a sequence of non white space. Return a pointer on the first blank character after the word. If there were no word, dest[0] == '\0' */ char *str_copyword(SSTRING &dest, const char *str) { str = str_skip(str); char tmp[1000]; char *pt = tmp; while (*str > ' ' && (pt-tmp)<999) *pt++ = *str++; *pt = '\0'; dest.setfrom (tmp); return (char*) str; } /* Copy one word from a string. A word is a sequence of non white space. Return a pointer on the first blank character after the word. If there were no word, dest[0] == '\0' */ char *str_copyword(string &dest, const char *str) { str = str_skip(str); const char *start = str; while (*str > ' ') str++; dest = string(start,str-start); return (char*) str; } /* Free all entry of the string table. */ void tbstr_free (char *tb[], int nb) { for (int i=0; i= ' ') line = str_skip(line); if (*line == '\0'){ break; }else{ const char *start = line; while (*line != '\0' && *line != delim && *line != delim2) line++; if (line > start || *line == delim || *line == delim2){ SSTRING *word = new SSTRING; word->setfrom (start,line-start); words.add (word); } if (*line == delim || *line == delim2) line++; } } return words.getnb()-start; } int str_splitline ( const char *line, // Line to split char delim, // Field delimiter vector &words) // Will contain the separated words { SSTRINGS tmp; int ret = str_splitline (line,delim,tmp); for (int i=0; ic_str()); return ret; } int str_splitline ( const SSTRING &line, // Line to split char delim, // Field delimiter SSTRINGS &words) // Will contain the separated words { return str_splitline (line.get(),delim,words); } int str_splitline ( const string &line, // Line to split char delim, // Field delimiter vector &words) // Will contain the separated words { return str_splitline (line.c_str(),delim,words); } vector str_splitline(PARAM_STRING line, char delim) { vector ret; str_splitline (line.ptr,delim,ret); return ret; } vector str_splitline(PARAM_STRING line) { return str_splitline (line,' '); } static int str_unquote(const char *&pt_start, int len, char quote1, char quote2) { if (*pt_start == quote1 || *pt_start == quote2){ if (len > 1 && *pt_start == pt_start[len-1]){ pt_start++; len -= 2; } } return len; } static void str_skipquote(const char *&line) { char quote = *line++; while (*line != '\0'){ if (*line == quote){ if (line[1] == quote){ line+=2; }else{ line++; break; } }else{ line++; } } } /* Decompose words in a line, including double quoted sequence. Words (and quoted sequences) are separated with white chars. Return the number of field written in words */ int str_splitlineq ( const char *line, // Line to split const char delim, const char quote1, const char quote2, vector &words) // Will contain the separated words { unsigned start = words.size(); while (1){ line = str_skip(line); if (*line == '\0') break; if (delim == ' '){ const char *pt_start = line; while (*line > ' '){ if (*line == quote1 || *line == quote2){ str_skipquote(line); }else{ line++; } } int len = line-pt_start; len = str_unquote(pt_start,len,quote1,quote2); words.emplace_back(pt_start,len); }else{ const char *pt = line; while (*pt != '\0' && *pt != delim){ if (*pt == quote1 || *pt == quote2){ str_skipquote(pt); }else{ pt++; } } int len = pt-line; len = str_unquote(line,len,quote1,quote2); words.emplace_back (line,len); line = pt; } if (delim != ' ' && *line == delim) line++; } return words.size()-start; } int str_splitlineq ( const char *line, // Line to split const char delim, const char quote1, const char quote2, SSTRINGS &words) // Will contain the separated words { vector tmp; int n = str_splitlineq (line,delim,quote1,quote2,tmp); for (int i=0; i &words) // Will contain the separated words { return str_splitlineq (line.ptr,' ','"','\'',words); } vector str_splitlineq ( PARAM_STRING line, // Line to split char delim) // Field delimiter { vector ret; str_splitlineq (line.ptr,delim,'"','\'',ret); return ret; } vector str_splitlineq ( PARAM_STRING line) // Line to split { return str_splitlineq (line,' '); } int str_splitlineq ( const char *line, // Line to split SSTRINGS &words) // Will contain the separated words { return str_splitlineq (line,' ','"','\'',words); } /* Split a multi-line string in a table Return the table. */ vector str_cnv2lines (PARAM_STRING txt) { vector tb; const char *pt = txt.ptr; while (*pt != '\0'){ const char *start = pt; while (*pt != '\n' && *pt != '\0') pt++; tb.emplace_back(start,pt-start); if (*pt == '\n') pt++; } return tb; } /* Split a multi-line string in a table Return the number of lines found. */ int str_cnv2lines(const char *pt, SSTRINGS &tb) { auto stl_tb = str_cnv2lines(pt); int ret = (int)stl_tb.size(); for (auto &s:stl_tb){ SSTRING *n = new SSTRING; if (s.size() > 0) n->setfrom (s.c_str(),s.size()); tb.add (n); } return ret; } int string_cmp(const PARAM_STRING s1, const PARAM_STRING s2) { return strcmp(s1.ptr,s2.ptr); } int string_ncmp(const PARAM_STRING s1, const PARAM_STRING s2, size_t len) { return strncmp(s1.ptr,s2.ptr,len); } int string_casecmp(const PARAM_STRING s1, const PARAM_STRING s2) { return strcasecmp(s1.ptr,s2.ptr); } int string_ncasecmp(const PARAM_STRING s1, const PARAM_STRING s2, size_t len) { return strncasecmp(s1.ptr,s2.ptr,len); } // Check if a string only contains digits static bool splitline_all_digits (const char *s) { bool ret = false; if (isdigit(*s)){ while (isdigit(*s)) s++; ret = *s == '\0'; } return ret; } void splitline_assign(bool &ok, long &a, const string &v) { if (splitline_all_digits(v.c_str())){ a = atol(v.c_str()); }else{ a = 0; ok = false; } } void splitline_assign(bool &ok, unsigned &a, const string &v) { if (splitline_all_digits(v.c_str())){ a = atoi(v.c_str()); }else{ a = 0; ok = false; } } void splitline_assign(bool &ok, int &a, const string &v) { const char *pt = v.c_str(); if ((*pt == '-' && splitline_all_digits(pt+1)) || splitline_all_digits(pt)){ a = atoi(v.c_str()); }else{ a = 0; ok = false; } } void splitline_assign(bool &ok, bool &a, const string &v) { if (v == "true"){ a = true; }else if (v == "false"){ a = false; }else{ a = false; ok = false; } } void splitline_assign(bool &ok, string &a, const string &v) { a = v; } void splitline_assign(bool &ok, double &a, const std::string &v) { const char *pt = v.c_str(); if (*pt == '-') pt++; if (isdigit(*pt)){ while (isdigit(*pt)) pt++; if (*pt == '.'){ pt++; while (isdigit(*pt)) pt++; } if (*pt != '\0'){ ok = false; }else{ a = atof(v.c_str()); } }else{ ok = false; } } void splitline_reset (long &a) { a = 0; } void splitline_reset (unsigned &a) { a = 0; } void splitline_reset (int &a) { a = 0; } void splitline_reset (string &a) { a.clear(); } void splitline_reset (bool &a) { a = false; } void splitline_reset (double &v) { v = 0; } bool splitline (const vector &tb, unsigned off) { //printf ("tb0 %s\n",__PRETTY_FUNCTION__); return tb.size() == off; } /* Return a modified copy of a string. The string is filter by a lambda function. The lambda receives a pointer to the current position in the string. From the content of the position, the function decides what to do with the current character. If the function does nothing (does not call the copystring_copybuf object) the character is copied in the output The member function of the copystring_copybuf object are replace(); the current character(s) won't be copied. They will be replaced insert(); insert something before the current characters skip(); skip some character in the input (they won't be copied) clear(); clear the output. stop(); stop processing and return what was placed in the output. keep(): copy some character from the input to the output. keep(1) is the default operation if the function does nothing */ string copystring(PARAM_STRING p,std::function func) { copystring_copybuf buf(p); while (!buf.end && *buf.pt != '\0'){ buf.skipped = false; func(buf,buf.pt); if (!buf.skipped && !buf.end){ // if skipped and end are not set by func() // it means that the character pointed by buf.pt // must be kept in the output (buf.buf). // So the default action, done here, is keep(1). buf.buf += *buf.pt; buf.pt++; } } return buf.buf; }; #ifdef TEST static void test_splitq (const char *t, char delim) { printf ("==== test_splitq delim='%c': %s\n",delim,t); auto tb = str_splitlineq(t,delim); printf ("nb=%lu\n",tb.size()); for (auto const &s:tb){ printf ("\t%s\n",s.c_str()); } } static void test_splitlineq_space(bool is_ok, const char *line) { int a1; string s1; unsigned a2; bool ok = splitlineq (line,a1,s1,limits(a2,1u,10u)); printf ("%s ", ok != is_ok ? "****" : " "); printf ("line=%-30s ok=%d a1=%d s1=%s a2=%u\n",line,ok,a1,s1.c_str(),a2); } static void test_splitline_space(bool is_ok, const char *line) { int a1; string s1; unsigned a2; bool ok = splitline (line,a1,s1,a2); printf ("%s ", ok != is_ok ? "****" : " "); printf ("line=%-30s ok=%d a1=%d s1=%s a2=%u\n",line,ok,a1,s1.c_str(),a2); } static void test_splitline_comma(bool is_ok, const char *line) { int a1; string s1; unsigned a2; bool ok = splitline (line,',',a1,s1,a2); printf ("%s ", ok != is_ok ? "****" : " "); printf ("line=%-30s ok=%d a1=%d s1=%s a2=%u\n",line,ok,a1,s1.c_str(),a2); } static void test_splitline_comma_enums(bool is_ok, const char *line) { int a1; string s1; unsigned a2; bool ok = splitline (line,',',a1,s1,enums(a2,{1u,3u,5u})); printf ("%s ", ok != is_ok ? "****" : " "); printf ("line=%-30s ok=%d a1=%d s1=%s a2=%u\n",line,ok,a1,s1.c_str(),a2); } static void test_splitline_double (bool is_ok, const char *line) { unsigned a1; string s1; double d1; bool ok = splitline (line,',',a1,s1,d1); printf ("%s ", ok != is_ok ? "****" : " "); printf ("line=%-30s ok=%d a1=%d s1=%s d1=%lf\n",line,ok,a1,s1.c_str(),d1); } static void test_copystring (const char *s) { string ret = copystring (s,[](auto &c, auto pt){ if (*pt == 'e'){ c.replace(1,"(e->E)"); }else if (*pt == 'h'){ c.replace(1,"H"); }else if (strncmp(pt,"are",3)==0){ c.insert ("ARE"); } }); printf ("copystring: %s -> %s\n",s,ret.c_str()); } int main (int argc, char *argv[]) { printf ("---- test splitline_comma ----\n"); test_splitline_comma (true,"1,allo,2"); test_splitline_comma (true,"-1,allo,2"); test_splitline_comma (false,"-1,allo,-2"); test_splitline_comma (false,"1a,allo,-2"); test_splitline_comma (false,"a,allo,-2"); test_splitline_comma (false,"a,allo,2"); test_splitline_comma (false,"1,allo,2,x"); test_splitline_comma (false,"1,allo"); printf ("---- test splitline_space ----\n"); test_splitline_space (true,"1 allo 2"); test_splitline_space (true,"-1 allo 2"); test_splitline_space (false,"a allo -2"); test_splitline_space (false,"1 allo 2 x"); test_splitline_space (false,"1 allo"); printf ("---- test splitlineq_space ----\n"); test_splitlineq_space (true,"1 allo 2"); test_splitlineq_space (true,"-1 'allo comment' 2"); test_splitlineq_space (false,"-1 'allo comment' 22"); test_splitlineq_space (false,"a allo -2"); test_splitlineq_space (false,"1 'allo comment' 2 x"); test_splitlineq_space (false,"1 allo"); printf ("---- test splitline_space_enums ----\n"); test_splitline_comma_enums (true,"1,allo,1"); test_splitline_comma_enums (true,"1,allo,3"); test_splitline_comma_enums (true,"1,allo,5"); test_splitline_comma_enums (false,"1,allo,2"); printf ("---- test splitline with double\n"); { test_splitline_double (true,"1,allo,1.2"); test_splitline_double (false,"1,allo,a1.2"); } printf ("---- test copystring\n"); test_copystring ("hello how are you ?"); printf ("---- test command line ----\n"); for (int i=1; i