W3TPL/archive/code

From Woozle Writes Code
< W3TPL‎ | archive
Revision as of 14:13, 25 July 2011 by Woozle (talk | contribs) (v0.44)
Jump to navigation Jump to search

Preface

I need to put this on GitHub. It's got a lot of rough edges, but it is definitely usable -- and other people could be working on the rough edges. --Woozle 10:13, 25 July 2011 (EDT)

PHP

<php><?php /*

HISTORY:

0.01 (Wzl) Mainly proof-of-concept; 0.02 (Wzl) Kluge to let <xploop> pull #var value under MW <1.12

	0.03 (Wzl) <func> and related tags seem to be working

0.04 (Wzl) Some debugging; now works with v1.12 {{#tag}} function and template parameters (but not very well) names are always lowercased because sometimes the parser does it for you names are always trimmed, because sometimes the parser includes extra spaces 0.05 (Wzl) Added variable indirection ($); removed now-redundant "namer" attribute from <let> can we do something similar with pre-parsing? (i.e. a character to indicate the need for it -- @(stuff to parse)) <if> can now make more sense, i.e. using actual values instead of assuming variable names 0.06 (Wzl) xploop now using variable indirection; removed listvar parameter 0.07 (Wzl) Execution trace in <dump> 0.08 (Wzl) <trace> to set trace options; "input" option in <call> 0.09 (Wzl) <echo> tag; <call> does not output its contents 0.10 (Wzl) Code runs ok; still writing <w3tpl> tag 0.11 (Wzl) Added detection of page-protection, and "raw" attribute for <echo> 0.12 (Wzl) Fixed minor incompatibilities with MW 1.10 0.13 (Wzl) <for> tag seems to be working, at least for simple stuff 0.14 (Wzl) <load> tag fails gracefully when title doesn't exist 0.15 (Wzl) Support for brackets in variable names, to reference arrays 0.16 (Wzl) No SQL on unprotected pages; "limit" attribute for retrieving partial data 0.17 (Wzl) Removed some undefined-var warnings which pop up under certain mysterious circumstances 0.18 (Wzl) Lots of under-the-hood changes; var names are now parsed by the class clsW3VarName, which may later get renamed to clsW3Var and integrated with the full-blown parser to be written. There's still some ambiguity about the exact circumstances under which <let> overwrites existing data and when it operates on the variable's current value. 0.19 (Wzl) $wgW3TPLSettings['raw-ok'] now allows raw output even if page not protected 0.20 (Wzl) added "pre" as a deprecated alias for "parse", for backwards compatibility 0.21 (Wzl) merged changes from other version 0.19 (accidental fork): "user.name" and "user.dbkey" system data 0.22 (Wzl) user.can.[action] 0.23 (Wzl) added "file=" attribute to <dump> tag; $wgW3_opt_fpLogs 0.24 (Wzl) wrote code for access to non-MW dbs via "db=" in <for> tag 0.25 (Wzl) patch for pre-5.3.0 PHP; @title.url 0.26 (Wzl) 'vars' option for <let> copied from <echo>, but it doesn't seem to work 0.27 (Wzl) @title.full 0.30 (Wzl) removed all echo-level tracking; added "var" attribute to <echo> 0.31 (Wzl) @user.rights - returns marked list of current user's rights "if (defined('__DIR__'))" properly invokes newer PHP constant if it's available 0.?? 2009-02-13 (Wzl) $wgOptCP_SubstFinish "]" -> "$]" so links and other bracketed stuff don't confuse the var parser 0.32 2009-04-02 (Wzl) Fixed some warning messages in <for> (use of undeclared var $doTbl in certain circumstances) Fixed bug where upper-cased things in sysvars (@) could not be accessed (was: 2009-01-29 can't access upper-case-named POST variables) "sql=" argument in <for> 0.33 2009-04-11 (Wzl) - var names are now lowercased before being used as an index, but @sysdata names still are not 0.34 2009-04-26 (Wzl) - @user.name, @user.email

	0.35 2009-05-30 (wzl) - merged changes made in v0.33 of separate branch (merged on 2009-06-06)

Removed <for name=> parameter, field name is now @row's 2nd argument (not 3rd) <for xps=> option to use xplodable string as list <let oparse> option to parse value only on output (use with "echo" option) @title.subject no longer includes subpages; added @title.name, which does 0.36 2010-01-19 (Wzl) - minor bugfix in efW3For(): make sure $doDb is always defined 0.37 2010-01-29 (Wzl) - another minor bugfix in efW3For(): set $out to NULL at start, in case there is no output 0.38 2010-05-05 (Wzl) - variables in function names using "func=" parameter 0.39 2010-07-25 (Wzl) - no functional changes; just sorted tag functions alphabetically 0.40 2010-09-11 (Wzl) 0.41 2011-05-05 (Wzl) split <for>'s row-display code off into a separate function, for external use (InstaGov) fixed bug in <get arg> added "tag" option to <echo> and <let> deprecated @post and @query; added @http.get/post/req 0.42 2011-06-01 (Wzl) added plus, minus, min, max, not operators to <let> 0.43 2011-06-13 (Wzl) moved @sql to @db.sql 0.44 2011-07-25 (Wzl) functions are now stored in page_props; <call> looks there if it can't find one already loaded TO DO: An alternate <call> syntax might be good, where the function name and arguments are given explicitly: <run func=funcName arg1=value arg2=value input=arg3>this will get passed as the value of arg3</run> ...or possibly just define the function name as a tag for the shorter form: <funcName value1 value2> Functions should be able to return values Variables inside functions should be local by default; need a way to make them global as well if we do that <load> should do nothing by default "parse[=var]" should tell it to parse the page's contents and place the results in var "raw=var" should tell it to put the page's unparsed contents into var "props=var" should tell it to load the page's page_props into array var[] "smwprops=var" should tell it to load the page's Semantic MediaWiki properties into array var[]

ELEMENTS:

<hide>: Runs the parser on everything in between the tags, but doesn't display the result. Useful for doing a lot of "programmish" stuff, so you can format it nicely and comment it without messing up your display <let>, <get>: much like PageVars extension, but using XML tags instead of {{#parser}} functions <func>: defines a function which can be called with arguments later <arg>: optional method of passing arguments to a function <call>: call a previously defined function <dump>: show list of all variables (with values) and functions (with code) <if>, <else>: control structure <xploop list="\demarcated\list" repl=string-to-replace sep=separator></xploop>: Same as {{#xploop}}, but uses varname instead of $s$ TO-DO <w3tpl></w3tpl>: The language itself parser should later be optimized for execution time by using PHP intrinsic string fx instead of PHP-code loop

  • /


if (defined( '__DIR__' )) {

 $fpThis = __DIR__;

} else {

 $fpThis = dirname(__FILE__);

// require_once('StringTemplate.php'); // can this be made load-on-demand? It's only used by <echo> } if (!defined('LIBMGR')) {

   require('libmgr.php');

} clsLibMgr::Add('StringTemplate', $fpThis.'/StringTemplate.php',__FILE__,__LINE__); clsLibMgr::Add('data', $fpThis.'/data.php',__FILE__,__LINE__);

$wgAutoloadClasses['clsStringTemplate'] = clsLibMgr::Path('StringTemplate'); $wgAutoloadClasses['clsDatabase'] = clsLibMgr::Path('data'); $wgOptCP_SubstStart = '[$'; $wgOptCP_SubstFinish = '$]';

$w3step = FALSE; $w3stop = FALSE;

$wgExtensionCredits['other'][] = array( 'name' => 'W3TPL', 'description' => 'Woozle\'s Wacky Wiki Text Processing Language', 'author' => 'Woozle (Nick) Staddon', 'url' => 'http://htyp.org/W3TPL', 'version' => '0.44 2011-07-25 (alpha)' );

define('ksFuncInit','efW3TPLInit');

//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980 if ( defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' ) ) {

       $wgHooks['ParserFirstCallInit'][] = ksFuncInit;

} else { // Otherwise do things the old fashioned way

       $wgExtensionFunctions[] = ksFuncInit;

} $wgHooks['LanguageGetMagic'][] = 'efW3_LanguageGetMagic'; $wgHooks['ParserAfterTidy'][] = 'efW3_ParserAfterTidy'; $wgHooks['OutputPageBeforeHTML'][] = 'efW3_OutputPageBeforeHTML';

function efW3TPLInit() {

       global $wgParser;

global $wgExtW3TPL; global $wgW3RawOk;

// hook in <tag>-style functions:

       $wgParser->setHook( 'arg',	'efW3Arg' );
       $wgParser->setHook( 'call',	'efW3Call' );
       $wgParser->setHook( 'class',	'efW3Class' );
       $wgParser->setHook( 'dump',	'efW3Dump' );
       $wgParser->setHook( 'echo',	'efW3Echo' );
       $wgParser->setHook( 'else',	'efW3Else' );
       $wgParser->setHook( 'for',	'efW3For' );
       $wgParser->setHook( 'func',	'efW3Func' );
       $wgParser->setHook( 'get',	'efW3Get' );
       $wgParser->setHook( 'hide',	'efW3Hide' );
       $wgParser->setHook( 'if',	'efW3If' );
       $wgParser->setHook( 'let',	'efW3Let' );
       $wgParser->setHook( 'load',	'efW3Load' );
       $wgParser->setHook( 'save',	'efW3Save' );
       $wgParser->setHook( 'trace',	'efW3Trace' );
       $wgParser->setHook( 'w3tpl',	'efW3TPLRender' );
       $wgParser->setHook( 'xploop',	'efW3Xploop' );
       return true;

} function efW3_LanguageGetMagic( &$magicWords, $langCode = "en" ) {

   switch ( $langCode ) {
       default:
           $magicWords['w3xploop']	= array ( 0, 'w3xploop' );
           $magicWords['w3xpcount']	= array ( 0, 'w3xpcount' );
   }
   return true;

}


function TrueFalse($iVar) { return $iVar?'TRUE':'FALSE'; } function W3VarExists($iName) { global $wgW3Vars;

$strName = strtolower($iName); return isset($wgW3Vars[$strName]); } function W3KillVar($iName) { global $wgW3Vars;

$strName = strtolower($iName); unset($wgW3Vars[$strName]); } function W3SetVar($iName, $iValue, $iAppend = FALSE) { global $wgW3Vars, $wgW3_doTrace_vars;

$strName = strtolower($iName); if ($iAppend && isset($wgW3Vars[$strName])) { $wgW3Vars[$strName] .= $iValue; if ($wgW3_doTrace_vars) { W3AddTrace(' $['.ShowHTML($strName).'] += ['.$iValue.'] => ['.$wgW3Vars[$strName].']'); } } else { $wgW3Vars[$strName] = $iValue; if ($wgW3_doTrace_vars) { W3AddTrace(' $['.ShowHTML($strName).'] = ['.$iValue.']'); } } } function W3GetSysData($iName) {

   global $wgTitle,$wgUser,$wgRequest;
   global $wgW3_doTrace_vars;
   global $wgW3_data;
   global $sql;
   $strName = $iName;
   $strParts =  explode('.', $strName);
   if (isset($strParts[1])) {

$strParam = strtolower($strParts[1]);

   } else {

$strParam = NULL;

   }
   switch ($strParts[0]) {
     case 'title':

switch ($strParam) { case 'id': $out = $wgTitle->getArticleID(); break; case 'full': // namespace:subject $out = $wgTitle->getPrefixedText(); break; case 'subject': // just the part after the namespace and before any slashes $out = $wgTitle->getBaseText(); break; case 'name': // just the part after the namespace $out = $wgTitle->getText(); break; case 'url': $out = $wgTitle->getFullURL(); break; case 'dbkey': // as stored in db tables $out = $wgTitle->getDBkey(); break; } break;

     case 'row':

$strFld = $strParts[1]; // field name $strSet = '@@row@@';

$out = NULL; // This is a horrible kluge necessitated by the 2 different ways of accessing data in <for> $val = nzArray($wgW3_data,$strSet); if (!is_null($val)) { $vRow = $val; if (is_array($vRow)) { if (array_key_exists($strFld,$vRow)) { $out = $vRow[$strFld]; } else { $strErr = 'Dataset ['.$strSet.'] has no field named ['.$strFld.'].'; //throw new exception($strErr); $out = 'Error: '.$strErr; } } else { if (isset($vRow->$strFld)) { $out = $vRow->$strFld; } } } W3AddTrace('DATA['.$strSet.']['.$strFld.'] => ['.$out.']'); break;

     case 'mem':

$out = memory_get_usage(TRUE); break;

     case 'user':

switch ($strParam) { case 'login': $out = $wgUser->getName(); break; case 'dbkey': $out = $wgUser->getTitleKey(); break; case 'id': $out = $wgUser->getID(); break; case 'can': $out = $wgUser->isAllowed($strParts[2]); break; case 'rights': $arrRights = $wgUser->getRights(); $out = ; foreach ($arrRights as $key=>$val) { $out .= '\\'.$val; } break; case 'email': $out = $wgUser->getEmail(); break; case 'name': $out = $wgUser->getRealName(); break; default: $out = '?'.$strParam; } break;

     case 'http':

$strName = nz($strParts[2]); switch ($strParam) { case 'get': if (empty($strName)) { # TO DO: return raw query } else { //$out = $wgRequest->getText($strParam); if (isset($_GET[$strName])) { $out = $_GET[$strName]; } else { $out = NULL; // maybe this should be a list? or raw query, unparsed? } } break; case 'post': if ($strParam) { if (isset($_POST[$strParam])) { $out = $_POST[$strParam]; } else { $out = NULL; // maybe this should be a list? } } W3AddTrace(' GET POST ['.ShowHTML($strParam).']: ['.$out.']'); break; case 'req': if ($strParam) { $out = $wgRequest->getVal($strName); } else { $out = NULL; // maybe this should be a list? } break; } break;

     case 'query':	// DEPRECATED -- same as http.get; eliminate eventually

if ($strParam == ) { // never used } else { //$out = $wgRequest->getText($strParam); if (isset($_GET[$strParam])) { $out = $_GET[$strParam]; } else { $out = ; } } break;

     case 'post':	// DEPRECATED -- same as http.post; eliminate eventually

if ($strParam) { if (isset($_POST[$strParam])) { $out = $_POST[$strParam]; } else { $out = NULL; } } W3AddTrace(' GET POST ['.ShowHTML($strParam).']: ['.$out.']'); break;

     case 'env':

if ($strParam) { if (isset($_ENV[$strParam])) { $out = $_ENV[$strParam]; } else { $out = NULL; } } break;

     case 'db':

switch ($strParam) { case 'sql': $out = $sql; break; default: $out = 'unknown subtype for db: ['.$strParam.']'; } break;

     /* This is mainly for debugging (later it may be useful for library maintenance), so I'm

not going to try to make it forward-compatible with the changes I expect to make later, i.e. having functions as an object type. SYNTAX: @func.name.def|page

     */
     case 'func':
     global $wgW3_funcs;

$fname = $strParam; $fobj = $wgW3_funcs[$fname];

switch ($strParts[2]) { case 'def': $out = $fobj->dump(); break; case 'page': // not implemented yet break; } break;

   }
   if ($wgW3_doTrace_vars) {

W3AddTrace(' GETSYSDATA-'.$strParts[0].' ['.ShowHTML($iName).']: ['.$out.']');

   }
   return $out;

} function W3SetSysData($iName,$iValue) { global $wgOut; global $wgW3Trace_indent;

W3AddTrace(' SETSYSDATA ['.$iName.':'.$iValue.']'); $strName = $iName; $strParts = explode('.', $strName); switch (strtolower($strParts[0])) { case 'catg': $wgW3Trace_indent++; W3AddTrace('CATG'); $wgW3Trace_indent--; $wgOut->mCategoryLinks = array(); break; } } function W3GetExpr($iName) { // check expression for $, meaning it's actually a reference to a variable // If found, return value of variable - otherwise return original string. $objVar = new clsW3VarName($iName); $objVar->Trace(); $objVar->Fetch(); $strOut = $objVar->Value; return $strOut;

} function W3GetVal($iName,$iIndex=NULL) { // gets value of given variable // checks function arguments, if function is defined $objVar = new clsW3VarName(); $objVar->ParseName($iName); if (!is_null($iIndex)) { $objVar->SetIndex($iIndex); } $objVar->Trace(); $objVar->Fetch(); $strVal = $objVar->Value; return $strVal; } function W3GetEcho() { global $wgW3_echoBuffer;

$out = $wgW3_echoBuffer; $wgW3_echoBuffer = NULL; return $out; } function W3AddEcho($iVal) { global $wgW3_echoBuffer;

$wgW3_echoBuffer .= $iVal; } function W3AddTrace($iLine,$iInd=0) { global $wgW3Trace, $wgW3Trace_indents, $wgW3Trace_indent; global $wgW3_doTrace; global $wgW3_TraceCount;

if ($wgW3_doTrace) { if ($wgW3_TraceCount < 1000) { $wgW3Trace[] = $iLine; $wgW3Trace_indents[] = $wgW3Trace_indent; $wgW3Trace_indent += $iInd; } $wgW3_TraceCount++; } /**/ } function W3Status_RawOk() { global $wgTitle; global $wgW3_func; global $wgW3TPLSettings; global $wgW3_Override_RawOk;

if (isset($wgW3_Override_RawOk)) { $isProt = $wgW3_Override_RawOk; } else { if ($wgW3TPLSettings['raw-ok']) { $isProt = TRUE; } else { $isProt = $wgTitle->isProtected ('edit'); } if (!$isProt) { if (is_object($wgW3_func)) { $isProt = $wgW3_func->isOkRaw; } } W3AddTrace('IS RAW ok in ['.$wgTitle->getFullText().']: '.TrueFalse($isProt)); } return $isProt; } function W3Status_SQLOk() {

   global $wgTitle;
   global $wgW3_func;
   global $wgW3TPLSettings;
   if ($wgW3TPLSettings['sql-ok']) {

$isOk = TRUE;

   } else {

$isProt = $wgTitle->isProtected ('edit'); if ($isProt) { $isOk = TRUE; } else { if (is_object($wgW3_func)) { $isOk = $wgW3_func->isOkSQL; } else { $isOk = FALSE; } }

   }
   // FUTURE: print a message if SQL is forbidden
   //W3AddTrace('IS SQL allowed in ['.$wgTitle->getFullText().']: '.TrueFalse($isProt));
   return $isOk;

} /*----

 HISTORY:
   2011-05-31 added "tag" attribute
  • /

function W3Let_scalar( $iVar, $iArgs, $input, $parser ) { global $wgRequest; global $wgW3_func; global $wgOptCP_SubstStart, $wgOptCP_SubstFinish;

$strRepl = W3GetExpr($iArgs->GetVal('repl')); $strWith = W3GetExpr($iArgs->GetVal('with')); $doRepl = !is_null($strRepl) || !is_null($strWith); $doAppend = $iArgs->Exists('append');

// TRACING: $strTrace = ' - LET scalar:'; if (!is_null($strRepl)) { $strTrace .= ' repl=“'.$strRepl.'”'; } if (!is_null($strWith)) { $strTrace .= ' repl=“'.$strWith.'”'; } if ($doAppend) { $strTrace .= ' APPEND'; } W3AddTrace($strTrace);

if ($iArgs->Exists('val')) { $iVar->Value = $iArgs->GetExpr('val'); $strTrace = ' - LET VAL: expr=['.ShowHTML($iVar->Value).']'; W3AddTrace($strTrace); } elseif ($iArgs->Exists('arg')) { $strCopy = $iArgs->vArgs['arg']; // don't do any indirection from user input (possible security hole) $parser->disableCache(); $iVar->Value = $wgRequest->getVal($strCopy); // , $strDefault) -- maybe add feature later } elseif ($iArgs->Exists('farg')) { if (is_null($wgW3_func)) { W3AddTrace(' - ERROR: no function active to provide arg ['.$strName.']'); } else { $strName = strtolower($iArgs->GetExpr('farg')); if ($wgW3_func->HasArg($strName)) { $iVar->Value = $wgW3_func->ArgVal($strName); W3AddTrace(' - ARG['.$strName.'] => “'.$iVar->Value.'”'); } else { W3AddTrace(' - ERROR: function ['.$wgW3_func->Name.'] has no argument named ['.$strName.'].'); } } } elseif ($iArgs->Exists('chr')) { $iVar->Value = chr($iArgs->GetExpr('chr')); }

// AT THIS POINT, $this->Value is loaded with the value we want to operate on.

// later, we may want inc/dec to imply self-operation if there is no other input... // but this needs to be thought through carefully. For now, require "self" to increment self.

// do processing on current value: if ($iArgs->Exists('inc')) { $iVar->Value++; } if ($iArgs->Exists('dec')) { $iVar->Value--; } if ($iArgs->Exists('not')) { $iVar->Value = !$iVar->Value; }

if ($iArgs->Exists('parse') || $iArgs->Exists('pre')) { // restoring "pre" for backwards compatibility $iVar->Value = $parser->recursiveTagParse($iVar->Value); } if ($iArgs->Exists('vars')) { W3AddTrace(' LET VARS before ['.ShowHTML($iVar->Value).']'); $objTplt = new clsStringTemplate_w3tpl($wgOptCP_SubstStart,$wgOptCP_SubstFinish); $objTplt->Value = $iVar->Value; $iVar->Value = $objTplt->Replace(); W3AddTrace(' LET VARS after ['.ShowHTML($iVar->Value).']'); } if ($iArgs->Exists('ucase')) { $iVar->Value = strtoupper($iVar->Value); } if ($iArgs->Exists('lcase')) { $iVar->Value = strtolower($iVar->Value); } if ($iArgs->Exists('ucfirst')) { $iVar->Value = ucfirst($iVar->Value); } if ($iArgs->Exists('lcfirst')) { $iVar->Value = lcfirst($iVar->Value); } if ($iArgs->Exists('trim')) { $iVar->Value = trim($iVar->Value); } if ($iArgs->Exists('len')) { $strLen = $iArgs->GetExpr('len'); if (is_numeric($strLen)) { $iVar->Value = substr($iVar->Value,0,$strLen); } }

// 2011-06-01 these functions will probably need some debugging, especially in how they interact with other functions if ($iArgs->Exists('plus')) { $valNew = $iVar->Value; // save the newly-calculated value off to one side $iVar->Fetch(); // restore the prior value $iVar->Value += $valNew; // add the new value to the prior value } if ($iArgs->Exists('minus')) { $valNew = $iVar->Value; // save the newly-calculated value off to one side $iVar->Fetch(); // restore the prior value $iVar->Value -= $valNew; // subtract the new value from the prior value } if ($iArgs->Exists('min')) { $valNew = $iVar->Value; // save the newly-calculated value off to one side $iVar->Fetch(); // restore the prior value if ($valNew < $iVar->Value) { $iVar->Value = $valNew; } } if ($iArgs->Exists('max')) { $valNew = $iVar->Value; // save the newly-calculated value off to one side $iVar->Fetch(); // restore the prior value if ($valNew > $iVar->Value) { $iVar->Value = $valNew; } }

if ($iArgs->Exists('fmt')) { $fmt = $iArgs->GetExpr('fmt'); $iVar->Value = sprintf($fmt,$iVar->Value); } if ($iArgs->Exists('tag')) { // surround result with <> to make it into an HTML tag $iVar->Value = '<'.trim($iVar->Value).'>'; } if ($doRepl) { if (is_null($strRepl)) { $strRepl = $input; } elseif (is_null($strWith)) { $strWith = $input; } $doIncluding = TRUE; if ($iArgs->Exists('before')) { // replace everything before the mark // TODO $doIncluding = FALSE; } if ($iArgs->Exists('after')) { // replace everything after the mark // TODO $doIncluding = FALSE; } if ($iArgs->Exists('including')) { $doIncluding = TRUE; } if ($doIncluding) { $strRes = str_replace($strRepl,$strWith,$iVar->Value); } W3AddTrace('LET REPLACE ['.$strRepl.'] WITH ['.$strWith.'] => ['.$strRes.'] in “'.$iVar->Value.'”'); $iVar->Value = $strRes; } W3AddTrace('LET ['.$iVar->Name.'] ← “'.$iVar->Value.'”');

// AT THIS POINT, we have the semi-final value to be stored // -- if it's being appended, then get the old value and prepend it to the new:

if ($doAppend) { $valNew = $iVar->Value; // save the newly-calculated value off to one side

W3AddTrace(' - APPEND “'.$valNew.'”'); $iVar->Fetch(); // restore the prior value $iVar->Value .= $valNew; // append the new value to the prior value } } function W3Let_array ( $iVar, $iArgs, $input, $parser ) { $doSort = $iArgs->Exists('sort');

if ($doSort) { $iVar->DoSort($iArgs->Exists('rev'),$iArgs->Exists('val')); } } // ********** // === BEGIN tag functions /*-----

 TAG: <arg>
  • /

function efW3Arg( $input, $args, $parser ) { global $wgW3_func;

if (isset($args['name'])) { $name = $args['name']; } else { $name = ; } if (isset($args['pre'])) { $value = $parser->recursiveTagParse($input); } else { $value = $input; } $strTrace = ' +ARG: '.$wgW3_func->LoadArg($value,$name); W3AddTrace($strTrace); } /*-----

 TAG: <call>
 NOTES: We might later split this into two tags, one for already-loaded functions and one that
   looks them up in the database, but I'm thinking that using alread-loaded functions will actually
   be the exception rather than the rule, so no need to optimize for it.
   ...and actually, if the function has been loaded, then access is almost as quick as before, so
   why optimize further?
  • /

function efW3Call( $input, $args, $parser ) { global $wgW3_funcs,$wgW3_func; global $wgOut;

W3AddTrace('{CALL:'); $pcnt = 0; $strTrace = NULL; // $wgW3_echoOutput = NULL; foreach ($args as $name => $value) { $strName = strtolower(trim($name)); if ($pcnt) { // every arg except the first one $strVal = W3GetExpr($value); $strTrace .= $objFunc->LoadArg($strVal,$strName); $strTrace .= ' '; $strTrace .= ')'; } else { // we're looking at the very first arg -- must be the function's name if ($strName == 'func') { $funcName = strtolower(W3GetExpr($value)); } else { $funcName = $strName; } W3AddTrace(' - (CALL) '.$funcName);

// there's probably a smoother way to do this... if (!is_array($wgW3_funcs)) { $wgW3_funcs = array(); } if (array_key_exists($funcName,$wgW3_funcs)) { // function already loaded $objFunc = $wgW3_funcs[$funcName]; $wgW3_func = $objFunc; } else { $objFunc = NULL; // in case we can't load it

// try to find it in page_props $fkey = '>fx()>'.$funcName; // pp_propname to find $sql = 'SELECT pp_page, pp_value FROM page_props WHERE pp_propname='.SQLValue($fkey); $dbr =& wfGetDB( DB_SLAVE ); try { $res = $dbr->query($sql); } catch (Exception $e) { $out = "W3TPL got a db error searching for function [$funcName] - ".$dbr->lastError()." - from this SQL:\n* ".$sql; return $parser->recursiveTagParse($out); } // get row ID of function //if (is_resource($res)) { if ($dbr->numRows( $res ) <= 0) { $objFunc = NULL; // function not found } while ($row = $dbr->fetchRow($res)) { $id = $row['pp_page']; $funcCode = $row['pp_value']; } // now look up arguments $akey = $fkey.'>'; $sql = 'SELECT pp_propname, pp_value FROM page_props WHERE ' .'(pp_page='.$id.') AND ' .'(pp_propname LIKE '.SQLValue($akey.'%').')'; try { $res = $dbr->query($sql); } catch (Exception $e) { $out = "W3TPL got a db error searching for arguments for function [$funcName] - ".$dbr->lastError()." - from this SQL:\n* ".$sql; return $parser->recursiveTagParse($out); }

$funcArgs = NULL; while ($row = $dbr->fetchRow($res)) { $arg = $row['pp_propname']; $val = $row['pp_value']; $funcArgs[$arg] = $val; } // create function object and add to loaded list: $objFunc = new clsW3Function($parser,$funcName,$funcArgs,$funcCode); $wgW3_func = $objFunc; $wgW3_funcs[$funcName] = $objFunc;

/*} else { $out = "W3TPL found no resource trying to load function [$funcName] from this SQL:\n* ".$sql; return $parser->recursiveTagParse($out); }*/

} if (!is_object($objFunc)) { $wgOut->AddHTML("W3TPL ERROR: Function [$funcName] is undefined.
* SQL: $sql"); return NULL; } $objFunc->ResetArgs(); } $pcnt++; } if ($input) { // $strTrace .= ' INPUT: {'.ShowHTML($input).'}'; $res = $parser->recursiveTagParse($input); // $strTrace .= ' PARSED: {'.ShowHTML($res).'}'; } if ($pcnt) { $out = $objFunc->execute(); } else { $wgOut->AddHTML('W3TPL ERROR: Function "'.$strName.'" not loaded; probably an internal error.'); } W3AddTrace($strTrace.' CALL}'); $out = W3GetEcho(); $wgW3_func = NULL; // no active function (is this still used?) return $out; } /*-----

 TAG: <class>
  • /

function efW3Class( $input, $args, $parser ) {

   global $wgW3_funcs;
   $valIn = $input;	// this will contain the class definition
   $arFuncsGlobal = $wgW3_funcs;	// save global functions
   $wgW3_funcs = NULL;			// reset function list
   $out = $parser->recursiveTagParse($valIn);	// adds functions defined within class to global function list
   $arFuncsClass = $wgW3_funcs;	// save class function list
   $wgW3_funcs = $arFuncsGlobal;	// restore global functions
   foreach ($arFuncsClass as $name => $code) {
   }

} /*-----

 TAG: <dump>
  • /

function efW3Dump( $input, $args, $parser ) { global $wgW3Vars, $wgW3_funcs; global $wgW3_doTrace, $wgW3_doTrace_vars; // tracing options global $wgW3Trace, $wgW3Trace_indents; // tracing data global $wgW3_TraceCount; global $wgW3_opt_fpLogs;

$out = '

    '; $doPost = isset($args['post']); // show posted data $doTrace = isset($args['trace']); // show trace log $doVars = isset($args['vars']); // show all variables $doFuncs = isset($args['funcs']); // show function definitions $doMem = isset($args['mem']); // show memory usage $wgW3_doTrace = $doTrace; $wgW3_doTrace_vars = $doTrace && $doVars; if ($doPost) { $out .= '
  • Posted::
      '; foreach ($_POST AS $key => $value) { $out .= ("\n
    • [$key]: [$value]"); } $out .= '
    ';

    }

    if ($doMem) {

    $out .= '
  • Memory usage before: '.memory_get_usage(TRUE).' bytes'; } if ($input != ) { $out .= $parser->recursiveTagParse($input); } if ($doMem) { $out .= '
  • Memory usage after: '.memory_get_usage(TRUE).' bytes'; } if ($doVars) { if (is_array($wgW3Vars)) { $out .= '
  • Variables:
      '; foreach ($wgW3Vars as $name => $value) { if (is_array($value)) { $out .= '
    • ['.$name.']: array'; $out .= '
        '; foreach ($value as $akey => $aval) { $out .= '
      • '.$name.'['.$akey.'] = ['.ShowHTML($aval).']'; } $out .= '
      ';

      } else {

      $out .= '
    • ['.$name.'] = ['.$value.']'; } } $out .= '
    ';

    } else {

    $out .= '
  • No variables set'; } } if ($doFuncs) { if (is_array($wgW3_funcs)) { $out .= '
  • Functions:
      '; foreach ($wgW3_funcs as $name => $obj) { $out .= '
    • '.$obj->dump(); } $out .= '
    ';

    } else {

    $out .= '
  • No functions defined'; } } if ($doTrace) { if (is_array($wgW3Trace)) { $out .= '
  • Trace ('.$wgW3_TraceCount.' events):
      '; $indCur = 0; foreach ($wgW3Trace as $idx => $line) { $indLine = $wgW3Trace_indents[$idx]; if ($indLine > $indCur) { $out .= '-'.$indLine.'-
        '; } elseif ($indLine < $indCur) { $out .= '
      ';

      } $indCur = $indLine; /**/

      $out .= '
    • '.$idx.' '.$line; } $out .= '
    ';

    } else {

    $out .= '
  • '.$wgW3_TraceCount.' trace events'; } } $out .= '

';

if (isset($args['file'])) { $strFile = $args['file']; // dump to a file instead of screen $fh = fopen($wgW3_opt_fpLogs.$strFile, 'a'); // $dt = new DateTime(); // $outPfx = $dt->format('Y-m-d H:i:s') . "\n"; $outPfx = date('Y-m-d H:i:s'); if (isset($args['msg'])) { $outPfx .= ' - '.$args['msg']; } $outPfx .= '
'; $qb = fwrite($fh, $outPfx.$out); fclose($fh); if (isset($args['hide'])) { return NULL; } else { return "$qb bytes logged to $strFile."; } } else { return $out; } } /*-----

 TAG: <echo>
  • /

function efW3Echo( $input, $args, $parser ) { global $wgOptCP_SubstStart,$wgOptCP_SubstFinish;

W3AddTrace('ECHO:');

if (isset($args['chr'])) { $valIn = chr($args['chr']); } else if (isset($args['var'])) { $valIn = W3GetVal($args['var']); } else { $valIn = $input; }

if (isset($args['strip'])) { $out = ShowHTML($valIn); } $doRaw = FALSE; if (isset($args['raw'])) { if (W3Status_RawOk()) { $doRaw = TRUE; } } $doNow = isset($args['now']); W3AddTrace(' input:['.ShowHTML($valIn).']'); $out = $valIn;

if (isset($args['vars'])) { W3AddTrace(' VARS before ['.ShowHTML($out).']'); $objTplt = new clsStringTemplate_w3tpl($wgOptCP_SubstStart,$wgOptCP_SubstFinish); $objTplt->Value = $out; $out = $objTplt->Replace(); W3AddTrace(' VARS after ['.ShowHTML($out).']'); }

if ($doRaw) { // no further processing } else { $out = $parser->recursiveTagParse($out); W3AddTrace(' PARSING returned ['.ShowHTML($out).']'); } if (isset($args['isolate'])) { $out = IsolateOutput($out); } if (isset($args['tag'])) { // surround result with <> to make it into an HTML tag $out = '<'.$out.'>'; }

W3AddTrace(' output: ['.ShowHTML($out).'] ECHO}'); if ($doNow) { return $out; } else { W3AddEcho($out); } } /*-----

 TAG: <else>
  • /

function efW3Else( $input, $args, $parser ) { global $wgW3_ifFlag, $wgW3_ifDepth;

$doHide = isset($args['hide']); // only output <echo> sections

$ifFlag = $wgW3_ifFlag[$wgW3_ifDepth]; W3AddTrace(' ELSE('.$wgW3_ifDepth.'): ['.$ifFlag.']'); if ($ifFlag) { W3AddTrace('ELSE skipped'); $out = NULL; } else { W3AddTrace('ELSE executed'); $wgW3_ifDepth++; $out = $parser->recursiveTagParse($input); $wgW3_ifDepth--; W3AddTrace('ELSE: OUT = ['.$out.']('.ShowHTML($out).')'); }

if ($doHide) { $out = W3GetEcho(); return $out; } else { return $out; } } /*----

 USED BY:
   efW3For()
   API (to be documented)
  • /

function ProcessRows($iDB,$iRes,$iName,$iParser,$input,$doHide, $iCallback=NULL) {

   global $wgW3_data;
   $dbr = $iDB;
   $res = $iRes;
   $strName = $iName;
   $parser = $iParser;
   $out = NULL;
   while( $row = $dbr->fetchObject ( $res ) ) {

W3AddTrace('FOR: row->['.$strName.']'); $wgW3_data[$strName] = $row; if (!is_null($iCallback)) { $out .= $iCallback($row); } $strParsed = $parser->recursiveTagParse($input); if ($doHide) { $out .= W3GetEcho(); W3AddTrace(' - FOR echo: ['.ShowHTML($out).']'); } else { $out .= $strParsed; W3AddTrace(' - FOR parse: ['.ShowHTML($out).']'); }

   }
   return $out;

} /*-----

 TAG: <for>
 TO DO: There needs to be a descendent data class which can handle MW databases so we can

switch between internal and external data just by selecting the appropriate class. As it is, there's a lot of untidy and almost-duplicate code for each case.

  • /

function efW3For( $input, $args, $parser ) { global $wgW3_data; global $wgW3Vars; global $wgW3DBs; global $w3stop; global $sql;

if ($w3stop) { return; }

$objArgs = new W3HookArgs($args); W3AddTrace('FOR:'); $out = NULL;

$doHide = isset($args['hide']); // only output <echo> sections $doArr = isset($args['array']); $doXps = isset($args['xps']); if ($doArr) { $strArr = $args['array']; } if ($doXps) { $strXps = $args['xps']; } if ($doArr || $doXps) { if (isset($args['index'])) { $strIdxName = $args['index']; } if (isset($args['sep'])) { $strSep = $args['sep']; } else { $strSep = NULL; } } if (W3Status_SQLOk()) { // for now, only look for SQL stuff if page is protected // TO DO: display error message on unprotected pages if SQL is used $doSql = isset($args['sql']); if ($doSql) { $sqlQry = $args['sql']; } $doTbl = isset($args['table']); if ($doTbl) { $strTbl = $args['table']; } $doDb = $doSql || $doTbl; $strWhere = $objArgs->GetExpr('where', TRUE); } else { $doDb = FALSE; $out .= 'W3TPL: database operation not allowed on unprotected page.'; } // these parameters can be used for other types of data (implemented yet? probably not) $strSort = $objArgs->GetExpr('sort', TRUE); $strLimit = $objArgs->GetExpr('limit', TRUE); // $strName = $objArgs->GetVal('name'); // name of variable for storing data $strName = '@@row@@'; // v0.35 $strEmpty = $objArgs->GetVal('empty'); // string to return if there is no data $strWhat = ; if ($doDb) { // doing something with a database $out = '<for table> WARNING: no output created'; // default message (TO DO: make this configurable) if ($objArgs->Exists('db')) { $useMWDB = FALSE; $strDBName = $objArgs->GetVal('db'); if (array_key_exists($strDBName,$wgW3DBs)) { $strDBSpec = $wgW3DBs[$strDBName]; $dbr = new clsDatabase($strDBSpec); $dbr->Open(); if ($doTbl) { $sqlWhat = $strTbl; // TO DO: make sure table exists } } else { throw new exception('$wgW3DBs does not have a database named "'.$strDBSpec.'"'); } } else { $useMWDB = TRUE; $dbr =& wfGetDB( DB_SLAVE ); if ($doTbl) { if ($dbr->tableExists($strTbl)) { $sqlWhat = $strTbl; } else { $out = "W3TPL: the table [$strTbl] does not exist. Use 'sql=' for more complex expressions."; return $out; } } } if ($strWhere != ) { // $sqlWhere = $dbr->addQuotes($strWhere); $sqlWhere = $strWhere; // TODO: need some way to harden against injection attack } else { $sqlWhere = FALSE; } if ($doSql) { $sqlFull = $sqlQry; } else { $sqlFull = 'SELECT * FROM '.$sqlWhat; if ($sqlWhere) { $sqlFull .= ' WHERE '.$sqlWhere; } if ($strSort) { $sqlFull .= ' ORDER BY '.$strSort; } if ($strLimit) { $sqlFull .= ' LIMIT '.$strLimit; } } $sql = $sqlFull; W3AddTrace(' - SQL=['.$sqlFull.']');

if ($useMWDB) { try { // $res = $dbr->query($sqlWhat,$sqlWhere); $res = $dbr->query($sqlFull); } catch (Exception $e) { $sqlSim = 'SELECT * FROM '.$sqlWhat; if ($sqlWhere) { $sqlSim .= ' WHERE '.$sqlWhere; } $out = "W3TPL encountered a database error - ".$dbr->lastError()." - from this SQL:\n* ".$sqlSim; return $parser->recursiveTagParse($out); } W3AddTrace(' - rows: '.$dbr->numRows( $res )); if ($dbr->numRows( $res ) <= 0) { $dbr->freeResult( $res ); return $parser->recursiveTagParse($strEmpty); }

/* while( $row = $dbr->fetchObject ( $res ) ) { W3AddTrace('FOR: row->['.$strName.']'); $wgW3_data[$strName] = $row; $strParsed = $parser->recursiveTagParse($input); if ($doHide) { $out .= W3GetEcho(); W3AddTrace(' - FOR echo: ['.ShowHTML($out).']'); } else { $out .= $strParsed; W3AddTrace(' - FOR parse: ['.ShowHTML($out).']'); } }

  • /

$out .= ProcessRows($dbr,$res,$strName,$parser,$input,$doHide); $dbr->freeResult( $res ); } else { $res = $dbr->_api_query($sqlFull); if (is_resource($res)) { if (mysql_num_rows( $res ) <= 0) { return $parser->recursiveTagParse($strEmpty); } while ($row = mysql_fetch_assoc($res)) { $wgW3_data[$strName] = $row; $strParsed = $parser->recursiveTagParse($input); if ($doHide) { $out .= W3GetEcho(); W3AddTrace(' - FOR echo: ['.ShowHTML($out).']'); } else { $out .= $strParsed; W3AddTrace(' - FOR parse: ['.ShowHTML($out).']'); } } } else { throw new exception('Problem executing SQL: ['.$sqlFull.']'); } } //$dbr->freeResult( $res ); // this actually causes *more* memory to be used //unset($wgW3_data); // and so does this! } if ($doArr) { if (isset($args['index'])) { $strIdxName = $args['index']; } //$wgW3Vars[$strArr][0] = 'zero'; $arr = $wgW3Vars[$strArr]; if (is_array($arr)) { $idx = 0; foreach ($arr as $name => $value) { $idx++; if ($strLimit) { if ($idx > $strLimit) { break; } } $strTrace = 'FOR: row->['.$strArr.']'; if ($strIdxName) { $wgW3Vars[$strIdxName] = (string)$name; $strTrace .= ' INDEX=['.$name.']=>['.$strIdxName.']'; } $strParsed = $parser->recursiveTagParse($input); W3AddTrace($strTrace); if (!isset($out)) { $out = NULL; } if ($doHide) { $out .= W3GetEcho(); W3AddTrace('FOR echo: ['.ShowHTML($out).']'); } else { $out .= $strParsed; W3AddTrace('FOR parse: ['.ShowHTML($out).']'); } } } else { W3AddTrace('FOR array=['.$strArr.']: not an array!'); } } if ($doXps) { W3AddTrace('FOR xps=['.$strXps.']'); if (isset($args['index'])) { $strIdxName = $args['index']; W3AddTrace(' - index ['.$strIdxName.']'); $tok = substr ( $strXps, 0, 1); // token for splitting W3AddTrace(' - tok ['.$tok.']'); $out = NULL; if ($tok) { $tks = substr ( $strXps, 1 ); // tokenized string $list = explode ( $tok, $tks ); // split the string foreach ($list as $value) { if (!is_null($out)) { $out .= $strSep; } $wgW3Vars[$strIdxName] = $value; W3AddTrace(' - XPS iteration: ['.$strIdxName.'] <- ['.$value.']'); $strParsed = $parser->recursiveTagParse($input); if ($doHide) { $out .= W3GetEcho(); W3AddTrace(' - echo: ['.ShowHTML($out).']'); } else { $out .= $strParsed; W3AddTrace(' - parse: ['.ShowHTML($out).']'); } } } } } return $out; } /*-----

 TAG: <func>
 NOTE: Function output is not sent to web output because typically we want to be able to format it nicely,
 which usually means lots of extra blank lines and indents.
  • /

function efW3Func( $input, $args, $parser ) { global $wgW3_funcs;

$pcnt = 0; $funcArgs = NULL; // declare var in case there are no args foreach ($args as $name => $value) { if ($pcnt) { /* The parser apparently sets the argument's value to its name if no value is specified. This is a sort of bug for this purpose, but maybe it makes sense in other contexts. The real way to get around it is to use <w3tpl> block syntax* instead of the <func> tag.

 *to be implemented
  • /

if ($value != $name) { $funcArgs[$name] = $value; } else { $funcArgs[$name] = null; } } else { $funcName = strtolower($name); } $pcnt++; } if (isset($funcName)) { W3AddTrace('FUNC “'.$funcName.'”'); $objFunc = new clsW3Function($parser,$funcName,$funcArgs,$input); $wgW3_funcs[$funcName] = $objFunc;

// store the function in page_props (added 2011-07-24) // -- we'll use prefix-marked strings to store the function data, using ">" as the prefix // because it should never be in a function or argument name $fkey = '>fx()>'.$funcName; // store the function's code $parser->mOutput->setProperty($fkey,$input); // store the argument data foreach ($funcArgs as $name => $val) { $akey = $fkey.'>'.$name; $parser->mOutput->setProperty($akey,$val); }

} else { W3AddTrace('FUNC: function name not set! input=['.$input.']'); } return NULL; } /*-----

 TAG: <get>
  • /

function efW3Get( $input, $args, $parser ) {

       global $wgRequest,$wgOut;

$objArgs = new W3HookArgs($args); W3AddTrace('GET:'); $doRaw = FALSE;

if (isset($args['default'])) { $strDefault = $args['default']; } else { $strDefault = NULL; }

// always get "name"; it may be used by other options, or overridden: $strName = strtolower($args['name']); W3AddTrace(' - name=['.$strName.']');

$strIdx = $objArgs->GetExpr('index',TRUE); $strVal = W3GetVal($strName,$strIdx);

if (isset($args['val'])) { $strVal = $args['val']; $strVal = W3GetExpr($strVal); // check for redirections } elseif (isset($args['arg'])) { $parser->disableCache(); $strVal = $wgRequest->getVal($strName, $strDefault); }

if (isset($args['pfx'])) { $strTxt = W3GetExpr($args['pfx']); $strVal = $strTxt.$strVal; } if (isset($args['sfx'])) { $strTxt = W3GetExpr($args['sfx']); $strVal .= $strTxt; }

if (isset($args['codes'])) { $strVal = ShowHTML($strVal); } else { $doRaw = FALSE; if (isset($args['raw'])) { if (W3Status_RawOk()) { $doRaw = TRUE; } } if (!$doRaw) { $strVal = $parser->recursiveTagParse($strVal); } } if (isset($args['isolate'])) { $strVal = IsolateOutput($strVal); } if (isset($args['len'])) { $strVal = substr($strVal,0,$args['len']); } if (isset($args['ucase'])) { $strVal = strtoupper($strVal); } if (isset($args['lcase'])) { $strVal = strtolower($strVal); } return $strVal; } /*-----

 TAG: <hide>
  • /

function efW3Hide( $input, $args, $parser ) { $parser->recursiveTagParse( $input ); return NULL; } /*-----

 TAG: <if>
  • /

function efW3If( $input, $args, $parser ) { global $wgW3_ifFlag,$wgW3_ifDepth;

$doHide = isset($args['hide']); // only output <echo> sections

$ifFlag = false; if (!$wgW3_ifDepth) { $wgW3_ifDepth = 0; } if (isset($args['flag'])) { $strName = $args['flag']; $strVal = W3GetVal($strName); if (is_null($strVal) || ($strVal == )) { $ifFlag = FALSE; $dbgType = 'blank'; } else if (is_numeric($strVal)) { $ifFlag = ($strVal != 0); $dbgType = 'numeric'; } else { $ifFlag = TRUE; $dbgType = ; }

$strTrace = ; if ($wgW3_ifDepth != 0) { $strTrace .= '.'.$wgW3_ifDepth; } $strTrace .= ' flag='.$strName; $strTrace .= ' val='.'['.$strVal.']';

W3AddTrace('IF'.$strTrace.' != 0: ['.TrueFalse($ifFlag).']:'.$dbgType); } elseif (isset($args['comp'])) { // We need to be able to pass either constants or variables via these parameters, so use GetExpr not GetVal $strName = $args['comp']; $strVal1 = W3GetExpr($strName);

$strTrace = ; if ($wgW3_ifDepth != 0) { $strTrace .= '.'.$wgW3_ifDepth; }

$strTrace .= ' ('.$strName.'="'.$strVal1.'")'; $strName = $args['with']; $strVal2 = W3GetExpr($strName); $strTrace .= ' ('.$strName.'="'.$strVal2.'")'; if (isset($args['pre'])) { $wgW3_ifDepth++; $strVal1 = $parser->recursiveTagParse($strVal1); $strVal2 = $parser->recursiveTagParse($strVal2); $wgW3_ifDepth--; // $strVal1 = $parser->replaceVariables($strVal1); // $strVal2 = $parser->replaceVariables($strVal2);

} $ifFlag = ($strVal1 == $strVal2); W3AddTrace('IF'.$strTrace.':'.TrueFalse($ifFlag)); } if (isset($args['not'])) { $ifFlag = !$ifFlag; // invert the flag } $wgW3_ifFlag[$wgW3_ifDepth] = $ifFlag; if ($ifFlag) { $wgW3_ifDepth++; $out = $parser->recursiveTagParse($input); $wgW3_ifDepth--; } else { $out = NULL; }

if ($doHide) { $out = W3GetEcho(); return $out; } else { return $out; } } /*-----

 TAG: <let>
  • /

function efW3Let( $input, $args, $parser ) {

       global $wgRequest;

global $wgW3Vars,$wgW3_func;

$strCopy = NULL; $objArgs = new W3HookArgs($args); $strNameRaw = $objArgs->GetVal('name');

// trim whitespace and normalize name: $strName = trim($strNameRaw); $objVar = new clsW3VarName(); $objVar->ParseName($strName); // resolve any indirection (e.g. $var)

if (isset($args['index'])) { $strIdx = W3GetExpr($args['index']); $objVar->SetIndex($strIdx); } $strName = $objVar->Name; W3AddTrace('LET name=['.$strNameRaw.'] parsed to ['.$strName.']');

if (isset($args['null'])) { // if "null" option, then nothing else matters $objVar->Value = NULL; } else { // "copy" option works for any data type: if ($objVar->CheckCopy($objArgs)) { // do nothing; work already done } else { if (is_null($input) or isset($args['self'])) { $objVar->Fetch(); W3AddTrace(' - from self: ['.$objVar->Value.']'); } else { $objVar->Value = $input; W3AddTrace(' - from input: ['.$objVar->Value.']'); } } if ($objVar->IsArray()) { W3Let_array ( $objVar, $objArgs, $input, $parser ); } else { W3Let_scalar ( $objVar, $objArgs, $input, $parser ); } } if (isset($args['parse'])) { // 2011-07-22 not tested yet $objVar->Value = $parser->recursiveTagParse($objVar->Value); } if (isset($args['tag'])) { // surround result with <> to make it into an HTML tag $objVar->Value = '<'.$objVar->Value.'>'; } $objVar->Store();

// (option) store the results: if (isset($args['save'])) { // is there some better way to access mOutput? $parser->mOutput->setProperty($strName,$objVar->Value ); }

// (option) print the results: if (isset($args['echo'])) { if (isset($args['oparse'])) { return $parser->recursiveTagParse($objVar->Value); } else { return $objVar->Value; } } else { return NULL; } /**/ } /*-----

 TAG: <load>
 NOTE: Some pages apparently don't create the parser object; if this code needs to run on one of those pages,

then this may need to create $wgParser if it doesn't exist. For now, we assume optimistically.

  TO DO:

Make parsing optional for protected pages

  • /

function efW3Load( $input, $args, $parser ) { global $wgTitle, $wgOut; global $w3stop;

if ($w3stop) { return; }

$strTitle = $args['page']; W3AddTrace('LOAD: page={'.$strTitle.'}'); $strTitle = W3GetExpr($strTitle); $doEcho = isset($args['echo']);

W3AddTrace('LOAD -> {'.$strTitle.'}');


$objTitle = Title::newFromText($strTitle); if (is_object($objTitle)) { if (stripos($strTitle, 'special:')===0) { /* title is Specialpage; you'd think there would be a general page-loading method which handles these, but I haven't been able to find it. */ W3AddTrace('LOAD SpecialPage ID='.$objTitle->getArticleID()); //$txtContent = SpecialPage::capturePath($objTitle);


$wgTitleOld = $wgTitle; $wgOutOld = $wgOut; $wgOut = new OutputPage;

$ret = SpecialPage::executePath( $objTitle, FALSE ); if ( $ret === true ) { $ret = $wgOut->getHTML(); } $wgTitle = $wgTitleOld; $wgOut = $wgOutOld;

//SpecialPage::executePath( $objTitle, false ); $txtContent = $ret; if ($txtContent === FALSE) { W3AddTrace('LOAD: Content not loadable'); } else { W3AddTrace('LOAD: Content has '.strlen($txtContent).' bytes'); } } else { W3AddTrace('LOAD Title ID='.$objTitle->getArticleID()); $objArticle = new Article($objTitle); $txtContent = $objArticle->getContent(); W3AddTrace('LOAD: page (Title ID='.$objTitle->getArticleID().') has '.strlen($txtContent).' bytes, starting with: '.substr($txtContent,0,40)); } $txtContent .= $input; // any additional input to be parsed in page's context

// eventually we will have a way to retrieve the contents via a variable // until then, the "raw" option is just for debugging if (isset($args['raw'])) { $out = $txtContent; } else { if (isset($args['local'])) { // parse title in its own context, not in the parent page's context W3AddTrace(' - LOAD as LOCAL');

// temporarily replace $wgTitle with the page we're parsing $objTitleOuter = $wgTitle; $wgTitle = $objTitle; $out = $parser->recursiveTagParse($txtContent); $wgTitle = $objTitleOuter; // restore $wgTitle's original value

} else { $out = $parser->recursiveTagParse($txtContent); } if (isset($args['nocat'])) { // clear out any categories added by parsing of loaded text $parser->mOutput->mCategories = array(); //$parser->mOutput->setCategoryLinks(NULL); } } } else { $out = 'Title ['.ShowHTML($strTitle).'] does not exist.'; // change this to a proper system message at some point } if (isset($args['let'])) { $strName = $args['let']; W3SetVar($strName, $out); } W3AddTrace('LOAD END'); if ($doEcho) { return $out; } else { return NULL; } } /*-----

 TAG: <save>
  • /

function efW3Save( $input, $args, $parser ) { global $wgW3_edit_queue,$w3stop;

if ($w3stop) { return; }

$strTitle = $args['page']; W3AddTrace('SAVE: page={'.$strTitle.'}'); $strTitle = W3GetExpr($strTitle); W3AddTrace('SAVE -> {'.$strTitle.'}');

$txtSummary = NULL; $intFlags = EDIT_DEFER_UPDATES; // does this prevent the parser from getting confused? if (isset($args['text'])) { $txtContent = W3GetExpr($args['text']); } else { $txtContent = ; } if (isset($args['insert'])) { $txtContent = W3GetExpr($args['insert']).$txtContent; } if (isset($args['append'])) { $txtContent .= W3GetExpr($args['append']); } if (isset($args['comment'])) { $txtSummary = $args['comment']; } else { $intFlags = $intFlags | EDIT_AUTOSUMMARY; } if (isset($args['minor'])) { $intFlags = $intFlags | EDIT_MINOR; }

$objTitle = Title::newFromText($strTitle); $ok = FALSE; $strStatus = 'fail - no article ['.$strTitle.']'; if (is_object($objTitle)) { $objArticle = new Article($objTitle); if (is_object($objArticle)) { $wgW3_edit_queue[] = new w3ArticleEdit($objArticle,$txtContent,$txtSummary,$intFlags); $ok = TRUE; $strStatus = 'ok'; } else { $ok = FALSE; $strStatus = 'fail - could not load ['.$strTitle.']'; } /* $objArticle = new Article($objTitle); $ok = $objArticle->doEdit( $txtContent, $txtSummary, $intFlags ); $strStatus = $ok?'ok':'fail - no save';

  • /

} if (isset($args['ok'])) { $strName = $args['ok']; W3SetVar($strName, $ok); } if (isset($args['status'])) { $strName = $args['status']; W3SetVar($strName, $strStatus); } } /*-----

 TAG: <w3tpl>
 TO DO: inline code parsing/processing
  • /

function efW3TPLRender( $input, $args, $parser ) { global $wgRestrictDisplayTitle; global $w3step,$w3stop;

$objArgs = new W3HookArgs($args);

$out = NULL;

if ($objArgs->Exists('nocache')) { $parser->disableCache(); } if ($objArgs->Exists('quit')) { $w3stop = TRUE; } if ($objArgs->Exists('title')) { $wgRestrictDisplayTitle = FALSE; $strTitle = $objArgs->GetExpr('title'); // only one of the following lines works, depending on whether we are previewing or viewing normally $parser->getOutput()->setDisplayTitle($strTitle); // changes the page header title (display mode) $parser->getOutput()->setTitleText($strTitle); // changes the HTML <title> text (preview mode) } if ($objArgs->Exists('step')) { $w3step = true; // show each line of code before it is executed } if ($input != ) { $out .= $input;

if (isset($args['pre'])) { $out = $parser->recursiveTagParse( $out ); } if (!isset($args['notpl'])) { $out = ActualRender($out,$args); } if (isset($args['post'])) { $out = $parser->recursiveTagParse( $out ); } } return $out; } /*-----

 TAG: <xploop>
 NOTE: I *think* this tag is deprecated, in favor of <for> with the appropriate option. It may be discontinued at some point.
  • /

function efW3Xploop( $input, $args, $parser ) { global $wgW3Vars;

$objArgs = new W3HookArgs($args);

$strListRaw = $objArgs->GetVal('list'); $strList = W3GetExpr($strListRaw); $strTok = $objArgs->GetVal('repl'); $doEcho = isset($args['echo']);

if (isset($args['var'])) { $strVar = strtolower($args['var']); } else { $strVar = NULL; } $sepStr = $objArgs->GetVal('sep');

if ($strTok) { // doing a straight token replacement $strTrace = 'XPLOOP replace ('.ShowHTML($strTok).') ← “'.ShowHTML($strList).'”'; } else { // setting variable value $strTrace = 'XPLOOP set ('.ShowHTML($strVar).') ← “'.ShowHTML($strList).'”'; } if ($strList != $strListRaw) { $strTrace .= '←“'.$strListRaw.'”'; } W3AddTrace($strTrace); if (isset($args['parselist'])) { $strList = $parser->recursiveTagParse( $strList ); }

$tok = substr ( $strList, 0, 1); // token for splitting if ($tok) { $tks = substr ( $strList, 1 ); // tokenized string $list = explode ( $tok, $tks ); // split the string $out = ; } else { return NULL; } if ($strTok) { // doing a straight token replacement foreach ($list as $value) { if ($out) { $out .= $sepStr; } $out .= str_replace( $strTok, $value, $input ); } $out = CharacterEscapes::charUnesc( $out, array(), $parser ); $out = $parser->recursiveTagParse( $out ); } else { foreach ($list as $value) { if ($out) { $out .= $sepStr; } $wgW3Vars[$strVar] = $value; W3AddTrace(' - XP: ['.$strVar.'] <- ['.$value.']'); $out .= $parser->recursiveTagParse( $input ); } } if ($doEcho) { return $out ; } else { $out = W3GetEcho(); return $out; } } //**********

class w3ArticleEdit { private $vArticle; private $vContent; private $vSummary; private $vFlags;

public function __construct($iArticle, $iContent, $iSummary, $iFlags) { $this->vArticle = $iArticle; $this->vContent = $iContent; $this->vSummary = $iSummary; $this->vFlags = $iFlags; }

public function Exec() { $ok = $this->vArticle->doEdit( $this->vContent, $this->vSummary, $this->vFlags ); $strStatus = $ok?'ok':'fail - no save'; return $ok; } }

/*

Each of these classes is initialized by passing it the remaining text
They each parse that text into an array of objects, and return any remaining text for the caller to finish parsing.
  • /

abstract class clsW3Code { private $vText;

public function __construct($iText) { $this->vText = $iText; } public function Dump() { return $vText; } } abstract class clsW3Code_sub extends clsW3Code { // Code with ending delimiter, after which remaining text must be parsed by caller private $vCloser; public $strRemain;

public function __construct($iText,$iCloser=) { $this->vText = $iText; $this->vCloser = $iCloser; } } class clsW3Code_body extends clsW3Code { private $vLines;

public function parse() { $strToParse = $this->vText;

$objChunk = NULL; while ($strToParse != ) { $objLine = new clsW3Code_line($strToParse); $strToParse = $objLine->strRemain; $this->vLines[] = $objLine; } } public function Dump() {

$out = '

    '; foreach ($this->vLines as $line) { $out .= '
  • '.$line->Dump(); } $out .= '

';

return $out; } } class clsW3Code_line extends clsW3Code_sub { private $vTokens;

public function parse() { $strToParse = $this->vText; $isDone = FALSE; $objChunk = NULL; for ($i = 0; ($ch=substr($strToParse,$i,1)) && !$isDone; $i++) { $doAdd = TRUE; // TRUE = add this character to the token buffer $isTok = FALSE; // TRUE = a token has been completed; save it and clear buffer switch ($ch) { // whitespace case ' ': // space case "\t": // tab $isTok = TRUE; $doAdd = FALSE; // don't include unquoted whitespace break; case '"': $isTok = TRUE; $doAdd = FALSE; // don't include paren in token $objChunk = new clsW3_qstring(substr($input,$i+1)); $strToParse = $objChunk->strRemain; break; case '(': $isTok = TRUE; // start new token $doAdd = FALSE; // don't include paren in token $objChunk = new clsW3Code_line(substr($input,$i+1),')'); $strToParse = $objChunk->strRemain; break; case '{': $isTok = TRUE; // start new token $doAdd = FALSE; // don't include braces in token $objChunk = new clsW3Code_body(substr($input,$i+1),'}'); $strToParse = $objChunk->strRemain; break; case ';': $isTok = TRUE; // start new token $doAdd = FALSE; // don't include braces in token $isDone = TRUE; break; case "\n": $doAdd = false; // don't include linebreaks in $clause break; default: $isDone = ($ch == $this->vCloser); } if ($doAdd) { $token .= $ch; } if ($isTok) { // TRUE = a token has been completed; save it and clear buffer if ($token) { $objTok = new clsW3_token($token); $this->vTokens[] = $objTok; } $token = NULL; } if (is_object($objChunk)) { $this->vTokens[] = $objChunk; $objChunk = NULL; } } $this->strRemain = substr($strToParse,$i+1); } } class clsW3_token extends clsW3Code {

} class clsW3_phrase extends clsW3Code { private $vList;

} /* class clsW3Token_rawexp extends clsW3Token { public __construct($iText) { } }

  • /

class clsW3_qstring extends clsW3Code { public function parse() { $isDone = FALSE; for ($i = 0; ($ch=substr($input,$i,1)) && !$isDone; $i++) { switch ($ch) { case '\\': $inEsc = true; break; case '"': $isDone = !$inEsc; } } } }


function ActualRender($input) { // break the code up into separate commands if ($doLine) { // TRUE = line is complete //W3AddTrace('TPL: LINE=['.$strDbgLine.']'); $out .= $cmdObj->execute($lines); } // final semicolon not required: if ($line) { $out .= $cmdObj->execute($line,$clause); } return $out; }

/*

TOKEN TYPES - for future use:

() phrase {} brace phrase non-quoted expression quoted string

  • /

class clsW3ParsedLine { private $tokens;

public function __construct($iTokens) { $this->tokens = $iTokens; } } class clsW3ParsedChunk { private $lines; // array of clsW3ParsedLines

public function __construct($iLines) { $this->lines = $iLines; } }

class clsW3Command { private $statemt; private $clause;

public function clsW3Command($iStatemt=, $iClause=) { $this->init($iStatemt, $iClause); } public function init($iStatemt, $iClause) { $this->statemt = trim($iStatemt); $this->clause = $iClause; } public function execute($iStatemt, $iClause) { // init + exec $this->init($iStatemt, $iClause); return $this->exec(); } public function exec() { global $w3step;

$strStmt = $this->statemt; if ($w3step) { $out = '
CMD: {'.$strStmt.'} CLAUSE: {'.$this->clause.'}'; } /* A command is in any of these forms: variable action-operator expression; expression; keyword (expression) {clause} [keyword (expression) {clause} ... ]; An expression is in any of these forms: function(expression[, expression[, ...]]) variable compare-operator expression variable constant A constant is either a quoted string or a number A variable is invoked by name


  • /

// parse the command: for ($i = 0; $ch=substr($strStmt,$i,1); $i++) { $isArgs = FALSE; if ($isTok) { //if (!$inQuo) { if ($cmd == ) { $cmd = $phrase; $phrase = ; } } elseif ($isArgs) { $args = $phrase; $phrase = ; } else { $phrase .= $ch; } } W3AddTrace('TPL layer 2: CMD=['.$cmd.'] ARGS=['.$args.'] leftover=['.$phrase.']'); // return $out; } } // TO DO: Change name to ShowMarkup, because it handles HTML, wikitext, and partly-parsed wikitext function ShowHTML($iText, $iRepNewLine=TRUE) {

/*/ // DEBUGGING - explode string by inserting space between each character: $cpLen = strlen($iText); $out2 = ; for ($i = 0; $i <= $cpLen; $i++) { $out2 .= substr($iText,$i,1).' '; } $out = $out2; /**/ // $out = 'LENGTH='.strlen($iText);

$out = $iText; $out = str_replace ( '<','<',$out ); $out = str_replace ( '>','>',$out); $out = str_replace ( '[','[',$out ); $out = str_replace ( ']',']',$out ); $out = str_replace ( chr(7),'^G',$out); $out = str_replace ( chr(127),'del',$out); if ($iRepNewLine) { $out = str_replace ( chr(10),'^J',$out); $out = str_replace ( chr(13),'^M',$out); } return $out; }

class clsStringTemplate_w3tpl extends clsStringTemplate { // This version can be used if the values are in an associative array protected function GetValue($iName) { return W3GetVal($iName); } }

/* class w3expr { private $text; abstract function Parse($iTask); } */

class clsW3Function { var $vParser; var $isOkRaw, $isOkSQL; var $Name, $vParams, $vCode; var $vArgs, $vArgIdx;

public function __construct($iParser, $iName, $iParams, $iCode) { $this->vParser = $iParser; $this->Name = $iName; $this->vParams = $iParams; $this->vCode = $iCode; $this->isOkRaw = W3Status_RawOk(); $this->isOkSQL = W3Status_SQLOk(); } public function dump() { $out = ''.$this->Name.'('; if (is_array($this->vParams)) { $pcnt = 0; foreach ($this->vParams as $name => $value) { if ($pcnt) { $out .= ', '; } $out .= ''.$name.''; if (isset($value)) { $out .= '='.$value; } $pcnt++; } } $out .= ') {'; $strCode = ShowHTML($this->vCode,FALSE);

$out .= '

'.$strCode.'

}';

return $out; } public function ResetArgs() { $this->vArgIdx = 0; unset($this->vArgs); } public function LoadArg($iValue,$iName=) { if ($iName) { $strName = strtolower($iName); } else { $strName = $this->ParamName($this->vArgIdx); $this->vArgIdx++; } $this->vArgs[$strName] = $iValue; return '['.$strName.']=“'.$iValue.'”'; } public function HasArg($iName) { return isset($this->vArgs[$iName]); } public function ArgVal($iName) { return $this->vArgs[$iName]; } public function ParamName($iIndex) { $keys = array_keys($this->vParams); $key = $keys[$iIndex]; return $key; } public function execute() { // set variables from passed arguments

$useArgs = FALSE; if (isset($this->vArgs)) { if (is_array($this->vArgs)) { $useArgs = TRUE; } } if ($useArgs) { foreach ($this->vArgs as $name => $value) { if (W3VarExists($name)) { $oldVars[$name] = W3GetVal($name); } W3SetVar($name, $value); } } // parse (execute) the function code $out = $this->vParser->recursiveTagParse( $this->vCode ); // restore original variables (old value if any, or remove from list) if ($useArgs) { foreach ($this->vArgs as $name => $value) { if (isset($oldVars[$name])) { W3SetVar($name, $oldVars[$name]); } else { W3KillVar($name); } } } return $out; } }

class clsW3VarName { /*

  • An *expression* can be:
    • a literal value - "this is a string"
    • a reference to a variable - "$theVar"
    • a reference to a special function - @row.fieldname
  • A variable reference can be:
    • scalar value - "$aScalar"
    • array index - "$anArray[index_expression]" where "index_expression" is an expression

We automatically find the value of all inner elements as needed, but leave the outermost unresolved in order to allow for different operations depending on context.

  • /

public $Expr; // code-expression to parse public $Name; // final name of variable or function being referenced public $Index; // (optional) index into variable array public $Value; // loaded value of variable or function, for operations public $isFunc;

public function __construct($iExpr = NULL) { $this->isFunc = FALSE; W3AddTrace('clsW3VarName: init=['.$iExpr.']'); if (!is_null($iExpr)) { $this->ParseExpr($iExpr); } }

public function ParseExpr($iExpr) { global $wgW3_doTrace_vars; global $wgW3Trace_indent;

$wgW3Trace_indent++; $strExpr = $iExpr; if ($wgW3_doTrace_vars) { W3AddTrace(' {PARSE-EXPR ['.ShowHTML($iExpr).']'); } $chFirst = substr($strExpr,0,1); switch ($chFirst) { case '$': $strRef = strtolower(substr($strExpr,1)); $this->ParseName($strRef); break; case '@': $strRef = strtolower(substr($strExpr,1)); $this->ParseName($strRef); $this->isFunc = TRUE; break; default: // it's a literal, so the string is the value $this->Value = $strExpr; } if ($wgW3_doTrace_vars) { W3AddTrace(' => ['.ShowHTML($strExpr).'] EXPR}'); } $wgW3Trace_indent--; return $strExpr; }

public function ParseName($iName) { global $wgW3_doTrace_vars; global $wgW3Trace_indent; $strName = $iName; $wgW3Trace_indent++; if ($wgW3_doTrace_vars) { W3AddTrace('{PARSE-NAME ['.ShowHTML($iName).']'); }

if (substr($strName,0,1) == '@') { $this->isFunc = TRUE; $this->Name = substr($strName,1); W3AddTrace(' - is func ['.$this->Name.']'); } else { if (substr($strName, -1) == ']') { // name includes index offset $idxOpen = strpos($strName,'['); if ($idxOpen) { $idxShut = strpos($strName,']',$idxOpen); $vIndex = substr($strName,$idxOpen+1,$idxShut-$idxOpen-1); $strTrace = 'INDEX['.$vIndex.'] (@'.$idxOpen.'-'.$idxShut.' in ['.$strName.']) -> ['; $strTrace .= $vIndex.']'; $objIdx = new clsW3VarName($vIndex); $strName = substr($strName,0,$idxOpen); $objIdx->Fetch(); // calculate value of index expression $this->Index = $objIdx->Value; $strTrace .= ' NEW NAME=['.$strName.']'; W3AddTrace($strTrace); } } $objVar = new clsW3VarName($strName); $objVar->Fetch(); $this->Name = $objVar->Value; } if ($wgW3_doTrace_vars) { W3AddTrace('name:['.ShowHTML($this->Name).'] = val:['.ShowHTML($this->Value).'] NAME}'); } $wgW3Trace_indent--; /**/ }

public function SetIndex($iValue) { $this->Index = $iValue; W3AddTrace('clsW3VarName.SetIndex of ('.$this->Name.') to ['.$iValue.']'); } public function IsElem() { // is element of an array? return !is_null($this->Index); } public function IsVar() { return !is_null($this->Name) && !$this->isFunc; } public function IsArray() { return is_array($this->Value); } public function Fetch() { global $wgW3Vars;

$strName = strtolower($this->Name); if ($this->isFunc) { $this->Value = W3GetSysData($this->Name); } elseif ($this->IsVar()) { if ($this->IsElem()) { $strIndex = $this->Index; if (isset($wgW3Vars[$strName][$strIndex])) { $this->Value = $wgW3Vars[$strName][$strIndex]; W3AddTrace('clsW3VarName.Fetch ('.$strName.')['.$strIndex.']=>“'.$this->Value.'”'); } else { $this->Value = NULL; W3AddTrace('clsW3VarName.Fetch ('.$strName.')['.$strIndex.']=>NULL'); } } else { if (isset($wgW3Vars[$strName])) { $this->Value = $wgW3Vars[$strName]; W3AddTrace('clsW3VarName.Fetch ('.$strName.')=>“'.$this->Value.'”'); } else { $this->Value = NULL; W3AddTrace('clsW3VarName.Fetch ('.$strName.')=>NULL'); } } } else { // literal value - already set. } W3AddTrace('clsW3VarName.Fetch: value=['.$this->Value.']'); $this->Trace(); }

public function Store() { global $wgW3Vars;

$strName = $this->Name; $strVal = $this->Value; if ($this->isFunc) { W3SetSysData($strName,$strVal); } elseif ($strName) { $strName = strtolower($strName); if ($this->isElem()) { $strIndex = $this->Index; $wgW3Vars[$strName][$strIndex] = $strVal; W3AddTrace('clsW3VarName.Store: '.$strName.'['.$strIndex.'] ← “'.$strVal.'”'); } else { $wgW3Vars[$strName] = $strVal; W3AddTrace('clsW3VarName.Store: ['.$strName.'] ← “'.$strVal.'”'); } $this->Trace(); } else { W3AddTrace('clsW3VarName.Store: ERROR: no name for value “'.$strVal.'”'); $this->Trace(); } }

public function DoSort($iRev=FALSE, $iVal=FALSE) { if (is_array($this->Value)) { if ($iVal) { // sort by value if ($iRev) { $ok = arsort($this->Value); } else { $ok = asort($this->Value); } } else { if ($iRev) { $ok = arsort($this->Value); } else { $ok = ksort($this->Value); } } if ($ok) { W3AddTrace('LET sort ['.$this->Name.'] OK'); } else { W3AddTrace('LET sort ['.$this->Name.'] ERROR: failed.'); } } else { W3AddTrace('LET sort ERROR: ['.$this->Name.'] is not an array.'); } }

public function CheckCopy($iArgs) { if ($iArgs->Exists('copy')) { $strSrce = $iArgs->GetVal('copy'); $this->Value = W3GetVal($strSrce); W3AddTrace('CheckCopy from ['.$strSrce.']'); // show raw input $this->Trace(); // show result return TRUE; } else { return FALSE; } }

public function Trace() { if (is_array($this->Value)) { $strVal = 'array!'; } else { $strVal = $this->Value; }

W3AddTrace('clsW3VarName.Trace: '. 'Name=['.$this->Name.'] '. 'Val=['.$strVal.'] '. 'Index=['.$this->Index.'] '. TrueFalseHTML('is var',$this->IsVar()).' '. TrueFalseHTML('is element',$this->IsElem()).' '. TrueFalseHTML('is func',$this->isFunc) ); } }

function TrueFalseHTML($iName, $iVal) { if ($iVal) { return ''.$iName.''; } else { return ''.$iName.''; } }

class W3HookArgs { var $vArgs;

public function __construct($iArgs) { $this->vArgs = $iArgs; } public function Exists($iName) { return isset($this->vArgs[$iName]); } public function GetVal($iName) { if (isset($this->vArgs[$iName])) { return $this->vArgs[$iName]; } else { return NULL; } } public function GetExpr($iName, $iTrace = FALSE) { if (isset($this->vArgs[$iName])) { $strArg = $this->vArgs[$iName]; $strOut = W3GetExpr($strArg); if ($iTrace) { W3AddTrace(' - '.strtoupper($iName).'=['.$strArg.'] -> ['.$strOut.']'); } return $strOut; } else { return NULL; } } }

/* class W3TPL_fx { function runXploop ( &$parser, $inStr = , $inTplt = '$s$', $inSep = ) { $tok = substr ( $inStr, 0, 1); // token for splitting if ($tok) { $tks = substr ( $inStr, 1 ); // tokenized string $list = explode ( $tok, $tks ); // split the string $sep = CharacterEscapes::charUnesc( $inSep, array(), $parser ); $tplt = CharacterEscapes::charUnesc( $inTplt, array(), $parser ); $out = ; foreach ($list as $value) { // $lcnt++; if ($out) { $out .= $sep; } $out .= str_replace( '$s$', $value, $tplt ); } return $parser->recursiveTagParse($out); // return array($out, 'noparse' => false, 'isHTML' => false); } else { return NULL; } } function runXpCount ( &$parser, $inStr = ) { $tok = substr ( $inStr, 0, 1); return substr_count($inStr, $tok); } function runLet ( &$parser, $iName = , $iVal = ) { global $wgW3Vars;

$strName = strtolower($iName); $strName = W3GetVal($strName); // check for indirection ($) $wgW3Vars[$strName] .= $iVal; } function runGet ( &$parser, $iName = ) { $strName = strtolower($iName); $strVal = W3GetVal('$'.$strName); return $parser->recursiveTagParse($strVal); } }

  • /

/*

Code for preventing raw "isolated" output from being further processed by the parser output stage
See http://www.mediawiki.org/wiki/Manual:Tag_extensions#How_can_I_avoid_modification_of_my_extension.27s_HTML_output.3F
  • /

$wgW3_Markers = array(); define('ksW3_parser_marker_start','@@W3TPL##--'); define('ksW3_parser_marker_stop','--##LPT3W@@'); function IsolateOutput($iText) { global $wgW3_Markers;

$markCount = count($wgW3_Markers); $mark = ksW3_parser_marker_start.$markCount.ksW3_parser_marker_stop; $wgW3_Markers[$markCount] = $iText; return $mark; }

function efW3_ParserAfterTidy(&$parser, &$text) { // find markers in $text // replace markers with actual output global $wgW3_Markers;

// replace markers with isolated text: $k = array(); for ($i = 0; $i < count($wgW3_Markers); $i++) $k[] = ksW3_parser_marker_start . $i . ksW3_parser_marker_stop; $text = str_replace($k, $wgW3_Markers, $text);

return true; } function efW3_OutputPageBeforeHTML(&$out, &$text) { global $wgW3_edit_queue; // execute deferred edits:

if (is_array($wgW3_edit_queue)) { foreach ($wgW3_edit_queue as $key=>$obj) { $obj->Exec(); } } return TRUE; }</php>

SQL

These tables are only needed for class/object functionality; if absent, nothing else is affected. For now, they should be in the same database as the wiki. (Later, it may turn out to be useful to allow them to be in an external database, to allow multiple wikis to share code and data.)

The code to use these tables is still under development. --Woozle 00:33, 26 July 2010 (UTC) <mysql>CREATE TABLE `w3_class` (

  `ID` INT  NOT NULL AUTO_INCREMENT,
  `Name`     VARCHAR(63) COMMENT 'name of class',
  PRIMARY KEY(`ID`)
)
ENGINE = MYISAM;</mysql>

<mysql>CREATE TABLE `w3_method` (

  `ID_class` INT          NOT NULL AUTO_INCREMENT COMMENT "ID of w3_class to which this field belongs",
  `Name`     VARCHAR(63)  NOT NULL                COMMENT "name of method",
  `Code`     VARCHAR(255) NOT NULL                COMMENT "method's code",
  PRIMARY KEY(`ID`)
)
ENGINE = MYISAM;</mysql>

<mysql>CREATE TABLE `w3_object` (

  `ID`       INT NOT NULL AUTO_INCREMENT,
  `ID_class` INT NOT NULL COMMENT "ID of w3_class for this object"
  `Name`     VARCHAR(63)  COMMENT 'name of object',
  PRIMARY KEY(`ID`)
)
ENGINE = MYISAM;</mysql>

<mysql>CREATE TABLE `w3_field` (

  `ID_object` INT         NOT NULL AUTO_INCREMENT COMMENT "ID of w3_object to which this field belongs",
  `Name`     VARCHAR(63)  NOT NULL                COMMENT "name of field",
  `Value`    VARCHAR(255) NOT NULL                COMMENT "value of field",
  PRIMARY KEY(`ID`)
)
ENGINE = MYISAM;</mysql>