pkg_noisrev 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "open4", "~>1.1.0"
4
+ gem "git", "~>1.2.5"
data/README.rdoc ADDED
@@ -0,0 +1,102 @@
1
+ =Name
2
+
3
+ pkg_noisrev--a fast way to summarize installed versions of FreeBSD packages.
4
+
5
+
6
+ ==Synopsis
7
+
8
+ pkg_noisrev [options]
9
+
10
+
11
+ ==Description
12
+
13
+ The pkg_noisrev utility is a <b>very fast</b> version of pkg_version
14
+ program that ships with FreeBSD. Consider the example from virtualized
15
+ FreeBSD 8.2 (with 696 installed packages) where virtual hdd is a main
16
+ performance bottle neck:
17
+
18
+ % time pkg_version
19
+ [...]
20
+ 21.006u 68.076s 1:59.73 74.3% 403+713k 1155+0io 3pf+0w
21
+
22
+ % time pkg_noisrev
23
+ [...]
24
+ 12.261u 10.249s 0:26.29 85.5% 95+1128k 0+0io 0pf+0w
25
+
26
+ pkg_noisrev is basically <b>~ 4.6 times faster</b>. It achieves this
27
+ speed by doing its work in several parallel threads + making some
28
+ not-so-interesting tricks of extracting version strings from Makefiles.
29
+
30
+ pkg_noisrev also adds filtering to the output, thus you can, for
31
+ example, only see out of sync packages. If you are a portmaster user,
32
+ you may like <tt>--likeportmaster</tt> option (I do!).
33
+
34
+ The options are as follows:
35
+
36
+ --config-dirs:: List all possible locations for the
37
+ configuration file. The first found wins.
38
+
39
+ --config NAME:: The name of the configuration file. If
40
+ it contains <tt>/</tt> in it, the list from
41
+ <tt>--config-dirs</tt> is ignored.
42
+
43
+ -V:: Show version and exit.
44
+
45
+ -v:: Be more verbose. You can supply it several
46
+ times, viz. <tt>-vv</tt> dumps even more
47
+ debug info.
48
+
49
+ --pkg-dir STR:: Set the alternate package db directory.
50
+
51
+ --ports-dir STR:: Set the alternate ports db directory.
52
+
53
+ --outofsync:: Filter all but out of sync packages.
54
+
55
+ --missing:: Filter all but packages that doesn't exists
56
+ in ports.
57
+
58
+ --likeportmaster:: Print like (but not quite) "portmaster -L".
59
+
60
+
61
+ ==Installation
62
+
63
+ (Only if you are not installing the gem.)
64
+
65
+ pkg_noisrev ships with a shared library (the comparator of a 2
66
+ versions-as-a-string that was extracted from pkg_version sources) which
67
+ must be compiled before you can use the program.
68
+
69
+ cd to a directory with pkg_noisrev sources and type:
70
+
71
+ % rake mydll:default
72
+
73
+ Then run <tt>bin/pkg_noisrev</tt> or make a symlink to it in one of your
74
+ directories in PATH.
75
+
76
+
77
+ ==Configuration
78
+
79
+ pkg_noisrev looks for its configuration at 3 places at start up.
80
+
81
+ 1. At <tt>PKG_NOISREV_CONF</tt> env variable.
82
+ (Its format is exactly similar to CL options.)
83
+
84
+ 2. At the configuration file. Its default name is
85
+ <tt>pkg_noisrev.yaml</tt> and it can be stored in several
86
+ system directories which are observable by <tt>--config--dirs</tt> CL
87
+ option.
88
+
89
+ 3. At command line.
90
+
91
+ Higher number levels overrides the values from lower number levels.
92
+
93
+ The configuration file must be in YAML format. Look into <tt>`gem env
94
+ gemdir`/gems/pkg_noisrev-x.y.z/etc/</tt> directory for samples.
95
+
96
+
97
+ ==Examples
98
+
99
+ % ri Pkg_noisrev
100
+ % pkg_noisrev --likeportmaster
101
+ % pkg_noisrev --outofsync
102
+ % pkg_noisrev --missing --likeportmaster
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ # -*-ruby-*-
2
+
3
+ require 'rake'
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+ require 'rubygems/package_task'
7
+
8
+ gem 'rdoc'
9
+ require 'rdoc/task'
10
+
11
+ require_relative 'ext/rakefile'
12
+ require_relative 'lib/pkg_noisrev/meta'
13
+ include Pkg_noisrev
14
+
15
+ require_relative 'test/rake_git'
16
+
17
+ spec = Gem::Specification.new {|i|
18
+ i.name = Meta::NAME
19
+ i.version = Meta::VERSION
20
+ i.summary = 'A fast way to summarize installed versions of FreeBSD packages'
21
+ i.description = i.summary + '.'
22
+ i.author = Meta::AUTHOR
23
+ i.email = Meta::EMAIL
24
+ i.homepage = Meta::HOMEPAGE
25
+
26
+ i.platform = Gem::Platform::RUBY
27
+ i.required_ruby_version = '>= 1.9.2'
28
+ i.files = git_ls('.')
29
+
30
+ i.executables = FileList['bin/*'].gsub(/^bin\//, '')
31
+
32
+ i.test_files = FileList['test/test_*.rb']
33
+
34
+ i.rdoc_options << '-m' << 'doc/README.rdoc'
35
+ i.extra_rdoc_files = FileList['doc/*']
36
+
37
+ i.extensions << 'ext/extconf.rb'
38
+
39
+ i.add_dependency('open4', '>= 1.1.0')
40
+ i.add_development_dependency('git', '>= 1.2.5')
41
+ }
42
+
43
+ Gem::PackageTask.new(spec).define
44
+
45
+ task default: [:repackage]
46
+
47
+ RDoc::Task.new('html') do |i|
48
+ i.main = 'doc/README.rdoc'
49
+ i.rdoc_files = FileList['doc/*', 'lib/**/*.rb']
50
+ # i.rdoc_files.exclude("lib/**/some-nasty-staff")
51
+ end
52
+
53
+ Rake::TestTask.new do |i|
54
+ i.test_files = FileList['test/test_*.rb']
55
+ end
56
+
57
+ task default: ['mydll:default', :repackage]
58
+ task clean: ['mydll:clean']
data/bin/pkg_noisrev ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+ # -*-ruby-*-
3
+
4
+ require 'thread'
5
+ require 'logger'
6
+
7
+ require_relative '../lib/pkg_noisrev/trestle.rb'
8
+ require_relative '../lib/pkg_noisrev/fbsdpackage.rb'
9
+
10
+ include Pkg_noisrev
11
+
12
+ $conf = Hash.new
13
+ u = Trestle.new($conf)
14
+
15
+ $conf[:banner] = "Usage: #{File.basename($0)} [options]"
16
+ $conf[:pkg_dir] = '/var/db/pkg'
17
+ $conf[:ports_dir] = '/usr/ports'
18
+ $conf[:log] = '/tmp/' + Pkg_noisrev::Meta::NAME + '.log'
19
+ $conf[:filter] = '' # or 'outofsync', 'missing'
20
+ $conf[:mode] = 'default' # or 'likeportmaster'
21
+ $conf[:int_attempts] = 2
22
+
23
+ # --[ main ]------------------------------------------------------------
24
+
25
+ u.config_parse(['foobar']) {|src|
26
+ o = u.cl_parse(src) # create an OptionParser object
27
+ o.on('--pkg-dir STR', 'Set the alternate package db directory.') {|i|
28
+ $conf[:pkg_dir] = i
29
+ }
30
+ o.on('--ports-dir STR', 'Set the alternate ports db directory.') {|i|
31
+ $conf[:ports_dir] = i
32
+ }
33
+ o.on('--outofsync', 'Filter all but out of sync packages.') {|i|
34
+ $conf[:filter] = 'outofsync'
35
+ }
36
+ o.on('--missing', 'Filter all but packages that doesn\'t exists in ports.') {|i|
37
+ $conf[:filter] = 'missing'
38
+ }
39
+ o.on('--likeportmaster', 'Print like (but not quite) "portmaster -L".') {|i|
40
+ $conf[:mode] = 'likeportmaster'
41
+ }
42
+ u.cl_parse(src, o) # run cl parser
43
+ }
44
+
45
+ # print our env
46
+ if $conf[:verbose] >= 2
47
+ puts 'Libs dir: ' + Trestle.gem_libdir
48
+ pp $conf
49
+ end
50
+
51
+ File.delete $conf[:log] rescue nil
52
+ log = Logger.new($conf[:log])
53
+ log.formatter = proc { |severity, d, p, msg| "#{severity}: #{msg}\n" }
54
+
55
+ Signal.trap(:INT) do
56
+ if $conf[:int_attempts] >= 0
57
+ print "\nWoot! (#{$conf[:int_attempts]})\n"
58
+ else
59
+ print "\n"
60
+ end
61
+ $conf[:int_attempts] == -1 ? exit(1) : $conf[:int_attempts] -= 1
62
+ end
63
+
64
+ begin
65
+ pkg = FbsdPackage.new $conf[:pkg_dir], $conf[:ports_dir]
66
+ rescue
67
+ Trestle.errx 1, $!.to_s
68
+ end
69
+ pkg.analyze log
70
+ pkg.print $conf[:mode], $conf[:filter]
data/doc/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2010 Alexander Gromnitsky.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/doc/NEWS.rdoc ADDED
@@ -0,0 +1,5 @@
1
+ === 0.0.1
2
+
3
+ Mon, 1 Aug 2011 12:34:04 +0300
4
+
5
+ - Created a first skeleton.
data/doc/README.rdoc ADDED
@@ -0,0 +1,102 @@
1
+ =Name
2
+
3
+ pkg_noisrev--a fast way to summarize installed versions of FreeBSD packages.
4
+
5
+
6
+ ==Synopsis
7
+
8
+ pkg_noisrev [options]
9
+
10
+
11
+ ==Description
12
+
13
+ The pkg_noisrev utility is a <b>very fast</b> version of pkg_version
14
+ program that ships with FreeBSD. Consider the example from virtualized
15
+ FreeBSD 8.2 (with 696 installed packages) where virtual hdd is a main
16
+ performance bottle neck:
17
+
18
+ % time pkg_version
19
+ [...]
20
+ 21.006u 68.076s 1:59.73 74.3% 403+713k 1155+0io 3pf+0w
21
+
22
+ % time pkg_noisrev
23
+ [...]
24
+ 12.261u 10.249s 0:26.29 85.5% 95+1128k 0+0io 0pf+0w
25
+
26
+ pkg_noisrev is basically <b>~ 4.6 times faster</b>. It achieves this
27
+ speed by doing its work in several parallel threads + making some
28
+ not-so-interesting tricks of extracting version strings from Makefiles.
29
+
30
+ pkg_noisrev also adds filtering to the output, thus you can, for
31
+ example, only see out of sync packages. If you are a portmaster user,
32
+ you may like <tt>--likeportmaster</tt> option (I do!).
33
+
34
+ The options are as follows:
35
+
36
+ --config-dirs:: List all possible locations for the
37
+ configuration file. The first found wins.
38
+
39
+ --config NAME:: The name of the configuration file. If
40
+ it contains <tt>/</tt> in it, the list from
41
+ <tt>--config-dirs</tt> is ignored.
42
+
43
+ -V:: Show version and exit.
44
+
45
+ -v:: Be more verbose. You can supply it several
46
+ times, viz. <tt>-vv</tt> dumps even more
47
+ debug info.
48
+
49
+ --pkg-dir STR:: Set the alternate package db directory.
50
+
51
+ --ports-dir STR:: Set the alternate ports db directory.
52
+
53
+ --outofsync:: Filter all but out of sync packages.
54
+
55
+ --missing:: Filter all but packages that doesn't exists
56
+ in ports.
57
+
58
+ --likeportmaster:: Print like (but not quite) "portmaster -L".
59
+
60
+
61
+ ==Installation
62
+
63
+ (Only if you are not installing the gem.)
64
+
65
+ pkg_noisrev ships with a shared library (the comparator of a 2
66
+ versions-as-a-string that was extracted from pkg_version sources) which
67
+ must be compiled before you can use the program.
68
+
69
+ cd to a directory with pkg_noisrev sources and type:
70
+
71
+ % rake mydll:default
72
+
73
+ Then run <tt>bin/pkg_noisrev</tt> or make a symlink to it in one of your
74
+ directories in PATH.
75
+
76
+
77
+ ==Configuration
78
+
79
+ pkg_noisrev looks for its configuration at 3 places at start up.
80
+
81
+ 1. At <tt>PKG_NOISREV_CONF</tt> env variable.
82
+ (Its format is exactly similar to CL options.)
83
+
84
+ 2. At the configuration file. Its default name is
85
+ <tt>pkg_noisrev.yaml</tt> and it can be stored in several
86
+ system directories which are observable by <tt>--config--dirs</tt> CL
87
+ option.
88
+
89
+ 3. At command line.
90
+
91
+ Higher number levels overrides the values from lower number levels.
92
+
93
+ The configuration file must be in YAML format. Look into <tt>`gem env
94
+ gemdir`/gems/pkg_noisrev-x.y.z/etc/</tt> directory for samples.
95
+
96
+
97
+ ==Examples
98
+
99
+ % ri Pkg_noisrev
100
+ % pkg_noisrev --likeportmaster
101
+ % pkg_noisrev --outofsync
102
+ % pkg_noisrev --missing --likeportmaster
data/doc/TODO ADDED
@@ -0,0 +1,6 @@
1
+ -*-text-*-
2
+
3
+ + look for missing ports in /usr/ports/MOVED file
4
+ + apply filtering to --likeportmaster too
5
+ + docs
6
+ + tests
@@ -0,0 +1,2 @@
1
+ ---
2
+ :foobar: foobar
data/ext/extconf.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ name = 'version'
4
+ create_makefile('pkg_noisrev/' + name)
5
+ #require 'pp'
6
+ #pp $configure_args
data/ext/rakefile.rb ADDED
@@ -0,0 +1,24 @@
1
+ # Building shared libraries.
2
+
3
+ module MyDll
4
+ PATH = File.dirname(__FILE__)
5
+ MK = PATH + '/Makefile'
6
+ EXTCONF = PATH + '/extconf.rb'
7
+ end
8
+
9
+ namespace 'mydll' do
10
+ desc "Generate dlls"
11
+ task :default => [MyDll::MK] do |i|
12
+ sh "cd #{MyDll::PATH} && make"
13
+ end
14
+
15
+ desc "Clean all crap"
16
+ task :clean => [MyDll::MK] do |i|
17
+ sh "cd #{MyDll::PATH} && make clean"
18
+ rm_rf i.prerequisites
19
+ end
20
+
21
+ file MyDll::MK => [MyDll::EXTCONF] do |i|
22
+ sh "cd #{MyDll::PATH} && ruby #{i.prerequisites.join(' ')}"
23
+ end
24
+ end
data/ext/version.c ADDED
@@ -0,0 +1,286 @@
1
+ /*
2
+ A modified version of /usr/src/usr.sbin/pkg_install/lib/version.c from
3
+ FreeBSD 8.2.
4
+ */
5
+
6
+ #include "version.h"
7
+
8
+ /*
9
+ * split_version(pkgname, endname, epoch, revision) returns a pointer to
10
+ * the version portion of a package name and the two special components.
11
+ *
12
+ * Syntax is: ${PORTNAME}-${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
13
+ *
14
+ * Written by Oliver Eikemeier
15
+ * Based on work of Jeremy D. Lea.
16
+ */
17
+ static const char *
18
+ split_version(const char *pkgname, const char **endname, unsigned long *epoch, unsigned long *revision)
19
+ {
20
+ char *ch;
21
+ const char *versionstr;
22
+ const char *endversionstr;
23
+
24
+ if (pkgname == NULL)
25
+ errx(2, "%s: Passed NULL pkgname.", __func__);
26
+
27
+ /* Look for the last '-' the the pkgname */
28
+ ch = strrchr(pkgname, '-');
29
+ /* Cheat if we are just passed a version, not a valid package name */
30
+ versionstr = ch ? ch + 1 : pkgname;
31
+
32
+ /* Look for the last '_' in the version string, advancing the end pointer */
33
+ ch = strrchr(versionstr, '_');
34
+ if (revision != NULL) {
35
+ *revision = ch ? strtoul(ch + 1, NULL, 10) : 0;
36
+ }
37
+ endversionstr = ch;
38
+
39
+ /* Look for the last ',' in the remaining version string */
40
+ ch = strrchr(endversionstr ? endversionstr + 1 : versionstr, ',');
41
+ if (epoch != NULL) {
42
+ *epoch = ch ? strtoul(ch + 1, NULL, 10) : 0;
43
+ }
44
+ if (ch && !endversionstr)
45
+ endversionstr = ch;
46
+
47
+ /* set the pointer behind the last character of the version without revision or epoch */
48
+ if (endname)
49
+ *endname = endversionstr ? endversionstr : strrchr(versionstr, '\0');
50
+
51
+ return versionstr;
52
+ }
53
+
54
+ /*
55
+ * PORTVERSIONs are composed of components separated by dots. A component
56
+ * consists of a version number, a letter and a patchlevel number. This does
57
+ * not conform to the porter's handbook, but let us formulate rules that
58
+ * fit the current practice and are far simpler than to make decisions
59
+ * based on the order of netters and lumbers. Besides, people use versions
60
+ * like 10b2 in the ports...
61
+ */
62
+
63
+ typedef struct {
64
+ #ifdef __LONG_LONG_SUPPORTED
65
+ long long n;
66
+ long long pl;
67
+ #else
68
+ long n;
69
+ long pl;
70
+ #endif
71
+ int a;
72
+ } version_component;
73
+
74
+ /*
75
+ * get_component(position, component) gets the value of the next component
76
+ * (number - letter - number triple) and returns a pointer to the next character
77
+ * after any leading separators
78
+ *
79
+ * - components are separated by dots
80
+ * - characters !~ [a-zA-Z0-9.+*] are treated as separators
81
+ * (1.0:2003.09.16 = 1.0.2003.09.16), this may not be what you expect:
82
+ * 1.0.1:2003.09.16 < 1.0:2003.09.16
83
+ * - consecutive separators are collapsed (10..1 = 10.1)
84
+ * - missing separators are inserted, essentially
85
+ * letter number letter => letter number . letter (10a1b2 = 10a1.b2)
86
+ * - missing components are assumed to be equal to 0 (10 = 10.0 = 10.0.0)
87
+ * - the letter sort order is: [none], a, b, ..., z; numbers without letters
88
+ * sort first (10 < 10a < 10b)
89
+ * - missing version numbers (in components starting with a letter) sort as -1
90
+ * (a < 0, 10.a < 10)
91
+ * - a separator is inserted before the special strings "pl", "alpha", "beta",
92
+ * "pre" and "rc".
93
+ * - "pl" sorts before every other letter, "alpha", "beta", "pre" and "rc"
94
+ * sort as a, b, p and r. (10alpha = 10.a < 10, but 10 < 10a; pl11 < alpha3
95
+ * < 0.1beta2 = 0.1.b2 < 0.1)
96
+ * - other strings use only the first letter for sorting, case is ignored
97
+ * (1.d2 = 1.dev2 = 1.Development2)
98
+ * - The special component `*' is guaranteed to be the smallest possible
99
+ * component (2.* < 2pl1 < 2alpha3 < 2.9f7 < 3.*)
100
+ * - components separated by `+' are handled by version_cmp below
101
+ *
102
+ * Oliver Eikemeier
103
+ */
104
+
105
+ static const struct {
106
+ const char *name;
107
+ size_t namelen;
108
+ int value;
109
+ } stage[] = {
110
+ { "pl", 2, 0 },
111
+ { "alpha", 5, 'a'-'a'+1 },
112
+ { "beta", 4, 'b'-'a'+1 },
113
+ { "pre", 3, 'p'-'a'+1 },
114
+ { "rc", 2, 'r'-'a'+1 },
115
+ { NULL, 0, -1 }
116
+ };
117
+
118
+ static const char *
119
+ get_component(const char *position, version_component *component)
120
+ {
121
+ const char *pos = position;
122
+ int hasstage = 0, haspatchlevel = 0;
123
+
124
+ if (!pos)
125
+ errx(2, "%s: Passed NULL position.", __func__);
126
+
127
+ /* handle version number */
128
+ if (isdigit(*pos)) {
129
+ char *endptr;
130
+ #ifdef __LONG_LONG_SUPPORTED
131
+ component->n = strtoll(pos, &endptr, 10);
132
+ #else
133
+ component->n = strtol(pos, &endptr, 10);
134
+ #endif
135
+ /* should we test for errno == ERANGE? */
136
+ pos = endptr;
137
+ } else if (*pos == '*') {
138
+ component->n = -2;
139
+ do {
140
+ pos++;
141
+ } while(*pos && *pos != '+');
142
+ } else {
143
+ component->n = -1;
144
+ hasstage = 1;
145
+ }
146
+
147
+ /* handle letter */
148
+ if (isalpha(*pos)) {
149
+ int c = tolower(*pos);
150
+ haspatchlevel = 1;
151
+ /* handle special suffixes */
152
+ if (isalpha(pos[1])) {
153
+ int i;
154
+ for (i = 0; stage[i].name; i++) {
155
+ if (strncasecmp(pos, stage[i].name, stage[i].namelen) == 0
156
+ && !isalpha(pos[stage[i].namelen])) {
157
+ if (hasstage) {
158
+ /* stage to value */
159
+ component->a = stage[i].value;
160
+ pos += stage[i].namelen;
161
+ } else {
162
+ /* insert dot */
163
+ component->a = 0;
164
+ haspatchlevel = 0;
165
+ }
166
+ c = 0;
167
+ break;
168
+ }
169
+ }
170
+ }
171
+ /* unhandled above */
172
+ if (c) {
173
+ /* use the first letter and skip following */
174
+ component->a = c - 'a' + 1;
175
+ do {
176
+ ++pos;
177
+ } while (isalpha(*pos));
178
+ }
179
+ } else {
180
+ component->a = 0;
181
+ haspatchlevel = 0;
182
+ }
183
+
184
+ if (haspatchlevel) {
185
+ /* handle patch number */
186
+ if (isdigit(*pos)) {
187
+ char *endptr;
188
+ #ifdef __LONG_LONG_SUPPORTED
189
+ component->pl = strtoll(pos, &endptr, 10);
190
+ #else
191
+ component->pl = strtol(pos, &endptr, 10);
192
+ #endif
193
+ /* should we test for errno == ERANGE? */
194
+ pos = endptr;
195
+ } else {
196
+ component->pl = -1;
197
+ }
198
+ } else {
199
+ component->pl = 0;
200
+ }
201
+
202
+ /* skip trailing separators */
203
+ while (*pos && !isdigit(*pos) && !isalpha(*pos) && *pos != '+' && *pos != '*') {
204
+ pos++;
205
+ }
206
+
207
+ return pos;
208
+ }
209
+
210
+ /*
211
+ * version_cmp(pkg1, pkg2) returns -1, 0 or 1 depending on if the version
212
+ * components of pkg1 is less than, equal to or greater than pkg2. No
213
+ * comparison of the basenames is done.
214
+ *
215
+ * The port version is defined by:
216
+ * ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
217
+ * ${PORTEPOCH} supersedes ${PORTVERSION} supersedes ${PORTREVISION}.
218
+ * See the commit log for revision 1.349 of ports/Mk/bsd.port.mk
219
+ * for more information.
220
+ *
221
+ * The epoch and revision are defined to be a single number, while the rest
222
+ * of the version should conform to the porting guidelines. It can contain
223
+ * multiple components, separated by a period, including letters.
224
+ *
225
+ * The tests allow for significantly more latitude in the version numbers
226
+ * than is allowed in the guidelines. No point in enforcing them here.
227
+ * That's what portlint is for.
228
+ *
229
+ * Jeremy D. Lea.
230
+ * reimplemented by Oliver Eikemeier
231
+ */
232
+ int
233
+ version_cmp(const char *pkg1, const char *pkg2)
234
+ {
235
+ const char *v1, *v2, *ve1, *ve2;
236
+ unsigned long e1, e2, r1, r2;
237
+ int result = 0;
238
+
239
+ v1 = split_version(pkg1, &ve1, &e1, &r1);
240
+ v2 = split_version(pkg2, &ve2, &e2, &r2);
241
+
242
+ /* Check epoch, port version, and port revision, in that order. */
243
+ if (e1 != e2) {
244
+ result = (e1 < e2 ? -1 : 1);
245
+ }
246
+
247
+ /* Shortcut check for equality before invoking the parsing routines. */
248
+ if (result == 0 && (ve1 - v1 != ve2 - v2 || strncasecmp(v1, v2, ve1 - v1) != 0)) {
249
+ /* Loop over different components (the parts separated by dots).
250
+ * If any component differs, we have the basis for an inequality. */
251
+ while(result == 0 && (v1 < ve1 || v2 < ve2)) {
252
+ int block_v1 = 0;
253
+ int block_v2 = 0;
254
+ version_component vc1 = {0, 0, 0};
255
+ version_component vc2 = {0, 0, 0};
256
+ if (v1 < ve1 && *v1 != '+') {
257
+ v1 = get_component(v1, &vc1);
258
+ } else {
259
+ block_v1 = 1;
260
+ }
261
+ if (v2 < ve2 && *v2 != '+') {
262
+ v2 = get_component(v2, &vc2);
263
+ } else {
264
+ block_v2 = 1;
265
+ }
266
+ if (block_v1 && block_v2) {
267
+ if (v1 < ve1)
268
+ v1++;
269
+ if (v2 < ve2)
270
+ v2++;
271
+ } else if (vc1.n != vc2.n) {
272
+ result = (vc1.n < vc2.n ? -1 : 1);
273
+ } else if (vc1.a != vc2.a) {
274
+ result = (vc1.a < vc2.a ? -1 : 1);
275
+ } else if (vc1.pl != vc2.pl) {
276
+ result = (vc1.pl < vc2.pl ? -1 : 1);
277
+ }
278
+ }
279
+ }
280
+
281
+ /* Compare FreeBSD revision numbers. */
282
+ if (result == 0 && r1 != r2) {
283
+ result = (r1 < r2 ? -1 : 1);
284
+ }
285
+ return result;
286
+ }