/*!
    Constructs a suggestions URL with a given \a searchTerm.

    The URL template is processed according to the specification:
    http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax

    See searchUrl() for more information about processing template parameters.

    \sa suggestionsUrlTemplate(), suggestionsParameters(), searchUrl()
*/
QUrl OpenSearchEngine::suggestionsUrl(const QString &searchTerm) const
{
    if (!m_preparedSuggestionsUrl.isEmpty()) {
        QString s = m_preparedSuggestionsUrl;
        s.replace(QLatin1String("%s"), searchTerm);
        return QUrl(s);
    }

    if (m_suggestionsUrlTemplate.isEmpty()) {
        return QUrl();
    }

    QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_suggestionsUrlTemplate).toUtf8());

    QUrlQuery query(retVal);
    if (m_suggestionsMethod != QLatin1String("post")) {
        Parameters::const_iterator end = m_suggestionsParameters.constEnd();
        Parameters::const_iterator i = m_suggestionsParameters.constBegin();
        for (; i != end; ++i) {
            query.addQueryItem(i->first, parseTemplate(searchTerm, i->second));
        }
        retVal.setQuery(query);
    }

    return retVal;
}
Beispiel #2
0
KUrl OpenSearchEngine::suggestionsUrl(const QString &searchTerm) const
{
    if (m_suggestionsUrlTemplate.isEmpty())
    {
        return KUrl();
    }

    KUrl retVal = KUrl::fromEncoded(parseTemplate(searchTerm, m_suggestionsUrlTemplate).toUtf8());

    QList<Parameter>::const_iterator i;
    for (i = m_suggestionsParameters.constBegin(); i != m_suggestionsParameters.constEnd(); ++i)
    {
        retVal.addQueryItem(i->first, parseTemplate(searchTerm, i->second));
    }
    return retVal;
}
Beispiel #3
0
void PageTemplate::setTemplate(const QString &temp)
{
    placeMarkers.clear();
    templateString.clear();
    templateString.append(temp);

    parseTemplate();
}
Beispiel #4
0
tMacro *
mLoad_While(tTemplate* pT, tMacro* pMac, char const ** ppzScan)
{
    size_t              srcLen = (size_t)pMac->res; /* macro len  */
    tpLoadProc const *  papLP  = papLoadProc;
    tMacro *            pEndMac;

    /*
     *  While processing an "IF" macro,
     *  we have handler functions for 'ELIF', 'ELSE' and 'ENDIF'
     *  Otherwise, we do not.  Switch the callout function table.
     */
    static tpLoadProc apWhileLoad[ FUNC_CT ] = { NULL };

    /*
     *  IF there is no associated text expression
     *  THEN woops!  what are we to case on?
     */
    if (srcLen == 0)
        AG_ABEND_IN(pT, pMac, LD_WHILE_NO_EXPR);

    if (apWhileLoad[0] == NULL) {
        memcpy((void*)apWhileLoad, apLoadProc, sizeof(apLoadProc));
        apWhileLoad[ FTYP_ENDWHILE ] = &mLoad_Ending;
    }

    papLoadProc = apWhileLoad;

    /*
     *  Load the expression
     */
    (void)mLoad_Expr(pT, pMac, ppzScan);

    /*
     *  Now, do a nested parse of the template.  When the matching 'ENDWHILE'
     *  macro is encountered, the handler routine will cause 'parseTemplate()'
     *  to return with the text scanning pointer pointing to the remaining
     *  text.
     */
    pEndMac = parseTemplate(pMac+1, ppzScan);
    if (*ppzScan == NULL)
        AG_ABEND_IN(pT, pMac, LD_WHILE_NO_ENDWHILE);

    pMac->sibIndex = pMac->endIndex = pEndMac - pT->aMacros;

    /*
     *  Restore the context of any encompassing block macros
     */
    papLoadProc = papLP;
    return pEndMac;
}
/*
 * Routine: 
 * Purpose: 
 * Algorithm:
 * Data Structures:
 *
 * Params:
 * Returns:
 * Called By: 
 * Calls: 
 * Assumptions:
 * Side Effects:
 * TODO: None
 */
int 
main(int ac, char* av[])
{
	template_t *pTemplate;

	process_options (ac, av);

	if (!is_set("QUIET"))
	{
		fprintf (stderr,
		"%s Query Generator (Version %d.%d.%d%s)\n",
		get_str("PROG"), VERSION, RELEASE, MODIFICATION, PATCH);
	fprintf (stderr, "Copyright %s %s\n", COPYRIGHT, C_DATES);
	}

	TemplateList = makeList(L_FL_TAIL, NULL);

	/* sync the keyword defines between lex/yacc/qgen */
	InitKeywords();
	
	if (is_set("YYDEBUG"))
		yydebug = 1;
	

	if (is_set("TEMPLATE"))
      parseTemplate(get_str("TEMPLATE"), 1);
	else
		parseQueries();	/* load the query templates */
	
	
	if (is_set("VERBOSE") && !is_set("QUIET"))
		fprintf(stderr, "Parsed %d templates\n", length(TemplateList));
	if (is_set("DUMP"))
	{
		for (pTemplate = (template_t *)getHead(TemplateList); pTemplate; pTemplate = (template_t *)getNext(TemplateList))
			PrintTemplate(pTemplate);
	}

	init_rand();

	generateQueryStreams();	/* output the resulting SQL */

	exit(0);

}
QByteArray OpenSearchEngine::getPostData(const QString &searchTerm) const
{
    if (m_searchMethod != QLatin1String("post")) {
        return QByteArray();
    }

    QUrl retVal = QUrl("http://foo.bar");

    QUrlQuery query(retVal);
    Parameters::const_iterator end = m_searchParameters.constEnd();
    Parameters::const_iterator i = m_searchParameters.constBegin();
    for (; i != end; ++i) {
        query.addQueryItem(i->first, parseTemplate(searchTerm, i->second));
    }
    retVal.setQuery(query);

    QByteArray data = retVal.toEncoded(QUrl::RemoveScheme);
    return data.contains('?') ? data.mid(data.lastIndexOf('?') + 1) : QByteArray();
}
Beispiel #7
0
void PageTemplate::loadFromFile(const QString &filename)
{
    placeMarkers.clear();
    templateString.clear();

    QFile data(filename);
    if (data.open(QFile::ReadOnly ))
    {
        QDataStream in(&data);
        char *filecon=new char[data.size()];
        in.readRawData(filecon,data.size());

        templateString=QString().fromUtf8(filecon,data.size());

        delete [] filecon;
        data.close();

        parseTemplate();
    }
}
/*
* Routine: 
* Purpose: 
* Algorithm:
* Data Structures:
*
* Params:
* Returns:
* Called By: 
* Calls: 
* Assumptions:
* Side Effects:
* TODO: None
*/
void
parseQueries(void)
{
	char szFileName[1024],
		*cp;
	FILE *pInputFile;
	int nIndex = 1;
	
	if (!is_set("INPUT"))
	{
		ReportErrorNoLine(QERR_NO_QUERYLIST, NULL, 1);
	}

	strcpy(szFileName, get_str("INPUT"));
	
#ifndef WIN32
	if ((pInputFile = fopen(szFileName, "r")) == NULL)
#else
	if ((pInputFile = fopen(szFileName, "rt")) == NULL)
#endif
	{
		SetErrorGlobals(szFileName, NULL);
		ReportErrorNoLine(QERR_OPEN_FAILED, szFileName, 1);
	}
	
	while (fgets(szFileName, 1024, pInputFile))
	{
		if (strncmp(szFileName, "--", 2) == 0)
			continue;
		if ((cp = strchr(szFileName, '\n')))
			*cp = '\0';
		if (!strlen(szFileName))
			continue;
			
		parseTemplate(szFileName, nIndex++);
	}

	return;
}
Beispiel #9
0
/**
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *  Load the macro array and file name.
 */
static void
load_macs(tTemplate * pT, char const * pzF, char const * pzN,
          char const * pzData)
{
    tMacro* pMac   = pT->aMacros;

    {
        char*   pzText = (char*)(pMac + pT->macroCt);
        size_t  len;

        AGDUPSTR(pT->pzTplFile, pzF, "templ file");

        len = strlen(pzN) + 1;
        memcpy((void*)pzText, (void*)pzN, len);
        pT->pzTplName   = pzText;
        pzText         += len;
        pT->pzTemplText = pzText;
        pT->pNext       = pzText + 1;
    }

    pCurTemplate = pT;

    {
        tMacro* pMacEnd = parseTemplate(pMac, &pzData);
        int     ct;

        /*
         *  Make sure all of the input string was scanned.
         */
        if (pzData != NULL)
            AG_ABEND("Template parse ended unexpectedly");

        ct = pMacEnd - pMac;

        /*
         *  IF there are empty macro slots,
         *  THEN pack the text
         */
        if (ct < pT->macroCt) {
            int     delta = sizeof(tMacro) * (pT->macroCt - ct);
            void*   data  =
                (pT->pzTplName == NULL) ? pT->pzTemplText : pT->pzTplName;
            size_t  size  = pT->pNext - (char*)data;
            memmove((void*)pMacEnd, data, size);

            pT->pzTemplText -= delta;
            pT->pNext       -= delta;
            pT->pzTplName   -= delta;
            pT->macroCt      = ct;
        }
    }

    pT->descSize = pT->pNext - (char*)pT;
    pT->pNext    = NULL;

    /*
     *  We cannot reallocate a smaller array because
     *  the entries are all linked together and
     *  realloc-ing it may cause it to move.
     */
#if defined(DEBUG_ENABLED)
    if (HAVE_OPT(SHOW_DEFS)) {
        static char const zSum[] =
            "loaded %d macros from %s\n"
            "\tBinary template size:  0x%zX\n\n";
        fprintf(pfTrace, zSum, pT->macroCt, pzF, pT->descSize);
    }
#endif
}
Beispiel #10
0
/** \fn int main(int argc, char * argv[])
 * \brief Main program function.
 * \param argc Argument count.
 * \param argv Pointer Pointer to Argument vector
 * \return system int
 */
int main(int argc, char * argv[])
{
	/* Variables for parsing directories */
	int lastd;
	int i;
	/* Error value */
	int rc;
	
	/* Variable to read in command line input */
	char inputfile[1000];
	char directory[1000];
	char filename[1000];
	char templatename[1000];
	char templatedirectory[1000];
	
	/* For reading input files */
	input_file * current_input_file;
	/* Structure to hold model data */
	model_data * modeldata;
	
	/* Hold modeldata data */
	xmachine * xmachines;
	xmachine_message * xmessage;
	variable * envvar;
	env_func * envfunc;
	variable * envdefine;
	variable * allvars;
	variable * constant_filter_vars;
	f_code * it_end_code;
	layer * layers;
	flame_communication * communications;
	model_datatype * datatypes;
	time_data * time_units;
	input_file * temp_input_file;
	
	/* Allocate memory for modeldata */
	modeldata = (model_data *)malloc(sizeof(model_data));
	/* 0=serial(default) 1=parallel 2=grid */
	modeldata->code_type = 0;
	/* 0=dgraph.dot 1=stategraph.dot */
	modeldata->depends_style = 0;
	modeldata->debug_mode = 1;

	inputfile[1]='\0';
	
	/* Initialise pointers */
	modeldata->name = NULL;
	modeldata->p_xmachines = &xmachines;
	xmachines = NULL;
	modeldata->p_xmessages = &xmessage;
	xmessage = NULL;
	modeldata->p_envvars = &envvar;
	envvar = NULL;
	modeldata->p_envfuncs = &envfunc;
	envfunc = NULL;
	modeldata->p_envdefines = &envdefine;
	envdefine = NULL;
	modeldata->p_allvars = &allvars;
	allvars = NULL;
	modeldata->p_it_end_code = &it_end_code;
	it_end_code = NULL;
	modeldata->p_layers = &layers;
	layers = NULL;
	modeldata->p_communications = &communications;
	communications = NULL;
	modeldata->p_datatypes = &datatypes;
	datatypes = NULL;
	modeldata->p_time_units = &time_units;
	time_units = NULL;
	modeldata->p_files = &temp_input_file;
	temp_input_file = NULL;
	modeldata->p_constant_filter_vars = &constant_filter_vars;
	constant_filter_vars = NULL;
	
	printf("xparser (Version %d.%d.%d)\n", VERSIONMAJOR, VERSIONMINOR, VERSIONMICRO);
	
	/* Must be at least the input file name */
	if(argc < 2)
	{
		printf("Usage: xparser [XMML file] [-s | -p] [-f]\n");
		printf("\t-s\tSerial mode\n");
		printf("\t-p\tParallel mode\n");
		printf("\t-f\tFinal production mode\n");
		free_modeldata(modeldata);
		return 0;
	}
	
	/* Copy location of xparser */
	strcpy(templatedirectory,argv[0]);
	
	/* parser command line */
	while(argc >1){
		if(argv[1][0] == '-') {
			switch (argv[1][1]){
			case 's': modeldata->code_type = 0;
				  break;
			case 'p': modeldata->code_type = 1;
				  break;
			case 'f' : modeldata->debug_mode = 0;
				  break;
			default:  printf("xparser: Error - unknown option %s\n",argv[1]);
				free_modeldata(modeldata);
				return 0;
			}
		}
		else
		{
			strcpy(inputfile,argv[1]);
			/* printf("XMML input file : %s\n",argv[1]); */
		}
		argc--;
		argv++;
	}
	
	if(inputfile[1] == '\0') {
		printf("xparser: Error - XMML must be specified\n");
		free_modeldata(modeldata);
		return 0;
	}
	
	/* Print what type of code writing */
    printf("\n");
    printf("Code type       : ");
	if(modeldata->code_type == 0) printf("Serial");
	if(modeldata->code_type == 1) printf("Parallel");
	if(modeldata->debug_mode == 1) printf(" (DEBUG)");
    printf("\n");
	
	/* Calculate directory to write files to */
	i = 0;
	lastd = 0;
	while(inputfile[i] != '\0')
	{
	/* For windows directories */
		if(inputfile[i] == '\\') lastd=i;
	/* For unix directories */
		if(inputfile[i] == '/') lastd=i;
		i++;
	}
	/* If a directory is in the path */
	if(lastd != 0)
	{
		strcpy(directory, inputfile);
		directory[lastd+1] = '\0';
	}
	else directory[0] = '\0';
	
	/* Calculate directory where xparser and template files are */
	i = 0;
	lastd = 0;
	while(templatedirectory[i] != '\0')
	{
		/* For windows directories */
		if(templatedirectory[i] == '\\') lastd=i;
		/* For unix directories */
		if(templatedirectory[i] == '/') lastd=i;
		i++;
	}
	/* If a directory is in the path */
	if(lastd != 0)
	{
		templatedirectory[lastd+1] = '\0';
	}
	else templatedirectory[0] = '\0';
	
	/* Appending templates subdir */
	strcat(templatedirectory, "templates/");
	
	printf("Input XMML file : %s\n", inputfile);
	printf("Model root dir  : %s\n", directory);
	printf("Template dir    : %s\n", templatedirectory);
    printf("\n");
	
	current_input_file = add_input_file(modeldata->p_files);
	current_input_file->fullfilepath = copystr(inputfile);
	current_input_file->fulldirectory = copystr(directory);
	current_input_file->localdirectory = copystr("");
	
	/* Read model from model xml file */
	current_input_file = * modeldata->p_files;
	while(current_input_file)
	{
		if(current_input_file->enabled == 1)
			readModel(current_input_file, directory, modeldata);
		
		current_input_file = current_input_file->next;
	}
	rc = checkmodel(modeldata);
	if(rc == -1)
	{
		free_modeldata(modeldata);
		return 0;
	}
	
	/* Calculate dependency graph for model functions */
	rc = create_dependency_graph(directory, modeldata);
	if(rc == -1)
	{
		free_modeldata(modeldata);
		return 0;
	}
	
	/* Looping through Template Directory searching for *.tmpl files */
	DIR *dir = opendir (templatedirectory);
	struct dirent *dp;          /* returned from readdir() */
	if (dir == NULL)
	{
		printf("Error: Opening %s directory failed.\n", templatedirectory);
	    return 0;            /* opendir() failed */
	}
	
	printf("Processing %s Directory.\n",templatedirectory);
	/* Loop through the directory. */
	while ((dp = readdir (dir)) != NULL)
	{
		int len = (int)strlen(dp->d_name);
		if(dp->d_name[len-1] == 'l' &&
			dp->d_name[len-2] == 'p' &&
			dp->d_name[len-3] == 'm' &&
			dp->d_name[len-4] == 't' &&
			dp->d_name[len-5] == '.')		/* if file ends with *.tmpl */
		{
			strcpy(templatename, templatedirectory); strcat(templatename, dp->d_name);
			strcpy(filename, directory); strcat(filename, dp->d_name);
			filename[strlen(filename)-5] = '\0';
			
			/* Parse templates to output files */
			parseTemplate(filename, templatename, modeldata);
			
		}
	}
	parseAgentHeaderTemplate(directory, modeldata);
	/*parseUnittest(directory, modeldata);*/
	/*parser0dtd(directory, modeldata);*/
	/*parser0xsd(directory, modeldata);*/
	
	free_modeldata(modeldata);
	
	printf("\n--- xparser finished ---\n\n");
    
    printf("To compile and run the generated code, you will need:\n");
    printf(" * libmboard (version %s or newer)\n", LIBMBOARD_MINVER_STR);
	
	/* Exit successfully by returning zero to Operating System */
	return 0;
}
Beispiel #11
0
/*
 *  mLoad_CASE
 *
 *  This function is called to set up (load) the macro
 *  when the template is first read in (before processing).
 */
tMacro*
mLoad_Case(tTemplate* pT, tMacro* pMac, char const ** ppzScan)
{
    size_t         srcLen     = (size_t)pMac->res;   /* macro len  */
    tCaseStack     save_stack = current_case;
    tMacro*        pEsacMac;

    /*
     *  Save the global macro loading mode
     */
    tpLoadProc const * papLP = papLoadProc;

    /*
     *  IF there is no associated text expression
     *  THEN woops!  what are we to case on?
     */
    if (srcLen == 0)
        AG_ABEND_IN(pT, pMac, "expressionless CASE");

    /*
     *  Load the expression
     */
    (void)mLoad_Expr(pT, pMac, ppzScan);

    /*
     *  IF this is the first time here,
     *  THEN set up the "CASE" mode callout tables.
     *  It is the standard table, except entries are inserted
     *  for SELECT and ESAC.
     */
    if (apCaseLoad[0] == NULL) {
        int i;

        /*
         *  Until there is a selection clause, only comment and select
         *  macros are allowed.
         */
        for (i=0; i < FUNC_CT; i++)
            apSelectOnly[i] = mLoad_Bogus;

        memcpy((void*)apCaseLoad, apLoadProc, sizeof( apLoadProc ));
        apSelectOnly[ FTYP_COMMENT] = mLoad_Comment;
        apSelectOnly[ FTYP_SELECT ] = \
        apCaseLoad[   FTYP_SELECT ] = mLoad_Select;
        apCaseLoad[   FTYP_ESAC   ] = mLoad_Ending;
    }

    /*
     *  Set the "select macro only" loading mode
     */
    papLoadProc = apSelectOnly;

    /*
     *  Save global pointers to the current macro entry.
     *  We will need this to link the CASE, SELECT and ESAC
     *  functions together.
     */
    current_case.pCase = current_case.pSelect = pMac;

    /*
     *  Continue parsing the template from this nested level
     */
    pEsacMac = parseTemplate(pMac+1, ppzScan);
    if (*ppzScan == NULL)
        AG_ABEND_IN(pT, pMac, "ESAC not found");

    /*
     *  Tell the last select macro where its end is.
     *  (It ends with the "next" sibling.  Since there
     *  is no "next" at the end, it is a tiny lie.)
     *
     *  Also, make sure the CASE macro knows where the end is.
     */
    pMac->endIndex = \
    current_case.pSelect->sibIndex = (pEsacMac - pT->aMacros);

    /*
     *  Restore any enclosing CASE function's context.
     */
    current_case = save_stack;

    /*
     *  Restore the global macro loading mode
     */
    papLoadProc  = papLP;

    /*
     *  Return the next available macro descriptor
     */
    return pEsacMac;
}
Beispiel #12
0
wstring QueryAssembler::CreateQuery(const FilledFrame& targetFrame, const NetEvaluator& evaluator, std::wstring& question)
{
	wstring toReturn = L"";

	currentFrameTense = targetFrame.GetTense();

	wstring qTemplate = getQueryTemplateFromDB(targetFrame.GetSemanticFrame()->GetFrameName(), pathToDb);

	queryTemplate = parseTemplate(qTemplate);

	vector<wstring> queryParts;
	queryParts.push_back(L"");

	wstring queryClause;
	bool timeSpecified = false;

	for(auto slot_p = targetFrame.GetSlotIterator(); slot_p != targetFrame.GetSlotEndIterator(); slot_p++)
	{
		if((*slot_p)->GetNetName() == CONST_QUERY) //if this is a [Query] slot, we extract key word for question type for it: why, where, when...
		{
			question = evaluator.Evaluate(*slot_p, currentFrameTense)[NetEvaluator::VALUE];
		}

		try
		{
			if(queryTemplate.find((*slot_p)->GetNetName()) != queryTemplate.end())
			{
				queryClause = interpolate(queryTemplate.at((*slot_p)->GetNetName()), *slot_p, evaluator);
				if((*slot_p)->IsExternal()) //now it just means that we encountered time expression
				{
					timeSpecified = true;
				}

				if(queryClause.find(L"SELECT") == 0) //we reserve first position for the SELECT clause
				{
					if(queryClause.find(L"WHERE") == wstring::npos)
						queryClause.append(L" WHERE 1=1");
					queryParts[0] = queryClause;
				}
				else if(!queryClause.empty()) // other parts of the query are joined by conjunction
				{
					queryClause = wstring(L" AND ").append(queryClause);
					queryParts.push_back(queryClause);
				}
			}
		}
		catch(...)
		{
			throw EInvalidTemplate(targetFrame.GetSemanticFrame()->GetFrameName().c_str());
		}
	}

	if(queryParts[0].empty()) //if we didn't find any slot which could determine source table we force select from Afisha
	{
		//throw 0;
		queryParts[0] = L"SELECT Year, Sport, Event, Athlete, Result, Medal, Country, Country_Taker, City_Taker, Season, COUNT(*) as Times FROM OlympData WHERE 1=1";
	}

	if(!timeSpecified) //if we didn't find any slot which could determine time we set default timex slot based on tense
	{
		Slots def_timex = createDefaultTimex(currentFrameTense);

		shared_ptr<IMatch> def_time_match = shared_ptr<IMatch>(new TimexMatch(def_timex));

		//Print("/home/stepan/zz.txt", queryTemplate);
		wstring sdklfdjfdskljfds = def_time_match->GetNetName();
		queryClause = L" AND " + interpolate(queryTemplate.at(def_time_match->GetNetName()), def_time_match, evaluator);
		
		queryParts.push_back(queryClause);
	}

	for(size_t i = 0; i < queryParts.size(); i++)
	{
		toReturn.append(queryParts[i]);
	}

	return toReturn;
}
Beispiel #13
0
tMacro*
mLoad_If(tTemplate* pT, tMacro* pMac, char const ** ppzScan)
{
    size_t              srcLen     = (size_t)pMac->res; /* macro len  */
    tIfStack            save_stack = current_if;
    tpLoadProc const *  papLP      = papLoadProc;
    tMacro *            pEndifMac;

    /*
     *  While processing an "IF" macro,
     *  we have handler functions for 'ELIF', 'ELSE' and 'ENDIF'
     *  Otherwise, we do not.  Switch the callout function table.
     */
    static tpLoadProc apIfLoad[ FUNC_CT ] = { NULL };

    /*
     *  IF there is no associated text expression
     *  THEN woops!  what are we to case on?
     */
    if (srcLen == 0)
        AG_ABEND_IN(pT, pMac, NO_IF_EXPR);

    if (apIfLoad[0] == NULL) {
        memcpy((void*)apIfLoad, apLoadProc, sizeof(apLoadProc));
        apIfLoad[ FTYP_ELIF ]  = &mLoad_Elif;
        apIfLoad[ FTYP_ELSE ]  = &mLoad_Else;
        apIfLoad[ FTYP_ENDIF ] = &mLoad_Ending;
    }

    papLoadProc = apIfLoad;

    /*
     *  We will need to chain together the 'IF', 'ELIF', and 'ELSE'
     *  macros.  The 'ENDIF' gets absorbed.
     */
    current_if.pIf = current_if.pElse = pMac;

    /*
     *  Load the expression
     */
    (void)mLoad_Expr(pT, pMac, ppzScan);

    /*
     *  Now, do a nested parse of the template.
     *  When the matching 'ENDIF' macro is encountered,
     *  the handler routine will cause 'parseTemplate()'
     *  to return with the text scanning pointer pointing
     *  to the remaining text.
     */
    pEndifMac = parseTemplate(pMac+1, ppzScan);
    if (*ppzScan == NULL)
        AG_ABEND_IN(pT, pMac, LD_IF_NO_ENDIF);

    current_if.pIf->endIndex   = \
    current_if.pElse->sibIndex = pEndifMac - pT->aMacros;

    /*
     *  Restore the context of any encompassing block macros
     */
    current_if  = save_stack;
    papLoadProc = papLP;
    return pEndifMac;
}