Version19.228

This commit is contained in:
acanas 2020-05-13 12:53:27 +02:00
parent 4368244ffa
commit 4377742d58
9 changed files with 585 additions and 282 deletions

View File

@ -548,10 +548,12 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD:
ps2pdf source.ps destination.pdf
*/
#define Log_PLATFORM_VERSION "SWAD 19.227 (2020-05-13)"
#define Log_PLATFORM_VERSION "SWAD 19.228 (2020-05-13)"
#define CSS_FILE "swad19.217.css"
#define JS_FILE "swad19.223.js"
/*
Version 19.228: May 13, 2020 Code refactoring and bug fixing in exam prints. (303837 lines)
Version 19.227.1: May 13, 2020 Cache of linked GIFs and videos. (303612 lines)
Version 19.227: May 13, 2020 Cache of linked images. (303586 lines)
1 change necessary in database:
CREATE TABLE IF NOT EXISTS file_cache (SessionId CHAR(43) NOT NULL,PrivPath TEXT COLLATE latin1_bin NOT NULL,TmpPubDir TEXT COLLATE latin1_bin NOT NULL,INDEX(SessionId));

View File

@ -36,6 +36,7 @@
#include "swad_date.h"
#include "swad_exam.h"
#include "swad_exam_event.h"
#include "swad_exam_print.h"
#include "swad_exam_result.h"
#include "swad_exam_set.h"
#include "swad_exam_type.h"
@ -4210,7 +4211,7 @@ static void ExaEvt_ComputeScore (struct TstPrn_Print *Print)
Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE;
/***** Compute score for this answer ******/
TstPrn_ComputeChoiceAnsScore (&Print->PrintedQuestions[NumQst],&Question);
ExaPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question);
/***** Update total score *****/
Print->Score += Print->PrintedQuestions[NumQst].Score;

View File

@ -36,6 +36,7 @@
#include "swad_database.h"
#include "swad_exam.h"
#include "swad_exam_event.h"
#include "swad_exam_print.h"
#include "swad_exam_result.h"
#include "swad_exam_set.h"
#include "swad_exam_type.h"
@ -129,6 +130,28 @@ static void ExaPrn_ComputeScoresAndStoreQuestionsOfPrint (struct ExaPrn_Print *P
bool UpdateQstScore);
static void ExaPrn_ComputeScoreAndStoreQuestionOfPrint (struct ExaPrn_Print *Print,
unsigned NumQst);
//-----------------------------------------------------------------------------
static void ExaPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void ExaPrn_GetCorrectAndComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void ExaPrn_GetCorrectAndComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void ExaPrn_GetCorrectAndComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void ExaPrn_GetCorrectAndComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void ExaPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question);
static void ExaPrn_GetCorrectFltAnswerFromDB (struct Tst_Question *Question);
static void ExaPrn_GetCorrectTF_AnswerFromDB (struct Tst_Question *Question);
static void ExaPrn_GetCorrectChoAnswerFromDB (struct Tst_Question *Question);
static void ExaPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question);
//-----------------------------------------------------------------------------
static void ExaPrn_GetAnswerFromDB (struct ExaPrn_Print *Print,long QstCod,
char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]);
static void ExaPrn_StoreOneQstOfPrintInDB (const struct ExaPrn_Print *Print,
@ -1047,7 +1070,7 @@ static void ExaPrn_ComputeScoreAndStoreQuestionOfPrint (struct ExaPrn_Print *Pri
Tst_QstConstructor (&Question);
Question.QstCod = Print->PrintedQuestions[NumQst].QstCod;
Question.Answer.Type = ExaSet_GetQstAnswerTypeFromDB (Question.QstCod);
TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question);
ExaPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question);
Tst_QstDestructor (&Question);
/***** If type is unique choice and the option (radio button) is checked
@ -1065,6 +1088,247 @@ static void ExaPrn_ComputeScoreAndStoreQuestionOfPrint (struct ExaPrn_Print *Pri
NumQst); // 0, 1, 2, 3...
}
/*****************************************************************************/
/************* Write answers of a question when assessing a test *************/
/*****************************************************************************/
void ExaPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Write answer depending on type *****/
switch (Question->Answer.Type)
{
case Tst_ANS_INT:
ExaPrn_GetCorrectAndComputeIntAnsScore (PrintedQuestion,Question); break;
case Tst_ANS_FLOAT:
ExaPrn_GetCorrectAndComputeFltAnsScore (PrintedQuestion,Question); break;
case Tst_ANS_TRUE_FALSE:
ExaPrn_GetCorrectAndComputeTF_AnsScore (PrintedQuestion,Question); break;
case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE:
ExaPrn_GetCorrectAndComputeChoAnsScore (PrintedQuestion,Question); break;
case Tst_ANS_TEXT:
ExaPrn_GetCorrectAndComputeTxtAnsScore (PrintedQuestion,Question); break;
default:
break;
}
}
/*****************************************************************************/
/******* Get correct answer and compute score for each type of answer ********/
/*****************************************************************************/
static void ExaPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get the numerical value of the correct answer *****/
ExaPrn_GetCorrectIntAnswerFromDB (Question);
/***** Compute score *****/
TstPrn_ComputeIntAnsScore (PrintedQuestion,Question);
}
static void ExaPrn_GetCorrectAndComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get the numerical value of the minimum and maximum correct answers *****/
ExaPrn_GetCorrectFltAnswerFromDB (Question);
/***** Compute score *****/
TstPrn_ComputeFltAnsScore (PrintedQuestion,Question);
}
static void ExaPrn_GetCorrectAndComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get answer true or false *****/
ExaPrn_GetCorrectTF_AnswerFromDB (Question);
/***** Compute score *****/
TstPrn_ComputeTF_AnsScore (PrintedQuestion,Question);
}
static void ExaPrn_GetCorrectAndComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get correct options of test question from database *****/
ExaPrn_GetCorrectChoAnswerFromDB (Question);
/***** Compute the total score of this question *****/
TstPrn_ComputeChoAnsScore (PrintedQuestion,Question);
}
static void ExaPrn_GetCorrectAndComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get correct answers for this question from database *****/
ExaPrn_GetCorrectTxtAnswerFromDB (Question);
/***** Compute score *****/
TstPrn_ComputeTxtAnsScore (PrintedQuestion,Question);
}
/*****************************************************************************/
/***************** Get correct answer for each type of answer ****************/
/*****************************************************************************/
static void ExaPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Query database *****/
Question->Answer.NumOptions =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get answers of a question",
"SELECT Answer" // row[0]
" FROM exa_set_answers"
" WHERE QstCod=%ld",
Question->QstCod);
/***** Check if number of rows is correct *****/
Tst_CheckIfNumberOfAnswersIsOne (Question);
/***** Get correct answer *****/
row = mysql_fetch_row (mysql_res);
if (sscanf (row[0],"%ld",&Question->Answer.Integer) != 1)
Lay_ShowErrorAndExit ("Wrong integer answer.");
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
static void ExaPrn_GetCorrectFltAnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumOpt;
double Tmp;
/***** Query database *****/
Question->Answer.NumOptions =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get answers of a question",
"SELECT Answer" // row[0]
" FROM exa_set_answers"
" WHERE QstCod=%ld",
Question->QstCod);
/***** Check if number of rows is correct *****/
if (Question->Answer.NumOptions != 2)
Lay_ShowErrorAndExit ("Wrong float range.");
/***** Get float range *****/
for (NumOpt = 0;
NumOpt < 2;
NumOpt++)
{
row = mysql_fetch_row (mysql_res);
Question->Answer.FloatingPoint[NumOpt] = Str_GetDoubleFromStr (row[0]);
}
if (Question->Answer.FloatingPoint[0] >
Question->Answer.FloatingPoint[1]) // The maximum and the minimum are swapped
{
/* Swap maximum and minimum */
Tmp = Question->Answer.FloatingPoint[0];
Question->Answer.FloatingPoint[0] = Question->Answer.FloatingPoint[1];
Question->Answer.FloatingPoint[1] = Tmp;
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
static void ExaPrn_GetCorrectTF_AnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Query database *****/
Question->Answer.NumOptions =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get answers of a question",
"SELECT Answer" // row[0]
" FROM exa_set_answers"
" WHERE QstCod=%ld",
Question->QstCod);
/***** Check if number of rows is correct *****/
Tst_CheckIfNumberOfAnswersIsOne (Question);
/***** Get answer *****/
row = mysql_fetch_row (mysql_res);
Question->Answer.TF = row[0][0];
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
static void ExaPrn_GetCorrectChoAnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumOpt;
/***** Query database *****/
Question->Answer.NumOptions =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get answers of a question",
"SELECT Correct" // row[0]
" FROM exa_set_answers"
" WHERE QstCod=%ld"
" ORDER BY AnsInd",
Question->QstCod);
for (NumOpt = 0;
NumOpt < Question->Answer.NumOptions;
NumOpt++)
{
/* Get next answer */
row = mysql_fetch_row (mysql_res);
/* Assign correctness (row[0]) of this answer (this option) */
Question->Answer.Options[NumOpt].Correct = (row[0][0] == 'Y');
}
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
}
static void ExaPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumOpt;
/***** Query database *****/
Question->Answer.NumOptions =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get answers of a question",
"SELECT Answer" // row[0]
" FROM exa_set_answers"
" WHERE QstCod=%ld",
Question->QstCod);
/***** Get text and correctness of answers for this question from database (one row per answer) *****/
for (NumOpt = 0;
NumOpt < Question->Answer.NumOptions;
NumOpt++)
{
/***** Get next answer *****/
row = mysql_fetch_row (mysql_res);
/***** Allocate memory for text in this choice answer *****/
if (!Tst_AllocateTextChoiceAnswer (Question,NumOpt))
/* Abort on error */
Ale_ShowAlertsAndExit ();
/***** Copy answer text (row[0]) and convert it, that is in HTML, to rigorous HTML ******/
Str_Copy (Question->Answer.Options[NumOpt].Text,row[0],
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Question->Answer.Options[NumOpt].Text,
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/************* Get the questions of an exam print from database **************/
/*****************************************************************************/

View File

@ -39,6 +39,9 @@ void ExaPrn_ShowExamPrint (void);
void ExaPrn_ReceivePrintAnswer (void);
void ExaPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
void ExaPrn_EndPrintAnswer (void);
#endif

View File

@ -1743,7 +1743,6 @@ static void ExaSet_CopyQstFromBankToExamSet (struct ExaSet_Set *Set,long QstCod)
{
/***** Clone media *****/
CloneMedCod = Med_CloneMedia (&Question.Media);
Ale_ShowAlert (Ale_INFO,"DEBUG: CloneMedCod = %ld",CloneMedCod);
/***** Insert question in table of questions *****/
QstCodInSet = DB_QueryINSERTandReturnCode ("can not add question to set",

View File

@ -4015,7 +4015,7 @@ static void Mch_ComputeScore (struct TstPrn_Print *Print)
Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE;
/***** Compute score for this answer ******/
TstPrn_ComputeChoiceAnsScore (&Print->PrintedQuestions[NumQst],&Question);
TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question);
/***** Update total score *****/
Print->Score += Print->PrintedQuestions[NumQst].Score;

View File

@ -1512,48 +1512,51 @@ static void Med_ShowJPG (const struct Media *Media,
const char *ClassMedia)
{
extern const char *Txt_File_not_found;
char FileNameMedia[NAME_MAX + 1];
char FileNameJPG[NAME_MAX + 1];
char TmpPubDir[PATH_MAX + 1];
char *FullPathMediaPriv;
char *FullPathJPGPriv;
char *URL;
bool Cached;
/***** Build private path to JPG *****/
snprintf (FileNameMedia,sizeof (FileNameMedia),
snprintf (FileNameJPG,sizeof (FileNameJPG),
"%s.%s",
Media->Name,Med_Extensions[Med_JPG]);
if (asprintf (&FullPathMediaPriv,"%s/%s",
PathMedPriv,FileNameMedia) < 0)
if (asprintf (&FullPathJPGPriv,"%s/%s",
PathMedPriv,FileNameJPG) < 0)
Lay_NotEnoughMemoryExit ();
/***** Check if private media file exists *****/
if (Fil_CheckIfPathExists (FullPathMediaPriv))
if (Fil_CheckIfPathExists (FullPathJPGPriv))
{
/***** Get cached public link to private file *****/
if (!Ses_GetPublicDirFromCache (FullPathMediaPriv,TmpPubDir))
Cached = Ses_GetPublicDirFromCache (FullPathJPGPriv,TmpPubDir);
if (!Cached)
{
/***** Create symbolic link from temporary public directory to private file
in order to gain access to it for showing/downloading *****/
Brw_CreateDirDownloadTmp ();
Brw_CreateTmpPublicLinkToPrivateFile (FullPathMediaPriv,FileNameMedia);
Brw_CreateTmpPublicLinkToPrivateFile (FullPathJPGPriv,FileNameJPG);
snprintf (TmpPubDir,sizeof (TmpPubDir),
"%s/%s",
Gbl.FileBrowser.TmpPubDir.L,Gbl.FileBrowser.TmpPubDir.R);
Ses_AddPublicDirToCache (FullPathMediaPriv,TmpPubDir);
Ses_AddPublicDirToCache (FullPathJPGPriv,TmpPubDir);
}
/***** Show media *****/
if (asprintf (&URL,"%s/%s",
Cfg_URL_FILE_BROWSER_TMP_PUBLIC,TmpPubDir) < 0)
Lay_NotEnoughMemoryExit ();
HTM_IMG (URL,FileNameMedia,Media->Title,
HTM_IMG (URL,FileNameJPG,Media->Title,
"class=\"%s\" lazyload=\"on\"",ClassMedia); // Lazy load of the media
free (URL);
}
else
HTM_Txt (Txt_File_not_found);
free (FullPathMediaPriv);
free (FullPathJPGPriv);
}
/*****************************************************************************/
@ -1565,56 +1568,64 @@ static void Med_ShowGIF (const struct Media *Media,
const char *ClassMedia)
{
extern const char *Txt_File_not_found;
char FileNameMedia[NAME_MAX + 1];
char FileNameGIF[NAME_MAX + 1];
char FileNamePNG[NAME_MAX + 1];
char TmpPubDir[PATH_MAX + 1];
char *FullPathGIFPriv;
char *FullPathPNGPriv;
char *URL;
char *URL_GIF;
char *URL_PNG;
bool Cached;
/***** Build private path to animated GIF image *****/
snprintf (FileNameMedia,sizeof (FileNameMedia),
snprintf (FileNameGIF,sizeof (FileNameGIF),
"%s.%s",
Media->Name,Med_Extensions[Med_GIF]);
if (asprintf (&FullPathGIFPriv,"%s/%s", // The animated GIF image
PathMedPriv,FileNameMedia) < 0)
PathMedPriv,FileNameGIF) < 0)
Lay_NotEnoughMemoryExit ();
/***** Build private path to static PNG image *****/
snprintf (FileNamePNG,sizeof (FileNamePNG),
"%s.png",
Media->Name);
if (asprintf (&FullPathPNGPriv,"%s/%s",
PathMedPriv,FileNamePNG) < 0)
Lay_NotEnoughMemoryExit ();
/***** Check if private media file exists *****/
if (Fil_CheckIfPathExists (FullPathGIFPriv)) // The animated GIF image
{
/***** Create symbolic link from temporary public directory to private file
in order to gain access to it for showing/downloading *****/
Brw_CreateDirDownloadTmp ();
Brw_CreateTmpPublicLinkToPrivateFile (FullPathGIFPriv,FileNameMedia);
/***** Get cached public link to private file *****/
Cached = Ses_GetPublicDirFromCache (FullPathGIFPriv,TmpPubDir);
/***** Create URL pointing to symbolic link *****/
if (asprintf (&URL,"%s/%s/%s",
Cfg_URL_FILE_BROWSER_TMP_PUBLIC,
Gbl.FileBrowser.TmpPubDir.L,
Gbl.FileBrowser.TmpPubDir.R) < 0)
Lay_NotEnoughMemoryExit ();
if (asprintf (&URL_GIF,"%s/%s",URL,FileNameMedia) < 0)
Lay_NotEnoughMemoryExit ();
if (!Cached)
{
/***** Create symbolic link from temporary public directory to private file
in order to gain access to it for showing/downloading *****/
Brw_CreateDirDownloadTmp ();
Brw_CreateTmpPublicLinkToPrivateFile (FullPathGIFPriv,FileNameGIF);
Brw_CreateTmpPublicLinkToPrivateFile (FullPathPNGPriv,FileNamePNG);
/***** Build private path to static PNG image *****/
snprintf (FileNameMedia,sizeof (FileNameMedia),
"%s.png",
Media->Name);
if (asprintf (&FullPathPNGPriv,"%s/%s",
PathMedPriv,FileNameMedia) < 0)
snprintf (TmpPubDir,sizeof (TmpPubDir),
"%s/%s",
Gbl.FileBrowser.TmpPubDir.L,Gbl.FileBrowser.TmpPubDir.R);
Ses_AddPublicDirToCache (FullPathGIFPriv,TmpPubDir);
}
/***** Create URLs pointing to symbolic links *****/
if (asprintf (&URL,"%s/%s",
Cfg_URL_FILE_BROWSER_TMP_PUBLIC,TmpPubDir) < 0)
Lay_NotEnoughMemoryExit ();
if (asprintf (&URL_PNG,"%s/%s",URL,FileNameMedia) < 0) // The static PNG image
if (asprintf (&URL_GIF,"%s/%s",URL,FileNameGIF) < 0)
Lay_NotEnoughMemoryExit ();
if (asprintf (&URL_PNG,"%s/%s",URL,FileNamePNG) < 0) // The static PNG image
Lay_NotEnoughMemoryExit ();
/***** Check if private media file exists *****/
if (Fil_CheckIfPathExists (FullPathPNGPriv)) // The static PNG image
{
/***** Create symbolic link from temporary public directory to private file
in order to gain access to it for showing/downloading *****/
Brw_CreateDirDownloadTmp ();
Brw_CreateTmpPublicLinkToPrivateFile (FullPathPNGPriv,FileNameMedia);
/***** Show static PNG and animated GIF *****/
HTM_DIV_Begin ("class=\"MED_PLAY\""
" onmouseover=\"toggleOnGIF(this,'%s');\""
@ -1623,7 +1634,7 @@ static void Med_ShowGIF (const struct Media *Media,
URL_PNG);
/* Image */
HTM_IMG (URL,FileNameMedia,Media->Title,
HTM_IMG (URL,FileNamePNG,Media->Title,
"class=\"%s\" lazyload=\"on\"",ClassMedia); // Lazy load of the media
/* Overlay with GIF label */
@ -1636,8 +1647,6 @@ static void Med_ShowGIF (const struct Media *Media,
else
HTM_Txt (Txt_File_not_found);
free (FullPathPNGPriv);
/***** Free URLs *****/
free (URL_PNG);
free (URL_GIF);
@ -1646,6 +1655,7 @@ static void Med_ShowGIF (const struct Media *Media,
else
HTM_Txt (Txt_File_not_found);
free (FullPathPNGPriv);
free (FullPathGIFPriv);
}
@ -1658,50 +1668,61 @@ static void Med_ShowVideo (const struct Media *Media,
const char *ClassMedia)
{
extern const char *Txt_File_not_found;
char FileNameMediaPriv[NAME_MAX + 1];
char *FullPathMediaPriv;
char URL_Video[PATH_MAX + 1];
char FileNameVideo[NAME_MAX + 1];
char TmpPubDir[PATH_MAX + 1];
char *FullPathVideoPriv;
char *URL;
bool Cached;
/***** Build private path to video *****/
snprintf (FileNameMediaPriv,sizeof (FileNameMediaPriv),
snprintf (FileNameVideo,sizeof (FileNameVideo),
"%s.%s",
Media->Name,Med_Extensions[Media->Type]);
if (asprintf (&FullPathMediaPriv,"%s/%s",
PathMedPriv,FileNameMediaPriv) < 0)
if (asprintf (&FullPathVideoPriv,"%s/%s",
PathMedPriv,FileNameVideo) < 0)
Lay_NotEnoughMemoryExit ();
/***** Check if private media file exists *****/
if (Fil_CheckIfPathExists (FullPathMediaPriv))
if (Fil_CheckIfPathExists (FullPathVideoPriv))
{
/***** Create symbolic link from temporary public directory to private file
in order to gain access to it for showing/downloading *****/
Brw_CreateDirDownloadTmp ();
Brw_CreateTmpPublicLinkToPrivateFile (FullPathMediaPriv,FileNameMediaPriv);
/***** Get cached public link to private file *****/
Cached = Ses_GetPublicDirFromCache (FullPathVideoPriv,TmpPubDir);
if (!Cached)
{
/***** Create symbolic link from temporary public directory to private file
in order to gain access to it for showing/downloading *****/
Brw_CreateDirDownloadTmp ();
Brw_CreateTmpPublicLinkToPrivateFile (FullPathVideoPriv,FileNameVideo);
snprintf (TmpPubDir,sizeof (TmpPubDir),
"%s/%s",
Gbl.FileBrowser.TmpPubDir.L,Gbl.FileBrowser.TmpPubDir.R);
Ses_AddPublicDirToCache (FullPathVideoPriv,TmpPubDir);
}
/***** Create URL pointing to symbolic link *****/
snprintf (URL_Video,sizeof (URL_Video),
"%s/%s/%s/%s",
Cfg_URL_FILE_BROWSER_TMP_PUBLIC,
Gbl.FileBrowser.TmpPubDir.L,
Gbl.FileBrowser.TmpPubDir.R,
FileNameMediaPriv);
if (asprintf (&URL,"%s/%s",
Cfg_URL_FILE_BROWSER_TMP_PUBLIC,TmpPubDir) < 0)
Lay_NotEnoughMemoryExit ();
/***** Show media *****/
HTM_TxtF ("<video src=\"%s\""
HTM_TxtF ("<video src=\"%s/%s\""
" preload=\"metadata\" controls=\"controls\""
" class=\"%s\"",
URL_Video,ClassMedia);
URL,FileNameVideo,ClassMedia);
if (Media->Title)
if (Media->Title[0])
HTM_TxtF (" title=\"%s\"",Media->Title);
HTM_Txt (" lazyload=\"on\">" // Lazy load of the media
"Your browser does not support HTML5 video."
"</video>");
free (URL);
}
else
HTM_Txt (Txt_File_not_found);
free (FullPathMediaPriv);
free (FullPathVideoPriv);
}
/*****************************************************************************/
@ -1905,12 +1926,6 @@ long Med_CloneMedia (const struct Media *MediaSrc)
MediaPriv[Med_DST].Path,MediaDst.Name,Med_Extensions[MediaSrc->Type]);
/* Copy file */
Ale_ShowAlert (Ale_INFO,"DEBUG<br />"
"MediaPriv[Med_SRC].FullPath = &quot;%s&quot<br />"
"MediaPriv[Med_DST].FullPath = &quot;%s&quot",
MediaPriv[Med_SRC].FullPath,
MediaPriv[Med_DST].FullPath);
Fil_FastCopyOfFiles (MediaPriv[Med_SRC].FullPath,
MediaPriv[Med_DST].FullPath);

View File

@ -78,24 +78,27 @@ static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat,
struct Tst_Question *Question,
bool QuestionExists,
unsigned Visibility);
static void TstPrn_ComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question);
static void TstPrn_ComputeFloatAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectFloatAnswerFromDB (struct Tst_Question *Question);
static void TstPrn_ComputeTFAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectTFAnswerFromDB (struct Tst_Question *Question);
static void TstPrn_GetCorrectChoiceAnswerFromDB (struct Tst_Question *Question);
static void TstPrn_ComputeScoreQst (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION], // Indexes of all answers of this question
bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION]);
static void TstPrn_ComputeTextAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectTextAnswerFromDB (struct Tst_Question *Question);
//-----------------------------------------------------------------------------
static void TstPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectAndComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectAndComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectAndComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectAndComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
static void TstPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question);
static void TstPrn_GetCorrectFltAnswerFromDB (struct Tst_Question *Question);
static void TstPrn_GetCorrectTF_AnswerFromDB (struct Tst_Question *Question);
static void TstPrn_GetCorrectChoAnswerFromDB (struct Tst_Question *Question);
static void TstPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question);
//-----------------------------------------------------------------------------
static void TstPrn_WriteAnswersExam (struct UsrData *UsrDat,
const struct TstPrn_Print *Print,
@ -394,7 +397,7 @@ void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print,
}
/*****************************************************************************/
/************* Write answers of a question when assessing a test *************/
/******************* Get correct answer and compute score ********************/
/*****************************************************************************/
void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
@ -404,47 +407,79 @@ void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
switch (Question->Answer.Type)
{
case Tst_ANS_INT:
TstPrn_ComputeIntAnsScore (PrintedQuestion,Question);
break;
TstPrn_GetCorrectAndComputeIntAnsScore (PrintedQuestion,Question); break;
case Tst_ANS_FLOAT:
TstPrn_ComputeFloatAnsScore (PrintedQuestion,Question);
break;
TstPrn_GetCorrectAndComputeFltAnsScore (PrintedQuestion,Question); break;
case Tst_ANS_TRUE_FALSE:
TstPrn_ComputeTFAnsScore (PrintedQuestion,Question);
break;
TstPrn_GetCorrectAndComputeTF_AnsScore (PrintedQuestion,Question); break;
case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE:
TstPrn_ComputeChoiceAnsScore (PrintedQuestion,Question);
break;
TstPrn_GetCorrectAndComputeChoAnsScore (PrintedQuestion,Question); break;
case Tst_ANS_TEXT:
TstPrn_ComputeTextAnsScore (PrintedQuestion,Question);
break;
TstPrn_GetCorrectAndComputeTxtAnsScore (PrintedQuestion,Question); break;
default:
break;
}
}
/*****************************************************************************/
/**************** Write integer answer when assessing a test *****************/
/******* Get correct answer and compute score for each type of answer ********/
/*****************************************************************************/
static void TstPrn_ComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
static void TstPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
long AnswerUsr;
/***** Get the numerical value of the correct answer *****/
TstPrn_GetCorrectIntAnswerFromDB (Question);
/***** Compute score *****/
PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer
PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0');
if (PrintedQuestion->AnswerIsNotBlank) // If user has answered the answer
if (sscanf (PrintedQuestion->StrAnswers,"%ld",&AnswerUsr) == 1)
if (AnswerUsr == Question->Answer.Integer) // Correct answer
PrintedQuestion->Score = 1.0;
TstPrn_ComputeIntAnsScore (PrintedQuestion,Question);
}
static void TstPrn_GetCorrectAndComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get the numerical value of the minimum and maximum correct answers *****/
TstPrn_GetCorrectFltAnswerFromDB (Question);
/***** Compute score *****/
TstPrn_ComputeFltAnsScore (PrintedQuestion,Question);
}
static void TstPrn_GetCorrectAndComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get answer true or false *****/
TstPrn_GetCorrectTF_AnswerFromDB (Question);
/***** Compute score *****/
TstPrn_ComputeTF_AnsScore (PrintedQuestion,Question);
}
static void TstPrn_GetCorrectAndComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get correct options of test question from database *****/
TstPrn_GetCorrectChoAnswerFromDB (Question);
/***** Compute the total score of this question *****/
TstPrn_ComputeChoAnsScore (PrintedQuestion,Question);
}
static void TstPrn_GetCorrectAndComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get correct answers for this question from database *****/
TstPrn_GetCorrectTxtAnswerFromDB (Question);
/***** Compute score *****/
TstPrn_ComputeTxtAnsScore (PrintedQuestion,Question);
}
/*****************************************************************************/
/**************** Get correct answer for each type of answer *****************/
/*****************************************************************************/
static void TstPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
@ -470,33 +505,7 @@ static void TstPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question)
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/***************** Write float answer when assessing a test ******************/
/*****************************************************************************/
static void TstPrn_ComputeFloatAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
double AnswerUsr;
/***** Get the numerical value of the minimum and maximum correct answers *****/
TstPrn_GetCorrectFloatAnswerFromDB (Question);
/***** Compute score *****/
PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer
PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0');
if (PrintedQuestion->AnswerIsNotBlank) // If user has answered the answer
{
AnswerUsr = Str_GetDoubleFromStr (PrintedQuestion->StrAnswers);
// A bad formatted floating point answer will interpreted as 0.0
PrintedQuestion->Score = (AnswerUsr >= Question->Answer.FloatingPoint[0] &&
AnswerUsr <= Question->Answer.FloatingPoint[1]) ? 1.0 : // If correct (inside the interval)
0.0; // If wrong (outside the interval)
}
}
static void TstPrn_GetCorrectFloatAnswerFromDB (struct Tst_Question *Question)
static void TstPrn_GetCorrectFltAnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
@ -536,26 +545,7 @@ static void TstPrn_GetCorrectFloatAnswerFromDB (struct Tst_Question *Question)
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/************** Write false / true answer when assessing a test **************/
/*****************************************************************************/
static void TstPrn_ComputeTFAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
/***** Get answer true or false *****/
TstPrn_GetCorrectTFAnswerFromDB (Question);
/***** Compute score *****/
PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0');
if (PrintedQuestion->AnswerIsNotBlank) // User has selected T or F
PrintedQuestion->Score = (PrintedQuestion->StrAnswers[0] == Question->Answer.TF) ? 1.0 : // Correct
-1.0; // Wrong
else
PrintedQuestion->Score = 0.0;
}
static void TstPrn_GetCorrectTFAnswerFromDB (struct Tst_Question *Question)
static void TstPrn_GetCorrectTF_AnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
@ -579,30 +569,7 @@ static void TstPrn_GetCorrectTFAnswerFromDB (struct Tst_Question *Question)
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/************ Compute score for single or multiple choice answer *************/
/*****************************************************************************/
void TstPrn_ComputeChoiceAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
{
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION];
/***** Get correct options of test question from database *****/
TstPrn_GetCorrectChoiceAnswerFromDB (Question);
/***** Get indexes for this question from string *****/
TstPrn_GetIndexesFromStr (PrintedQuestion->StrIndexes,Indexes);
/***** Get the user's answers for this question from string *****/
TstPrn_GetAnswersFromStr (PrintedQuestion->StrAnswers,UsrAnswers);
/***** Compute the total score of this question *****/
TstPrn_ComputeScoreQst (PrintedQuestion,Question,Indexes,UsrAnswers);
}
static void TstPrn_GetCorrectChoiceAnswerFromDB (struct Tst_Question *Question)
static void TstPrn_GetCorrectChoAnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
@ -631,88 +598,108 @@ static void TstPrn_GetCorrectChoiceAnswerFromDB (struct Tst_Question *Question)
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/********************* Get vector of indexes from string *********************/
/*****************************************************************************/
void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION])
static void TstPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumOpt;
const char *Ptr;
char StrOneIndex[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
/***** Get indexes from string *****/
for (NumOpt = 0, Ptr = StrIndexesOneQst;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION && *Ptr;
NumOpt++)
{
Par_GetNextStrUntilComma (&Ptr,StrOneIndex,Cns_MAX_DECIMAL_DIGITS_UINT);
/***** Query database *****/
Question->Answer.NumOptions =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get answers of a question",
"SELECT Answer" // row[0]
" FROM tst_answers"
" WHERE QstCod=%ld",
Question->QstCod);
if (sscanf (StrOneIndex,"%u",&(Indexes[NumOpt])) != 1)
Lay_ShowErrorAndExit ("Wrong index of answer.");
if (Indexes[NumOpt] >= Tst_MAX_OPTIONS_PER_QUESTION)
Lay_ShowErrorAndExit ("Wrong index of answer.");
}
/***** Initialize remaining to 0 *****/
for (;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
Indexes[NumOpt] = 0;
}
/*****************************************************************************/
/****************** Get vector of user's answers from string *****************/
/*****************************************************************************/
void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1],
bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION])
{
unsigned NumOpt;
const char *Ptr;
char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
unsigned AnsUsr;
/***** Initialize all answers to false *****/
/***** Get text and correctness of answers for this question from database (one row per answer) *****/
for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
UsrAnswers[NumOpt] = false;
/***** Set selected answers to true *****/
for (NumOpt = 0, Ptr = StrAnswersOneQst;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION && *Ptr;
NumOpt < Question->Answer.NumOptions;
NumOpt++)
{
Par_GetNextStrUntilComma (&Ptr,StrOneAnswer,Cns_MAX_DECIMAL_DIGITS_UINT);
/***** Get next answer *****/
row = mysql_fetch_row (mysql_res);
if (sscanf (StrOneAnswer,"%u",&AnsUsr) != 1)
Lay_ShowErrorAndExit ("Bad user's answer.");
/***** Allocate memory for text in this choice answer *****/
if (!Tst_AllocateTextChoiceAnswer (Question,NumOpt))
/* Abort on error */
Ale_ShowAlertsAndExit ();
if (AnsUsr >= Tst_MAX_OPTIONS_PER_QUESTION)
Lay_ShowErrorAndExit ("Bad user's answer.");
UsrAnswers[AnsUsr] = true;
/***** Copy answer text (row[0]) and convert it, that is in HTML, to rigorous HTML ******/
Str_Copy (Question->Answer.Options[NumOpt].Text,row[0],
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Question->Answer.Options[NumOpt].Text,
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/*********************** Compute the score of a question *********************/
/************** Compute answer score for each type of answer *****************/
/*****************************************************************************/
static void TstPrn_ComputeScoreQst (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION], // Indexes of all answers of this question
bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION])
void TstPrn_ComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question)
{
long AnswerUsr;
PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer
PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0');
if (PrintedQuestion->AnswerIsNotBlank) // If user has answered the answer
if (sscanf (PrintedQuestion->StrAnswers,"%ld",&AnswerUsr) == 1)
if (AnswerUsr == Question->Answer.Integer) // Correct answer
PrintedQuestion->Score = 1.0;
}
void TstPrn_ComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question)
{
double AnswerUsr;
PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer
PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0');
if (PrintedQuestion->AnswerIsNotBlank) // If user has answered the answer
{
AnswerUsr = Str_GetDoubleFromStr (PrintedQuestion->StrAnswers);
// A bad formatted floating point answer will interpreted as 0.0
PrintedQuestion->Score = (AnswerUsr >= Question->Answer.FloatingPoint[0] &&
AnswerUsr <= Question->Answer.FloatingPoint[1]) ? 1.0 : // If correct (inside the interval)
0.0; // If wrong (outside the interval)
}
}
void TstPrn_ComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question)
{
PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0');
if (PrintedQuestion->AnswerIsNotBlank) // User has selected T or F
PrintedQuestion->Score = (PrintedQuestion->StrAnswers[0] == Question->Answer.TF) ? 1.0 : // Correct
-1.0; // Wrong
else
PrintedQuestion->Score = 0.0;
}
void TstPrn_ComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question)
{
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION];
unsigned NumOpt;
unsigned NumOptTotInQst = 0;
unsigned NumOptCorrInQst = 0;
unsigned NumAnsGood = 0;
unsigned NumAnsBad = 0;
/***** Get indexes for this question from string *****/
TstPrn_GetIndexesFromStr (PrintedQuestion->StrIndexes,Indexes);
/***** Get the user's answers for this question from string *****/
TstPrn_GetAnswersFromStr (PrintedQuestion->StrAnswers,UsrAnswers);
/***** Compute the total score of this question *****/
for (NumOpt = 0;
NumOpt < Question->Answer.NumOptions;
@ -767,21 +754,13 @@ static void TstPrn_ComputeScoreQst (struct TstPrn_PrintedQuestion *PrintedQuesti
PrintedQuestion->Score = 0.0;
}
/*****************************************************************************/
/********************* Compute score for text answer *************************/
/*****************************************************************************/
static void TstPrn_ComputeTextAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question)
void TstPrn_ComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question)
{
unsigned NumOpt;
char TextAnsUsr[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1];
char TextAnsOK[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1];
/***** Get correct answers for this question from database *****/
TstPrn_GetCorrectTextAnswerFromDB (Question);
/***** Compute score *****/
PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer
PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0');
if (PrintedQuestion->AnswerIsNotBlank) // If user has answered the answer
@ -811,43 +790,71 @@ static void TstPrn_ComputeTextAnsScore (struct TstPrn_PrintedQuestion *PrintedQu
}
}
static void TstPrn_GetCorrectTextAnswerFromDB (struct Tst_Question *Question)
/*****************************************************************************/
/********** Get vector of unsigned indexes from string with indexes **********/
/*****************************************************************************/
void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION])
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumOpt;
const char *Ptr;
char StrOneIndex[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
/***** Query database *****/
Question->Answer.NumOptions =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get answers of a question",
"SELECT Answer" // row[0]
" FROM tst_answers"
" WHERE QstCod=%ld",
Question->QstCod);
/***** Get text and correctness of answers for this question from database (one row per answer) *****/
for (NumOpt = 0;
NumOpt < Question->Answer.NumOptions;
/***** Get indexes from string *****/
for (NumOpt = 0, Ptr = StrIndexesOneQst;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION && *Ptr;
NumOpt++)
{
/***** Get next answer *****/
row = mysql_fetch_row (mysql_res);
Par_GetNextStrUntilComma (&Ptr,StrOneIndex,Cns_MAX_DECIMAL_DIGITS_UINT);
/***** Allocate memory for text in this choice answer *****/
if (!Tst_AllocateTextChoiceAnswer (Question,NumOpt))
/* Abort on error */
Ale_ShowAlertsAndExit ();
if (sscanf (StrOneIndex,"%u",&(Indexes[NumOpt])) != 1)
Lay_ShowErrorAndExit ("Wrong index of answer.");
/***** Copy answer text (row[0]) and convert it, that is in HTML, to rigorous HTML ******/
Str_Copy (Question->Answer.Options[NumOpt].Text,row[0],
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Question->Answer.Options[NumOpt].Text,
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
if (Indexes[NumOpt] >= Tst_MAX_OPTIONS_PER_QUESTION)
Lay_ShowErrorAndExit ("Wrong index of answer.");
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
/***** Initialize remaining to 0 *****/
for (;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
Indexes[NumOpt] = 0;
}
/*****************************************************************************/
/************ Get vector of bool answers from string with answers ************/
/*****************************************************************************/
void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1],
bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION])
{
unsigned NumOpt;
const char *Ptr;
char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
unsigned AnsUsr;
/***** Initialize all answers to false *****/
for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
UsrAnswers[NumOpt] = false;
/***** Set selected answers to true *****/
for (NumOpt = 0, Ptr = StrAnswersOneQst;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION && *Ptr;
NumOpt++)
{
Par_GetNextStrUntilComma (&Ptr,StrOneAnswer,Cns_MAX_DECIMAL_DIGITS_UINT);
if (sscanf (StrOneAnswer,"%u",&AnsUsr) != 1)
Lay_ShowErrorAndExit ("Bad user's answer.");
if (AnsUsr >= Tst_MAX_OPTIONS_PER_QUESTION)
Lay_ShowErrorAndExit ("Bad user's answer.");
UsrAnswers[AnsUsr] = true;
}
}
/*****************************************************************************/

View File

@ -76,8 +76,20 @@ void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print,
bool UpdateQstScore);
void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
void TstPrn_ComputeChoiceAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Tst_Question *Question);
//-----------------------------------------------------------------------------
void TstPrn_ComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question);
void TstPrn_ComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question);
void TstPrn_ComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question);
void TstPrn_ComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question);
void TstPrn_ComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
const struct Tst_Question *Question);
//-----------------------------------------------------------------------------
void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]);
void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1],