Mercurial > hg > octave-terminal
changeset 3640:d3b0ff09dda7
[project @ 2000-03-24 10:28:19 by jwe]
author | jwe |
---|---|
date | Fri, 24 Mar 2000 10:28:20 +0000 |
parents | fed1847dfd6c |
children | 5ac1b0cb4fe8 |
files | src/ChangeLog src/oct-stream.cc src/oct-stream.h |
diffstat | 3 files changed, 433 insertions(+), 375 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,35 @@ +2000-03-24 John W. Eaton <jwe@bevo.che.wisc.edu> + + * oct-stream.cc (printf_format_list::add_elt_to_list, + printf_format_list::process_conversion, + printf_format_list::finish_conversion): New args, flags, fw, and prec. + (printf_format_list::printf_format_list): Save more complete info. + (printf_format_list::printme): Print flags, fw, and prec. + (octave_base_stream::printf): Simplify. + (do_printf_conv): Delete have_arg arg, since it is always true now. + (octave_base_stream::do_printf): Handle case of no args and % + directly instead of using do_printf_conv. + (printf_value_cache::exhausted): Rename from no_more_values. + (DO_PCT_CONVERSION): New macro + (octave_base_streain::do_scanf, octave_base_streain::do_oscanf): + Use it. + (scanf_format_list::finish_conversion): `%' counts as a conversion too. + Also don't forget to set type for it. + (OCTAVE_SCAN_0): Delete. + (OCTAVE_SCAN): Rename from OCTAVE_SCAN_1. + (octave_base_stream::scanf, octave_base_stream::oscanf): Don't + special-case number of conversions here. + (octave_base_stream::oscanf, octave_base_stream::do_oscanf): Only + cycle through fmt elements if the number of conversions is greater + than 0. + + * oct-stream.h (scanf_format_list::next): New arg, `cycle'. + (printf_format_list::next): New arg, `cycle'. + (printf_format_list::last_elt_p): New function. + (printf_format_elt): New fields fw, prec, and flags. + Define copy constructor and assignment operator. + (scanf_format_elt): Define copy constructor and assignment operator. + 2000-03-23 John W. Eaton <jwe@bevo.che.wisc.edu> * oct-stream.cc (OCTAVE_SCAN_0, OCTAVE_SCAN_1): New macros.
--- a/src/oct-stream.cc +++ b/src/oct-stream.cc @@ -25,7 +25,6 @@ #endif #include <cassert> -#include <cstdarg> #include <cstring> #include <iomanip> @@ -268,8 +267,8 @@ list(num_elts++) = elt; } - else - delete [] text; + + delete [] text; } delete buf; @@ -423,13 +422,16 @@ std::string char_class; + int beg_idx = -1; + int end_idx = -1; + if (s[i] == '%') - *buf << s[i++]; + { + type = '%'; + *buf << s[i++]; + } else { - int beg_idx = -1; - int end_idx = -1; - type = s[i]; if (s[i] == '[') @@ -471,18 +473,17 @@ } else *buf << s[i++]; - - nconv++; - - if (nconv > 0) - { - 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); - } + } + + nconv++; + + if (nconv > 0) + { + 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; @@ -587,30 +588,53 @@ int i = 0; int args = 0; + string flags; + int fw = 0; + int prec = 0; char modifier = '\0'; char type = '\0'; bool have_more = true; + bool empty_buf = true; while (i < n) { have_more = true; if (! buf) - buf = new std::ostrstream (); + { + buf = new std::ostrstream (); + empty_buf = true; + } switch (s[i]) { case '%': - process_conversion (s, i, n, args, type, modifier, num_elts); - have_more = (buf != 0); + { + if (empty_buf) + { + process_conversion (s, i, n, args, flags, fw, prec, + type, modifier, num_elts); + + have_more = (buf != 0); + } + else + add_elt_to_list (args, flags, fw, prec, type, modifier, + num_elts); + } break; default: - args = 0; - modifier = '\0'; - type = '\0'; - *buf << s[i++]; + { + args = 0; + flags = ""; + fw = 0; + prec = 0; + modifier = '\0'; + type = '\0'; + *buf << s[i++]; + empty_buf = false; + } break; } @@ -622,7 +646,7 @@ } if (have_more) - add_elt_to_list (args, type, modifier, num_elts); + add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts); list.resize (num_elts); @@ -641,8 +665,9 @@ } void -printf_format_list::add_elt_to_list (int args, char type, char modifier, - int& num_elts) +printf_format_list::add_elt_to_list (int args, const std::string& flags, + int fw, int prec, char type, + char modifier, int& num_elts) { if (buf) { @@ -655,15 +680,16 @@ if (*text) { printf_format_elt *elt - = new printf_format_elt (text, args, type, modifier); + = new printf_format_elt (text, args, fw, prec, flags, + type, modifier); if (num_elts == list.length ()) list.resize (2 * num_elts); list(num_elts++) = elt; } - else - delete [] text; + + delete [] text; } delete buf; @@ -672,11 +698,14 @@ } void -printf_format_list::process_conversion (const std::string& s, int& i, int n, - int& args, char& modifier, - char& type, int& num_elts) +printf_format_list::process_conversion + (const std::string& s, int& i, int n, int& args, std::string& flags, + int& fw, int& prec, char& modifier, char& type, int& num_elts) { args = 0; + flags = ""; + fw = 0; + prec = 0; modifier = '\0'; type = '\0'; @@ -689,6 +718,7 @@ switch (s[i]) { case '-': case '+': case ' ': case '0': case '#': + flags += s[i]; *buf << s[i++]; break; @@ -705,11 +735,19 @@ { if (s[i] == '*') { + fw = -1; args++; *buf << s[i++]; } else { + if (isdigit (s[i])) + { + int n = 0; + string tmp = s.substr (i); + sscanf (tmp.c_str (), "%d%n", &fw, &n); + } + while (i < n && isdigit (s[i])) *buf << s[i++]; } @@ -723,11 +761,19 @@ { if (s[i] == '*') { + prec = -1; args++; *buf << s[i++]; } else { + if (isdigit (s[i])) + { + int n = 0; + string tmp = s.substr (i); + sscanf (tmp.c_str (), "%d%n", &prec, &n); + } + while (i < n && isdigit (s[i])) *buf << s[i++]; } @@ -749,15 +795,15 @@ } if (i < n) - finish_conversion (s, i, args, modifier, type, num_elts); + finish_conversion (s, i, args, flags, fw, prec, modifier, type, num_elts); else nconv = -1; } void -printf_format_list::finish_conversion (const std::string& s, int& i, - int args, char modifier, - char& type, int& num_elts) +printf_format_list::finish_conversion + (const std::string& s, int& i, int args, const std::string& flags, + int fw, int prec, char modifier, char& type, int& num_elts) { switch (s[i]) @@ -789,21 +835,18 @@ fini: - if (s[i] == '%' && args == 0) - *buf << s[i++]; - else - { - if (s[i] != '%') - args++; - - type = s[i]; - - *buf << s[i++]; - - add_elt_to_list (args, type, modifier, num_elts); - - nconv++; - } + type = s[i]; + + *buf << s[i++]; + + if (type != '%' || args != 0) + nconv++; + + if (type != '%') + args++; + + add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts); + break; default: @@ -821,10 +864,14 @@ { printf_format_elt *elt = list(i); - std::cerr << elt->args<< "\t" - << elt->type << "\t" - << elt->modifier << "\t" - << undo_string_escapes (elt->text) << "\n"; + std::cerr + << "args: " << elt->args << "\n" + << "flags: `" << elt->flags << "'\n" + << "width: " << elt->fw << "\n" + << "prec: " << elt->prec << "\n" + << "type: `" << elt->type << "'\n" + << "modifier: `" << elt->modifier << "'\n" + << "text: `" << undo_string_escapes (elt->text) << "'\n\n"; } } @@ -1009,28 +1056,18 @@ #if defined (__GNUG__) -#define OCTAVE_SCAN_0(is, fmt) is.scan ((fmt).text) - -#define OCTAVE_SCAN_1(is, fmt, arg) is.scan ((fmt).text, arg) +#define OCTAVE_SCAN(is, fmt, arg) is.scan ((fmt).text, arg) #else -#define OCTAVE_SCAN_0(is, fmt) octave_scan (is, fmt) - -#define OCTAVE_SCAN_1(is, fmt, arg) octave_scan (is, fmt, arg) - -std::istream& -octave_scan (std::istream& is, const scanf_format_elt& fmt) -{ - return is; -} +#define OCTAVE_SCAN(is, fmt, arg) octave_scan (is, fmt, arg) template <class T> std::istream& octave_scan (std::istream& is, const scanf_format_elt& fmt, T valptr) { - // Someone else will have to fix this code. I refuse to waste my - // time working on it when a reasonable alternative like + // Someone else who cares will have to fix this code. I refuse to + // waste my time working on it when a reasonable alternative like // istream::scan exists in the GNU iostream library. --jwe error ("formatted input only works when Octave is compiled with G++"); @@ -1069,7 +1106,7 @@ int& conversion_count, int nr, int max_size, bool discard) { - OCTAVE_SCAN_1 (is, fmt, valptr); + OCTAVE_SCAN (is, fmt, valptr); if (is) { @@ -1155,6 +1192,24 @@ } \ while (0) +#define DO_PCT_CONVERSION() \ + do \ + { \ + int c = is.get (); \ + \ + if (c != EOF) \ + { \ + if (c != '%') \ + { \ + is.putback (c); \ + is.setstate (std::ios::failbit); \ + } \ + } \ + else \ + is.setstate (std::ios::failbit); \ + } \ + while (0) + #define BEGIN_C_CONVERSION() \ is.unsetf (std::ios::skipws); \ \ @@ -1183,7 +1238,7 @@ { \ tmp = new char [width+1]; \ \ - OCTAVE_SCAN_1 (is, *elt, tmp); \ + OCTAVE_SCAN (is, *elt, tmp); \ \ tmp[width] = '\0'; \ } \ @@ -1224,7 +1279,7 @@ { \ tmp = new char[width+1]; \ \ - OCTAVE_SCAN_1 (is, *elt, tmp); \ + OCTAVE_SCAN (is, *elt, tmp); \ \ tmp[width] = '\0'; \ } \ @@ -1310,6 +1365,8 @@ { conversion_count = 0; + int nconv = fmt_list.num_conversions (); + int data_index = 0; octave_value retval = Matrix (); @@ -1435,11 +1492,7 @@ break; case '%': - { - int dummy; - - OCTAVE_SCAN_1 (is, *elt, &dummy); - } + DO_PCT_CONVERSION (); break; case 'd': case 'i': case 'o': case 'u': case 'x': @@ -1591,7 +1644,7 @@ break; } - elt = fmt_list.next (); + elt = fmt_list.next (nconv > 0); } } @@ -1620,66 +1673,22 @@ if (isp) { - std::istream& is = *isp; - scanf_format_list fmt_list (fmt); - switch (fmt_list.num_conversions ()) + if (fmt_list.num_conversions () == -1) + ::error ("fscanf: invalid format specified"); + else { - case -1: - ::error ("fscanf: invalid format specified"); - break; - - case 0: - { - const scanf_format_elt *elt = fmt_list.first (); - - if (elt) - { - is.clear (); - - OCTAVE_SCAN_0 (is, *elt); - - if (! is) - { - // If it looks like we have a matching failure, then - // reset the failbit in the stream state. - - if (is.rdstate () & std::ios::failbit) - is.clear (is.rdstate () & (~std::ios::failbit)); - else - 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; - do_gets (-1, err, false, "fscanf"); - } - } - } - } - break; - - default: - { - int nr = -1; - int nc = -1; - - bool one_elt_size_spec; - - get_size (size, nr, nc, one_elt_size_spec, "fscanf"); - - if (! error_state) - retval = do_scanf (fmt_list, nr, nc, one_elt_size_spec, - conversion_count); - } - break; + int nr = -1; + int nc = -1; + + bool one_elt_size_spec; + + get_size (size, nr, nc, one_elt_size_spec, "fscanf"); + + if (! error_state) + retval = do_scanf (fmt_list, nr, nc, one_elt_size_spec, + conversion_count); } } else @@ -1720,10 +1729,11 @@ case '%': { - int dummy; - - if (! OCTAVE_SCAN_1 (is, *elt, &dummy)) + DO_PCT_CONVERSION (); + + if (! is) quit = true; + } break; @@ -1731,7 +1741,7 @@ { int tmp; - if (OCTAVE_SCAN_1 (is, *elt, &tmp)) + if (OCTAVE_SCAN (is, *elt, &tmp)) { if (! discard) retval = static_cast<double> (tmp); @@ -1745,7 +1755,7 @@ { double tmp; - if (OCTAVE_SCAN_1 (is, *elt, &tmp)) + if (OCTAVE_SCAN (is, *elt, &tmp)) { if (! discard) retval = tmp; @@ -1843,88 +1853,53 @@ int nconv = fmt_list.num_conversions (); - switch (nconv) + if (nconv == -1) + ::error ("fscanf: invalid format specified"); + else { - case -1: - ::error ("fscanf: invalid format specified"); - break; - - case 0: - { - const scanf_format_elt *elt = fmt_list.first (); - - if (elt) - { - is.clear (); - - OCTAVE_SCAN_0 (is, *elt); - - if (! is) - { - 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; - do_gets (-1, err, false, "fscanf"); - } - } - } - } - break; - - default: - { - is.clear (); - - int len = fmt_list.length (); - - retval.resize (nconv+1, Matrix ()); - - const scanf_format_elt *elt = fmt_list.first (); - - int num_values = 0; - - bool quit = false; - - for (int i = 0; i < len; i++) - { - octave_value tmp; - - quit = do_oscanf (elt, tmp); - - if (quit) - break; - else - { - if (tmp.is_defined ()) - retval (num_values++) = tmp; - - if (! ok ()) - break; - elt = fmt_list.next (); - } - } - - retval (nconv) = static_cast<double> (num_values); - - if (! quit) - { - // Pick up any trailing stuff. - if (ok () && len > nconv) - { - octave_value tmp; - do_oscanf (elt, tmp); - } - } - } - break; + is.clear (); + + int len = fmt_list.length (); + + retval.resize (nconv+1, Matrix ()); + + const scanf_format_elt *elt = fmt_list.first (); + + int num_values = 0; + + bool quit = false; + + for (int i = 0; i < len; i++) + { + octave_value tmp; + + quit = do_oscanf (elt, tmp); + + if (quit) + break; + else + { + if (tmp.is_defined ()) + retval (num_values++) = tmp; + + if (! ok ()) + break; + + elt = fmt_list.next (nconv > 0); + } + } + + retval (nconv) = static_cast<double> (num_values); + + if (! quit) + { + // Pick up any trailing stuff. + if (ok () && len > nconv) + { + octave_value tmp; + do_oscanf (elt, tmp); + } + } } } else @@ -2015,7 +1990,8 @@ operator bool () const { return (curr_state == ok); } - bool no_more_values (void) { return curr_state == list_exhausted; } + bool exhausted (void) + { return (curr_state == list_exhausted || val_idx + 1 >= n_vals); } bool looking_at_string (void); @@ -2159,31 +2135,22 @@ template <class T> int do_printf_conv (std::ostream& os, const char *fmt, int nsa, int sa_1, - int sa_2, bool have_arg, T arg) + int sa_2, T arg) { int retval = 0; switch (nsa) { case 2: - if (have_arg) - retval = octave_format (os, fmt, sa_1, sa_2, arg); - else - retval = octave_format (os, fmt, sa_1, sa_2); + retval = octave_format (os, fmt, sa_1, sa_2, arg); break; case 1: - if (have_arg) - retval = octave_format (os, fmt, sa_1, arg); - else - retval = octave_format (os, fmt, sa_1); + retval = octave_format (os, fmt, sa_1, arg); break; case 0: - if (have_arg) - retval = octave_format (os, fmt, arg); - else - retval = octave_format (os, fmt); + retval = octave_format (os, fmt, arg); break; default: @@ -2195,16 +2162,16 @@ } template int -do_printf_conv (std::ostream&, const char*, int, int, int, bool, int); - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, bool, long); - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, bool, double); - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, bool, const char*); +do_printf_conv (std::ostream&, const char*, int, int, int, int); + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, long); + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, double); + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, const char*); int octave_base_stream::do_printf (printf_format_list& fmt_list, @@ -2212,6 +2179,8 @@ { int retval = 0; + int nconv = fmt_list.num_conversions (); + std::ostream *osp = output_stream (); if (osp) @@ -2226,13 +2195,9 @@ { if (elt) { - int args = elt->args; - int nsa = args; - - int doing_percent = elt->type == '%'; - - if (args > 0 && ! doing_percent) - nsa--; + // NSA is the number of `star' args to convert. + + int nsa = (elt->fw < 0) + (elt->prec < 0); int sa_1 = 0; int sa_2 = 0; @@ -2257,70 +2222,67 @@ const char *fmt = elt->text; - if (doing_percent || args == 0) - retval += do_printf_conv (os, fmt, nsa, sa_1, sa_2, - false, 0.0); + if (elt->type == '%') + { + os << "%"; + retval++; + } + else if (elt->args == 0 && elt->text) + { + os << elt->text; + retval += strlen (elt->text); + } + else if (elt->type == 's' && val_cache.looking_at_string ()) + { + std::string val = val_cache.string_value (); + + if (val_cache) + retval += do_printf_conv (os, fmt, nsa, sa_1, + sa_2, val.c_str ()); + else + break; + } else { - if (elt->type == 's' && val_cache.looking_at_string ()) + double val = val_cache.double_value (); + + if (val_cache) { - std::string val = val_cache.string_value (); - - if (val_cache) - retval += do_printf_conv (os, fmt, nsa, sa_1, - sa_2, true, val.c_str ()); - else - break; + switch (elt->type) + { + case 'd': case 'i': case 'o': case 'x': + case 'X': case 'u': case 'c': + { + if (elt->modifier == 'l') + retval + += do_printf_conv (os, fmt, nsa, sa_1, sa_2, + static_cast<long> (val)); + else + retval + += do_printf_conv (os, fmt, nsa, sa_1, sa_2, + static_cast<int> (val)); + } + break; + + case 'f': case 'e': case 'E': + case 'g': case 'G': + retval + += do_printf_conv (os, fmt, nsa, sa_1, sa_2, val); + break; + + default: + error ("fprintf: invalid format specifier"); + return -1; + break; + } } else - { - double val = val_cache.double_value (); - - if (val_cache) - { - switch (elt->type) - { - case 'd': case 'i': case 'o': case 'x': - case 'X': case 'u': case 'c': - { - if (elt->modifier == 'l') - retval - += do_printf_conv (os, fmt, nsa, - sa_1, sa_2, true, - static_cast<long> (val)); - else - retval - += do_printf_conv (os, fmt, nsa, - sa_1, sa_2, true, - static_cast<int> (val)); - } - break; - - case 'f': case 'e': case 'E': - case 'g': case 'G': - retval - += do_printf_conv (os, fmt, nsa, sa_1, - sa_2, true, val); - break; - - default: - error ("fprintf: invalid format specifier"); - return -1; - break; - } - } - else - break; - } - - if (val_cache.no_more_values ()) break; } if (! os) { error ("fprintf: write error"); - retval = -1; break; } } @@ -2331,61 +2293,30 @@ break; } - elt = fmt_list.next (); - } + elt = fmt_list.next (nconv > 0 && ! val_cache.exhausted ()); + + if (! elt || (val_cache.exhausted () && elt->args > 0)) + break; + } } + else + invalid_operation ("fprintf", "writing"); return retval; } int -octave_base_stream::printf (const std::string& fmt, const octave_value_list& args) +octave_base_stream::printf (const std::string& fmt, + const octave_value_list& args) { - int retval = -1; - - std::ostream *osp = output_stream (); - - if (osp) - { - std::ostream& os = *osp; - - printf_format_list fmt_list (fmt); - - switch (fmt_list.num_conversions ()) - { - case -1: - ::error ("fprintf: invalid format specified"); - break; - - case 0: - { - const printf_format_elt *elt = fmt_list.first (); - - if (elt) - { - retval = octave_format (os, elt->text); - - if (! os) - { - retval = -1; - error ("fprintf: write error"); - } - } - } - break; - - default: - { - if (args.length () == 0) - ::error ("fprintf: no arguments available for specified format"); - else - retval = do_printf (fmt_list, args); - } - break; - } - } + int retval = 0; + + printf_format_list fmt_list (fmt); + + if (fmt_list.num_conversions () == -1) + ::error ("fprintf: invalid format specified"); else - invalid_operation ("fprintf", "writing"); + retval = do_printf (fmt_list, args); return retval; }
--- a/src/oct-stream.h +++ b/src/oct-stream.h @@ -34,11 +34,14 @@ #include "Array.h" #include "data-conv.h" +#include "lo-utils.h" #include "mach-info.h" -struct +class scanf_format_elt { +public: + enum special_conversion { whitespace_conversion = 1, @@ -48,16 +51,47 @@ scanf_format_elt (const char *txt = 0, int w = 0, bool d = false, char typ = '\0', char mod = '\0', const std::string& ch_class = std::string ()) - : text (txt), width (w), discard (d), type (typ), modifier (mod), - char_class (ch_class) { } + : text (strsave (txt)), width (w), discard (d), type (typ), + modifier (mod), char_class (ch_class) { } + + scanf_format_elt (const scanf_format_elt& e) + : text (strsave (e.text)), width (e.width), discard (e.discard), + type (e.type), modifier (e.modifier), char_class (e.char_class) { } - ~scanf_format_elt (void) { delete text; } + scanf_format_elt& operator = (const scanf_format_elt& e) + { + if (this != &e) + { + text = strsave (e.text); + width = e.width; + discard = e.discard; + type = e.type; + modifier = e.modifier; + char_class = e.char_class; + } + return *this; + } + + ~scanf_format_elt (void) { delete [] text; } + + // The C-style format string. const char *text; + + // The maximum field width. int width; + + // TRUE if we are not storing the result of this conversion. bool discard; + + // Type of conversion -- `d', `i', `o', `u', `x', `e', `f', `g', + // `c', `s', `p', `%', or `['. char type; + + // A length modifier -- `h', `l', or `L'. char modifier; + + // The class of characters in a `[' format. std::string char_class; }; @@ -88,11 +122,17 @@ const scanf_format_elt *current (void) const { return list.length () > 0 ? list.elem (curr_idx) : 0; } - const scanf_format_elt *next (void) + const scanf_format_elt *next (bool cycle = true) { curr_idx++; + if (curr_idx >= list.length ()) - curr_idx = 0; + { + if (cycle) + curr_idx = 0; + else + return 0; + } return current (); } @@ -122,7 +162,8 @@ std::ostrstream *buf; void add_elt_to_list (int width, bool discard, char type, char modifier, - int& num_elts, const std::string& char_class = std::string ()); + int& num_elts, + const std::string& char_class = std::string ()); void process_conversion (const std::string& s, int& i, int n, int& width, bool& discard, char& type, char& modifier, @@ -138,18 +179,59 @@ scanf_format_list& operator = (const scanf_format_list&); }; -struct +class printf_format_elt { - printf_format_elt (const char *txt = 0, int n = 0, char typ = '\0', - char mod = '\0') - : text (txt), args (n), type (typ), modifier (mod) { } +public: + + printf_format_elt (const char *txt = 0, int n = 0, int w = 0, + int p = 0, const std::string& f = std::string (), + char typ = '\0', char mod = '\0') + : text (strsave (txt)), args (n), fw (w), prec (p), flags (f), + type (typ), modifier (mod) { } + + printf_format_elt (const printf_format_elt& e) + : text (strsave (e.text)), args (e.args), fw (e.fw), prec (e.prec), + flags (e.flags), type (e.type), modifier (e.modifier) { } + + printf_format_elt& operator = (const printf_format_elt& e) + { + if (this != &e) + { + text = strsave (e.text); + args = e.args; + fw = e.fw; + prec = e.prec; + flags = e.flags; + type = e.type; + modifier = e.modifier; + } - ~printf_format_elt (void) { delete text; } + return *this; + } + ~printf_format_elt (void) { delete [] text; } + + // The C-style format string. const char *text; + + // How many args do we expect to consume? int args; + + // Field width. + int fw; + + // Precision. + int prec; + + // Flags -- `-', `+', ` ', `0', or `#'. + string flags; + + // Type of conversion -- `d', `i', `o', `x', `X', `u', `c', `s', + // `f', `e', `E', `g', `G', `p', or `%' char type; + + // A length modifier -- `h', `l', or `L'. char modifier; }; @@ -173,14 +255,23 @@ const printf_format_elt *current (void) const { return list.length () > 0 ? list.elem (curr_idx) : 0; } - const printf_format_elt *next (void) + const printf_format_elt *next (bool cycle = true) { curr_idx++; + if (curr_idx >= list.length ()) - curr_idx = 0; + { + if (cycle) + curr_idx = 0; + else + return 0; + } + return current (); } + bool last_elt_p (void) { return (curr_idx + 1 == list.length ()); } + void printme (void) const; bool ok (void) const { return (nconv >= 0); } @@ -202,13 +293,17 @@ // Temporary buffer. std::ostrstream *buf; - void add_elt_to_list (int args, char type, char modifier, - int& num_elts); - - void process_conversion (const std::string& s, int& i, int n, int& args, - char& modifier, char& type, int& num_elts); - + void add_elt_to_list (int args, const std::string& flags, int fw, + int prec, char type, char modifier, + int& num_elts); + + void process_conversion (const std::string& s, int& i, int n, + int& args, std::string& flags, int& fw, + int& prec, char& modifier, char& type, + int& num_elts); + void finish_conversion (const std::string& s, int& i, int args, + const std::string& flags, int fw, int prec, char modifier, char& type, int& num_elts); // No copying!