1#!/usr/bin/env perl
2#-
3# Copyright (c) 2000 Mark Ovens
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer
11#    in this position and unchanged.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27
28
29# Each port record in INDEX contains 10 fields, delimited by ``|'', some
30# of which may be empty. The fields are:
31#
32# distribution-name|port-path|installation-prefix|comment| \
33# description-file|maintainer|categories|build deps|run deps|www site
34
35
36use strict;
37use Getopt::Std;
38use vars qw/ $key @list %fields %list %opts /;
39
40#
41# Global variables
42#
43
44my $osrel = `/usr/bin/uname -r`;
45$osrel =~ s/\..+$//s;
46
47my $portsdir = "/usr/mports";
48$portsdir = $ENV{PORTSDIR} if ( defined $ENV{'PORTSDIR'} );
49
50my $VERSION = "1.0";
51my $file = "$portsdir/INDEX-$osrel";
52my $match = 1;
53my $count = 0;
54my $fulldesc = 0;
55
56# We only need 7 of the 10 fields in a record; define which ones in a
57# hash slice to ignore the un-needed ones. This also makes it easy to
58# add or remove fields in the future.
59
60@fields{qw(n p i e m x b r)} = (0, 1, 3, 4, 5, 6, 7, 8);
61
62#
63# Print a basic help message
64#
65
66sub usage() {
67	print(STDERR "
68Usage: portsearch [-h] [-e] [-n name] [-p path] [-i info] [-m maint] [-x index]
69		[-b b_deps] [-r r_deps] [-d deps] [-f file]
70
71");
72} # usage()
73
74#
75# Print a more verbose help message
76#
77
78sub help() {
79	print(STDERR "portsearch $VERSION - A utility for searching the ports tree.
80
81Options:
82
83  -n name	Search for \"name\" in name of ports
84  -p path	Search for \"path\" in location of ports
85  -i info	Search for \"info\" in ports COMMENT
86  -m maint	Search for \"maint\" in ports Maintainer
87  -x index	Search for \"index\" in ports categories
88  -b b_deps	Search for \"b_deps\" in build depends of ports
89  -r r_deps	Search for \"r_deps\" in run depends of ports
90  -d deps	Search for \"deps\" in both build & run depends of ports
91  -f file	Use \"file\" instead of /usr/ports/INDEX
92  -e	 	Show long description for all matching ports
93  -h		Print this message and exit
94
95");
96} # help()
97
98#
99# The program proper
100#
101
102MAIN: {
103				# No command-line args
104	if ($#ARGV == -1) {
105		usage();
106		exit(1);
107	}
108
109	getopts('ehf:n:p:i:m:x:b:r:d:', \%opts);
110				# Process -e first, as it doesn't take
111				# arguments
112	if (defined($opts{"e"})) {
113		$fulldesc = 1;
114		delete $opts{"e"};
115	}
116				# Command-line args, but without options
117	if (keys(%opts) == 0 ) {
118				# Default to name search if no constraints
119				# specified
120		if ($#ARGV == 0) {
121	   		$opts{"n"} = $ARGV[0];
122		} else {
123			usage();
124			exit(1);
125		}
126	}
127				# If ``-h'', ignore any other options
128	if (defined($opts{"h"})) {
129		help();
130		exit(1);
131	}
132				# A different INDEX file
133	if (defined($opts{"f"})) {
134		$file = $opts{"f"};
135	}
136				# If ``-d'' used we don't want ``-b'' & ``-r''
137	if (defined($opts{"d"})) {
138		delete $opts{"b"};
139		delete $opts{"r"};
140	}
141				# Finished with it now so remove it from hash
142	delete $opts{"f"};
143
144	open(INDEX, "$file") || die "Unable to open $file";
145
146	while (<INDEX>) {
147		chomp;
148		@list = split(/\|/);
149
150			$match = 1;
151					# All searches are case-insensitive!
152					# For ``-d'' search both build & run depends.
153					# Only fail to match if not found in either.
154		foreach $key (keys (%opts)) {
155			if ($key eq "d") {
156				if ($list[$fields{"b"}] !~ m#$opts{$key}#i &&
157				  $list[$fields{"r"}] !~ m#$opts{$key}#i) {
158					$match = 0;
159					last;
160				}
161			} else {
162				if ($list[$fields{$key}] !~ m#$opts{$key}#i) {
163					$match = 0;
164					last;
165				}
166			}
167		} # foreach
168
169		if ($match == 1) {
170			$count++;
171			write;
172			if ($fulldesc) {
173				open my $pkgdescr, $list[$fields{"e"}] || next;
174				print while <$pkgdescr>; print "\n";
175				close $pkgdescr;
176			}
177		}
178
179	} # while
180
181	close(INDEX);
182
183	print ("Number of matching ports = $count\n\n");
184
185} # MAIN
186
187
188format STDOUT =
189
190Port:	@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
191$list[$fields{"n"}]
192Path:	@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
193$list[$fields{"p"}]
194Info:	^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
195$list[$fields{"i"}]
196~~	^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
197$list[$fields{"i"}]
198Maint:	@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
199$list[$fields{"m"}]
200Index:	@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
201$list[$fields{"x"}]
202B-deps:	^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
203$list[$fields{"b"}]
204~~	^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
205$list[$fields{"b"}]
206R-deps:	^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
207$list[$fields{"r"}]
208~~	^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
209$list[$fields{"r"}]
210
211.
212