I wrote this code. Feel free to use it, at no charge, however you like. --Richard Gillmann
Yes, really, you can write CGI programs in C or C++. Here's a real simple one to get you started. Compile it, put it in the CGI-BIN directory and off you go.
/*
hello.c - CGI program for the web
*/
#include <stdio.h>
int main()
{
printf("content-type: text/html\n\n");
printf("<html>\n<body>\n");
printf("<h1> Hello, World! </h1>\n");
printf("</body>\n</html>\n");
return 0;
}
OK, let's be a little more modern and do it in C++.
// hellop.cpp - CGI program for the web
#include <iostream>
using namespace std;
int main()
{
cout << "content-type: text/html" << endl << endl;
cout << "<html><body>" << endl;
cout << "<h1> Hello, World! </h1>" << endl;
cout << "</body></html>" << endl;
return 0;
}
I wrote this function to do file locking in a CGI program for the web. I couldn't find a useful example on the web, so here's mine and I hope you find it handy. It's been tested on Red Hat Linux, for a CGI program running under Apache. For Windows, you'll have to do something different, using _sopen I think.
// assume Unix, use fcntl
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
// file locking (so multiple users don't interfere with each other)
// bWrite = true for write/exclusive access, else read/shared access
// returns a file descriptor if successful, else -1
// note: locks are released when the files are closed at end of program
int LockPlease(const char * filename,const bool bWrite)
{
const int MAX_TRY = 10;
int fd; // file descriptor
struct flock lck;
fd = open(filename, (bWrite ? O_WRONLY : O_RDONLY));
if (fd < 0)
return -1; // file not found, or could not be opened
// set up the record locking structure, the address of which
// is passed to the fcntl system call.
lck.l_type = (bWrite ? F_WRLCK : F_RDLCK); // write or read lock
lck.l_whence = 0; // from beginning of file
lck.l_start = lck.l_len = 0L; // until end of the file
// Attempt locking MAX_TRY times before giving up.
for (int tryno = 0; tryno < MAX_TRY; tryno++)
if (fcntl(fd, F_SETLK, &lck) == 0)
return fd; // lock obtained OK
else if (errno == EAGAIN || errno == EACCES) // file in use
sleep(2); // wait 2 seconds and try again
else
return -1; // fcntl error other than file in use
return -1; // MAX_TRY exceeded
}
This C program lists the arguments passed to the program, lists all the environment variables it can see, and shows what came in on stdin.
/*
showenv.c - display arguments and environment variables
*/
#include <stdio.h>
int main(int argc, char *argv[], char*envp[])
{
int i,c;
printf("content-type: text/html\n\n");
printf("<HTML>\n<HEAD>\n");
printf("<TITLE>Arguments and Environment Variables</TITLE>\n");
printf("</HEAD>\n<BODY>\n");
printf("<H1>Arguments</H1>\n<P>\n");
for (i=0; i<argc; i++)
printf("%d: %s<BR>\n",i,argv[i]);
printf("</P>\n<H1>Environment Variables</H1>\n<P>\n");
for (i=0; envp[i]; i++)
printf("%s<BR>\n",envp[i]);
printf("</p>\n<H1>Stdin</h1>\n<pre>\n");
while ((c=getchar()) != EOF)
putchar(c);
printf("</pre>\n</BODY>\n</HTML>\n");
return 0;
}
This C++ program reads a text file and displays the first line.
// readfile.cpp - CGI program for the web // test out reading a data file from a cgi program #include <fstream> #include <iostream> using namespace std; int main() { char buffer[10000]; ifstream fin; cout << "content-type: text/html" << endl << endl; cout << "<HTML>" << endl << "<BODY>" << endl; // your pathname here fin.open("/usr/home/yourlogin/data/testfile.txt",ios::in); if (fin.is_open()) { memset(buffer,0,sizeof(buffer)); fin.getline(buffer,sizeof(buffer)-1); cout << "<h1> Here is your data: </h1>" << endl; cout << "<p> " << buffer << " </p>" << endl; fin.close(); } else cout << "<h1> Couldn't open the file. </h1>" << endl; cout << "</BODY>" << endl << "</HTML>" << endl; return 0; }Getting a CGI program working on a new ISP
ISPs all do things differently, so it can take a bit of work to move a compiled CGI program to a new one. Here are the steps that I've found work for me.
- Get the "hello" and "showenv" programs shown above working on the new system.
You may need to put it in a special CGI or CGI-BIN directory. You may need to set the permissions on the executable file to allow read and execute by all users. You may need to give the executable a file name with a special extension (like .cgi). Or some combination of these things.
I've found that the "make" program on FreeBSD is funky, but you can use "gmake" instead. I mention BSD because I haven't yet found a Linux-based ISP that is fully satisfactory for doing CGI programs in C++. Many ISPs even ban development. You can do this stuff on a Windows server, too, but things like file locking and sendmail will be different.- Try a sample form using POST and/or GET and having the action be the showenv program. Make sure the form fields are coming through on stdin for POST.
- Get reading a file working.
Use the readfile program above. For some reason you have to use absolute pathnames in cgi programs, relative ones don't work.- Now you can try your big program, using what you have learned.
| © Copyright 2007 by Richard Gillmann | Last modified |