#!Test c:\bin\messagebox.exe Display for {a} %xyz% {} {xyz} {} and {p}
## #!Test2 c:\bin\messagebox.exe Display for {a} and {} with {} and {p}
#!Edit {o}\qeditor.exe {a} !!
# Run the #!Inst command
#! c:\bin\qeditor.exe "{a}" !!
#!py c:\bin\messagebox.exe "{a}" is a python program
#!Inst c:\windows\system32\cmd.exe /C copy "{a}" "{i}\{f}" !!
#!BadI c:\windows\system32\cmd.exe /C copy "{a}" "{i}\{f}"
#!Run c:\sys\python27\pythonw.exe "{a}" list of arguments
## #!OKI c:\windows\system32\cmd.exe /C copy "{a}" "{t}\{f}" !!
#!pynew c:\bin\messagebox.exe Display for {a} new
#!oldpy c:\bin\messagebox.exe Display for "{a}" old
mHelpText = '''
# ----------------------------------------------
# Name: pb
# Description: Expand and execute command from file
## D20H-57 Expand and execute command
#
# Author: Philip S. Rist
# Date: 10/26/2010
# Copyright 2010 by St. Thomas Software
# ----------------------------------------------
# This program is freeware. It may be used
# for any moral purpose. You use it at your
# own risk. St. Thomas Software makes no
# guarantees to its fitness to do anything.
#
# If you feel you must pay for it. Please
# send one million dollars to
#
# The International Rescue Committee
# 122 East 42nd Street
# New York, N.Y. 10168-1289
#
# Ok, we are in a recession. So, make it a half
# million.
# pb.py -
# Scan file for specified #! keyword then expand and execute command following on line.
# See above for examples. Scanned lines must be at the beginning of the file with no
# blank or shorx t lines preceeding them.
#
# Usage examples:
#
#[HKEY_CLASSES_ROOT\*\Shell\Runpb]
#@="Run"
#"EditFlags"=hex:01,00,00,00
#[HKEY_CLASSES_ROOT\*\Shell\Runpb\Command]
#@="c:\\sys\\python25\\pythonw.exe c:\\bin\\pb.py \"%1\" #!run "
#
# Syntax:
# pb.py [ Options ] <File path> #!<Key> [ <Optional parameter> ... ]
#
# Options:
#
# -c <Count> - Set last line to search for #! default 10
# A too short line will also abort scan
# -d <Directory path> - Set current directory
# -e <Name>=<Value> - Set environment variable
# -h - Display this text
# -s <File to search> - Set name of file containing command, defaults to
# primary file named in <File path>
# -v - Run in verbose mode
# -w <Count> - Set last column in line to search for #! default 15
# -x - Do not run, list expanded command
'''
import sys
import os
import getopt
import Do # Recipe: 577439
import Do2 # Recipe: 577440
import subprocess
def FindCommand(pKey, pFilePath, pSearchPath, pCount=10, pDefault='#!', pList=False, pWidth=10, pVerbose=False):
'''
Find command keyword and extract containing line
pKey -- String identifying line to use as command template
pFilePath -- File to use in macro expansion
pSearchPath -- File to scan for command '
pCount -- Number of lines at the start of the file to scan
pDefault -- Prefix for keys, from UNIX #!
pList -- True to display available commands
pWidth -- Number of columns at start of line in which key must appear
'''
lShortest = 6 # A line shorter than this will abort scan
if not os.path.exists(pSearchPath):
lCommand = ''
print 'pb.py Could not find search file', pSearchPath
else:
# ---- Check allowed key values
if pKey == '' or pKey == pDefault: # #!
lKey = pDefault
elif pKey.find('{') >= 0: # #!{e}
lKey = pDefault + Do.Expand(pKey, pFilePath)
if not lKey.startswith(pDefault):
lKey = pDefault + lKey
elif pKey.startswith(pDefault): # #!text
lKey = pKey
else:
lKey = pDefault + pKey # text
lKey = lKey.lower()
# lKey += ' ' # Full key only
# ---- read maximum scan lines
lFile = open(pSearchPath, 'r')
lText = lFile.readlines(pCount)
lText = lText[0:pCount] #???
lFile.close()
lCommand = ''
# ---- list available commands
if pList:
lText = [x for x in lText if x.find(pDefault) >= 0 ]
lText = [x for x in lText if x.find(pDefault) < pWidth ]
print 'Available Commands in', pSearchPath
for (lCount, lLine) in enumerate(lText):
lLine = lLine.strip()
print "%5d: %s" % (lCount, lLine)
# ---- Scan for selected command
# Since comments in some languages do not start with first character of key,
# the key need not appear at start of line but must appear within first pWidth
# columns to allow for skipping lines with key that are not to be matched
else:
lCount = 0
for lLine in lText:
if len(lLine.strip()) < lShortest: # blank or short line will stop scan
break
lLine = lLine.lower()
lPos = lLine.find(lKey.lower())
if pVerbose:
lCount += 1
print "pb.py %5d: %s" % (lCount, lLine),
if lPos >= 0:
lAt = lPos + 13
print ' ' * lAt + '^'
if lPos >= 0 and lPos < pWidth:
# ---- Full key only
# lCommand = lLine[lPos+len(lKey):]
# ---- Partial keys allowed
lCommand = lLine[lPos+len(lKey):]
if lCommand[0] == ' ': # matched full key
lCommand = lCommand.lstrip()
else:
lPos = lCommand.find(' ') # matched partial key
lCommand = lCommand[lPos:].lstrip()
break
return lCommand[0:-1]
def Expand(pArgs, pFilePath, pSearchPath, pCount, pSep='!!', pDefault='#!', pList=False, pWidth=15, pVerbose=False):
'''
Extract command from file and replace all macros
pArgs -- Args passed to program except file path
#!key and any arguments
pFilePath -- File to use in macro expansion
pSearchPath -- File to scan for command '
pCount -- Number of lines at the start of the file to scan
pSep -- String used to identify end of command, extra arguments will not be appended
pList -- True to display available commands
pWidth -- Number of columns to scan for #!
'''
# ---- Find command
if len(pArgs[1]) == 0:
lKey = pDefault
lStart = 1
elif pArgs[1].startswith(pDefault):
lKey = pArgs[1]
lStart = 2
else:
lKey = pDefault
lStart = 1
lCommand = FindCommand(lKey, pFilePath, pSearchPath, pCount, pDefault=pDefault, pList=pList, pWidth=pWidth, pVerbose=pVerbose)
if lCommand == '':
print 'pb.py Command', lKey, 'not found'
# ---- Expand and insert/append any passed arguments
# Arguments on original pb.py command line will replace {} from left to right
# otherwise they will be appended to the end of the command
if len(lCommand) > 0:
if len(pArgs) > lStart:
for lArg in pArgs[lStart:]:
if lArg.find('{') >= 0:
lArg = Do2.ExpandArg(lArg, pFilePath, '')
lPos = lCommand.find('{}')
if lPos >= 0:
lCommand = lCommand[0:lPos] + lArg + lCommand[lPos+2:]
else:
lCommand += ' ' + lArg
# ---- Prevent unwanted arguments appended to command
lPos = lCommand.rfind(pSep)
if lPos > 0:
lCommand = lCommand[0:lPos]
# ---- Expand all remaining macros
if lCommand.find('{') >= 0:
lCommand = Do.Expand(lCommand, pFilePath)
return lCommand
def submitnow(pArgs, pFilePath, pSearchPath, pCount, pList=False, pExtract=False, pVerbose=False, pWidth=15):
'Expand and submit command'
if pVerbose:
print 'pb.py File path: ', pFilePath
print 'pb.py Search path:', pSearchPath
print 'pb.py Arguments: ', pArgs
lCommand = Expand(pArgs, pFilePath, pSearchPath, pCount, pList=pList, pWidth=pWidth, pVerbose=pVerbose)
# ---- Any macro not expanded will be assumed to be an environment variable
# If %...% had been used it would have been replaced when pb.py was run
lCommand = lCommand.replace('{}',' ') # <-- may want to do something else
lCommand = lCommand.replace('{', '%')
lCommand = lCommand.replace('}', '%')
# ---- Complete execution
if pList: # List only
pass
elif len(lCommand) == 0: # Expansion failed
print 'pb.py Expansion failed'
elif pExtract: # Expand command only
print lCommand
else: # Submit command
lCommand = '"' + lCommand + '"'
if pVerbose:
print 'pb.py Submitting: ', lCommand
subprocess.Popen(lCommand, shell=True)
def setenviron(pValue, pFileName):
'Set environment variable'
lParts = pValue.split('=')
if len(lParts) > 1:
lKey = lParts[0]
lValue = lParts[1]
if lValue.find('{') >= 0:
lValue = Do2.ExpandArg(lValue, pFileName, '')
os.environ[lKey] = lValue
else:
os.environ[pValue] = ''
#sys.argv.extend( [ 'c:\\source\\python\\projects\\program execution\\pb.py', '#!Inst', 'A', '{p}' ] )
#sys.argv.extend( [ 'c:\\source\\python\\projects\\program execution\\pb.py', '#!BadI', 'A', '{p}' ] )
#sys.argv.extend( [ 'c:\\source\\python\\projects\\program execution\\pb.py', '#!OKI', 'A', '{p}' ] )
#sys.argv.extend( [ 'c:\\source\\python\\projects\\program execution\\pb.py', '#!Edit', 'A', '{p}' ] )
if __name__ == '__main__':
(mOptions, mArgs) = getopt.getopt(sys.argv[1:], 'c:d:e:hls:vx')
if len(mArgs) > 1:
# ---- Set defaults
mFilePath = os.path.abspath(mArgs[0])
mArgs[1] = mArgs[1].replace('_', ' ')
mSearchPath = mFilePath
mCount = 10
mList = False
mExtract = False
mVerbose = False
mWidth = 15
mHelp = False
# ---- Scan option list
for (mKey, mValue) in mOptions:
if mKey == '-d': # Set current directory
if mValue.find('{') >= 0:
mValue = Do.Expand(mValue, mFilePath)
os.chdir(mValue)
elif mKey == '-e': # Set environment variable
setenviron(mValue, mFilePath)
elif mKey == '-c': # Set last line to search for #!
try:
mCount = int(mValue)
except Exception, e:
mCount = 10
elif mKey == '-s': # Set search path
mSearchPath = mValue
if mValue.find('{') >= 0:
mSearchPath = Do2.ExpandArg(mSearchPath, mFilePath, '')
if mSearchPath[0] == '"':
mSearchPath = mSearchPath[1:-1]
mSearchPath = os.path.abspath(mSearchPath)
elif mKey == '-h': # Display help only
mHelp = True
elif mKey == '-l': # Display available commands
mList = True
elif mKey == '-x': # List expanded command only
mExtract = True
elif mKey == '-v': # Run in verbose mode
mVerbose = True
elif mKey == '-w': # Set last column in file to search for #!
try:
mWidth = int(mValue)
except Exception, e:
mWidth = 10
if mHelp:
print mHelpText
print 'pb.py Search file:', mSearchPath
print 'pb.py Width: ', mWidth
print 'pb.py Lines: ', mCount
mList = True
else:
submitnow(mArgs, mFilePath, mSearchPath, mCount, mList, mExtract, mVerbose, mWidth)
else:
print 'pb.py Command and/or file path missing'