Version 15.184

This commit is contained in:
Antonio Cañas Vargas 2016-04-06 19:26:09 +02:00
parent 72c3301506
commit 58ccf23b80
8 changed files with 282 additions and 294 deletions

View File

@ -1743,12 +1743,12 @@ a:hover img.CENTRE_PHOTO_SHOW
.TEST_EXA_LIGHT {color:#A0A0A0; font-size:12pt;} .TEST_EXA_LIGHT {color:#A0A0A0; font-size:12pt;}
.TEST_EDI {color:#404040; font-size:12pt;} .TEST_EDI {color:#404040; font-size:12pt;}
.TEST_EDI_LIGHT {color:#A0A0A0; font-size:12pt;} .TEST_EDI_LIGHT {color:#A0A0A0; font-size:12pt;}
.TEST_IMG_SHOW_STEM {width:600px; margin:10px 0;} .TEST_IMG_SHOW_STEM {width:600px; border-radius:4px; margin:10px 0;}
.TEST_IMG_SHOW_ANS {width:450px; margin:10px 0;} .TEST_IMG_SHOW_ANS {width:450px; border-radius:4px; margin:10px 0;}
.TEST_IMG_EDIT_LIST_STEM {width:300px; margin:5px 0;} .TEST_IMG_EDIT_LIST_STEM {width:300px; border-radius:2px; margin:5px 0;}
.TEST_IMG_EDIT_LIST_ANS {width:225px; margin:5px 0;} .TEST_IMG_EDIT_LIST_ANS {width:225px; border-radius:2px; margin:5px 0;}
.TEST_IMG_EDIT_ONE_STEM {width:600px;} .TEST_IMG_EDIT_ONE_STEM {width:600px; border-radius:4px;}
.TEST_IMG_EDIT_ONE_ANS {width:450px;} .TEST_IMG_EDIT_ONE_ANS {width:450px; border-radius:4px;}
/******************************* Time table **********************************/ /******************************* Time table **********************************/
#timetable #timetable

View File

@ -132,13 +132,15 @@
/****************************** Public constants *****************************/ /****************************** Public constants *****************************/
/*****************************************************************************/ /*****************************************************************************/
#define Log_PLATFORM_VERSION "SWAD 15.183.1 (2016-04-06)" #define Log_PLATFORM_VERSION "SWAD 15.184 (2016-04-06)"
#define CSS_FILE "swad15.178.2.css" #define CSS_FILE "swad15.178.2.css"
#define JS_FILE "swad15.178.2.js" #define JS_FILE "swad15.178.2.js"
// Number of lines (includes comments but not blank lines) has been got with the following command: // 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 // nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1
/* /*
Version 15.184: Apr 06, 2016 Code refactoring in tests and images.
Fixed bugs in test questions. (198682 lines)
Version 15.183.1: Apr 06, 2016 Fix bug in feedback of test question. (198706 lines) Version 15.183.1: Apr 06, 2016 Fix bug in feedback of test question. (198706 lines)
Version 15.183: Apr 06, 2016 Change in length of title/attribution of images. (198704 lines) Version 15.183: Apr 06, 2016 Change in length of title/attribution of images. (198704 lines)
2 changes necessary in database: 2 changes necessary in database:

View File

@ -71,45 +71,47 @@ static void Img_ProcessImage (const char *FileNameImgOriginal,
/*************************** Reset image title *******************************/ /*************************** Reset image title *******************************/
/*****************************************************************************/ /*****************************************************************************/
void Img_ResetImageTitle (struct Image *Image) void Img_FreeImageTitle (struct Image *Image)
{ {
// Image->Title must be initialized to NULL
if (Image->Title) if (Image->Title)
{
free ((void *) Image->Title); free ((void *) Image->Title);
Image->Title = NULL; Image->Title = NULL;
}
} }
/*****************************************************************************/ /*****************************************************************************/
/********* Get image name and title from strings and copy to struct **********/ /****** Get image name and title from a query result and copy to struct ******/
/*****************************************************************************/ /*****************************************************************************/
void Img_GetImageNameAndTitle (const char *Name,const char *Title, void Img_GetImageNameAndTitleFromRow (const char *Name,const char *Title,
struct Image *Image) struct Image *Image)
{ {
size_t Length; size_t Length;
Img_ResetImageTitle (Image); /***** Copy image name to struct *****/
strncpy (Image->Name,Name,Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Image->Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
if (Name[0]) /***** Set status of image file *****/
Image->Status = Image->Name[0] ? Img_NAME_STORED_IN_DB :
Img_FILE_NONE;
/***** Copy image title to struct *****/
Img_FreeImageTitle (Image);
if (Title[0])
{ {
strncpy (Image->Name,Name,Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64); /* Get and limit length of the title */
Image->Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0'; Length = strlen (Title);
if (Length > Img_MAX_BYTES_TITLE)
Length = Img_MAX_BYTES_TITLE;
if (Image->Name[0]) // There is an image if ((Image->Title = (char *) malloc (Length+1)) == NULL)
if (Title[0]) Lay_ShowErrorAndExit ("Error allocating memory for image title.");
{ strncpy (Image->Title,Title,Length);
/* Get and limit length of the title */ Image->Title[Length] = '\0';
Length = strlen (Title);
if (Length > Img_MAX_BYTES_TITLE)
Length = Img_MAX_BYTES_TITLE;
if ((Image->Title = (char *) malloc (Length+1)) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for image title.");
strncpy (Image->Title,Title,Length);
Image->Title[Length] = '\0';
}
} }
else // No image in this question
Image->Name[0] = '\0';
} }
/*****************************************************************************/ /*****************************************************************************/
@ -117,50 +119,60 @@ void Img_GetImageNameAndTitle (const char *Name,const char *Title,
/*****************************************************************************/ /*****************************************************************************/
void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image, void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
void (*GetImageNameFromDB) (unsigned NumOpt,struct Image *Image), void (*GetImageFromDB) (unsigned NumOpt,struct Image *Image),
const char *ParamAction,const char *ParamFile,const char *ParamTitle, const char *ParamAction,const char *ParamFile,const char *ParamTitle,
unsigned Width,unsigned Height,unsigned Quality) unsigned Width,unsigned Height,unsigned Quality)
{ {
char Title[Img_MAX_BYTES_TITLE+1];
size_t Length;
Image->Action = Img_GetImageActionFromForm (ParamAction); Image->Action = Img_GetImageActionFromForm (ParamAction);
Image->Status = Img_FILE_NONE; Image->Status = Img_FILE_NONE;
Img_FreeImageTitle (Image); // Reset to NULL
switch (Image->Action) switch (Image->Action)
{ {
case Img_ACTION_NO_IMAGE: // Do not use image (remove current image if exists) case Img_ACTION_NO_IMAGE: // Do not use image (remove current image if exists)
/***** Reset image name *****/ /***** Reset image name *****/
Image->Name[0] = '\0'; Image->Name[0] = '\0';
Img_ResetImageTitle (Image);
break; break;
case Img_ACTION_KEEP_IMAGE: // Keep current image unchanged case Img_ACTION_KEEP_IMAGE: // Keep current image unchanged
/***** Get image name *****/ /***** Get image name *****/
GetImageNameFromDB (NumOpt,Image); GetImageFromDB (NumOpt,Image);
if (Image->Name[0])
Image->Status = Img_NAME_STORED_IN_DB;
break; break;
case Img_ACTION_NEW_IMAGE: // Upload new image case Img_ACTION_NEW_IMAGE: // Upload new image
/***** Get new image (if present ==> process and create temporary file) *****/ /***** Get new image (if present ==> process and create temporary file) *****/
Img_GetAndProcessImageFileFromForm (Image,ParamFile,ParamTitle, Img_GetAndProcessImageFileFromForm (Image,ParamFile,
Width,Height,Quality); Width,Height,Quality);
if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully
{ {
/* Reset image name */ /* Reset image name */
Image->Status = Img_FILE_NONE; Image->Status = Img_FILE_NONE;
Image->Name[0] = '\0'; Image->Name[0] = '\0';
Img_ResetImageTitle (Image);
} }
break; break;
case Img_ACTION_CHANGE_IMAGE: // Replace old image by new image case Img_ACTION_CHANGE_IMAGE: // Replace old image by new image
/***** Get new image (if present ==> process and create temporary file) *****/ /***** Get new image (if present ==> process and create temporary file) *****/
Img_GetAndProcessImageFileFromForm (Image,ParamFile,ParamTitle, Img_GetAndProcessImageFileFromForm (Image,ParamFile,
Width,Height,Quality); Width,Height,Quality);
if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully
{
/* Get image name */ /* Get image name */
GetImageNameFromDB (NumOpt,Image); GetImageFromDB (NumOpt,Image);
Image->Status = (Image->Name[0] ? Img_NAME_STORED_IN_DB :
Img_FILE_NONE);
}
break; break;
} }
/***** Get image title from form *****/
Par_GetParToHTML (ParamTitle,Title,Img_MAX_BYTES_TITLE);
if ((Length = strlen (Title)) > 0) // If title comming from the form is not empty
{
/* Overwrite current title (empty or coming from database)
with the title coming from the form */
Img_FreeImageTitle (Image);
if ((Image->Title = (char *) malloc (Length + 1)) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for image title.");
strncpy (Image->Title,Title,Length);
Image->Title[Length] = '\0';
}
} }
/*****************************************************************************/ /*****************************************************************************/
@ -183,12 +195,9 @@ Img_Action_t Img_GetImageActionFromForm (const char *ParamAction)
/*****************************************************************************/ /*****************************************************************************/
/**************************** Get image from form ****************************/ /**************************** Get image from form ****************************/
/*****************************************************************************/ /*****************************************************************************/
// Return true if image is created
void Img_GetAndProcessImageFileFromForm (struct Image *Image, void Img_GetAndProcessImageFileFromForm (struct Image *Image,const char *ParamFile,
const char *ParamFile,const char *ParamTitle, unsigned Width,unsigned Height,unsigned Quality)
unsigned Width,unsigned Height,
unsigned Quality)
{ {
struct Param *Param; struct Param *Param;
char FileNameImgSrc[PATH_MAX+1]; char FileNameImgSrc[PATH_MAX+1];
@ -199,8 +208,6 @@ void Img_GetAndProcessImageFileFromForm (struct Image *Image,
char FileNameImgOrig[PATH_MAX+1]; // Full name of original uploaded file char FileNameImgOrig[PATH_MAX+1]; // Full name of original uploaded file
char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file
bool WrongType = false; bool WrongType = false;
char Title[Img_MAX_BYTES_TITLE+1];
size_t Length;
/***** Rest image file status *****/ /***** Rest image file status *****/
Image->Status = Img_FILE_NONE; Image->Status = Img_FILE_NONE;
@ -265,17 +272,6 @@ void Img_GetAndProcessImageFileFromForm (struct Image *Image,
/***** Remove temporary original file *****/ /***** Remove temporary original file *****/
unlink (FileNameImgOrig); unlink (FileNameImgOrig);
/***** Get image title from form *****/
Par_GetParToHTML (ParamTitle,Title,Img_MAX_BYTES_TITLE); // TODO: Create a function to get only the length of a parameter
Length = strlen (Title);
if (Length > 0)
{
if ((Image->Title = (char *) malloc (Length+1)) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for image title.");
strncpy (Image->Title,Title,Length);
Image->Title[Length] = '\0';
}
} }
} }

View File

@ -94,19 +94,17 @@ struct Image
/***************************** Public prototypes *****************************/ /***************************** Public prototypes *****************************/
/*****************************************************************************/ /*****************************************************************************/
void Img_ResetImageTitle (struct Image *Image); void Img_FreeImageTitle (struct Image *Image);
void Img_GetImageNameAndTitle (const char *Name,const char *Title, void Img_GetImageNameAndTitleFromRow (const char *Name,const char *Title,
struct Image *Image); struct Image *Image);
void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image, void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
void (*GetImageNameFromDB) (unsigned NumOpt,struct Image *Image), void (*GetImageFromDB) (unsigned NumOpt,struct Image *Image),
const char *ParamAction,const char *ParamFile,const char *ParamTitle, const char *ParamAction,const char *ParamFile,const char *ParamTitle,
unsigned Width,unsigned Height,unsigned Quality); unsigned Width,unsigned Height,unsigned Quality);
Img_Action_t Img_GetImageActionFromForm (const char *ParamAction); Img_Action_t Img_GetImageActionFromForm (const char *ParamAction);
void Img_GetAndProcessImageFileFromForm (struct Image *Image, void Img_GetAndProcessImageFileFromForm (struct Image *Image,const char *ParamFile,
const char *ParamFile,const char *ParamTitle, unsigned Width,unsigned Height,unsigned Quality);
unsigned Width,unsigned Height,
unsigned Quality);
void Img_MoveImageToDefinitiveDirectory (struct Image *Image); void Img_MoveImageToDefinitiveDirectory (struct Image *Image);
void Img_ShowImage (struct Image *Image,const char *ClassImg); void Img_ShowImage (struct Image *Image,const char *ClassImg);

View File

@ -2527,7 +2527,7 @@ static unsigned Svy_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res)
/***** Count number of rows of result *****/ /***** Count number of rows of result *****/
if (NumRows == 0) if (NumRows == 0)
Lay_ShowErrorAndExit ("Error when getting answers of a question."); Lay_ShowAlert (Lay_ERROR,"Error when getting answers of a question.");
return (unsigned) NumRows; return (unsigned) NumRows;
} }
@ -3024,64 +3024,67 @@ static void Svy_WriteAnswersOfAQst (struct Survey *Svy,struct SurveyQuestion *Sv
NumAnswers = Svy_GetAnswersQst (SvyQst->QstCod,&mysql_res); // Result: AnsInd,NumUsrs,Answer NumAnswers = Svy_GetAnswersQst (SvyQst->QstCod,&mysql_res); // Result: AnsInd,NumUsrs,Answer
/***** Write the answers *****/ /***** Write the answers *****/
fprintf (Gbl.F.Out,"<table class=\"CELLS_PAD_5\" style=\"width:100%%;\">"); if (NumAnswers)
for (NumAns = 0;
NumAns < NumAnswers;
NumAns++)
{ {
row = mysql_fetch_row (mysql_res); fprintf (Gbl.F.Out,"<table class=\"CELLS_PAD_5\" style=\"width:100%%;\">");
for (NumAns = 0;
NumAns < NumAnswers;
NumAns++)
{
row = mysql_fetch_row (mysql_res);
/* Get number of users who have marked this answer (row[1]) */ /* Get number of users who have marked this answer (row[1]) */
if (sscanf (row[1],"%u",&NumUsrsThisAnswer) != 1) if (sscanf (row[1],"%u",&NumUsrsThisAnswer) != 1)
Lay_ShowErrorAndExit ("Error when getting number of users who have marked an answer."); Lay_ShowErrorAndExit ("Error when getting number of users who have marked an answer.");
/* Convert the answer (row[2]), that is in HTML, to rigorous HTML */ /* Convert the answer (row[2]), that is in HTML, to rigorous HTML */
AnsLength = strlen (row[2]) * Str_MAX_LENGTH_SPEC_CHAR_HTML; AnsLength = strlen (row[2]) * Str_MAX_LENGTH_SPEC_CHAR_HTML;
if ((Answer = malloc (AnsLength+1)) == NULL) if ((Answer = malloc (AnsLength+1)) == NULL)
Lay_ShowErrorAndExit ("Not enough memory to store answer."); Lay_ShowErrorAndExit ("Not enough memory to store answer.");
strcpy (Answer,row[2]); strcpy (Answer,row[2]);
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Answer,AnsLength,false); Answer,AnsLength,false);
/* Selectors and label with the letter of the answer */ /* Selectors and label with the letter of the answer */
fprintf (Gbl.F.Out,"<tr>"); fprintf (Gbl.F.Out,"<tr>");
if (PutFormAnswerSurvey) if (PutFormAnswerSurvey)
{ {
/* Write selector to choice this answer */ /* Write selector to choice this answer */
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP\">" fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP\">"
"<input type=\""); "<input type=\"");
if (SvyQst->AnswerType == Svy_ANS_UNIQUE_CHOICE) if (SvyQst->AnswerType == Svy_ANS_UNIQUE_CHOICE)
fprintf (Gbl.F.Out,"radio\"" fprintf (Gbl.F.Out,"radio\""
" onclick=\"selectUnselectRadio(this,this.form.Ans%010u,%u)\"", " onclick=\"selectUnselectRadio(this,this.form.Ans%010u,%u)\"",
(unsigned) SvyQst->QstCod,NumAnswers); (unsigned) SvyQst->QstCod,NumAnswers);
else // SvyQst->AnswerType == Svy_ANS_MULTIPLE_CHOICE else // SvyQst->AnswerType == Svy_ANS_MULTIPLE_CHOICE
fprintf (Gbl.F.Out,"checkbox\""); fprintf (Gbl.F.Out,"checkbox\"");
fprintf (Gbl.F.Out," name=\"Ans%010u\" value=\"%u\" />" fprintf (Gbl.F.Out," name=\"Ans%010u\" value=\"%u\" />"
"</td>", "</td>",
(unsigned) SvyQst->QstCod,NumAns); (unsigned) SvyQst->QstCod,NumAns);
} }
/* Write the number of option */ /* Write the number of option */
fprintf (Gbl.F.Out,"<td class=\"DAT LEFT_TOP\" style=\"width:50px;\">" fprintf (Gbl.F.Out,"<td class=\"DAT LEFT_TOP\" style=\"width:50px;\">"
"%u)" "%u)"
"</td>", "</td>",
NumAns + 1); NumAns + 1);
/* Write the text of the answer */ /* Write the text of the answer */
fprintf (Gbl.F.Out,"<td class=\"TEST_EDI LEFT_TOP\">%s</td>", fprintf (Gbl.F.Out,"<td class=\"TEST_EDI LEFT_TOP\">%s</td>",
Answer); Answer);
/* Show stats of this answer */ /* Show stats of this answer */
if (Svy->Status.ICanViewResults) if (Svy->Status.ICanViewResults)
Svy_DrawBarNumUsrs (NumUsrsThisAnswer,Svy->NumUsrs); Svy_DrawBarNumUsrs (NumUsrsThisAnswer,Svy->NumUsrs);
fprintf (Gbl.F.Out,"</tr>"); fprintf (Gbl.F.Out,"</tr>");
/* Free memory allocated for the answer */ /* Free memory allocated for the answer */
free ((void *) Answer); free ((void *) Answer);
}
fprintf (Gbl.F.Out,"</table>");
} }
fprintf (Gbl.F.Out,"</table>");
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);

View File

@ -219,6 +219,9 @@ static int Tst_CountNumTagsInList (void);
static int Tst_CountNumAnswerTypesInList (void); static int Tst_CountNumAnswerTypesInList (void);
static void Tst_PutFormEditOneQst (char *Stem,char *Feedback); static void Tst_PutFormEditOneQst (char *Stem,char *Feedback);
static void Tst_FreeTextChoiceAnswers (void);
static void Tst_FreeTextChoiceAnswer (unsigned NumOpt);
static void Tst_InitImagesOfQuestion (void); static void Tst_InitImagesOfQuestion (void);
static void Tst_FreeImagesOfQuestion (void); static void Tst_FreeImagesOfQuestion (void);
@ -236,7 +239,7 @@ static void Tst_EnableOrDisableTag (long TagCod,bool TagHidden);
static void Tst_PutIconToRemoveOneQst (void); static void Tst_PutIconToRemoveOneQst (void);
static void Tst_PutParamsRemoveOneQst (void); static void Tst_PutParamsRemoveOneQst (void);
static bool Tst_GetQstCod (void); static long Tst_GetQstCod (void);
static void Tst_InsertOrUpdateQstIntoDB (void); static void Tst_InsertOrUpdateQstIntoDB (void);
static void Tst_InsertTagsIntoDB (void); static void Tst_InsertTagsIntoDB (void);
@ -249,8 +252,6 @@ static void Tst_RemoveUnusedTagsFromCurrentCrs (void);
static void Tst_RemoveImgFilesFromStemOfQsts (long CrsCod,long QstCod); static void Tst_RemoveImgFilesFromStemOfQsts (long CrsCod,long QstCod);
static void Tst_RemoveImgFilesFromAnsOfQsts (long CrsCod,long QstCod,unsigned AnsInd); static void Tst_RemoveImgFilesFromAnsOfQsts (long CrsCod,long QstCod,unsigned AnsInd);
static void Tst_FreeTextChoiceAnswer (unsigned NumOpt);
static unsigned Tst_GetNumTstQuestions (Sco_Scope_t Scope,Tst_AnswerType_t AnsType,struct Tst_Stats *Stats); static unsigned Tst_GetNumTstQuestions (Sco_Scope_t Scope,Tst_AnswerType_t AnsType,struct Tst_Stats *Stats);
static unsigned Tst_GetNumCoursesWithTstQuestions (Sco_Scope_t Scope,Tst_AnswerType_t AnsType); static unsigned Tst_GetNumCoursesWithTstQuestions (Sco_Scope_t Scope,Tst_AnswerType_t AnsType);
static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Sco_Scope_t Scope,Tst_AnswerType_t AnsType); static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Sco_Scope_t Scope,Tst_AnswerType_t AnsType);
@ -981,6 +982,10 @@ static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
row[10] Score row[10] Score
*/ */
/***** Create test question *****/
Tst_QstConstructor ();
Gbl.Test.QstCod = QstCod;
/***** Write number of question *****/ /***** Write number of question *****/
fprintf (Gbl.F.Out,"<tr>" fprintf (Gbl.F.Out,"<tr>"
"<td class=\"RIGHT_TOP COLOR%u\">" "<td class=\"RIGHT_TOP COLOR%u\">"
@ -999,12 +1004,9 @@ static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">", fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
Gbl.RowEvenOdd); Gbl.RowEvenOdd);
Tst_WriteQstStem (row[4],"TEST_EXA"); Tst_WriteQstStem (row[4],"TEST_EXA");
if (row[6][0]) Img_GetImageNameAndTitleFromRow (row[6],row[7],&Gbl.Test.Image);
{ Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_SHOW_STEM");
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameAndTitle (row[6],row[7],&Gbl.Test.Image);
Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_SHOW_STEM");
}
if (Gbl.Action.Act == ActSeeTst) if (Gbl.Action.Act == ActSeeTst)
Tst_WriteAnswersOfAQstSeeExam (NumQst,QstCod,(Str_ConvertToUpperLetter (row[3][0]) == 'Y')); Tst_WriteAnswersOfAQstSeeExam (NumQst,QstCod,(Str_ConvertToUpperLetter (row[3][0]) == 'Y'));
else // Assessing exam / Viewing old exam else // Assessing exam / Viewing old exam
@ -1018,9 +1020,8 @@ static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
fprintf (Gbl.F.Out,"</td>" fprintf (Gbl.F.Out,"</td>"
"</tr>"); "</tr>");
/***** Free answers and images of this test question *****/ /***** Destroy test question *****/
Tst_FreeTextChoiceAnswers (); Tst_QstDestructor ();
Tst_FreeImagesOfQuestion ();
} }
/*****************************************************************************/ /*****************************************************************************/
@ -2615,7 +2616,6 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
Tst_QuestionsOrder_t Order; Tst_QuestionsOrder_t Order;
unsigned long NumRow; unsigned long NumRow;
MYSQL_ROW row; MYSQL_ROW row;
long QstCod;
unsigned UniqueId; unsigned UniqueId;
time_t TimeUTC; time_t TimeUTC;
unsigned long NumHitsThisQst; unsigned long NumHitsThisQst;
@ -2706,8 +2706,11 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
row[ 9] NumHitsNotBlank row[ 9] NumHitsNotBlank
row[10] Score row[10] Score
*/ */
/***** Create test question *****/
Tst_QstConstructor ();
/* row[0] holds the code of the question */ /* row[0] holds the code of the question */
if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((Gbl.Test.QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/* Write icon to remove the question */ /* Write icon to remove the question */
@ -2716,7 +2719,7 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
Act_FormStart (ActReqRemTstQst); Act_FormStart (ActReqRemTstQst);
Sta_WriteParamsDatesSeeAccesses (); Sta_WriteParamsDatesSeeAccesses ();
Tst_WriteParamEditQst (); Tst_WriteParamEditQst ();
Par_PutHiddenParamLong ("QstCod",QstCod); Par_PutHiddenParamLong ("QstCod",Gbl.Test.QstCod);
if (NumRows == 1) if (NumRows == 1)
Par_PutHiddenParamChar ("OnlyThisQst",'Y'); // If there are only one row, don't list again after removing Par_PutHiddenParamChar ("OnlyThisQst",'Y'); // If there are only one row, don't list again after removing
Lay_PutIconRemove (); Lay_PutIconRemove ();
@ -2726,7 +2729,7 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
/* Write icon to edit the question */ /* Write icon to edit the question */
fprintf (Gbl.F.Out,"<td class=\"BT%u\">",Gbl.RowEvenOdd); fprintf (Gbl.F.Out,"<td class=\"BT%u\">",Gbl.RowEvenOdd);
Act_FormStart (ActEdiOneTstQst); Act_FormStart (ActEdiOneTstQst);
Par_PutHiddenParamLong ("QstCod",QstCod); Par_PutHiddenParamLong ("QstCod",Gbl.Test.QstCod);
fprintf (Gbl.F.Out,"<input type=\"image\" src=\"%s/edit64x64.png\"" fprintf (Gbl.F.Out,"<input type=\"image\" src=\"%s/edit64x64.png\""
" alt=\"%s\" title=\"%s\"" " alt=\"%s\" title=\"%s\""
" class=\"ICON20x20\" />", " class=\"ICON20x20\" />",
@ -2746,7 +2749,7 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
fprintf (Gbl.F.Out,"<td class=\"DAT_SMALL CENTER_TOP COLOR%u\">" fprintf (Gbl.F.Out,"<td class=\"DAT_SMALL CENTER_TOP COLOR%u\">"
"%ld&nbsp;" "%ld&nbsp;"
"</td>", "</td>",
Gbl.RowEvenOdd,QstCod); Gbl.RowEvenOdd,Gbl.Test.QstCod);
/* Write the date (row[1] has the UTC date-time) */ /* Write the date (row[1] has the UTC date-time) */
TimeUTC = Dat_GetUNIXTimeFromStr (row[1]); TimeUTC = Dat_GetUNIXTimeFromStr (row[1]);
@ -2762,7 +2765,7 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
/* Write the question tags */ /* Write the question tags */
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">", fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
Gbl.RowEvenOdd); Gbl.RowEvenOdd);
Tst_GetAndWriteTagsQst (QstCod); Tst_GetAndWriteTagsQst (Gbl.Test.QstCod);
fprintf (Gbl.F.Out,"</td>"); fprintf (Gbl.F.Out,"</td>");
/* Write the question type (row[2]) */ /* Write the question type (row[2]) */
@ -2780,7 +2783,7 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE)
{ {
Act_FormStart (ActShfTstQst); Act_FormStart (ActShfTstQst);
Par_PutHiddenParamLong ("QstCod",QstCod); Par_PutHiddenParamLong ("QstCod",Gbl.Test.QstCod);
Sta_WriteParamsDatesSeeAccesses (); Sta_WriteParamsDatesSeeAccesses ();
Tst_WriteParamEditQst (); Tst_WriteParamEditQst ();
if (NumRows == 1) if (NumRows == 1)
@ -2800,20 +2803,12 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">", fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
Gbl.RowEvenOdd); Gbl.RowEvenOdd);
Tst_WriteQstStem (row[4],"TEST_EDI"); Tst_WriteQstStem (row[4],"TEST_EDI");
if (row[6][0]) Img_GetImageNameAndTitleFromRow (row[6],row[7],&Gbl.Test.Image);
{ Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_EDIT_LIST_STEM");
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameAndTitle (row[6],row[7],&Gbl.Test.Image);
Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_EDIT_LIST_STEM");
}
Tst_WriteQstFeedback (row[5],"TEST_EDI_LIGHT"); Tst_WriteQstFeedback (row[5],"TEST_EDI_LIGHT");
Tst_WriteAnswersOfAQstEdit (QstCod); Tst_WriteAnswersOfAQstEdit (Gbl.Test.QstCod);
fprintf (Gbl.F.Out,"</td>"); fprintf (Gbl.F.Out,"</td>");
/* Free answers and images of this test question */
Tst_FreeTextChoiceAnswers ();
Tst_FreeImagesOfQuestion ();
/* Get number of hits /* Get number of hits
(number of times that the question has been answered, (number of times that the question has been answered,
including blank answers) (row[8]) */ including blank answers) (row[8]) */
@ -2865,6 +2860,9 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
fprintf (Gbl.F.Out,"N.A."); fprintf (Gbl.F.Out,"N.A.");
fprintf (Gbl.F.Out,"</td>" fprintf (Gbl.F.Out,"</td>"
"</tr>"); "</tr>");
/***** Destroy test question *****/
Tst_QstDestructor ();
} }
/***** End table *****/ /***** End table *****/
@ -2901,7 +2899,7 @@ void Tst_WriteParamEditQst (void)
unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle) unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle)
{ {
char Query[256]; char Query[512];
unsigned long NumRows; unsigned long NumRows;
/***** Get answers of a question from database *****/ /***** Get answers of a question from database *****/
@ -2911,7 +2909,7 @@ unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle)
Shuffle ? "RAND(NOW())" : Shuffle ? "RAND(NOW())" :
"AnsInd"); "AnsInd");
if (!(NumRows = DB_QuerySELECT (Query,mysql_res,"can not get answers of a question"))) if (!(NumRows = DB_QuerySELECT (Query,mysql_res,"can not get answers of a question")))
Lay_ShowErrorAndExit ("Error when getting answers of a question."); Lay_ShowAlert (Lay_ERROR,"Error when getting answers of a question.");
return (unsigned) NumRows; return (unsigned) NumRows;
} }
@ -3007,11 +3005,7 @@ static void Tst_WriteAnswersOfAQstEdit (long QstCod)
} }
/* Copy image */ /* Copy image */
if (row[3][0]) Img_GetImageNameAndTitleFromRow (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
{
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameAndTitle (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
}
/* Put an icon that indicates whether the answer is correct or wrong */ /* Put an icon that indicates whether the answer is correct or wrong */
fprintf (Gbl.F.Out,"<tr>" fprintf (Gbl.F.Out,"<tr>"
@ -3037,8 +3031,7 @@ static void Tst_WriteAnswersOfAQstEdit (long QstCod)
"<div class=\"TEST_EDI\">" "<div class=\"TEST_EDI\">"
"%s", "%s",
Answer); Answer);
if (Gbl.Test.Answer.Options[NumOpt].Image.Name[0]) Img_ShowImage (&Gbl.Test.Answer.Options[NumOpt].Image,"TEST_IMG_EDIT_LIST_ANS");
Img_ShowImage (&Gbl.Test.Answer.Options[NumOpt].Image,"TEST_IMG_EDIT_LIST_ANS");
fprintf (Gbl.F.Out,"</div>"); fprintf (Gbl.F.Out,"</div>");
/* Write the text of the feedback */ /* Write the text of the feedback */
@ -3106,6 +3099,10 @@ static void Tst_WriteAnswersOfAQstAssessExam (unsigned NumQst,long QstCod,
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
/***** Create test question *****/
Tst_QstConstructor ();
Gbl.Test.QstCod = QstCod;
/***** Get answers of a question from database *****/ /***** Get answers of a question from database *****/
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct
/* /*
@ -3141,6 +3138,9 @@ static void Tst_WriteAnswersOfAQstAssessExam (unsigned NumQst,long QstCod,
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
/***** Destroy test question *****/
Tst_QstDestructor ();
} }
/*****************************************************************************/ /*****************************************************************************/
@ -3281,8 +3281,9 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
bool ErrorInIndex = false; bool ErrorInIndex = false;
char ParamName[3+6+1]; char ParamName[3+6+1];
/***** Start of table *****/ /***** Create test question *****/
fprintf (Gbl.F.Out,"<table class=\"CELLS_PAD_2\">"); Tst_QstConstructor ();
Gbl.Test.QstCod = QstCod;
/***** Get answers of a question from database *****/ /***** Get answers of a question from database *****/
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,Shuffle); // Result: AnsInd,Answer,Correct Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,Shuffle); // Result: AnsInd,Answer,Correct
@ -3294,6 +3295,10 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
row[ 4] ImageTitle row[ 4] ImageTitle
row[ 5] Correct row[ 5] Correct
*/ */
/***** Start of table *****/
fprintf (Gbl.F.Out,"<table class=\"CELLS_PAD_2\">");
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions; NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++) NumOpt++)
@ -3324,11 +3329,7 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
/***** Copy image *****/ /***** Copy image *****/
if (row[3][0]) Img_GetImageNameAndTitleFromRow (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
{
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameAndTitle (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
}
/***** Write selectors and letter of this option *****/ /***** Write selectors and letter of this option *****/
fprintf (Gbl.F.Out,"<tr>" fprintf (Gbl.F.Out,"<tr>"
@ -3351,8 +3352,7 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
fprintf (Gbl.F.Out,"<td class=\"TEST_EXA LEFT_TOP\">" fprintf (Gbl.F.Out,"<td class=\"TEST_EXA LEFT_TOP\">"
"%s", "%s",
Gbl.Test.Answer.Options[NumOpt].Text); Gbl.Test.Answer.Options[NumOpt].Text);
if (Gbl.Test.Answer.Options[NumOpt].Image.Name[0]) Img_ShowImage (&Gbl.Test.Answer.Options[NumOpt].Image,"TEST_IMG_SHOW_ANS");
Img_ShowImage (&Gbl.Test.Answer.Options[NumOpt].Image,"TEST_IMG_SHOW_ANS");
fprintf (Gbl.F.Out,"</td>" fprintf (Gbl.F.Out,"</td>"
"</tr>"); "</tr>");
} }
@ -3360,12 +3360,11 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
/***** End of table *****/ /***** End of table *****/
fprintf (Gbl.F.Out,"</table>"); fprintf (Gbl.F.Out,"</table>");
/***** Free answers and images of this test question *****/
Tst_FreeTextChoiceAnswers ();
Tst_FreeImagesOfQuestion ();
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
/***** Destroy test question *****/
Tst_QstDestructor ();
} }
/*****************************************************************************/ /*****************************************************************************/
@ -3430,11 +3429,7 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
} }
/***** Copy image *****/ /***** Copy image *****/
if (row[3][0]) Img_GetImageNameAndTitleFromRow (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
{
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameAndTitle (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
}
/***** Assign correctness (row[5]) of this answer (this option) *****/ /***** Assign correctness (row[5]) of this answer (this option) *****/
Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[5][0]) == 'Y'); Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[5][0]) == 'Y');
@ -3526,8 +3521,7 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
"<div class=\"TEST_EXA\">" "<div class=\"TEST_EXA\">"
"%s", "%s",
Gbl.Test.Answer.Options[Indexes[NumOpt]].Text); Gbl.Test.Answer.Options[Indexes[NumOpt]].Text);
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Image.Name[0]) Img_ShowImage (&Gbl.Test.Answer.Options[Indexes[NumOpt]].Image,"TEST_IMG_SHOW_ANS");
Img_ShowImage (&Gbl.Test.Answer.Options[Indexes[NumOpt]].Image,"TEST_IMG_SHOW_ANS");
fprintf (Gbl.F.Out,"</div>"); fprintf (Gbl.F.Out,"</div>");
if (Gbl.Test.Config.FeedbackType == Tst_FEEDBACK_FULL_FEEDBACK) if (Gbl.Test.Config.FeedbackType == Tst_FEEDBACK_FULL_FEEDBACK)
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback) if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback)
@ -3606,10 +3600,6 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
/***** End of table *****/ /***** End of table *****/
fprintf (Gbl.F.Out,"</table>"); fprintf (Gbl.F.Out,"</table>");
/***** Free answers and images of this test question *****/
Tst_FreeTextChoiceAnswers ();
Tst_FreeImagesOfQuestion ();
} }
/*****************************************************************************/ /*****************************************************************************/
@ -3791,9 +3781,6 @@ static void Tst_WriteTextAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
} }
fprintf (Gbl.F.Out,"</table>"); fprintf (Gbl.F.Out,"</table>");
/***** Free answers *****/
Tst_FreeTextChoiceAnswers ();
} }
/*****************************************************************************/ /*****************************************************************************/
@ -4351,8 +4338,18 @@ void Tst_ShowFormEditOneQst (void)
char Stem[Cns_MAX_BYTES_TEXT+1]; char Stem[Cns_MAX_BYTES_TEXT+1];
char Feedback[Cns_MAX_BYTES_TEXT+1]; char Feedback[Cns_MAX_BYTES_TEXT+1];
/***** Create test question *****/
Tst_QstConstructor ();
Gbl.Test.QstCod = Tst_GetQstCod ();
Stem[0] = Feedback[0] = '\0'; Stem[0] = Feedback[0] = '\0';
if (Gbl.Test.QstCod > 0) // If question already exists in the database
Tst_GetQstDataFromDB (Stem,Feedback);
/***** Put form to edit question *****/
Tst_PutFormEditOneQst (Stem,Feedback); Tst_PutFormEditOneQst (Stem,Feedback);
/***** Destroy test question *****/
Tst_QstDestructor ();
} }
/*****************************************************************************/ /*****************************************************************************/
@ -4398,16 +4395,6 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
char ParamFile[32]; char ParamFile[32];
char ParamTitle[32]; char ParamTitle[32];
/***** If no receiving the question, but editing a new or existing question
==> init or edit data of question *****/
if (Gbl.Action.Act == ActEdiOneTstQst)
{
Tst_InitQst ();
if (Tst_GetQstCod ()) // If parameter QstCod received ==>
// ==> question already exists in the database
Tst_GetQstDataFromDB (Stem,Feedback);
}
/***** Start frame *****/ /***** Start frame *****/
if (Gbl.Test.QstCod > 0) // The question already has assigned a code if (Gbl.Test.QstCod > 0) // The question already has assigned a code
{ {
@ -4737,21 +4724,18 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
/***** End frame *****/ /***** End frame *****/
Lay_EndRoundFrame (); Lay_EndRoundFrame ();
/***** Free memory for answers *****/
Tst_FreeTextChoiceAnswers ();
} }
/*****************************************************************************/ /*****************************************************************************/
/********************* Initialize a new question to zero *********************/ /********************* Initialize a new question to zero *********************/
/*****************************************************************************/ /*****************************************************************************/
void Tst_InitQst (void) void Tst_QstConstructor (void)
{ {
unsigned NumOpt; unsigned NumOpt;
unsigned NumTag; unsigned NumTag;
Gbl.Test.QstCod = -1; Gbl.Test.QstCod = -1L;
for (NumTag = 0; for (NumTag = 0;
NumTag < Tst_MAX_TAGS_PER_QUESTION; NumTag < Tst_MAX_TAGS_PER_QUESTION;
NumTag++) NumTag++)
@ -4781,6 +4765,74 @@ void Tst_InitQst (void)
Tst_InitImagesOfQuestion (); Tst_InitImagesOfQuestion ();
} }
/*****************************************************************************/
/***************** Free memory allocated for test question *******************/
/*****************************************************************************/
void Tst_QstDestructor (void)
{
Tst_FreeTextChoiceAnswers ();
Tst_FreeImagesOfQuestion ();
}
/*****************************************************************************/
/******************* Allocate memory for a choice answer *********************/
/*****************************************************************************/
int Tst_AllocateTextChoiceAnswer (unsigned NumOpt)
{
Tst_FreeTextChoiceAnswer (NumOpt);
if ((Gbl.Test.Answer.Options[NumOpt].Text =
malloc (Tst_MAX_BYTES_ANSWER_OR_FEEDBACK + 1)) == NULL)
{
sprintf (Gbl.Message,"Not enough memory to store answer.");
return 0;
}
if ((Gbl.Test.Answer.Options[NumOpt].Feedback =
malloc (Tst_MAX_BYTES_ANSWER_OR_FEEDBACK + 1)) == NULL)
{
sprintf (Gbl.Message,"Not enough memory to store feedback.");
return 0;
}
Gbl.Test.Answer.Options[NumOpt].Text[0] =
Gbl.Test.Answer.Options[NumOpt].Feedback[0] = '\0';
return 1;
}
/*****************************************************************************/
/******************** Free memory of all choice answers **********************/
/*****************************************************************************/
static void Tst_FreeTextChoiceAnswers (void)
{
unsigned NumOpt;
for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
Tst_FreeTextChoiceAnswer (NumOpt);
}
/*****************************************************************************/
/********************** Free memory of a choice answer ***********************/
/*****************************************************************************/
static void Tst_FreeTextChoiceAnswer (unsigned NumOpt)
{
if (Gbl.Test.Answer.Options[NumOpt].Text)
{
free ((void *) Gbl.Test.Answer.Options[NumOpt].Text);
Gbl.Test.Answer.Options[NumOpt].Text = NULL;
}
if (Gbl.Test.Answer.Options[NumOpt].Feedback)
{
free ((void *) Gbl.Test.Answer.Options[NumOpt].Feedback);
Gbl.Test.Answer.Options[NumOpt].Feedback = NULL;
}
}
/*****************************************************************************/ /*****************************************************************************/
/***************** Initialize images of a question to zero *******************/ /***************** Initialize images of a question to zero *******************/
/*****************************************************************************/ /*****************************************************************************/
@ -4812,11 +4864,11 @@ static void Tst_FreeImagesOfQuestion (void)
{ {
unsigned NumOpt; unsigned NumOpt;
Img_ResetImageTitle (&Gbl.Test.Image); Img_FreeImageTitle (&Gbl.Test.Image);
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION; NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++) NumOpt++)
Img_ResetImageTitle (&Gbl.Test.Answer.Options[NumOpt].Image); Img_FreeImageTitle (&Gbl.Test.Answer.Options[NumOpt].Image);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -4869,13 +4921,7 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
} }
/* Get the image name of the question from the database (row[4]) */ /* Get the image name of the question from the database (row[4]) */
if (row[4][0]) Img_GetImageNameAndTitleFromRow (row[4],row[5],&Gbl.Test.Image);
{
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameAndTitle (row[4],row[5],&Gbl.Test.Image);
}
else
Gbl.Test.Image.Status = Img_FILE_NONE;
/* Free structure that stores the query result */ /* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
@ -4946,11 +4992,7 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
} }
/* Copy image */ /* Copy image */
if (row[3][0]) Img_GetImageNameAndTitleFromRow (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
{
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameAndTitle (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
}
Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[5][0]) == 'Y'); Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[5][0]) == 'Y');
break; break;
@ -4991,7 +5033,7 @@ static void Tst_GetImageFromDB (unsigned NumOpt,struct Image *Image)
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/***** Get the image name (row[0]) *****/ /***** Get the image name (row[0]) *****/
Img_GetImageNameAndTitle (row[0],row[1],Image); Img_GetImageNameAndTitleFromRow (row[0],row[1],Image);
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
@ -5040,11 +5082,11 @@ void Tst_ReceiveQst (void)
char Stem[Cns_MAX_BYTES_TEXT+1]; char Stem[Cns_MAX_BYTES_TEXT+1];
char Feedback[Cns_MAX_BYTES_TEXT+1]; char Feedback[Cns_MAX_BYTES_TEXT+1];
/***** Initialize new question to zero *****/ /***** Create test question *****/
Tst_InitQst (); Tst_QstConstructor ();
Stem[0] = Feedback[0] = '\0';
/***** Get parameters of the question from form *****/ /***** Get parameters of the question from form *****/
Stem[0] = Feedback[0] = '\0';
Tst_GetQstFromForm (Stem,Feedback); Tst_GetQstFromForm (Stem,Feedback);
/***** Make sure that tags, text and answer are not empty *****/ /***** Make sure that tags, text and answer are not empty *****/
@ -5068,8 +5110,8 @@ void Tst_ReceiveQst (void)
Tst_PutFormEditOneQst (Stem,Feedback); Tst_PutFormEditOneQst (Stem,Feedback);
} }
/***** Free answers *****/ /***** Destroy test question *****/
Tst_FreeTextChoiceAnswers (); Tst_QstDestructor ();
} }
/*****************************************************************************/ /*****************************************************************************/
@ -5094,7 +5136,7 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
char ParamTitle[32]; char ParamTitle[32];
/***** Get question code *****/ /***** Get question code *****/
Tst_GetQstCod (); Gbl.Test.QstCod = Tst_GetQstCod ();
/***** Get answer type *****/ /***** Get answer type *****/
Par_GetParToText ("AnswerType",UnsignedStr,10); Par_GetParToText ("AnswerType",UnsignedStr,10);
@ -5645,7 +5687,8 @@ void Tst_RequestRemoveQst (void)
/***** Get main parameters from form *****/ /***** Get main parameters from form *****/
/* Get the question code */ /* Get the question code */
if (!Tst_GetQstCod ()) Gbl.Test.QstCod = Tst_GetQstCod ();
if (Gbl.Test.QstCod <= 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/* Get a parameter that indicates whether it's necessary /* Get a parameter that indicates whether it's necessary
@ -5697,7 +5740,8 @@ void Tst_RemoveQst (void)
bool EditingOnlyThisQst; bool EditingOnlyThisQst;
/***** Get the question code *****/ /***** Get the question code *****/
if (!Tst_GetQstCod ()) Gbl.Test.QstCod = Tst_GetQstCod ();
if (Gbl.Test.QstCod <= 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/***** Get a parameter that indicates whether it's necessary /***** Get a parameter that indicates whether it's necessary
@ -5749,7 +5793,8 @@ void Tst_ChangeShuffleQst (void)
bool Shuffle; bool Shuffle;
/***** Get the question code *****/ /***** Get the question code *****/
if (!Tst_GetQstCod ()) Gbl.Test.QstCod = Tst_GetQstCod ();
if (Gbl.Test.QstCod <= 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/***** Get a parameter that indicates whether it's necessary to continue listing the rest of questions ******/ /***** Get a parameter that indicates whether it's necessary to continue listing the rest of questions ******/
@ -5787,14 +5832,12 @@ void Tst_ChangeShuffleQst (void)
/************ Get the parameter with the code of a test question *************/ /************ Get the parameter with the code of a test question *************/
/*****************************************************************************/ /*****************************************************************************/
static bool Tst_GetQstCod (void) static long Tst_GetQstCod (void)
{ {
char LongStr[1+10+1]; char LongStr[1+10+1];
Par_GetParToText ("QstCod",LongStr,1+10); Par_GetParToText ("QstCod",LongStr,1+10);
if ((Gbl.Test.QstCod = Str_ConvertStrCodToLongCod (LongStr)) < 0) return Str_ConvertStrCodToLongCod (LongStr);
return false;
return true;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -5825,9 +5868,10 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
char *Query; char *Query;
/***** Allocate space for query *****/ /***** Allocate space for query *****/
if ((Query = malloc (256 + if ((Query = malloc (512 +
Gbl.Test.Stem.Length + Gbl.Test.Stem.Length +
Gbl.Test.Feedback.Length)) == NULL) Gbl.Test.Feedback.Length +
Img_MAX_BYTES_TITLE)) == NULL)
Lay_ShowErrorAndExit ("Not enough memory to store database query."); Lay_ShowErrorAndExit ("Not enough memory to store database query.");
if (Gbl.Test.QstCod < 0) // It's a new question if (Gbl.Test.QstCod < 0) // It's a new question
@ -6144,64 +6188,6 @@ static void Tst_RemoveImgFilesFromAnsOfQsts (long CrsCod,
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
} }
/*****************************************************************************/
/******************* Allocate memory for a choice answer *********************/
/*****************************************************************************/
int Tst_AllocateTextChoiceAnswer (unsigned NumOpt)
{
Tst_FreeTextChoiceAnswer (NumOpt);
if ((Gbl.Test.Answer.Options[NumOpt].Text =
malloc (Tst_MAX_BYTES_ANSWER_OR_FEEDBACK + 1)) == NULL)
{
sprintf (Gbl.Message,"Not enough memory to store answer.");
return 0;
}
if ((Gbl.Test.Answer.Options[NumOpt].Feedback =
malloc (Tst_MAX_BYTES_ANSWER_OR_FEEDBACK + 1)) == NULL)
{
sprintf (Gbl.Message,"Not enough memory to store feedback.");
return 0;
}
Gbl.Test.Answer.Options[NumOpt].Text[0] =
Gbl.Test.Answer.Options[NumOpt].Feedback[0] = '\0';
return 1;
}
/*****************************************************************************/
/******************** Free memory of all choice answers **********************/
/*****************************************************************************/
void Tst_FreeTextChoiceAnswers (void)
{
unsigned NumOpt;
for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
Tst_FreeTextChoiceAnswer (NumOpt);
}
/*****************************************************************************/
/********************** Free memory of a choice answer ***********************/
/*****************************************************************************/
static void Tst_FreeTextChoiceAnswer (unsigned NumOpt)
{
if (Gbl.Test.Answer.Options[NumOpt].Text)
{
free ((void *) Gbl.Test.Answer.Options[NumOpt].Text);
Gbl.Test.Answer.Options[NumOpt].Text = NULL;
}
if (Gbl.Test.Answer.Options[NumOpt].Feedback)
{
free ((void *) Gbl.Test.Answer.Options[NumOpt].Feedback);
Gbl.Test.Answer.Options[NumOpt].Feedback = NULL;
}
}
/*****************************************************************************/ /*****************************************************************************/
/*********************** Get stats about test questions **********************/ /*********************** Get stats about test questions **********************/
/*****************************************************************************/ /*****************************************************************************/

View File

@ -141,7 +141,12 @@ void Tst_GetConfigFromRow (MYSQL_ROW row);
bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void); bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void);
void Tst_ReceiveConfigTst (void); void Tst_ReceiveConfigTst (void);
void Tst_ShowFormEditOneQst (void); void Tst_ShowFormEditOneQst (void);
void Tst_InitQst (void);
void Tst_QstConstructor (void);
void Tst_QstDestructor (void);
int Tst_AllocateTextChoiceAnswer (unsigned NumOpt);
Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD); Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD);
void Tst_ReceiveQst (void); void Tst_ReceiveQst (void);
bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void); bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void);
@ -152,8 +157,6 @@ void Tst_RemoveQst (void);
void Tst_ChangeShuffleQst (void); void Tst_ChangeShuffleQst (void);
void Tst_InsertOrUpdateQstTagsAnsIntoDB (void); void Tst_InsertOrUpdateQstTagsAnsIntoDB (void);
int Tst_AllocateTextChoiceAnswer (unsigned NumOpt);
void Tst_FreeTextChoiceAnswers (void);
void Tst_FreeTagsList (void); void Tst_FreeTagsList (void);
void Tst_GetTestStats (Tst_AnswerType_t AnsType,struct Tst_Stats *Stats); void Tst_GetTestStats (Tst_AnswerType_t AnsType,struct Tst_Stats *Stats);

View File

@ -533,8 +533,8 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
{ {
if (!strcmp (QuestionElem->TagName,"question")) if (!strcmp (QuestionElem->TagName,"question"))
{ {
/***** Initialize new question to zero *****/ /***** Create test question *****/
Tst_InitQst (); Tst_QstConstructor ();
/* Get type of questions (in mandatory attribute "type") */ /* Get type of questions (in mandatory attribute "type") */
AnswerTypeFound = false; AnswerTypeFound = false;
@ -653,8 +653,8 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
} }
} }
/***** Free answers *****/ /***** Destroy test question *****/
Tst_FreeTextChoiceAnswers (); Tst_QstDestructor ();
} }
} }