# HG changeset patch # User jwe # Date 948929831 0 # Node ID 1bb6e519a4a2bc9f5e9c6bf90aad234e829b0464 # Parent e461b8ed7c4dfef35c6c37102b24e8a80285d8e4 [project @ 2000-01-26 23:37:10 by jwe] diff --git a/scripts/ChangeLog b/scripts/ChangeLog --- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,8 @@ +2000-01-26 John W. Eaton + + * miscellaneous/popen2.m: Deal with the fact that pipe now returns + a list of file structures, not a vector of numeric file ids. + 2000-01-25 John W. Eaton * plot/__axis_label__.m: New function. diff --git a/scripts/miscellaneous/popen2.m b/scripts/miscellaneous/popen2.m --- a/scripts/miscellaneous/popen2.m +++ b/scripts/miscellaneous/popen2.m @@ -71,14 +71,14 @@ if (pid == 0) - fclose (stdin_pipe (2)); - fclose (stdout_pipe (1)); + fclose (nth (stdin_pipe, 2)); + fclose (nth (stdout_pipe, 1)); - dup2 (stdin_pipe (1), stdin); - fclose (stdin_pipe (1)); + dup2 (nth (stdin_pipe, 1), stdin); + fclose (nth (stdin_pipe, 1)); - dup2 (stdout_pipe (2), stdout); - fclose (stdout_pipe (2)); + dup2 (nth (stdout_pipe, 2), stdout); + fclose (nth (stdout_pipe, 2)); if (exec (command, args) < 0) error ("popen2: unable to start process `%s'", command); @@ -87,14 +87,14 @@ elseif (pid) - fclose (stdin_pipe (1)); - fclose (stdout_pipe (2)); + fclose (nth (stdin_pipe, 1)); + fclose (nth (stdout_pipe, 2)); - if (fcntl (stdout_pipe (1), __F_SETFL__, __O_NONBLOCK__) < 0) + if (fcntl (nth (stdout_pipe, 1), __F_SETFL__, __O_NONBLOCK__) < 0) error ("popen2: error setting file mode"); else - in = stdin_pipe (2); - out = stdout_pipe (1); + in = nth (stdin_pipe, 2); + out = nth (stdout_pipe, 1); endif elseif (pid < 0) diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,29 @@ +2000-01-26 John W. Eaton + + * oct-stream.h (scanf_format_elt::char_class): New struct elt. + Add arg to constructor. + (scanf_format_elt::special_conversion): New enum. + * oct-stream.cc (scanf_format_list::add_elt_to_list): New arg, + char_class. Pass it to scanf_format_elt constructor. + (scanf_format_list::scanf_format_list): Create separate list + elements for whitespace and literal conversions. + (expand_char_class): New function. + (scanf_format_list::finish_conversion): Extract character class + (not including the delimiting brackets) and expand the list of + characters. Pass the result to add_elt_to_list. + (scanf_format_list::all_character_conversions): Also accept '^', + scanf_format_elt::literal_conversion, and + scanf_format_elt::whitespace_conversion types too. + (DO_WHITESPACE_CONVERSION, BEGIN_CHAR_CLASS_CONVERSION, + BEGIN_C_CONVERSION, BEGIN_S_CONVERSION, DO_LITERAL_CONVERSION): + New macros. + (octave_base_stream::do_scanf, octave_base_stream::do_oscanf): + Use them to avoid code duplication. + Handle whitespace, literal text, and character class conversions. + (octave_base_stream::oscanf): Loop over all format list elements, + not just the first nconv elements. Clear status flags on is for + all streams. + 2000-01-25 John W. Eaton * xdiv.cc (result_ok): Just check value of info. diff --git a/src/oct-stream.cc b/src/oct-stream.cc --- a/src/oct-stream.cc +++ b/src/oct-stream.cc @@ -177,17 +177,42 @@ if (s[i] == '%') { + // Process percent-escape conversion type. + process_conversion (s, i, n, width, discard, type, modifier, num_elts); have_more = (buf != 0); } - else + else if (isspace (s[i])) { + type = scanf_format_elt::whitespace_conversion; + width = 0; discard = false; modifier = '\0'; - type = '\0'; - *buf << s[i++]; + *buf << " "; + + while (++i < n && isspace (s[i])) + /* skip whitespace */; + + add_elt_to_list (width, discard, type, modifier, num_elts); + + have_more = false; + } + else + { + type = scanf_format_elt::literal_conversion; + + width = 0; + discard = false; + modifier = '\0'; + + while (i < n && ! isspace (s[i]) && s[i] != '%') + *buf << s[i++]; + + add_elt_to_list (width, discard, type, modifier, num_elts); + + have_more = false; } if (nconv < 0) @@ -218,7 +243,8 @@ void scanf_format_list::add_elt_to_list (int width, bool discard, char type, - char modifier, int& num_elts) + char modifier, int& num_elts, + const string& char_class) { if (buf) { @@ -231,7 +257,8 @@ if (*text) { scanf_format_elt *elt - = new scanf_format_elt (text, width, discard, type, modifier); + = new scanf_format_elt (text, width, discard, type, + modifier, char_class); if (num_elts == list.length ()) list.resize (2 * num_elts); @@ -247,11 +274,45 @@ } } +static string +expand_char_class (const string& s) +{ + string retval; + + size_t len = s.length (); + + size_t i = 0; + + while (i < len) + { + unsigned char c = s[i++]; + + if (c == '-' && i > 1 && i < len + && (unsigned char) s[i-2] <= (unsigned char) s[i]) + { + // Add all characters from the range except the first (we + // already added it below). + + for (c = s[i-2]+1; c < s[i]; c++) + retval += c; + } + else + { + // Add the character to the class. Only add '-' if it is + // the last character in the class. + + if (c != '-' || i == len) + retval += c; + } + } + + return retval; +} + void scanf_format_list::process_conversion (const string& s, int& i, int n, int& width, bool& discard, char& type, char& modifier, int& num_elts) - { width = 0; discard = false; @@ -357,10 +418,15 @@ { int retval = 0; + string char_class; + if (s[i] == '%') *buf << s[i++]; else { + int beg_idx = -1; + int end_idx = -1; + type = s[i]; if (s[i] == '[') @@ -369,10 +435,20 @@ if (i < n) { + beg_idx = i; + if (s[i] == '^') { type = '^'; *buf << s[i++]; + + if (i < n) + { + beg_idx = i; + + if (s[i] == ']') + *buf << s[i++]; + } } else if (s[i] == ']') *buf << s[i++]; @@ -382,7 +458,10 @@ *buf << s[i++]; if (i < n && s[i] == ']') - *buf << s[i++]; + { + end_idx = i-1; + *buf << s[i++]; + } if (s[i-1] != ']') retval = nconv = -1; @@ -393,7 +472,14 @@ nconv++; if (nconv > 0) - add_elt_to_list (width, discard, type, modifier, num_elts); + { + if (beg_idx >= 0 && end_idx >= 0) + char_class = expand_char_class (s.substr (beg_idx, + end_idx - beg_idx +1)); + + add_elt_to_list (width, discard, type, modifier, num_elts, + char_class); + } } return retval; @@ -408,11 +494,20 @@ { scanf_format_elt *elt = list(i); - cerr << elt->width << "\t" - << elt->discard << "\t" - << elt->type << "\t" - << elt->modifier << "\t" - << undo_string_escapes (elt->text) << "\n"; + cerr << "width: " << elt->width << "\n" + << "discard: " << elt->discard << "\n" + << "type: "; + + if (elt->type == scanf_format_elt::literal_conversion) + cerr << "literal text\n"; + else if (elt->type == scanf_format_elt::whitespace_conversion) + cerr << "whitespace\n"; + else + cerr << elt->type << "\n"; + + cerr << "modifier: " << elt->modifier << "\n" + << "char_class: `" << undo_string_escapes (elt->char_class) << "'\n" + << "text: `" << undo_string_escapes (elt->text) << "'\n\n"; } } @@ -429,7 +524,9 @@ switch (elt->type) { - case 'c': case 's': case '%': case '[': + case 'c': case 's': case '%': case '[': case '^': + case scanf_format_elt::literal_conversion: + case scanf_format_elt::whitespace_conversion: break; default: @@ -956,6 +1053,153 @@ do_scanf_conv (istream&, const char*, double*, Matrix&, double*, int&, int&, int, int, bool); +#define DO_WHITESPACE_CONVERSION() \ + do \ + { \ + int c = EOF; \ + \ + while (is && (c = is.get ()) != EOF && isspace (c)) \ + /* skip whitespace */; \ + \ + if (c != EOF) \ + is.putback (c); \ + } \ + while (0) + +#define DO_LITERAL_CONVERSION() \ + do \ + { \ + int c = EOF; \ + \ + int n = strlen (fmt); \ + int i = 0; \ + \ + while (i < n && is && (c = is.get ()) != EOF) \ + { \ + if (c == fmt[i]) \ + { \ + i++; \ + continue; \ + } \ + else \ + { \ + is.putback (c); \ + break; \ + } \ + } \ + \ + if (i != n) \ + is.setstate (ios::failbit); \ + } \ + while (0) + +#define BEGIN_C_CONVERSION() \ + is.unsetf (ios::skipws); \ + \ + int width = elt->width ? elt->width : 1; \ + \ + char *tmp = new char[width + 1]; \ + \ + int c = EOF; \ + int n = 0; \ + \ + while (is && n < width && (c = is.get ()) != EOF) \ + tmp[n++] = (char) c; \ + \ + tmp[n] = '\0' + +// For a `%s' format, skip initial whitespace and then read until the +// next whitespace character. +#define BEGIN_S_CONVERSION() \ + int width = elt->width; \ + \ + char *tmp = 0; \ + \ + do \ + { \ + if (width) \ + { \ + tmp = new char [width+1]; \ + \ + is.scan (fmt, tmp); \ + \ + tmp[width] = '\0'; \ + } \ + else \ + { \ + ostrstream buf; \ + \ + int c = EOF; \ + \ + while (is && (c = is.get ()) != EOF && isspace (c)) \ + /* skip leading whitespace */; \ + \ + if (is && c != EOF) \ + buf << (char) c; \ + \ + while (is && (c = is.get ()) != EOF && ! isspace (c)) \ + buf << (char) c; \ + \ + if (isspace (c)) \ + is.putback (c); \ + \ + buf << ends; \ + \ + tmp = buf.str (); \ + } \ + } \ + while (0) + +// This format must match a nonempty sequence of characters. +#define BEGIN_CHAR_CLASS_CONVERSION() \ + int width = elt->width; \ + \ + char *tmp = 0; \ + \ + do \ + { \ + if (width) \ + { \ + tmp = new char[width+1]; \ + \ + is.scan (fmt, tmp); \ + \ + tmp[width] = '\0'; \ + } \ + else \ + { \ + ostrstream buf; \ + \ + string char_class = elt->char_class; \ + \ + int c = EOF; \ + \ + if (elt->type == '[') \ + { \ + while (is && (c = is.get ()) != EOF \ + && char_class.find (c) != NPOS) \ + buf << (char) c; \ + } \ + else \ + { \ + while (is && (c = is.get ()) != EOF \ + && char_class.find (c) == NPOS) \ + buf << (char) c; \ + } \ + \ + if (c != EOF) \ + is.putback (c); \ + \ + buf << ends; \ + \ + tmp = buf.str (); \ + \ + if (strlen (tmp) == 0) \ + is.setstate (ios::failbit); \ + } \ + } \ + while (0) + #define FINISH_CHARACTER_CONVERSION() \ do \ { \ @@ -1120,13 +1364,21 @@ switch (elt->type) { + case scanf_format_elt::whitespace_conversion: + DO_WHITESPACE_CONVERSION (); + break; + + case scanf_format_elt::literal_conversion: + DO_LITERAL_CONVERSION (); + break; + case '%': { int dummy; is.scan (fmt, &dummy); } - break; + break; case 'd': case 'i': case 'o': case 'u': case 'x': { @@ -1139,7 +1391,7 @@ data_index, conversion_count, nr, max_size, discard); } - break; + break; case 'l': { @@ -1148,7 +1400,7 @@ data_index, conversion_count, nr, max_size, discard); } - break; + break; default: { @@ -1157,10 +1409,10 @@ data_index, conversion_count, nr, max_size, discard); } - break; + break; } } - break; + break; case 'e': case 'f': case 'g': { @@ -1170,76 +1422,35 @@ data_index, conversion_count, nr, max_size, discard); } - break; + break; case 'c': { - is.unsetf (ios::skipws); - - int width = elt->width; - - if (width == 0) - width = 1; - - char *tmp = new char[width+1]; - - int c = EOF; - int n = 0; - - while (is && n < width && (c = is.get ()) != EOF) - tmp[n++] = (char) c; - - tmp[n] = '\0'; + BEGIN_C_CONVERSION (); FINISH_CHARACTER_CONVERSION (); + + is.setf (flags); } break; case 's': { - int width = elt->width; - - char *tmp = 0; - - if (width) - { - tmp = new char [width+1]; - - is.scan (fmt, tmp); - - tmp[width] = '\0'; - } - else - { - // We're looking at a `%s' format. We have to - // skip initial whitespace and then read until - // the next whitespace character. - - ostrstream buf; - - int c = EOF; - - while (is && (c = is.get ()) != EOF && isspace (c)) - /* skip leading whitespace */; - - if (is && c != EOF) - buf << (char) c; - - while (is && (c = is.get ()) != EOF && ! isspace (c)) - buf << (char) c; - - buf << ends; - - tmp = buf.str (); - } + BEGIN_S_CONVERSION (); FINISH_CHARACTER_CONVERSION (); - - is.setf (flags); } - break; - - case 'p': case '[': + break; + + case '[': case '^': + { + BEGIN_CHAR_CLASS_CONVERSION (); + + FINISH_CHARACTER_CONVERSION (); + } + break; + + case 'p': error ("fscanf: unsupported format specifier"); break; @@ -1436,6 +1647,14 @@ switch (elt->type) { + case scanf_format_elt::whitespace_conversion: + DO_WHITESPACE_CONVERSION (); + break; + + case scanf_format_elt::literal_conversion: + DO_LITERAL_CONVERSION (); + break; + case '%': { int dummy; @@ -1475,69 +1694,26 @@ case 'c': { - is.unsetf (ios::skipws); - - int width = elt->width ? elt->width : 1; - - char *tmp = new char[width + 1]; - - if (is.scan (fmt, tmp)) - { - if (! discard) - { - tmp[width] = '\0'; - retval = tmp; - } - } - else + BEGIN_C_CONVERSION (); + + if (! discard) + retval = tmp; + + delete [] tmp; + + if (! is) quit = true; is.setf (flags); - - delete [] tmp; } break; case 's': { - int width = elt->width; - - char *tmp = 0; - - if (width) - { - tmp = new char [width+1]; - - is.scan (fmt, tmp); - - tmp[width] = '\0'; - } - else - { - // We're looking at a `%s' format. We have to - // skip initial whitespace and then read until - // the next whitespace character. - - ostrstream buf; - - int c = EOF; - - while (is && (c = is.get ()) != EOF && isspace (c)) - /* skip leading whitespace */; - - if (is && c != EOF) - buf << (char) c; - - while (is && (c = is.get ()) != EOF && ! isspace (c)) - buf << (char) c; - - buf << ends; - - tmp = buf.str (); - - if (! discard) - retval = tmp; - } + BEGIN_S_CONVERSION (); + + if (! discard) + retval = tmp; delete [] tmp; @@ -1546,7 +1722,21 @@ } break; - case 'p': case '[': + case '[': case '^': + { + BEGIN_CHAR_CLASS_CONVERSION (); + + if (! discard) + retval = tmp; + + delete [] tmp; + + if (! is) + quit = true; + } + break; + + case 'p': error ("fscanf: unsupported format specifier"); break; @@ -1559,13 +1749,11 @@ if (ok () && is.fail ()) { error ("fscanf: read error"); - + // XXX FIXME XXX -- is this the right thing to do? if (interactive && name () == "stdin") { - is.clear (); - // Skip to end of line. bool err; @@ -1630,6 +1818,8 @@ default: { + is.clear (); + int len = fmt_list.length (); retval.resize (nconv, Matrix ()); @@ -1640,7 +1830,7 @@ bool quit = false; - for (int i = 0; i < nconv; i++) + for (int i = 0; i < len; i++) { octave_value tmp; diff --git a/src/oct-stream.h b/src/oct-stream.h --- a/src/oct-stream.h +++ b/src/oct-stream.h @@ -41,9 +41,17 @@ struct scanf_format_elt { + enum special_conversion + { + whitespace_conversion = 1, + literal_conversion = 2 + }; + scanf_format_elt (const char *txt = 0, int w = 0, bool d = false, - char typ = '\0', char mod = '\0') - : text (txt), width (w), discard (d), type (typ), modifier (mod) { } + char typ = '\0', char mod = '\0', + const string& ch_class = string ()) + : text (txt), width (w), discard (d), type (typ), modifier (mod), + char_class (ch_class) { } ~scanf_format_elt (void) { delete text; } @@ -52,6 +60,7 @@ bool discard; char type; char modifier; + string char_class; }; class @@ -115,7 +124,7 @@ ostrstream *buf; void add_elt_to_list (int width, bool discard, char type, char modifier, - int& num_elts); + int& num_elts, const string& char_class = string ()); void process_conversion (const string& s, int& i, int n, int& width, bool& discard, char& type, char& modifier,