Subversion Repositories PHPX

Rev

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

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