diff --git a/swad_changelog.h b/swad_changelog.h
index 2d9eb3ce..9bd5a344 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -138,13 +138,14 @@
/****************************** Public constants *****************************/
/*****************************************************************************/
-#define Log_PLATFORM_VERSION "SWAD 15.167 (2016-03-29)"
+#define Log_PLATFORM_VERSION "SWAD 15.168 (2016-03-29)"
#define CSS_FILE "swad15.165.5.css"
#define JS_FILE "swad15.131.3.js"
// Number of lines (includes comments but not blank lines) has been got with the following command:
// nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1
/*
+ Version 15.168: Mar 30, 2016 When content is normal, all parameters are retrieved in a list. (197085 lines)
Version 15.167: Mar 30, 2016 Query string is allocated to the exact needed size to optimize memory. (196998 lines)
Version 15.166.1: Mar 30, 2016 Fixed bug while reading a parameter. (196959 lines)
Version 15.166: Mar 30, 2016 Changes in form to edit a test question.
diff --git a/swad_global.c b/swad_global.c
index eabd2988..ac44a73d 100644
--- a/swad_global.c
+++ b/swad_global.c
@@ -105,8 +105,10 @@ void Gbl_InitializeGlobals (void)
Gbl.WebService.IsWebService = false;
- Gbl.ContentLength = 0;
- Gbl.QueryString = NULL;
+ Gbl.Params.ContentLength = 0;
+ Gbl.Params.QueryString = NULL;
+ Gbl.Params.List = NULL;
+ Gbl.Params.GetMethod = false;
Gbl.F.Out = stdout;
Gbl.F.Tmp = NULL;
@@ -117,7 +119,6 @@ void Gbl_InitializeGlobals (void)
Gbl.Error = false;
- Gbl.GetMethod = false;
Gbl.Layout.WritingHTMLStart =
Gbl.Layout.HTMLStartWritten =
diff --git a/swad_global.h b/swad_global.h
index 628325ad..042e9ba6 100644
--- a/swad_global.h
+++ b/swad_global.h
@@ -95,13 +95,23 @@ struct Globals
bool Inside; // Set to true inside a form to avoid nested forms
} Form;
bool Error;
- bool GetMethod; // Am I accessed using GET method?
- struct soap *soap; // gSOAP runtime environment
+
+ struct
+ {
+ size_t ContentLength;
+ char *QueryString; // String allocated dynamically with the arguments sent to the CGI
+ struct Param *List; // Linked list of parameters
+ bool GetMethod; // Am I accessing using GET method?
+ } Params;
+
Act_Content_t ContentReceivedByCGI; /* Content send by the form and received by the CGI:
- Act_CONTENT_NORM (if CONTENT_TYPE==text/plain) or
- Act_CONTENT_DATA (if CONTENT_TYPE==multipart/form-data) */
+ Act_CONTENT_NORM (if CONTENT_TYPE==text/plain) or
+ Act_CONTENT_DATA (if CONTENT_TYPE==multipart/form-data) */
char DelimiterString[1000];
char DelimiterStringIncludingInitialRet[2+1000];
+
+ struct soap *soap; // gSOAP runtime environment
+
struct
{
bool WritingHTMLStart; // Used to avoid writing the HTML head when aborting program on error
@@ -115,7 +125,7 @@ struct Globals
bool LockedTables;
} DB;
- bool HiddenParamsInsertedIntoDB; // Indica si se ha insertado algún parameter in the database in esta ejecución
+ bool HiddenParamsInsertedIntoDB; // If parameters are inserted in the database in this execution
/* To compute execution time of the program */
struct timeval tvStart,tvPageCreated,tvPageSent;
@@ -702,8 +712,6 @@ struct Globals
float MaxPercent;
} DegPhotos;
} Stat;
- size_t ContentLength;
- char *QueryString; // String allocated dynamically with the arguments sent to the CGI
};
/*****************************************************************************/
diff --git a/swad_layout.c b/swad_layout.c
index 29a26a4e..556e01e3 100644
--- a/swad_layout.c
+++ b/swad_layout.c
@@ -369,7 +369,7 @@ static void Lay_WritePageTitle (void)
fprintf (Gbl.F.Out,"
");
- if (Gbl.GetMethod && Gbl.CurrentDeg.Deg.DegCod > 0)
+ if (Gbl.Params.GetMethod && Gbl.CurrentDeg.Deg.DegCod > 0)
{
fprintf (Gbl.F.Out,"%s > %s",
Cfg_PLATFORM_SHORT_NAME,
diff --git a/swad_parameter.c b/swad_parameter.c
index 9a6807b0..af5b0ef7 100644
--- a/swad_parameter.c
+++ b/swad_parameter.c
@@ -59,6 +59,8 @@ extern struct Globals Gbl;
/***************************** Private prototypes ****************************/
/*****************************************************************************/
+static void Par_GetParameters (void);
+
static void Par_ShowErrorReadingParam (const char *ParamName,const char *ExpectedChar,int Ch);
/*****************************************************************************/
@@ -76,18 +78,18 @@ bool Par_GetQueryString (void)
if (!strcmp (Method,"GET"))
{
/***** GET method *****/
- Gbl.GetMethod = true;
+ Gbl.Params.GetMethod = true;
Gbl.ContentReceivedByCGI = Act_CONTENT_NORM;
/* Get content length */
- Gbl.ContentLength = strlen (getenv ("QUERY_STRING"));
+ Gbl.Params.ContentLength = strlen (getenv ("QUERY_STRING"));
/* Allocate memory for query string */
- if ((Gbl.QueryString = (char *) malloc (Gbl.ContentLength + 1)) == NULL)
+ if ((Gbl.Params.QueryString = (char *) malloc (Gbl.Params.ContentLength + 1)) == NULL)
return false;
/* Copy query string from environment variable */
- strcpy (Gbl.QueryString,getenv ("QUERY_STRING"));
+ strcpy (Gbl.Params.QueryString,getenv ("QUERY_STRING"));
}
else
{
@@ -96,7 +98,7 @@ bool Par_GetQueryString (void)
if (getenv ("CONTENT_LENGTH"))
{
strcpy (UnsignedLongStr,getenv ("CONTENT_LENGTH"));
- if (sscanf (UnsignedLongStr,"%lu",&Gbl.ContentLength) != 1)
+ if (sscanf (UnsignedLongStr,"%lu",&Gbl.Params.ContentLength) != 1)
return false;
}
else
@@ -132,18 +134,22 @@ bool Par_GetQueryString (void)
Gbl.ContentReceivedByCGI = Act_CONTENT_NORM;
/* Allocate memory for query string */
- if ((Gbl.QueryString = (char *) malloc (Gbl.ContentLength + 1)) == NULL)
+ if ((Gbl.Params.QueryString = (char *) malloc (Gbl.Params.ContentLength + 1)) == NULL)
return false;
/* Copy query string from stdin */
- if (fread ((void *) Gbl.QueryString,sizeof (char),Gbl.ContentLength,stdin) != Gbl.ContentLength)
+ if (fread ((void *) Gbl.Params.QueryString,sizeof (char),Gbl.Params.ContentLength,stdin) != Gbl.Params.ContentLength)
{
- Gbl.QueryString[0] = '\0';
+ Gbl.Params.QueryString[0] = '\0';
return false;
}
- Gbl.QueryString[Gbl.ContentLength] = '\0';
+ Gbl.Params.QueryString[Gbl.Params.ContentLength] = '\0';
}
}
+
+ if (Gbl.ContentReceivedByCGI == Act_CONTENT_NORM)
+ Par_GetParameters ();
+
return true;
}
@@ -153,8 +159,8 @@ bool Par_GetQueryString (void)
void Par_FreeQueryString (void)
{
- if (Gbl.QueryString)
- free ((void *) Gbl.QueryString);
+ if (Gbl.Params.QueryString)
+ free ((void *) Gbl.Params.QueryString);
}
/*****************************************************************************/
@@ -447,6 +453,95 @@ unsigned Par_GetParAndChangeFormat (const char *ParamName,char *ParamValue,size_
return NumTimes;
}
+
+/*****************************************************************************/
+/************************* Get the value of a parameter **********************/
+/*****************************************************************************/
+// Return the number of parameters found
+
+#define Par_LENGTH_OF_STR_BEFORE_PARAM 38 // Length of "CONTENT-DISPOSITION: FORM-DATA; NAME=\""
+#define Par_MAX_BYTES_STR_AUX 1024
+
+static void Par_GetParameters (void)
+ {
+ unsigned long i;
+ struct Param *Param;
+ struct Param *NewParam;
+
+ switch (Gbl.ContentReceivedByCGI)
+ {
+ case Act_CONTENT_NORM:
+ if (Gbl.Params.QueryString == NULL)
+ {
+ Gbl.Params.List = NULL;
+ return;
+ }
+ if (!Gbl.Params.QueryString[0])
+ {
+ Gbl.Params.List = NULL;
+ return;
+ }
+
+ for (i = 0;
+ i < Gbl.Params.ContentLength;
+ )
+ {
+ /* Allocate space for parameter */
+ if ((NewParam = (struct Param *) malloc (sizeof (struct Param))) == NULL)
+ Lay_ShowErrorAndExit ("Error allocating memory for parameter");
+
+ /* Point last element in list to this */
+ if (i == 0)
+ Gbl.Params.List = NewParam;
+ else
+ Param->Next = NewParam;
+
+ /* Point current element to the new just created */
+ Param = NewParam;
+ Param->Next = NULL;
+
+ /* Get parameter name */
+ Param->Name.Start = i;
+ Param->Name.Length = strcspn (&Gbl.Params.QueryString[i],"=");
+
+ /* Get parameter value */
+ i += Param->Name.Length;
+ if (i < Gbl.Params.ContentLength)
+ {
+ if (Gbl.Params.QueryString[i] == '=')
+ {
+ i++; // Skip '='
+ Param->Value.Start = i;
+ if (i < Gbl.Params.ContentLength)
+ {
+ Param->Value.Length = strcspn (&Gbl.Params.QueryString[i],"&");
+ i += Param->Value.Length;
+ if (i < Gbl.Params.ContentLength)
+ if (Gbl.Params.QueryString[i] == '&')
+ i++; // Skip '&'
+ }
+ else
+ Param->Value.Length = 0;
+ }
+ else
+ {
+ Param->Value.Start = i;
+ Param->Value.Length = 0;
+ }
+ }
+ else
+ {
+ Param->Value.Start = i;
+ Param->Value.Length = 0;
+ }
+ }
+ break;
+ case Act_CONTENT_DATA:
+ // TODO: Implement
+ break;
+ }
+ }
+
/*****************************************************************************/
/************************* Get the value of a parameter **********************/
/*****************************************************************************/
@@ -463,9 +558,9 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
size_t BytesAlreadyCopied = 0;
int Ch;
unsigned i;
- char *PtrSrc;
+ struct Param *Param;
char *PtrDst;
- char *PtrStartOfParam;
+ const char *PtrSrc = NULL;
int Result;
unsigned NumTimes = 0;
bool ParamFound = false;
@@ -479,7 +574,7 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
switch (Gbl.ContentReceivedByCGI)
{
case Act_CONTENT_NORM:
- if (Gbl.GetMethod) // Only some selected parameters can be passed by GET method
+ if (Gbl.Params.GetMethod) // Only some selected parameters can be passed by GET method
{
if (strcmp (ParamName,"cty") && // To enter directly to a country
strcmp (ParamName,"ins") && // To enter directly to an institution
@@ -493,38 +588,28 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
strcmp (ParamName,"key")) // To verify an email address
return 0; // Return no-parameters-found when method is GET and parameter name is not one of these
}
- PtrSrc = Gbl.QueryString;
+
PtrDst = ParamValue;
+ Param = Gbl.Params.List;
for (NumTimes = 0;
NumTimes < 1 || ParamType == Par_PARAM_MULTIPLE;
NumTimes++)
{
- ParamFound = false;
- do
- {
- /* If method is GET ==> do case insensitive comparison */
- PtrStartOfParam = strstr (PtrSrc,ParamName);
- if (PtrStartOfParam)
- {
- // String ParamName found inside Gbl.QueryString
- if (*(PtrStartOfParam + ParamNameLength) == '=')
+ for (ParamFound = false;
+ Param != NULL && !ParamFound;
+ Param = Param->Next)
+ if (ParamNameLength == Param->Name.Length)
+ if (!strncmp (ParamName,&Gbl.Params.QueryString[Param->Name.Start],
+ Param->Name.Length))
{
- // Just after the name of the parameter, must be found a '=' symbol
- if (PtrStartOfParam == Gbl.QueryString) // The parameter is just at start
- ParamFound = true;
- else if (*(PtrStartOfParam - 1) == '&') // The parameter is not at start, but just after an "&" separator
- ParamFound = true;
- else // String has been found at the end of another parameter
- PtrSrc = PtrStartOfParam + ParamNameLength;
+ ParamFound = true;
+ if ((BytesToCopy = Param->Value.Length))
+ PtrSrc = &Gbl.Params.QueryString[Param->Value.Start];
}
- else // String has been found, but it is not a parameter
- PtrSrc = PtrStartOfParam + ParamNameLength;
- }
- }
- while (PtrStartOfParam != NULL && !ParamFound);
- if (!ParamFound) // Not found ==> PtrStartOfParam == NULL
+
+ if (!ParamFound)
break;
- PtrSrc = PtrStartOfParam + ParamNameLength + 1; // Add 1 due to the '=' symbol
+
if (NumTimes)
{
if (BytesAlreadyCopied + 1 > MaxBytes)
@@ -537,7 +622,7 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
*PtrDst++ = Par_SEPARATOR_PARAM_MULTIPLE; // Separator in the destination string
BytesAlreadyCopied++;
}
- BytesToCopy = strcspn (PtrSrc,"&"); // The & charecter is the separator of two parameters
+
if (BytesAlreadyCopied + BytesToCopy > MaxBytes)
{
sprintf (Gbl.Message,"Parameter %s too large,"
@@ -545,10 +630,12 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
ParamName,(unsigned long) MaxBytes);
Lay_ShowErrorAndExit (Gbl.Message);
}
- strncpy (PtrDst,PtrSrc,BytesToCopy);
- BytesAlreadyCopied += BytesToCopy;
- PtrDst += BytesToCopy;
- PtrSrc += BytesToCopy;
+ if (BytesToCopy)
+ {
+ strncpy (PtrDst,PtrSrc,BytesToCopy);
+ BytesAlreadyCopied += BytesToCopy;
+ PtrDst += BytesToCopy;
+ }
}
*PtrDst = '\0'; // strncpy() does not add the final NULL
break;
diff --git a/swad_parameter.h b/swad_parameter.h
index 354363e2..2969b19a 100644
--- a/swad_parameter.h
+++ b/swad_parameter.h
@@ -34,6 +34,18 @@
/************************** Public types and constants ***********************/
/*****************************************************************************/
+struct StartLength
+ {
+ unsigned long Start;
+ size_t Length;
+ };
+struct Param
+ {
+ struct StartLength Name;
+ struct StartLength Value;
+ struct Param *Next;
+ };
+
typedef enum
{
Par_PARAM_SINGLE,