Developer Forums | About Us | Site Map
Search  
HOME > TUTORIALS > SERVER SIDE CODING > PERL TUTORIALS > THE ROAD TO BETTER PROGRAMMING: CHAPTER 7. TOP LEVEL CONTROL FLOW


Sponsors





Useful Lists

Web Host
site hosted by netplex

Online Manuals

The road to better programming: Chapter 7. Top-level control flow
By Teodor Zlatanov - 2004-03-15 Page:  1 2 3 4 5

The main loop

The main cfperl loop is, as follows:

  1. Modules
  2. Constants
  3. Initialization, globals, grammars
  4. cfrun loop

Actually, before the modules, two things are done. First is a preamble (program identification, the GPL license). Then the $VERSION variable is declared and initialized to be the same as the CVS revision. Note the use of $Revision: 1.9 $ and $Id: c10.xml,v 1.9 2002/06/09 23:27:55 lifelogs Exp $, which are automatically filled in by CVS on check-in. $VERSION is introduced here, because it is (conceptually) a meta-variable: not used directly by cfperl itself, but reflecting something about the state of cfperl.

Listing 1. cfperl preamble

        
#!/usr/bin/perl -w
# cfperl.pl: cfengine parser in Perl
# by tzz@iglou.com $Id: c10.xml,v 1.9 2002/06/09 23:27:55 lifelogs Exp $

#  ... license omitted ... 

my $VERSION = sprintf('%d.%02d', (q$Revision: 1.9 $ =~ /\d+/g));

The modules section is next. I use the folding-mode provided by Emacs; the # {{{ and # }}} strings indicate the beginning and end of a section, respectively.

Listing 2. cfperl modules


        
# {{{ modules
use Data::Dumper;
use English;
use strict;
use POSIX;
use Parse::RecDescent;
use Carp;
use File::Basename;
use AppConfig qw/:expand :argcount/;
use IO::File;
use Sys::Hostname;
# }}}

Next is the constants section. I give symbolic names to each cfengine configuration section we handle specifically, and these symbolic names are used throughout the cfperl source code instead of string constants. Also the name of the "any" class is defined here as a constant, and the default global configuration file is set. Constants make source code much easier to maintain; always look for opportunities to use constants instead of variables.

Listing 3. cfperl constants

        
# {{{ constants
use constant GLOBAL_CONFIG_FILE => '/etc/cfengine/cfengine.conf';

use constant ANY_CLASS    => 'any';

use constant GROUPS_SECTION   => 'groups';
use constant IMPORT_SECTION   => 'import';
use constant CONTROL_SECTION  => 'control';
use constant DEFAULT_SECTION  => 'default';
use constant CRON_SECTION   => 'cron';
# }}}

The initialization, globals, and grammars sections are next. I am omitting the grammars from the code samples here, since they will be examined in a future chapter.

Auto-flushing the output and terse output for Data::Dumper are vital settings to aid debugging. The AppConfig options will be explained in the section on configuration options. Having a global $config object helps greatly in managing configuration options.

The globals are set to a default if they are scalars (a good practice to avoid obscure bugs is to always initialize your variables -- but to never assume that they are initialized). The cfrun queue and order, and the classes hash will be explained in future chapters. They are defined to be global to make access easier, since they are used throughout cfperl.

Listing 4. cfperl initialization and globals

        
# {{{ initialization settings
$| = 1;         # auto-flush the output
$Data::Dumper::Terse = 1;   # produce human-readable Data::Dumper output
$Data::Dumper::Indent = 0;    # produce human-readable Data::Dumper output

my $config = AppConfig->new();
$config->define(
# see the section on configuration options for the full AppConfig definitions
         );
# }}}

# {{{ globals
my $current_section = 'control';# the current section while parsing
my $current_classes = 'any';  # the current classes while parsing, starts out as 'any'
my @cfrun_queue;   # the cfrun queue (cfrun atoms, see add_line)
my %classes;      # the list of defined classes
my @cfrun_order;    # the defined order of execution
# }}}

After further initializations of the defined classes and processing of configuration options (we will explain configuration options in the section on configuration options), the process_line() and cfrun() functions are invoked on the cfengine configuration given to cfperl. Note that the -exec (or -e) options will run process_line() and cfrun() earlier, on the parameter given to -e.

Listing 5. cfperl main loop

        
my $input_line;
while ($input_line = <$config_file>)
{
 chomp $input_line;
 process_line($input_line);
}

cfrun();


View The road to better programming: Chapter 7. Top-level control flow Discussion

Page:  1 2 3 4 5 Next Page: The control flow

First published by IBM developerWorks


Copyright 2004-2017 GrindingGears.com. All rights reserved.
Article copyright and all rights retained by the author.