Subversion Repositories SvarDOS

Rev

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

Rev 919 Rev 920
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') {
104
    } else if ($greek == 'gamma') {
105
      $subver[2] = 3;
105
      $subver[2] = 3;
-
 
106
    } else if ($greek == 'delta') {
-
 
107
      $subver[2] = 4;
-
 
108
    } else if ($greek == 'rc') {
-
 
109
      $subver[2] = 5;
106
    } else {
110
    } else {
107
      return(false);
111
      return(false);
108
    }
112
    }
109
  } else {
113
  } else {
110
    $subver[2] = 99;
114
    $subver[2] = 99;
111
  }
115
  }
112
 
116
 
113
  // does the version string have a single-letter subversion? (1.0c)
117
  // does the version string have a single-letter subversion? (1.0c)
114
  if (preg_match('/[a-z]$/', $verstr)) {
118
  if (preg_match('/[a-z]$/', $verstr)) {
115
    $subver[1] = ord(substr($verstr, -1));
119
    $subver[1] = ord(substr($verstr, -1));
116
    $verstr = substr_replace($verstr, '', -1); // remove last character from string
120
    $verstr = substr_replace($verstr, '', -1); // remove last character from string
117
  }
121
  }
118
 
122
 
119
  // validate the format is supported, should be something no more complex than 1.05.3.33
123
  // validate the format is supported, should be something no more complex than 1.05.3.33
120
  if (! preg_match('/^[0-9][0-9.]{0,20}$/', $verstr)) {
124
  if (! preg_match('/^[0-9][0-9.]{0,20}$/', $verstr)) {
121
    return(false);
125
    return(false);
122
  }
126
  }
123
 
127
 
124
  // NOTE: a zero right after a separator and trailed with a digit (as in 1.01)
128
  // NOTE: a zero right after a separator and trailed with a digit (as in 1.01)
125
  //       has a special meaning
129
  //       has a special meaning
126
  $exploded = explode('.', $verstr);
130
  $exploded = explode('.', $verstr);
127
  if (count($exploded) > 16) {
131
  if (count($exploded) > 16) {
128
    return(false);
132
    return(false);
129
  }
133
  }
130
  $exploded[16] = $subver[0]; // unused yet
134
  $exploded[16] = $subver[0]; // unused yet
131
  $exploded[17] = $subver[1]; // a-z (1.0c)
135
  $exploded[17] = $subver[1]; // a-z (1.0c)
132
  $exploded[18] = $subver[2]; // alpha/beta
136
  $exploded[18] = $subver[2]; // alpha/beta
133
  $exploded[19] = $subver[3]; // svar-ver (1.0+5)
137
  $exploded[19] = $subver[3]; // svar-ver (1.0+5)
134
  for ($i = 0; $i < 20; $i++) if (empty($exploded[$i])) $exploded[$i] = '0';
138
  for ($i = 0; $i < 20; $i++) if (empty($exploded[$i])) $exploded[$i] = '0';
135
 
139
 
136
  ksort($exploded);
140
  ksort($exploded);
137
 
141
 
138
  return($exploded);
142
  return($exploded);
139
}
143
}
140
 
144
 
141
 
145
 
142
function dos_version_compare($v1, $v2) {
146
function dos_version_compare($v1, $v2) {
143
  $v1arr = vertoarr($v1);
147
  $v1arr = vertoarr($v1);
144
  $v2arr = vertoarr($v2);
148
  $v2arr = vertoarr($v2);
145
  for ($i = 0; $i < count($v1arr); $i++) {
149
  for ($i = 0; $i < count($v1arr); $i++) {
146
    $r = strcmp($v1arr[$i], $v2arr[$i]);
150
    $r = strcmp($v1arr[$i], $v2arr[$i]);
147
    if ($r != 0) return($r);
151
    if ($r != 0) return($r);
148
  }
152
  }
149
  return(0);
153
  return(0);
150
}
154
}
151
 
155
 
152
 
156
 
153
// reads file fil from zip archive z and returns its content, or false on error
157
// reads file fil from zip archive z and returns its content, or false on error
154
function read_file_from_zip($z, $fil) {
158
function read_file_from_zip($z, $fil) {
155
  $zip = new ZipArchive;
159
  $zip = new ZipArchive;
156
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
160
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
157
    echo "ERROR: failed to open zip file '{$z}'\n";
161
    echo "ERROR: failed to open zip file '{$z}'\n";
158
    return(false);
162
    return(false);
159
  }
163
  }
160
 
164
 
161
  // load the appinfo/pkgname.lsm file
165
  // load the appinfo/pkgname.lsm file
162
  $res = $zip->getFromName($fil, 8192, ZipArchive::FL_NOCASE);
166
  $res = $zip->getFromName($fil, 8192, ZipArchive::FL_NOCASE);
163
 
167
 
164
  $zip->close();
168
  $zip->close();
165
  return($res);
169
  return($res);
166
}
170
}
167
 
171
 
168
 
172
 
169
function read_list_of_files_in_zip($z) {
173
function read_list_of_files_in_zip($z) {
170
  $zip = new ZipArchive;
174
  $zip = new ZipArchive;
171
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
175
  if ($zip->open($z, ZipArchive::RDONLY) !== true) {
172
    echo "ERROR: failed to open zip file '{$z}'\n";
176
    echo "ERROR: failed to open zip file '{$z}'\n";
173
    return(false);
177
    return(false);
174
  }
178
  }
175
 
179
 
176
  $res = array();
180
  $res = array();
177
  for ($i = 0; $i < $zip->numFiles; $i++) $res[] = $zip->getNameIndex($i);
181
  for ($i = 0; $i < $zip->numFiles; $i++) $res[] = $zip->getNameIndex($i);
178
 
182
 
179
  $zip->close();
183
  $zip->close();
180
  return($res);
184
  return($res);
181
}
185
}
182
 
186
 
183
 
187
 
184
// reads a LSM string and returns it in the form of an array
188
// reads a LSM string and returns it in the form of an array
185
function parse_lsm($s) {
189
function parse_lsm($s) {
186
  $res = array();
190
  $res = array();
187
  for ($l = strtok($s, "\n"); $l !== false; $l = strtok("\n")) {
191
  for ($l = strtok($s, "\n"); $l !== false; $l = strtok("\n")) {
188
    // the line is "token: value", let's find the colon
192
    // the line is "token: value", let's find the colon
189
    $colpos = strpos($l, ':');
193
    $colpos = strpos($l, ':');
190
    if (($colpos === false) || ($colpos === 0)) continue;
194
    if (($colpos === false) || ($colpos === 0)) continue;
191
    $tok = strtolower(trim(substr($l, 0, $colpos)));
195
    $tok = strtolower(trim(substr($l, 0, $colpos)));
192
    $val = trim(substr($l, $colpos + 1));
196
    $val = trim(substr($l, $colpos + 1));
193
    $res[$tok] = $val;
197
    $res[$tok] = $val;
194
  }
198
  }
195
  return($res);
199
  return($res);
196
}
200
}
197
 
201
 
198
 
202
 
199
// on PHP 8+ there is str_starts_with(), but not on PHP 7 so I use this
203
// on PHP 8+ there is str_starts_with(), but not on PHP 7 so I use this
200
function str_head_is($haystack, $needle) {
204
function str_head_is($haystack, $needle) {
201
  return strpos($haystack, $needle) === 0;
205
  return strpos($haystack, $needle) === 0;
202
}
206
}
203
 
207
 
204
 
208
 
205
// returns an array that contains CORE packages (populated from the core subdirectory in pkgdir)
209
// returns an array that contains CORE packages (populated from the core subdirectory in pkgdir)
206
function load_core_list($repodir) {
210
function load_core_list($repodir) {
207
  $res = array();
211
  $res = array();
208
 
212
 
209
  foreach (scandir($repodir . '/core/') as $f) {
213
  foreach (scandir($repodir . '/core/') as $f) {
210
    if (!preg_match('/\.svp$/', $f)) continue;
214
    if (!preg_match('/\.svp$/', $f)) continue;
211
    $res[] = explode('.', $f)[0];
215
    $res[] = explode('.', $f)[0];
212
  }
216
  }
213
  return($res);
217
  return($res);
214
}
218
}
215
 
219
 
216
 
220
 
217
// ***************** MAIN ROUTINE *********************************************
221
// ***************** MAIN ROUTINE *********************************************
218
 
222
 
219
//echo "SvarDOS repository index generator ver {$PVER}\n";
223
//echo "SvarDOS repository index generator ver {$PVER}\n";
220
 
224
 
221
if (($_SERVER['argc'] != 2) || ($_SERVER['argv'][1][0] == '-')) {
225
if (($_SERVER['argc'] != 2) || ($_SERVER['argv'][1][0] == '-')) {
222
  echo "usage: php buildidx.php repodir\n";
226
  echo "usage: php buildidx.php repodir\n";
223
  exit(1);
227
  exit(1);
224
}
228
}
225
 
229
 
226
$repodir = $_SERVER['argv'][1];
230
$repodir = $_SERVER['argv'][1];
227
 
231
 
228
$pkgfiles = scandir($repodir);
232
$pkgfiles = scandir($repodir);
229
$pkgcount = 0;
233
$pkgcount = 0;
230
 
234
 
231
 
235
 
232
// load the list of CORE and MSDOS_COMPAT packages
236
// load the list of CORE and MSDOS_COMPAT packages
233
 
237
 
234
$core_packages_list = load_core_list($repodir);
238
$core_packages_list = load_core_list($repodir);
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');
239
$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');
236
 
240
 
237
// do a list of all svp packages with their available versions and descriptions
241
// do a list of all svp packages with their available versions and descriptions
238
 
242
 
239
$pkgdb = array();
243
$pkgdb = array();
240
foreach ($pkgfiles as $fname) {
244
foreach ($pkgfiles as $fname) {
241
  if (!preg_match('/\.svp$/i', $fname)) continue; // skip non-svp files
245
  if (!preg_match('/\.svp$/i', $fname)) continue; // skip non-svp files
242
 
246
 
243
  if (!preg_match('/^[a-zA-Z0-9+. _-]*\.svp$/', $fname)) {
247
  if (!preg_match('/^[a-zA-Z0-9+. _-]*\.svp$/', $fname)) {
244
    echo "ERROR: {$fname} has a very weird name\n";
248
    echo "ERROR: {$fname} has a very weird name\n";
245
    continue;
249
    continue;
246
  }
250
  }
247
 
251
 
248
  $path_parts = pathinfo($fname);
252
  $path_parts = pathinfo($fname);
249
  $pkgnam = explode('-', $path_parts['filename'])[0];
253
  $pkgnam = explode('-', $path_parts['filename'])[0];
250
  $pkgfullpath = realpath($repodir . '/' . $fname);
254
  $pkgfullpath = realpath($repodir . '/' . $fname);
251
 
255
 
252
  $lsm = read_file_from_zip($pkgfullpath, "appinfo/{$pkgnam}.lsm");
256
  $lsm = read_file_from_zip($pkgfullpath, "appinfo/{$pkgnam}.lsm");
253
  if ($lsm == false) {
257
  if ($lsm == false) {
254
    echo "ERROR: {$fname} does not contain an LSM file at the expected location\n";
258
    echo "ERROR: {$fname} does not contain an LSM file at the expected location\n";
255
    continue;
259
    continue;
256
  }
260
  }
257
  $lsmarray = parse_lsm($lsm);
261
  $lsmarray = parse_lsm($lsm);
258
  if (empty($lsmarray['version'])) {
262
  if (empty($lsmarray['version'])) {
259
    echo "ERROR: lsm file in {$fname} does not contain a version\n";
263
    echo "ERROR: lsm file in {$fname} does not contain a version\n";
260
    continue;
264
    continue;
261
  }
265
  }
262
  if (strlen($lsmarray['version']) > 16) {
266
  if (strlen($lsmarray['version']) > 16) {
263
    echo "ERROR: version string in lsm file of {$fname} is too long (16 chars max)\n";
267
    echo "ERROR: version string in lsm file of {$fname} is too long (16 chars max)\n";
264
    continue;
268
    continue;
265
  }
269
  }
266
  if (empty($lsmarray['description'])) {
270
  if (empty($lsmarray['description'])) {
267
    echo "ERROR: lsm file in {$fname} does not contain a description\n";
271
    echo "ERROR: lsm file in {$fname} does not contain a description\n";
268
    continue;
272
    continue;
269
  }
273
  }
270
 
274
 
271
  // validate the files present in the archive
275
  // validate the files present in the archive
272
  $listoffiles = read_list_of_files_in_zip($pkgfullpath);
276
  $listoffiles = read_list_of_files_in_zip($pkgfullpath);
273
  $pkgdir = $pkgnam;
277
  $pkgdir = $pkgnam;
274
 
278
 
275
  // special rule for "parent and children" packages
279
  // special rule for "parent and children" packages
276
  if (str_head_is($pkgnam, 'djgpp_')) $pkgdir = 'djgpp'; // djgpp_* packages put their files in djgpp
280
  if (str_head_is($pkgnam, 'djgpp_')) $pkgdir = 'djgpp'; // djgpp_* packages put their files in djgpp
277
  if ($pkgnam == 'fbc_help') $pkgdir = 'fbc'; // FreeBASIC help goes to the FreeBASIC dir
281
  if ($pkgnam == 'fbc_help') $pkgdir = 'fbc'; // FreeBASIC help goes to the FreeBASIC dir
278
  if ($pkgnam == 'clamdb') $pkgdir = 'clamav'; // data patterns for clamav
282
  if ($pkgnam == 'clamdb') $pkgdir = 'clamav'; // data patterns for clamav
279
 
283
 
280
  // array used to detect duplicated entries after lower-case conversion
284
  // array used to detect duplicated entries after lower-case conversion
281
  $duparr = array();
285
  $duparr = array();
282
 
286
 
283
  // will hold the list of categories that this package belongs to
287
  // will hold the list of categories that this package belongs to
284
  $catlist = array();
288
  $catlist = array();
285
 
289
 
286
  foreach ($listoffiles as $f) {
290
  foreach ($listoffiles as $f) {
287
    $f = strtolower($f);
291
    $f = strtolower($f);
288
    $path_array = explode('/', $f);
292
    $path_array = explode('/', $f);
289
    // emit a warning when non-8+3 filenames are spotted and find duplicates
293
    // emit a warning when non-8+3 filenames are spotted and find duplicates
290
    foreach ($path_array as $item) {
294
    foreach ($path_array as $item) {
291
      if (empty($item)) continue; // skip empty items at end of paths (eg. appinfo/)
295
      if (empty($item)) continue; // skip empty items at end of paths (eg. appinfo/)
292
      if (!preg_match("/[a-z0-9!#$%&'()@^_`{}~-]{1,8}(\.[a-z0-9!#$%&'()@^_`{}~-]{1,3}){0,1}/", $item)) {
296
      if (!preg_match("/[a-z0-9!#$%&'()@^_`{}~-]{1,8}(\.[a-z0-9!#$%&'()@^_`{}~-]{1,3}){0,1}/", $item)) {
293
        echo "WARNING: {$fname} contains a non-8+3 path (or weird char): {$item} (in $f)\n";
297
        echo "WARNING: {$fname} contains a non-8+3 path (or weird char): {$item} (in $f)\n";
294
      }
298
      }
295
    }
299
    }
296
    // look for dups
300
    // look for dups
297
    if (array_search($f, $duparr) !== false) {
301
    if (array_search($f, $duparr) !== false) {
298
      echo "WARNING: {$fname} contains a duplicated entry: '{$f}'\n";
302
      echo "WARNING: {$fname} contains a duplicated entry: '{$f}'\n";
299
    } else {
303
    } else {
300
      $duparr[] = $f;
304
      $duparr[] = $f;
301
    }
305
    }
302
    // LSM file is ok
306
    // LSM file is ok
303
    if ($f === "appinfo/{$pkgnam}.lsm") continue;
307
    if ($f === "appinfo/{$pkgnam}.lsm") continue;
304
    if ($f === "appinfo/") continue;
308
    if ($f === "appinfo/") continue;
305
    // CORE and MSDOS_COMPAT packages are premium citizens and can do a little more
309
    // CORE and MSDOS_COMPAT packages are premium citizens and can do a little more
306
    $core_or_msdoscompat = 0;
310
    $core_or_msdoscompat = 0;
307
    if (array_search($pkgnam, $core_packages_list) !== false) {
311
    if (array_search($pkgnam, $core_packages_list) !== false) {
308
      $catlist[] = 'core';
312
      $catlist[] = 'core';
309
      $core_or_msdoscompat = 1;
313
      $core_or_msdoscompat = 1;
310
    }
314
    }
311
    if (array_search($pkgnam, $msdos_compat_list) !== false) {
315
    if (array_search($pkgnam, $msdos_compat_list) !== false) {
312
      $catlist[] = 'msdos_compat';
316
      $catlist[] = 'msdos_compat';
313
      $core_or_msdoscompat = 1;
317
      $core_or_msdoscompat = 1;
314
    }
318
    }
315
    if ($core_or_msdoscompat == 1) {
319
    if ($core_or_msdoscompat == 1) {
316
      if (str_head_is($f, 'bin/')) continue;
320
      if (str_head_is($f, 'bin/')) continue;
317
      if (str_head_is($f, 'cpi/')) continue;
321
      if (str_head_is($f, 'cpi/')) continue;
318
      if (str_head_is($f, "doc/{$pkgdir}/")) continue;
322
      if (str_head_is($f, "doc/{$pkgdir}/")) continue;
319
      if ($f === 'doc/') continue;
323
      if ($f === 'doc/') continue;
320
      if (str_head_is($f, "nls/{$pkgdir}.")) continue;
324
      if (str_head_is($f, "nls/{$pkgdir}.")) continue;
321
      if ($f === 'nls/') continue;
325
      if ($f === 'nls/') continue;
322
    }
326
    }
323
    // the help package is allowed to put files in... help
327
    // the help package is allowed to put files in... help
324
    if (($pkgnam == 'help') && (str_head_is($f, 'help/'))) continue;
328
    if (($pkgnam == 'help') && (str_head_is($f, 'help/'))) continue;
325
    // must be category-prefixed file, add it to the list of categories for this package
329
    // must be category-prefixed file, add it to the list of categories for this package
326
    $catlist[] = explode('/', $f)[0];
330
    $catlist[] = explode('/', $f)[0];
327
    // well-known "category" dirs are okay
331
    // well-known "category" dirs are okay
328
    if (str_head_is($f, "progs/{$pkgdir}/")) continue;
332
    if (str_head_is($f, "progs/{$pkgdir}/")) continue;
329
    if ($f === 'progs/') continue;
333
    if ($f === 'progs/') continue;
330
    if (str_head_is($f, "devel/{$pkgdir}/")) continue;
334
    if (str_head_is($f, "devel/{$pkgdir}/")) continue;
331
    if ($f === 'devel/') continue;
335
    if ($f === 'devel/') continue;
332
    if (str_head_is($f, "games/{$pkgdir}/")) continue;
336
    if (str_head_is($f, "games/{$pkgdir}/")) continue;
333
    if ($f === 'games/') continue;
337
    if ($f === 'games/') continue;
334
    if (str_head_is($f, "drivers/{$pkgdir}/")) continue;
338
    if (str_head_is($f, "drivers/{$pkgdir}/")) continue;
335
    if ($f === 'drivers/') continue;
339
    if ($f === 'drivers/') continue;
336
    echo "WARNING: {$fname} contains a file in an illegal location: {$f}\n";
340
    echo "WARNING: {$fname} contains a file in an illegal location: {$f}\n";
337
  }
341
  }
338
 
342
 
339
  // do I understand the version string?
343
  // do I understand the version string?
340
  if (vertoarr($lsmarray['version']) === false) echo "WARNING: {$fname} parsing of version string failed ('{$lsmarray['version']}')\n";
344
  if (vertoarr($lsmarray['version']) === false) echo "WARNING: {$fname} parsing of version string failed ('{$lsmarray['version']}')\n";
341
 
345
 
342
  $meta['fname'] = $fname;
346
  $meta['fname'] = $fname;
343
  $meta['desc'] = $lsmarray['description'];
347
  $meta['desc'] = $lsmarray['description'];
344
  $meta['cats'] = array_unique($catlist);
348
  $meta['cats'] = array_unique($catlist);
345
 
349
 
346
  $pkgdb[$pkgnam][$lsmarray['version']] = $meta;
350
  $pkgdb[$pkgnam][$lsmarray['version']] = $meta;
347
}
351
}
348
 
352
 
349
 
353
 
350
$db = array();
354
$db = array();
351
$cats = array();
355
$cats = array();
352
 
356
 
353
// ******** compute the version-sorted list of packages with a single *********
357
// ******** compute the version-sorted list of packages with a single *********
354
// ******** description and category list for each package ********************
358
// ******** description and category list for each package ********************
355
 
359
 
356
// iterate over each svp package
360
// iterate over each svp package
357
foreach ($pkgdb as $pkg => $versions) {
361
foreach ($pkgdb as $pkg => $versions) {
358
 
362
 
359
  // sort filenames by version, highest first
363
  // sort filenames by version, highest first
360
  uksort($versions, "dos_version_compare");
364
  uksort($versions, "dos_version_compare");
361
  $versions = array_reverse($versions, true);
365
  $versions = array_reverse($versions, true);
362
 
366
 
363
  foreach ($versions as $ver => $meta) {
367
  foreach ($versions as $ver => $meta) {
364
    $fname = $meta['fname'];
368
    $fname = $meta['fname'];
365
    $desc = $meta['desc'];
369
    $desc = $meta['desc'];
366
 
370
 
367
    $bsum = file2bsum(realpath($repodir . '/' . $fname));
371
    $bsum = file2bsum(realpath($repodir . '/' . $fname));
368
 
372
 
369
    $meta2['ver'] = strval($ver);
373
    $meta2['ver'] = strval($ver);
370
    $meta2['bsum'] = $bsum;
374
    $meta2['bsum'] = $bsum;
371
 
375
 
372
    if (empty($db[$pkg]['desc'])) $db[$pkg]['desc'] = $desc;
376
    if (empty($db[$pkg]['desc'])) $db[$pkg]['desc'] = $desc;
373
    if (empty($db[$pkg]['cats'])) {
377
    if (empty($db[$pkg]['cats'])) {
374
      $db[$pkg]['cats'] = $meta['cats'];
378
      $db[$pkg]['cats'] = $meta['cats'];
375
      $cats = array_unique(array_merge($cats, $meta['cats']));
379
      $cats = array_unique(array_merge($cats, $meta['cats']));
376
    }
380
    }
377
    $db[$pkg]['versions'][$fname] = $meta2;
381
    $db[$pkg]['versions'][$fname] = $meta2;
378
  }
382
  }
379
 
383
 
380
  $pkgcount++;
384
  $pkgcount++;
381
 
385
 
382
}
386
}
383
 
387
 
384
if ($pkgcount < 100) echo "WARNING: an unexpectedly low number of packages has been found in the repo ({$pkgcount})\n";
388
if ($pkgcount < 100) echo "WARNING: an unexpectedly low number of packages has been found in the repo ({$pkgcount})\n";
385
 
389
 
386
$json_blob = json_encode($db);
390
$json_blob = json_encode($db);
387
if ($json_blob === false) {
391
if ($json_blob === false) {
388
  echo "ERROR: JSON convertion failed! -> ";
392
  echo "ERROR: JSON convertion failed! -> ";
389
  switch (json_last_error()) {
393
  switch (json_last_error()) {
390
    case JSON_ERROR_DEPTH:
394
    case JSON_ERROR_DEPTH:
391
      echo 'maximum stack depth exceeded';
395
      echo 'maximum stack depth exceeded';
392
      break;
396
      break;
393
    case JSON_ERROR_STATE_MISMATCH:
397
    case JSON_ERROR_STATE_MISMATCH:
394
      echo 'underflow of the modes mismatch';
398
      echo 'underflow of the modes mismatch';
395
      break;
399
      break;
396
    case JSON_ERROR_CTRL_CHAR:
400
    case JSON_ERROR_CTRL_CHAR:
397
      echo 'unexpected control character found';
401
      echo 'unexpected control character found';
398
      break;
402
      break;
399
    case JSON_ERROR_UTF8:
403
    case JSON_ERROR_UTF8:
400
      echo 'malformed utf-8 characters';
404
      echo 'malformed utf-8 characters';
401
      break;
405
      break;
402
    default:
406
    default:
403
      echo "unknown error";
407
      echo "unknown error";
404
      break;
408
      break;
405
  }
409
  }
406
  echo "\n";
410
  echo "\n";
407
}
411
}
408
 
412
 
409
file_put_contents($repodir . '/_index.json', $json_blob);
413
file_put_contents($repodir . '/_index.json', $json_blob);
410
 
414
 
411
$cats_json = json_encode($cats);
415
$cats_json = json_encode($cats);
412
file_put_contents($repodir . '/_cats.json', $cats_json);
416
file_put_contents($repodir . '/_cats.json', $cats_json);
413
 
417
 
414
exit(0);
418
exit(0);
415
 
419
 
416
?>
420
?>
417
 
421