1#!/usr/bin/env python 2import sys 3import os 4 5class FileContextsNode: 6 path = None 7 fileType = None 8 context = None 9 Type = None 10 meta = None 11 stemLen = None 12 strLen = None 13 Type = None 14 def __init__(self, path, fileType, context, meta, stemLen, strLen): 15 self.path = path 16 self.fileType = fileType 17 self.context = context 18 self.meta = meta 19 self.stemLen = stemLen 20 self.strlen = strLen 21 self.Type = context.split(":")[2] 22 23metaChars = frozenset(['.', '^', '$', '?', '*', '+', '|', '[', '(', '{']) 24escapedMetaChars = frozenset(['\.', '\^', '\$', '\?', '\*', '\+', '\|', '\[', '\(', '\{']) 25 26def getStemLen(path): 27 global metaChars 28 stemLen = 0 29 i = 0 30 while i < len(path): 31 if path[i] == "\\": 32 i += 1 33 elif path[i] in metaChars: 34 break 35 stemLen += 1 36 i += 1 37 return stemLen 38 39 40def getIsMeta(path): 41 global metaChars 42 global escapedMetaChars 43 metaCharsCount = 0 44 escapedMetaCharsCount = 0 45 for c in metaChars: 46 if c in path: 47 metaCharsCount += 1 48 for c in escapedMetaChars: 49 if c in path: 50 escapedMetaCharsCount += 1 51 return metaCharsCount > escapedMetaCharsCount 52 53def CreateNode(line): 54 global metaChars 55 if (len(line) == 0) or (line[0] == '#'): 56 return None 57 58 split = line.split() 59 path = split[0].strip() 60 context = split[-1].strip() 61 fileType = None 62 if len(split) == 3: 63 fileType = split[1].strip() 64 meta = getIsMeta(path) 65 stemLen = getStemLen(path) 66 strLen = len(path.replace("\\", "")) 67 68 return FileContextsNode(path, fileType, context, meta, stemLen, strLen) 69 70def ReadFileContexts(files): 71 fc = [] 72 for f in files: 73 fd = open(f) 74 for line in fd: 75 node = CreateNode(line.strip()) 76 if node != None: 77 fc.append(node) 78 return fc 79 80# Comparator function for list.sort() based off of fc_sort.c 81# Compares two FileContextNodes a and b and returns 1 if a is more 82# specific or -1 if b is more specific. 83def compare(a, b): 84 # The regex without metachars is more specific 85 if a.meta and not b.meta: 86 return -1 87 if b.meta and not a.meta: 88 return 1 89 90 # The regex with longer stemlen (regex before any meta characters) is more specific. 91 if a.stemLen < b.stemLen: 92 return -1 93 if b.stemLen < a.stemLen: 94 return 1 95 96 # The regex with longer string length is more specific 97 if a.strLen < b.strLen: 98 return -1 99 if b.strLen < a.strLen: 100 return 1 101 102 # A regex with a fileType defined (e.g. file, dir) is more specific. 103 if a.fileType is None and b.fileType is not None: 104 return -1 105 if b.fileType is None and a.fileType is not None: 106 return 1 107 108 # Regexes are equally specific. 109 return 0 110 111def FcSort(files): 112 for f in files: 113 if not os.path.exists(f): 114 sys.exit("Error: File_contexts file " + f + " does not exist\n") 115 116 Fc = ReadFileContexts(files) 117 Fc.sort(cmp=compare) 118 119 return Fc 120 121if __name__ == '__main__': 122 if len(sys.argv) < 2: 123 sys.exit("Usage: fc_sort.py <file_contexts 1> <file_contexts 2> <file_contexts 3>") 124 125 FcSorted = FcSort(sys.argv[1:]) 126