Subversion Repositories SvarDOS

Rev

Rev 1524 | Rev 1608 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
562 mateuszvis 1
<?php /*
2
 
3
  SvarDOS repo index builder
1267 mateusz.vi 4
  Copyright (C) Mateusz Viste 2012-2023
562 mateuszvis 5
 
734 bttr 6
  buildidx computes an index json file for the SvarDOS repository.
673 mateusz.vi 7
  it must be executed pointing to a directory that stores packages (*.svp)
562 mateuszvis 8
  files. buildidx will generate the index file and save it into the package
9
  repository.
10
 
11
  requires php-zip
12
 
1607 mateusz.vi 13
  24 nov 2023: SVED included in the MS-DOS compat list instead of EDIT
1522 mateusz.vi 14
  25 aug 2023: validation of the hwreq section in LSM files
1509 mateusz.vi 15
  24 aug 2023: load hwreq data from LSM and store them in the json index + skip the '.svn' dir
1267 mateusz.vi 16
  30 jun 2023: adapted for new CORE packages location (../packages-core)
999 mateusz.vi 17
  28 feb 2022: svarcom allowed to have a COMMAND.COM file without subdirectory
951 mateusz.vi 18
  24 feb 2022: added hardcoded hack to translate version 'x.xx' to '0.44' (NESticle)
941 mateusz.vi 19
  23 feb 2022: basic validation of source archives (not empty + matches an existing svp file)
912 mateusz.vi 20
  21 feb 2022: buildidx collects categories looking at the dir layout of each package + improved version string parsing (replaced version_compare call by dos_version_compare)
775 mateusz.vi 21
  17 feb 2022: checking for non-8+3 filenames in packages and duplicates + devload no longer part of CORE
736 mateusz.vi 22
  16 feb 2022: added warning about overlong version strings and wild files location
719 mateusz.vi 23
  15 feb 2022: index is generated as json, contains all filenames and alt versions
673 mateusz.vi 24
  14 feb 2022: packages are expected to have the *.svp extension
650 mateusz.vi 25
  12 feb 2022: skip source packages from being processed (*.src.zip)
562 mateuszvis 26
  20 jan 2022: rewritten the code from ANSI C to PHP for easier maintenance
27
  13 feb 2021: 'title' LSM field is no longer looked after
28
  11 feb 2021: lsm headers are no longer checked, so it is compatible with the simpler lsm format used by SvarDOS
29
  13 jan 2021: removed the identification line, changed CRC32 to bsum, not creating the listing.txt file and stopped compressing index
30
  23 apr 2017: uncompressed index is no longer created, added CRC32 of zib (bin only) files, if present
31
  28 aug 2016: listing.txt is always written inside the repo dir (instead of inside current dir)
32
  27 aug 2016: accepting full paths to repos (starting with /...)
33
  07 dec 2013: rewritten buildidx in ANSI C89
34
  19 aug 2013: add a compressed version of the index file to repos (index.gz)
35
  22 jul 2013: creating a listing.txt file with list of packages
36
  18 jul 2013: writing the number of packaged into the first line of the lst file
37
  11 jul 2013: added a switch to 7za to make it case insensitive when extracting lsm files
38
  10 jul 2013: changed unzip calls to 7za (to handle cases when appinfo is compressed with lzma)
39
  04 feb 2013: added CRC32 support
40
  22 sep 2012: forked 1st version from FDUPDATE builder
41
*/
42
 
1522 mateusz.vi 43
$PVER = "20230825";
562 mateuszvis 44
 
45
 
46
// computes the BSD sum of a file and returns it
47
function file2bsum($fname) {
48
  $result = 0;
49
 
50
  $fd = fopen($fname, 'rb');
51
  if ($fd === false) return(0);
52
 
53
  while (!feof($fd)) {
54
 
55
    $buff = fread($fd, 1024 * 1024);
56
 
563 mateuszvis 57
    $slen = strlen($buff);
58
    for ($i = 0; $i < $slen; $i++) {
562 mateuszvis 59
      // rotr
60
      $result = ($result >> 1) | ($result << 15);
61
      // add and truncate to 16 bits
563 mateuszvis 62
      $result += ord($buff[$i]);
562 mateuszvis 63
      $result &= 0xffff;
64
    }
65
  }
66
 
67
  fclose($fd);
68
  return($result);
69
}
70
 
71
 
912 mateusz.vi 72
// translates a version string into a array of integer values.
73
// Accepted formats follow:
74
//    300.12.1
75
//    1
76
//    12.2.34.2-4.5
77
//    1.2c
78
//    1.01 beta+3
79
//    2013-12-31
80
//    20220222 alpha
81
function vertoarr($verstr) {
82
  $subver = array(0,0,0,0);
83
 
84
  // switch string to lcase for easier processing and trim any leading or trailing white spaces
85
  $verstr = strtolower(trim($verstr));
86
 
87
  // replace all '-' and '/' characters to '.' (uniformization of sub-version parts delimiters)
88
  $verstr = strtr($verstr, '-/', '..');
89
 
90
  // is there a subversion value? (for example "+4" in "1.05+4")
91
  $i = strrpos($verstr, '+', 1);
92
  if ($i !== false) {
93
    // validate the svar-version is a proper integer
94
    $svarver = substr($verstr, $i + 1);
95
    if (! preg_match('/[1-9][0-9]*/', $svarver)) {
96
      return(false);
97
    }
98
    $subver[3] = intval($svarver); // set the +rev as a very minor item
99
    $verstr = substr($verstr, 0, $i);
100
  }
101
 
951 mateusz.vi 102
  // NESticls hack: version "x.xx" is translated to "0.44"... that sucks but that's how it is.
103
  // ref: https://web.archive.org/web/20070205074631/http://www.zophar.net/NESticle/
104
  if ($verstr == 'x.xx') $verstr = '0.44';
105
 
936 mateusz.vi 106
  // beta reordering: convert "beta 0.95" to "0.95 beta"
107
  if (preg_match('/^beta /', $verstr)) $verstr = substr($verstr, 5) . ' beta';
108
 
927 mateusz.vi 109
  // any occurence of alpha,beta,gamma,delta etc preceded by a digit should have a space separator added
110
  // example: "2.6.0pre9" becomes "2.6.0 pre9"
111
  $verstr = preg_replace('/([0-9])(alpha|beta|gamma|delta|pre|rc|patch)/', '$1 $2', $verstr);
112
 
113
  // same as above, but this time adding a trailing space separator
114
  // example: "2.6.0 pre9" becomes "2.6.0 pre 9"
115
  $verstr = preg_replace('/(alpha|beta|gamma|delta|pre|rc|patch)([0-9])/', '$1 $2', $verstr);
116
 
921 mateusz.vi 117
  // is the version ending with ' alpha', 'beta', etc?
922 mateusz.vi 118
  if (preg_match('/ (alpha|beta|gamma|delta|pre|rc|patch)( [0-9]{1,4}){0,1}$/', $verstr)) {
921 mateusz.vi 119
    // if there is a trailing beta-number, process it first
120
    if (preg_match('/ [0-9]{1,4}$/', $verstr)) {
121
      $i = strrpos($verstr, ' ');
122
      $subver[2] = intval(substr($verstr, $i + 1));
123
      $verstr = trim(substr($verstr, 0, $i));
124
    }
912 mateusz.vi 125
    $i = strrpos($verstr, ' ');
126
    $greek = substr($verstr, $i + 1);
127
    $verstr = trim(substr($verstr, 0, $i));
128
    if ($greek == 'alpha') {
921 mateusz.vi 129
      $subver[1] = 1;
912 mateusz.vi 130
    } else if ($greek == 'beta') {
921 mateusz.vi 131
      $subver[1] = 2;
920 mateusz.vi 132
    } else if ($greek == 'gamma') {
921 mateusz.vi 133
      $subver[1] = 3;
920 mateusz.vi 134
    } else if ($greek == 'delta') {
921 mateusz.vi 135
      $subver[1] = 4;
136
    } else if ($greek == 'pre') {
137
      $subver[1] = 5;
914 mateusz.vi 138
    } else if ($greek == 'rc') {
921 mateusz.vi 139
      $subver[1] = 6;
922 mateusz.vi 140
    } else if ($greek == 'patch') { // this is a POST-release version, as opposed to all above that are PRE-release versions
141
      $subver[1] = 99;
912 mateusz.vi 142
    } else {
143
      return(false);
144
    }
914 mateusz.vi 145
  } else {
922 mateusz.vi 146
    $subver[1] = 98; // one less than the 'patch' level
912 mateusz.vi 147
  }
148
 
149
  // does the version string have a single-letter subversion? (1.0c)
150
  if (preg_match('/[a-z]$/', $verstr)) {
921 mateusz.vi 151
    $subver[0] = ord(substr($verstr, -1));
912 mateusz.vi 152
    $verstr = substr_replace($verstr, '', -1); // remove last character from string
153
  }
154
 
926 mateusz.vi 155
  // convert "30-jan-99", "1999-jan-30" and "30-jan-1999" versions to "30jan99" or "30jan1999"
156
  // note that dashes have already been replaced by dots
157
  if (preg_match('/^([0-9][0-9]){1,2}\.(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\.([0-9][0-9]){1,2}$/', $verstr)) {
158
    $verstr = str_replace('.', '', $verstr);
159
  }
160
 
161
  // convert "2009mar17" versions to "17mar2009"
162
  if (preg_match('/^[0-9]{4}(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[0-9]{2}$/', $verstr)) {
163
    $dy = substr($verstr, 7);
164
    $mo = substr($verstr, 4, 3);
165
    $ye = substr($verstr, 0, 4);
925 mateusz.vi 166
    $verstr = "{$dy}{$mo}{$ye}";
923 mateusz.vi 167
  }
168
 
169
  // convert "30jan99" versions to 99.1.30 and "30jan1999" to 1999.1.30
925 mateusz.vi 170
  if (preg_match('/^[0-3][0-9](jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)([0-9][0-9]){1,2}$/', $verstr)) {
923 mateusz.vi 171
    $months = array('jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8, 'sep' => 9, 'oct' => 10, 'nov' => 11, 'dec' => 12);
172
    $dy = substr($verstr, 0, 2);
173
    $mo = $months[substr($verstr, 2, 3)];
174
    $ye = substr($verstr, 5);
175
    $verstr = "{$ye}.{$mo}.{$dy}";
176
  }
177
 
912 mateusz.vi 178
  // validate the format is supported, should be something no more complex than 1.05.3.33
919 mateusz.vi 179
  if (! preg_match('/^[0-9][0-9.]{0,20}$/', $verstr)) {
912 mateusz.vi 180
    return(false);
181
  }
182
 
183
  // NOTE: a zero right after a separator and trailed with a digit (as in 1.01)
184
  //       has a special meaning
185
  $exploded = explode('.', $verstr);
186
  if (count($exploded) > 16) {
187
    return(false);
188
  }
921 mateusz.vi 189
  $exploded[16] = $subver[0]; // a-z (1.0c)
190
  $exploded[17] = $subver[1]; // alpha/beta/gamma/delta/rc/pre
191
  $exploded[18] = $subver[2]; // alpha-beta-gamma subversion (eg. "beta 9")
912 mateusz.vi 192
  $exploded[19] = $subver[3]; // svar-ver (1.0+5)
193
  for ($i = 0; $i < 20; $i++) if (empty($exploded[$i])) $exploded[$i] = '0';
194
 
195
  ksort($exploded);
196
 
197
  return($exploded);
198
}
199
 
200
 
201
function dos_version_compare($v1, $v2) {
202
  $v1arr = vertoarr($v1);
203
  $v2arr = vertoarr($v2);
204
  for ($i = 0; $i < count($v1arr); $i++) {
921 mateusz.vi 205
    if ($v1arr[$i] > $v2arr[$i]) return(1);
206
    if ($v1arr[$i] < $v2arr[$i]) return(-1);
912 mateusz.vi 207
  }
208
  return(0);
209
}
210
 
211
 
562 mateuszvis 212
// reads file fil from zip archive z and returns its content, or false on error
213
function read_file_from_zip($z, $fil) {
214
  $zip = new ZipArchive;
215
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
216
    echo "ERROR: failed to open zip file '{$z}'\n";
217
    return(false);
218
  }
219
 
220
  // load the appinfo/pkgname.lsm file
221
  $res = $zip->getFromName($fil, 8192, ZipArchive::FL_NOCASE);
222
 
223
  $zip->close();
224
  return($res);
225
}
226
 
227
 
731 mateusz.vi 228
function read_list_of_files_in_zip($z) {
229
  $zip = new ZipArchive;
230
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
231
    echo "ERROR: failed to open zip file '{$z}'\n";
232
    return(false);
233
  }
234
 
235
  $res = array();
236
  for ($i = 0; $i < $zip->numFiles; $i++) $res[] = $zip->getNameIndex($i);
237
 
238
  $zip->close();
239
  return($res);
240
}
241
 
242
 
562 mateuszvis 243
// reads a LSM string and returns it in the form of an array
244
function parse_lsm($s) {
245
  $res = array();
246
  for ($l = strtok($s, "\n"); $l !== false; $l = strtok("\n")) {
247
    // the line is "token: value", let's find the colon
248
    $colpos = strpos($l, ':');
249
    if (($colpos === false) || ($colpos === 0)) continue;
250
    $tok = strtolower(trim(substr($l, 0, $colpos)));
251
    $val = trim(substr($l, $colpos + 1));
252
    $res[$tok] = $val;
253
  }
254
  return($res);
255
}
256
 
257
 
731 mateusz.vi 258
// on PHP 8+ there is str_starts_with(), but not on PHP 7 so I use this
259
function str_head_is($haystack, $needle) {
260
  return strpos($haystack, $needle) === 0;
261
}
262
 
263
 
791 mateusz.vi 264
// returns an array that contains CORE packages (populated from the core subdirectory in pkgdir)
1267 mateusz.vi 265
function load_core_list($repodir_core) {
791 mateusz.vi 266
  $res = array();
267
 
1267 mateusz.vi 268
  foreach (scandir($repodir_core) as $f) {
791 mateusz.vi 269
    if (!preg_match('/\.svp$/', $f)) continue;
270
    $res[] = explode('.', $f)[0];
271
  }
272
  return($res);
273
}
274
 
275
 
562 mateuszvis 276
// ***************** MAIN ROUTINE *********************************************
277
 
719 mateusz.vi 278
//echo "SvarDOS repository index generator ver {$PVER}\n";
562 mateuszvis 279
 
280
if (($_SERVER['argc'] != 2) || ($_SERVER['argv'][1][0] == '-')) {
281
  echo "usage: php buildidx.php repodir\n";
282
  exit(1);
283
}
284
 
285
$repodir = $_SERVER['argv'][1];
286
 
287
$pkgfiles = scandir($repodir);
288
$pkgcount = 0;
289
 
738 mateusz.vi 290
 
795 mateusz.vi 291
// load the list of CORE and MSDOS_COMPAT packages
738 mateusz.vi 292
 
1267 mateusz.vi 293
$core_packages_list = load_core_list($repodir . '/../packages-core/');
1607 mateusz.vi 294
$msdos_compat_list = explode(' ', 'append assign attrib callver chkdsk choice comp cpidos debug defrag deltree diskcomp diskcopy display edlin exe2bin fc fdapm fdisk find format help himemx kernel keyb label localcfg mem mirror mode more move nlsfunc print replace share shsucdx sort svarcom sved swsubst tree undelete unformat xcopy');
738 mateusz.vi 295
 
719 mateusz.vi 296
// do a list of all svp packages with their available versions and descriptions
562 mateuszvis 297
 
719 mateusz.vi 298
$pkgdb = array();
299
foreach ($pkgfiles as $fname) {
562 mateuszvis 300
 
941 mateusz.vi 301
  // zip files (ie. source archives)
302
  if (preg_match('/\.zip$/', $fname)) {
303
    // the zip archive should contain at least one file
304
    if (count(read_list_of_files_in_zip($repodir . '/' . $fname)) < 1) echo "WARNING: source archive {$fname} contains no files (either empty or corrupted)\n";
305
    // check that the file relates to an existing svp package
306
    $svpfname = preg_replace('/zip$/', 'svp', $fname);
307
    if (!file_exists($repodir . '/' . $svpfname)) echo "ERROR: orphaned source archive '{$fname}' (no matching svp file, expecting a package named '{$svpfname}')\n";
308
    // that is for zip files
309
    continue;
310
  }
311
 
1509 mateusz.vi 312
  // silently skip the hidden .svn directory
313
  if ($fname === '.svn') continue;
314
 
941 mateusz.vi 315
  // skip (and warn about) non-svp
316
  if (!preg_match('/\.svp$/', $fname)) {
1267 mateusz.vi 317
    $okfiles = array('.', '..', '_cats.json', '_index.json', '_buildidx.log');
941 mateusz.vi 318
    if (array_search($fname, $okfiles) !== false) continue;
1509 mateusz.vi 319
    echo "WARNING: wild file '{$fname}' (this is either an useless file that should be removed, or a misnamed package or source archive)'\n";
941 mateusz.vi 320
    continue;
321
  }
322
 
801 mateusz.vi 323
  if (!preg_match('/^[a-zA-Z0-9+. _-]*\.svp$/', $fname)) {
324
    echo "ERROR: {$fname} has a very weird name\n";
325
    continue;
326
  }
327
 
719 mateusz.vi 328
  $path_parts = pathinfo($fname);
329
  $pkgnam = explode('-', $path_parts['filename'])[0];
330
  $pkgfullpath = realpath($repodir . '/' . $fname);
562 mateuszvis 331
 
719 mateusz.vi 332
  $lsm = read_file_from_zip($pkgfullpath, "appinfo/{$pkgnam}.lsm");
562 mateuszvis 333
  if ($lsm == false) {
802 mateusz.vi 334
    echo "ERROR: {$fname} does not contain an LSM file at the expected location\n";
719 mateusz.vi 335
    continue;
562 mateuszvis 336
  }
337
  $lsmarray = parse_lsm($lsm);
338
  if (empty($lsmarray['version'])) {
719 mateusz.vi 339
    echo "ERROR: lsm file in {$fname} does not contain a version\n";
340
    continue;
562 mateuszvis 341
  }
730 mateusz.vi 342
  if (strlen($lsmarray['version']) > 16) {
737 mateusz.vi 343
    echo "ERROR: version string in lsm file of {$fname} is too long (16 chars max)\n";
730 mateusz.vi 344
    continue;
345
  }
562 mateuszvis 346
  if (empty($lsmarray['description'])) {
719 mateusz.vi 347
    echo "ERROR: lsm file in {$fname} does not contain a description\n";
348
    continue;
562 mateuszvis 349
  }
350
 
731 mateusz.vi 351
  // validate the files present in the archive
352
  $listoffiles = read_list_of_files_in_zip($pkgfullpath);
739 mateusz.vi 353
  $pkgdir = $pkgnam;
354
 
768 mateusz.vi 355
  // special rule for "parent and children" packages
356
  if (str_head_is($pkgnam, 'djgpp_')) $pkgdir = 'djgpp'; // djgpp_* packages put their files in djgpp
754 mateusz.vi 357
  if ($pkgnam == 'fbc_help') $pkgdir = 'fbc'; // FreeBASIC help goes to the FreeBASIC dir
802 mateusz.vi 358
  if ($pkgnam == 'clamdb') $pkgdir = 'clamav'; // data patterns for clamav
739 mateusz.vi 359
 
768 mateusz.vi 360
  // array used to detect duplicated entries after lower-case conversion
361
  $duparr = array();
362
 
909 mateusz.vi 363
  // will hold the list of categories that this package belongs to
364
  $catlist = array();
365
 
731 mateusz.vi 366
  foreach ($listoffiles as $f) {
367
    $f = strtolower($f);
768 mateusz.vi 368
    $path_array = explode('/', $f);
369
    // emit a warning when non-8+3 filenames are spotted and find duplicates
370
    foreach ($path_array as $item) {
371
      if (empty($item)) continue; // skip empty items at end of paths (eg. appinfo/)
372
      if (!preg_match("/[a-z0-9!#$%&'()@^_`{}~-]{1,8}(\.[a-z0-9!#$%&'()@^_`{}~-]{1,3}){0,1}/", $item)) {
373
        echo "WARNING: {$fname} contains a non-8+3 path (or weird char): {$item} (in $f)\n";
374
      }
375
    }
376
    // look for dups
377
    if (array_search($f, $duparr) !== false) {
378
      echo "WARNING: {$fname} contains a duplicated entry: '{$f}'\n";
379
    } else {
380
      $duparr[] = $f;
381
    }
731 mateusz.vi 382
    // LSM file is ok
383
    if ($f === "appinfo/{$pkgnam}.lsm") continue;
384
    if ($f === "appinfo/") continue;
795 mateusz.vi 385
    // CORE and MSDOS_COMPAT packages are premium citizens and can do a little more
909 mateusz.vi 386
    $core_or_msdoscompat = 0;
387
    if (array_search($pkgnam, $core_packages_list) !== false) {
388
      $catlist[] = 'core';
389
      $core_or_msdoscompat = 1;
390
    }
391
    if (array_search($pkgnam, $msdos_compat_list) !== false) {
392
      $catlist[] = 'msdos_compat';
393
      $core_or_msdoscompat = 1;
394
    }
395
    if ($core_or_msdoscompat == 1) {
736 mateusz.vi 396
      if (str_head_is($f, 'bin/')) continue;
779 mateusz.vi 397
      if (str_head_is($f, 'cpi/')) continue;
749 mateusz.vi 398
      if (str_head_is($f, "doc/{$pkgdir}/")) continue;
399
      if ($f === 'doc/') continue;
400
      if (str_head_is($f, "nls/{$pkgdir}.")) continue;
401
      if ($f === 'nls/') continue;
736 mateusz.vi 402
    }
999 mateusz.vi 403
    // SVARCOM is allowed to have a root-based COMMAND.COM file
404
    if ($pkgnam === 'svarcom') {
405
      if ($f === 'command.com') continue;
406
    }
798 mateusz.vi 407
    // the help package is allowed to put files in... help
408
    if (($pkgnam == 'help') && (str_head_is($f, 'help/'))) continue;
909 mateusz.vi 409
    // must be category-prefixed file, add it to the list of categories for this package
410
    $catlist[] = explode('/', $f)[0];
749 mateusz.vi 411
    // well-known "category" dirs are okay
739 mateusz.vi 412
    if (str_head_is($f, "progs/{$pkgdir}/")) continue;
731 mateusz.vi 413
    if ($f === 'progs/') continue;
739 mateusz.vi 414
    if (str_head_is($f, "devel/{$pkgdir}/")) continue;
731 mateusz.vi 415
    if ($f === 'devel/') continue;
739 mateusz.vi 416
    if (str_head_is($f, "games/{$pkgdir}/")) continue;
731 mateusz.vi 417
    if ($f === 'games/') continue;
739 mateusz.vi 418
    if (str_head_is($f, "drivers/{$pkgdir}/")) continue;
731 mateusz.vi 419
    if ($f === 'drivers/') continue;
768 mateusz.vi 420
    echo "WARNING: {$fname} contains a file in an illegal location: {$f}\n";
731 mateusz.vi 421
  }
422
 
912 mateusz.vi 423
  // do I understand the version string?
424
  if (vertoarr($lsmarray['version']) === false) echo "WARNING: {$fname} parsing of version string failed ('{$lsmarray['version']}')\n";
425
 
1511 mateusz.vi 426
  $meta = array();
719 mateusz.vi 427
  $meta['fname'] = $fname;
428
  $meta['desc'] = $lsmarray['description'];
909 mateusz.vi 429
  $meta['cats'] = array_unique($catlist);
719 mateusz.vi 430
 
1522 mateusz.vi 431
  if (!empty($lsmarray['hwreq'])) {
432
    $meta['hwreq'] = explode(' ', strtolower($lsmarray['hwreq']));
1524 mateusz.vi 433
    sort($meta['hwreq']);
1522 mateusz.vi 434
 
435
    // validate list of valid hwreq tokens
436
    $validtokens = array('8086', '186', '286', '386', '486', '586', 'fpu', 'mda', 'cga', 'ega', 'vga', 'mcga', 'svga');
437
    foreach (array_diff($meta['hwreq'], $validtokens) as $tok) echo "WARNING: {$fname} contains an LSM hwreq section with invalid token: {$tok}\n";
438
  }
439
 
719 mateusz.vi 440
  $pkgdb[$pkgnam][$lsmarray['version']] = $meta;
441
}
442
 
801 mateusz.vi 443
 
719 mateusz.vi 444
$db = array();
909 mateusz.vi 445
$cats = array();
719 mateusz.vi 446
 
909 mateusz.vi 447
// ******** compute the version-sorted list of packages with a single *********
448
// ******** description and category list for each package ********************
449
 
719 mateusz.vi 450
// iterate over each svp package
451
foreach ($pkgdb as $pkg => $versions) {
452
 
453
  // sort filenames by version, highest first
912 mateusz.vi 454
  uksort($versions, "dos_version_compare");
719 mateusz.vi 455
  $versions = array_reverse($versions, true);
456
 
457
  foreach ($versions as $ver => $meta) {
458
    $fname = $meta['fname'];
459
    $desc = $meta['desc'];
460
 
461
    $bsum = file2bsum(realpath($repodir . '/' . $fname));
462
 
1511 mateusz.vi 463
    $meta2 = array();
719 mateusz.vi 464
    $meta2['ver'] = strval($ver);
465
    $meta2['bsum'] = $bsum;
1522 mateusz.vi 466
    if (!empty($meta['hwreq'])) $meta2['hwreq'] = $meta['hwreq'];
719 mateusz.vi 467
 
468
    if (empty($db[$pkg]['desc'])) $db[$pkg]['desc'] = $desc;
909 mateusz.vi 469
    if (empty($db[$pkg]['cats'])) {
470
      $db[$pkg]['cats'] = $meta['cats'];
471
      $cats = array_unique(array_merge($cats, $meta['cats']));
472
    }
719 mateusz.vi 473
    $db[$pkg]['versions'][$fname] = $meta2;
474
  }
475
 
562 mateuszvis 476
  $pkgcount++;
477
 
478
}
479
 
719 mateusz.vi 480
if ($pkgcount < 100) echo "WARNING: an unexpectedly low number of packages has been found in the repo ({$pkgcount})\n";
562 mateuszvis 481
 
801 mateusz.vi 482
$json_blob = json_encode($db);
483
if ($json_blob === false) {
484
  echo "ERROR: JSON convertion failed! -> ";
485
  switch (json_last_error()) {
486
    case JSON_ERROR_DEPTH:
487
      echo 'maximum stack depth exceeded';
488
      break;
489
    case JSON_ERROR_STATE_MISMATCH:
490
      echo 'underflow of the modes mismatch';
491
      break;
492
    case JSON_ERROR_CTRL_CHAR:
493
      echo 'unexpected control character found';
494
      break;
495
    case JSON_ERROR_UTF8:
496
      echo 'malformed utf-8 characters';
497
      break;
498
    default:
499
      echo "unknown error";
500
      break;
501
  }
502
  echo "\n";
503
}
504
 
909 mateusz.vi 505
file_put_contents($repodir . '/_index.json', $json_blob);
562 mateuszvis 506
 
909 mateusz.vi 507
$cats_json = json_encode($cats);
508
file_put_contents($repodir . '/_cats.json', $cats_json);
509
 
562 mateuszvis 510
exit(0);
511
 
512
?>