Diff for /parser3/src/classes/table.C between versions 1.315 and 1.323

version 1.315, 2016/07/29 13:30:42 version 1.323, 2016/09/08 17:01:49
Line 51  String table_reverse_name(TABLE_REVERSE_ Line 51  String table_reverse_name(TABLE_REVERSE_
   
 // methods  // methods
   
 static Table::Action_options get_action_options(Request& r, MethodParams& params,   static Table::Action_options get_action_options(Request& r, MethodParams& params, size_t options_index, const Table& source) {
                                                 size_t options_index, const Table& source) {  
         Table::Action_options result;          Table::Action_options result;
         if(params.count() <= options_index)          if(params.count() <= options_index)
                 return result;                  return result;
Line 73  static Table::Action_options get_action_ Line 72  static Table::Action_options get_action_
                         if(soffset == "cur")                          if(soffset == "cur")
                                 result.offset=source.current();                                  result.offset=source.current();
                         else                          else
                                 throw Exception(PARSER_RUNTIME,                                  throw Exception(PARSER_RUNTIME, &soffset, "must be 'cur' string or expression");
                                         &soffset,  
                                         "must be 'cur' string or expression");  
                 } else                   } else 
                         result.offset=r.process_to_value(*voffset).as_int();                          result.offset=r.process_to_value(*voffset).as_int();
         }          }
Line 96  static Table::Action_options get_action_ Line 93  static Table::Action_options get_action_
         return result;          return result;
 }  }
   
 struct TableSeparators {  struct TableControlChars {
         char column;  const String* scolumn;          char separator;  const String* sseparator;
         char encloser; const String* sencloser;          char encloser; const String* sencloser;
   
         TableSeparators():          char separators[3];
                 column('\t'), scolumn(new String("\t")),  
           TableControlChars():
                   separator('\t'), sseparator(new String("\t")),
                 encloser(0), sencloser(0)                  encloser(0), sencloser(0)
         {}          {
                   strcpy(separators,"\t\n");
           }
   
         int load( HashStringValue& options ) {          int load( HashStringValue& options ) {
                 int result=0;                  int result=0;
                 if(Value* vseparator=options.get(PA_COLUMN_SEPARATOR_NAME)) {                  if(Value* vseparator=options.get(PA_COLUMN_SEPARATOR_NAME)) {
                         scolumn=&vseparator->as_string();                          sseparator=&vseparator->as_string();
                         if(scolumn->length()!=1)                          if(sseparator->length()!=1)
                                 throw Exception(PARSER_RUNTIME,                                  throw Exception(PARSER_RUNTIME, sseparator, "separator must be one byte character");
                                         scolumn,                          separator=sseparator->first_char();
                                         "separator must be one character long");                          separators[0]=separator;
                         column=scolumn->first_char();  
                         result++;                          result++;
                 }                  }
                 if(Value* vencloser=options.get(PA_COLUMN_ENCLOSER_NAME)) {                  if(Value* vencloser=options.get(PA_COLUMN_ENCLOSER_NAME)) {
Line 121  struct TableSeparators { Line 122  struct TableSeparators {
                                 encloser=0;                                  encloser=0;
                         } else {                          } else {
                         if(sencloser->length()!=1)                          if(sencloser->length()!=1)
                                 throw Exception(PARSER_RUNTIME,                                  throw Exception(PARSER_RUNTIME, sencloser, "encloser must be one byte character");
                                         sencloser,  
                                         "encloser must be one character long");  
                         encloser=sencloser->first_char();                          encloser=sencloser->first_char();
                         }                          }
                         result++;                          result++;
Line 132  struct TableSeparators { Line 131  struct TableSeparators {
         }          }
 };  };
   
   
   struct lsplit_sresult {
           String* piece;
           char delim;
   
           lsplit_sresult() : piece(0), delim(0){}
   
           operator bool() { return piece!=0; }
   
           void append(String *str){
                   if(piece)
                           *piece << *str;
                   else
                           piece = str;
           }
   };
   
   class StringSplitHelper : public String {
   public:
           char* base;
   
           StringSplitHelper(String astring) : String(astring), base(cstrm()) {}
   
           bool check_lang(const char *pos){
                   return langs.check_lang(L_AS_IS, pos-base, 1);
           }
   
           String *extract(char *pos){
                   String *result=new String;
                   // first: their langs
                   result->langs.append(result->body, langs, pos-base, strlen(pos));
                   // next: letters themselves
                   result->body=Body(pos);
                   return result;
           }
   };
   
   inline lsplit_sresult lsplit(char* *string_ref, const char* delims, StringSplitHelper& helper) {
           lsplit_sresult result;
           if(char *pos=*string_ref) {
                   while(char* v=strpbrk(pos, delims)) {
                           if(helper.check_lang(v)){
                                   result.delim=*v;
                                   *v=0;
                                   result.piece=helper.extract(*string_ref);
                                   *string_ref=v+1;
                                   return result;
                           }
                           pos=v+1;
                   }
                   result.piece=helper.extract(*string_ref);
                   *string_ref=0;
           }
           return result;
   }
   
   static lsplit_sresult lsplit(char** string_ref, const char* delims, char encloser, StringSplitHelper& helper) {
           lsplit_sresult result;
   
           if(char *pos=*string_ref) {
                   if(encloser && *pos==encloser && helper.check_lang(pos)) {
                           *string_ref=++pos;
   
                           // we are enclosed, searching for second encloser
                           while(1) {
                                   if(char* v=strchr(pos, encloser)){
                                           if(helper.check_lang(v)){
                                                   *(v++)=0;
                                                   result.append(helper.extract(*string_ref));
                                                   if(*v==encloser && helper.check_lang(v)){ // double-encloser stands for encloser
                                                           *string_ref=v+1;
                                                   } else {
                                                           *string_ref=pos=v;
                                                           break;
                                                   }
                                           }
                                           pos=v+1;
                                   }{
                                           result.append(helper.extract(*string_ref));
                                           *string_ref=0;
                                           return result;
                                   }
                           }
   
                           // we are no longer enclosed, searching for delimiter
                           while(char* v=strpbrk(pos, delims)) {
                                   if(helper.check_lang(v)){
                                           result.delim=*v;
                                           if(v>*string_ref){
                                                   *v=0;
                                                   result.append(helper.extract(*string_ref));
                                           }
                                           *string_ref=v+1;
                                           return result;
                                   }
                                   pos=v+1;
                           }
                           result.append(helper.extract(*string_ref));
                           *string_ref=0;
                   } else
                           return lsplit(string_ref, delims, helper);
           }
           return result;
   }
   
   static void skip_clean_empty_lines(char** data_ref, StringSplitHelper& helper) {
           if(*data_ref) {
                   while(**data_ref == '\n' && helper.check_lang(*data_ref))
                           (*data_ref)++;
           }
   }
   
 static void _create(Request& r, MethodParams& params) {  static void _create(Request& r, MethodParams& params) {
         // clone/copy part?          // clone/copy part?
         if(Table *source=params[0].get_table()) {          if(Table *source=params[0].get_table()) {
Line 149  static void _create(Request& r, MethodPa Line 260  static void _create(Request& r, MethodPa
                 if(params[0].is_string()){ // can be nameless only                  if(params[0].is_string()){ // can be nameless only
                         const String& snameless=params.as_string(0, "called with more then 1 param, first param may be only string 'nameless' or junction");                          const String& snameless=params.as_string(0, "called with more then 1 param, first param may be only string 'nameless' or junction");
                         if(snameless!="nameless")                          if(snameless!="nameless")
                                 throw Exception(PARSER_RUNTIME,                                  throw Exception(PARSER_RUNTIME, &snameless, "table::create called with more then 1 param, first param may be only 'nameless'");
                                         &snameless,  
                                         "table::create called with more then 1 param, first param may be only 'nameless'");  
                         nameless=true;                          nameless=true;
                         data_param_index++;                          data_param_index++;
                 }                  }
         }          }
   
         HashStringValue *options=0;          HashStringValue *options=0;
         TableSeparators separators;          TableControlChars control_chars;
   
         size_t options_param_index=data_param_index+1;          size_t options_param_index=data_param_index+1;
         if(          if( options_param_index<params.count() && (options=params.as_hash(options_param_index)) ) {
                 options_param_index<params.count()  
                 && (options=params.as_hash(options_param_index))  
         ) {  
                 // cloning, so that we could change                  // cloning, so that we could change
                 options=new HashStringValue(*options);                  options=new HashStringValue(*options);
                 separators.load(*options);                  control_chars.load(*options);
                 if(separators.encloser){  
                         throw Exception(PARSER_RUNTIME,  
                                 0,  
                                 "encloser not supported for table::create yet");  
                 }  
         }          }
   
         // data          // data
         Temp_lang temp_lang(r, String::L_PASS_APPENDED);          Temp_lang temp_lang(r, String::L_PASS_APPENDED);
         const String&  data=          StringSplitHelper sdata(r.process_to_string(params.as_junction(data_param_index, "body must be table or code")));
                 r.process_to_string(params.as_junction(data_param_index, "body must be table or code"));          char *data=sdata.base;
   
         // parse columns          // parse columns
         size_t raw_pos_after=0;  
         Table::columns_type columns;          Table::columns_type columns;
           if(nameless) {
         if(nameless){                  columns=0; // nameless
                 columns=Table::columns_type(0); // nameless  
         } else {          } else {
                 columns=Table::columns_type(new ArrayString);                  columns=new ArrayString;
                   while( lsplit_sresult sr=lsplit(&data, control_chars.separators, control_chars.encloser, sdata) ) {
                 ArrayString head;                          *columns+=sr.piece;
                 data.split(head, raw_pos_after, "\n", String::L_AS_IS, 1);                          if(sr.delim=='\n') 
                 if(head.count()) {                                  break;
                         size_t col_pos_after=0;  
                         if(head[0]->is_empty())  
                                 *columns += new String();  
                         else  
                                 head[0]->split(*columns, col_pos_after, *separators.scolumn, String::L_AS_IS);  
                 }                  }
         }          }
           
         Table& table=*new Table(columns);          Table& table=*new Table(columns);
         // parse cells          int columns_count=columns ? columns->count(): 0;
   
         ArrayString rows;  
         data.split(rows, raw_pos_after, "\n", String::L_AS_IS);  
         Array_iterator<const String*> i(rows);  
         while(i.has_next()) {  
                 Table::element_type row(new ArrayString);  
                 const String& string=*i.next();  
                 // remove comment lines  
                 if(string.is_empty())  
                         continue;  
   
                 size_t col_pos_after=0;          // parse cells
                 string.split(*row, col_pos_after, *separators.scolumn, String::L_AS_IS);          Table::element_type row(new ArrayString(columns_count));
                 table+=row;          skip_clean_empty_lines(&data, sdata);
           while( lsplit_sresult sr=lsplit(&data, control_chars.separators, control_chars.encloser, sdata) ) {
                   if(sr.piece->is_empty() && !sr.delim && !row->count()) // append last empty column [if without \n]
                           break;
                   *row+=sr.piece;
                   if(sr.delim=='\n') {
                           table+=row;
                           row=new ArrayString(columns_count);
                           skip_clean_empty_lines(&data, sdata);
                   }
         }          }
           // last line [if without \n]
           if(row->count())
                   table+=row;
           
         // replace any previous table value          // replace any previous table value
         GET_SELF(r, VTable).set_table(table);          GET_SELF(r, VTable).set_table(table);
 }  }
Line 226  struct lsplit_result { Line 322  struct lsplit_result {
         char* piece;          char* piece;
         char delim;          char delim;
   
           lsplit_result(char *apiece=0) : piece(apiece), delim(0){}
         operator bool() { return piece!=0; }          operator bool() { return piece!=0; }
 };  };
   
 inline lsplit_result lsplit(char* string, char delim1, char delim2) {  inline lsplit_result lsplit(char* *string_ref, const char* delims) {
         lsplit_result result;          lsplit_result result(*string_ref);
         if(string) {          if(result.piece) {
                 char delims[]={delim1, delim2, 0};                  if(char* v=strpbrk(result.piece, delims)) {
                 if(char* v=strpbrk(string, delims)) {  
                         result.delim=*v;                          result.delim=*v;
                         *v=0;                          *v=0;
                         result.piece=v+1;                          *string_ref=v+1;
                         return result;                          return result;
                 }                  }
                   *string_ref=0;
         }          }
         result.piece=0;  
         result.delim=0;  
         return result;          return result;
 }  }
   
 inline lsplit_result lsplit(char* *string_ref, char delim1, char delim2) {  static lsplit_result lsplit(char** string_ref, const char* delims, char encloser) {
         lsplit_result result;          lsplit_result result(*string_ref);
         result.piece=*string_ref;  
         lsplit_result next=lsplit(*string_ref, delim1, delim2);  
         result.delim=next.delim;  
         *string_ref=next.piece;  
         return result;  
 }  
   
 static lsplit_result lsplit(char** string_ref, char delim1, char delim2, char encloser) {  
         lsplit_result result;  
   
         if(char* string=*string_ref) {          if(result.piece) {
                 if(encloser && *string==encloser) {                  if(encloser && *result.piece==encloser) {
                         string++;                          result.piece++;
                                                   
                           char c;
                         char *read;                          char *read;
                         char *write;                          char *write;
                         write=read=string;                          write=read=result.piece;
                         char c;  
                         // we are enclosed, searching for second encloser                          // we are enclosed, searching for second encloser
                         while(c=*read++) {                          while(c=*read++) {
                                 if(c==encloser) {                                  if(c==encloser) {
Line 275  static lsplit_result lsplit(char** strin Line 362  static lsplit_result lsplit(char** strin
                                 }                                  }
                                 *write++=c;                                  *write++=c;
                         }                          }
   
                         // we are no longer enclosed, searching for delimiter, skipping extra enclosers                          // we are no longer enclosed, searching for delimiter, skipping extra enclosers
                         while(c=*read++) {                          while(c=*read++) {
                                 if(c==delim1 || c==delim2) {                                  if(c==delims[0] || c==delims[1]) {
                                         result.delim=c;                                          result.delim=c;
                                         break;                                          break;
                                 } else  if(c!=encloser)                                  } else  if(c!=encloser)
                                         *write++=c;                                          *write++=c;
                         }                          }
   
                         *write=0; // terminate                          *write=0; // terminate
                         *string_ref=c? read: 0;                          *string_ref=c ? read : 0;
                         result.piece=string;  
                         return result;                          return result;
                 } else                  } else
                         return lsplit(string_ref, delim1, delim2);                          return lsplit(string_ref, delims);
         }          }
         result.piece=0;  
         return result;          return result;
 }  }
   
 static void skip_empty_and_comment_lines( char** data_ref ) {  static void skip_empty_and_comment_lines( char** data_ref ) {
         if(char *data=*data_ref) {          while(*data_ref) {
                 while( char c=*data ) {                  if(**data_ref == '\n'){
                         if( c== '\n' || c == '#' ) {                          (*data_ref)++;
                                 /*nowhere=*/getrow(&data); // remove empty&comment lines                  } else {
                                 if(!(*data_ref=data))                          if(**data_ref == '#' )
                                         break;                                  /*nowhere=*/getrow(data_ref);
                                 continue;                          else
                         }                                  break;
                         break;  
                 }                  }
         }          }
 }  }
   
 static void skip_empty_lines( char** data_ref ) {  static void skip_empty_lines( char** data_ref ) {
         if(char *data=*data_ref) {          if(*data_ref) {
                 while( char c=*data ) {                  while(**data_ref == '\n')
                         if( c== '\n' ) {                          (*data_ref)++;
                                 /*nowhere=*/getrow(&data); // remove empty lines  
                                 if(!(*data_ref=data))  
                                         break;  
                                 continue;  
                         }  
                         break;  
                 }  
         }          }
 }  }
   
Line 333  static void _load(Request& r, MethodPara Line 412  static void _load(Request& r, MethodPara
         size_t options_param_index=filename_param_index+1;          size_t options_param_index=filename_param_index+1;
   
         HashStringValue *options=0;          HashStringValue *options=0;
         TableSeparators separators;          TableControlChars control_chars;
         if(options_param_index<params.count()          if(options_param_index<params.count()
                 && (options=params.as_hash(options_param_index))) {                  && (options=params.as_hash(options_param_index))) {
                 // cloning, so that we could change [to simplify checks on params inside file_read_text                  // cloning, so that we could change [to simplify checks on params inside file_read_text
                 options=new HashStringValue(*options);                  options=new HashStringValue(*options);
                 separators.load(*options);                  control_chars.load(*options);
         }          }
   
         // loading text          // loading text
         char *data=file_load_text(r,          char *data=file_load_text(r, r.absolute(params.as_string(filename_param_index, FILE_NAME_MUST_BE_STRING)), true, options);
                 r.absolute(params.as_string(filename_param_index, FILE_NAME_MUST_BE_STRING)),  
                 true,  
                 options  
         );  
   
         Skip_lines_action skip_lines_action = (separators.column=='#' || separators.encloser=='#') ? skip_empty_lines : skip_empty_and_comment_lines;          Skip_lines_action skip_lines_action = (control_chars.separator=='#' || control_chars.encloser=='#') ? skip_empty_lines : skip_empty_and_comment_lines;
   
         // parse columns          // parse columns
         Table::columns_type columns;          Table::columns_type columns;
         if(nameless) {          if(nameless) {
                 columns=Table::columns_type(0); // nameless                  columns=0; // nameless
         } else {          } else {
                 columns=Table::columns_type(new ArrayString);                  columns=new ArrayString;
   
                 skip_lines_action(&data);                  skip_lines_action(&data);
                 while( lsplit_result sr=lsplit(&data, separators.column, '\n', separators.encloser) ) {                  while( lsplit_result sr=lsplit(&data, control_chars.separators, control_chars.encloser) ) {
                         *columns+=new String(sr.piece, String::L_TAINTED);                          *columns+=new String(sr.piece, String::L_TAINTED);
                         if(sr.delim=='\n')                           if(sr.delim=='\n') 
                                 break;                                  break;
Line 366  static void _load(Request& r, MethodPara Line 441  static void _load(Request& r, MethodPara
         }          }
                   
         Table& table=*new Table(columns);          Table& table=*new Table(columns);
         int columns_count=columns? columns->count(): 0;          int columns_count=columns ? columns->count(): 0;
   
         // parse cells          // parse cells
         Table::element_type row(new ArrayString(columns_count));          Table::element_type row(new ArrayString(columns_count));
         skip_lines_action(&data);          skip_lines_action(&data);
         while( lsplit_result sr=lsplit(&data, separators.column, '\n', separators.encloser) ) {          while( lsplit_result sr=lsplit(&data, control_chars.separators, control_chars.encloser) ) {
                 if(!*sr.piece && !sr.delim && !row->count()) // append last empty column [if without \n]                  if(!*sr.piece && !sr.delim && !row->count()) // append last empty column [if without \n]
                         break;                          break;
                 *row+=new String(sr.piece, String::L_TAINTED);                  *row+=new String(sr.piece, String::L_TAINTED);
Line 415  static void enclose( pa_stringstream& to Line 490  static void enclose( pa_stringstream& to
         }          }
 }  }
   
 static void table_to_csv(pa_stringstream& result, Table& table, TableSeparators& separators, bool output_column_names) {  static void table_to_csv(pa_stringstream& result, Table& table, TableControlChars& control_chars, bool output_column_names) {
         if(output_column_names) {          if(output_column_names) {
                 if(table.columns()) { // named table                  if(table.columns()) { // named table
                         if(separators.encloser){                          if(control_chars.encloser){
                                 for(Array_iterator<const String*> i(*table.columns()); i.has_next(); ) {                                  for(Array_iterator<const String*> i(*table.columns()); i.has_next(); ) {
                                         enclose( result, i.next(), separators.encloser );                                          enclose( result, i.next(), control_chars.encloser );
                                         if(i.has_next())                                          if(i.has_next())
                                                 result<<separators.column;                                                  result<<control_chars.separator;
                                 }                                  }
                         } else {                          } else {
                                 for(Array_iterator<const String*> i(*table.columns()); i.has_next(); ) {                                  for(Array_iterator<const String*> i(*table.columns()); i.has_next(); ) {
                                         result<<i.next()->cstr();                                          result<<i.next()->cstr();
                                         if(i.has_next())                                          if(i.has_next())
                                                 result<<separators.column;                                                  result<<control_chars.separator;
                                 }                                  }
                         }                          }
                 } else { // nameless table [we were asked to output column names]                  } else { // nameless table [we were asked to output column names]
                         if(int lsize=table.count()?table[0]->count():0)                          if(int lsize=table.count()?table[0]->count():0)
                                 for(int column=0; column<lsize; column++) {                                  for(int column=0; column<lsize; column++) {
                                         if(separators.encloser) {                                          if(control_chars.encloser) {
                                                 result<<separators.encloser<<column<<separators.encloser;                                                  result<<control_chars.encloser<<column<<control_chars.encloser;
                                         } else {                                          } else {
                                                 result<<column;                                                  result<<column;
                                         }                                          }
                                         if(column<lsize-1){                                          if(column<lsize-1){
                                                 result<<separators.column;                                                  result<<control_chars.separator;
                                         }                                          }
                                 }                                  }
                         else                          else
Line 451  static void table_to_csv(pa_stringstream Line 526  static void table_to_csv(pa_stringstream
   
         // process data lines          // process data lines
         Array_iterator<ArrayString*> i(table);          Array_iterator<ArrayString*> i(table);
         if(separators.encloser){          if(control_chars.encloser){
                 while(i.has_next()) {                  while(i.has_next()) {
                         for(Array_iterator<const String*> c(*i.next()); c.has_next(); ) {                          for(Array_iterator<const String*> c(*i.next()); c.has_next(); ) {
                                 enclose( result, c.next(), separators.encloser );                                  enclose( result, c.next(), control_chars.encloser );
                                 if(c.has_next())                                  if(c.has_next())
                                         result<<separators.column;                                          result<<control_chars.separator;
                         }                          }
                         result<<'\n';                          result<<'\n';
                 }                  }
Line 465  static void table_to_csv(pa_stringstream Line 540  static void table_to_csv(pa_stringstream
                         for(Array_iterator<const String*> c(*i.next()); c.has_next(); ) {                          for(Array_iterator<const String*> c(*i.next()); c.has_next(); ) {
                                 result<<c.next()->cstr();                                  result<<c.next()->cstr();
                                 if(c.has_next())                                  if(c.has_next())
                                         result<<separators.column;                                          result<<control_chars.separator;
                         }                          }
                         result<<'\n';                          result<<'\n';
                 }                  }
Line 494  void enclose( String& to, const String* Line 569  void enclose( String& to, const String*
         }          }
 }  }
   
 static void table_to_csv(String& result, Table& table, TableSeparators& separators, bool output_column_names) {  static void table_to_csv(String& result, Table& table, TableControlChars& control_chars, bool output_column_names) {
         if(output_column_names) {          if(output_column_names) {
                 if(table.columns()) { // named table                  if(table.columns()) { // named table
                         if(separators.encloser) {                          if(control_chars.encloser) {
                                 for(Array_iterator<const String*> i(*table.columns()); i.has_next(); ) {                                  for(Array_iterator<const String*> i(*table.columns()); i.has_next(); ) {
                                         enclose( result, i.next(), separators.encloser, separators.sencloser );                                          enclose( result, i.next(), control_chars.encloser, control_chars.sencloser );
                                         if(i.has_next())                                          if(i.has_next())
                                                 result<<*separators.scolumn;                                                  result<<*control_chars.sseparator;
                                 }                                  }
                         } else {                          } else {
                                 for(Array_iterator<const String*> i(*table.columns()); i.has_next(); ) {                                  for(Array_iterator<const String*> i(*table.columns()); i.has_next(); ) {
                                         result<<*i.next();                                          result<<*i.next();
                                         if(i.has_next())                                          if(i.has_next())
                                                 result<<*separators.scolumn;                                                  result<<*control_chars.sseparator;
                                 }                                  }
                         }                          }
                 } else { // nameless table [we were asked to output column names]                  } else { // nameless table [we were asked to output column names]
                         if(int lsize=table.count()?table[0]->count():0)                          if(int lsize=table.count()?table[0]->count():0)
                                 for(int column=0; column<lsize; column++) {                                  for(int column=0; column<lsize; column++) {
                                         if(separators.encloser) {                                          if(control_chars.encloser) {
                                                 result<<*separators.sencloser<<String::Body::Format(column)<<*separators.sencloser;                                                  result<<*control_chars.sencloser<<String::Body::Format(column)<<*control_chars.sencloser;
                                         } else {                                          } else {
                                                 result<<String::Body::Format(column);                                                  result<<String::Body::Format(column);
                                         }                                          }
                                         if(column<lsize-1){                                          if(column<lsize-1){
                                                 result<<*separators.scolumn;                                                  result<<*control_chars.sseparator;
                                         }                                          }
                                 }                                  }
                         else                          else
Line 530  static void table_to_csv(String& result, Line 605  static void table_to_csv(String& result,
   
         // data lines          // data lines
         Array_iterator<ArrayString*> i(table);          Array_iterator<ArrayString*> i(table);
         if(separators.encloser){          if(control_chars.encloser){
                 while(i.has_next()) {                  while(i.has_next()) {
                         for(Array_iterator<const String*> c(*i.next()); c.has_next(); ) {                          for(Array_iterator<const String*> c(*i.next()); c.has_next(); ) {
                                 enclose( result, c.next(), separators.encloser, separators.sencloser );                                  enclose( result, c.next(), control_chars.encloser, control_chars.sencloser );
                                 if(c.has_next())                                  if(c.has_next())
                                         result<<*separators.scolumn;                                          result<<*control_chars.sseparator;
                         }                          }
                         result.append_know_length("\n", 1, String::L_CLEAN);                          result.append_know_length("\n", 1, String::L_CLEAN);
                 }                  }
Line 544  static void table_to_csv(String& result, Line 619  static void table_to_csv(String& result,
                         for(Array_iterator<const String*> c(*i.next()); c.has_next(); ) {                          for(Array_iterator<const String*> c(*i.next()); c.has_next(); ) {
                                 result<<*c.next();                                  result<<*c.next();
                                 if(c.has_next())                                  if(c.has_next())
                                         result<<*separators.scolumn;                                          result<<*control_chars.sseparator;
                         }                          }
                         result.append_know_length("\n", 1, String::L_CLEAN);                          result.append_know_length("\n", 1, String::L_CLEAN);
                 }                  }
Line 574  static void _save(Request& r, MethodPara Line 649  static void _save(Request& r, MethodPara
         if(do_append && file_exist(file_spec))          if(do_append && file_exist(file_spec))
                 output_column_names=false;                  output_column_names=false;
   
         TableSeparators separators;          TableControlChars control_chars;
         if(param_index<params.count())          if(param_index<params.count())
                 if(HashStringValue* options=params.as_hash(param_index++)) {                  if(HashStringValue* options=params.as_hash(param_index++)) {
                         int valid_options=separators.load(*options);                          int valid_options=control_chars.load(*options);
                         if(valid_options!=options->count())                          if(valid_options!=options->count())
                                 throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);                                  throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
                 }                  }
   
         if(param_index<params.count())          if(param_index<params.count())
                 throw Exception(PARSER_RUNTIME,                  throw Exception(PARSER_RUNTIME, 0, "bad mode (must be nameless or append)");
                         0,  
                         "bad mode (must be nameless or append)");  
   
         Table& table=GET_SELF(r, VTable).table();          Table& table=GET_SELF(r, VTable).table();
   
 #ifdef USE_STRINGSTREAM  #ifdef USE_STRINGSTREAM
         pa_stringstream ost(std::stringstream::out);          pa_stringstream ost(std::stringstream::out);
   
         table_to_csv(ost, table, separators, output_column_names);          table_to_csv(ost, table, control_chars, output_column_names);
   
         // write          // write
                 pa_string data=ost.str();                  pa_string data=ost.str();
Line 601  static void _save(Request& r, MethodPara Line 674  static void _save(Request& r, MethodPara
 #else  #else
         String sdata;          String sdata;
   
         table_to_csv(sdata, table, separators, output_column_names);          table_to_csv(sdata, table, control_chars, output_column_names);
   
         // write          // write
                 const char* data_cstr=sdata.cstr();                  const char* data_cstr=sdata.cstr();
Line 619  static void _csv_string(Request& r, Meth Line 692  static void _csv_string(Request& r, Meth
                         output_column_names=false;                          output_column_names=false;
                         param_index++;                          param_index++;
                 } else {                  } else {
                         throw Exception(PARSER_RUNTIME,                          throw Exception(PARSER_RUNTIME, 0, "bad mode (must be nameless)");
                                 0,  
                                 "bad mode (must be nameless)");  
                 }                  }
         }          }
   
         TableSeparators separators;          TableControlChars control_chars;
         if(param_index<params.count())          if(param_index<params.count())
                 if(HashStringValue* options=params.as_hash(param_index++)) {                  if(HashStringValue* options=params.as_hash(param_index++)) {
                         int valid_options=separators.load(*options);                          int valid_options=control_chars.load(*options);
                         if(valid_options!=options->count())                          if(valid_options!=options->count())
                                 throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);                                  throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
                 }                  }
Line 638  static void _csv_string(Request& r, Meth Line 709  static void _csv_string(Request& r, Meth
 #ifdef USE_STRINGSTREAM  #ifdef USE_STRINGSTREAM
         pa_stringstream ost(std::stringstream::out);          pa_stringstream ost(std::stringstream::out);
   
         table_to_csv(ost, table, separators, output_column_names);          table_to_csv(ost, table, control_chars, output_column_names);
   
         r.write_no_lang(*new VString(*new String(pa_strdup(ost.str().c_str()), String::L_CLEAN)));          r.write_no_lang(*new VString(*new String(pa_strdup(ost.str().c_str()), String::L_CLEAN)));
 #else  #else
         String sdata;          String sdata;
   
         table_to_csv(sdata, table, separators, output_column_names);          table_to_csv(sdata, table, control_chars, output_column_names);
   
         r.write_no_lang(*new VString(*new String(sdata.cstr(), String::L_CLEAN)));          r.write_no_lang(*new VString(*new String(sdata.cstr(), String::L_CLEAN)));
 #endif  #endif
Line 685  static void _offset(Request& r, MethodPa Line 756  static void _offset(Request& r, MethodPa
                     else if(whence=="set")                      else if(whence=="set")
                                 absolute=true;                                  absolute=true;
                     else                      else
                                 throw Exception(PARSER_RUNTIME,                                  throw Exception(PARSER_RUNTIME, &whence, "is invalid whence, valid are 'cur' or 'set'");
                                         &whence,  
                                         "is invalid whence, valid are 'cur' or 'set'");  
                 }                  }
                                   
                 int offset=params.as_int(params.count()-1, "offset must be expression", r);                  int offset=params.as_int(params.count()-1, "offset must be expression", r);
Line 705  static void _menu(Request& r, MethodPara Line 774  static void _menu(Request& r, MethodPara
   
         Table& table=GET_SELF(r, VTable).table();          Table& table=GET_SELF(r, VTable).table();
         size_t saved_current=table.current();          size_t saved_current=table.current();
         size_t size=table.count();  
   
         if(delim_maybe_code) { // delimiter set          if(delim_maybe_code) { // delimiter set
                 bool need_delim=false;                  bool need_delim=false;
                 for(size_t row=0; row<size; row++) {                  for(size_t row=0; row<table.count(); row++) {
                         table.set_current(row);                          table.set_current(row);
   
                         StringOrValue sv_processed=r.process(body_code);                          StringOrValue sv_processed=r.process(body_code);
Line 729  static void _menu(Request& r, MethodPara Line 797  static void _menu(Request& r, MethodPara
                                 break;                                  break;
                 }                  }
         } else {          } else {
                 for(size_t row=0; row<size; row++) {                  for(size_t row=0; row<table.count(); row++) {
                         table.set_current(row);                          table.set_current(row);
     
                         r.process_write(body_code);                          r.process_write(body_code);
Line 772  static void table_row_to_hash(Table::ele Line 840  static void table_row_to_hash(Table::ele
         bool exist=false;          bool exist=false;
         switch(info->value_type) {          switch(info->value_type) {
                 case C_STRING: {                  case C_STRING: {
                         size_t index=info->value_fields->get(0);                          if(info->value_fields->count()){
                         exist=info->hash->put_dont_replace(*key, (index < row->count()) ? new VString(*row->get(index)) : new VString());                                  size_t index=info->value_fields->get(0);
                                   exist=info->hash->put_dont_replace(*key, (index < row->count()) ? new VString(*row->get(index)) : VString::empty());
                           } else {
                                   exist=info->hash->put_dont_replace(*key, VString::empty());
                           }
                         break;                          break;
                 }                  }
                 case C_HASH: {                  case C_HASH: {
Line 899  static void _hash(Request& r, MethodPara Line 971  static void _hash(Request& r, MethodPara
                                         throw Exception(PARSER_RUNTIME, 0, "you can't specify value field(s) with option $.distinct[tables] or $.type[tables]");                                          throw Exception(PARSER_RUNTIME, 0, "you can't specify value field(s) with option $.distinct[tables] or $.type[tables]");
   
                                 Value& value_fields_param=params[1];                                  Value& value_fields_param=params[1];
                                 if(value_fields_param.get_junction()){                                  if(value_fields_param.get_junction()){ // code specified
                                         value_code=&value_fields_param;                                          value_code=&value_fields_param;
                                 } else if(value_fields_param.is_string()) { // one column as string was specified                                  } else if(value_fields_param.is_string()) { // one column as string was specified
                                         value_fields+=self_table.column_name2index(*value_fields_param.get_string(), true);                                          const String &field_name=*value_fields_param.get_string();
                                           if(!field_name.is_empty())
                                                   value_fields+=self_table.column_name2index(field_name, true);
                                 } else if(Table* value_fields_table=value_fields_param.get_table()) { // list of columns were specified in table                                  } else if(Table* value_fields_table=value_fields_param.get_table()) { // list of columns were specified in table
                                         for(Array_iterator<Table::element_type> i(*value_fields_table); i.has_next(); ) {                                          for(Array_iterator<Table::element_type> i(*value_fields_table); i.has_next(); ) {
                                                 const String& value_field_name =*i.next()->get(0);                                                  const String& value_field_name =*i.next()->get(0);
Line 1083  static void _foreach(Request& r, MethodP Line 1157  static void _foreach(Request& r, MethodP
   
         Table& table=GET_SELF(r, VTable).table();          Table& table=GET_SELF(r, VTable).table();
         size_t saved_current=table.current();          size_t saved_current=table.current();
         size_t size=table.count();  
   
         const String* rownum_var_name=rownum_name.is_empty()? 0 : &rownum_name;          const String* rownum_var_name=rownum_name.is_empty()? 0 : &rownum_name;
         const String* value_var_name=value_name.is_empty()? 0 : &value_name;          const String* value_var_name=value_name.is_empty()? 0 : &value_name;
Line 1092  static void _foreach(Request& r, MethodP Line 1165  static void _foreach(Request& r, MethodP
   
         if(delim_maybe_code) { // delimiter set          if(delim_maybe_code) { // delimiter set
                 bool need_delim=false;                  bool need_delim=false;
                 for(size_t row=0; row<size; row++) {                  for(size_t row=0; row<table.count(); row++) {
                         table.set_current(row);                          table.set_current(row);
   
                         if(rownum_var_name)                          if(rownum_var_name)
Line 1117  static void _foreach(Request& r, MethodP Line 1190  static void _foreach(Request& r, MethodP
                                 break;                                  break;
                 }                  }
         } else {          } else {
                 for(size_t row=0; row<size; row++) {                  for(size_t row=0; row<table.count(); row++) {
                         table.set_current(row);                          table.set_current(row);
     
                         if(rownum_var_name)                          if(rownum_var_name)
Line 1207  static void _join(Request& r, MethodPara Line 1280  static void _join(Request& r, MethodPara
   
         Table& dest=GET_SELF(r, VTable).table();          Table& dest=GET_SELF(r, VTable).table();
         if(&src == &dest)          if(&src == &dest)
                 throw Exception(PARSER_RUNTIME,                   throw Exception(PARSER_RUNTIME, 0, "source and destination are same table");
                         0,   
                         "source and destination are same table");  
   
         if(dest.columns()) // dest is named          if(dest.columns()) // dest is named
                 src.table_for_each(join_named_row, &dest, o);                  src.table_for_each(join_named_row, &dest, o);

Removed from v.1.315  
changed lines
  Added in v.1.323


E-mail: