2 //==============================================================================
4 // Description: Use parsing classes to generate a documentation skeleton
6 // Author: johanp@aditus.nu
7 // Version: $Id: jpgendb.php,v 1.18 2002/08/29 10:12:43 aditus Exp $
10 // Copyright (C) 2002 Johan Persson
12 //==============================================================================
13 include_once("jplintphp.php");
14 include_once("jpdb.php");
15 include_once("de_utils.php");
18 var $iDisplayLog=false;
21 function ToScreen($aStr,$aLineBreak=true) {
22 if( $this->iDisplayLog ) {
23 echo "<font color=#FF0000>";
34 class DBFuncProp extends FuncProp {
38 var $iMethodRef=array();
39 var $iArgsDes=array();
44 function DBFuncProp($aProjname,$aClassName,$aName,$aLineNbr,$aArgs,$aArgsVal,$aShortDesc="",$aFileName="") {
45 parent::FuncProp($aClassName,$aName,$aLineNbr,$aArgs,$aArgsVal,$aShortDesc,$aFileName);
46 $this->iProjname = $aProjname;
47 $this->iPublic = 1; // Default to public
50 function Internalize($aDBRow) {
53 function Externalize($aDB,$aClassIdx="",$aKey="") {
54 $this->iClassIdx = $aClassIdx;
55 $q = "REPLACE INTO tbl_method_".$this->iProjname." SET ";
56 $q .= "fld_key='".$aKey."',";
57 $q .= "fld_name='".$this->iName."',";
58 $q .= "fld_public=".$this->iPublic.",";
59 $q .= "fld_linenbr='".$this->iLineNbr."',";
60 $q .= "fld_file='".mysql_escape_string(basename($this->iFileName))."',";
61 $q .= "fld_shortdesc='".mysql_escape_string($this->iShortComment)."',";
62 $q .= "fld_classidx='".$aClassIdx."',";
63 $q .= "fld_classname='".$this->iClassName."',";
64 $q .= "fld_desc='".mysql_escape_string($this->iDesc)."',";
65 $q .= "fld_example='".mysql_escape_string($this->iExample)."',";
67 for( $i=1; $i<=4; ++$i ) {
69 if( !empty($this->iMethodRef[$i-1]) )
70 $mref = $this->iMethodRef[$i-1];
71 $q .= "fld_methref$i='".$mref."',";
73 $q .= "fld_numargs=".$this->iNumArgs;
74 for( $i=1; $i<=$this->iNumArgs; ++$i ) {
75 $q .= ",fld_arg$i='".$this->iArgs[$i-1]."'";
77 for( $i=1; $i<=$this->iNumArgs; ++$i ) {
78 if( empty($this->iArgsDes[$i-1]) )
81 $argdes = $this->iArgsDes[$i-1];
82 $q .= ",fld_argdes$i='".mysql_escape_string($argdes)."'";
85 for( $i=1; $i<=$this->iNumArgs; ++$i ) {
86 if( !isset($this->iArgsVal[$i-1]) )
89 $argval = $this->iArgsVal[$i-1];
90 $q .= ",fld_argval$i='".mysql_escape_string($argval)."'";
94 $this->iKey = $aDB->LastIdx();
98 function UpdateFromExisting($aOldFunc) {
100 if( $this->iName != $aOldFunc["fld_name"] )
101 die("PANIC: UpdateArguments() Function name different.".$this->iName." != ". $aOldFunc['fld_name'] );
103 $numoldargs=$aOldFunc["fld_numargs"];
104 $numnewargs=$this->iNumArgs;
106 // Get the old descriptions and references
108 $this->iDesc = empty($aOldFunc['fld_desc']) ? '' : $aOldFunc['fld_desc'];
109 $this->iShortComment = empty($aOldFunc["fld_shortdesc"]) ? '' : $aOldFunc['fld_shortdesc'];
110 $this->iExample = empty($aOldFunc['fld_example']) ? '' : $aOldFunc['fld_example'];
111 $this->iPublic = $aOldFunc['fld_public'];
113 for( $i=0; $i < 4 ; ++$i) {
114 $this->iMethodRef[$i] = @$aOldFunc["fld_methref".($i+1)];
117 // DB Optimization. If old args are the same as new then don't
118 // bother touching DB.
119 for($i=0; $i<$numoldargs; ++$i) {
123 for($i=1; $i<=$numoldargs; ++$i) {
124 $arg = $aOldFunc["fld_arg$i"];
125 for( $j=0; $j<$numnewargs; ++$j) {
126 if( $this->iArgs[$j] == $arg ) {
127 $exists[$i-1] = true;
128 $this->iArgsDes[$j] = $aOldFunc["fld_argdes$i"];
133 if( $numoldargs == $numnewargs ) {
135 for( $i=0; $i<$numoldargs; ++$i) {
140 // Check if any default value have changed
142 for( $i=1; $i<=$numoldargs && $allsame; ++$i) {
143 if( isset($this->iArgsVal[$i-1]) && $this->iArgsVal[$i-1] != $aOldFunc["fld_argval$i"] )
148 if( $allsame && ($aOldFunc["fld_linenbr"]==$this->iLineNbr) ) {
153 // Create the new set of arguments by combining the old existing
154 // one that is the same with the new one.
155 for( $i=0; $i<$numnewargs; ++$i ) {
156 $newarg = $this->iArgs[$i];
157 $this->iArgsDes[$i] = '';
158 for( $j=0; $j<$numoldargs; ++$j ) {
159 $oldarg = $aOldFunc['fld_arg'.($j+1)];
160 if( empty($aOldFunc['fld_argdes'.($j+1)]) )
163 $oldargdes = $aOldFunc['fld_argdes'.($j+1)];
164 if( $newarg==$oldarg ) {
165 $this->iArgsDes[$i] = $oldargdes;
174 class DBClassProp extends ClassProp {
181 function DBClassProp($aProjname,$aParent,$aName,$aLineNbr,$aFile) {
182 parent::ClassProp($aParent,$aName,$aLineNbr,$aFile);
183 $this->iProjname = $aProjname;
184 for($i=0; $i < 4; ++$i)
188 function Internalize($aDBRow) {
191 function Externalize($aDB) {
192 // Check if this class already exist in the DB
193 $q = "SELECT * FROM tbl_class_".$this->iProjname." WHERE ";
194 $q .= "fld_name='".$this->iName."'";
195 $res = $aDB->query($q);
196 if( $res->NumRows() > 0 ) {
197 $GLOBALS["gLogger"]->ToScreen( "Class '".$this->iName."' at line #".$this->iLineNbr." is already in database<br>" );
198 $row = $res->Fetch();
200 // Update properties in this class with the DB proeprties
204 if( !empty($row["fld_desc"]) )
205 $this->iDesc = $row["fld_desc"];
206 if( !is_null($row["fld_public"]) )
207 $this->iPublic = $row["fld_public"];
209 for( $i=1; $i<=4; ++$i ) {
210 if( !empty($row['fld_ref'.$i]) && (int)$row['fld_ref'.$i]!='-1' )
211 $this->iRef[$i-1] = $row['fld_ref'.$i];
213 $this->iRef[$i-1] = '';
216 $idx = $row['fld_key'];
218 // A sanity check of DB
219 if( is_null($row['fld_numfuncs']) ) {
220 echo "PANIC: DB Corruption. fld_numfuncs in DB is NULL for class ".$row['fld_name'].".($row[fld_numfuncs])<br>";
223 $this->ExternalizeUpdateMethods($aDB,$idx);
224 $this->ExternalizeClass($aDB,$idx);
227 $GLOBALS["gLogger"]->ToScreen( "Adding class ".$this->iName );
228 $idx=$this->ExternalizeClass($aDB);
229 $this->ExternalizeMethods($aDB,$idx);
231 $this->ExternalizeVars($aDB,$idx);
235 function ExternalizeClass($aDB,$aKey="") {
237 $q = "REPLACE INTO tbl_class_".$this->iProjname." SET ";
238 $q .= "fld_key='".$aKey."',";
239 $q .= "fld_name='".$this->iName."',";
240 $q .= "fld_public=".$this->iPublic.',';
241 $q .= "fld_ref1='".$this->iRef[0]."',";
242 $q .= "fld_ref2='".$this->iRef[1]."',";
243 $q .= "fld_ref3='".$this->iRef[2]."',";
244 $q .= "fld_ref4='".$this->iRef[3]."',";
245 $q .= "fld_parentname='".$this->iParent."',";
246 $q .= "fld_file='".mysql_escape_string(basename($this->iFileName))."',";
247 $q .= "fld_numfuncs=".$this->iFuncNbr.",";
248 $q .= "fld_desc='".mysql_escape_string($this->iDesc)."',";
249 $q .= "fld_linenbr=".$this->iLineNbr." ";
251 $this->iKey = $aDB->LastIdx();
256 function ExternalizeMethods($aDB,$aClassIdx) {
257 for( $m=0; $m<$this->iFuncNbr; ++$m) {
258 $func = $this->iFuncs[$m];
259 $func->Externalize($aDB,$aClassIdx);
263 function ExternalizeUpdateMethods($aDB,$aClassIdx) {
264 // Now get all the methods that is registred for this class
266 $q = "SELECT * FROM tbl_method_".$this->iProjname." WHERE fld_classidx=$aClassIdx";
267 $methres = $aDB->query($q);
268 $nbrmeth = $methres->NumRows();
271 // Read all existing methods into 'oldfuncs'
273 for($i=0; $i<$nbrmeth; ++$i) {
274 $oldfuncs[$i]=$methres->Fetch();
277 $nold = count($oldfuncs);
279 // Sanity check of Database
280 for($i=0; $i<$nold; ++$i ) {
281 for($j=$i+1; $j<$nold; ++$j ) {
282 if( $oldfuncs[$i]['fld_name'] == $oldfuncs[$j]['fld_name'] ) {
283 echo "PANIC: Corruption in database. Function ".$oldfuncs[$j]['fld_name']." is double defined for classidx $aClassIdx<p>";
289 // Walk through all the existing methods
290 for($i=0; $i<$this->iFuncNbr ; ++$i) {
292 $func = $this->iFuncs[$i];
294 // This unfortunately have to be an O(n^2) mathching ...
295 for($j=0; ($j < $nold) && !$found ; ++$j) {
296 if( $oldfuncs[$j]["fld_name"] == $func->iName ) {
299 $oldfunc = $oldfuncs[$j];
303 $GLOBALS["gLogger"]->ToScreen( "Checking if method :$func->iName exists..." );
306 $GLOBALS["gLogger"]->ToScreen( " no. Adding it to DB." );
307 $func->Externalize($aDB,$aClassIdx);
310 $GLOBALS["gLogger"]->ToScreen( " yes." );
312 // Now update the newly parsed method with any exsiting descriptions
314 $changed = $func->UpdateFromExisting($oldfunc);
316 $func->Externalize($aDB,$aClassIdx,$oldfunc["fld_key"]);
320 // Delete no longer existing methods
321 for( $i=0; $i<$nold; ++$i ) {
323 $GLOBALS["gLogger"]->ToScreen( "Deleting method ".$this->iName."::".$oldfuncs[$i]["fld_name"]."()" );
324 $q = "DELETE FROM tbl_method_".$this->iProjname." WHERE fld_key=".$oldfuncs[$i]["fld_key"];
325 $res = $aDB->query($q);
326 if( $res->iRes==1 ) {
327 $q = "UPDATE tbl_class_".$this->iProjname." SET fld_numfuncs=fld_numfuncs-1 WHERE fld_key=$aClassIdx";
331 echo "PANIC: DB Corruption. Can't delete function ".$oldfuncs[$i]["fld_name"]."<br>$q<p>\n";
338 // No existing methods in the DB so just store the new ones
339 $this->ExternalizeMethods($aDB,$aClassIdx);
343 function ExternalizeVars($aDB,$aClassIdx) {
344 // We just delete all exiting variables for this class and then
345 // add the new ones. This could be DB optimized to only
346 // delete variables that doesn't exist any more and just adding
347 // the new one but this is simpler!
348 $q = "DELETE FROM tbl_classvars_".$this->iProjname." WHERE fld_classidx=".$aClassIdx;
349 $res = $aDB->query($q);
351 for( $i=0; $i < $this->iVarNbr; ++$i ) {
352 $q = "INSERT INTO tbl_classvars_".$this->iProjname." SET fld_key='',";
353 $q .= "fld_name='".mysql_escape_string($this->iVars[$i][0])."',";
354 $q .= "fld_default='".mysql_escape_string($this->iVars[$i][1])."',";
355 $q .= "fld_classidx=".$aClassIdx;
361 class DBParser extends Parser {
364 var $iClassIdx=array();
366 var $iPrettyPrint=false;
368 function DBParser($aProjname,$aFile,$aDB) {
371 $this->iProjName = $aProjname;
372 parent::Parser($aFile);
375 function PrettyPrint($aFlg) {
376 $this->iPrettyPrint = $aFlg;
379 function LineIndicatorMinor($aLineNbr) {
382 function LineIndicatorMajor($aLineNbr) {
385 function StartIndicator($aFilename) {
388 // Override Factory function for classes
389 function &NewClassProp($aParent,$aName,$aLineNbr,$aFileName) {
390 return new DBClassProp($this->iProjName,$aParent,$aName,$aLineNbr,$aFileName);
393 // Override Factory function for methods
394 function &NewFuncProp($aClassName,$aName,$aLineNbr,$aArgs,$aArgsVal,$aShortComment) {
395 return new DBFuncProp($this->iProjName,$aClassName,$aName,$aLineNbr,$aArgs,$aArgsVal,$aShortComment,$this->iCurrFileName);
398 // Map function for global functions
399 function MapGlobalFunc($aFunc) {
401 if( $this->iPrettyPrint )
402 parent::MapGlobalFunc($aFunc);
404 // Check if this function already exists
405 $q = "SELECT * FROM tbl_method_".$this->iProjName." WHERE fld_name='".$aFunc->iName."' AND fld_file='".mysql_escape_string(basename($this->iCurrFileName))."'";
406 //$q = "SELECT * FROM tbl_method_".$this->iProjName." WHERE fld_name='".$aFunc->iName."' ORDER BY fld_name";
407 $res = $this->iDB->Query($q);
410 $oldfunc = $res->Fetch();
411 $aFunc->UpdateFromExisting($oldfunc);
412 $oldidx = $oldfunc['fld_key'];
413 $aFunc->Externalize($this->iDB,0,$oldidx);
418 for( $i=0; $i<$n; ++$n ) {
419 $rows[] = $res->Fetch();
421 for( $i=0; $i<$n; ++$n ) {
422 if( $rows[$i]['fld_name'] == $this->iCurrFileName &&
423 basename($rows[$i]['fld_file']) == basename($rows[$i+1]['fld_file']) ) {
424 die('PANIC : Database corrupt. There are multiple versions of GLOBAL function : '.$aFunc->iName);
427 // Same name but in different files
432 die('PANIC : Database corrupt. There are multiple versions of GLOBAL function : '.$aFunc->iName);
436 $aFunc->Externalize($this->iDB);
439 // map function for classes
440 function MapClass($aClass) {
441 if( $this->iPrettyPrint ) {
442 $GLOBALS["gLogger"]->ToScreen( "<p>Mapping class '".$aClass->iName );
443 parent::MapClass($aClass);
445 $this->iClassIdx[$aClass->iName] = $aClass->Externalize($this->iDB);
450 class DBDriver extends LintDriver {
453 var $iPrintFile = false;
455 function DBDriver($aProjname,$aFile,$aDB) {
457 $this->iProjname = $aProjname;
458 parent::Driver($aFile);
461 function NewParser($aFile) {
462 return new DBParser($this->iProjname,$aFile,$this->iDB);
465 function PostProcessing() {
466 parent::PostProcessing();
472 class DBTestDriver extends LintDriver {
476 function DBDriver($aProjname,$aFile) {
477 $this->iDB = DBFactory::InitDB();
478 $this->iProjname = $aProjname;
479 parent::Driver($aFile);
482 function NewParser($aFile) {
483 return new DBParser($this->iProjname,$aFile,$this->iDB);
486 function PostProcessing() {
487 parent::PostProcessing();
488 $res = $this->iParser->GetUnusedClassVariables();
490 echo "<hr><h3>SUMMARY of unused instance variables</h3>$res";
491 $res = $this->iParser->GetWarnings();
493 echo "<hr><h3>SUMMARY of warnings</h3>$res";
499 //==========================================================================
500 // Script entry point for test harness
501 // Read URL argument and create Driver
502 //==========================================================================
503 //if( !isset($HTTP_GET_VARS['target']) )
504 //die("<b>No file specified.</b> Use 'mylintphp.php?target=file_name'" );
505 //$file = urldecode($HTTP_GET_VARS['target']);
506 //$driver = new DBTestDriver($file);