Subversion Repositories SvarDOS

Rev

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

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