Subversion Repositories SvarDOS

Rev

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

Rev 912 Rev 914
1
<?php /*
1
<?php /*
2
 
2
 
3
  SvarDOS repo index builder
3
  SvarDOS repo index builder
4
  Copyright (C) Mateusz Viste 2012-2022
4
  Copyright (C) Mateusz Viste 2012-2022
5
 
5
 
6
  buildidx computes an index json file for the SvarDOS repository.
6
  buildidx computes an index json file for the SvarDOS repository.
7
  it must be executed pointing to a directory that stores packages (*.svp)
7
  it must be executed pointing to a directory that stores packages (*.svp)
8
  files. buildidx will generate the index file and save it into the package
8
  files. buildidx will generate the index file and save it into the package
9
  repository.
9
  repository.
10
 
10
 
11
  requires php-zip
11
  requires php-zip
12
 
12
 
13
  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)
13
  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)
14
  17 feb 2022: checking for non-8+3 filenames in packages and duplicates + devload no longer part of CORE
14
  17 feb 2022: checking for non-8+3 filenames in packages and duplicates + devload no longer part of CORE
15
  16 feb 2022: added warning about overlong version strings and wild files location
15
  16 feb 2022: added warning about overlong version strings and wild files location
16
  15 feb 2022: index is generated as json, contains all filenames and alt versions
16
  15 feb 2022: index is generated as json, contains all filenames and alt versions
17
  14 feb 2022: packages are expected to have the *.svp extension
17
  14 feb 2022: packages are expected to have the *.svp extension
18
  12 feb 2022: skip source packages from being processed (*.src.zip)
18
  12 feb 2022: skip source packages from being processed (*.src.zip)
19
  20 jan 2022: rewritten the code from ANSI C to PHP for easier maintenance
19
  20 jan 2022: rewritten the code from ANSI C to PHP for easier maintenance
20
  13 feb 2021: 'title' LSM field is no longer looked after
20
  13 feb 2021: 'title' LSM field is no longer looked after
21
  11 feb 2021: lsm headers are no longer checked, so it is compatible with the simpler lsm format used by SvarDOS
21
  11 feb 2021: lsm headers are no longer checked, so it is compatible with the simpler lsm format used by SvarDOS
22
  13 jan 2021: removed the identification line, changed CRC32 to bsum, not creating the listing.txt file and stopped compressing index
22
  13 jan 2021: removed the identification line, changed CRC32 to bsum, not creating the listing.txt file and stopped compressing index
23
  23 apr 2017: uncompressed index is no longer created, added CRC32 of zib (bin only) files, if present
23
  23 apr 2017: uncompressed index is no longer created, added CRC32 of zib (bin only) files, if present
24
  28 aug 2016: listing.txt is always written inside the repo dir (instead of inside current dir)
24
  28 aug 2016: listing.txt is always written inside the repo dir (instead of inside current dir)
25
  27 aug 2016: accepting full paths to repos (starting with /...)
25
  27 aug 2016: accepting full paths to repos (starting with /...)
26
  07 dec 2013: rewritten buildidx in ANSI C89
26
  07 dec 2013: rewritten buildidx in ANSI C89
27
  19 aug 2013: add a compressed version of the index file to repos (index.gz)
27
  19 aug 2013: add a compressed version of the index file to repos (index.gz)
28
  22 jul 2013: creating a listing.txt file with list of packages
28
  22 jul 2013: creating a listing.txt file with list of packages
29
  18 jul 2013: writing the number of packaged into the first line of the lst file
29
  18 jul 2013: writing the number of packaged into the first line of the lst file
30
  11 jul 2013: added a switch to 7za to make it case insensitive when extracting lsm files
30
  11 jul 2013: added a switch to 7za to make it case insensitive when extracting lsm files
31
  10 jul 2013: changed unzip calls to 7za (to handle cases when appinfo is compressed with lzma)
31
  10 jul 2013: changed unzip calls to 7za (to handle cases when appinfo is compressed with lzma)
32
  04 feb 2013: added CRC32 support
32
  04 feb 2013: added CRC32 support
33
  22 sep 2012: forked 1st version from FDUPDATE builder
33
  22 sep 2012: forked 1st version from FDUPDATE builder
34
*/
34
*/
35
 
35
 
36
$PVER = "20220221";
36
$PVER = "20220221";
37
 
37
 
38
 
38
 
39
// computes the BSD sum of a file and returns it
39
// computes the BSD sum of a file and returns it
40
function file2bsum($fname) {
40
function file2bsum($fname) {
41
  $result = 0;
41
  $result = 0;
42
 
42
 
43
  $fd = fopen($fname, 'rb');
43
  $fd = fopen($fname, 'rb');
44
  if ($fd === false) return(0);
44
  if ($fd === false) return(0);
45
 
45
 
46
  while (!feof($fd)) {
46
  while (!feof($fd)) {
47
 
47
 
48
    $buff = fread($fd, 1024 * 1024);
48
    $buff = fread($fd, 1024 * 1024);
49
 
49
 
50
    $slen = strlen($buff);
50
    $slen = strlen($buff);
51
    for ($i = 0; $i < $slen; $i++) {
51
    for ($i = 0; $i < $slen; $i++) {
52
      // rotr
52
      // rotr
53
      $result = ($result >> 1) | ($result << 15);
53
      $result = ($result >> 1) | ($result << 15);
54
      // add and truncate to 16 bits
54
      // add and truncate to 16 bits
55
      $result += ord($buff[$i]);
55
      $result += ord($buff[$i]);
56
      $result &= 0xffff;
56
      $result &= 0xffff;
57
    }
57
    }
58
  }
58
  }
59
 
59
 
60
  fclose($fd);
60
  fclose($fd);
61
  return($result);
61
  return($result);
62
}
62
}
63
 
63
 
64
 
64
 
65
// translates a version string into a array of integer values.
65
// translates a version string into a array of integer values.
66
// Accepted formats follow:
66
// Accepted formats follow:
67
//    300.12.1
67
//    300.12.1
68
//    1
68
//    1
69
//    12.2.34.2-4.5
69
//    12.2.34.2-4.5
70
//    1.2c
70
//    1.2c
71
//    1.01 beta+3
71
//    1.01 beta+3
72
//    2013-12-31
72
//    2013-12-31
73
//    20220222 alpha
73
//    20220222 alpha
74
function vertoarr($verstr) {
74
function vertoarr($verstr) {
75
  $subver = array(0,0,0,0);
75
  $subver = array(0,0,0,0);
76
 
76
 
77
  // switch string to lcase for easier processing and trim any leading or trailing white spaces
77
  // switch string to lcase for easier processing and trim any leading or trailing white spaces
78
  $verstr = strtolower(trim($verstr));
78
  $verstr = strtolower(trim($verstr));
79
 
79
 
80
  // replace all '-' and '/' characters to '.' (uniformization of sub-version parts delimiters)
80
  // replace all '-' and '/' characters to '.' (uniformization of sub-version parts delimiters)
81
  $verstr = strtr($verstr, '-/', '..');
81
  $verstr = strtr($verstr, '-/', '..');
82
 
82
 
83
  // is there a subversion value? (for example "+4" in "1.05+4")
83
  // is there a subversion value? (for example "+4" in "1.05+4")
84
  $i = strrpos($verstr, '+', 1);
84
  $i = strrpos($verstr, '+', 1);
85
  if ($i !== false) {
85
  if ($i !== false) {
86
    // validate the svar-version is a proper integer
86
    // validate the svar-version is a proper integer
87
    $svarver = substr($verstr, $i + 1);
87
    $svarver = substr($verstr, $i + 1);
88
    if (! preg_match('/[1-9][0-9]*/', $svarver)) {
88
    if (! preg_match('/[1-9][0-9]*/', $svarver)) {
89
      return(false);
89
      return(false);
90
    }
90
    }
91
    $subver[3] = intval($svarver); // set the +rev as a very minor item
91
    $subver[3] = intval($svarver); // set the +rev as a very minor item
92
    $verstr = substr($verstr, 0, $i);
92
    $verstr = substr($verstr, 0, $i);
93
  }
93
  }
94
 
94
 
95
  // is the version ending with ' alpha', 'beta'?
95
  // is the version ending with ' alpha', 'beta'?
96
  if (preg_match('/ (alpha|beta)$/', $verstr)) {
96
  if (preg_match('/ (alpha|beta)$/', $verstr)) {
97
    $i = strrpos($verstr, ' ');
97
    $i = strrpos($verstr, ' ');
98
    $greek = substr($verstr, $i + 1);
98
    $greek = substr($verstr, $i + 1);
99
    $verstr = trim(substr($verstr, 0, $i));
99
    $verstr = trim(substr($verstr, 0, $i));
100
    if ($greek == 'alpha') {
100
    if ($greek == 'alpha') {
101
      $subver[2] = 1;
101
      $subver[2] = 1;
102
    } else if ($greek == 'beta') {
102
    } else if ($greek == 'beta') {
103
      $subver[2] = 2;
103
      $subver[2] = 2;
-
 
104
    } else if ($greek == 'rc') {
-
 
105
      $subver[2] = 3;
104
    } else {
106
    } else {
105
      return(false);
107
      return(false);
106
    }
108
    }
-
 
109
  } else {
-
 
110
    $subver[2] = 99;
107
  }
111
  }
108
 
112
 
109
  // does the version string have a single-letter subversion? (1.0c)
113
  // does the version string have a single-letter subversion? (1.0c)
110
  if (preg_match('/[a-z]$/', $verstr)) {
114
  if (preg_match('/[a-z]$/', $verstr)) {
111
    $subver[1] = ord(substr($verstr, -1));
115
    $subver[1] = ord(substr($verstr, -1));
112
    $verstr = substr_replace($verstr, '', -1); // remove last character from string
116
    $verstr = substr_replace($verstr, '', -1); // remove last character from string
113
  }
117
  }
114
 
118
 
115
  // validate the format is supported, should be something no more complex than 1.05.3.33
119
  // validate the format is supported, should be something no more complex than 1.05.3.33
116
  if (! preg_match('/[0-9][0-9.]{0,20}/', $verstr)) {
120
  if (! preg_match('/[0-9][0-9.]{0,20}/', $verstr)) {
117
    return(false);
121
    return(false);
118
  }
122
  }
119
 
123
 
120
  // NOTE: a zero right after a separator and trailed with a digit (as in 1.01)
124
  // NOTE: a zero right after a separator and trailed with a digit (as in 1.01)
121
  //       has a special meaning
125
  //       has a special meaning
122
  $exploded = explode('.', $verstr);
126
  $exploded = explode('.', $verstr);
123
  if (count($exploded) > 16) {
127
  if (count($exploded) > 16) {
124
    return(false);
128
    return(false);
125
  }
129
  }
126
  $exploded[16] = $subver[0]; // unused yet
130
  $exploded[16] = $subver[0]; // unused yet
127
  $exploded[17] = $subver[1]; // a-z (1.0c)
131
  $exploded[17] = $subver[1]; // a-z (1.0c)
128
  $exploded[18] = $subver[2]; // alpha/beta
132
  $exploded[18] = $subver[2]; // alpha/beta
129
  $exploded[19] = $subver[3]; // svar-ver (1.0+5)
133
  $exploded[19] = $subver[3]; // svar-ver (1.0+5)
130
  for ($i = 0; $i < 20; $i++) if (empty($exploded[$i])) $exploded[$i] = '0';
134
  for ($i = 0; $i < 20; $i++) if (empty($exploded[$i])) $exploded[$i] = '0';
131
 
135
 
132
  ksort($exploded);
136
  ksort($exploded);
133
 
137
 
134
  return($exploded);
138
  return($exploded);
135
}
139
}
136
 
140
 
137
 
141
 
138
function dos_version_compare($v1, $v2) {
142
function dos_version_compare($v1, $v2) {
139
  $v1arr = vertoarr($v1);
143
  $v1arr = vertoarr($v1);
140
  $v2arr = vertoarr($v2);
144
  $v2arr = vertoarr($v2);
141
  for ($i = 0; $i < count($v1arr); $i++) {
145
  for ($i = 0; $i < count($v1arr); $i++) {
142
    $r = strcmp($v1arr[$i], $v2arr[$i]);
146
    $r = strcmp($v1arr[$i], $v2arr[$i]);
143
    if ($r != 0) return($r);
147
    if ($r != 0) return($r);
144
  }
148
  }
145
  return(0);
149
  return(0);
146
}
150
}
147
 
151
 
148
 
152
 
149
// reads file fil from zip archive z and returns its content, or false on error
153
// reads file fil from zip archive z and returns its content, or false on error
150
function read_file_from_zip($z, $fil) {
154
function read_file_from_zip($z, $fil) {
151
  $zip = new ZipArchive;
155
  $zip = new ZipArchive;
152
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
156
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
153
    echo "ERROR: failed to open zip file '{$z}'\n";
157
    echo "ERROR: failed to open zip file '{$z}'\n";
154
    return(false);
158
    return(false);
155
  }
159
  }
156
 
160
 
157
  // load the appinfo/pkgname.lsm file
161
  // load the appinfo/pkgname.lsm file
158
  $res = $zip->getFromName($fil, 8192, ZipArchive::FL_NOCASE);
162
  $res = $zip->getFromName($fil, 8192, ZipArchive::FL_NOCASE);
159
 
163
 
160
  $zip->close();
164
  $zip->close();
161
  return($res);
165
  return($res);
162
}
166
}
163
 
167
 
164
 
168
 
165
function read_list_of_files_in_zip($z) {
169
function read_list_of_files_in_zip($z) {
166
  $zip = new ZipArchive;
170
  $zip = new ZipArchive;
167
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
171
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
168
    echo "ERROR: failed to open zip file '{$z}'\n";
172
    echo "ERROR: failed to open zip file '{$z}'\n";
169
    return(false);
173
    return(false);
170
  }
174
  }
171
 
175
 
172
  $res = array();
176
  $res = array();
173
  for ($i = 0; $i < $zip->numFiles; $i++) $res[] = $zip->getNameIndex($i);
177
  for ($i = 0; $i < $zip->numFiles; $i++) $res[] = $zip->getNameIndex($i);
174
 
178
 
175
  $zip->close();
179
  $zip->close();
176
  return($res);
180
  return($res);
177
}
181
}
178
 
182
 
179
 
183
 
180
// reads a LSM string and returns it in the form of an array
184
// reads a LSM string and returns it in the form of an array
181
function parse_lsm($s) {
185
function parse_lsm($s) {
182
  $res = array();
186
  $res = array();
183
  for ($l = strtok($s, "\n"); $l !== false; $l = strtok("\n")) {
187
  for ($l = strtok($s, "\n"); $l !== false; $l = strtok("\n")) {
184
    // the line is "token: value", let's find the colon
188
    // the line is "token: value", let's find the colon
185
    $colpos = strpos($l, ':');
189
    $colpos = strpos($l, ':');
186
    if (($colpos === false) || ($colpos === 0)) continue;
190
    if (($colpos === false) || ($colpos === 0)) continue;
187
    $tok = strtolower(trim(substr($l, 0, $colpos)));
191
    $tok = strtolower(trim(substr($l, 0, $colpos)));
188
    $val = trim(substr($l, $colpos + 1));
192
    $val = trim(substr($l, $colpos + 1));
189
    $res[$tok] = $val;
193
    $res[$tok] = $val;
190
  }
194
  }
191
  return($res);
195
  return($res);
192
}
196
}
193
 
197
 
194
 
198
 
195
// on PHP 8+ there is str_starts_with(), but not on PHP 7 so I use this
199
// on PHP 8+ there is str_starts_with(), but not on PHP 7 so I use this
196
function str_head_is($haystack, $needle) {
200
function str_head_is($haystack, $needle) {
197
  return strpos($haystack, $needle) === 0;
201
  return strpos($haystack, $needle) === 0;
198
}
202
}
199
 
203
 
200
 
204
 
201
// returns an array that contains CORE packages (populated from the core subdirectory in pkgdir)
205
// returns an array that contains CORE packages (populated from the core subdirectory in pkgdir)
202
function load_core_list($repodir) {
206
function load_core_list($repodir) {
203
  $res = array();
207
  $res = array();
204
 
208
 
205
  foreach (scandir($repodir . '/core/') as $f) {
209
  foreach (scandir($repodir . '/core/') as $f) {
206
    if (!preg_match('/\.svp$/', $f)) continue;
210
    if (!preg_match('/\.svp$/', $f)) continue;
207
    $res[] = explode('.', $f)[0];
211
    $res[] = explode('.', $f)[0];
208
  }
212
  }
209
  return($res);
213
  return($res);
210
}
214
}
211
 
215
 
212
 
216
 
213
// ***************** MAIN ROUTINE *********************************************
217
// ***************** MAIN ROUTINE *********************************************
214
 
218
 
215
//echo "SvarDOS repository index generator ver {$PVER}\n";
219
//echo "SvarDOS repository index generator ver {$PVER}\n";
216
 
220
 
217
if (($_SERVER['argc'] != 2) || ($_SERVER['argv'][1][0] == '-')) {
221
if (($_SERVER['argc'] != 2) || ($_SERVER['argv'][1][0] == '-')) {
218
  echo "usage: php buildidx.php repodir\n";
222
  echo "usage: php buildidx.php repodir\n";
219
  exit(1);
223
  exit(1);
220
}
224
}
221
 
225
 
222
$repodir = $_SERVER['argv'][1];
226
$repodir = $_SERVER['argv'][1];
223
 
227
 
224
$pkgfiles = scandir($repodir);
228
$pkgfiles = scandir($repodir);
225
$pkgcount = 0;
229
$pkgcount = 0;
226
 
230
 
227
 
231
 
228
// load the list of CORE and MSDOS_COMPAT packages
232
// load the list of CORE and MSDOS_COMPAT packages
229
 
233
 
230
$core_packages_list = load_core_list($repodir);
234
$core_packages_list = load_core_list($repodir);
231
$msdos_compat_list = explode(' ', 'append assign attrib chkdsk choice command comp cpidos debug defrag deltree diskcomp diskcopy display edit edlin exe2bin fc fdapm fdisk find format help himemx kernel keyb label localcfg mem mirror mode more move nlsfunc print replace share shsucdx sort swsubst tree undelete unformat xcopy');
235
$msdos_compat_list = explode(' ', 'append assign attrib chkdsk choice command comp cpidos debug defrag deltree diskcomp diskcopy display edit edlin exe2bin fc fdapm fdisk find format help himemx kernel keyb label localcfg mem mirror mode more move nlsfunc print replace share shsucdx sort swsubst tree undelete unformat xcopy');
232
 
236
 
233
// do a list of all svp packages with their available versions and descriptions
237
// do a list of all svp packages with their available versions and descriptions
234
 
238
 
235
$pkgdb = array();
239
$pkgdb = array();
236
foreach ($pkgfiles as $fname) {
240
foreach ($pkgfiles as $fname) {
237
  if (!preg_match('/\.svp$/i', $fname)) continue; // skip non-svp files
241
  if (!preg_match('/\.svp$/i', $fname)) continue; // skip non-svp files
238
 
242
 
239
  if (!preg_match('/^[a-zA-Z0-9+. _-]*\.svp$/', $fname)) {
243
  if (!preg_match('/^[a-zA-Z0-9+. _-]*\.svp$/', $fname)) {
240
    echo "ERROR: {$fname} has a very weird name\n";
244
    echo "ERROR: {$fname} has a very weird name\n";
241
    continue;
245
    continue;
242
  }
246
  }
243
 
247
 
244
  $path_parts = pathinfo($fname);
248
  $path_parts = pathinfo($fname);
245
  $pkgnam = explode('-', $path_parts['filename'])[0];
249
  $pkgnam = explode('-', $path_parts['filename'])[0];
246
  $pkgfullpath = realpath($repodir . '/' . $fname);
250
  $pkgfullpath = realpath($repodir . '/' . $fname);
247
 
251
 
248
  $lsm = read_file_from_zip($pkgfullpath, "appinfo/{$pkgnam}.lsm");
252
  $lsm = read_file_from_zip($pkgfullpath, "appinfo/{$pkgnam}.lsm");
249
  if ($lsm == false) {
253
  if ($lsm == false) {
250
    echo "ERROR: {$fname} does not contain an LSM file at the expected location\n";
254
    echo "ERROR: {$fname} does not contain an LSM file at the expected location\n";
251
    continue;
255
    continue;
252
  }
256
  }
253
  $lsmarray = parse_lsm($lsm);
257
  $lsmarray = parse_lsm($lsm);
254
  if (empty($lsmarray['version'])) {
258
  if (empty($lsmarray['version'])) {
255
    echo "ERROR: lsm file in {$fname} does not contain a version\n";
259
    echo "ERROR: lsm file in {$fname} does not contain a version\n";
256
    continue;
260
    continue;
257
  }
261
  }
258
  if (strlen($lsmarray['version']) > 16) {
262
  if (strlen($lsmarray['version']) > 16) {
259
    echo "ERROR: version string in lsm file of {$fname} is too long (16 chars max)\n";
263
    echo "ERROR: version string in lsm file of {$fname} is too long (16 chars max)\n";
260
    continue;
264
    continue;
261
  }
265
  }
262
  if (empty($lsmarray['description'])) {
266
  if (empty($lsmarray['description'])) {
263
    echo "ERROR: lsm file in {$fname} does not contain a description\n";
267
    echo "ERROR: lsm file in {$fname} does not contain a description\n";
264
    continue;
268
    continue;
265
  }
269
  }
266
 
270
 
267
  // validate the files present in the archive
271
  // validate the files present in the archive
268
  $listoffiles = read_list_of_files_in_zip($pkgfullpath);
272
  $listoffiles = read_list_of_files_in_zip($pkgfullpath);
269
  $pkgdir = $pkgnam;
273
  $pkgdir = $pkgnam;
270
 
274
 
271
  // special rule for "parent and children" packages
275
  // special rule for "parent and children" packages
272
  if (str_head_is($pkgnam, 'djgpp_')) $pkgdir = 'djgpp'; // djgpp_* packages put their files in djgpp
276
  if (str_head_is($pkgnam, 'djgpp_')) $pkgdir = 'djgpp'; // djgpp_* packages put their files in djgpp
273
  if ($pkgnam == 'fbc_help') $pkgdir = 'fbc'; // FreeBASIC help goes to the FreeBASIC dir
277
  if ($pkgnam == 'fbc_help') $pkgdir = 'fbc'; // FreeBASIC help goes to the FreeBASIC dir
274
  if ($pkgnam == 'clamdb') $pkgdir = 'clamav'; // data patterns for clamav
278
  if ($pkgnam == 'clamdb') $pkgdir = 'clamav'; // data patterns for clamav
275
 
279
 
276
  // array used to detect duplicated entries after lower-case conversion
280
  // array used to detect duplicated entries after lower-case conversion
277
  $duparr = array();
281
  $duparr = array();
278
 
282
 
279
  // will hold the list of categories that this package belongs to
283
  // will hold the list of categories that this package belongs to
280
  $catlist = array();
284
  $catlist = array();
281
 
285
 
282
  foreach ($listoffiles as $f) {
286
  foreach ($listoffiles as $f) {
283
    $f = strtolower($f);
287
    $f = strtolower($f);
284
    $path_array = explode('/', $f);
288
    $path_array = explode('/', $f);
285
    // emit a warning when non-8+3 filenames are spotted and find duplicates
289
    // emit a warning when non-8+3 filenames are spotted and find duplicates
286
    foreach ($path_array as $item) {
290
    foreach ($path_array as $item) {
287
      if (empty($item)) continue; // skip empty items at end of paths (eg. appinfo/)
291
      if (empty($item)) continue; // skip empty items at end of paths (eg. appinfo/)
288
      if (!preg_match("/[a-z0-9!#$%&'()@^_`{}~-]{1,8}(\.[a-z0-9!#$%&'()@^_`{}~-]{1,3}){0,1}/", $item)) {
292
      if (!preg_match("/[a-z0-9!#$%&'()@^_`{}~-]{1,8}(\.[a-z0-9!#$%&'()@^_`{}~-]{1,3}){0,1}/", $item)) {
289
        echo "WARNING: {$fname} contains a non-8+3 path (or weird char): {$item} (in $f)\n";
293
        echo "WARNING: {$fname} contains a non-8+3 path (or weird char): {$item} (in $f)\n";
290
      }
294
      }
291
    }
295
    }
292
    // look for dups
296
    // look for dups
293
    if (array_search($f, $duparr) !== false) {
297
    if (array_search($f, $duparr) !== false) {
294
      echo "WARNING: {$fname} contains a duplicated entry: '{$f}'\n";
298
      echo "WARNING: {$fname} contains a duplicated entry: '{$f}'\n";
295
    } else {
299
    } else {
296
      $duparr[] = $f;
300
      $duparr[] = $f;
297
    }
301
    }
298
    // LSM file is ok
302
    // LSM file is ok
299
    if ($f === "appinfo/{$pkgnam}.lsm") continue;
303
    if ($f === "appinfo/{$pkgnam}.lsm") continue;
300
    if ($f === "appinfo/") continue;
304
    if ($f === "appinfo/") continue;
301
    // CORE and MSDOS_COMPAT packages are premium citizens and can do a little more
305
    // CORE and MSDOS_COMPAT packages are premium citizens and can do a little more
302
    $core_or_msdoscompat = 0;
306
    $core_or_msdoscompat = 0;
303
    if (array_search($pkgnam, $core_packages_list) !== false) {
307
    if (array_search($pkgnam, $core_packages_list) !== false) {
304
      $catlist[] = 'core';
308
      $catlist[] = 'core';
305
      $core_or_msdoscompat = 1;
309
      $core_or_msdoscompat = 1;
306
    }
310
    }
307
    if (array_search($pkgnam, $msdos_compat_list) !== false) {
311
    if (array_search($pkgnam, $msdos_compat_list) !== false) {
308
      $catlist[] = 'msdos_compat';
312
      $catlist[] = 'msdos_compat';
309
      $core_or_msdoscompat = 1;
313
      $core_or_msdoscompat = 1;
310
    }
314
    }
311
    if ($core_or_msdoscompat == 1) {
315
    if ($core_or_msdoscompat == 1) {
312
      if (str_head_is($f, 'bin/')) continue;
316
      if (str_head_is($f, 'bin/')) continue;
313
      if (str_head_is($f, 'cpi/')) continue;
317
      if (str_head_is($f, 'cpi/')) continue;
314
      if (str_head_is($f, "doc/{$pkgdir}/")) continue;
318
      if (str_head_is($f, "doc/{$pkgdir}/")) continue;
315
      if ($f === 'doc/') continue;
319
      if ($f === 'doc/') continue;
316
      if (str_head_is($f, "nls/{$pkgdir}.")) continue;
320
      if (str_head_is($f, "nls/{$pkgdir}.")) continue;
317
      if ($f === 'nls/') continue;
321
      if ($f === 'nls/') continue;
318
    }
322
    }
319
    // the help package is allowed to put files in... help
323
    // the help package is allowed to put files in... help
320
    if (($pkgnam == 'help') && (str_head_is($f, 'help/'))) continue;
324
    if (($pkgnam == 'help') && (str_head_is($f, 'help/'))) continue;
321
    // must be category-prefixed file, add it to the list of categories for this package
325
    // must be category-prefixed file, add it to the list of categories for this package
322
    $catlist[] = explode('/', $f)[0];
326
    $catlist[] = explode('/', $f)[0];
323
    // well-known "category" dirs are okay
327
    // well-known "category" dirs are okay
324
    if (str_head_is($f, "progs/{$pkgdir}/")) continue;
328
    if (str_head_is($f, "progs/{$pkgdir}/")) continue;
325
    if ($f === 'progs/') continue;
329
    if ($f === 'progs/') continue;
326
    if (str_head_is($f, "devel/{$pkgdir}/")) continue;
330
    if (str_head_is($f, "devel/{$pkgdir}/")) continue;
327
    if ($f === 'devel/') continue;
331
    if ($f === 'devel/') continue;
328
    if (str_head_is($f, "games/{$pkgdir}/")) continue;
332
    if (str_head_is($f, "games/{$pkgdir}/")) continue;
329
    if ($f === 'games/') continue;
333
    if ($f === 'games/') continue;
330
    if (str_head_is($f, "drivers/{$pkgdir}/")) continue;
334
    if (str_head_is($f, "drivers/{$pkgdir}/")) continue;
331
    if ($f === 'drivers/') continue;
335
    if ($f === 'drivers/') continue;
332
    echo "WARNING: {$fname} contains a file in an illegal location: {$f}\n";
336
    echo "WARNING: {$fname} contains a file in an illegal location: {$f}\n";
333
  }
337
  }
334
 
338
 
335
  // do I understand the version string?
339
  // do I understand the version string?
336
  if (vertoarr($lsmarray['version']) === false) echo "WARNING: {$fname} parsing of version string failed ('{$lsmarray['version']}')\n";
340
  if (vertoarr($lsmarray['version']) === false) echo "WARNING: {$fname} parsing of version string failed ('{$lsmarray['version']}')\n";
337
 
341
 
338
  $meta['fname'] = $fname;
342
  $meta['fname'] = $fname;
339
  $meta['desc'] = $lsmarray['description'];
343
  $meta['desc'] = $lsmarray['description'];
340
  $meta['cats'] = array_unique($catlist);
344
  $meta['cats'] = array_unique($catlist);
341
 
345
 
342
  $pkgdb[$pkgnam][$lsmarray['version']] = $meta;
346
  $pkgdb[$pkgnam][$lsmarray['version']] = $meta;
343
}
347
}
344
 
348
 
345
 
349
 
346
$db = array();
350
$db = array();
347
$cats = array();
351
$cats = array();
348
 
352
 
349
// ******** compute the version-sorted list of packages with a single *********
353
// ******** compute the version-sorted list of packages with a single *********
350
// ******** description and category list for each package ********************
354
// ******** description and category list for each package ********************
351
 
355
 
352
// iterate over each svp package
356
// iterate over each svp package
353
foreach ($pkgdb as $pkg => $versions) {
357
foreach ($pkgdb as $pkg => $versions) {
354
 
358
 
355
  // sort filenames by version, highest first
359
  // sort filenames by version, highest first
356
  uksort($versions, "dos_version_compare");
360
  uksort($versions, "dos_version_compare");
357
  $versions = array_reverse($versions, true);
361
  $versions = array_reverse($versions, true);
358
 
362
 
359
  foreach ($versions as $ver => $meta) {
363
  foreach ($versions as $ver => $meta) {
360
    $fname = $meta['fname'];
364
    $fname = $meta['fname'];
361
    $desc = $meta['desc'];
365
    $desc = $meta['desc'];
362
 
366
 
363
    $bsum = file2bsum(realpath($repodir . '/' . $fname));
367
    $bsum = file2bsum(realpath($repodir . '/' . $fname));
364
 
368
 
365
    $meta2['ver'] = strval($ver);
369
    $meta2['ver'] = strval($ver);
366
    $meta2['bsum'] = $bsum;
370
    $meta2['bsum'] = $bsum;
367
 
371
 
368
    if (empty($db[$pkg]['desc'])) $db[$pkg]['desc'] = $desc;
372
    if (empty($db[$pkg]['desc'])) $db[$pkg]['desc'] = $desc;
369
    if (empty($db[$pkg]['cats'])) {
373
    if (empty($db[$pkg]['cats'])) {
370
      $db[$pkg]['cats'] = $meta['cats'];
374
      $db[$pkg]['cats'] = $meta['cats'];
371
      $cats = array_unique(array_merge($cats, $meta['cats']));
375
      $cats = array_unique(array_merge($cats, $meta['cats']));
372
    }
376
    }
373
    $db[$pkg]['versions'][$fname] = $meta2;
377
    $db[$pkg]['versions'][$fname] = $meta2;
374
  }
378
  }
375
 
379
 
376
  $pkgcount++;
380
  $pkgcount++;
377
 
381
 
378
}
382
}
379
 
383
 
380
if ($pkgcount < 100) echo "WARNING: an unexpectedly low number of packages has been found in the repo ({$pkgcount})\n";
384
if ($pkgcount < 100) echo "WARNING: an unexpectedly low number of packages has been found in the repo ({$pkgcount})\n";
381
 
385
 
382
$json_blob = json_encode($db);
386
$json_blob = json_encode($db);
383
if ($json_blob === false) {
387
if ($json_blob === false) {
384
  echo "ERROR: JSON convertion failed! -> ";
388
  echo "ERROR: JSON convertion failed! -> ";
385
  switch (json_last_error()) {
389
  switch (json_last_error()) {
386
    case JSON_ERROR_DEPTH:
390
    case JSON_ERROR_DEPTH:
387
      echo 'maximum stack depth exceeded';
391
      echo 'maximum stack depth exceeded';
388
      break;
392
      break;
389
    case JSON_ERROR_STATE_MISMATCH:
393
    case JSON_ERROR_STATE_MISMATCH:
390
      echo 'underflow of the modes mismatch';
394
      echo 'underflow of the modes mismatch';
391
      break;
395
      break;
392
    case JSON_ERROR_CTRL_CHAR:
396
    case JSON_ERROR_CTRL_CHAR:
393
      echo 'unexpected control character found';
397
      echo 'unexpected control character found';
394
      break;
398
      break;
395
    case JSON_ERROR_UTF8:
399
    case JSON_ERROR_UTF8:
396
      echo 'malformed utf-8 characters';
400
      echo 'malformed utf-8 characters';
397
      break;
401
      break;
398
    default:
402
    default:
399
      echo "unknown error";
403
      echo "unknown error";
400
      break;
404
      break;
401
  }
405
  }
402
  echo "\n";
406
  echo "\n";
403
}
407
}
404
 
408
 
405
file_put_contents($repodir . '/_index.json', $json_blob);
409
file_put_contents($repodir . '/_index.json', $json_blob);
406
 
410
 
407
$cats_json = json_encode($cats);
411
$cats_json = json_encode($cats);
408
file_put_contents($repodir . '/_cats.json', $cats_json);
412
file_put_contents($repodir . '/_cats.json', $cats_json);
409
 
413
 
410
exit(0);
414
exit(0);
411
 
415
 
412
?>
416
?>
413
 
417