Command File Parser
By: Wout Mertens - Revised: 2006-07-11 devin
Introduction
A shell & perl script that parses a command file and handles if/then/else type structures.
Script
create-defines.sh#!/bin/bash
# Get the user requested defines
# UDEFS is a list of keywords, and is meant to be writeable by your users
# PRE and POSTCMD get added as command files if they exist, allowing
# system defines or system-local command files.
# (note that system-local transcripts won't be able to be downloaded from the
# server though)
DEFDIR=/var/radmind/state
UDEFS=/etc/TACSUNS/flags/user-radmind-defines
PRECMD=$DEFDIR/pre-command.K
POSTCMD=$DEFDIR/post-command.K
DEFAULTS=/var/radmind/client/defines.K
COMMAND=/var/radmind/client/command.K
if [ -n "$1" ]; then
COMMAND=$1
fi
[ -r $DEFAULTS ] && echo k $DEFAULTS
# Let's assume defines only contain a-zA-Z0-9 and _ or -
[ -r $UDEFS ] && egrep '^#(define|undef) [a-zA-Z0-9_-][a-zA-Z0-9_-]*$' $UDEFS
[ -r $PRECMD ] && echo k $PRECMD
echo k command.K
[ -r $POSTCMD ] && echo k $POSTCMD
exit 0
parse-command.pl
#!/usr/bin/perl
# Parse a command file, creating a new command file
# Features:
# - Consolidates command files
# - Removes duplicate transcripts
# - Allows removing a transcript
# - ifdef statements
# - standard defines: ppc, intel, osx, panther, tiger, leopard, linux, solaris
#
# Syntax of a parseable command file:
# [p|n|k] [file] : as normal
# #- [file] : remove a transcript from the list
# #define [foo] : define a condition named foo
# #undef [foo] : delete the condition named foo
# #ifdef [foo] : parse this block if foo is defined
# #else : otherwise, parse this block
# #endif : end of an if block
# Anything else is ignored
# !!! Important: If a command file is called defines.K, it is NOT included.
# This allows you to send along standard defines that can be used by the
# define stage described below.
#
# Recommended use:
# "standard" radmind sequence is ktcheck, fsdiff, lapply
# this should become ktcheck, define, parse, fsdiff, lapply
# - define stage: Business logic that creates a file that looks like:
# k defines.K
# #define foo
# #undef bar
# k command.K
# and saves it as /var/radmind/client/defines.K
# Note that you could use user preferences to generate this.
# - parse stage: Run this script on /var/radmind/client/defines.K
# and send the output to /var/radmind/client/parsed.K
# - fsdiff stage should then use parsed.K instead of command.K
use strict;
my %transcripts;
my %type;
my %defines;
my $count=0;
# Standard defines. Only tested on OSX/ppc.
chomp(my $uname = `uname -sp`);
if ($uname) {
$uname =~ /powerpc/i and $defines{ppc} = 1;
$uname =~ /intel/i and $defines{intel} = 1;
if ($uname =~ /darwin/i) {
$defines{osx} = 1;
chomp(my $version = `uname -r`);
$version =~ /^7\./i and $defines{panther} = 1;
$version =~ /^8\./i and $defines{tiger} = 1;
$version =~ /^9\./i and $defines{leopard} = 1;
}
$uname =~ /linux/i and $defines{linux} = 1;
$uname =~ /solaris/i and $defines{solaris} = 1;
}
sub test_def {
my $name = lc(shift);
warn "Warning: Illegal define: \"$name\". Defines should only contain alphanumerics."
unless $name =~ /^[a-z0-9_-]+$/;
return $name;
}
sub read_command {
my $cmd = shift;
local *CFILE;
open(CFILE,"<",$cmd) or die "Can't open $cmd: $!";
# My Fugly Parser
my $iflvl=0;
my $ifshow=0;
while (my $line = <CFILE>) {
chomp ($line);
next unless $line =~ m/^\s*([npk]|#(-|ifdef|else|endif|define|undef))\s*(.*)$/;
my $type = $1;
my $name = $3;
#print "$type $name $iflvl $ifshow\n";
# First handle flow control
if ($type eq "#endif") {
$iflvl--;
$ifshow = 0 if ($ifshow > $iflvl);
} elsif ($type eq "#else") {
if ($ifshow) {
if ($iflvl == $ifshow) {
$ifshow = 0;
}
} else {
$ifshow = $iflvl;
}
} elsif ($type eq "#ifdef") {
$iflvl++;
$name=test_def($name);
if(!$ifshow && !defined($defines{$name})) {
$ifshow=$iflvl;
}
}
next if $ifshow && $iflvl >= $ifshow;
# Now handle the rest
if ($type eq "k") {
next if $name eq "defines.K";
read_command($name);
} elsif ($type eq "n" or $type eq "p") {
$transcripts{$name}=$count;
$type{$name}=$type;
$count++;
} elsif ($type eq "#-") {
delete $transcripts{$name};
} elsif ($type eq "#define") {
$name=test_def($name);
$defines{$name}=1;
} elsif ($type eq "#undef") {
$name=test_def($name);
delete $defines{$name};
}
}
warn "Warning: Unmatched ifdef statement!\n" if ($iflvl);
close CFILE;
}
my $commandfile = "/var/radmind/client/command.K";
if ($#ARGV > -1) {
$commandfile = $ARGV[0];
}
if ($commandfile =~ /^(.*)\/([^\/]*)/) {
my $dir = $1;
$commandfile = $2;
chdir($dir) || die "Could not chdir to $dir: $!";
}
# Parse command file
read_command $commandfile;
# Print transcripts that survived parsing, in order
foreach my $key (sort { $transcripts{$a} <=> $transcripts{$b} } keys %transcripts) {
print "$type{$key} $key\n";
}
exit 0;