Controling
-
This part is all about if, and then, and else and true and false – the nuts and bolts of how we express and control the execution of a program. his can be very dry and dusty material so to make it more understandable we are going to solve a problem you are going to need to solve to do any interactive web work of any complexity.
We will build something we can use in order to provide something like the functionality that can be obtained from typical getParameter(“ITEM1”) method in Java servlets or $_REQUEST[“ITEM1”] function in PHP.
In Section "C PROGRAMMING INTRO" we saw that environment variables can be accessed by the implicit argument to the main function. We can also use the library function getenv() to request the value of any named environment variable.
#include <stdio.h> #include <string.h> int main(int argc, char *argv[], char *env[]) { printf("Content-type:text/html\n\n<html><body bgcolor=#23abe2>\n"); char value[256]=""; strncpy(value,(char *) getenv("QUERY_STRING"),255); printf("QUERY_STRING:%s<br>\n",value); printf("<form>\n"); printf("<input type=\"TEXT\" name=\"ITEM1\">\n"); printf("<input type=\"TEXT\" name=\"ITEM2\">\n"); printf("<input type=\"SUBMIT\" name=\"Submit\">\n"); printf("</form></body></html>\n"); return 0; }
Here we display the QUERY_STRING which is what the program gets as the entire contents of an HTML form which contains NAME=VALUE pairs for all the named form elements.
An HTML form by default uses the GET method which transmits all form data back to the program or page that contains the form unless otherwise speciied in an action attribute. his data is contained in the QUERY_STRING as a series of variable = value pairs separated by the & character.
Note that in HTML values of things are enclosed in quotation marks, so to embed these inside C string we have to “escape” the character with a special sign \ like this “\”ITEM1\””. Also are using “\n” or explicit new line characters at the end of each piece of HTML output, so that when we select “view source” in the browser we get some reasonably formatted text to view rather than the whole apge appearing as one long single line.
Calling this program in a browser we see a form and can enter some data in the boxes:
And ater submitting the form we see:
To make much sense of the QUERY_STRING and ind a particular value in it, we are going to have to parse it, to chop it up into its constituent pieces and for this we will need some conditional logic (if, else etc.) and some loop to count through the characters in the variable. A basic function to do this would ideally be created as this is a task you might need to do do again and again so it makes sense to have a chunk of code that can be called over again.
In the next example we add this function and the noticeable diference in the output is that we can insert the extracted values into the HTML boxes ater we have parsed them. We seem to have successfully created something like a java getParameter() function – or have we?
If I were tp type DAVID !!! into the first ield:
I get this result:
A space character has become a + and ! has become %21.
This encoding occurs because certain characters are explicitly used in the transmission protocol itself. he & for example is used to separate portions of the QUERY_STRING and the space cannot be sent at all as it is.
Any program wishing to use information from the HTML form must be able to decode all this stuf which will now attempt to do.
The program Section 4 accomplishes what we see so far. It has a main function and a decode_value function all in the same file.
The decode_value function takes three arguments:
- the name of the value we are looking for “ITEM1=” or “ITEM2=”.
- the address of the variable into which we are going to put the value if found
- the maximum number of characters to copy
The function looks for the start and end positions in the QUERY_STRING of the value and then copies the characters found one by one to the value variable, adding a NULL charcter to terminate the string.
#include <stdio.h> #include <string.h> int main(int argc, char *argv[], char *env[]) { int length=0,i=0,j=0; char *pos1='\0', *ps2='\0'; //if the string key is in the query string if ((pos1=strstr((char *) getenv("QUERY_STRING"),KEY)) !=NULL) { //find start of value for this key for(i=0;i<strlen(key);i++) pos1++; //find length of the value if((pos2=strstr(pos1,"&"))!=NULL) length=pos2-pos1; else length=strlen(pos1); \\character by character, copy value from query string for(i=0,j=0;i<length; i++,j++) { if(j<size) value[j]=pos1[i]; } //add NULL character to end of the value if(j<size) value[j]='\0'; else value[size-1]='\0'; } } int main(int argc, char *argv[], char *env[]) { printf("Content-type:text/html\n\n<html><body bgcolor=#23abe2>\n"); char value[255]=""; strncpy(value,(char *) getenv("QUERY_STRING"),255); printf("QUERY_STRING:%s<br>\n",value); printf("<form>\n"); //call the decode value funciotn to get value of "ITEM2" decode_value("ITEM1=",(char *) &value, 255); if(strlen(value)>0) printf("<input type=\"TEXT\" name=\"ITEM1\" value=\"%s\">\n", value); else printf("<input type=\"TEXT\" name=\"ITEM1\">\n"); //call the decode_value function to get value of "ITEM2" decode_value("ITEM2=",(char *) &value, 255); if(strlen(value)>0) printf("<input type=\"TEXT\" name=\"ITEM2\" value=\"%s\">\n", value); else printf("<input type=\"TEXT\" name=\"ITEM2\">\n"); printf("<input type=\"SUBMIT\" name=\"Submit\">\n"); printf("</form></body></html>\n"); return 0; }
It looks like we are going to have to do some serious work on this decode_value package so as this is work we can expect to do over and over again it makes sense to write a function that can be reused.
Ffirst of we can put this function into a separate ile called decode_value.c and create a ile for all the functions we may write called c_in_linux.h and compile all this into a library. In the Make ile we can add:
SRC_CIL=decode_value.c OBJ_CIL=decode_value.o #CIL_INCLUDES=-I/usr/include/apache2-I.-I/usr/include/apache2-I/usr/include/apr-1 #CIL_LIBS=-L/usr/lib/mysql-lmysqlclient-L/usr/lib-lgd-L/home/david/public_html/Ventus/code all:lib_cil 4-4 lib_cil; gcc -c $(SRC_CIL) ar rcs c_in_linux.a $(OBJ_CIL) $(RM) *.o 4-4; gcc -0 logic4 filename.c c_in_linux.a -lc cp logic4/home/david/public_html/cgi-bin/logic4
This looks horrible and complex but all it means is this:
typing “make all” will:
- compile all the *.c iles listed in the list OBJ_SRC and into object iles *.o
- compile all the object iles into a library archive called lib_c_in_linux.a
- compile 4-4 using this new archive.
This is the model we will use to keep our iles as small as possible and the share-ability of code at its maximum.
We can now have a simpler “main” function ile, and iles for stuf we might want to write as call-able functions from anywhere really which we do not yet know about. All this is organised into a library ile (*.a for archive) – these can also be compiled as dynamically loadable shared objects *.so whch are much like Windows DLLs. his exactly how all Linux sotware is written and delivered.
For example the MySQL C Application Programmers Interface (API) comprises:
- all the header iles in /usr/include/mysql
- the library ile /usr/lib/mysql/libmysqlclient.a
What we are doing really is how all of Linux is put together – we are simply adding to it in the same way.
Our main ile now looks like this:
#include<stdio.h> #include<string.h> #include"c_in_linux.h" int main(int argc, char *argv[], char *env[]) { printf("content-type:text/html\n\n<html><body bgcolor=#23abe2>\n"); char value[255]=""; strncpy(value,(char*) getenv("QUERY_STRING"),255); printf("QUERY_STRING : %s<BR>\n", value); printf("<form>\n"); //call the decode_value function to get value of "ITEM1" decode_value("ITEM1=",(char*) &value,255); if(strlen(value)>0) printf("<input type=\"TEXT\" name=\"ITEM1\" value=\"%s\">\n", value); else printf("<input type=\"TEXT\" name=\"ITEM1\">\n"); //call the decode_value function to get value of "ITEM2" decode_value("ITEM2=",(char*) &value,255); if(strlen(value)>0) printf("<input type=\"TEXT\" name=\"ITEM2\" value=\"%s\">\n", value); else printf("<input type=\"TEXT\" name=\"ITEM2\">\n"); printf("<input type=\"SUBMIT\">"); printf("</form></body></html>); return 0; } }
This code calls the function decode_value in the same way but because the library, c_in_linux.a was linked in when it was compiled and as it has access to the header ile c_in_linux.h that lists all the functions in the library it all works properly.
Try to describe the process in pseudocode of decoding this QUERY STRING:
get the QUERY_STRING ind the search string “ITEM1=” inside it look for the end of the value of “ITEM1=” copy the value to our “value” variable, translating funny codes such as: %21 is ! %23 is #
These special codes are generated by the browser so that whatever you put in an HTML form will get safely transmitted and not mess about with the HTTP protocol. here are lot of them and the task for this chapter is to inish this task of so that EVERY key on your keyboard works as you think it should!!
Program privews section calls this uninished function decode_value which this far can only cope with the space character and ! – it uses if and else and for and the library function getenv, strcpy, strlen, ststrin a piece of conditional logic in which a string is analysed to ind a speciic item and this thing thencopied into a piece of memory called value which has been passed to it.
The result shows the decoded value pasted into the ffirst field;
#include<stdlib.h> #include<sring.h> void decode_value(const char *key, char *value, int size) { unsigned int length=0; insigned int i=0; int j=0; char *pos1='\0', *pos2='\0', *code1='\0', *code1='\0'; strcpy(value, ""); if((pos1=strstr(getenv("QUERY_STRING"), key))!NULL) { for(i=0; i<strlen(key); i++)="" ps1++;="" if((pos2="strstr(pos1,"&"))!=NULL)" {="" length="pos2-pos1;" }="" else="" for(i="0," j="0;" i<length;="" i++,j++)="" if(j<size)="" if(pos1[i]="='%')" i++;="" code1="pos1[i];" code2="pos1[i];" if(code1="='2'" &&="" value[j]="" ;="" 0x20="" vlaue[j]="!" 0x21="" value[size-1]="\0" <="" pre="">