** Start of listing of h4int.cc ** /* Stub: How to build h4int-c++.cgi ? Answer: fake header below compiles whole module right in, so trivial build: g++ h4int.cc mv h4int-c++.cgi ~/Trash mv a.out h4int-c++.cgi */ #include #include #include using std::cout; #include "CGI-cc.h" // Warning, that's not a header, it's the whole source!! CGI c; // Contains all the CGI info. See CGI-cc.h for access methods. char* br = "
"; char* nl = "\n"; #define maxch 10 enum errcode {good=0, nonum=-1, garbfnum=-2, signxnum=-3, garafnum=-4}; /* Given a string (nul-term), find start of number, + - or digit, pass back index by side-effect, and return 0 if OK or negative errcode: nonum = end without number, garbfnum = garbage before number */ enum errcode strchkint1(string str, int* pix) { (*pix)=0; while (1) { if (str.size() <= *pix) { //cout << "At ix=" << *pix << "endOfString before startOfNumber.\n"; return(nonum); } char ch = str.at(*pix); if ('\n' == ch) { //cout << "At ix=" << *pix << ", ch='" << ch << "', eol before start of number.\n"; return(nonum); } if (('+' == ch) || ('-' == ch)) { //cout << "At ix=" << *pix << ", ch='" << ch << "', found sign.\n"; return(good); } if (('0' <= ch) && ('9' >= ch)) { //cout << "At ix=" << *pix << ", ch='" << ch << "', found digit.\n"; return(good); } if (' ' == ch) { //cout << "At ix=" << *pix << ", ch='" << ch << "', skip white.\n"; (*pix)++; } else { //cout << "At ix=" << *pix << ", ch='" << ch << "', garbage, aborting.\n"; return(garbfnum); } } } /* Given a string (nul-term), and index where first digit or sign found, skip just the sign if that's what was found, update index, make sure a digit is immediately after the sign, return 0 if ok else error code: signxnum = sign without number */ enum errcode strchkint2(string str, int* pix) { char ch = str.at(*pix); if (('+' == ch) || ('-' == ch)) { //cout << "At ix=" << *pix << ", ch='" << ch << "', it was sign.\n"; (*pix)++; } if (str.size() <= *pix) { //cout << "End of string immediately after sign!\n"; return(signxnum); } ch = str.at(*pix); if (('0' <= ch) && ('9' >= ch)) { //cout << "At ix=" << *pix << ", ch='" << ch << "', it was digit.\n"; return(good); } //cout << "No digit after sign!\n"; return(signxnum); } /* Given a string (nul-term), and index where first digit found, scan to end of digits, update index, return code always 0 (OK). */ enum errcode strchkint3(string str, int* pix) { while (1) { if (str.size() <= *pix) { //cout << "At ix=" << *pix << ", end-of-string after digits.\n"; return(good); } char ch = str.at(*pix); if (('0' <= ch) && ('9' >= ch)) { //cout << "At ix=" << *pix << ", ch='" << ch << "', saw digit.\n"; (*pix)++; } else { //cout << "At ix=" << *pix << ", ch='" << ch << "', no more digit.\n"; return(good); } } } /* Given a string (nul-term), and index where digits ended, scan to very end making sure no junk, return code: garafnum = garbage after number */ enum errcode strchkint4(string str, int* pix) { while (1) { if (str.size() <= *pix) { //cout << "At ix=" << *pix << ", end-of-string after digits.\n"; return(good); } char ch = str.at(*pix); if ('\n' == ch) { //cout << "At ix=" << *pix << ", ch='" << ch << "', eol reached.\n"; return(good); } else if (' ' == ch) { //cout << "At ix=" << *pix << ", ch='" << ch << "', skip white.\n"; (*pix)++; } else { //cout << "At ix=" << *pix << ", ch='" << ch << "', junk.\n"; return(garafnum); } } } /* Given a string (nul-term), and integer where to put the final index, check if string consists exactly of representation of an integer (except for surrounding whitespace which are ignored). Return 0 (true) if it's all correct, an error code otherwise. Index is updated to point to EOL or NUL at end of string if all OK, else index points to first problem spot. */ enum errcode strchkint(string str, int* pix) { enum errcode scanres; if (0 != (scanres = strchkint1(str,pix))) { //cout << "scanres#1=" << scanres << ", ix=" << *pix << ", aborting.\n"; } else if (0 != (scanres = strchkint2(str,pix))) { //cout << "scanres#2=" << scanres << ", ix=" << *pix << ", aborting.\n"; } else if (0 != (scanres = strchkint3(str,pix))) { //cout << "scanres#3=" << scanres << ", ix=" << *pix << ", aborting.\n"; } else if (0 != (scanres = strchkint4(str,pix))) { //cout << "scanres#4=" << scanres << ", ix=" << *pix << ", aborting.\n"; } else { //cout << "scanres#4=" << scanres << ", ix=" << *pix << ", stub.\n"; } return(scanres); } /* Given bad results from strchkint, i.e. index where scan stopped and error code which is nonzero, describe problem to user. */ void tellproblem(string str, int ix, enum errcode erc) { switch (erc) { case nonum: cout << "Not a single digit anywhere.\n"; break; case garbfnum: if (0==ix) { cout << "Right at the very start: "; } else { cout << "Everything was fine for " << ix << " characters, "; cout << "just whitespace, but then: "; } cout << "a garbage character '" << str.at(ix) << "'.\n"; break; case signxnum: if (1==ix) { cout << "Right at the very start: "; } else { cout << "Everything was fine for " << ix << " characters, "; cout << "just whitespace, but then: "; } cout << "sign '" << str.at(ix-1) << "' followed by "; if (str.size() <= ix) { cout << "end of string already.\n"; } else { cout << "non-number '" << str[ix] << "'.\n"; } break; case garafnum: cout << "Everything was fine, optional whitespace and "; cout << "sign, and good number, but then garbage character '" << str[ix] << "'.\n"; break; default: cout << "(Stub, other case #" << erc << ")\n"; } } void keygetchecktell(char* key) { char *fn; if ((fn = c.copy_value(key)) == NULL) { cout << "Your form doesn't contain any [" << key << "] field." << br << nl; return; } else { cout << "For key [" << key << "] the value is [" << fn << "]." << br << nl; } int ix; enum errcode scanres = strchkint(fn,&ix); if (0 != scanres) tellproblem(fn, ix, scanres); else cout << "Hey, you got it correct, a number in that form-field!"; cout << br << nl; } main() { char* qs = getenv("QUERY_STRING"); c.start_html("Robert Maas CalRobert642@Yahoo.com", "Test CGI Page- written using C++ Include file", "white"); std::cout << "The query string is: [" << qs << "]" << br << nl; char *key; /* Will point to various literals */ char* fn; int ix; enum errcode scanres; cout << "**WARNING** Untested new stuff ..." << br << nl; keygetchecktell("num1"); keygetchecktell("num2"); keygetchecktell("num3"); keygetchecktell("num4"); keygetchecktell("num5"); keygetchecktell("num6"); keygetchecktell("num7"); keygetchecktell("num8"); /* while (1) { cout << "Type a number:"; string line; std::getline(cin, line); cout << "You typed the string [" << line << "]\n"; enum errcode chkres; int ix; chkres = strchkint(line, &ix); cout << "Toplevel result: chkres=" << chkres << " ix=" << ix << "\n"; if (0 != chkres) tellproblem(line, ix, chkres); if (chkres==0) { int n; istringstream(line) >> n; cout << "The number was [" << n << "]\n"; } else cout << "Skipping the number parse this time around.\n"; } */ } ** End of listing of h4int.cc ** Here is the directory entry for that source file: -rw------- 1 rem user 7619 Feb 10 2007 h4int.cc ^ Note user execute permission *not* needed for source files. That gets compiled to a.out, but then renamed to something.cgi so that it will be usable by remote users via CGI: -rwx------ 1 rem user 39936 Feb 10 2007 h4int-c++.cgi ^ Note user execute permission needed for all CGI programs. (because compiled-C++ is native machine code running directly on machine)