Subversion Repositories SvarDOS

Rev

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

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