optimizations to input class for reading very long lines

This commit is contained in:
Steve Plimpton
2022-06-29 15:10:03 -06:00
parent ae18e1e01c
commit 7546955046

View File

@ -188,17 +188,20 @@ of the file is reached. The *infile* pointer will usually point to
void Input::file() void Input::file()
{ {
int m,n; int m,n,mstart,ntriple,endfile;
while (true) { while (true) {
// read a line from input script // read a line from input script
// n = length of line including str terminator, 0 if end of file // when done, n = length of line including str terminator, 0 if end of file
// if line ends in continuation char '&', concatenate next line // if line ends in continuation char '&', concatenate next line
// if triple quotes are used, read until closing triple quotes
if (me == 0) { if (me == 0) {
ntriple = 0;
endfile = 0;
m = 0; m = 0;
while (true) { while (true) {
if (infile == nullptr) { if (infile == nullptr) {
@ -206,40 +209,60 @@ void Input::file()
break; break;
} }
mstart = m;
while (1) {
if (maxline-m < 2) reallocate(line,maxline,0); if (maxline-m < 2) reallocate(line,maxline,0);
// end of file reached, so break // end of file reached, so break
// n == 0 if nothing read, else n = line with str terminator // n == 0 if nothing read, else n = line with str terminator
if (fgets(&line[m],maxline-m,infile) == nullptr) { if (fgets(&line[m],maxline-m,infile) == nullptr) {
endfile = 1;
if (m) n = strlen(line) + 1; if (m) n = strlen(line) + 1;
else n = 0; else n = 0;
break; break;
} }
// continue if last char read was not a newline // continue if last char read was not a newline
// could happen if line is very long // can happen if line is very long
m = strlen(line); m += strlen(&line[m]);
if (line[m-1] != '\n') continue; if (line[m-1] != '\n') continue;
break;
}
// continue reading if final printable char is & char if (endfile) break;
// or if odd number of triple quotes
// else break with n = line with str terminator // add # of triple quotes in just-read line to ntriple
ntriple += numtriple(&line[mstart]);
// trim whitespace from end of line
// line[m] = last printable char
m--; m--;
while (m >= 0 && isspace(line[m])) m--; while (m >= 0 && isspace(line[m])) m--;
if (m < 0 || line[m] != '&') {
if (numtriple(line) % 2) { // continue reading if final printable char is "&"
if (m >= 0 && line[m] == '&') continue;
// continue reading if odd number of triple quotes
if (ntriple % 2) {
line[m+1] = '\n';
m += 2; m += 2;
continue; continue;
} }
// done, break with n = length of line with str terminator
line[m+1] = '\0'; line[m+1] = '\0';
n = m+2; n = m+2;
break; break;
} }
} }
}
// bcast the line // bcast the line
// if n = 0, end-of-file // if n = 0, end-of-file
@ -371,8 +394,9 @@ char *Input::one(const std::string &single)
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
Send text to active echo file pointers send text to active echo file pointers
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void Input::write_echo(const std::string &txt) void Input::write_echo(const std::string &txt)
{ {
if (me == 0) { if (me == 0) {
@ -399,34 +423,35 @@ void Input::parse()
if (n > maxcopy) reallocate(copy,maxcopy,n); if (n > maxcopy) reallocate(copy,maxcopy,n);
strcpy(copy,line); strcpy(copy,line);
// strip any # comment by replacing it with 0 // strip a # comment by replacing it with 0
// do not strip from a # inside single/double/triple quotes // do not treat a # inside single/double/triple quotes as a comment
// quoteflag = 1,2,3 when encounter first single/double,triple quote
// quoteflag = 0 when encounter matching single/double,triple quote
int quoteflag = 0; char *ptrmatch;
char *ptr = copy; char *ptr = copy;
while (*ptr) { while (*ptr) {
if (*ptr == '#' && !quoteflag) { if (*ptr == '#') {
*ptr = '\0'; *ptr = '\0';
break; break;
} }
if (quoteflag == 0) { if (*ptr == '\'') {
ptrmatch = strchr(ptr+1,'\'');
if (ptrmatch == NULL)
error->all(FLERR,"Unmatched single quote in command");
ptr = ptrmatch + 1;
} else if (*ptr == '"') {
if (strstr(ptr,"\"\"\"") == ptr) { if (strstr(ptr,"\"\"\"") == ptr) {
quoteflag = 3; ptrmatch = strstr(ptr+3,"\"\"\"");
ptr += 2; if (ptrmatch == NULL)
} error->all(FLERR,"Unmatched triple quote in command");
else if (*ptr == '"') quoteflag = 2; ptr = ptrmatch + 3;
else if (*ptr == '\'') quoteflag = 1;
} else { } else {
if (quoteflag == 3 && strstr(ptr,"\"\"\"") == ptr) { ptrmatch = strchr(ptr+1,'"');
quoteflag = 0; if (ptrmatch == NULL)
ptr += 2; error->all(FLERR,"Unmatched double quote in command");
ptr = ptrmatch + 1;
} }
else if (quoteflag == 2 && *ptr == '"') quoteflag = 0; } else ptr++;
else if (quoteflag == 1 && *ptr == '\'') quoteflag = 0;
}
ptr++;
} }
if (utils::has_utf8(copy)) { if (utils::has_utf8(copy)) {
@ -534,16 +559,18 @@ void Input::substitute(char *&str, char *&str2, int &max, int &max2, int flag)
{ {
// use str2 as scratch space to expand str, then copy back to str // use str2 as scratch space to expand str, then copy back to str
// reallocate str and str2 as necessary // reallocate str and str2 as necessary
// do not replace $ inside single/double/triple quotes // do not replace variables inside single/double/triple quotes
// var = pts at variable name, ended by null char // var = pts at variable name, ended by null char
// if $ is followed by '{', trailing '}' becomes null char // if $ is followed by '{', trailing '}' becomes null char
// else $x becomes x followed by null char // else $x becomes x followed by null char
// beyond = points to text following variable // beyond = points to text following variable
int i,n,paren_count; int i,n,paren_count,nchars;;
char immediate[256]; char immediate[256];
char *var,*value,*beyond; char *var,*value,*beyond;
int quoteflag = 0; int quoteflag = 0;
char *ptrmatch;
char *ptr = str; char *ptr = str;
n = strlen(str) + 1; n = strlen(str) + 1;
@ -637,34 +664,41 @@ void Input::substitute(char *&str, char *&str2, int &max, int &max2, int flag)
if (echo_log && logfile) fprintf(logfile,"%s%s\n",str2,beyond); if (echo_log && logfile) fprintf(logfile,"%s%s\n",str2,beyond);
} }
continue; // check for single/double/triple quotes and skip past them
}
// quoteflag = 1,2,3 when encounter first single/double,triple quote } else if (*ptr == '\'') {
// quoteflag = 0 when encounter matching single/double,triple quote ptrmatch = strchr(ptr+1,'\'');
// copy 2 extra triple quote chars into str2 if (ptrmatch == NULL)
error->all(FLERR,"Unmatched single quote in command");
if (quoteflag == 0) { nchars = ptrmatch+1 - ptr;
strncpy(ptr2,ptr,nchars);
ptr += nchars;
ptr2 += nchars;
} else if (*ptr == '"') {
if (strstr(ptr,"\"\"\"") == ptr) { if (strstr(ptr,"\"\"\"") == ptr) {
quoteflag = 3; ptrmatch = strstr(ptr+3,"\"\"\"");
*ptr2++ = *ptr++; if (ptrmatch == NULL)
*ptr2++ = *ptr++; error->all(FLERR,"Unmatched triple quote in command");
} nchars = ptrmatch+3 - ptr;
else if (*ptr == '"') quoteflag = 2; strncpy(ptr2,ptr,nchars);
else if (*ptr == '\'') quoteflag = 1; ptr += nchars;
ptr2 += nchars;
} else { } else {
if (quoteflag == 3 && strstr(ptr,"\"\"\"") == ptr) { ptrmatch = strchr(ptr+1,'"');
quoteflag = 0; if (ptrmatch == NULL)
*ptr2++ = *ptr++; error->all(FLERR,"Unmatched double quote in command");
*ptr2++ = *ptr++; nchars = ptrmatch+1 - ptr;
} strncpy(ptr2,ptr,nchars);
else if (quoteflag == 2 && *ptr == '"') quoteflag = 0; ptr += nchars;
else if (quoteflag == 1 && *ptr == '\'') quoteflag = 0; ptr2 += nchars;
} }
// copy current character into str2 // else copy current single character into str2
} else *ptr2++ = *ptr++;
// terminate current str2 so variable sub can perform strlen()
*ptr2++ = *ptr++;
*ptr2 = '\0'; *ptr2 = '\0';
} }