diff --git a/swad_changelog.h b/swad_changelog.h
index 72377aed..1f115361 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -138,14 +138,15 @@
/****************************** Public constants *****************************/
/*****************************************************************************/
-#define Log_PLATFORM_VERSION "SWAD 15.168.1 (2016-03-30)"
+#define Log_PLATFORM_VERSION "SWAD 15.168.2 (2016-03-30)"
#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.1: Mar 30, 2016 Fixed bug in list o parameters. (197097 lines)
+ Version 15.168.2: Mar 30, 2016 Code refactoring in list of parameters. (197128 lines)
+ Version 15.168.1: Mar 30, 2016 Fixed bug in list of parameters. (197097 lines)
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)
diff --git a/swad_parameter.c b/swad_parameter.c
index d1492424..6fcaecd8 100644
--- a/swad_parameter.c
+++ b/swad_parameter.c
@@ -59,7 +59,9 @@ extern struct Globals Gbl;
/***************************** Private prototypes ****************************/
/*****************************************************************************/
-static void Par_GetParameters (void);
+static void Par_CreateListOfParams (void);
+static void Par_CreateListOfParamsFromQueryString (void);
+static void Par_CreateListOfParamsFromTmpFile (void);
static void Par_ShowErrorReadingParam (const char *ParamName,const char *ExpectedChar,int Ch);
@@ -148,10 +150,127 @@ bool Par_GetQueryString (void)
}
if (Gbl.ContentReceivedByCGI == Act_CONTENT_NORM)
- Par_GetParameters ();
+ Par_CreateListOfParams ();
return true;
}
+/*****************************************************************************/
+/************************ Create list of parameters **************************/
+/*****************************************************************************/
+
+static void Par_CreateListOfParams (void)
+ {
+ switch (Gbl.ContentReceivedByCGI)
+ {
+ case Act_CONTENT_NORM:
+ Par_CreateListOfParamsFromQueryString ();
+ break;
+ case Act_CONTENT_DATA:
+ Par_CreateListOfParamsFromTmpFile ();
+ break;
+ }
+ }
+
+/*****************************************************************************/
+/**************** Create list of parameters from query string ****************/
+/*****************************************************************************/
+/*
+ +-------------+ +-------------+ +-------------+
+List -> | Name.Start | --> | Name.Start | --> | Name.Start |
+ +-------------+ / +-------------+ / +-------------+
+ | Name.Length | / | Name.Length | / | Name.Length |
+ +-------------+ / +-------------+ / +-------------+
+ | Value.Start | / | Value.Start | / | Value.Start |
+ +-------------+ / +-------------+ / +-------------+
+ | Value.Lengh | / | Value.Lengh | / | Value.Lengh |
+ +-------------+ / +-------------+ / +-------------+
+ | Next ----- | Next ----- | NULL |
+ +-------------+ +-------------+ +-------------+
+*/
+static void Par_CreateListOfParamsFromQueryString (void)
+ {
+ unsigned long CurPos; // Current position in query string
+ struct Param *Param;
+ struct Param *NewParam;
+
+ /***** Check if query string is empty *****/
+ if (Gbl.Params.QueryString == NULL)
+ {
+ Gbl.Params.List = NULL;
+ return;
+ }
+ if (!Gbl.Params.QueryString[0])
+ {
+ Gbl.Params.List = NULL;
+ return;
+ }
+
+ /***** Go over the query string
+ getting start positions and lengths of parameters *****/
+ for (CurPos = 0;
+ CurPos < Gbl.Params.ContentLength;
+ )
+ {
+ /* Allocate space for a new parameter */
+ if ((NewParam = (struct Param *) malloc (sizeof (struct Param))) == NULL)
+ Lay_ShowErrorAndExit ("Error allocating memory for parameter");
+
+ /* Link the previous element in list with the current element */
+ if (CurPos == 0)
+ Gbl.Params.List = NewParam;
+ else
+ Param->Next = NewParam;
+
+ /* Make the current element to be the just created */
+ Param = NewParam;
+ Param->Next = NULL;
+
+ /* Get parameter name */
+ Param->Name.Start = CurPos;
+ Param->Name.Length = strcspn (&Gbl.Params.QueryString[CurPos],"=");
+ CurPos += Param->Name.Length;
+
+ /* Get parameter value */
+ if (CurPos < Gbl.Params.ContentLength)
+ {
+ if (Gbl.Params.QueryString[CurPos] == '=')
+ {
+ CurPos++; // Skip '='
+ Param->Value.Start = CurPos;
+ if (CurPos < Gbl.Params.ContentLength)
+ {
+ Param->Value.Length = strcspn (&Gbl.Params.QueryString[CurPos],"&");
+ CurPos += Param->Value.Length;
+ if (CurPos < Gbl.Params.ContentLength)
+ if (Gbl.Params.QueryString[CurPos] == '&')
+ CurPos++; // Skip '&'
+ }
+ else
+ Param->Value.Length = 0;
+ }
+ else
+ {
+ Param->Value.Start = CurPos;
+ Param->Value.Length = 0;
+ }
+ }
+ else
+ {
+ Param->Value.Start = CurPos;
+ Param->Value.Length = 0;
+ }
+ }
+ }
+
+/*****************************************************************************/
+/*************** Create list of parameters from temporary file ***************/
+/*****************************************************************************/
+// TODO: Rename Gbl.F.Tmp to Gbl.F.In (InFile, QueryFile)?
+
+static void Par_CreateListOfParamsFromTmpFile (void)
+ {
+ // TODO: Implement
+ }
/*****************************************************************************/
/***************** Free memory allocated for query string ********************/
@@ -176,6 +295,190 @@ void Par_FreeParams (void)
free ((void *) Gbl.Params.QueryString);
}
+/*****************************************************************************/
+/************************* 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
+
+unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
+ char *ParamValue,size_t MaxBytes)
+ {
+ static const char *StringBeforeParam = "Content-Disposition: form-data; name=\"";
+ size_t BytesToCopy;
+ size_t BytesAlreadyCopied = 0;
+ int Ch;
+ unsigned i;
+ struct Param *Param;
+ char *PtrDst;
+ const char *PtrSrc = NULL;
+ int Result;
+ unsigned NumTimes = 0;
+ bool ParamFound = false;
+ bool ContinueSearching = true;
+ unsigned ParamNameLength;
+ char StrAux[Par_MAX_BYTES_STR_AUX+1];
+
+ ParamValue[0] = '\0'; // By default, the value of the parameter will be an empty string
+ ParamNameLength = strlen (ParamName);
+
+ switch (Gbl.ContentReceivedByCGI)
+ {
+ case Act_CONTENT_NORM:
+ 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
+ strcmp (ParamName,"ctr") && // To enter directly to a centre
+ strcmp (ParamName,"deg") && // To enter directly to a degree
+ strcmp (ParamName,"crs") && // To enter directly to a course
+ strcmp (ParamName,"CrsCod") && // To enter directly to a course (allowed for compatibility with old links, to be removed in 2016)
+ strcmp (ParamName,"usr") && // To enter directly to a user
+ strcmp (ParamName,"act") && // To execute directly an action (allowed only for fully public actions)
+ strcmp (ParamName,"ses") && // To use an open session when redirecting from one language to another
+ 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
+ }
+
+ PtrDst = ParamValue;
+ Param = Gbl.Params.List;
+ for (NumTimes = 0;
+ NumTimes < 1 || ParamType == Par_PARAM_MULTIPLE;
+ NumTimes++)
+ {
+ 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))
+ {
+ ParamFound = true;
+ if ((BytesToCopy = Param->Value.Length))
+ PtrSrc = &Gbl.Params.QueryString[Param->Value.Start];
+ }
+
+ if (!ParamFound)
+ break;
+
+ if (NumTimes)
+ {
+ if (BytesAlreadyCopied + 1 > MaxBytes)
+ {
+ sprintf (Gbl.Message,"Multiple parameter %s too large,"
+ " it exceed the maximum allowed size (%lu bytes).",
+ ParamName,(unsigned long) MaxBytes);
+ Lay_ShowErrorAndExit (Gbl.Message);
+ }
+ *PtrDst++ = Par_SEPARATOR_PARAM_MULTIPLE; // Separator in the destination string
+ BytesAlreadyCopied++;
+ }
+
+ if (BytesAlreadyCopied + BytesToCopy > MaxBytes)
+ {
+ sprintf (Gbl.Message,"Parameter %s too large,"
+ " it exceed the maximum allowed size (%lu bytes).",
+ ParamName,(unsigned long) MaxBytes);
+ Lay_ShowErrorAndExit (Gbl.Message);
+ }
+ if (BytesToCopy)
+ {
+ strncpy (PtrDst,PtrSrc,BytesToCopy);
+ BytesAlreadyCopied += BytesToCopy;
+ PtrDst += BytesToCopy;
+ }
+ }
+ *PtrDst = '\0'; // strncpy() does not add the final NULL
+ break;
+ case Act_CONTENT_DATA:
+ rewind (Gbl.F.Tmp);
+
+ while (ContinueSearching)
+ {
+ Result = Str_ReceiveFileUntilDelimitStr (Gbl.F.Tmp,
+ (FILE *) NULL,(char *) NULL,
+ Gbl.DelimiterString,
+ Fil_MAX_FILE_SIZE);
+ switch (Result)
+ {
+ case -1: // Delimiter string not found
+ ContinueSearching = false;
+ break;
+ case 0: // Par_MAX_BYTES_STR_AUX exceeded
+ ContinueSearching = false;
+ break;
+ case 1: // Delimiter string found
+ /* Skip carriage returns, spaces, etc. */
+ do
+ Ch = fgetc (Gbl.F.Tmp);
+ while (isspace (Ch) && Ch != EOF);
+
+ if (Ch == (int) StringBeforeParam[0])
+ {
+ Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux,Par_LENGTH_OF_STR_BEFORE_PARAM-1);
+ if (!strcasecmp (StrAux,StringBeforeParam+1)) // Start of a parameter
+ {
+ /* Check if parameter is the parameter that we are looking for */
+ Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux,ParamNameLength);
+ if (!strcasecmp (StrAux,ParamName)) // Parameter found
+ {
+ /* Skip quote after parameter name */
+ Ch = fgetc (Gbl.F.Tmp);
+ if (Ch != (int) '\"')
+ Par_ShowErrorReadingParam (ParamName,""",Ch);
+
+ /* Skip two CR-LF (0x0D 0x0A) */
+ for (i = 0;
+ i < 2;
+ i++)
+ {
+ Ch = fgetc (Gbl.F.Tmp);
+ if (Ch != 0x0D) // '\r'
+ Par_ShowErrorReadingParam (ParamName,"0x0D",Ch);
+ Ch = fgetc (Gbl.F.Tmp);
+ if (Ch != 0x0A) // '\n'
+ Par_ShowErrorReadingParam (ParamName,"0x0A",Ch);
+ }
+
+ /* Get the parameter */
+ Result = Str_ReceiveFileUntilDelimitStr (Gbl.F.Tmp,
+ (FILE *) NULL,ParamValue,
+ Gbl.DelimiterStringIncludingInitialRet,
+ (unsigned long long) MaxBytes);
+
+ /* Depending on the result... */
+ switch (Result)
+ {
+ case -1: // Delimiter string not found
+ sprintf (Gbl.Message,"Parameter %s has not been readed properly.",
+ ParamName);
+ Lay_ShowErrorAndExit (Gbl.Message);
+ break;
+ case 0: // Parameter's too long
+ sprintf (Gbl.Message,"Parameter %s exceed the maximum allowed size (%lu bytes).",
+ ParamName,(unsigned long) MaxBytes);
+ Lay_ShowErrorAndExit (Gbl.Message);
+ break;
+ case 1: // Delimiter string and parameter value found
+ ParamFound = true;
+ ContinueSearching = false;
+ NumTimes = 1;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return NumTimes;
+ }
+
/*****************************************************************************/
/****************** Get the parameters sent to this CGI **********************/
/*****************************************************************************/
@@ -466,279 +769,6 @@ 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 **********************/
-/*****************************************************************************/
-// 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
-
-unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
- char *ParamValue,size_t MaxBytes)
- {
- static const char *StringBeforeParam = "Content-Disposition: form-data; name=\"";
- size_t BytesToCopy;
- size_t BytesAlreadyCopied = 0;
- int Ch;
- unsigned i;
- struct Param *Param;
- char *PtrDst;
- const char *PtrSrc = NULL;
- int Result;
- unsigned NumTimes = 0;
- bool ParamFound = false;
- bool ContinueSearching = true;
- unsigned ParamNameLength;
- char StrAux[Par_MAX_BYTES_STR_AUX+1];
-
- ParamValue[0] = '\0'; // By default, the value of the parameter will be an empty string
- ParamNameLength = strlen (ParamName);
-
- switch (Gbl.ContentReceivedByCGI)
- {
- case Act_CONTENT_NORM:
- 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
- strcmp (ParamName,"ctr") && // To enter directly to a centre
- strcmp (ParamName,"deg") && // To enter directly to a degree
- strcmp (ParamName,"crs") && // To enter directly to a course
- strcmp (ParamName,"CrsCod") && // To enter directly to a course (allowed for compatibility with old links, to be removed in 2016)
- strcmp (ParamName,"usr") && // To enter directly to a user
- strcmp (ParamName,"act") && // To execute directly an action (allowed only for fully public actions)
- strcmp (ParamName,"ses") && // To use an open session when redirecting from one language to another
- 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
- }
-
- PtrDst = ParamValue;
- Param = Gbl.Params.List;
- for (NumTimes = 0;
- NumTimes < 1 || ParamType == Par_PARAM_MULTIPLE;
- NumTimes++)
- {
- 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))
- {
- ParamFound = true;
- if ((BytesToCopy = Param->Value.Length))
- PtrSrc = &Gbl.Params.QueryString[Param->Value.Start];
- }
-
- if (!ParamFound)
- break;
-
- if (NumTimes)
- {
- if (BytesAlreadyCopied + 1 > MaxBytes)
- {
- sprintf (Gbl.Message,"Multiple parameter %s too large,"
- " it exceed the maximum allowed size (%lu bytes).",
- ParamName,(unsigned long) MaxBytes);
- Lay_ShowErrorAndExit (Gbl.Message);
- }
- *PtrDst++ = Par_SEPARATOR_PARAM_MULTIPLE; // Separator in the destination string
- BytesAlreadyCopied++;
- }
-
- if (BytesAlreadyCopied + BytesToCopy > MaxBytes)
- {
- sprintf (Gbl.Message,"Parameter %s too large,"
- " it exceed the maximum allowed size (%lu bytes).",
- ParamName,(unsigned long) MaxBytes);
- Lay_ShowErrorAndExit (Gbl.Message);
- }
- if (BytesToCopy)
- {
- strncpy (PtrDst,PtrSrc,BytesToCopy);
- BytesAlreadyCopied += BytesToCopy;
- PtrDst += BytesToCopy;
- }
- }
- *PtrDst = '\0'; // strncpy() does not add the final NULL
- break;
- case Act_CONTENT_DATA:
- rewind (Gbl.F.Tmp);
-
- while (ContinueSearching)
- {
- Result = Str_ReceiveFileUntilDelimitStr (Gbl.F.Tmp,
- (FILE *) NULL,(char *) NULL,
- Gbl.DelimiterString,
- Fil_MAX_FILE_SIZE);
- switch (Result)
- {
- case -1: // Delimiter string not found
- ContinueSearching = false;
- break;
- case 0: // Par_MAX_BYTES_STR_AUX exceeded
- ContinueSearching = false;
- break;
- case 1: // Delimiter string found
- /* Skip carriage returns, spaces, etc. */
- do
- Ch = fgetc (Gbl.F.Tmp);
- while (isspace (Ch) && Ch != EOF);
-
- if (Ch == (int) StringBeforeParam[0])
- {
- Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux,Par_LENGTH_OF_STR_BEFORE_PARAM-1);
- if (!strcasecmp (StrAux,StringBeforeParam+1)) // Start of a parameter
- {
- /* Check if parameter is the parameter that we are looking for */
- Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux,ParamNameLength);
- if (!strcasecmp (StrAux,ParamName)) // Parameter found
- {
- /* Skip quote after parameter name */
- Ch = fgetc (Gbl.F.Tmp);
- if (Ch != (int) '\"')
- Par_ShowErrorReadingParam (ParamName,""",Ch);
-
- /* Skip two CR-LF (0x0D 0x0A) */
- for (i = 0;
- i < 2;
- i++)
- {
- Ch = fgetc (Gbl.F.Tmp);
- if (Ch != 0x0D) // '\r'
- Par_ShowErrorReadingParam (ParamName,"0x0D",Ch);
- Ch = fgetc (Gbl.F.Tmp);
- if (Ch != 0x0A) // '\n'
- Par_ShowErrorReadingParam (ParamName,"0x0A",Ch);
- }
-
- /* Get the parameter */
- Result = Str_ReceiveFileUntilDelimitStr (Gbl.F.Tmp,
- (FILE *) NULL,ParamValue,
- Gbl.DelimiterStringIncludingInitialRet,
- (unsigned long long) MaxBytes);
-
- /* Depending on the result... */
- switch (Result)
- {
- case -1: // Delimiter string not found
- sprintf (Gbl.Message,"Parameter %s has not been readed properly.",
- ParamName);
- Lay_ShowErrorAndExit (Gbl.Message);
- break;
- case 0: // Parameter's too long
- sprintf (Gbl.Message,"Parameter %s exceed the maximum allowed size (%lu bytes).",
- ParamName,(unsigned long) MaxBytes);
- Lay_ShowErrorAndExit (Gbl.Message);
- break;
- case 1: // Delimiter string and parameter value found
- ParamFound = true;
- ContinueSearching = false;
- NumTimes = 1;
- break;
- }
- }
- }
- }
- break;
- }
- }
- break;
- }
-
- return NumTimes;
- }
-
/*****************************************************************************/
/********************** Write error reading parameter ************************/
/*****************************************************************************/
diff --git a/swad_parameter.h b/swad_parameter.h
index ea43b7d1..82abac62 100644
--- a/swad_parameter.h
+++ b/swad_parameter.h
@@ -60,6 +60,9 @@ typedef enum
bool Par_GetQueryString (void);
void Par_FreeParams (void);
+unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
+ char *ParamValue,size_t MaxBytes);
+
void Par_GetMainParameters (void);
unsigned Par_GetParToText (const char *ParamName,char *ParamValue,size_t MaxBytes);
@@ -67,8 +70,6 @@ unsigned Par_GetParToHTML (const char *ParamName,char *ParamValue,size_t MaxByte
unsigned Par_GetParMultiToText (const char *ParamName,char *ParamValue,size_t MaxBytes);
unsigned Par_GetParAndChangeFormat (const char *ParamName,char *ParamValue,size_t MaxBytes,
Str_ChangeTo_t ChangeTo,bool RemoveLeadingAndTrailingSpaces);
-unsigned Par_GetParameter (tParamType ParamType,const char *ParamName,
- char *ParamValue,size_t MaxBytes);
bool Par_GetNextStrUntilSeparParamMult (const char **StrSrc,char *StrDst,size_t LongMax);
void Par_ReplaceSeparatorMultipleByComma (const char *StrSrc,char *StrDst);