Subversion Repositories PHPX

Rev

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

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