summaryrefslogtreecommitdiffstats
path: root/knetworkconf/backends/parse.pl.in
diff options
context:
space:
mode:
Diffstat (limited to 'knetworkconf/backends/parse.pl.in')
-rw-r--r--knetworkconf/backends/parse.pl.in1828
1 files changed, 1828 insertions, 0 deletions
diff --git a/knetworkconf/backends/parse.pl.in b/knetworkconf/backends/parse.pl.in
new file mode 100644
index 0000000..9bad7d8
--- /dev/null
+++ b/knetworkconf/backends/parse.pl.in
@@ -0,0 +1,1828 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# parse.pl: Common parsing stuff for the ximian-setup-tools backends.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+# Arturo Espinosa <arturo@ximian.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Library General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/){
+
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/util.pl$DOTIN";
+require "$SCRIPTSDIR/file.pl$DOTIN";
+require "$SCRIPTSDIR/debug.pl$DOTIN";
+
+
+# The concept of keyword (kw) here is a key, normaly in its own line, whose
+# boolean representation is its own existence.
+
+# Every final parsing function to be used by a table must handle one key
+# at a time, but maybe parse several values from there and return a
+# ref to array or hash.
+#
+# Always return a scalar. If you need to return an array or a hash,
+# return a ref to it.
+
+# First some helper functions for the whole process.
+# Expand substrings of the form #$substr# to the $value in
+# the string or recursively in the array $strarr.
+
+sub gst_parse_expand
+{
+ my ($strarr, $substr, $value) = @_;
+
+ if (ref $strarr eq "ARRAY")
+ {
+ my ($i);
+
+ $strarr = [ @$strarr ];
+ foreach $i (@$strarr)
+ {
+ $i = &gst_parse_expand ($i, $substr, $value);
+ }
+
+ return $strarr;
+ }
+
+ $strarr =~ s/\#$substr\#/$value/;
+ return $strarr;
+}
+
+sub gst_parse_replace_hash_values
+{
+ my ($cp, $hash) = @_;
+ my ($j, $replace_key, $value);
+
+ foreach $j (@$cp)
+ {
+ while ($j =~ /%([^%]*)%/)
+ {
+ $replace_key = $1;
+ if (exists $$hash{$replace_key})
+ {
+ $value = $$hash{$replace_key};
+ if (ref $value)
+ {
+ $j = $value;
+ }
+ else
+ {
+ $j =~ s/%$replace_key%/$value/g;
+ }
+ }
+ else
+ {
+ &gst_debug_print_line ("Warning: gst_parse_replace_hash_values: key $replace_key doesn't exist.");
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+sub gst_parse_replace_files
+{
+ my ($values, $fn_hash) = @_;
+ my @ret;
+
+ return () if $values eq undef;
+ $values = [$values] if !ref $values;
+
+ foreach $i (@$values)
+ {
+ if (exists $$fn_hash{$i})
+ {
+ push @ret, $$fn_hash{$i};
+ }
+ else
+ {
+ push @ret, $i;
+ }
+ }
+
+ return @ret;
+}
+
+# Additional abstraction: parse table entries can have
+# arrays inside. The parsing proc will be ran with every
+# combination that the arrays provide. Ex:
+# ["user", \&gst_parse_foo, [0, 1], [2, 3] ] will parse
+# using the combinatory of [0, 1]x[2, 3] until a result
+# ne undef is given. Check RedHat 7.2's network parse table
+# for further enlightenment.
+sub gst_parse_run_entry
+{
+ my ($hash, $key, $proc, $cp) = @_;
+ my ($ncp, $i, $j, $res);
+
+ $ncp = [@$cp];
+ for ($i = 0; $i < scalar (@$cp); $i ++)
+ {
+ if (ref $$cp[$i] eq "ARRAY")
+ {
+ foreach $j (@{$$cp[$i]})
+ {
+ $$ncp[$i] = $j;
+ $res = &gst_parse_run_entry ($hash, $key, $proc, $ncp);
+ return $res if $res ne undef;
+ }
+ return undef;
+ }
+ }
+
+ # OK, the given entry didn't have any array refs in it...
+
+ return undef if (!&gst_parse_replace_hash_values ($cp, $hash));
+
+ &gst_report_enter ();
+ &gst_report ("parse_table", "$key");
+ &gst_report_leave ();
+
+ $$hash{$key} = &$proc (@$cp);
+ return $$hash{$key};
+}
+
+# OK, this is the good stuff:
+
+# gst_parse_from_table takes a file mapping and a parse table.
+#
+# The functions in the replace tables, most of which are coded in
+# this file, receive the mapped files of the first argument, and then
+# a set of values.
+
+# The value the parse function returns is set into a hash,
+# using as key the first item of the parse table entry. This is done
+# only if the $hash{$key} is empty, which allows us to try with
+# several parse methods to try to get a value, where our parse functions
+# can return undef if they failed to get the requested value.
+#
+# A ref to the hash with all the fetched values is returned.
+sub gst_parse_from_table
+{
+ my ($fn, $table) = @_;
+ my %hash;
+ my ($key, $proc, @param);
+ my ($i, @cp, @files);
+
+ foreach $i (@$table)
+ {
+ @cp = @$i;
+ $key = shift (@cp);
+
+ if ($hash{$key} eq undef)
+ {
+ $proc = shift (@cp);
+ @files = &gst_parse_replace_files (shift (@cp), $fn);
+
+ # Don't unshift the resulting files if none were given.
+ unshift @cp, @files if (scalar @files) > 0;
+
+ &gst_parse_run_entry (\%hash, $key, $proc, \@cp);
+ }
+ }
+
+ foreach $i (keys (%hash))
+ {
+ delete $hash{$i} if ($hash{$i} eq undef);
+ }
+
+ return \%hash;
+}
+
+# Just return the passed values. If there's just
+# one value, the value. If more, a reference to an
+# array with the values.
+sub gst_parse_trivial
+{
+ my (@res) = @_;
+
+ &gst_report_enter ();
+ &gst_report ("parse_trivial", "@res");
+ &gst_report_leave ();
+
+ return $res[0] if (scalar @res) <= 1;
+ return \@res;
+}
+
+# Try to read a line from $fd and remove any leading or
+# trailing white spaces. Return ref to read $line or
+# -1 if eof.
+sub gst_parse_chomp_line_std
+{
+ my ($fd) = @_;
+ my $line;
+
+ $line = <$fd>;
+ return -1 if !$line;
+
+ chomp $line;
+ $line =~ s/^[ \t]+//;
+ $line =~ s/[ \t]+$//;
+
+ return \$line;
+}
+
+# Assuming $line is a line read from a shell file,
+# remove comments.
+sub gst_parse_process_sh_line
+{
+ my ($line) = @_;
+ my ($pline);
+
+ # This will put escaped hashes out of danger.
+ # But only inside valid quotes!
+ while ($line =~ /([^\"\']*[\"\'][^\#\"\']*)(\#?)([^\"\']*[\"\'])/g)
+ {
+ $pline .= $1;
+ $pline .= "__hash__" if ($2 ne undef);
+ $pline .= $3;
+ }
+
+ # The line may not match the regexp above,
+ $pline = $line if ($pline eq undef);
+
+ $pline =~ s/\\\#/\\__hash__/g;
+
+ # Nuke everything after a hash and bye bye trailing spaces.
+ $pline =~ s/[ \t]*\#.*//;
+
+ # Let escaped hashes come back home.
+ $pline =~ s/__hash__/\#/g;
+
+ return $pline;
+}
+
+# Same as gst_parse_chomp_line_std, but apply
+# the sh line processing before returning.
+# -1 if eof, ref to read $line if success.
+sub gst_parse_chomp_line_hash_comment
+{
+ my ($fd) = @_;
+ my $line;
+
+ $line = &gst_parse_chomp_line_std ($fd);
+ return -1 if $line == -1;
+
+ $line = &gst_parse_process_sh_line ($$line);
+ return \$line;
+}
+
+# Get an sh line, and remove the export keyword, if any.
+sub gst_parse_chomp_line_sh_export
+{
+ my ($fd) = @_;
+ my $line;
+
+ $line = &gst_parse_chomp_line_hash_comment ($fd);
+ return -1 if $line == -1;
+
+ $line = $$line;
+
+ $line =~ s/^export //;
+
+ return \$line;
+}
+
+# Parse a $file, wich is assumed to have a column-based format, with $re matching field separators
+# and one record per line. Search for $key, and return either a scalar with the first ocurrence,
+# or an array with all the found ocurrences.
+sub gst_parse_split_ref
+{
+ my ($file, $key, $re, $all, $line_read_proc) = @_;
+ my ($fd, @line, @res);
+
+ &gst_report_enter ();
+ &gst_report ("parse_split", $key, $file);
+
+ $proc = $line_read_proc? $line_read_proc : \&gst_parse_chomp_line_std;
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $all = 0 if !$fd;
+
+ while (($line = &$proc ($fd)) != -1)
+ {
+ $line = $$line;
+ next if $line eq "";
+
+ @line = split ($re, $line, 2);
+
+ if (shift (@line) =~ "^$key\$")
+ {
+ if ($all) {
+ push @res, $line[0];
+ }
+ else
+ {
+ &gst_report_leave ();
+ &gst_file_close ($fd);
+ return \$line[0];
+ }
+ }
+ }
+
+ &gst_report_leave ();
+ &gst_file_close ($fd);
+ return \@res if ($all);
+ return -1;
+}
+
+sub gst_parse_split
+{
+ my $res;
+
+ # Don't pass @_ like this anywhere. This is bad practice.
+ $res = &gst_parse_split_ref (@_);
+
+ return $$res if ref $res eq "SCALAR";
+ return @$res if ref $res eq "ARRAY";
+ return undef;
+}
+
+# This gives meaning to the $all flag of gst_parse_split, and returns a reference to the array, which
+# is what we want. (ie search a.com\nsearch b.com\nsearch c.com)
+sub gst_parse_split_all
+{
+ my ($file, $key, $re, $line_read_proc) = @_;
+ my @a;
+
+ @a = &gst_parse_split ($file, $key, $re, 1, $line_read_proc);
+
+ return \@a;
+}
+
+# Same, but use the hash_comment routine for line analysis.
+sub gst_parse_split_all_hash_comment
+{
+ my ($file, $key, $re) = @_;
+
+ return &gst_parse_split_all ($file, $key, $re, \&gst_parse_chomp_line_hash_comment);
+}
+
+# Make the elements of the resulting array unique.
+sub gst_parse_split_all_unique_hash_comment
+{
+ my ($file, $key, $re) = @_;
+ my ($arr, @res);
+ my (%hash, $i);
+
+ $arr = &gst_parse_split_all ($file, $key, $re, \&gst_parse_chomp_line_hash_comment);
+
+ foreach $i (@$arr)
+ {
+ next if exists $hash{$i};
+ $hash{$i} = 1;
+ push @res, $i;
+ }
+
+ return \@res;
+}
+
+sub gst_parse_split_all_array_with_pos
+{
+ my ($file, $key, $pos, $re, $sep, $line_read_proc) = @_;
+ my ($arr, @s, @ret, $i);
+
+ $arr = &gst_parse_split_all ($file, $key, $re, $line_read_proc);
+
+ foreach $i (@$arr)
+ {
+ @s = split ($sep, $i);
+ push @ret, @s[0];
+ }
+
+ return \@ret;
+}
+
+# Same, but for $all = 0. (ie nameserver 10.0.0.1)
+sub gst_parse_split_first_str
+{
+ my ($file, $key, $re, $line_read_proc) = @_;
+
+ return &gst_parse_split ($file, $key, $re, 0, $line_read_proc);
+}
+
+# Interpret the result as a boolean. (ie multi on)
+sub gst_parse_split_first_bool
+{
+ my ($file, $key, $re, $line_read_proc) = @_;
+ my $ret;
+
+ $ret = &gst_parse_split_first_str ($file, $key, $re, $line_read_proc);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+# After getting the first field, split the result with $sep matching separators. (ie order hosts,bind)
+sub gst_parse_split_first_array
+{
+ my ($file, $key, $re, $sep, $line_read_proc) = @_;
+ my @ret;
+
+ @ret = split ($sep, &gst_parse_split ($file, $key, $re, 0, $line_read_proc));
+
+ return \@ret;
+}
+
+sub gst_parse_split_first_array_pos
+{
+ my ($file, $key, $pos, $re, $sep, $line_read_proc) = @_;
+ my (@ret);
+
+ @ret = split ($sep, &gst_parse_split ($file, $key, $re, 0, $line_read_proc));
+ return $ret[$pos];
+}
+
+# Do an gst_parse_split_first_array and then make
+# the array elements unique. This is to fix broken
+# searchdomain entries in /etc/resolv.conf, for example.
+sub gst_parse_split_first_array_unique
+{
+ my ($file, $key, $re, $sep, $line_read_proc) = @_;
+ my (@arr, @res);
+ my (%hash, $i);
+
+ @arr = split ($sep, &gst_parse_split ($file, $key, $re, 0, $line_read_proc));
+
+ foreach $i (@arr)
+ {
+ next if exists $hash{$i};
+ $hash{$i} = 1;
+ push @res, $i;
+ }
+
+ return \@res;
+}
+
+# For all keys in $file, sepparated from its values
+# by $key_re, sepparate its values using $value_re
+# and assign to a newly created hash. Use ONLY when
+# you don't know what keys you are going to parse
+# (i.e. /etc/hosts). Any other application will not
+# be very portable and should be avoided.
+sub gst_parse_split_hash
+{
+ my ($file, $key_re, $value_re) = @_;
+ my ($fd, @line, %res, $key);
+
+ &gst_report_enter ();
+ &gst_report ("parse_split_hash", $file);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (<$fd>)
+ {
+ chomp;
+ s/^[ \t]+//;
+ s/[ \t]+$//;
+ s/\#.*$//;
+ next if (/^$/);
+ @line = split ($key_re, $_, 2);
+
+ $key = shift (@line);
+ push @{$res{$key}}, split ($value_re, $line[0]);
+ }
+
+ &gst_file_close ($fd);
+ &gst_report_leave ();
+ return undef if (scalar keys (%res) == 0);
+ return \%res;
+}
+
+# Same as above, but join lines that end with '\'.
+sub gst_parse_split_hash_with_continuation
+{
+ my ($file, $key_re, $value_re) = @_;
+ my ($fd, $l, @line, %res, $key);
+
+ &gst_report_enter ();
+ &gst_report ("parse_split_hash_cont", $file);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (($l = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$l;
+ chomp;
+ s/^[ \t]+//;
+ s/[ \t]+$//;
+ s/\#.*$//;
+ next if (/^$/);
+ @line = split ($key_re, $_, 2);
+
+ $key = shift (@line);
+ $res{$key} = [ split ($value_re, $line[0]) ];
+ }
+
+ &gst_file_close ($fd);
+ &gst_report_leave ();
+ return undef if (scalar keys (%res) == 0);
+ return \%res;
+}
+
+# Remove escape sequences in a shell value.
+sub gst_parse_shell_unescape
+{
+ my $ret = $_[0];
+
+ # Quote shell special chars.
+ $ret =~ s/\\\"/\\_/g;
+ $ret =~ s/\"//g;
+ $ret =~ s/\\_/\"/g;
+ $ret =~ s/\\\'/\\_/g;
+ $ret =~ s/\'//g;
+ $ret =~ s/\\_/\'/g;
+ $ret =~ s/\\(.)/$1/g;
+
+ return $ret;
+}
+
+# unescape (escape (x)) == x
+sub gst_parse_shell_escape
+{
+ my ($value) = @_;
+
+ $value =~ s/([\"\`\$\\])/\\$1/g;
+ $value = "\"$value\"" if ($value =~ /[ \t\'&|*?\[\]\{\}\{\}<>]/);
+
+ return $value;
+}
+
+# For files which are a list of /bin/sh shell variable declarations. (ie GATEWAY=10.10.10.1)
+sub gst_parse_sh
+{
+ my ($file, $key) = @_;
+ my $ret;
+
+ &gst_report_enter ();
+ &gst_report ("parse_sh", $key, $file);
+ $ret = &gst_parse_split_first_str ($file, $key, "[ \t]*=[ \t]*",
+ \&gst_parse_chomp_line_hash_comment);
+ &gst_report_leave ();
+
+ return &gst_parse_shell_unescape ($ret);
+}
+
+# Same, but interpret the returning value as a bool. (ie NETWORKING=yes)
+sub gst_parse_sh_bool
+{
+ my ($file, $key) = @_;
+ my $ret;
+
+ $ret = &gst_parse_sh ($file, $key);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+# Get an sh value and then split with $re, returning ref to resulting array.
+sub gst_parse_sh_split
+{
+ my ($file, $key, $re) = @_;
+ my (@ret, $val);
+
+ $val = &gst_parse_sh ($file, $key);
+ @ret = split ($re, $val);
+
+ return \@ret;
+}
+
+# Get a fully qualified hostname from a $key shell var in $file
+# and extract the hostname from there. e.g.: suse70's /etc/rc.config's FQHOSTNAME.
+sub gst_parse_sh_get_hostname
+{
+ my ($file, $key) = @_;
+ my ($val);
+
+ $val = &gst_parse_sh_split ($file, $key, "\\.");
+
+ return $$val[0];
+}
+
+# Get a fully qualified hostname from a $key shell var in $file
+# and extract the domain from there. e.g.: suse70's /etc/rc.config's FQHOSTNAME.
+sub gst_parse_sh_get_domain
+{
+ my ($file, $key) = @_;
+ my ($val);
+
+ $val = &gst_parse_sh_split ($file, $key, "\\.");
+
+ return join ".", @$val[1..$#$val];
+}
+
+# For files which are a list of /bin/sh shell variable exports. (eg export GATEWAY=10.10.10.1)
+sub gst_parse_sh_export
+{
+ my ($file, $key) = @_;
+ my $ret;
+
+ &gst_report_enter ();
+ &gst_report ("parse_sh", $key, $file);
+ $ret = &gst_parse_split_first_str ($file, $key, "[ \t]*=[ \t]*",
+ \&gst_parse_chomp_line_sh_export);
+ &gst_report_leave ();
+
+ return &gst_parse_shell_unescape ($ret);
+}
+
+# Same, but interpret the returing value as a bool. (ie export NETWORKING=yes)
+sub gst_parse_sh_export_bool
+{
+ my ($file, $key) = @_;
+ my $ret;
+
+ $ret = &gst_parse_sh_export ($file, $key);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+# Same, but accepting a regexp and returning the value between the paren operator
+sub gst_parse_sh_re
+{
+ my ($file, $key, $re) = @_;
+ my $ret;
+
+ $ret = &gst_parse_sh ($file, $key);
+
+ $ret =~ /$re/i;
+ return $1;
+}
+
+
+# Search for $keyword in $file, delimited by $re (default " ") or EOL.
+# If keyword exists, return 1, else 0.
+sub gst_parse_kw
+{
+ my ($file, $keyword, $re, $line_read_proc) = @_;
+ my $res;
+
+ &gst_report_enter ();
+ &gst_report ("parse_kw", $keyword, $file);
+
+ if (! -f "$gst_prefix/$file")
+ {
+ &gst_report_enter ();
+ &gst_report ("file_open_read_failed", $file);
+ &gst_report_leave ();
+ &gst_report_leave ();
+ return undef;
+ }
+
+ $re = " " if $re eq undef;
+ $res = &gst_parse_split_ref ($file, $keyword, $re, 0, $line_read_proc);
+
+ &gst_report_leave ();
+ return 0 if $res == -1;
+ return 1;
+}
+
+# A file containing the desired value in its first line. (ie /etc/hostname)
+sub gst_parse_line_first
+{
+ my ($file) = @_;
+ my ($fd, $res);
+
+ &gst_report_enter ();
+ &gst_report ("parse_line_first", $file);
+ $fd = &gst_file_open_read_from_names ($file);
+ &gst_report_leave ();
+
+ return undef if !$fd;
+
+ chomp ($res = <$fd>);
+ &gst_file_close ($fd);
+ return $res;
+}
+
+# parse a chat file, searching for an entry that matches $re.
+# $re must have one paren operator (ie "^atd[^0-9]*([0-9, -]+)").
+sub gst_parse_chat
+{
+ my ($file, $re) = @_;
+ my ($fd, $found);
+
+ &gst_report_enter ();
+ &gst_report ("parse_chat", $file);
+ $fd = &gst_file_open_read_from_names ("$file");
+ &gst_report_leave ();
+ return undef if !$fd;
+
+ while (<$fd>)
+ {
+ # We'll be emptying $_ as we "scan".
+ chomp;
+ while ($_ ne "")
+ {
+ # If it uses quotes. FIXME: Assuming they surround the whole string.
+ if (/^\'/)
+ {
+ s/\'([^\']*)\' ?//;
+ $found = $1;
+ }
+ else
+ {
+ s/([^ \t]*) ?//;
+ $found = $1;
+ }
+
+ # If it looks like what we're looking for, return what matched the parens.
+ if ($found =~ /$re/i)
+ {
+ &gst_file_close ($fd);
+ return $1;
+ }
+ }
+ }
+
+ &gst_file_close ($fd);
+ # Oops: not found.
+ return undef;
+}
+
+# Clean an ini line of comments and leading or
+# trailing spaces.
+sub gst_parse_ini_line_clean
+{
+ $_ = $_[0];
+
+ chomp;
+ s/\#.*//;
+ s/;.*//;
+ s/^[ \t]+//;
+ s/[ \t]+$//;
+
+ return $_;
+}
+
+# Read an ini line, which may have to be joined
+# with the next one if it ends with '\'.
+sub gst_parse_ini_line_read
+{
+ my $fd = $_[0];
+ my $l;
+
+ $l = <$fd>;
+ return -1 if ($l eq undef);
+
+ $l = &gst_parse_ini_line_clean ($l);
+ while ($l =~ /\\$/)
+ {
+ $l =~ s/\\$//;
+ $l .= &gst_parse_ini_line_clean (scalar <$fd>);
+ }
+
+ return \$l;
+}
+
+# Return an array of all found sections in $file.
+sub gst_parse_ini_sections
+{
+ my ($file) = @_;
+ my (@sections, $line);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (($line = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+ push @sections, $1 if (/\[([^\]]+)\]/i);
+ }
+
+ &gst_file_close ($fd);
+
+ return @sections;
+}
+
+# Get the value of a $var in a $section from $file.
+sub gst_parse_ini
+{
+ my ($file, $section, $var) = @_;
+ my ($fd, $res, $line);
+ my $found_section_flag = 0;
+
+ &gst_report_enter ();
+ &gst_report ("parse_ini", $var, $file, $section);
+ $fd = &gst_file_open_read_from_names ($file);
+ &gst_report_leave ();
+ $res = undef;
+
+ while (($line = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+
+ if (/\[$section\]/i)
+ {
+ $found_section_flag = 1;
+ next;
+ }
+
+ if ($found_section_flag)
+ {
+ if (/^$var[ \t]*=/i)
+ {
+ s/^$var[ \t]*=[ \t]*//i;
+ $res = $_;
+ last;
+ }
+ elsif (/\[\S+\]/i)
+ {
+ last;
+ }
+ }
+ }
+
+ &gst_file_close ($fd);
+
+ return $res;
+}
+
+# Same, but treat value as bool and return 1/0.
+sub gst_parse_ini_bool
+{
+ my ($file, $section, $var) = @_;
+ my $ret;
+
+ $ret = &gst_parse_ini ($file, $section, $var);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+sub gst_parse_cap_line_clean
+{
+ $_ = $_[0];
+
+ chomp;
+ s/^[ \t]*\#.*//;
+ s/;.*//;
+ s/^[ \t]+//;
+ s/[ \t]+$//;
+
+ return $_;
+}
+
+sub gst_parse_cap_line_read
+{
+ my $fd = $_[0];
+ my $l;
+
+ $l = <$fd>;
+ return -1 if ($l eq undef);
+
+ $l = &gst_parse_cap_line_clean ($l);
+ while ($l =~ /\\$/)
+ {
+ $l =~ s/\\$//;
+ $l .= &gst_parse_cap_line_clean (scalar <$fd>);
+ }
+
+ return \$l;
+}
+
+sub gst_parse_cap_sections
+{
+ my ($file) = @_;
+ my (@sections, $line);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (($line = &gst_parse_cap_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+ push @sections, $1 if (/^([^:|]+)/i);
+ }
+
+ &gst_file_close ($fd);
+ return @sections;
+}
+
+sub gst_parse_cap
+{
+ my ($file, $section, $var) = @_;
+ my ($fd, $res, $line);
+ my $found_section_flag = 0;
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $res = undef;
+
+ while (($line = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+ if (/^$section[:|]/i)
+ {
+ $found_section_flag = 1;
+ }
+
+ if ($found_section_flag && /:$var\#/i)
+ {
+ $_ =~ /:$var\#([^:]*)/;
+ $res = $1;
+ last;
+ }
+# if ($found_section_flag && /:$var[#=]/i)
+# {
+# $_ =~ /:$var[#=]([^:]*)/;
+# $res = $1;
+# last;
+# }
+ }
+
+ &gst_file_close ($fd);
+ return $res;
+}
+
+sub gst_parse_cap_bool
+{
+ my ($file, $section, $var) = @_;
+ my ($fd, $res, $line);
+ my $found_section_flag = 0;
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $res = 0;
+
+ while (($line = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+ if (/^$section[:|]/i)
+ {
+ $found_section_flag = 1;
+ }
+
+ if ($found_section_flag && /:$var[:\#=]/i)
+ {
+ $res = 1;
+ last;
+ }
+ }
+
+ &gst_file_close ($fd);
+ return $res;
+}
+
+# Load a printcap file to buffer, join \ lines and split them back up into a
+# 'one option, printtool comment or section name per line' format.
+sub gst_parse_printcap_buffer_load
+{
+ my ($file) = @_;
+ my ($inbuf, @outbuf);
+
+ $inbuf = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($inbuf);
+
+ for $i (@$inbuf)
+ {
+ my ($comment) = ("");
+
+ chomp $i;
+ $comment = $1 if $i =~ s/^([ \t]*[\#].*)//;
+
+ if ($i ne "")
+ {
+ my @line = split /:/, $i;
+
+ if ($i =~ /^[a-z0-9]+/i)
+ {
+ push @outbuf, ($line [0] . ":\n");
+ shift @line;
+ }
+
+ for $elem (@line)
+ {
+ $elem =~ s/^[ \t]//;
+ $elem =~ s/[ \t]$//;
+ if ($elem ne "")
+ {
+ push @outbuf, ("\t:$elem:\n");
+ }
+ }
+ }
+ elsif ($comment ne "")
+ {
+ push @outbuf, ($comment . "\n");
+ }
+ else
+ {
+ push @outbuf, "\n";
+ }
+ }
+
+ return \@outbuf;
+}
+
+# Find next printer definition, returning (printtool-comment-lineno, stanza-name-lineno).
+sub gst_parse_printcap_get_next_stanza
+{
+ my ($buf, $line_no) = @_;
+ my ($last_printtool_line) = (-1);
+
+ while ($line_no <= $#$buf)
+ {
+ if ($$buf [$line_no] =~ /^\#\#PRINTTOOL3\#\#/)
+ {
+ $last_printtool_line = $line_no;
+ }
+ elsif ($$buf [$line_no] =~ /^[a-z0-9]+/i)
+ {
+ return ($last_printtool_line, $line_no);
+ }
+
+ $line_no++;
+ }
+
+ return (-1, -1);
+}
+
+# Find next printer option.
+sub gst_parse_printcap_get_next_option
+{
+ my ($buf, $line_no) = @_;
+
+ while ($line_no <= $#$buf)
+ {
+ if ($$buf [$line_no] =~ /^\#\#PRINTTOOL3\#\#/ ||
+ $$buf [$line_no] =~ /^[a-z0-9]+/i)
+ {
+ last;
+ }
+
+ if ($$buf [$line_no] =~ /^\t:/)
+ {
+ return $line_no;
+ }
+
+ $line_no++;
+ }
+
+ return -1;
+}
+
+sub gst_parse_printcap_parse_stanza
+{
+ my ($stanza) = @_;
+ my ($key);
+
+ $key = $1 if $stanza =~ /^([a-z0-9]+)/i;
+ return $key;
+}
+
+sub gst_parse_printcap_parse_option
+{
+ my ($option) = @_;
+ my ($key, $value);
+
+ $key = $1 if $option =~ /^\t:([a-z0-9]+)/i;
+ $value = $1 if $option =~ /^\t:[a-z0-9]+[\#=]([a-z0-9\/_-]*)/i;
+ return ($key, $value);
+}
+
+# Locate stanza line for $printer in $buf, starting at $line_no.
+sub gst_parse_printcap_find_stanza
+{
+ my ($buf, $line_no, $printer) = @_;
+ my ($printtool_line_no, $found_printer);
+
+ while ((($printtool_line_no, $line_no) = &gst_parse_printcap_get_next_stanza ($buf, $line_no)))
+ {
+ if ($line_no == -1) { last; }
+
+ $found_printer = &gst_parse_printcap_parse_stanza ($$buf [$line_no]);
+ return ($printtool_line_no, $line_no) if ($found_printer eq $printer);
+ $line_no++;
+ }
+
+ return (-1, -1);
+}
+
+# Search buffer for option with key $key, starting
+# at $line_no position. Return line number, or -1 if not found.
+sub gst_parse_printcap_find_option
+{
+ my ($buf, $line_no, $key) = @_;
+ my $found_key;
+
+ while (($line_no = &gst_parse_printcap_get_next_option ($buf, $line_no)) != -1)
+ {
+ ($found_key) = &gst_parse_printcap_parse_option ($$buf [$line_no]);
+ return $line_no if ($found_key eq $key);
+ $line_no++;
+ }
+
+ return -1;
+}
+
+# High-level API.
+sub gst_parse_printcap
+{
+ my ($file, $section, $var) = @_;
+ my ($printtool_line_no, $stanza_line_no, $option_line_no);
+ my ($buf);
+ my ($key, $value);
+
+ $buf = &gst_parse_printcap_buffer_load ($file);
+
+ ($printtool_line_no, $stanza_line_no) = &gst_parse_printcap_find_stanza ($buf, 0, $section);
+ return undef if ($stanza_line_no == -1);
+
+ $option_line_no = &gst_parse_printcap_find_option ($buf, $stanza_line_no + 1, $var);
+ return undef if ($option_line_no == -1);
+
+ ($key, $value) = &gst_parse_printcap_parse_option ($$buf [$option_line_no]);
+ return $value;
+}
+
+# High-level API.
+sub gst_parse_printcap_bool
+{
+ my ($file, $section, $var) = @_;
+ my ($printtool_line_no, $stanza_line_no, $option_line_no);
+ my ($buf);
+ my ($key, $value);
+
+ $buf = &gst_parse_printcap_buffer_load ($file);
+
+ ($printtool_line_no, $stanza_line_no) = &gst_parse_printcap_find_stanza ($buf, 0, $section);
+ return 0 if ($stanza_line_no == -1);
+
+ $option_line_no = &gst_parse_printcap_find_option ($buf, $stanza_line_no + 1, $var);
+ return 0 if ($option_line_no == -1);
+
+ return 1;
+}
+
+# Debian interfaces(5) states that files starting with # are comments.
+# Also, leading and trailing spaces are ignored.
+sub gst_parse_interfaces_line_clean
+{
+ $_ = $_[0];
+
+ chomp;
+ s/^[ \t]+//;
+ s/^\#.*//;
+ s/[ \t]+$//;
+
+ return $_;
+}
+
+# interfaces(5) also states that \ line continuation is possible.
+sub gst_parse_interfaces_line_read
+{
+ my $fd = $_[0];
+ my $l;
+
+ $l = <$fd>;
+ return -1 if ($l eq undef);
+
+ $l = &gst_parse_interfaces_line_clean ($l);
+ while ($l =~ /\\$/)
+ {
+ $l =~ s/\\$//;
+ $l .= &gst_parse_interfaces_line_clean (scalar <$fd>);
+ }
+
+ return \$l;
+}
+
+# Read lines until a stanza, a line starting with $stanza_type is found.
+# Return ref to an array with the stanza params split.
+sub gst_parse_interfaces_get_next_stanza
+{
+ my ($fd, $stanza_type) = @_;
+ my $line;
+
+ while (($line = &gst_parse_interfaces_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ if (/^$stanza_type[ \t]+[^ \t]/)
+ {
+ s/^$stanza_type[ \t]+//;
+ return [ split ("[ \t]+", $_) ];
+ }
+ }
+
+ return -1;
+}
+
+# Read lines until a line not recognized as a stanza is
+# found, and split in a "tuple" of key/value.
+sub gst_parse_interfaces_get_next_option
+{
+ my $fd = $_[0];
+ my $line;
+
+ while (($line = &gst_parse_interfaces_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if /^$/;
+
+ return [ split ("[ \t]+", $_, 2) ] if (!/^iface[ \t]/);
+ return -1;
+ }
+
+ return -1;
+}
+
+# Get all stanzas from file. Return array.
+sub gst_parse_interfaces_stanzas
+{
+ my ($file, $stanza_type) = @_;
+ my ($fd, @res);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $res = undef;
+
+ while (($_ = &gst_parse_interfaces_get_next_stanza ($fd, $stanza_type)) != -1)
+ {
+ push @res, $_;
+ }
+
+ &gst_file_close ($fd);
+
+ return @res;
+}
+
+# Find stanza for $iface in $file, and return
+# tuple for option with $key. Return -1 if unexisting.
+sub gst_parse_interfaces_option_tuple
+{
+ my ($file, $iface, $key, $all) = @_;
+ my ($fd, @res);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (($stanza = &gst_parse_interfaces_get_next_stanza ($fd, "iface")) != -1)
+ {
+ if ($$stanza[0] eq $iface)
+ {
+ while (($tuple = &gst_parse_interfaces_get_next_option ($fd)) != -1)
+ {
+ if ($$tuple[0] =~ /$key/)
+ {
+ return $tuple if !$all;
+ push @res, $tuple;
+ }
+ }
+
+ return -1 if !$all;
+ }
+ }
+
+ return @res if $all;
+ return -1;
+}
+
+# Go get option $kw for $iface stanza. If found,
+# return 1 (true), else, false.
+sub gst_parse_interfaces_option_kw
+{
+ my ($file, $iface, $kw) = @_;
+ my $tuple;
+
+ &gst_report_enter ();
+ &gst_report ("parse_ifaces_kw", $kw, $file);
+ $tuple = &gst_parse_interfaces_option_tuple ($file, $iface, $kw);
+ &gst_report_leave ();
+
+ if ($tuple != -1)
+ {
+ &gst_report ("parse_ifaces_kw_strange", $iface, $file) if ($$tuple[1] ne "");
+
+ return 1;
+ }
+
+ return 0;
+}
+
+# For such keywords as noauto, whose existence means
+# a false value.
+sub gst_parse_interfaces_option_kw_not
+{
+ my ($file, $iface, $kw) = @_;
+
+ return &gst_parse_interfaces_option_kw ($file, $iface, $kw)? 0 : 1;
+}
+
+# Go get option $key for $iface in $file and return value.
+sub gst_parse_interfaces_option_str
+{
+ my ($file, $iface, $key) = @_;
+ my $tuple;
+
+ &gst_report_enter ();
+ &gst_report ("parse_ifaces_str", $kw, $file);
+ $tuple = &gst_parse_interfaces_option_tuple ($file, $iface, $key);
+ &gst_report_leave ();
+
+ if ($tuple != -1)
+ {
+ return $$tuple[1];
+ }
+
+ return undef;
+}
+
+
+# Implementing pump(8) pump.conf file format parser.
+# May be useful for dhcpd too.
+sub gst_parse_pump_get_next_option
+{
+ my ($fd) = @_;
+ my $line;
+
+ while (($line = &gst_parse_interfaces_line_read ($fd)) != -1)
+ {
+ $line = $$line;
+ if ($line ne "")
+ {
+ return [ split ("[ \t]+", $line, 2) ];
+ }
+ }
+
+ return -1;
+}
+
+sub gst_parse_pump_get_device
+{
+ my ($fd, $iface) = @_;
+ my ($opt);
+
+ while (($opt = &gst_parse_pump_get_next_option ($fd)) != -1)
+ {
+ if ($$opt[0] eq "device")
+ {
+ $$opt[1] =~ s/[ \t]*\{//;
+ return 1 if $$opt[1] eq $iface;
+ }
+ }
+
+ return 0;
+}
+
+sub gst_parse_pump_get_iface_option_ref
+{
+ my ($file, $iface, $key) = @_;
+ my ($fd, $opt, $ret);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ if (&gst_parse_pump_get_device ($fd, $iface))
+ {
+ while (($opt = &gst_parse_pump_get_next_option ($fd)) != -1)
+ {
+ if ($$opt[0] eq $key)
+ {
+ $ret = &gst_parse_shell_unescape ($$opt[1]);
+ return \$ret;
+ }
+
+ return -1 if ($$opt[0] eq "}");
+ }
+ }
+
+ return -1;
+}
+
+sub gst_parse_pump_get_iface_kw
+{
+ my ($file, $iface, $key) = @_;
+ my ($ret);
+
+ return 1 if &gst_parse_pump_get_iface_option_ref ($file, $iface, $key) != -1;
+ return 0;
+}
+
+sub gst_parse_pump_get_iface_kw_not
+{
+ my ($file, $iface, $key) = @_;
+
+ return 0 if &gst_parse_pump_get_iface_option_ref ($file, $iface, $key) != -1;
+ return 1;
+}
+
+# Read a variable out of an XML document. The varpath is the '/'-separated path to the
+# XML tag. If the name of a property is passed, that property of the leaf tag is read,
+# otherwise the tag's PCDATA.
+sub gst_parse_xml
+{
+ my ($file, $varpath, $property) = @_;
+ my ($model, $branch);
+
+ ($model) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_find ($model, $varpath);
+
+ if ($branch)
+ {
+ return &gst_xml_model_get_attribute ($branch, $property) if $property ne "";
+ return &gst_xml_model_get_pcdata ($branch);
+ }
+
+ return undef;
+}
+
+sub gst_parse_xml_child_names
+{
+ my ($file, $varpath) = @_;
+ my ($model, $branch, @children);
+
+ ($model) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_find ($model, $varpath);
+
+ if (!$branch) { return @children; }
+
+ my @list = @$branch;
+ shift @list; # Attributes
+
+ while (@list)
+ {
+ if ($list [0] ne "__unparsed__" && $list [0] ne "0")
+ {
+ push @children, shift @list;
+ }
+ else
+ {
+ shift @list;
+ }
+
+ shift @list;
+ }
+
+ return @children;
+}
+
+sub gst_parse_alchemist
+{
+ my ($file, $varpath) = @_;
+
+ $varpath = "/adm_context/datatree/" . $varpath;
+ return &gst_parse_xml ($file, $varpath, "VALUE");
+}
+
+sub gst_parse_alchemist_print
+{
+ my ($file, $printer, $varpath) = @_;
+
+ $varpath = "printconf/print_queues/" . $printer . "/" . $varpath;
+ return &gst_parse_alchemist ($file, $varpath);
+}
+
+sub gst_parse_alchemist_print_option
+{
+ my ($file, $printer, $name) = @_;
+ my ($varpath, $model, $branch, $fd, $options, $option);
+
+ ($model) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_find ($model, "/adm_context/datatree/printconf/print_queues/" . $printer .
+ "/filter_data/foomatic_defaults");
+
+ return undef if (!$branch);
+
+ $options = &gst_xml_model_get_children ($branch);
+
+ foreach $o (@$options)
+ {
+ my $opt_node = &gst_xml_model_find ($o, "name");
+ next if (!$opt_node);
+
+ if (&gst_xml_model_get_attribute ($opt_node, "VALUE") eq $name)
+ {
+ $option = $o;
+ last;
+ }
+ }
+
+ return undef if (!$option);
+
+ my $node = &gst_xml_model_find ($option, "default");
+ return undef if (!$node);
+
+ return &gst_xml_model_get_attribute ($node, "VALUE");
+}
+
+# extracts hostname from a fully qualified hostname
+# contained in a file
+sub gst_parse_fq_hostname
+{
+ my ($file) = @_;
+ my ($ret);
+
+ $ret = &gst_parse_line_first ($file);
+ $ret =~ s/\..*//; #remove domain
+
+ return $ret;
+}
+
+# extracts domain from a fully qualified hostname
+# contained in a file
+sub gst_parse_fq_domain
+{
+ my ($file) = @_;
+ my ($ret);
+
+ $ret = &gst_parse_line_first ($file);
+ $ret =~ s/^[^\.]*\.//;
+
+ return $ret;
+}
+
+sub gst_parse_rcinet1conf
+{
+ my ($file, $iface, $kw) = @_;
+ my ($line);
+
+ $iface =~ s/eth//;
+
+ #we must double escape those []
+ $line = "$kw\\[$iface\\]";
+
+ return &gst_parse_sh ($file, $line);
+}
+
+sub gst_parse_rcinet1conf_bool
+{
+ my ($file, $iface, $kw) = @_;
+ my ($ret);
+
+ $ret = &gst_parse_rcinet1conf ($file, $iface, $kw);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+sub gst_parse_wireless_opts
+{
+ my ($file, $iface, $proc, $kw) = @_;
+ my $ifaces = &$proc ();
+ my $found = 0;
+ my $search = 1;
+ my $val = "";
+ my $fd;
+
+ foreach $i (@$ifaces)
+ {
+ $found = 1 if ($iface eq $i);
+ }
+
+ return undef if (!$found);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ while (<$fd>)
+ {
+ $line = $_;
+
+ if ($line =~ /^case/)
+ {
+ # we don't want to search inside the case
+ $search = 0;
+ }
+ elsif ($line =~ /^esac/)
+ {
+ # continue searching
+ $search = 1;
+ }
+ elsif (($line =~ /^[ \t]*$kw/ ) && ($search))
+ {
+ $line =~ s/.*=//;
+
+ if ($line =~ /"(.*)"/)
+ {
+ $line = $1;
+ }
+
+ $val = $line;
+ }
+ }
+
+ &gst_file_close ($fd);
+ return $val;
+}
+
+# function for parsing /etc/start_if.$iface files in FreeBSD
+sub gst_parse_startif
+{
+ my ($file, $regex) = @_;
+ my ($fd, $line, $val);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $val = undef;
+
+ return undef if ($fd eq undef);
+
+ while (<$fd>)
+ {
+ chomp;
+
+ # ignore comments
+ next if (/^\#/);
+
+ if (/$regex/)
+ {
+ $val = $1;
+ }
+ }
+
+ # remove double quote
+ if ($val =~ /\"(.*)\"/)
+ {
+ $val = $1;
+ }
+
+ return $val;
+}
+
+# functions for parsing /etc/ppp/ppp.conf sections in FreeBSD
+sub gst_parse_pppconf_find_next_stanza
+{
+ my ($buff, $line_no) = @_;
+
+ $line_no = 0 if ($line_no eq undef);
+
+ while ($$buff[$line_no] ne undef)
+ {
+ if ($$buff[$line_no] !~ /^[\#\n]/)
+ {
+ return $line_no if ($$buff[$line_no] =~ /^[^ \t]+/);
+ }
+
+ $line_no++;
+ }
+
+ return -1;
+}
+
+sub gst_parse_pppconf_find_stanza
+{
+ my ($buff, $section) = @_;
+ my ($line_no) = 0;
+
+ while (($line_no = &gst_parse_pppconf_find_next_stanza ($buff, $line_no)) != -1)
+ {
+ return $line_no if ($$buff[$line_no] =~ /^$section\:/);
+ $line_no++;
+ }
+
+ return -1;
+}
+
+sub gst_parse_pppconf_common
+{
+ my ($file, $section, $key) = @_;
+ my ($fd, $val);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ return undef if ($fd eq undef);
+
+ $val = undef;
+
+ # First of all, we must find the line where the section begins
+ while (<$fd>)
+ {
+ chomp;
+ last if (/^$section\:[ \t]*/);
+ }
+
+ while (<$fd>)
+ {
+ chomp;
+
+ # read until the next section arrives
+ last if (/^[^ \t]/);
+
+ next if (/^\#/);
+
+ if (/^[ \t]+(add|set|enable|disable)[ \t]+$key/)
+ {
+ $val = $_;
+ last;
+ }
+ }
+
+ # this is done because commands can be multiline
+ while (<$fd>)
+ {
+ last if (/^[^ \t]/);
+ last if ($val !~ /\\$/);
+
+ s/^[ \t]*/ /;
+ $val =~ s/\\$//;
+ $val .= $_;
+ }
+
+ &gst_file_close ($fd);
+
+ if ($val eq undef)
+ {
+ return undef if ($section eq "default");
+ return &gst_parse_pppconf_common ($file, "default", $key);
+ }
+ else
+ {
+ $val =~ s/\#[^\#]*$//;
+ $val =~ s/[ \t]*$//;
+ $val =~ s/^[ \t]*//;
+ return $val;
+ }
+}
+
+sub gst_parse_pppconf
+{
+ my ($file, $section, $key) = @_;
+ my ($val);
+
+ $val = &gst_parse_pppconf_common ($file, $section, $key);
+
+ if ($val =~ /$key[ \t]+(.+)/)
+ {
+ return $1;
+ }
+}
+
+sub gst_parse_pppconf_bool
+{
+ my ($file, $section, $key) = @_;
+ my ($val);
+
+ $val = &gst_parse_pppconf_common ($file, $section, $key);
+
+ return 1 if ($val ne undef);
+ return 0;
+}
+
+sub gst_parse_pppconf_re
+{
+ my ($file, $section, $key, $re) = @_;
+ my ($val);
+
+ $val = &gst_parse_pppconf_common ($file, $section, $key);
+
+ if ($val =~ /$re/i)
+ {
+ return $1;
+ }
+}
+
+sub gst_parse_confd_net
+{
+ my ($file, $key) = @_;
+ my ($str, $contents, $i);
+
+ $contents = &gst_file_buffer_load ($file);
+
+ for ($i = 0; $i <= scalar (@$contents); $i++)
+ {
+ # search for key
+ if ($$contents[$i] =~ /^$key[ \t]*=[ \t]*\(/)
+ {
+ # contents can be multiline,
+ # just get the first value
+ do {
+ $$contents[$i] =~ /\"([^\"]*)\"/;
+ $str = $1;
+ $i++;
+ } while (!$str);
+ }
+ }
+
+ return $str;
+}
+
+sub gst_parse_confd_net_re
+{
+ my ($file, $key, $re) = @_;
+ my ($str);
+
+ $str = &gst_parse_confd_net ($file, $key);
+
+ if ($str =~ /$re/i)
+ {
+ return $1;
+ }
+}