Subversion Repositories SvarDOS

Rev

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

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