Subversion Repositories PHPX

Rev

Rev 14 | Rev 17 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 14 Rev 16
1
<?php
1
<?php
2
2
3
require_once 'global.inc';
3
require_once 'global.inc';
4
4
5
define('FEATURES_ENCODING',
5
define('FEATURES_ENCODING',
6
  mb_detect_encoding(file_get_contents($_SERVER['SCRIPT_FILENAME'])));
6
  mb_detect_encoding(file_get_contents($_SERVER['SCRIPT_FILENAME'])));
7
7
8
/**
8
/**
9
 * A list of language features with URNs definitions
9
 * A list of language features with URNs definitions
10
 * for reference links.
10
 * for reference links.
11
 */
11
 */
12
class FeatureList
12
class FeatureList
13
{
13
{
14
  public $versions = array();
14
  public $versions = array();
15
 
15
 
16
  /**
16
  /**
17
   * Versions of implementations that are considered safe.
17
   * Versions of implementations that are considered safe.
18
   * A feature is considered safe if it does not require
18
   * A feature is considered safe if it does not require
19
   * an implementation version above these versions.
19
   * an implementation version above these versions.
20
   *
20
   *
21
   * @var Array[string=>string]
21
   * @var Array[string=>string]
22
   */
22
   */
23
  public $safeVersions = array();
23
  public $safeVersions = array();
24
 
24
 
25
  /**
25
  /**
26
   * URNs that can be used for reference links.
26
   * URNs that can be used for reference links.
27
   *
27
   *
28
   * @var Array[string=>string]
28
   * @var Array[string=>string]
29
   */
29
   */
30
  protected $urns = array();
30
  protected $urns = array();
31
 
31
 
32
  /**
32
  /**
33
   * The list of language features
33
   * The list of language features
34
   *
34
   *
35
   * @var array[Features]
35
   * @var array[Features]
36
   */
36
   */
37
  protected $items = array();
37
  protected $items = array();
38
 
38
 
39
  /**
39
  /**
40
   * Determines the number of printed items the table headings should be repeated
40
   * Determines the number of printed items the table headings should be repeated
41
   *
41
   *
42
   * @var int
42
   * @var int
43
   */
43
   */
44
  protected $headerRepeat = 25;
44
  protected $headerRepeat = 25;
45
45
46
  /**
46
  /**
47
   * Initializes the FeatureList object
47
   * Initializes the FeatureList object
48
   *
48
   *
49
   * @param array|Object $a
49
   * @param array|Object $a
50
   * @return FeatureList
50
   * @return FeatureList
51
   */
51
   */
52
  public function __construct($a)
52
  public function __construct($a)
53
  {
53
  {
54
    $aVars = get_class_vars(get_class($this));
54
    $aVars = get_class_vars(get_class($this));
55
   
55
   
56
    while ((list($key, $value) = each($aVars)))
56
    while ((list($key, $value) = each($aVars)))
57
    {
57
    {
58
      if (isset($a[$key]))
58
      if (isset($a[$key]))
59
      {
59
      {
60
        $this->$key = $a[$key];
60
        $this->$key = $a[$key];
61
      }
61
      }
62
    }
62
    }
63
   
63
   
64
    /* Inform items of ourself so that URNs can be used for links */
64
    /* Inform items of ourself so that URNs can be used for links */
65
    if (is_array($this->items))
65
    if (is_array($this->items))
66
    {
66
    {
67
      foreach ($this->items as &$item)
67
      foreach ($this->items as &$item)
68
      {
68
      {
69
        $item->setList($this);
69
        $item->setList($this);
70
      }
70
      }
71
    }
71
    }
72
   
72
   
73
    /* resolve URN references that are URNs */
73
    /* resolve URN references that are URNs */
74
    if (is_array($this->urns))
74
    if (is_array($this->urns))
75
    {
75
    {
76
      foreach ($this->urns as &$urn)
76
      foreach ($this->urns as &$urn)
77
      {
77
      {
78
        if (($url = $this->resolveURN($urn)))
78
        if (($url = $this->resolveURN($urn)))
79
        {
79
        {
80
          $urn = $url;
80
          $urn = $url;
81
        }
81
        }
82
      }
82
      }
83
    }
83
    }
84
  }
84
  }
85
 
85
 
86
  public function printHeaders()
86
  public function printHeaders()
87
  {
87
  {
88
    foreach ($this->versions as $ver)
88
    foreach ($this->versions as $ver)
89
    {
89
    {
90
?>
90
?>
91
          <th><?php echo $ver; ?></th>
91
          <th><?php echo $ver; ?></th>
92
<?php
92
<?php
93
    }
93
    }
94
  }
94
  }
95
   
95
   
96
  /**
96
  /**
97
   * Prints the list of features.
97
   * Prints the list of features.
98
   *
98
   *
99
   * @see Feature::printMe()
99
   * @see Feature::printMe()
100
   */
100
   */
101
  public function printItems()
101
  public function printItems()
102
  {
102
  {
103
    $counter = 0;
103
    $counter = 0;
104
    $headerRepeat = $this->headerRepeat;
104
    $headerRepeat = $this->headerRepeat;
105
    $repeatHeaders = ($headerRepeat > 1);
105
    $repeatHeaders = ($headerRepeat > 1);
106
   
106
   
107
    foreach ($this->items as $feature)
107
    foreach ($this->items as $feature)
108
    {
108
    {
109
      if ($feature instanceof Feature)
109
      if ($feature instanceof Feature)
110
      {
110
      {
-
 
111
        /*
-
 
112
         * TODO: Disabled header repetition until footnote ref. name/ID
-
 
113
         * problem has been solved
-
 
114
         */
111
        if ($repeatHeaders
115
//        if ($repeatHeaders
112
            && $counter > 1
116
//            && $counter > 1
113
            && $counter % $headerRepeat === 0)
117
//            && $counter % $headerRepeat === 0)
114
        {
118
//        {
115
?>
119
//          echo <<<HTML
116
        <tr class="header">
120
//        <tr class="header">
117
          <th>Feature</th>
121
//          <th>Feature</th>
118
          <?php $this->printHeaders(); ?>
122
//          {$this->printHeaders()}
119
        </tr>
123
//        </tr>
120
<?php
124
//HTML;
121
        }
125
//        }
122
       
126
       
123
        $feature->printMe();
127
        $feature->printMe();
124
       
128
       
125
        $counter++;
129
        $counter++;
126
      }
130
      }
127
    }
131
    }
128
  }
132
  }
129
 
133
 
130
  /**
134
  /**
131
   * Resolves a URN according to the value of the
135
   * Resolves a URN according to the value of the
132
   * object's <code>$urn</code> property.
136
   * object's <code>$urn</code> property.
133
   *
137
   *
134
   * @param string $urn
138
   * @param string $urn
135
   *   URN to be resolved
139
   *   URN to be resolved
136
   * @return string|boolean
140
   * @return string|boolean
137
   *   The resolved URN if successful,
141
   *   The resolved URN if successful,
138
   *   <code>false</code> otherwise.
142
   *   <code>false</code> otherwise.
139
   */
143
   */
140
  public function resolveURN($urn)
144
  public function resolveURN($urn)
141
  {
145
  {
142
    if (is_array($this->urns))
146
    if (is_array($this->urns))
143
    {
147
    {
144
      $reURN = '|^(.+?):(?!//)|';
148
      $reURN = '|^(.+?):(?!//)|';
145
     
149
     
146
      if (preg_match($reURN, $urn, $m) && isset($this->urns[$m[1]]))
150
      if (preg_match($reURN, $urn, $m) && isset($this->urns[$m[1]]))
147
      {
151
      {
148
        return preg_replace($reURN, $this->urns[$m[1]], $urn);
152
        return preg_replace($reURN, $this->urns[$m[1]], $urn);
149
      }
153
      }
150
    }
154
    }
151
155
152
    return $urn;
156
    return $urn;
153
  }
157
  }
154
}
158
}
155
159
156
/**
160
/**
157
 * A language feature.
161
 * A language feature.
158
 */
162
 */
159
class Feature
163
class Feature
160
{
164
{
161
  /**
165
  /**
162
   * Fragment identifiers to be defined for quickly accessing
166
   * Fragment identifiers to be defined for quickly accessing
163
   * the feature description.
167
   * the feature description.
164
   *
168
   *
165
   * @var Array[String]
169
   * @var Array[String]
166
   */
170
   */
167
  protected $anchors = array();
171
  protected $anchors = array();
168
 
172
 
169
  /**
173
  /**
170
   * Value of the explanatory <code>title</code> attribute for the feature.
174
   * Value of the explanatory <code>title</code> attribute for the feature.
171
   *
175
   *
172
   * @var string
176
   * @var string
173
   */
177
   */
174
  protected $title = '';
178
  protected $title = '';
175
 
179
 
176
  /**
180
  /**
177
   * Name or example code of the feature
181
   * Name or example code of the feature
178
   *
182
   *
179
   * @var string
183
   * @var string
180
   */
184
   */
181
  protected $content = '';
185
  protected $content = '';
182
   
186
   
183
  /**
187
  /**
184
   * Description of the feature.  Displayed directly if code is missing,
188
   * Description of the feature.  Displayed directly if code is missing,
185
   * otherwise used as `title' attribute value.
189
   * otherwise used as `title' attribute value.
186
   *
190
   *
187
   * @var string
191
   * @var string
188
   */
192
   */
189
  protected $descr = '';
193
  protected $descr = '';
190
 
194
 
191
  /**
195
  /**
192
   * Versions that support this feature
196
   * Versions that support this feature
193
   *
197
   *
194
   * @var Array
198
   * @var Array
195
   */
199
   */
196
  protected $versions = array();
200
  protected $versions = array();
197
   
201
   
198
  /**
202
  /**
199
   * Reference to the FeatureList that this feature belongs to
203
   * Reference to the FeatureList that this feature belongs to
200
   *
204
   *
201
   * @var FeatureList
205
   * @var FeatureList
202
   */
206
   */
203
  protected $list = null;
207
  protected $list = null;
204
 
208
 
205
  public function setList(&$oList)
209
  public function setList(&$oList)
206
  {
210
  {
207
    $this->list =& $oList;
211
    $this->list =& $oList;
208
  }
212
  }
209
213
210
  /**
214
  /**
211
   * Creates a new Feature object, using values from the passed parameters
215
   * Creates a new Feature object, using values from the passed parameters
212
   * array.
216
   * array.
213
   *
217
   *
214
   * @param array|Object $params
218
   * @param array|Object $params
215
   * @return Feature
219
   * @return Feature
216
   */
220
   */
217
  public function __construct($params = array())
221
  public function __construct($params = array())
218
  {
222
  {
219
    $aVars = get_class_vars(__CLASS__);
223
    $aVars = get_class_vars(__CLASS__);
220
   
224
   
221
    while ((list($key, $value) = each($aVars)))
225
    while ((list($key, $value) = each($aVars)))
222
    {
226
    {
223
      if (isset($params[$key]))
227
      if (isset($params[$key]))
224
      {
228
      {
225
        $this->$key = $params[$key];
229
        $this->$key = $params[$key];
226
      }
230
      }
227
    }
231
    }
228
  }
232
  }
229
 
233
 
230
  /**
234
  /**
231
   * Returns <code>' class="safe"'</code> if the feature
235
   * Returns <code>' class="safe"'</code> if the feature
232
   * can be considered safe.  The required information
236
   * can be considered safe.  The required information
233
   * is stored in the <code>safeVersions</code> property
237
   * is stored in the <code>safeVersions</code> property
234
   * of the associated <code>FeatureList</code> object.
238
   * of the associated <code>FeatureList</code> object.
235
   *
239
   *
236
   * @return string
240
   * @return string
237
   * @see FeatureList::defaultSafeVersions
241
   * @see FeatureList::defaultSafeVersions
238
   */
242
   */
239
  protected function getSafeStr()
243
  protected function getSafeStr()
240
  {
244
  {
241
    if (!is_null($this->list))
245
    if (!is_null($this->list))
242
    {
246
    {
243
      foreach ($this->list->safeVersions as $impl => &$safeVer)
247
      foreach ($this->list->safeVersions as $impl => &$safeVer)
244
      {
248
      {
245
        $thisImplVer =& $this->versions[$impl];
249
        $thisImplVer =& $this->versions[$impl];
246
        if (is_array($thisImplVer))
250
        if (is_array($thisImplVer))
247
        {
251
        {
248
          if (isset($thisImplVer['tested']) && !is_bool($thisImplVer['tested']))
252
          if (isset($thisImplVer['tested']) && !is_bool($thisImplVer['tested']))
249
          {
253
          {
250
            $thisImplVer =& $thisImplVer['tested'];
254
            $thisImplVer =& $thisImplVer['tested'];
251
          }
255
          }
252
          else
256
          else
253
        {
257
        {
254
            $thisImplVer =& $thisImplVer[0];
258
            $thisImplVer =& $thisImplVer[0];
255
          }
259
          }
256
        }
260
        }
257
       
261
       
258
        /* DEBUG */
262
        /* DEBUG */
259
        // echo " $impl=$thisImplVer ";
263
        // echo " $impl=$thisImplVer ";
260
       
264
       
261
        if (preg_match('/^-?$/', $thisImplVer) || $thisImplVer > $safeVer)
265
        if (preg_match('/^-?$/', $thisImplVer) || $thisImplVer > $safeVer)
262
        {
266
        {
263
          return '';
267
          return '';
264
        }
268
        }
265
      }
269
      }
266
     
270
     
267
      return ' class="safe"';
271
      return ' class="safe"';
268
    }
272
    }
269
    else
273
    else
270
    {
274
    {
271
      return '';
275
      return '';
272
    }
276
    }
273
  }
277
  }
274
 
278
 
275
  protected function getTitleStr()
279
  protected function getTitleStr()
276
  {
280
  {
277
    if (!empty($this->title))
281
    if (!empty($this->title))
278
    {
282
    {
279
      return " title=\"{$this->title}\"";
283
      return " title=\"{$this->title}\"";
280
    }
284
    }
281
    else
285
    else
282
    {
286
    {
283
      return '';
287
      return '';
284
    }
288
    }
285
  }
289
  }
286
 
290
 
287
  protected function getAnchors()
291
  protected function getAnchors()
288
  {
292
  {
289
    $result = array();
293
    $result = array();
290
 
294
 
291
    foreach ($this->anchors as $anchor)
295
    foreach ($this->anchors as $anchor)
292
    {
296
    {
293
      $result[] = "<a name=\"{$anchor}\"";
297
      $result[] = "<a name=\"{$anchor}\"";
294
     
298
     
295
      if (preg_match('/^[a-z][a-z0-9_:.-]*/i', $anchor))
299
      if (preg_match('/^[a-z][a-z0-9_:.-]*/i', $anchor))
296
      {
300
      {
297
        $result[] = " id=\"{$anchor}\"";
301
        $result[] = " id=\"{$anchor}\"";
298
      }
302
      }
299
     
303
     
300
      $result[] = '></a>';
304
      $result[] = '></a>';
301
    }
305
    }
302
   
306
   
303
    return join('', $result);
307
    return join('', $result);
304
  }
308
  }
305
309
306
  protected function getAssumed($v)
310
  protected function getAssumed($v)
307
  {
311
  {
308
    if (is_array($v) && isset($v['assumed']) && $v['assumed'])
312
    if (is_array($v) && isset($v['assumed']) && $v['assumed'])
309
    {
313
    {
310
      return ' class="assumed"';
314
      return ' class="assumed"';
311
    }
315
    }
312
   
316
   
313
    return '';
317
    return '';
314
  }
318
  }
315
319
316
  protected function getTested($v)
320
  protected function getTested($v)
317
  {
321
  {
318
    if (is_array($v) && isset($v['tested']) && $v['tested'])
322
    if (is_array($v) && isset($v['tested']) && $v['tested'])
319
    {
323
    {
320
      return ' class="tested"';
324
      return ' class="tested"';
321
    }
325
    }
322
   
326
   
323
    return '';
327
    return '';
324
  }
328
  }
325
 
329
 
326
  /**
330
  /**
327
   * Returns the version of a feature.
331
   * Returns the version of a feature.
328
   *
332
   *
329
   * @param string|VersionInfo $vInfo
333
   * @param string|VersionInfo $vInfo
330
   * @return mixed
334
   * @return mixed
331
   */
335
   */
332
  protected function getVer($vInfo)
336
  protected function getVer($vInfo)
333
  {
337
  {
334
    if (is_array($vInfo))
338
    if (is_array($vInfo))
335
    {
339
    {
336
      /* TODO: Return all versions: documented, assumed, and tested */
340
      /* TODO: Return all versions: documented, assumed, and tested */
337
      $vNumber = (isset($vInfo['tested'])
341
      $vNumber = (isset($vInfo['tested'])
338
                  && gettype($vInfo['tested']) !== 'boolean')
342
                  && gettype($vInfo['tested']) !== 'boolean')
339
                     ? $vInfo['tested']
343
                     ? $vInfo['tested']
340
                     : $vInfo[0];
344
                     : $vInfo[0];
341
      $section = isset($vInfo['section'])
345
      $section = isset($vInfo['section'])
342
                   ? ' <span class="section" title="Specification section">['
346
                   ? ' <span class="section" title="Specification section">['
343
                      . $vInfo['section'] . ']</span>'
347
                      . $vInfo['section'] . ']</span>'
344
                   : '';
348
                   : '';
345
     
349
     
346
      if (isset($vInfo['urn']))
350
      if (isset($vInfo['urn']))
347
      {
351
      {
348
        if ($this->list instanceof FeatureList)
352
        if ($this->list instanceof FeatureList)
349
        {
353
        {
350
          $url = $this->list->resolveURN($vInfo['urn']);
354
          $url = $this->list->resolveURN($vInfo['urn']);
351
          $vNumber = '<a href="' . $url . '">' . $vNumber
355
          $vNumber = '<a href="' . $url . '">' . $vNumber
352
            . ($section ? $section : '') . '</a>';
356
            . ($section ? $section : '') . '</a>';
353
        }
357
        }
354
      }
358
      }
355
      else if ($section)
359
      else if ($section)
356
      {
360
      {
357
        $vNumber .= $section;
361
        $vNumber .= $section;
358
      }
362
      }
359
363
360
      $vInfo = $vNumber;
364
      $vInfo = $vNumber;
361
    }
365
    }
362
366
363
    return ($vInfo === '-')
367
    return ($vInfo === '-')
364
      ? '<span title="Not supported">&#8722;</span>'
368
      ? '<span title="Not supported">&#8722;</span>'
365
      : $vInfo;
369
      : $vInfo;
366
  }
370
  }
367
   
371
   
368
  protected static function shl($s)
372
  protected static function shl($s)
369
  {
373
  {
370
    /* stub */
374
    /* stub */
371
  }
375
  }
372
 
376
 
373
  public function printMe()
377
  public function printMe()
374
  {
378
  {
375
    ?>
379
    ?>
376
<tr<?php echo $this->getSafeStr(); ?>>
380
<tr<?php echo $this->getSafeStr(); ?>>
377
          <th<?php echo $this->getTitleStr(); ?>><?php
381
          <th<?php echo $this->getTitleStr(); ?>><?php
378
            echo $this->getAnchors();
382
            echo $this->getAnchors();
379
            echo /*preg_replace_callback(
383
            echo /*preg_replace_callback(
380
              '#(<code>)(.+?)(</code>)#',
384
              '#(<code>)(.+?)(</code>)#',
381
              array('self', 'shl'),*/
385
              array('self', 'shl'),*/
382
              preg_replace('/&hellip;/', '&#8230;', $this->content)/*)*/;
386
              preg_replace('/&hellip;/', '&#8230;', $this->content)/*)*/;
383
            ?></th>
387
            ?></th>
384
<?php
388
<?php
385
    $versions = $this->versions;
389
    $versions = $this->versions;
386
    if (!is_null($this->list))
390
    if (!is_null($this->list))
387
    {
391
    {
388
      $versions =& $this->list->versions;
392
      $versions =& $this->list->versions;
389
    }
393
    }
390
394
391
    static $row = 0;
395
    static $row = 0;
392
    $row++;
396
    $row++;
393
   
397
   
394
    $column = 0;
398
    $column = 0;
395
   
399
   
396
    foreach ($versions as $key => $value)
400
    foreach ($versions as $key => $value)
397
    {
401
    {
398
      $column++;
402
      $column++;
399
      $id = "td$row-$column";
403
      $id = "td$row-$column";
400
      $ver = $this->versions[$key];
404
      $ver = $this->versions[$key];
401
?>
405
?>
402
          <td id="<?php echo $id; ?>"<?php
406
          <td id="<?php echo $id; ?>"<?php
403
            echo $this->getAssumed($ver) . $this->getTested($ver);
407
            echo $this->getAssumed($ver) . $this->getTested($ver);
404
            if (!$key)
408
            if (!$key)
405
            {
409
            {
406
              if (!empty($ver))
410
              if (!empty($ver))
407
              {
411
              {
408
                echo ' title="Test code: '
412
                echo ' title="Test code: '
409
                  . htmlspecialchars(
413
                  . htmlspecialchars(
410
                      stripslashes($ver),
414
                      stripslashes($ver),
411
                      ENT_COMPAT,
415
                      ENT_COMPAT,
412
                      FEATURES_ENCODING)
416
                      FEATURES_ENCODING)
413
                  . '"';
417
                  . '"';
414
              }
418
              }
415
              else
419
              else
416
              {
420
              {
417
                echo ' title="Not applicable: No automated test case'
421
                echo ' title="Not applicable: No automated test case'
418
                  . ' is available for this feature.  Please click'
422
                  . ' is available for this feature.  Please click'
419
                  . ' the feature code in the first column to run'
423
                  . ' the feature code in the first column to run'
420
                  . ' a manual test."';
424
                  . ' a manual test."';
421
              }
425
              }
422
            }
426
            }
423
            ?>><?php
427
            ?>><?php
424
            if ($key)
428
            if ($key)
425
            {
429
            {
426
              echo $this->getVer($ver);
430
              echo $this->getVer($ver);
427
            }
431
            }
428
            else
432
            else
429
            {
433
            {
430
              if (!empty($ver))
434
              if (!empty($ver))
431
              {
435
              {
432
                ?><script type="text/javascript">
436
                ?><script type="text/javascript">
433
  // <![CDATA[
437
  // <![CDATA[
434
  var s = test(<?php echo $ver; ?>, '<span title="Supported">+</span>',
438
  var s = test(<?php echo $ver; ?>, '<span title="Supported">+</span>',
435
    '<span title="Not supported">&#8722;</span>');
439
    '<span title="Not supported">&#8722;</span>');
436
  tryThis("document.write(s);",
440
  tryThis("document.write(s);",
437
          "document.getElementById('<?php echo $id; ?>').appendChild("
441
          "document.getElementById('<?php echo $id; ?>').appendChild("
438
          + "document.createTextNode(s));");
442
          + "document.createTextNode(s));");
439
  // ]]>
443
  // ]]>
440
</script><?php
444
</script><?php
441
              }
445
              }
442
              else
446
              else
443
              {
447
              {
444
                echo '<abbr>N/A</abbr>';
448
                echo '<abbr>N/A</abbr>';
445
              }
449
              }
446
            }
450
            }
447
            ?></td>
451
            ?></td>
448
<?php
452
<?php
449
    }
453
    }
450
?>
454
?>
451
        </tr>
455
        </tr>
452
<?php
456
<?php
453
  }
457
  }
454
}
458
}
455
 
459
 
456
?>
460
?>
457
 
461