[selinux-policy: 264/3172] initial commit

Daniel J Walsh dwalsh at fedoraproject.org
Thu Oct 7 19:27:44 UTC 2010


commit 89ec2321b71cdd48a654bb1b81b3e03f968f1ce2
Author: Chris PeBenito <cpebenito at tresys.com>
Date:   Tue Jun 7 18:23:00 2005 +0000

    initial commit

 refpolicy/support/fc_sort.c    |  484 ++++++++++++++++++++++++++++++++++++++++
 refpolicy/support/pyplate.py   |  391 ++++++++++++++++++++++++++++++++
 refpolicy/support/sedoctool.py |  143 ++++++++++++
 3 files changed, 1018 insertions(+), 0 deletions(-)
---
diff --git a/refpolicy/support/fc_sort.c b/refpolicy/support/fc_sort.c
new file mode 100644
index 0000000..4ebf1e5
--- /dev/null
+++ b/refpolicy/support/fc_sort.c
@@ -0,0 +1,484 @@
+#include <stdio.h>
+
+/* file_context_node
+ * A node used in a linked list of file contexts.
+ * Each node contains the regular expression, the type and 
+ *  the context, as well as information about the regular
+ *  expression. The regular expression data (meta, stem_len
+ *  and str_len) can be filled in by using the fc_fill_data
+ *  function after the regular expression has been loaded.
+ * next points to the next node in the linked list.
+ */
+struct file_context_node { 
+	char* regex;
+	char* type;
+        char* context;
+        int meta;
+        int stem_len;
+        int str_len;
+
+        struct file_context_node* next;
+};
+
+
+
+/* file_context_bucket
+ * A node used in a linked list of buckets that contain
+ *  file_context_node's.
+ * Each node contains a pointer to a file_context_node which
+ *  is the header of its linked list. This linked list is the
+ *  content of this bucket.
+ * next points to the next bucket in the linked list.
+ */
+struct file_context_bucket {
+	struct file_context_node* data;
+
+	struct file_context_bucket* next;
+};
+
+
+
+/* fc_merge
+ * Merges two sorted file context linked lists into one
+ *  sorted one.
+ * Pass two lists a and b, and after the completion of fc_merge,
+ *  the final list is contained in a, and b is empty.
+ */
+struct file_context_node* fc_merge( struct file_context_node* a, struct file_context_node* b )
+{
+        struct file_context_node* a_current;
+        struct file_context_node* b_current;
+        struct file_context_node* temp;
+        struct file_context_node* jumpto;
+
+        /* If a is a empty list, and b is not,
+         *  set a as b and proceed to the end. */
+        if( !a && b )
+                a = b;
+        /* If b is an empty list, leave a as it is. */
+        else if( !b ) { }
+        else {
+                /* Make it so the list a has the lesser
+                 *  first element always. */
+                if( fc_compare( a, b ) == 1 ) {
+                        temp = a;
+                        a = b;
+                        b = temp;
+                }
+                a_current = a;
+                b_current = b;
+
+                /* Merge by inserting b's nodes inbetween a's nodes. */
+                while( a_current->next && b_current ) {
+                        jumpto = a_current->next;
+
+                        /* Insert b's nodes inbetween the current a node
+                         *  and the next a node.*/
+                        while( b_current && a_current->next &&
+                               fc_compare( a_current->next, b_current) != -1 ) {                                temp = a_current->next;
+                                a_current->next = b_current;
+                                b_current = b_current->next;
+                                a_current->next->next = temp;
+                                a_current = a_current->next;
+                        }
+
+                        /* Skip all the inserted node from b to the
+                         *  next node in the original a. */
+                        a_current = jumpto;
+                }
+
+
+                /* if there is anything left in b to be inserted,
+                   put it on the end */
+                if( b_current ) {
+                        a_current->next = b_current;
+                }
+        }
+
+        b = NULL;
+
+        return a;
+}
+
+
+
+/* fc_merge_sort
+ * Sorts file contexts from least specific to more specific.
+ * The bucket linked list is passed and after the completion
+ *  of the fc_merge_sort function, there is only one bucket
+ *  (pointed to by master) that contains a linked list
+ *  of all the file contexts, in sorted order.
+ * Explanation of the algorithm:
+ *  The algorithm implemented in fc_merge_sort is an iterative
+ *   implementation of merge sort.
+ *  At first, each bucket has a linked list of file contexts
+ *   that are 1 element each.
+ *  Each pass, each odd numbered bucket is merged into the bucket
+ *   before it. This halves the number of buckets each pass.
+ *  It will continue passing over the buckets (as described above)
+ *   until there is only  one bucket left, containing the list of
+ *   file contexts, sorted.
+ */
+void fc_merge_sort( struct file_context_bucket* master )
+{
+        int i;
+
+        struct file_context_bucket* current;
+        struct file_context_bucket* temp;
+
+        struct file_context_node* ncurrent;
+        struct file_context_node* ntemp;
+
+	/* Loop until master is the only bucket left
+         * so that this will stop when master contains
+	 * the sorted list. */
+        while( master->next ) {
+                current = master;
+
+		/* This loop merges buckets two-by-two. */
+		while( current ) {
+                        if( current->next ) {
+				/* Merge the next one into the current one. */
+                                current->data = fc_merge( current->data, current->next->data );
+                        	/* remove the next bucket that is now empty. */
+				temp = current->next;
+                                current->next = current->next->next;
+                                free( temp );
+                        }
+                        current = current->next;
+                }
+        }
+}
+
+/* fc_compare
+ * Compares two file contexts' regular expressions and returns:
+ *    -1 if a is less specific than b
+ *     0 if a and be are equally specific
+ *     1 if a is more specific than b
+ * The comparison is based on the following statements,
+ *  in order from most important to least important, given a and b:
+ *     If a is a regular expression and b is not,
+ *      -> a is less specific than b.
+ *     If a's stem length is shorter than b's stem length,
+ *      -> a is less specific than b.
+ *     If a's string length is shorter than b's string length,
+ *      -> a is less specific than b.
+ *     If a does not have a specified type and b does not,
+ *      -> a is less specific than b.
+ */
+int fc_compare( struct file_context_node* a, struct file_context_node* b )
+{
+	/* Check to see if either a or b have meta characters
+         *  and the other doesn't. */
+        if( a->meta && !b->meta )
+                return -1;
+        if( b->meta && !a->meta )
+                return 1;
+
+	/* Check to see if either a or b have a shorter stem
+         *  length than the other. */
+        if( a->stem_len < b->stem_len )
+                return -1;
+        if( b->stem_len < a->stem_len )
+                return 1;
+
+	/* Check to see if either a or b have a shorter string
+         *  length than the other. */
+        if( a->str_len < b->str_len )
+                return -1;
+        if( b->str_len < b->str_len )
+                return 1;
+
+	/* Check to see if either a or b has a specified type
+         *  and the other doesn't. */
+        if( !a->type && b->type )
+                return -1;
+        if( !b->type && a->type )
+                return 1;
+
+	/* If none of the above conditions were satisfied, 
+         * then a and b are equally specific. */
+        return 0;
+}
+
+
+
+/* fc_fill_data
+ * This processes a regular expression in a file context
+ *  and sets the data held in file_context_node, namely
+ *  meta, str_len and stem_len. 
+ * The following changes are made to fc_node after the
+ *  the completion of the function:
+ *     fc_node->meta =		1 if regex has a meta character,
+ *                       	0 if not.
+ *     fc_node->str_len =	The string length of the regular
+ *                               expression.
+ *     fc_node->stem_len = 	The number of characters up until
+ *				 the first meta character.
+ */
+void fc_fill_data( struct file_context_node* fc_node )
+{
+        int c = 0;
+
+        fc_node->meta = 0;
+        fc_node->stem_len = 0;
+        fc_node->str_len = 0;
+
+	/* Process until the string termination character
+         *  has been reached.
+	 * Note: this while loop has been adapted from
+         *  spec_hasMetaChars in matchpathcon.c from
+         *  libselinux-1.22. */
+        while( fc_node->regex[c] != 0 ) {
+                switch( fc_node->regex[c] ) {
+                        case '.':
+                        case '^':
+                        case '$':
+                        case '?':
+                        case '*':
+                        case '+':
+                        case '|':
+                        case '[':
+                        case '(':
+                        case '{':
+            			/* If a meta character is found,
+                                 *  set meta to one */
+		                fc_node->meta = 1;
+                                break;
+                        case '\\':
+				/* If a escape character is found,
+                                 *  skip the next character. */
+                                c++;
+                        default:
+				/* If no meta character has been found yet,
+				 *  add one to the stem length. */
+                                if( !fc_node->meta ) fc_node->stem_len++;
+                                break;
+                }
+
+		fc_node->str_len++;
+                c++;
+        }
+}
+
+/* main
+ * This program takes in two arguments, the input filename and the
+ *  output filename. The input file should be syntactically correct.
+ * Overall what is done in the main is read in the file and store each
+ *  line of code, sort it, then output it to the output file.
+ */
+int main( int argc, char *argv[])
+{
+	int i, j, lines;
+	int start, finish;
+	char* str;
+	struct file_context_node* temp;
+	struct file_context_node* head;
+	struct file_context_node* current;
+	struct file_context_node* array; 
+	struct file_context_bucket* master;
+	struct file_context_bucket* bcurrent;
+
+	FILE *path;
+	char line_buf[ 127 ];
+
+	/* Check for the correct number of command line arguments. */
+	if( argc != 3 ) {
+		printf( "Error: invalid number of command line arguments.\n" );
+		return -1;
+	}
+
+	i = j = lines = 0;
+
+	/* Allocate the head of the file_context linked list. */
+	if( !( current = head = (struct file_context_node*)malloc( sizeof( struct file_context_node ) ) ) ) {
+		printf( "Error: failure allocating memory.\n" );
+		return -1;
+	}
+	
+	/* Make sure to have a terminating character, always. */
+	line_buf[127] = 0;
+
+	/* Open the input file. */
+	if( !( path = fopen( argv[1], "r" ) ) ) {
+		printf( "Error: failure opening input file for read.\n" );
+		return -1;
+	}
+
+	/* Parse the file into a file_context linked list. */
+	while( fgets( line_buf, 126, path ) != NULL ) {
+
+		/* Get rid of whitespace from the front of the line. */
+		i = 0;
+		while( line_buf[i] && line_buf[i] <= 32 ) i++;
+
+		/* Check if the line isn't empty and isn't a comment */
+		if( line_buf[i] && line_buf[i] != '#' ) {
+			/* Allocate a new node. */
+			temp = (struct file_context_node*)malloc( sizeof( struct file_context_node ) );
+			if( !temp ) {
+				printf( "Error: failure allocating memory.\n" );
+				return -1;
+			}
+			temp->next = NULL;
+
+			/* Parse out the regular expression from the line. */
+			start = i;
+			while( line_buf[i] > 32 )i++;
+			finish = i;
+
+			/* Allocate a character array to hold the regular
+ 			 *  expression. */
+			temp->regex = (char*)malloc( sizeof( char ) * ( finish - start + 1) );
+			if( !( temp->regex ) ) {
+				printf( "Error: failure allocating memory.\n" );
+				return -1;
+			}
+			temp->regex[0] = 0;
+
+			/* Fill the regular expression array. */
+			temp->regex[ ( finish - start ) ] = 0;
+			for( j = 0; j < finish - start; j++ ) {
+				temp->regex[j] = line_buf[j + start];
+			}
+
+			/* Get rid of whitespace after the regular
+                         *  expression. */
+			while( line_buf[i] <= 32 ) i++;
+
+			/* Parse out the type from the line (if it 
+                         *  is there). */
+			if( line_buf[i] == '-' ) {
+				/* Allocate a character array to
+                                 *  hold the type. */
+				temp->type = (char*)malloc( sizeof( char ) * 3 );
+				if( !( temp->type ) ) {
+					printf( "Error: failure allocating memory.\n" );
+					return -1;
+				}
+
+				/* Fill the type into the array. */
+				temp->type[0] = line_buf[i];
+				temp->type[1] = line_buf[i + 1];
+				i += 2;
+				temp->type[2] = 0;
+				
+				/* Get rid of whitespace after the type. */
+				while( line_buf[i] <= 32 ) i++;
+			}
+
+			/* Parse out the context from the line. */
+                        start = i;
+                        while( line_buf[i] > 32 ) i++;
+                        finish = i;
+
+			/* Allocate a character array to hold the context. */
+                        temp->context = (char*)malloc( sizeof( char ) * ( finish - start + 1 ) );
+			if( !( temp->context ) ) {
+				printf( "Error: failure allocating memory.\n" );
+				return -1;
+			}
+			temp->context[0] = 0;
+
+			/* Fill the context array. */
+                        temp->context[ ( finish - start ) ] = 0;
+                        for( j = 0; j < finish - start; j++ ) {
+                                temp->context[j] = line_buf[j + start];
+                        }
+
+			/* Set all the data about the regular
+                         *  expression. */
+			fc_fill_data( temp );
+
+			/* Link this line of code at the end of
+                         *  the linked list. */
+			current->next = temp;
+			current = current->next;
+			lines++;
+		}
+	}
+	fclose( path );
+
+	/* Create the bucket linked list from the earlier linked list. */
+	current = head->next;
+	bcurrent = master = (struct file_context_bucket*)malloc( sizeof( struct file_context_bucket ) );
+	/* Go until all the nodes have been put in individual buckets. */
+	while( current ) {
+		/* Copy over the file context line into the bucket. */
+		bcurrent->data = current;
+		current = current->next;
+
+		/* Detatch the node in the bucket from the old list. */
+		bcurrent->data->next = NULL;
+
+		/* If there should be another bucket, put one at the end. */
+		if( current ) {
+			bcurrent->next = (struct file_context_bucket*) malloc( sizeof( struct file_context_bucket ) );
+			if( !( bcurrent->next ) ) {
+				printf( "Error: failure allocating memory.\n" );
+				return -1;
+			}
+
+			/* Make sure the new bucket thinks it's the end of the
+                         *  list. */
+			bcurrent->next->next = NULL;
+
+			bcurrent = bcurrent->next;
+		}
+	}
+
+	/* Sort the bucket list. */
+	fc_merge_sort( master );
+
+	/* Open the output file. */
+	if( !(path = fopen( argv[2], "w" ) ) ) {
+		printf( "Error: failure opening output file for write.\n" );
+		return -1;
+	}
+
+	/* Output the sorted file_context linked list to the output file. */
+	current = master->data;
+	while( current ) {
+		/* Output the regular expression. */
+		i = 0;
+		while( current->regex[i] != 0 ) {
+			fprintf( path, "%c", current->regex[i] );
+			i++;
+		}
+		fprintf( path, "\t" );
+		
+		/* Output the type, if there is one. */
+		if( current->type ) {
+			i = 0;
+			while( current->type[i] != 0 ) {
+				fprintf( path, "%c", current->type[i] );
+				i++;
+			}
+			fprintf( path, "\t" ); 	
+		}
+
+		/* Output the context. */
+		i = 0;
+		while( current->context[i] != 0 ) {
+			fprintf( path, "%c", current->context[i] );
+			i++;
+		}
+		fprintf( path, "\n" );
+
+		/* Remove the node. */
+		temp = current;
+		current = current->next;
+
+		free( temp->regex );
+		if( temp->type)
+			free( temp->type );
+		free( temp->context );		
+		free( temp );
+	}
+	free( master );
+
+	fclose( path );
+
+	return 0;
+}
+
diff --git a/refpolicy/support/pyplate.py b/refpolicy/support/pyplate.py
new file mode 100755
index 0000000..20b1bc6
--- /dev/null
+++ b/refpolicy/support/pyplate.py
@@ -0,0 +1,391 @@
+"""PyPlate : a simple Python-based templating program
+
+PyPlate parses a file and replaces directives (in double square brackets [[ ... ]])
+by various means using a given dictionary of variables.  Arbitrary Python code
+can be run inside many of the directives, making this system highly flexible.
+
+Usage:
+# Load and parse template file
+template = pyplate.Template("output") (filename or string)
+# Execute it with a dictionary of variables
+template.execute_file(output_stream, locals())
+
+PyPlate defines the following directives:
+  [[...]]       evaluate the arbitrary Python expression and insert the
+                result into the output
+
+  [[# ... #]]   comment.
+
+  [[exec ...]]  execute arbitrary Python code in the sandbox namespace
+
+  [[if ...]]    conditional expressions with usual Python semantics
+  [[elif ...]]
+  [[else]]
+  [[end]]
+
+  [[for ... in ...]]  for-loop with usual Python semantics
+  [[end]]
+
+  [[def ...(...)]]  define a "function" out of other templating elements
+  [[end]]
+
+  [[call ...]]  call a templating function (not a regular Python function)
+"""
+
+#
+# Copyright (C) 2002 Michael Droettboom
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU 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 General Public License for more details.
+# 
+# You should have received a copy of the GNU 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.
+#
+
+from __future__ import nested_scopes
+import sys, string, re, cStringIO
+
+re_directive = re.compile("\[\[(.*)\]\]")
+re_for_loop = re.compile("for (.*) in (.*)")
+re_if = re.compile("if (.*)")
+re_elif = re.compile("elif (.*)")
+re_def = re.compile("def (.*?)\((.*)\)")
+re_call = re.compile("call (.*?)\((.*)\)")
+re_exec = re.compile("exec (.*)")
+re_comment = re.compile("#(.*)#")
+
+############################################################
+# Template parser
+class ParserException(Exception):
+  def __init__(self, lineno, s):
+    Exception.__init__(self, "line %d: %s" % (lineno, s))
+
+class Template:
+  def __init__(self, filename=None):
+    if filename != None:
+      try:
+        self.parse_file(filename)
+      except:
+        self.parse_string(filename)
+
+  def parse_file(self, filename):
+    file = open(filename, 'r')
+    self.parse(file)
+    file.close()
+
+  def parse_string(self, template):
+    file = cStringIO.StringIO(template)
+    self.parse(file)
+    file.close()
+
+  def parse(self, file):
+    self.file = file
+    self.line = self.file.read()
+    self.lineno = 0
+    self.functions = {}
+    self.tree = TopLevelTemplateNode(self)
+
+  def parser_get(self):
+    if self.line == '':
+      return None
+    return self.line
+
+  def parser_eat(self, chars):
+    self.lineno = self.lineno + self.line[:chars].count("\n")
+    self.line = self.line[chars:]
+
+  def parser_exception(self, s):
+    raise ParserException(self.lineno, s)
+
+  def execute_file(self, filename, data):
+    file = open(filename, 'w')
+    self.execute(file, data)
+    file.close()
+
+  def execute_string(self, data):
+    s = cStringIO.StringIO()
+    self.execute(s, data)
+    return s.getvalue()
+
+  def execute_stdout(self, data):
+    self.execute(sys.stdout, data)
+
+  def execute(self, stream=sys.stdout, data={}):
+    self.tree.execute(stream, data)
+
+  def __repr__(self):
+    return repr(self.tree)
+
+
+############################################################
+# NODES
+class TemplateNode:
+  def __init__(self, parent, s):
+    self.parent = parent
+    self.s = s
+    self.node_list = []
+    while 1:
+      new_node = TemplateNodeFactory(parent)
+      if self.add_node(new_node):
+        break
+
+  def add_node(self, node):
+    if node == 'end':
+      return 1
+    elif node != None:
+      self.node_list.append(node)
+    else:
+      raise self.parent.parser_exception(
+        "[[%s]] does not have a matching [[end]]" % self.s)
+
+  def execute(self, stream, data):
+    for node in self.node_list:
+      node.execute(stream, data)
+
+  def __repr__(self):
+    r = "<" + self.__class__.__name__ + " "
+    for i in self.node_list:
+      r = r + repr(i)
+    r = r + ">"
+    return r
+
+class TopLevelTemplateNode(TemplateNode):
+  def __init__(self, parent):
+    TemplateNode.__init__(self, parent, '')
+
+  def add_node(self, node):
+    if node != None:
+      self.node_list.append(node)
+    else:
+      return 1
+
+class ForTemplateNode(TemplateNode):
+  def __init__(self, parent, s):
+    TemplateNode.__init__(self, parent, s)
+    match = re_for_loop.match(s)
+    if match == None:
+      raise self.parent.parser_exception(
+        "[[%s]] is not a valid for-loop expression" % self.s)
+    else:
+      self.vars_temp = match.group(1).split(",")
+      self.vars = []
+      for v in self.vars_temp:
+        self.vars.append(v.strip())
+      print self.vars
+      self.expression = match.group(2)
+
+  def execute(self, stream, data):
+    remember_vars = {}
+    for var in self.vars:
+      if data.has_key(var):
+        remember_vars[var] = data[var]
+    for list in eval(self.expression, globals(), data):
+      if util.is_sequence(list):
+        for index, value in util.enumerate(list):
+          data[self.vars[index]] = value
+      else:
+        data[self.vars[0]] = list
+      TemplateNode.execute(self, stream, data)
+    for key, value in remember_vars.items():
+      data[key] = value
+
+class IfTemplateNode(TemplateNode):
+  def __init__(self, parent, s):
+    self.else_node = None
+    TemplateNode.__init__(self, parent, s)
+    match = re_if.match(s)
+    if match == None:
+      raise self.parent.parser_exception(
+        "[[%s]] is not a valid if expression" % self.s)
+    else:
+      self.expression = match.group(1)
+
+  def add_node(self, node):
+    if node == 'end':
+      return 1
+    elif isinstance(node, ElseTemplateNode):
+      self.else_node = node
+      return 1
+    elif isinstance(node, ElifTemplateNode):
+      self.else_node = node
+      return 1
+    elif node != None:
+      self.node_list.append(node)
+    else:
+      raise self.parent.parser_exception(
+        "[[%s]] does not have a matching [[end]]" % self.s)
+
+  def execute(self, stream, data):
+    if eval(self.expression, globals(), data):
+      TemplateNode.execute(self, stream, data)
+    elif self.else_node != None:
+      self.else_node.execute(stream, data)
+
+class ElifTemplateNode(IfTemplateNode):
+  def __init__(self, parent, s):
+    self.else_node = None
+    TemplateNode.__init__(self, parent, s)
+    match = re_elif.match(s)
+    if match == None:
+      self.parent.parser_exception(
+        "[[%s]] is not a valid elif expression" % self.s)
+    else:
+      self.expression = match.group(1)
+
+class ElseTemplateNode(TemplateNode):
+  pass
+
+class FunctionTemplateNode(TemplateNode):
+  def __init__(self, parent, s):
+    TemplateNode.__init__(self, parent, s)
+    match = re_def.match(s)
+    if match == None:
+      self.parent.parser_exception(
+        "[[%s]] is not a valid function definition" % self.s)
+    self.function_name = match.group(1)
+    self.vars_temp = match.group(2).split(",")
+    self.vars = []
+    for v in self.vars_temp:
+      self.vars.append(v.strip())
+    print self.vars
+    self.parent.functions[self.function_name] = self
+
+  def execute(self, stream, data):
+    pass
+
+  def call(self, args, stream, data):
+    remember_vars = {}
+    for index, var in util.enumerate(self.vars):
+      if data.has_key(var):
+        remember_vars[var] = data[var]
+      data[var] = args[index]
+    TemplateNode.execute(self, stream, data)
+    for key, value in remember_vars.items():
+      data[key] = value
+      
+class LeafTemplateNode(TemplateNode):
+  def __init__(self, parent, s):
+    self.parent = parent
+    self.s = s
+
+  def execute(self, stream, data):
+    stream.write(self.s)
+
+  def __repr__(self):
+    return "<" + self.__class__.__name__ + ">"
+
+class CommentTemplateNode(LeafTemplateNode):
+  def execute(self, stream, data):
+    pass
+
+class ExpressionTemplateNode(LeafTemplateNode):
+  def execute(self, stream, data):
+    stream.write(str(eval(self.s, globals(), data)))
+
+class ExecTemplateNode(LeafTemplateNode):
+  def __init__(self, parent, s):
+    LeafTemplateNode.__init__(self, parent, s)
+    match = re_exec.match(s)
+    if match == None:
+      self.parent.parser_exception(
+        "[[%s]] is not a valid statement" % self.s)
+    self.s = match.group(1)
+
+  def execute(self, stream, data):
+    exec(self.s, globals(), data)
+    pass
+    
+class CallTemplateNode(LeafTemplateNode):
+  def __init__(self, parent, s):
+    LeafTemplateNode.__init__(self, parent, s)
+    match = re_call.match(s)
+    if match == None:
+      self.parent.parser_exception(
+        "[[%s]] is not a valid function call" % self.s)
+    self.function_name = match.group(1)
+    self.vars = "(" + match.group(2).strip() + ",)"
+  
+  def execute(self, stream, data):
+    self.parent.functions[self.function_name].call(
+      eval(self.vars, globals(), data), stream, data)
+
+
+############################################################
+# Node factory
+template_factory_type_map = {
+  'if'   : IfTemplateNode,
+  'for'  : ForTemplateNode,
+  'elif' : ElifTemplateNode,
+  'else' : ElseTemplateNode,
+  'def'  : FunctionTemplateNode,
+  'call' : CallTemplateNode,
+  'exec' : ExecTemplateNode }
+template_factory_types = template_factory_type_map.keys()
+
+def TemplateNodeFactory(parent):
+  src = parent.parser_get()
+
+  if src == None:
+    return None
+  match = re_directive.search(src)
+  if match == None:
+    parent.parser_eat(len(src))
+    return LeafTemplateNode(parent, src)
+  elif src == '' or match.start() != 0:
+    parent.parser_eat(match.start())
+    return LeafTemplateNode(parent, src[:match.start()])
+  else:
+    directive = match.group()[2:-2].strip()
+    parent.parser_eat(match.end())
+    if directive == 'end':
+      return 'end'
+    elif re_comment.match(directive):
+      return CommentTemplateNode(parent, directive)
+    else:
+      for i in template_factory_types:
+        if directive[0:len(i)] == i:
+          return template_factory_type_map[i](parent, directive)
+      return ExpressionTemplateNode(parent, directive)
+
+
+############################################################
+# TESTING CODE
+if __name__ == '__main__':
+  combinations = (('OneBit', 'Float', 'GreyScale'),
+                  ('GreyScale', 'RGB'))
+  
+  template = Template("""
+  [[# This is a comment #]]
+  [[# This example does recursive function calls need to generate feature combinations #]]
+  [[def switch(layer, args)]]
+     switch(m[[layer]].id) {
+     [[for option in combinations[layer]]]
+     [[exec current = option + '(m' + str(layer) + ')']]
+     case [[option]]:
+       [[if layer == layers - 1]]
+         function_call([[string.join(args + [current], ',')]]);
+       [[else]]
+         [[call switch(layer + 1, args + [current])]]
+       [[end]]
+     break;
+     [[end]]
+     }
+  [[end]]
+
+  PyObject *py_overload_resolution_[[function_name]](PyObject *args) {
+  [[call switch(0, [])]]
+  }
+  """)
+
+  data = {'combinations'  : combinations,
+          'function_name' : 'threshold',
+          'layers'        : 2}
+  template.execute(sys.stdout, data)
diff --git a/refpolicy/support/sedoctool.py b/refpolicy/support/sedoctool.py
new file mode 100755
index 0000000..4db8263
--- /dev/null
+++ b/refpolicy/support/sedoctool.py
@@ -0,0 +1,143 @@
+#!/usr/bin/python
+
+#  Author: Joshua Brindle <jbrindle at tresys.com>
+#
+# Copyright (C) 2003 - 2005 Tresys Technology, LLC
+#      This program is free software; you can redistribute it and/or modify
+#      it under the terms of the GNU General Public License as published by
+#      the Free Software Foundation, version 2.
+
+"""
+	this does dstuff
+"""
+
+import sys
+import getopt
+import pyplate
+from xml.dom.ext import *
+from xml.dom.ext.reader import Sax2
+
+def read_policy_xml(filename):
+	try:
+		reader = Sax2.Reader()
+		doc = reader.fromStream(filename)
+	except: 
+		error("Error while parsing xml")
+	
+	return doc
+
+def gen_tunable_conf(doc, file):
+	for node in doc.getElementsByTagName("tunable"):
+		s = string.split(node.firstChild.data, "\n")
+		for line in s:
+			file.write("# %s\n" % line)
+		tun_name = tun_val = None
+        	for (name, value) in node.attributes.items():
+			if name[1] == "name":
+				tun_name = value.value
+			elif name[1] == "dftval":
+				tun_val = value.value
+
+			if tun_name and tun_val:
+	            		file.write("%s = %s\n\n" % (tun_name, tun_val))
+				tun_name = tun_val = None
+
+def gen_module_conf(doc, file):
+	for node in doc.getElementsByTagName("module"):
+		for desc in node.getElementsByTagName("summary"):
+			s = string.split(desc.firstChild.data, "\n")
+			for line in s:
+				file.write("# %s\n" % line)	
+			file.write("#\n")
+			for (name, value) in node.attributes.items():
+				if name[1] == "name":
+					file.write("# %s\n\n" % value.value)
+
+def gen_docs(doc, file):
+	try:
+		bodyfile = open("templates/header.html", "r")
+		intfile = open("templates/interface.html", "r")
+	except:
+		error("Could not open templates")
+
+	interface_buf = None
+	interface_parameters = {}
+
+	for node in doc.getElementsByTagName("module"):
+		for interface in node.getElementsByTagName("interface"):
+			interface_tpl = pyplate.Template(intfile.read())
+			for i,v in interface.attributes.items():
+				interface_name = v
+			for desc in interface.getElementsByTagName("description"):
+				interface_desc = desc.firstChild.data
+			for desc in interface.getElementsByTagName("securitydesc"):
+				if desc:
+					interface_secdesc = desc.firstChild.data
+				else:
+					interface_secdesc = None
+			
+			for args in interface.getElementsByTagName("parameter"):
+				paramdesc = args.firstChild.data
+				for i,v in interface.attributes.items():
+					arg = { "name" : v,
+						"desc" : paramdesc }
+					
+
+def error(error):
+        sys.stderr.write("%s exiting for: " % sys.argv[0])
+        sys.stderr.write("%s\n" % error)
+        sys.stderr.flush()
+        sys.exit(1)
+
+def usage():
+	sys.stdout.write("%s [-tmd] -x <xmlfile>\n\n" % sys.argv[0])
+	sys.stdout.write("Options:\n")
+	sys.stdout.write("-t --tunables			--	write tunable config to <file>\n")
+	sys.stdout.write("-m --modules <file>		--	write module config to <file>\n")
+	sys.stdout.write("-d --docs <dir>		--	write interface documentation to <dir>\n")
+	sys.stdout.write("-x --xml <file>		--	filename to read xml data from\n")
+
+
+try:
+	opts, args = getopt.getopt(sys.argv[1:], "t:m:d:x:", ["tunables","modules","docs","xml"])
+except getopt.GetoptError:
+	usage()
+	sys.exit(1)
+
+tunables = modules = docs = xmlfile = None
+
+for opt, val in opts:
+	if opt in ("-t", "--tunables"):
+		tunables = val
+	if opt in ("-m", "--modules"):
+		modules = val
+	if opt in ("-d", "--docs"):
+		docs = val
+	if opt in ("-x", "--xml"):
+		xmlfile = val
+
+if xmlfile == None:
+	usage()
+	sys.exit(1)
+
+doc = read_policy_xml(xmlfile)
+		
+if tunables:
+	try:
+		conf = open(tunables, 'w')
+	except:
+		error("Could not open tunables file for writing")
+	gen_tunable_conf(doc, conf)
+	conf.close()
+
+
+if modules:
+	try:
+		conf = open(modules, 'w')
+	except:
+		error("Could not open modules file for writing")
+	gen_module_conf(doc, conf)
+	conf.close()
+
+if docs: 
+	gen_docs(doc, sys.stdout)


More information about the scm-commits mailing list