📄 tij0168.html
字号:
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>string</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
instead of a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>char*</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.)
You don’t need to define a copy-constructor,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>operator=,</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
or destructor because the compiler does that for you, and does it correctly.
But even if it sometimes works automatically, C++ programmers must still know
the details of copy-construction and assignment.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
remainder of the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Pair</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
class consists of the two methods
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>decodeURLString( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and a helper method
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>translateHex( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which is used by
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>decodeURLString( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
(Note that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>translateHex( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
does not guard against bad user input such as “%1H.”) After
allocating adequate storage (which must be released by the destructor),
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>decodeURLString( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
moves through and replaces each ‘
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>+</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">’
with a space and each hex code (beginning with a ‘
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>%</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">’)
with the appropriate character.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CGI_vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
parses and holds an entire CGI GET command. It is inherited from the STL
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>vector,</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
which is instantiated to hold
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Pair</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s.
Inheritance in C++ is denoted by using a colon at the point you’d say
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>extends</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in Java. In addition, inheritance defaults to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>private</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
so you’ll almost always need to use the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
keyword as was done here. You can also see that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CGI_vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
has a copy-constructor and an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>operator=</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
but they’re both declared as
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>private</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
This is to prevent the compiler from synthesizing the two functions (which it
will do if you don’t declare them yourself), but it also prevents the
client programmer from passing a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CGI_vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
by value or from using assignment.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CGI_vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">’s
job is to take the QUERY_STRING and parse it into name-value pairs, which it
will do with the aid of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Pair</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
First it copies the string into locally-allocated memory and keeps track of the
starting address with the constant pointer
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>start.
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">(This
is later used in the destructor to release the memory.)
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Then
it uses its method
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>nextPair( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
to parse the string into raw name-value pairs, delimited by ‘
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>=</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">’
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">‘</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>&</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">’
signs. These are handed by
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>nextPair( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Pair</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
constructor so
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>nextPair( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
can return the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Pair</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object, which is then added to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
with
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>push_back( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
When
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>nextPair( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
runs out of QUERY_STRING, it returns zero.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Now
that the basic tools are defined, they can easily be used in a CGI program,
like this:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: Listmgr2.cpp</font>
<font color="#009900">// CGI version of Listmgr.c in C++, which </font>
<font color="#009900">// extracts its input via the GET submission </font>
<font color="#009900">// from the associated applet. Also works as</font>
<font color="#009900">// an ordinary CGI program with HTML forms.</font>
#include <stdio.h>
#include "CGITools.h"
<font color="#0000ff">const</font> <font color="#0000ff">char</font>* dataFile = "list2.txt";
<font color="#0000ff">const</font> <font color="#0000ff">char</font>* notify = "Bruce@EckelObjects.com";
#undef DEBUG
<font color="#009900">// Similar code as before, except that it looks</font>
<font color="#009900">// for the email name inside of '<>':</font>
<font color="#0000ff">int</font> inList(FILE* list, <font color="#0000ff">const</font> <font color="#0000ff">char</font>* emailName) {
<font color="#0000ff">const</font> <font color="#0000ff">int</font> BSIZE = 255;
<font color="#0000ff">char</font> lbuf[BSIZE];
<font color="#0000ff">char</font> emname[BSIZE];
<font color="#009900">// Put the email name in '<>' so there's no</font>
<font color="#009900">// possibility of a match within another name:</font>
sprintf(emname, "<%s>", emailName);
<font color="#009900">// Go to the beginning of the list:</font>
fseek(list, 0, SEEK_SET);
<font color="#009900">// Read each line in the list:</font>
<font color="#0000ff">while</font>(fgets(lbuf, BSIZE, list)) {
<font color="#009900">// Strip off the newline: </font>
<font color="#0000ff">char</font> * newline = strchr(lbuf, '\n');
<font color="#0000ff">if</font>(newline != 0)
*newline = '\0';
<font color="#0000ff">if</font>(strstr(lbuf, emname) != 0)
<font color="#0000ff">return</font> 1;
}
<font color="#0000ff">return</font> 0;
}
<font color="#0000ff">void</font> main() {
<font color="#009900">// You MUST print this out, otherwise the </font>
<font color="#009900">// server will not send the response:</font>
printf("Content-type: text/plain\n\n");
FILE* list = fopen(dataFile, "a+t");
<font color="#0000ff">if</font>(list == 0) {
printf("error: could not open database. ");
printf("Notify %s", notify);
<font color="#0000ff">return</font>;
}
<font color="#009900">// For a CGI "GET," the server puts the data</font>
<font color="#009900">// in the environment variable QUERY_STRING:</font>
CGI_vector query(getenv("QUERY_STRING"));
#<font color="#0000ff">if</font> defined(DEBUG)
<font color="#009900">// Test: dump all names and values</font>
<font color="#0000ff">for</font>(<font color="#0000ff">int</font> i = 0; i < query.size(); i++) {
printf("query[%d].name() = [%s], ",
i, query[i].name());
printf("query[%d].value() = [%s]\n",
i, query[i].value());
}
#endif(DEBUG)
Pair name = query[0];
Pair email = query[1];
<font color="#0000ff">if</font>(name.empty() || email.empty()) {
printf("error: <font color="#0000ff">null</font> name or email");
<font color="#0000ff">return</font>;
}
<font color="#0000ff">if</font>(inList(list, email.value())) {
printf("Already in list: %s", email.value());
<font color="#0000ff">return</font>;
}
<font color="#009900">// It's not in the list, add it:</font>
fseek(list, 0, SEEK_END);
fprintf(list, "%s <%s>;\n",
name.value(), email.value());
fflush(list);
fclose(list);
printf("%s <%s> added to list\n",
name.value(), email.value());
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>alreadyInList( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
function is almost identical to the previous version, except that it assumes
all email names are inside ‘
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B><></B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">’.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">When
you use the <A NAME="Index2798"></A><A NAME="Index2799"></A><A NAME="Index2800"></A>GET
approach (which is normally done in the HTML METHOD tag of the FORM directive,
but which is controlled here by the way the data is sent), the Web server grabs
everything after the ‘?’ and puts in into the environment variable <A NAME="Index2801"></A><A NAME="Index2802"></A>QUERY_STRING.
So to read that information you have to get the value of QUERY_STRING, which
you do using the standard C library function
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>getenv( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
In
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>main( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">notice
how simple the act of parsing the QUERY_STRING is: you just hand it to the
constructor for the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CGI_vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object called
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>query
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">and
all the work is done for you. From then on you can pull out the names and
values from
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>query</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
as if it were an array. (This is because the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>operator[]</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is overloaded in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>vector.</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
You can see how this works in the debug code, which is surrounded by the
preprocessor directives
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>#if
defined(DEBUG)
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>#endif(DEBUG)</B></FONT><FONT FACE="Carmina Md BT" S
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -