Showing the changes to sys/src/cmd/python/Demo/scripts (23 of 3706 files). Show all
Unified · Split
| @@ -0,0 +1,23 @@ | |||
| 1 | This directory contains a collection of executable Python scripts. | ||
| 2 | |||
| 3 | See also the Tools/scripts directory! | ||
| 4 | |||
| 5 | beer.py Print the classic 'bottles of beer' list. | ||
| 6 | eqfix.py Fix .py files to use the correct equality test operator | ||
| 7 | fact.py Factorize numbers | ||
| 8 | find-uname.py Search for Unicode characters using regexps. | ||
| 9 | from.py Summarize mailbox | ||
| 10 | ftpstats.py Summarize ftp daemon log file | ||
| 11 | lpwatch.py Watch BSD line printer queues | ||
| 12 | makedir.py Like mkdir -p | ||
| 13 | markov.py Markov chain simulation of words or characters | ||
| 14 | mboxconvvert.py Convert MH or MMDF mailboxes to unix mailbox format | ||
| 15 | mkrcs.py Fix symlinks named RCS into parallel tree | ||
| 16 | morse.py Produce morse code (audible or on AIFF file) | ||
| 17 | pi.py Print all digits of pi -- given enough time and memory | ||
| 18 | pp.py Emulate some Perl command line options | ||
| 19 | primes.py Print prime numbers | ||
| 20 | queens.py Dijkstra's solution to Wirth's "N Queens problem" | ||
| 21 | script.py Equivalent to BSD script(1) -- by Steen Lumholt | ||
| 22 | unbirthday.py Print unbirthday count | ||
| 23 | update.py Update a bunch of files according to a script. | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | # By GvR, demystified after a version by Fredrik Lundh. | ||
| 3 | import sys | ||
| 4 | n = 100 | ||
| 5 | if sys.argv[1:]: n = int(sys.argv[1]) | ||
| 6 | def bottle(n): | ||
| 7 | if n == 0: return "no more bottles of beer" | ||
| 8 | if n == 1: return "one bottle of beer" | ||
| 9 | return str(n) + " bottles of beer" | ||
| 10 | for i in range(n): | ||
| 11 | print bottle(n-i), "on the wall," | ||
| 12 | print bottle(n-i) + "." | ||
| 13 | print "Take one down, pass it around," | ||
| 14 | print bottle(n-i-1), "on the wall." | ||
| @@ -0,0 +1,198 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Fix Python source files to use the new equality test operator, i.e., | ||
| 4 | # if x = y: ... | ||
| 5 | # is changed to | ||
| 6 | # if x == y: ... | ||
| 7 | # The script correctly tokenizes the Python program to reliably | ||
| 8 | # distinguish between assignments and equality tests. | ||
| 9 | # | ||
| 10 | # Command line arguments are files or directories to be processed. | ||
| 11 | # Directories are searched recursively for files whose name looks | ||
| 12 | # like a python module. | ||
| 13 | # Symbolic links are always ignored (except as explicit directory | ||
| 14 | # arguments). Of course, the original file is kept as a back-up | ||
| 15 | # (with a "~" attached to its name). | ||
| 16 | # It complains about binaries (files containing null bytes) | ||
| 17 | # and about files that are ostensibly not Python files: if the first | ||
| 18 | # line starts with '#!' and does not contain the string 'python'. | ||
| 19 | # | ||
| 20 | # Changes made are reported to stdout in a diff-like format. | ||
| 21 | # | ||
| 22 | # Undoubtedly you can do this using find and sed or perl, but this is | ||
| 23 | # a nice example of Python code that recurses down a directory tree | ||
| 24 | # and uses regular expressions. Also note several subtleties like | ||
| 25 | # preserving the file's mode and avoiding to even write a temp file | ||
| 26 | # when no changes are needed for a file. | ||
| 27 | # | ||
| 28 | # NB: by changing only the function fixline() you can turn this | ||
| 29 | # into a program for a different change to Python programs... | ||
| 30 | |||
| 31 | import sys | ||
| 32 | import re | ||
| 33 | import os | ||
| 34 | from stat import * | ||
| 35 | import string | ||
| 36 | |||
| 37 | err = sys.stderr.write | ||
| 38 | dbg = err | ||
| 39 | rep = sys.stdout.write | ||
| 40 | |||
| 41 | def main(): | ||
| 42 | bad = 0 | ||
| 43 | if not sys.argv[1:]: # No arguments | ||
| 44 | err('usage: ' + sys.argv[0] + ' file-or-directory ...\n') | ||
| 45 | sys.exit(2) | ||
| 46 | for arg in sys.argv[1:]: | ||
| 47 | if os.path.isdir(arg): | ||
| 48 | if recursedown(arg): bad = 1 | ||
| 49 | elif os.path.islink(arg): | ||
| 50 | err(arg + ': will not process symbolic links\n') | ||
| 51 | bad = 1 | ||
| 52 | else: | ||
| 53 | if fix(arg): bad = 1 | ||
| 54 | sys.exit(bad) | ||
| 55 | |||
| 56 | ispythonprog = re.compile('^[a-zA-Z0-9_]+\.py$') | ||
| 57 | def ispython(name): | ||
| 58 | return ispythonprog.match(name) >= 0 | ||
| 59 | |||
| 60 | def recursedown(dirname): | ||
| 61 | dbg('recursedown(%r)\n' % (dirname,)) | ||
| 62 | bad = 0 | ||
| 63 | try: | ||
| 64 | names = os.listdir(dirname) | ||
| 65 | except os.error, msg: | ||
| 66 | err('%s: cannot list directory: %r\n' % (dirname, msg)) | ||
| 67 | return 1 | ||
| 68 | names.sort() | ||
| 69 | subdirs = [] | ||
| 70 | for name in names: | ||
| 71 | if name in (os.curdir, os.pardir): continue | ||
| 72 | fullname = os.path.join(dirname, name) | ||
| 73 | if os.path.islink(fullname): pass | ||
| 74 | elif os.path.isdir(fullname): | ||
| 75 | subdirs.append(fullname) | ||
| 76 | elif ispython(name): | ||
| 77 | if fix(fullname): bad = 1 | ||
| 78 | for fullname in subdirs: | ||
| 79 | if recursedown(fullname): bad = 1 | ||
| 80 | return bad | ||
| 81 | |||
| 82 | def fix(filename): | ||
| 83 | ## dbg('fix(%r)\n' % (dirname,)) | ||
| 84 | try: | ||
| 85 | f = open(filename, 'r') | ||
| 86 | except IOError, msg: | ||
| 87 | err('%s: cannot open: %r\n' % (filename, msg)) | ||
| 88 | return 1 | ||
| 89 | head, tail = os.path.split(filename) | ||
| 90 | tempname = os.path.join(head, '@' + tail) | ||
| 91 | g = None | ||
| 92 | # If we find a match, we rewind the file and start over but | ||
| 93 | # now copy everything to a temp file. | ||
| 94 | lineno = 0 | ||
| 95 | while 1: | ||
| 96 | line = f.readline() | ||
| 97 | if not line: break | ||
| 98 | lineno = lineno + 1 | ||
| 99 | if g is None and '\0' in line: | ||
| 100 | # Check for binary files | ||
| 101 | err(filename + ': contains null bytes; not fixed\n') | ||
| 102 | f.close() | ||
| 103 | return 1 | ||
| 104 | if lineno == 1 and g is None and line[:2] == '#!': | ||
| 105 | # Check for non-Python scripts | ||
| 106 | words = string.split(line[2:]) | ||
| 107 | if words and re.search('[pP]ython', words[0]) < 0: | ||
| 108 | msg = filename + ': ' + words[0] | ||
| 109 | msg = msg + ' script; not fixed\n' | ||
| 110 | err(msg) | ||
| 111 | f.close() | ||
| 112 | return 1 | ||
| 113 | while line[-2:] == '\\\n': | ||
| 114 | nextline = f.readline() | ||
| 115 | if not nextline: break | ||
| 116 | line = line + nextline | ||
| 117 | lineno = lineno + 1 | ||
| 118 | newline = fixline(line) | ||
| 119 | if newline != line: | ||
| 120 | if g is None: | ||
| 121 | try: | ||
| 122 | g = open(tempname, 'w') | ||
| 123 | except IOError, msg: | ||
| 124 | f.close() | ||
| 125 | err('%s: cannot create: %r\n' % (tempname, msg)) | ||
| 126 | return 1 | ||
| 127 | f.seek(0) | ||
| 128 | lineno = 0 | ||
| 129 | rep(filename + ':\n') | ||
| 130 | continue # restart from the beginning | ||
| 131 | rep(repr(lineno) + '\n') | ||
| 132 | rep('< ' + line) | ||
| 133 | rep('> ' + newline) | ||
| 134 | if g is not None: | ||
| 135 | g.write(newline) | ||
| 136 | |||
| 137 | # End of file | ||
| 138 | f.close() | ||
| 139 | if not g: return 0 # No changes | ||
| 140 | |||
| 141 | # Finishing touch -- move files | ||
| 142 | |||
| 143 | # First copy the file's mode to the temp file | ||
| 144 | try: | ||
| 145 | statbuf = os.stat(filename) | ||
| 146 | os.chmod(tempname, statbuf[ST_MODE] & 07777) | ||
| 147 | except os.error, msg: | ||
| 148 | err('%s: warning: chmod failed (%r)\n' % (tempname, msg)) | ||
| 149 | # Then make a backup of the original file as filename~ | ||
| 150 | try: | ||
| 151 | os.rename(filename, filename + '~') | ||
| 152 | except os.error, msg: | ||
| 153 | err('%s: warning: backup failed (%r)\n' % (filename, msg)) | ||
| 154 | # Now move the temp file to the original file | ||
| 155 | try: | ||
| 156 | os.rename(tempname, filename) | ||
| 157 | except os.error, msg: | ||
| 158 | err('%s: rename failed (%r)\n' % (filename, msg)) | ||
| 159 | return 1 | ||
| 160 | # Return succes | ||
| 161 | return 0 | ||
| 162 | |||
| 163 | |||
| 164 | from tokenize import tokenprog | ||
| 165 | |||
| 166 | match = {'if':':', 'elif':':', 'while':':', 'return':'\n', \ | ||
| 167 | '(':')', '[':']', '{':'}', '`':'`'} | ||
| 168 | |||
| 169 | def fixline(line): | ||
| 170 | # Quick check for easy case | ||
| 171 | if '=' not in line: return line | ||
| 172 | |||
| 173 | i, n = 0, len(line) | ||
| 174 | stack = [] | ||
| 175 | while i < n: | ||
| 176 | j = tokenprog.match(line, i) | ||
| 177 | if j < 0: | ||
| 178 | # A bad token; forget about the rest of this line | ||
| 179 | print '(Syntax error:)' | ||
| 180 | print line, | ||
| 181 | return line | ||
| 182 | a, b = tokenprog.regs[3] # Location of the token proper | ||
| 183 | token = line[a:b] | ||
| 184 | i = i+j | ||
| 185 | if stack and token == stack[-1]: | ||
| 186 | del stack[-1] | ||
| 187 | elif match.has_key(token): | ||
| 188 | stack.append(match[token]) | ||
| 189 | elif token == '=' and stack: | ||
| 190 | line = line[:a] + '==' + line[b:] | ||
| 191 | i, n = a + len('=='), len(line) | ||
| 192 | elif token == '==' and not stack: | ||
| 193 | print '(Warning: \'==\' at top level:)' | ||
| 194 | print line, | ||
| 195 | return line | ||
| 196 | |||
| 197 | if __name__ == "__main__": | ||
| 198 | main() | ||
| @@ -0,0 +1,49 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Factorize numbers. | ||
| 4 | # The algorithm is not efficient, but easy to understand. | ||
| 5 | # If there are large factors, it will take forever to find them, | ||
| 6 | # because we try all odd numbers between 3 and sqrt(n)... | ||
| 7 | |||
| 8 | import sys | ||
| 9 | from math import sqrt | ||
| 10 | |||
| 11 | error = 'fact.error' # exception | ||
| 12 | |||
| 13 | def fact(n): | ||
| 14 | if n < 1: raise error # fact() argument should be >= 1 | ||
| 15 | if n == 1: return [] # special case | ||
| 16 | res = [] | ||
| 17 | # Treat even factors special, so we can use i = i+2 later | ||
| 18 | while n%2 == 0: | ||
| 19 | res.append(2) | ||
| 20 | n = n/2 | ||
| 21 | # Try odd numbers up to sqrt(n) | ||
| 22 | limit = sqrt(float(n+1)) | ||
| 23 | i = 3 | ||
| 24 | while i <= limit: | ||
| 25 | if n%i == 0: | ||
| 26 | res.append(i) | ||
| 27 | n = n/i | ||
| 28 | limit = sqrt(n+1) | ||
| 29 | else: | ||
| 30 | i = i+2 | ||
| 31 | if n != 1: | ||
| 32 | res.append(n) | ||
| 33 | return res | ||
| 34 | |||
| 35 | def main(): | ||
| 36 | if len(sys.argv) > 1: | ||
| 37 | for arg in sys.argv[1:]: | ||
| 38 | n = eval(arg) | ||
| 39 | print n, fact(n) | ||
| 40 | else: | ||
| 41 | try: | ||
| 42 | while 1: | ||
| 43 | n = input() | ||
| 44 | print n, fact(n) | ||
| 45 | except EOFError: | ||
| 46 | pass | ||
| 47 | |||
| 48 | if __name__ == "__main__": | ||
| 49 | main() | ||
| @@ -0,0 +1,40 @@ | |||
| 1 | #!/usr/bin/env python | ||
| 2 | |||
| 3 | """ | ||
| 4 | For each argument on the command line, look for it in the set of all Unicode | ||
| 5 | names. Arguments are treated as case-insensitive regular expressions, e.g.: | ||
| 6 | |||
| 7 | % find-uname 'small letter a$' 'horizontal line' | ||
| 8 | *** small letter a$ matches *** | ||
| 9 | LATIN SMALL LETTER A (97) | ||
| 10 | COMBINING LATIN SMALL LETTER A (867) | ||
| 11 | CYRILLIC SMALL LETTER A (1072) | ||
| 12 | PARENTHESIZED LATIN SMALL LETTER A (9372) | ||
| 13 | CIRCLED LATIN SMALL LETTER A (9424) | ||
| 14 | FULLWIDTH LATIN SMALL LETTER A (65345) | ||
| 15 | *** horizontal line matches *** | ||
| 16 | HORIZONTAL LINE EXTENSION (9135) | ||
| 17 | """ | ||
| 18 | |||
| 19 | import unicodedata | ||
| 20 | import sys | ||
| 21 | import re | ||
| 22 | |||
| 23 | def main(args): | ||
| 24 | unicode_names= [] | ||
| 25 | for ix in range(sys.maxunicode+1): | ||
| 26 | try: | ||
| 27 | unicode_names.append( (ix, unicodedata.name(unichr(ix))) ) | ||
| 28 | except ValueError: # no name for the character | ||
| 29 | pass | ||
| 30 | for arg in args: | ||
| 31 | pat = re.compile(arg, re.I) | ||
| 32 | matches = [(x,y) for (x,y) in unicode_names | ||
| 33 | if pat.search(y) is not None] | ||
| 34 | if matches: | ||
| 35 | print "***", arg, "matches", "***" | ||
| 36 | for (x,y) in matches: | ||
| 37 | print "%s (%d)" % (y,x) | ||
| 38 | |||
| 39 | if __name__ == "__main__": | ||
| 40 | main(sys.argv[1:]) | ||
| @@ -0,0 +1,35 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Print From and Subject of messages in $MAIL. | ||
| 4 | # Extension to multiple mailboxes and other bells & whistles are left | ||
| 5 | # as exercises for the reader. | ||
| 6 | |||
| 7 | import sys, os | ||
| 8 | |||
| 9 | # Open mailbox file. Exits with exception when this fails. | ||
| 10 | |||
| 11 | try: | ||
| 12 | mailbox = os.environ['MAIL'] | ||
| 13 | except (AttributeError, KeyError): | ||
| 14 | sys.stderr.write('No environment variable $MAIL\n') | ||
| 15 | sys.exit(2) | ||
| 16 | |||
| 17 | try: | ||
| 18 | mail = open(mailbox) | ||
| 19 | except IOError: | ||
| 20 | sys.exit('Cannot open mailbox file: ' + mailbox) | ||
| 21 | |||
| 22 | while 1: | ||
| 23 | line = mail.readline() | ||
| 24 | if not line: | ||
| 25 | break # EOF | ||
| 26 | if line.startswith('From '): | ||
| 27 | # Start of message found | ||
| 28 | print line[:-1], | ||
| 29 | while 1: | ||
| 30 | line = mail.readline() | ||
| 31 | if not line or line == '\n': | ||
| 32 | break | ||
| 33 | if line.startswith('Subject: '): | ||
| 34 | print repr(line[9:-1]), | ||
| 35 | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Extract statistics from ftp daemon log. | ||
| 4 | |||
| 5 | # Usage: | ||
| 6 | # ftpstats [-m maxitems] [-s search] [file] | ||
| 7 | # -m maxitems: restrict number of items in "top-N" lists, default 25. | ||
| 8 | # -s string: restrict statistics to lines containing this string. | ||
| 9 | # Default file is /usr/adm/ftpd; a "-" means read standard input. | ||
| 10 | |||
| 11 | # The script must be run on the host where the ftp daemon runs. | ||
| 12 | # (At CWI this is currently buizerd.) | ||
| 13 | |||
| 14 | import os | ||
| 15 | import sys | ||
| 16 | import re | ||
| 17 | import string | ||
| 18 | import getopt | ||
| 19 | |||
| 20 | pat = '^([a-zA-Z0-9 :]*)!(.*)!(.*)!([<>].*)!([0-9]+)!([0-9]+)$' | ||
| 21 | prog = re.compile(pat) | ||
| 22 | |||
| 23 | def main(): | ||
| 24 | maxitems = 25 | ||
| 25 | search = None | ||
| 26 | try: | ||
| 27 | opts, args = getopt.getopt(sys.argv[1:], 'm:s:') | ||
| 28 | except getopt.error, msg: | ||
| 29 | print msg | ||
| 30 | print 'usage: ftpstats [-m maxitems] [file]' | ||
| 31 | sys.exit(2) | ||
| 32 | for o, a in opts: | ||
| 33 | if o == '-m': | ||
| 34 | maxitems = string.atoi(a) | ||
| 35 | if o == '-s': | ||
| 36 | search = a | ||
| 37 | file = '/usr/adm/ftpd' | ||
| 38 | if args: file = args[0] | ||
| 39 | if file == '-': | ||
| 40 | f = sys.stdin | ||
| 41 | else: | ||
| 42 | try: | ||
| 43 | f = open(file, 'r') | ||
| 44 | except IOError, msg: | ||
| 45 | print file, ':', msg | ||
| 46 | sys.exit(1) | ||
| 47 | bydate = {} | ||
| 48 | bytime = {} | ||
| 49 | byfile = {} | ||
| 50 | bydir = {} | ||
| 51 | byhost = {} | ||
| 52 | byuser = {} | ||
| 53 | bytype = {} | ||
| 54 | lineno = 0 | ||
| 55 | try: | ||
| 56 | while 1: | ||
| 57 | line = f.readline() | ||
| 58 | if not line: break | ||
| 59 | lineno = lineno + 1 | ||
| 60 | if search and string.find(line, search) < 0: | ||
| 61 | continue | ||
| 62 | if prog.match(line) < 0: | ||
| 63 | print 'Bad line', lineno, ':', repr(line) | ||
| 64 | continue | ||
| 65 | items = prog.group(1, 2, 3, 4, 5, 6) | ||
| 66 | (logtime, loguser, loghost, logfile, logbytes, | ||
| 67 | logxxx2) = items | ||
| 68 | ## print logtime | ||
| 69 | ## print '-->', loguser | ||
| 70 | ## print '--> -->', loghost | ||
| 71 | ## print '--> --> -->', logfile | ||
| 72 | ## print '--> --> --> -->', logbytes | ||
| 73 | ## print '--> --> --> --> -->', logxxx2 | ||
| 74 | ## for i in logtime, loghost, logbytes, logxxx2: | ||
| 75 | ## if '!' in i: print '???', i | ||
| 76 | add(bydate, logtime[-4:] + ' ' + logtime[:6], items) | ||
| 77 | add(bytime, logtime[7:9] + ':00-59', items) | ||
| 78 | direction, logfile = logfile[0], logfile[1:] | ||
| 79 | # The real path probably starts at the last //... | ||
| 80 | while 1: | ||
| 81 | i = string.find(logfile, '//') | ||
| 82 | if i < 0: break | ||
| 83 | logfile = logfile[i+1:] | ||
| 84 | add(byfile, logfile + ' ' + direction, items) | ||
| 85 | logdir = os.path.dirname(logfile) | ||
| 86 | ## logdir = os.path.normpath(logdir) + '/.' | ||
| 87 | while 1: | ||
| 88 | add(bydir, logdir + ' ' + direction, items) | ||
| 89 | dirhead = os.path.dirname(logdir) | ||
| 90 | if dirhead == logdir: break | ||
| 91 | logdir = dirhead | ||
| 92 | add(byhost, loghost, items) | ||
| 93 | add(byuser, loguser, items) | ||
| 94 | add(bytype, direction, items) | ||
| 95 | except KeyboardInterrupt: | ||
| 96 | print 'Interrupted at line', lineno | ||
| 97 | show(bytype, 'by transfer direction', maxitems) | ||
| 98 | show(bydir, 'by directory', maxitems) | ||
| 99 | show(byfile, 'by file', maxitems) | ||
| 100 | show(byhost, 'by host', maxitems) | ||
| 101 | show(byuser, 'by user', maxitems) | ||
| 102 | showbar(bydate, 'by date') | ||
| 103 | showbar(bytime, 'by time of day') | ||
| 104 | |||
| 105 | def showbar(dict, title): | ||
| 106 | n = len(title) | ||
| 107 | print '='*((70-n)/2), title, '='*((71-n)/2) | ||
| 108 | list = [] | ||
| 109 | keys = dict.keys() | ||
| 110 | keys.sort() | ||
| 111 | for key in keys: | ||
| 112 | n = len(str(key)) | ||
| 113 | list.append((len(dict[key]), key)) | ||
| 114 | maxkeylength = 0 | ||
| 115 | maxcount = 0 | ||
| 116 | for count, key in list: | ||
| 117 | maxkeylength = max(maxkeylength, len(key)) | ||
| 118 | maxcount = max(maxcount, count) | ||
| 119 | maxbarlength = 72 - maxkeylength - 7 | ||
| 120 | for count, key in list: | ||
| 121 | barlength = int(round(maxbarlength*float(count)/maxcount)) | ||
| 122 | bar = '*'*barlength | ||
| 123 | print '%5d %-*s %s' % (count, maxkeylength, key, bar) | ||
| 124 | |||
| 125 | def show(dict, title, maxitems): | ||
| 126 | if len(dict) > maxitems: | ||
| 127 | title = title + ' (first %d)'%maxitems | ||
| 128 | n = len(title) | ||
| 129 | print '='*((70-n)/2), title, '='*((71-n)/2) | ||
| 130 | list = [] | ||
| 131 | keys = dict.keys() | ||
| 132 | for key in keys: | ||
| 133 | list.append((-len(dict[key]), key)) | ||
| 134 | list.sort() | ||
| 135 | for count, key in list[:maxitems]: | ||
| 136 | print '%5d %s' % (-count, key) | ||
| 137 | |||
| 138 | def add(dict, key, item): | ||
| 139 | if dict.has_key(key): | ||
| 140 | dict[key].append(item) | ||
| 141 | else: | ||
| 142 | dict[key] = [item] | ||
| 143 | |||
| 144 | if __name__ == "__main__": | ||
| 145 | main() | ||
| @@ -0,0 +1,110 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Watch line printer queue(s). | ||
| 4 | # Intended for BSD 4.3 lpq. | ||
| 5 | |||
| 6 | import posix | ||
| 7 | import sys | ||
| 8 | import time | ||
| 9 | import string | ||
| 10 | |||
| 11 | DEF_PRINTER = 'psc' | ||
| 12 | DEF_DELAY = 10 | ||
| 13 | |||
| 14 | def main(): | ||
| 15 | delay = DEF_DELAY # XXX Use getopt() later | ||
| 16 | try: | ||
| 17 | thisuser = posix.environ['LOGNAME'] | ||
| 18 | except: | ||
| 19 | thisuser = posix.environ['USER'] | ||
| 20 | printers = sys.argv[1:] | ||
| 21 | if printers: | ||
| 22 | # Strip '-P' from printer names just in case | ||
| 23 | # the user specified it... | ||
| 24 | for i in range(len(printers)): | ||
| 25 | if printers[i][:2] == '-P': | ||
| 26 | printers[i] = printers[i][2:] | ||
| 27 | else: | ||
| 28 | if posix.environ.has_key('PRINTER'): | ||
| 29 | printers = [posix.environ['PRINTER']] | ||
| 30 | else: | ||
| 31 | printers = [DEF_PRINTER] | ||
| 32 | # | ||
| 33 | clearhome = posix.popen('clear', 'r').read() | ||
| 34 | # | ||
| 35 | while 1: | ||
| 36 | text = clearhome | ||
| 37 | for name in printers: | ||
| 38 | text = text + makestatus(name, thisuser) + '\n' | ||
| 39 | print text | ||
| 40 | time.sleep(delay) | ||
| 41 | |||
| 42 | def makestatus(name, thisuser): | ||
| 43 | pipe = posix.popen('lpq -P' + name + ' 2>&1', 'r') | ||
| 44 | lines = [] | ||
| 45 | users = {} | ||
| 46 | aheadbytes = 0 | ||
| 47 | aheadjobs = 0 | ||
| 48 | userseen = 0 | ||
| 49 | totalbytes = 0 | ||
| 50 | totaljobs = 0 | ||
| 51 | while 1: | ||
| 52 | line = pipe.readline() | ||
| 53 | if not line: break | ||
| 54 | fields = string.split(line) | ||
| 55 | n = len(fields) | ||
| 56 | if len(fields) >= 6 and fields[n-1] == 'bytes': | ||
| 57 | rank = fields[0] | ||
| 58 | user = fields[1] | ||
| 59 | job = fields[2] | ||
| 60 | files = fields[3:-2] | ||
| 61 | bytes = eval(fields[n-2]) | ||
| 62 | if user == thisuser: | ||
| 63 | userseen = 1 | ||
| 64 | elif not userseen: | ||
| 65 | aheadbytes = aheadbytes + bytes | ||
| 66 | aheadjobs = aheadjobs + 1 | ||
| 67 | totalbytes = totalbytes + bytes | ||
| 68 | totaljobs = totaljobs + 1 | ||
| 69 | if users.has_key(user): | ||
| 70 | ujobs, ubytes = users[user] | ||
| 71 | else: | ||
| 72 | ujobs, ubytes = 0, 0 | ||
| 73 | ujobs = ujobs + 1 | ||
| 74 | ubytes = ubytes + bytes | ||
| 75 | users[user] = ujobs, ubytes | ||
| 76 | else: | ||
| 77 | if fields and fields[0] <> 'Rank': | ||
| 78 | line = string.strip(line) | ||
| 79 | if line == 'no entries': | ||
| 80 | line = name + ': idle' | ||
| 81 | elif line[-22:] == ' is ready and printing': | ||
| 82 | line = name | ||
| 83 | lines.append(line) | ||
| 84 | # | ||
| 85 | if totaljobs: | ||
| 86 | line = '%d K' % ((totalbytes+1023)/1024) | ||
| 87 | if totaljobs <> len(users): | ||
| 88 | line = line + ' (%d jobs)' % totaljobs | ||
| 89 | if len(users) == 1: | ||
| 90 | line = line + ' for %s' % (users.keys()[0],) | ||
| 91 | else: | ||
| 92 | line = line + ' for %d users' % len(users) | ||
| 93 | if userseen: | ||
| 94 | if aheadjobs == 0: | ||
| 95 | line = line + ' (%s first)' % thisuser | ||
| 96 | else: | ||
| 97 | line = line + ' (%d K before %s)' % ( | ||
| 98 | (aheadbytes+1023)/1024, thisuser) | ||
| 99 | lines.append(line) | ||
| 100 | # | ||
| 101 | sts = pipe.close() | ||
| 102 | if sts: | ||
| 103 | lines.append('lpq exit status %r' % (sts,)) | ||
| 104 | return string.joinfields(lines, ': ') | ||
| 105 | |||
| 106 | if __name__ == "__main__": | ||
| 107 | try: | ||
| 108 | main() | ||
| 109 | except KeyboardInterrupt: | ||
| 110 | pass | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Like mkdir, but also make intermediate directories if necessary. | ||
| 4 | # It is not an error if the given directory already exists (as long | ||
| 5 | # as it is a directory). | ||
| 6 | # Errors are not treated specially -- you just get a Python exception. | ||
| 7 | |||
| 8 | import sys, os | ||
| 9 | |||
| 10 | def main(): | ||
| 11 | for p in sys.argv[1:]: | ||
| 12 | makedirs(p) | ||
| 13 | |||
| 14 | def makedirs(p): | ||
| 15 | if p and not os.path.isdir(p): | ||
| 16 | head, tail = os.path.split(p) | ||
| 17 | makedirs(head) | ||
| 18 | os.mkdir(p, 0777) | ||
| 19 | |||
| 20 | if __name__ == "__main__": | ||
| 21 | main() | ||
| @@ -0,0 +1,117 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | class Markov: | ||
| 4 | def __init__(self, histsize, choice): | ||
| 5 | self.histsize = histsize | ||
| 6 | self.choice = choice | ||
| 7 | self.trans = {} | ||
| 8 | def add(self, state, next): | ||
| 9 | if not self.trans.has_key(state): | ||
| 10 | self.trans[state] = [next] | ||
| 11 | else: | ||
| 12 | self.trans[state].append(next) | ||
| 13 | def put(self, seq): | ||
| 14 | n = self.histsize | ||
| 15 | add = self.add | ||
| 16 | add(None, seq[:0]) | ||
| 17 | for i in range(len(seq)): | ||
| 18 | add(seq[max(0, i-n):i], seq[i:i+1]) | ||
| 19 | add(seq[len(seq)-n:], None) | ||
| 20 | def get(self): | ||
| 21 | choice = self.choice | ||
| 22 | trans = self.trans | ||
| 23 | n = self.histsize | ||
| 24 | seq = choice(trans[None]) | ||
| 25 | while 1: | ||
| 26 | subseq = seq[max(0, len(seq)-n):] | ||
| 27 | options = trans[subseq] | ||
| 28 | next = choice(options) | ||
| 29 | if not next: break | ||
| 30 | seq = seq + next | ||
| 31 | return seq | ||
| 32 | |||
| 33 | def test(): | ||
| 34 | import sys, string, random, getopt | ||
| 35 | args = sys.argv[1:] | ||
| 36 | try: | ||
| 37 | opts, args = getopt.getopt(args, '0123456789cdw') | ||
| 38 | except getopt.error: | ||
| 39 | print 'Usage: markov [-#] [-cddqw] [file] ...' | ||
| 40 | print 'Options:' | ||
| 41 | print '-#: 1-digit history size (default 2)' | ||
| 42 | print '-c: characters (default)' | ||
| 43 | print '-w: words' | ||
| 44 | print '-d: more debugging output' | ||
| 45 | print '-q: no debugging output' | ||
| 46 | print 'Input files (default stdin) are split in paragraphs' | ||
| 47 | print 'separated blank lines and each paragraph is split' | ||
| 48 | print 'in words by whitespace, then reconcatenated with' | ||
| 49 | print 'exactly one space separating words.' | ||
| 50 | print 'Output consists of paragraphs separated by blank' | ||
| 51 | print 'lines, where lines are no longer than 72 characters.' | ||
| 52 | histsize = 2 | ||
| 53 | do_words = 0 | ||
| 54 | debug = 1 | ||
| 55 | for o, a in opts: | ||
| 56 | if '-0' <= o <= '-9': histsize = eval(o[1:]) | ||
| 57 | if o == '-c': do_words = 0 | ||
| 58 | if o == '-d': debug = debug + 1 | ||
| 59 | if o == '-q': debug = 0 | ||
| 60 | if o == '-w': do_words = 1 | ||
| 61 | if not args: args = ['-'] | ||
| 62 | m = Markov(histsize, random.choice) | ||
| 63 | try: | ||
| 64 | for filename in args: | ||
| 65 | if filename == '-': | ||
| 66 | f = sys.stdin | ||
| 67 | if f.isatty(): | ||
| 68 | print 'Sorry, need stdin from file' | ||
| 69 | continue | ||
| 70 | else: | ||
| 71 | f = open(filename, 'r') | ||
| 72 | if debug: print 'processing', filename, '...' | ||
| 73 | text = f.read() | ||
| 74 | f.close() | ||
| 75 | paralist = string.splitfields(text, '\n\n') | ||
| 76 | for para in paralist: | ||
| 77 | if debug > 1: print 'feeding ...' | ||
| 78 | words = string.split(para) | ||
| 79 | if words: | ||
| 80 | if do_words: data = tuple(words) | ||
| 81 | else: data = string.joinfields(words, ' ') | ||
| 82 | m.put(data) | ||
| 83 | except KeyboardInterrupt: | ||
| 84 | print 'Interrupted -- continue with data read so far' | ||
| 85 | if not m.trans: | ||
| 86 | print 'No valid input files' | ||
| 87 | return | ||
| 88 | if debug: print 'done.' | ||
| 89 | if debug > 1: | ||
| 90 | for key in m.trans.keys(): | ||
| 91 | if key is None or len(key) < histsize: | ||
| 92 | print repr(key), m.trans[key] | ||
| 93 | if histsize == 0: print repr(''), m.trans[''] | ||
| 94 | |||
| 95 | while 1: | ||
| 96 | data = m.get() | ||
| 97 | if do_words: words = data | ||
| 98 | else: words = string.split(data) | ||
| 99 | n = 0 | ||
| 100 | limit = 72 | ||
| 101 | for w in words: | ||
| 102 | if n + len(w) > limit: | ||
| 103 | |||
| 104 | n = 0 | ||
| 105 | print w, | ||
| 106 | n = n + len(w) + 1 | ||
| 107 | |||
| 108 | |||
| 109 | |||
| 110 | def tuple(list): | ||
| 111 | if len(list) == 0: return () | ||
| 112 | if len(list) == 1: return (list[0],) | ||
| 113 | i = len(list)/2 | ||
| 114 | return tuple(list[:i]) + tuple(list[i:]) | ||
| 115 | |||
| 116 | if __name__ == "__main__": | ||
| 117 | test() | ||
| @@ -0,0 +1,124 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Convert MH directories (1 message per file) or MMDF mailboxes (4x^A | ||
| 4 | # delimited) to unix mailbox (From ... delimited) on stdout. | ||
| 5 | # If -f is given, files contain one message per file (e.g. MH messages) | ||
| 6 | |||
| 7 | import rfc822 | ||
| 8 | import sys | ||
| 9 | import time | ||
| 10 | import os | ||
| 11 | import stat | ||
| 12 | import getopt | ||
| 13 | import re | ||
| 14 | |||
| 15 | def main(): | ||
| 16 | dofile = mmdf | ||
| 17 | try: | ||
| 18 | opts, args = getopt.getopt(sys.argv[1:], 'f') | ||
| 19 | except getopt.error, msg: | ||
| 20 | sys.stderr.write('%s\n' % msg) | ||
| 21 | sys.exit(2) | ||
| 22 | for o, a in opts: | ||
| 23 | if o == '-f': | ||
| 24 | dofile = message | ||
| 25 | if not args: | ||
| 26 | args = ['-'] | ||
| 27 | sts = 0 | ||
| 28 | for arg in args: | ||
| 29 | if arg == '-' or arg == '': | ||
| 30 | sts = dofile(sys.stdin) or sts | ||
| 31 | elif os.path.isdir(arg): | ||
| 32 | sts = mh(arg) or sts | ||
| 33 | elif os.path.isfile(arg): | ||
| 34 | try: | ||
| 35 | f = open(arg) | ||
| 36 | except IOError, msg: | ||
| 37 | sys.stderr.write('%s: %s\n' % (arg, msg)) | ||
| 38 | sts = 1 | ||
| 39 | continue | ||
| 40 | sts = dofile(f) or sts | ||
| 41 | f.close() | ||
| 42 | else: | ||
| 43 | sys.stderr.write('%s: not found\n' % arg) | ||
| 44 | sts = 1 | ||
| 45 | if sts: | ||
| 46 | sys.exit(sts) | ||
| 47 | |||
| 48 | numeric = re.compile('[1-9][0-9]*') | ||
| 49 | |||
| 50 | def mh(dir): | ||
| 51 | sts = 0 | ||
| 52 | msgs = os.listdir(dir) | ||
| 53 | for msg in msgs: | ||
| 54 | if numeric.match(msg) != len(msg): | ||
| 55 | continue | ||
| 56 | fn = os.path.join(dir, msg) | ||
| 57 | try: | ||
| 58 | f = open(fn) | ||
| 59 | except IOError, msg: | ||
| 60 | sys.stderr.write('%s: %s\n' % (fn, msg)) | ||
| 61 | sts = 1 | ||
| 62 | continue | ||
| 63 | sts = message(f) or sts | ||
| 64 | return sts | ||
| 65 | |||
| 66 | def mmdf(f): | ||
| 67 | sts = 0 | ||
| 68 | while 1: | ||
| 69 | line = f.readline() | ||
| 70 | if not line: | ||
| 71 | break | ||
| 72 | if line == '\1\1\1\1\n': | ||
| 73 | sts = message(f, line) or sts | ||
| 74 | else: | ||
| 75 | sys.stderr.write( | ||
| 76 | 'Bad line in MMFD mailbox: %r\n' % (line,)) | ||
| 77 | return sts | ||
| 78 | |||
| 79 | counter = 0 # for generating unique Message-ID headers | ||
| 80 | |||
| 81 | def message(f, delimiter = ''): | ||
| 82 | sts = 0 | ||
| 83 | # Parse RFC822 header | ||
| 84 | m = rfc822.Message(f) | ||
| 85 | # Write unix header line | ||
| 86 | fullname, email = m.getaddr('From') | ||
| 87 | tt = m.getdate('Date') | ||
| 88 | if tt: | ||
| 89 | t = time.mktime(tt) | ||
| 90 | else: | ||
| 91 | sys.stderr.write( | ||
| 92 | 'Unparseable date: %r\n' % (m.getheader('Date'),)) | ||
| 93 | t = os.fstat(f.fileno())[stat.ST_MTIME] | ||
| 94 | print 'From', email, time.ctime(t) | ||
| 95 | # Copy RFC822 header | ||
| 96 | for line in m.headers: | ||
| 97 | print line, | ||
| 98 | # Invent Message-ID header if none is present | ||
| 99 | if not m.has_key('message-id'): | ||
| 100 | global counter | ||
| 101 | counter = counter + 1 | ||
| 102 | msgid = "<%s.%d>" % (hex(t), counter) | ||
| 103 | sys.stderr.write("Adding Message-ID %s (From %s)\n" % | ||
| 104 | (msgid, email)) | ||
| 105 | print "Message-ID:", msgid | ||
| 106 | |||
| 107 | # Copy body | ||
| 108 | while 1: | ||
| 109 | line = f.readline() | ||
| 110 | if line == delimiter: | ||
| 111 | break | ||
| 112 | if not line: | ||
| 113 | sys.stderr.write('Unexpected EOF in message\n') | ||
| 114 | sts = 1 | ||
| 115 | break | ||
| 116 | if line[:5] == 'From ': | ||
| 117 | line = '>' + line | ||
| 118 | print line, | ||
| 119 | # Print trailing newline | ||
| 120 | |||
| 121 | return sts | ||
| 122 | |||
| 123 | if __name__ == "__main__": | ||
| 124 | main() | ||
| @@ -0,0 +1,61 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # A rather specialized script to make sure that a symbolic link named | ||
| 4 | # RCS exists pointing to a real RCS directory in a parallel tree | ||
| 5 | # referenced as RCStree in an ancestor directory. | ||
| 6 | # (I use this because I like my RCS files to reside on a physically | ||
| 7 | # different machine). | ||
| 8 | |||
| 9 | import os | ||
| 10 | |||
| 11 | def main(): | ||
| 12 | rcstree = 'RCStree' | ||
| 13 | rcs = 'RCS' | ||
| 14 | if os.path.islink(rcs): | ||
| 15 | print '%r is a symlink to %r' % (rcs, os.readlink(rcs)) | ||
| 16 | return | ||
| 17 | if os.path.isdir(rcs): | ||
| 18 | print '%r is an ordinary directory' % (rcs,) | ||
| 19 | return | ||
| 20 | if os.path.exists(rcs): | ||
| 21 | print '%r is a file?!?!' % (rcs,) | ||
| 22 | return | ||
| 23 | # | ||
| 24 | p = os.getcwd() | ||
| 25 | up = '' | ||
| 26 | down = '' | ||
| 27 | # Invariants: | ||
| 28 | # (1) join(p, down) is the current directory | ||
| 29 | # (2) up is the same directory as p | ||
| 30 | # Ergo: | ||
| 31 | # (3) join(up, down) is the current directory | ||
| 32 | #print 'p =', repr(p) | ||
| 33 | while not os.path.isdir(os.path.join(p, rcstree)): | ||
| 34 | head, tail = os.path.split(p) | ||
| 35 | #print 'head = %r; tail = %r' % (head, tail) | ||
| 36 | if not tail: | ||
| 37 | print 'Sorry, no ancestor dir contains %r' % (rcstree,) | ||
| 38 | return | ||
| 39 | p = head | ||
| 40 | up = os.path.join(os.pardir, up) | ||
| 41 | down = os.path.join(tail, down) | ||
| 42 | #print 'p = %r; up = %r; down = %r' % (p, up, down) | ||
| 43 | there = os.path.join(up, rcstree) | ||
| 44 | there = os.path.join(there, down) | ||
| 45 | there = os.path.join(there, rcs) | ||
| 46 | if os.path.isdir(there): | ||
| 47 | print '%r already exists' % (there, ) | ||
| 48 | else: | ||
| 49 | print 'making %r' % (there,) | ||
| 50 | makedirs(there) | ||
| 51 | print 'making symlink %r -> %r' % (rcs, there) | ||
| 52 | os.symlink(there, rcs) | ||
| 53 | |||
| 54 | def makedirs(p): | ||
| 55 | if not os.path.isdir(p): | ||
| 56 | head, tail = os.path.split(p) | ||
| 57 | makedirs(head) | ||
| 58 | os.mkdir(p, 0777) | ||
| 59 | |||
| 60 | if __name__ == "__main__": | ||
| 61 | main() | ||
| @@ -0,0 +1,149 @@ | |||
| 1 | # DAH should be three DOTs. | ||
| 2 | # Space between DOTs and DAHs should be one DOT. | ||
| 3 | # Space between two letters should be one DAH. | ||
| 4 | # Space between two words should be DOT DAH DAH. | ||
| 5 | |||
| 6 | import sys, math, audiodev | ||
| 7 | |||
| 8 | DOT = 30 | ||
| 9 | DAH = 3 * DOT | ||
| 10 | OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ... | ||
| 11 | |||
| 12 | morsetab = { | ||
| 13 | 'A': '.-', 'a': '.-', | ||
| 14 | 'B': '-...', 'b': '-...', | ||
| 15 | 'C': '-.-.', 'c': '-.-.', | ||
| 16 | 'D': '-..', 'd': '-..', | ||
| 17 | 'E': '.', 'e': '.', | ||
| 18 | 'F': '..-.', 'f': '..-.', | ||
| 19 | 'G': '--.', 'g': '--.', | ||
| 20 | 'H': '....', 'h': '....', | ||
| 21 | 'I': '..', 'i': '..', | ||
| 22 | 'J': '.---', 'j': '.---', | ||
| 23 | 'K': '-.-', 'k': '-.-', | ||
| 24 | 'L': '.-..', 'l': '.-..', | ||
| 25 | 'M': '--', 'm': '--', | ||
| 26 | 'N': '-.', 'n': '-.', | ||
| 27 | 'O': '---', 'o': '---', | ||
| 28 | 'P': '.--.', 'p': '.--.', | ||
| 29 | 'Q': '--.-', 'q': '--.-', | ||
| 30 | 'R': '.-.', 'r': '.-.', | ||
| 31 | 'S': '...', 's': '...', | ||
| 32 | 'T': '-', 't': '-', | ||
| 33 | 'U': '..-', 'u': '..-', | ||
| 34 | 'V': '...-', 'v': '...-', | ||
| 35 | 'W': '.--', 'w': '.--', | ||
| 36 | 'X': '-..-', 'x': '-..-', | ||
| 37 | 'Y': '-.--', 'y': '-.--', | ||
| 38 | 'Z': '--..', 'z': '--..', | ||
| 39 | '0': '-----', | ||
| 40 | '1': '.----', | ||
| 41 | '2': '..---', | ||
| 42 | '3': '...--', | ||
| 43 | '4': '....-', | ||
| 44 | '5': '.....', | ||
| 45 | '6': '-....', | ||
| 46 | '7': '--...', | ||
| 47 | '8': '---..', | ||
| 48 | '9': '----.', | ||
| 49 | ',': '--..--', | ||
| 50 | '.': '.-.-.-', | ||
| 51 | '?': '..--..', | ||
| 52 | ';': '-.-.-.', | ||
| 53 | ':': '---...', | ||
| 54 | "'": '.----.', | ||
| 55 | '-': '-....-', | ||
| 56 | '/': '-..-.', | ||
| 57 | '(': '-.--.-', | ||
| 58 | ')': '-.--.-', | ||
| 59 | '_': '..--.-', | ||
| 60 | ' ': ' ' | ||
| 61 | } | ||
| 62 | |||
| 63 | # If we play at 44.1 kHz (which we do), then if we produce one sine | ||
| 64 | # wave in 100 samples, we get a tone of 441 Hz. If we produce two | ||
| 65 | # sine waves in these 100 samples, we get a tone of 882 Hz. 882 Hz | ||
| 66 | # appears to be a nice one for playing morse code. | ||
| 67 | def mkwave(octave): | ||
| 68 | global sinewave, nowave | ||
| 69 | sinewave = '' | ||
| 70 | for i in range(100): | ||
| 71 | val = int(math.sin(math.pi * float(i) * octave / 50.0) * 30000) | ||
| 72 | sinewave = sinewave + chr((val >> 8) & 255) + chr(val & 255) | ||
| 73 | nowave = '\0' * 200 | ||
| 74 | |||
| 75 | mkwave(OCTAVE) | ||
| 76 | |||
| 77 | def main(): | ||
| 78 | import getopt, string | ||
| 79 | try: | ||
| 80 | opts, args = getopt.getopt(sys.argv[1:], 'o:p:') | ||
| 81 | except getopt.error: | ||
| 82 | sys.stderr.write('Usage ' + sys.argv[0] + | ||
| 83 | ' [ -o outfile ] [ args ] ...\n') | ||
| 84 | sys.exit(1) | ||
| 85 | dev = None | ||
| 86 | for o, a in opts: | ||
| 87 | if o == '-o': | ||
| 88 | import aifc | ||
| 89 | dev = aifc.open(a, 'w') | ||
| 90 | dev.setframerate(44100) | ||
| 91 | dev.setsampwidth(2) | ||
| 92 | dev.setnchannels(1) | ||
| 93 | if o == '-p': | ||
| 94 | mkwave(string.atoi(a)) | ||
| 95 | if not dev: | ||
| 96 | import audiodev | ||
| 97 | dev = audiodev.AudioDev() | ||
| 98 | dev.setoutrate(44100) | ||
| 99 | dev.setsampwidth(2) | ||
| 100 | dev.setnchannels(1) | ||
| 101 | dev.close = dev.stop | ||
| 102 | dev.writeframesraw = dev.writeframes | ||
| 103 | if args: | ||
| 104 | line = string.join(args) | ||
| 105 | else: | ||
| 106 | line = sys.stdin.readline() | ||
| 107 | while line: | ||
| 108 | mline = morse(line) | ||
| 109 | play(mline, dev) | ||
| 110 | if hasattr(dev, 'wait'): | ||
| 111 | dev.wait() | ||
| 112 | if not args: | ||
| 113 | line = sys.stdin.readline() | ||
| 114 | else: | ||
| 115 | line = '' | ||
| 116 | dev.close() | ||
| 117 | |||
| 118 | # Convert a string to morse code with \001 between the characters in | ||
| 119 | # the string. | ||
| 120 | def morse(line): | ||
| 121 | res = '' | ||
| 122 | for c in line: | ||
| 123 | try: | ||
| 124 | res = res + morsetab[c] + '\001' | ||
| 125 | except KeyError: | ||
| 126 | pass | ||
| 127 | return res | ||
| 128 | |||
| 129 | # Play a line of morse code. | ||
| 130 | def play(line, dev): | ||
| 131 | for c in line: | ||
| 132 | if c == '.': | ||
| 133 | sine(dev, DOT) | ||
| 134 | elif c == '-': | ||
| 135 | sine(dev, DAH) | ||
| 136 | else: # space | ||
| 137 | pause(dev, DAH + DOT) | ||
| 138 | pause(dev, DOT) | ||
| 139 | |||
| 140 | def sine(dev, length): | ||
| 141 | for i in range(length): | ||
| 142 | dev.writeframesraw(sinewave) | ||
| 143 | |||
| 144 | def pause(dev, length): | ||
| 145 | for i in range(length): | ||
| 146 | dev.writeframesraw(nowave) | ||
| 147 | |||
| 148 | if __name__ == '__main__' or sys.argv[0] == __name__: | ||
| 149 | main() | ||
| @@ -0,0 +1,59 @@ | |||
| 1 | NEWSLIST | ||
| 2 | ======== | ||
| 3 | A program to assist HTTP browsing of newsgroups | ||
| 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | |||
| 6 | WWW browsers such as NCSA Mosaic allow the user to read newsgroup | ||
| 7 | articles by specifying the group name in a URL eg 'news:comp.answers'. | ||
| 8 | |||
| 9 | To browse through many groups, though, (and there are several thousand | ||
| 10 | of them) you really need a page or pages containing links to all the | ||
| 11 | groups. There are some good ones out there, for example, | ||
| 12 | |||
| 13 | http://info.cern.ch/hypertext/DataSources/News/Groups/Overview.html | ||
| 14 | |||
| 15 | is the standard one at CERN, but it only shows the groups available there, | ||
| 16 | which may be rather different from those available on your machine. | ||
| 17 | |||
| 18 | Newslist is a program which creates a hierarchy of pages for you based | ||
| 19 | on the groups available from YOUR server. It is written in python - a | ||
| 20 | splendid interpreted object-oriented language which I suggest you get | ||
| 21 | right now from the directory /pub/python at ftp.cwi.nl, if you haven't | ||
| 22 | already got it. | ||
| 23 | |||
| 24 | You should be able to see some sample output by looking at: | ||
| 25 | http://pelican.cl.cam.ac.uk/newspage/root.html | ||
| 26 | |||
| 27 | Descriptions of newsgroups can be added from a file with one group | ||
| 28 | per line. eg: | ||
| 29 | |||
| 30 | alt.foo Articles about foo | ||
| 31 | comp.bar Programming in 'bar' and related languages | ||
| 32 | |||
| 33 | A suitable list detailing most groups can be found at ftp.uu.net in | ||
| 34 | /uunet-info/newsgroups.gz. | ||
| 35 | |||
| 36 | Make sure you read the information at the beginning of the program source and | ||
| 37 | configure the variables before running. | ||
| 38 | |||
| 39 | In addition to python, you need: | ||
| 40 | |||
| 41 | An NNTP-based news feed. | ||
| 42 | A directory in which to put the pages. | ||
| 43 | |||
| 44 | The programming is not very beautiful, but it works! It comes with no | ||
| 45 | warranty, express or implied, but with the hope that some others may | ||
| 46 | find it useful. | ||
| 47 | |||
| 48 | Comments, improvements & suggestions welcomed. | ||
| 49 | Quentin Stafford-Fraser | ||
| 50 | |||
| 51 | ---------------------------------------------------------------------- | ||
| 52 | Quentin Stafford-Fraser | ||
| 53 | http://pelican.cl.cam.ac.uk/people/qs101/me.html | ||
| 54 | |||
| 55 | Cambridge University Computer Lab Rank Xerox Cambridge EuroPARC | ||
| 56 | qs101@cl.cam.ac.uk fraser@europarc.xerox.com | ||
| 57 | Tel: +44 223 334411 Tel: +44 223 341521 | ||
| 58 | Fax: +44 223 334679 Fax: +44 223 341510 | ||
| 59 | ---------------------------------------------------------------------- | ||
| @@ -0,0 +1,366 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | ####################################################################### | ||
| 3 | # Newslist $Revision: 37320 $ | ||
| 4 | # | ||
| 5 | # Syntax: | ||
| 6 | # newslist [ -a ] | ||
| 7 | # | ||
| 8 | # This is a program to create a directory full of HTML pages | ||
| 9 | # which between them contain links to all the newsgroups available | ||
| 10 | # on your server. | ||
| 11 | # | ||
| 12 | # The -a option causes a complete list of all groups to be read from | ||
| 13 | # the server rather than just the ones which have appeared since last | ||
| 14 | # execution. This recreates the local list from scratch. Use this on | ||
| 15 | # the first invocation of the program, and from time to time thereafter. | ||
| 16 | # When new groups are first created they may appear on your server as | ||
| 17 | # empty groups. By default, empty groups are ignored by the -a option. | ||
| 18 | # However, these new groups will not be created again, and so will not | ||
| 19 | # appear in the server's list of 'new groups' at a later date. Hence it | ||
| 20 | # won't appear until you do a '-a' after some articles have appeared. | ||
| 21 | # | ||
| 22 | # I should really keep a list of ignored empty groups and re-check them | ||
| 23 | # for articles on every run, but I haven't got around to it yet. | ||
| 24 | # | ||
| 25 | # This assumes an NNTP news feed. | ||
| 26 | # | ||
| 27 | # Feel free to copy, distribute and modify this code for | ||
| 28 | # non-commercial use. If you make any useful modifications, let me | ||
| 29 | # know! | ||
| 30 | # | ||
| 31 | # (c) Quentin Stafford-Fraser 1994 | ||
| 32 | # fraser@europarc.xerox.com qs101@cl.cam.ac.uk | ||
| 33 | # # | ||
| 34 | ####################################################################### | ||
| 35 | import sys,nntplib, string, marshal, time, os, posix, string | ||
| 36 | |||
| 37 | ####################################################################### | ||
| 38 | # Check these variables before running! # | ||
| 39 | |||
| 40 | # Top directory. | ||
| 41 | # Filenames which don't start with / are taken as being relative to this. | ||
| 42 | topdir='/anfs/qsbigdisc/web/html/newspage' | ||
| 43 | |||
| 44 | # The name of your NNTP host | ||
| 45 | # eg. | ||
| 46 | # newshost = 'nntp-serv.cl.cam.ac.uk' | ||
| 47 | # or use following to get the name from the NNTPSERVER environment | ||
| 48 | # variable: | ||
| 49 | # newshost = posix.environ['NNTPSERVER'] | ||
| 50 | newshost = 'nntp-serv.cl.cam.ac.uk' | ||
| 51 | |||
| 52 | # The filename for a local cache of the newsgroup list | ||
| 53 | treefile = 'grouptree' | ||
| 54 | |||
| 55 | # The filename for descriptions of newsgroups | ||
| 56 | # I found a suitable one at ftp.uu.net in /uunet-info/newgroups.gz | ||
| 57 | # You can set this to '' if you don't wish to use one. | ||
| 58 | descfile = 'newsgroups' | ||
| 59 | |||
| 60 | # The directory in which HTML pages should be created | ||
| 61 | # eg. | ||
| 62 | # pagedir = '/usr/local/lib/html/newspage' | ||
| 63 | # pagedir = 'pages' | ||
| 64 | pagedir = topdir | ||
| 65 | |||
| 66 | # The html prefix which will refer to this directory | ||
| 67 | # eg. | ||
| 68 | # httppref = '/newspage/', | ||
| 69 | # or leave blank for relative links between pages: (Recommended) | ||
| 70 | # httppref = '' | ||
| 71 | httppref = '' | ||
| 72 | |||
| 73 | # The name of the 'root' news page in this directory. | ||
| 74 | # A .html suffix will be added. | ||
| 75 | rootpage = 'root' | ||
| 76 | |||
| 77 | # Set skipempty to 0 if you wish to see links to empty groups as well. | ||
| 78 | # Only affects the -a option. | ||
| 79 | skipempty = 1 | ||
| 80 | |||
| 81 | # pagelinkicon can contain html to put an icon after links to | ||
| 82 | # further pages. This helps to make important links stand out. | ||
| 83 | # Set to '' if not wanted, or '...' is quite a good one. | ||
| 84 | pagelinkicon='... <img src="http://pelican.cl.cam.ac.uk/icons/page.xbm"> ' | ||
| 85 | |||
| 86 | # --------------------------------------------------------------------- | ||
| 87 | # Less important personal preferences: | ||
| 88 | |||
| 89 | # Sublistsize controls the maximum number of items the will appear as | ||
| 90 | # an indented sub-list before the whole thing is moved onto a different | ||
| 91 | # page. The smaller this is, the more pages you will have, but the | ||
| 92 | # shorter each will be. | ||
| 93 | sublistsize = 4 | ||
| 94 | |||
| 95 | # That should be all. # | ||
| 96 | ####################################################################### | ||
| 97 | |||
| 98 | for dir in os.curdir, os.environ['HOME']: | ||
| 99 | rcfile = os.path.join(dir, '.newslistrc.py') | ||
| 100 | if os.path.exists(rcfile): | ||
| 101 | print rcfile | ||
| 102 | execfile(rcfile) | ||
| 103 | break | ||
| 104 | |||
| 105 | from nntplib import NNTP | ||
| 106 | from stat import * | ||
| 107 | |||
| 108 | rcsrev = '$Revision: 37320 $' | ||
| 109 | rcsrev = string.join(filter(lambda s: '$' not in s, string.split(rcsrev))) | ||
| 110 | desc = {} | ||
| 111 | |||
| 112 | # Make (possibly) relative filenames into absolute ones | ||
| 113 | treefile = os.path.join(topdir,treefile) | ||
| 114 | descfile = os.path.join(topdir,descfile) | ||
| 115 | page = os.path.join(topdir,pagedir) | ||
| 116 | |||
| 117 | # First the bits for creating trees --------------------------- | ||
| 118 | |||
| 119 | # Addtotree creates/augments a tree from a list of group names | ||
| 120 | def addtotree(tree, groups): | ||
| 121 | print 'Updating tree...' | ||
| 122 | for i in groups: | ||
| 123 | parts = string.splitfields(i,'.') | ||
| 124 | makeleaf(tree, parts) | ||
| 125 | |||
| 126 | # Makeleaf makes a leaf and the branch leading to it if necessary | ||
| 127 | def makeleaf(tree,path): | ||
| 128 | j = path[0] | ||
| 129 | l = len(path) | ||
| 130 | |||
| 131 | if not tree.has_key(j): | ||
| 132 | tree[j] = {} | ||
| 133 | if l == 1: | ||
| 134 | tree[j]['.'] = '.' | ||
| 135 | if l > 1: | ||
| 136 | makeleaf(tree[j],path[1:]) | ||
| 137 | |||
| 138 | # Then the bits for outputting trees as pages ---------------- | ||
| 139 | |||
| 140 | # Createpage creates an HTML file named <root>.html containing links | ||
| 141 | # to those groups beginning with <root>. | ||
| 142 | |||
| 143 | def createpage(root, tree, p): | ||
| 144 | filename = os.path.join(pagedir,root+'.html') | ||
| 145 | if root == rootpage: | ||
| 146 | detail = '' | ||
| 147 | else: | ||
| 148 | detail = ' under ' + root | ||
| 149 | f = open(filename,'w') | ||
| 150 | # f.write('Content-Type: text/html\n') | ||
| 151 | f.write('<TITLE>Newsgroups available' + detail + '</TITLE>\n') | ||
| 152 | f.write('<H1>Newsgroups available' + detail +'</H1>\n') | ||
| 153 | f.write('<A HREF="'+httppref+rootpage+'.html">Back to top level</A><P>\n') | ||
| 154 | printtree(f,tree,0,p) | ||
| 155 | f.write('<I>This page automatically created by \'newslist\' v. '+rcsrev+'.') | ||
| 156 | f.write(time.ctime(time.time()) + '</I><P>') | ||
| 157 | f.close() | ||
| 158 | |||
| 159 | # Printtree prints the groups as a bulleted list. Groups with | ||
| 160 | # more than <sublistsize> subgroups will be put on a separate page. | ||
| 161 | # Other sets of subgroups are just indented. | ||
| 162 | |||
| 163 | def printtree(f, tree, indent, p): | ||
| 164 | global desc | ||
| 165 | l = len(tree) | ||
| 166 | |||
| 167 | if l > sublistsize and indent>0: | ||
| 168 | # Create a new page and a link to it | ||
| 169 | f.write('<LI><B><A HREF="'+httppref+p[1:]+'.html">') | ||
| 170 | f.write(p[1:]+'.*') | ||
| 171 | f.write('</A></B>'+pagelinkicon+'\n') | ||
| 172 | createpage(p[1:], tree, p) | ||
| 173 | return | ||
| 174 | |||
| 175 | kl = tree.keys() | ||
| 176 | |||
| 177 | if l > 1: | ||
| 178 | kl.sort() | ||
| 179 | if indent > 0: | ||
| 180 | # Create a sub-list | ||
| 181 | f.write('<LI>'+p[1:]+'\n<UL>') | ||
| 182 | else: | ||
| 183 | # Create a main list | ||
| 184 | f.write('<UL>') | ||
| 185 | indent = indent + 1 | ||
| 186 | |||
| 187 | for i in kl: | ||
| 188 | if i == '.': | ||
| 189 | # Output a newsgroup | ||
| 190 | f.write('<LI><A HREF="news:' + p[1:] + '">'+ p[1:] + '</A> ') | ||
| 191 | if desc.has_key(p[1:]): | ||
| 192 | f.write(' <I>'+desc[p[1:]]+'</I>\n') | ||
| 193 | else: | ||
| 194 | f.write('\n') | ||
| 195 | else: | ||
| 196 | # Output a hierarchy | ||
| 197 | printtree(f,tree[i], indent, p+'.'+i) | ||
| 198 | |||
| 199 | if l > 1: | ||
| 200 | f.write('\n</UL>') | ||
| 201 | |||
| 202 | # Reading descriptions file --------------------------------------- | ||
| 203 | |||
| 204 | # This returns an array mapping group name to its description | ||
| 205 | |||
| 206 | def readdesc(descfile): | ||
| 207 | global desc | ||
| 208 | |||
| 209 | desc = {} | ||
| 210 | |||
| 211 | if descfile == '': | ||
| 212 | return | ||
| 213 | |||
| 214 | try: | ||
| 215 | d = open(descfile, 'r') | ||
| 216 | print 'Reading descriptions...' | ||
| 217 | except (IOError): | ||
| 218 | print 'Failed to open description file ' + descfile | ||
| 219 | return | ||
| 220 | l = d.readline() | ||
| 221 | while l != '': | ||
| 222 | bits = string.split(l) | ||
| 223 | try: | ||
| 224 | grp = bits[0] | ||
| 225 | dsc = string.join(bits[1:]) | ||
| 226 | if len(dsc)>1: | ||
| 227 | desc[grp] = dsc | ||
| 228 | except (IndexError): | ||
| 229 | pass | ||
| 230 | l = d.readline() | ||
| 231 | |||
| 232 | # Check that ouput directory exists, ------------------------------ | ||
| 233 | # and offer to create it if not | ||
| 234 | |||
| 235 | def checkopdir(pagedir): | ||
| 236 | if not os.path.isdir(pagedir): | ||
| 237 | print 'Directory '+pagedir+' does not exist.' | ||
| 238 | print 'Shall I create it for you? (y/n)' | ||
| 239 | if sys.stdin.readline()[0] == 'y': | ||
| 240 | try: | ||
| 241 | os.mkdir(pagedir,0777) | ||
| 242 | except: | ||
| 243 | print 'Sorry - failed!' | ||
| 244 | sys.exit(1) | ||
| 245 | else: | ||
| 246 | print 'OK. Exiting.' | ||
| 247 | sys.exit(1) | ||
| 248 | |||
| 249 | # Read and write current local tree ---------------------------------- | ||
| 250 | |||
| 251 | def readlocallist(treefile): | ||
| 252 | print 'Reading current local group list...' | ||
| 253 | tree = {} | ||
| 254 | try: | ||
| 255 | treetime = time.localtime(os.stat(treefile)[ST_MTIME]) | ||
| 256 | except: | ||
| 257 | print '\n*** Failed to open local group cache '+treefile | ||
| 258 | print 'If this is the first time you have run newslist, then' | ||
| 259 | print 'use the -a option to create it.' | ||
| 260 | sys.exit(1) | ||
| 261 | treedate = '%02d%02d%02d' % (treetime[0] % 100 ,treetime[1], treetime[2]) | ||
| 262 | try: | ||
| 263 | dump = open(treefile,'r') | ||
| 264 | tree = marshal.load(dump) | ||
| 265 | dump.close() | ||
| 266 | except (IOError): | ||
| 267 | print 'Cannot open local group list ' + treefile | ||
| 268 | return (tree, treedate) | ||
| 269 | |||
| 270 | def writelocallist(treefile, tree): | ||
| 271 | try: | ||
| 272 | dump = open(treefile,'w') | ||
| 273 | groups = marshal.dump(tree,dump) | ||
| 274 | dump.close() | ||
| 275 | print 'Saved list to '+treefile+'\n' | ||
| 276 | except: | ||
| 277 | print 'Sorry - failed to write to local group cache '+treefile | ||
| 278 | print 'Does it (or its directory) have the correct permissions?' | ||
| 279 | sys.exit(1) | ||
| 280 | |||
| 281 | # Return list of all groups on server ----------------------------- | ||
| 282 | |||
| 283 | def getallgroups(server): | ||
| 284 | print 'Getting list of all groups...' | ||
| 285 | treedate='010101' | ||
| 286 | info = server.list()[1] | ||
| 287 | groups = [] | ||
| 288 | print 'Processing...' | ||
| 289 | if skipempty: | ||
| 290 | print '\nIgnoring following empty groups:' | ||
| 291 | for i in info: | ||
| 292 | grpname = string.split(i[0])[0] | ||
| 293 | if skipempty and string.atoi(i[1]) < string.atoi(i[2]): | ||
| 294 | print grpname+' ', | ||
| 295 | else: | ||
| 296 | groups.append(grpname) | ||
| 297 | print '\n' | ||
| 298 | if skipempty: | ||
| 299 | print '(End of empty groups)' | ||
| 300 | return groups | ||
| 301 | |||
| 302 | # Return list of new groups on server ----------------------------- | ||
| 303 | |||
| 304 | def getnewgroups(server, treedate): | ||
| 305 | print 'Getting list of new groups since start of '+treedate+'...', | ||
| 306 | info = server.newgroups(treedate,'000001')[1] | ||
| 307 | print 'got %d.' % len(info) | ||
| 308 | print 'Processing...', | ||
| 309 | groups = [] | ||
| 310 | for i in info: | ||
| 311 | grpname = string.split(i)[0] | ||
| 312 | groups.append(grpname) | ||
| 313 | print 'Done' | ||
| 314 | return groups | ||
| 315 | |||
| 316 | # Now the main program -------------------------------------------- | ||
| 317 | |||
| 318 | def main(): | ||
| 319 | global desc | ||
| 320 | |||
| 321 | tree={} | ||
| 322 | |||
| 323 | # Check that the output directory exists | ||
| 324 | checkopdir(pagedir); | ||
| 325 | |||
| 326 | try: | ||
| 327 | print 'Connecting to '+newshost+'...' | ||
| 328 | if sys.version[0] == '0': | ||
| 329 | s = NNTP.init(newshost) | ||
| 330 | else: | ||
| 331 | s = NNTP(newshost) | ||
| 332 | connected = 1 | ||
| 333 | except (nntplib.error_temp, nntplib.error_perm), x: | ||
| 334 | print 'Error connecting to host:', x | ||
| 335 | print 'I\'ll try to use just the local list.' | ||
| 336 | connected = 0 | ||
| 337 | |||
| 338 | # If -a is specified, read the full list of groups from server | ||
| 339 | if connected and len(sys.argv) > 1 and sys.argv[1] == '-a': | ||
| 340 | |||
| 341 | groups = getallgroups(s) | ||
| 342 | |||
| 343 | # Otherwise just read the local file and then add | ||
| 344 | # groups created since local file last modified. | ||
| 345 | else: | ||
| 346 | |||
| 347 | (tree, treedate) = readlocallist(treefile) | ||
| 348 | if connected: | ||
| 349 | groups = getnewgroups(s, treedate) | ||
| 350 | |||
| 351 | if connected: | ||
| 352 | addtotree(tree, groups) | ||
| 353 | writelocallist(treefile,tree) | ||
| 354 | |||
| 355 | # Read group descriptions | ||
| 356 | readdesc(descfile) | ||
| 357 | |||
| 358 | print 'Creating pages...' | ||
| 359 | createpage(rootpage, tree, '') | ||
| 360 | print 'Done' | ||
| 361 | |||
| 362 | if __name__ == "__main__": | ||
| 363 | main() | ||
| 364 | |||
| 365 | # That's all folks | ||
| 366 | ###################################################################### | ||
| @@ -0,0 +1,34 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Print digits of pi forever. | ||
| 4 | # | ||
| 5 | # The algorithm, using Python's 'long' integers ("bignums"), works | ||
| 6 | # with continued fractions, and was conceived by Lambert Meertens. | ||
| 7 | # | ||
| 8 | # See also the ABC Programmer's Handbook, by Geurts, Meertens & Pemberton, | ||
| 9 | # published by Prentice-Hall (UK) Ltd., 1990. | ||
| 10 | |||
| 11 | import sys | ||
| 12 | |||
| 13 | def main(): | ||
| 14 | k, a, b, a1, b1 = 2L, 4L, 1L, 12L, 4L | ||
| 15 | while 1: | ||
| 16 | # Next approximation | ||
| 17 | p, q, k = k*k, 2L*k+1L, k+1L | ||
| 18 | a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1 | ||
| 19 | # Print common digits | ||
| 20 | d, d1 = a/b, a1/b1 | ||
| 21 | while d == d1: | ||
| 22 | output(d) | ||
| 23 | a, a1 = 10L*(a%b), 10L*(a1%b1) | ||
| 24 | d, d1 = a/b, a1/b1 | ||
| 25 | |||
| 26 | def output(d): | ||
| 27 | # Use write() to avoid spaces between the digits | ||
| 28 | # Use str() to avoid the 'L' | ||
| 29 | sys.stdout.write(str(d)) | ||
| 30 | # Flush so the output is seen immediately | ||
| 31 | sys.stdout.flush() | ||
| 32 | |||
| 33 | if __name__ == "__main__": | ||
| 34 | main() | ||
| @@ -0,0 +1,130 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Emulate some Perl command line options. | ||
| 4 | # Usage: pp [-a] [-c] [-d] [-e scriptline] [-F fieldsep] [-n] [-p] [file] ... | ||
| 5 | # Where the options mean the following: | ||
| 6 | # -a : together with -n or -p, splits each line into list F | ||
| 7 | # -c : check syntax only, do not execute any code | ||
| 8 | # -d : run the script under the debugger, pdb | ||
| 9 | # -e scriptline : gives one line of the Python script; may be repeated | ||
| 10 | # -F fieldsep : sets the field separator for the -a option [not in Perl] | ||
| 11 | # -n : runs the script for each line of input | ||
| 12 | # -p : prints the line after the script has run | ||
| 13 | # When no script lines have been passed, the first file argument | ||
| 14 | # contains the script. With -n or -p, the remaining arguments are | ||
| 15 | # read as input to the script, line by line. If a file is '-' | ||
| 16 | # or missing, standard input is read. | ||
| 17 | |||
| 18 | # XXX To do: | ||
| 19 | # - add -i extension option (change files in place) | ||
| 20 | # - make a single loop over the files and lines (changes effect of 'break')? | ||
| 21 | # - add an option to specify the record separator | ||
| 22 | # - except for -n/-p, run directly from the file if at all possible | ||
| 23 | |||
| 24 | import sys | ||
| 25 | import string | ||
| 26 | import getopt | ||
| 27 | |||
| 28 | FS = '' | ||
| 29 | SCRIPT = [] | ||
| 30 | AFLAG = 0 | ||
| 31 | CFLAG = 0 | ||
| 32 | DFLAG = 0 | ||
| 33 | NFLAG = 0 | ||
| 34 | PFLAG = 0 | ||
| 35 | |||
| 36 | try: | ||
| 37 | optlist, ARGS = getopt.getopt(sys.argv[1:], 'acde:F:np') | ||
| 38 | except getopt.error, msg: | ||
| 39 | sys.stderr.write(sys.argv[0] + ': ' + msg + '\n') | ||
| 40 | sys.exit(2) | ||
| 41 | |||
| 42 | for option, optarg in optlist: | ||
| 43 | if option == '-a': | ||
| 44 | AFLAG = 1 | ||
| 45 | elif option == '-c': | ||
| 46 | CFLAG = 1 | ||
| 47 | elif option == '-d': | ||
| 48 | DFLAG = 1 | ||
| 49 | elif option == '-e': | ||
| 50 | for line in string.splitfields(optarg, '\n'): | ||
| 51 | SCRIPT.append(line) | ||
| 52 | elif option == '-F': | ||
| 53 | FS = optarg | ||
| 54 | elif option == '-n': | ||
| 55 | NFLAG = 1 | ||
| 56 | PFLAG = 0 | ||
| 57 | elif option == '-p': | ||
| 58 | NFLAG = 1 | ||
| 59 | PFLAG = 1 | ||
| 60 | else: | ||
| 61 | print option, 'not recognized???' | ||
| 62 | |||
| 63 | if not ARGS: ARGS.append('-') | ||
| 64 | |||
| 65 | if not SCRIPT: | ||
| 66 | if ARGS[0] == '-': | ||
| 67 | fp = sys.stdin | ||
| 68 | else: | ||
| 69 | fp = open(ARGS[0], 'r') | ||
| 70 | while 1: | ||
| 71 | line = fp.readline() | ||
| 72 | if not line: break | ||
| 73 | SCRIPT.append(line[:-1]) | ||
| 74 | del fp | ||
| 75 | del ARGS[0] | ||
| 76 | if not ARGS: ARGS.append('-') | ||
| 77 | |||
| 78 | if CFLAG: | ||
| 79 | prologue = ['if 0:'] | ||
| 80 | epilogue = [] | ||
| 81 | elif NFLAG: | ||
| 82 | # Note that it is on purpose that AFLAG and PFLAG are | ||
| 83 | # tested dynamically each time through the loop | ||
| 84 | prologue = [ \ | ||
| 85 | 'LINECOUNT = 0', \ | ||
| 86 | 'for FILE in ARGS:', \ | ||
| 87 | ' \tif FILE == \'-\':', \ | ||
| 88 | ' \t \tFP = sys.stdin', \ | ||
| 89 | ' \telse:', \ | ||
| 90 | ' \t \tFP = open(FILE, \'r\')', \ | ||
| 91 | ' \tLINENO = 0', \ | ||
| 92 | ' \twhile 1:', \ | ||
| 93 | ' \t \tLINE = FP.readline()', \ | ||
| 94 | ' \t \tif not LINE: break', \ | ||
| 95 | ' \t \tLINENO = LINENO + 1', \ | ||
| 96 | ' \t \tLINECOUNT = LINECOUNT + 1', \ | ||
| 97 | ' \t \tL = LINE[:-1]', \ | ||
| 98 | ' \t \taflag = AFLAG', \ | ||
| 99 | ' \t \tif aflag:', \ | ||
| 100 | ' \t \t \tif FS: F = string.splitfields(L, FS)', \ | ||
| 101 | ' \t \t \telse: F = string.split(L)' \ | ||
| 102 | ] | ||
| 103 | epilogue = [ \ | ||
| 104 | ' \t \tif not PFLAG: continue', \ | ||
| 105 | ' \t \tif aflag:', \ | ||
| 106 | ' \t \t \tif FS: print string.joinfields(F, FS)', \ | ||
| 107 | ' \t \t \telse: print string.join(F)', \ | ||
| 108 | ' \t \telse: print L', \ | ||
| 109 | ] | ||
| 110 | else: | ||
| 111 | prologue = ['if 1:'] | ||
| 112 | epilogue = [] | ||
| 113 | |||
| 114 | # Note that we indent using tabs only, so that any indentation style | ||
| 115 | # used in 'command' will come out right after re-indentation. | ||
| 116 | |||
| 117 | program = string.joinfields(prologue, '\n') + '\n' | ||
| 118 | for line in SCRIPT: | ||
| 119 | program = program + (' \t \t' + line + '\n') | ||
| 120 | program = program + (string.joinfields(epilogue, '\n') + '\n') | ||
| 121 | |||
| 122 | import tempfile | ||
| 123 | fp = tempfile.NamedTemporaryFile() | ||
| 124 | fp.write(program) | ||
| 125 | fp.flush() | ||
| 126 | if DFLAG: | ||
| 127 | import pdb | ||
| 128 | pdb.run('execfile(%r)' % (tfn,)) | ||
| 129 | else: | ||
| 130 | execfile(tfn) | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Print prime numbers in a given range | ||
| 4 | |||
| 5 | def main(): | ||
| 6 | import sys | ||
| 7 | min, max = 2, 0x7fffffff | ||
| 8 | if sys.argv[1:]: | ||
| 9 | min = int(eval(sys.argv[1])) | ||
| 10 | if sys.argv[2:]: | ||
| 11 | max = int(eval(sys.argv[2])) | ||
| 12 | primes(min, max) | ||
| 13 | |||
| 14 | def primes(min, max): | ||
| 15 | if 2 >= min: print 2 | ||
| 16 | primes = [2] | ||
| 17 | i = 3 | ||
| 18 | while i <= max: | ||
| 19 | for p in primes: | ||
| 20 | if i%p == 0 or p*p > i: break | ||
| 21 | if i%p <> 0: | ||
| 22 | primes.append(i) | ||
| 23 | if i >= min: print i | ||
| 24 | i = i+2 | ||
| 25 | |||
| 26 | if __name__ == "__main__": | ||
| 27 | main() | ||
| @@ -0,0 +1,85 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | """N queens problem. | ||
| 4 | |||
| 5 | The (well-known) problem is due to Niklaus Wirth. | ||
| 6 | |||
| 7 | This solution is inspired by Dijkstra (Structured Programming). It is | ||
| 8 | a classic recursive backtracking approach. | ||
| 9 | |||
| 10 | """ | ||
| 11 | |||
| 12 | N = 8 # Default; command line overrides | ||
| 13 | |||
| 14 | class Queens: | ||
| 15 | |||
| 16 | def __init__(self, n=N): | ||
| 17 | self.n = n | ||
| 18 | self.reset() | ||
| 19 | |||
| 20 | def reset(self): | ||
| 21 | n = self.n | ||
| 22 | self.y = [None]*n # Where is the queen in column x | ||
| 23 | self.row = [0]*n # Is row[y] safe? | ||
| 24 | self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe? | ||
| 25 | self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe? | ||
| 26 | self.nfound = 0 # Instrumentation | ||
| 27 | |||
| 28 | def solve(self, x=0): # Recursive solver | ||
| 29 | for y in range(self.n): | ||
| 30 | if self.safe(x, y): | ||
| 31 | self.place(x, y) | ||
| 32 | if x+1 == self.n: | ||
| 33 | self.display() | ||
| 34 | else: | ||
| 35 | self.solve(x+1) | ||
| 36 | self.remove(x, y) | ||
| 37 | |||
| 38 | def safe(self, x, y): | ||
| 39 | return not self.row[y] and not self.up[x-y] and not self.down[x+y] | ||
| 40 | |||
| 41 | def place(self, x, y): | ||
| 42 | self.y[x] = y | ||
| 43 | self.row[y] = 1 | ||
| 44 | self.up[x-y] = 1 | ||
| 45 | self.down[x+y] = 1 | ||
| 46 | |||
| 47 | def remove(self, x, y): | ||
| 48 | self.y[x] = None | ||
| 49 | self.row[y] = 0 | ||
| 50 | self.up[x-y] = 0 | ||
| 51 | self.down[x+y] = 0 | ||
| 52 | |||
| 53 | silent = 0 # If set, count solutions only | ||
| 54 | |||
| 55 | def display(self): | ||
| 56 | self.nfound = self.nfound + 1 | ||
| 57 | if self.silent: | ||
| 58 | return | ||
| 59 | print '+-' + '--'*self.n + '+' | ||
| 60 | for y in range(self.n-1, -1, -1): | ||
| 61 | print '|', | ||
| 62 | for x in range(self.n): | ||
| 63 | if self.y[x] == y: | ||
| 64 | print "Q", | ||
| 65 | else: | ||
| 66 | print ".", | ||
| 67 | print '|' | ||
| 68 | print '+-' + '--'*self.n + '+' | ||
| 69 | |||
| 70 | def main(): | ||
| 71 | import sys | ||
| 72 | silent = 0 | ||
| 73 | n = N | ||
| 74 | if sys.argv[1:2] == ['-n']: | ||
| 75 | silent = 1 | ||
| 76 | del sys.argv[1] | ||
| 77 | if sys.argv[1:]: | ||
| 78 | n = int(sys.argv[1]) | ||
| 79 | q = Queens(n) | ||
| 80 | q.silent = silent | ||
| 81 | q.solve() | ||
| 82 | print "Found", q.nfound, "solutions." | ||
| 83 | |||
| 84 | if __name__ == "__main__": | ||
| 85 | main() | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | # script.py -- Make typescript of terminal session. | ||
| 3 | # Usage: | ||
| 4 | # -a Append to typescript. | ||
| 5 | # -p Use Python as shell. | ||
| 6 | # Author: Steen Lumholt. | ||
| 7 | |||
| 8 | |||
| 9 | import os, time, sys | ||
| 10 | import pty | ||
| 11 | |||
| 12 | def read(fd): | ||
| 13 | data = os.read(fd, 1024) | ||
| 14 | file.write(data) | ||
| 15 | return data | ||
| 16 | |||
| 17 | shell = 'sh' | ||
| 18 | filename = 'typescript' | ||
| 19 | mode = 'w' | ||
| 20 | if os.environ.has_key('SHELL'): | ||
| 21 | shell = os.environ['SHELL'] | ||
| 22 | if '-a' in sys.argv: | ||
| 23 | mode = 'a' | ||
| 24 | if '-p' in sys.argv: | ||
| 25 | shell = 'python' | ||
| 26 | |||
| 27 | file = open(filename, mode) | ||
| 28 | |||
| 29 | sys.stdout.write('Script started, file is %s\n' % filename) | ||
| 30 | file.write('Script started on %s\n' % time.ctime(time.time())) | ||
| 31 | pty.spawn(shell, read) | ||
| 32 | file.write('Script done on %s\n' % time.ctime(time.time())) | ||
| 33 | sys.stdout.write('Script done, file is %s\n' % filename) | ||
| @@ -0,0 +1,107 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Calculate your unbirthday count (see Alice in Wonderland). | ||
| 4 | # This is defined as the number of days from your birth until today | ||
| 5 | # that weren't your birthday. (The day you were born is not counted). | ||
| 6 | # Leap years make it interesting. | ||
| 7 | |||
| 8 | import sys | ||
| 9 | import time | ||
| 10 | import calendar | ||
| 11 | |||
| 12 | def main(): | ||
| 13 | # Note that the range checks below also check for bad types, | ||
| 14 | # e.g. 3.14 or (). However syntactically invalid replies | ||
| 15 | # will raise an exception. | ||
| 16 | if sys.argv[1:]: | ||
| 17 | year = int(sys.argv[1]) | ||
| 18 | else: | ||
| 19 | year = int(raw_input('In which year were you born? ')) | ||
| 20 | if 0<=year<100: | ||
| 21 | print "I'll assume that by", year, | ||
| 22 | year = year + 1900 | ||
| 23 | print 'you mean', year, 'and not the early Christian era' | ||
| 24 | elif not (1850<=year<=2002): | ||
| 25 | print "It's hard to believe you were born in", year | ||
| 26 | return | ||
| 27 | # | ||
| 28 | if sys.argv[2:]: | ||
| 29 | month = int(sys.argv[2]) | ||
| 30 | else: | ||
| 31 | month = int(raw_input('And in which month? (1-12) ')) | ||
| 32 | if not (1<=month<=12): | ||
| 33 | print 'There is no month numbered', month | ||
| 34 | return | ||
| 35 | # | ||
| 36 | if sys.argv[3:]: | ||
| 37 | day = int(sys.argv[3]) | ||
| 38 | else: | ||
| 39 | day = int(raw_input('And on what day of that month? (1-31) ')) | ||
| 40 | if month == 2 and calendar.isleap(year): | ||
| 41 | maxday = 29 | ||
| 42 | else: | ||
| 43 | maxday = calendar.mdays[month] | ||
| 44 | if not (1<=day<=maxday): | ||
| 45 | print 'There are no', day, 'days in that month!' | ||
| 46 | return | ||
| 47 | # | ||
| 48 | bdaytuple = (year, month, day) | ||
| 49 | bdaydate = mkdate(bdaytuple) | ||
| 50 | print 'You were born on', format(bdaytuple) | ||
| 51 | # | ||
| 52 | todaytuple = time.localtime()[:3] | ||
| 53 | todaydate = mkdate(todaytuple) | ||
| 54 | print 'Today is', format(todaytuple) | ||
| 55 | # | ||
| 56 | if bdaytuple > todaytuple: | ||
| 57 | print 'You are a time traveler. Go back to the future!' | ||
| 58 | return | ||
| 59 | # | ||
| 60 | if bdaytuple == todaytuple: | ||
| 61 | print 'You were born today. Have a nice life!' | ||
| 62 | return | ||
| 63 | # | ||
| 64 | days = todaydate - bdaydate | ||
| 65 | print 'You have lived', days, 'days' | ||
| 66 | # | ||
| 67 | age = 0 | ||
| 68 | for y in range(year, todaytuple[0] + 1): | ||
| 69 | if bdaytuple < (y, month, day) <= todaytuple: | ||
| 70 | age = age + 1 | ||
| 71 | # | ||
| 72 | print 'You are', age, 'years old' | ||
| 73 | # | ||
| 74 | if todaytuple[1:] == bdaytuple[1:]: | ||
| 75 | print 'Congratulations! Today is your', nth(age), 'birthday' | ||
| 76 | print 'Yesterday was your', | ||
| 77 | else: | ||
| 78 | print 'Today is your', | ||
| 79 | print nth(days - age), 'unbirthday' | ||
| 80 | |||
| 81 | def format((year, month, day)): | ||
| 82 | return '%d %s %d' % (day, calendar.month_name[month], year) | ||
| 83 | |||
| 84 | def nth(n): | ||
| 85 | if n == 1: return '1st' | ||
| 86 | if n == 2: return '2nd' | ||
| 87 | if n == 3: return '3rd' | ||
| 88 | return '%dth' % n | ||
| 89 | |||
| 90 | def mkdate((year, month, day)): | ||
| 91 | # Januari 1st, in 0 A.D. is arbitrarily defined to be day 1, | ||
| 92 | # even though that day never actually existed and the calendar | ||
| 93 | # was different then... | ||
| 94 | days = year*365 # years, roughly | ||
| 95 | days = days + (year+3)/4 # plus leap years, roughly | ||
| 96 | days = days - (year+99)/100 # minus non-leap years every century | ||
| 97 | days = days + (year+399)/400 # plus leap years every 4 centirues | ||
| 98 | for i in range(1, month): | ||
| 99 | if i == 2 and calendar.isleap(year): | ||
| 100 | days = days + 29 | ||
| 101 | else: | ||
| 102 | days = days + calendar.mdays[i] | ||
| 103 | days = days + day | ||
| 104 | return days | ||
| 105 | |||
| 106 | if __name__ == "__main__": | ||
| 107 | main() | ||
| @@ -0,0 +1,92 @@ | |||
| 1 | #! /usr/bin/env python | ||
| 2 | |||
| 3 | # Update a bunch of files according to a script. | ||
| 4 | # The input file contains lines of the form <filename>:<lineno>:<text>, | ||
| 5 | # meaning that the given line of the given file is to be replaced | ||
| 6 | # by the given text. This is useful for performing global substitutions | ||
| 7 | # on grep output: | ||
| 8 | |||
| 9 | import os | ||
| 10 | import sys | ||
| 11 | import re | ||
| 12 | |||
| 13 | pat = '^([^: \t\n]+):([1-9][0-9]*):' | ||
| 14 | prog = re.compile(pat) | ||
| 15 | |||
| 16 | class FileObj: | ||
| 17 | def __init__(self, filename): | ||
| 18 | self.filename = filename | ||
| 19 | self.changed = 0 | ||
| 20 | try: | ||
| 21 | self.lines = open(filename, 'r').readlines() | ||
| 22 | except IOError, msg: | ||
| 23 | print '*** Can\'t open "%s":' % filename, msg | ||
| 24 | self.lines = None | ||
| 25 | return | ||
| 26 | print 'diffing', self.filename | ||
| 27 | |||
| 28 | def finish(self): | ||
| 29 | if not self.changed: | ||
| 30 | print 'no changes to', self.filename | ||
| 31 | return | ||
| 32 | try: | ||
| 33 | os.rename(self.filename, self.filename + '~') | ||
| 34 | fp = open(self.filename, 'w') | ||
| 35 | except (os.error, IOError), msg: | ||
| 36 | print '*** Can\'t rewrite "%s":' % self.filename, msg | ||
| 37 | return | ||
| 38 | print 'writing', self.filename | ||
| 39 | for line in self.lines: | ||
| 40 | fp.write(line) | ||
| 41 | fp.close() | ||
| 42 | self.changed = 0 | ||
| 43 | |||
| 44 | def process(self, lineno, rest): | ||
| 45 | if self.lines is None: | ||
| 46 | print '(not processed): %s:%s:%s' % ( | ||
| 47 | self.filename, lineno, rest), | ||
| 48 | return | ||
| 49 | i = eval(lineno) - 1 | ||
| 50 | if not 0 <= i < len(self.lines): | ||
| 51 | print '*** Line number out of range: %s:%s:%s' % ( | ||
| 52 | self.filename, lineno, rest), | ||
| 53 | return | ||
| 54 | if self.lines[i] == rest: | ||
| 55 | print '(no change): %s:%s:%s' % ( | ||
| 56 | self.filename, lineno, rest), | ||
| 57 | return | ||
| 58 | if not self.changed: | ||
| 59 | self.changed = 1 | ||
| 60 | print '%sc%s' % (lineno, lineno) | ||
| 61 | print '<', self.lines[i], | ||
| 62 | print '---' | ||
| 63 | self.lines[i] = rest | ||
| 64 | print '>', self.lines[i], | ||
| 65 | |||
| 66 | def main(): | ||
| 67 | if sys.argv[1:]: | ||
| 68 | try: | ||
| 69 | fp = open(sys.argv[1], 'r') | ||
| 70 | except IOError, msg: | ||
| 71 | print 'Can\'t open "%s":' % sys.argv[1], msg | ||
| 72 | sys.exit(1) | ||
| 73 | else: | ||
| 74 | fp = sys.stdin | ||
| 75 | curfile = None | ||
| 76 | while 1: | ||
| 77 | line = fp.readline() | ||
| 78 | if not line: | ||
| 79 | if curfile: curfile.finish() | ||
| 80 | break | ||
| 81 | n = prog.match(line) | ||
| 82 | if n < 0: | ||
| 83 | print 'Funny line:', line, | ||
| 84 | continue | ||
| 85 | filename, lineno = prog.group(1, 2) | ||
| 86 | if not curfile or filename <> curfile.filename: | ||
| 87 | if curfile: curfile.finish() | ||
| 88 | curfile = FileObj(filename) | ||
| 89 | curfile.process(lineno, line[n:]) | ||
| 90 | |||
| 91 | if __name__ == "__main__": | ||
| 92 | main() | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | # This is here so I can use 'wh' instead of 'which' in '~/bin/generic_python' | ||
| 2 | import which | ||