/* * Scanf code. Extend File namespace with reading code */ extend namespace File { public int vfscanf (file f, string format, (*poly)[*] args) /* * According to 'format', read from 'f' to 'args' */ { /* Skip whitespace */ void whitespace () { int c; while (Ctype::isspace (c = File::getc (f))) ; File::ungetc (c, f); } bool isbinary (int c) { if ('0' <= c && c <= '1') return true; if (c == '-') return true; return false; } bool isoctal (int c) { if ('0' <= c && c <= '7') return true; if (c == '-') return true; return false; } bool isdecimal (int c) { if ('0' <= c && c <= '9') return true; if (c == '-') return true; return false; } bool ishex (int c) { if ('0' <= c && c <= '9') return true; if ('a' <= c && c <= 'f') return true; if ('A' <= c && c <= 'F') return true; if (c == '-') return true; return false; } bool isfloat (int c) { if ('0' <= c && c <= '9') return true; if (c == 'e') return true; if (c == '-') return true; if (c == '.') return true; if (c == '{' || c == '}') return true; return false; } /* return next integer in input */ int integer (bool(int c) test, int base) { int c; string s; whitespace(); s = ""; while (test (c = File::getc (f))) s = s + String::new(c); File::ungetc (c, f); return string_to_integer (s, base); } /* return next number in input */ real number (bool(int c) test) { int c; string s; whitespace(); s = ""; while (test (c = File::getc (f))) s = s + String::new(c); File::ungetc (c, f); return string_to_real (s); } string word () { int c; string s; whitespace(); s = ""; while (!File::end (f)) { c = File::getc(f); if (!Ctype::isgraph (c)) { File::ungetc (c, f); break; } s = s + String::new(c); } return s; } int i = 0; int argc = 0; int c; while (i < String::length (format) && !File::end(f) && !File::error(f)) { switch (format[i]) { case ' ': case '\t': whitespace (); break; case '%': i++; switch (format[i]) { case 'b': case 'B': *args[argc++] = integer (isbinary, 2); break; case 'o': case 'O': *args[argc++] = integer (isoctal, 8); break; case 'd': case 'D': *args[argc++] = integer (isdecimal, 10); break; case 'x': case 'X': *args[argc++] = integer (ishex, 16); break; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': *args[argc++] = number(isfloat); break; case 'c': *args[argc++] = File::getc(f); break; case 's': *args[argc++] = word(); break; default: c = File::getc(f); if (c != format[i]) { File::ungetc (c, f); return argc; } } break; default: c = File::getc(f); if (c != format[i]) { File::ungetc (c, f); return argc; } break; } i++; } return argc; } public int fscanf (file f, string format, *poly args...) /* * According to 'format', read from 'f' to 'args' */ { return vfscanf (f, format, args); } public int sscanf (string s, string format, *poly args...) /* * According to 'format', read from 's' to 'args' */ { file sf = string_read(s); int n = vfscanf (sf, format, args); close(sf); return n; } public namespace ScanfGlobals { public int scanf (string format, *poly args...) /* * According to 'format', read from stdin to 'args' */ { return File::vfscanf (stdin, format, args); } public int vscanf (string format, (*poly)[*] args) /* * According to 'format', read from stdin to 'args' */ { return File::vfscanf (stdin, format, args); } } public import ScanfGlobals; } import File::ScanfGlobals;