Add sanitized scripts for public consumption.
authorDan White <dan@whiteaudio.com>
Thu, 3 Feb 2011 23:56:49 +0000 (17:56 -0600)
committerDan White <dan@whiteaudio.com>
Thu, 3 Feb 2011 23:56:49 +0000 (17:56 -0600)
19 files changed:
chrome [new file with mode: 0755]
cleanup-timesamples [new file with mode: 0755]
extblock [new file with mode: 0755]
findchips.sh [new file with mode: 0755]
getuntil.pl [new file with mode: 0755]
interleave.sh [new file with mode: 0755]
lcdoff [new file with mode: 0755]
note [new file with mode: 0755]
octopart.sh [new file with mode: 0755]
parent_has.sh [new file with mode: 0755]
sms [new file with mode: 0755]
sppp [new file with mode: 0755]
tag [new file with mode: 0755]
tdrec [new file with mode: 0755]
termcolors.sh [new file with mode: 0755]
texify [new file with mode: 0755]
textmail [new file with mode: 0755]
vimpager [new file with mode: 0755]
vwf2pwl.py [new file with mode: 0755]

diff --git a/chrome b/chrome
new file mode 100755 (executable)
index 0000000..be86e98
--- /dev/null
+++ b/chrome
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# run chromium / google-chrome on current display hack
+
+DISPDIR=$(echo $DISPLAY | awk -F. '{print $1}')
+exec google-chrome --user-data-dir=$HOME/.config/google-chrome/$DISPDIR $@
diff --git a/cleanup-timesamples b/cleanup-timesamples
new file mode 100755 (executable)
index 0000000..dd2763f
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# cleanup data from timeSampler,
+# removes null entries and sorts by time
+
+TMPFILE=$(tempfile)
+for f in $(ls -1 $HOME/.timeSampler.*); do
+    grep -v "null$" $f | sort > $TMPFILE
+    cp $TMPFILE $f
+done
+
+rm -f $TMPFILE
diff --git a/extblock b/extblock
new file mode 100755 (executable)
index 0000000..669c543
--- /dev/null
+++ b/extblock
@@ -0,0 +1,63 @@
+#!/usr/bin/perl -w
+
+# usage: extblock infile rem_out spattern scount epattern ecount
+#
+# Dan White <dan@whiteaudio.com>
+
+# From infile, start copying the contents to stdout after finding spattern
+# scount times.  Once epattern has been found ecount times (typically 1), copy
+# the remaininder of infile to rem_out.
+
+# Originally written to iteratively pick out HSPICE listing output related to
+# .print statements, e.g.:
+#   extblock infile remfile "^x" 1 "^y" 1 > print_block.csv
+
+# There are better ways of doing this, probably with sed or awk, but I don't
+# know those languages.
+
+open(INFILE, $ARGV[0]) or die "Can't open file [ $ARGV[0] ] for reading.";
+open(OUTFILE, '>'.$ARGV[1]) or die "Can't open file [ $ARGV[1] ] for writing.";
+my $spattern=$ARGV[2];
+my $scount=$ARGV[3];
+my $epattern=$ARGV[4];
+my $ecount=$ARGV[5];
+
+my $sc=0;
+while(<INFILE>) { 
+    #find start pattern
+    if(/$spattern/) {
+        if($sc<$scount) {
+            $sc++;
+            next;
+        } else {
+            last;
+        }
+    }
+    next;
+}
+
+print;
+my $ec=1;
+while(<INFILE>) {
+    #find end pattern
+    if(/$epattern/) {
+        if($ec<$ecount) {
+            $ec++;
+            print;
+            next;
+        }
+        #this is the ending line target
+        print;
+        last;
+    }
+    print;
+}
+
+#copy rest of file to rem_file
+#including the previous last line!
+print OUTFILE;
+while(<INFILE>) {
+    print OUTFILE;
+}
+
+
diff --git a/findchips.sh b/findchips.sh
new file mode 100755 (executable)
index 0000000..4202899
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# dirty hack to quickly look for a chip by PN
+
+browser=${BROWSER:-"xdg-open"}
+encoded=$(echo "$1" | perl -MURI::Escape -lne 'print uri_escape($_)')
+$browser "http://www.findchips.com/avail?part=$encoded"
+
diff --git a/getuntil.pl b/getuntil.pl
new file mode 100755 (executable)
index 0000000..153c335
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/perl -w
+
+# getuntil infile start_pattern scount end_pattern ecount
+#   cat's file until it finds 'pattern' and exits
+
+if($ARGV[0] eq '-h') {
+    print "Usage:\n";
+    print "getuntil infile start_pattern scount end_pattern ecount\n";
+    exit(1);
+}
+
+$infile=$ARGV[0];
+$spattern=$ARGV[1];
+$scount=$ARGV[2];
+$epattern=$ARGV[3];
+$ecount=$ARGV[4];
+
+open(IFP, $infile);
+
+$sc=0;
+$ec=0;
+while(<IFP>){
+    if ($sc < $scount) {
+        if (/$spattern/) { $sc++; }
+        if ($sc == $scount) { print; }
+    } elsif ($ec < $ecount) {
+        #within start and end sections
+        if (/$epattern/) { $ec++; }
+        print;
+    } else {
+        last;
+    }
+}
+
+exit(0);
+
diff --git a/interleave.sh b/interleave.sh
new file mode 100755 (executable)
index 0000000..e87b5f6
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+# (C) Dan White <dan@whiteaudio.com>, GPL license
+
+VERBOSE=0
+
+function usage() {
+cat << EOF
+Usage: $0 [-o output.pdf] infile1.pdf [infile2.pdf [...]]
+
+Output a pdf whose pages are infile1:1, infile2:1 ... infile1:2, infile2:2
+The number of output pages is the length of the longest input file times the
+number of input files.
+EOF
+}
+
+letters=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
+declare -i nfiles=0
+declare -i maxpages=0
+outfile="output.pdf"
+while [ "$1" != "" ]; do
+    if [ "$1" == "-o" ]; then
+        #set name of output file to non-default value
+        outfile=$2
+        shift
+    elif [ "$1" == "-h" ]; then
+        usage
+        exit 1
+    else
+        infiles[$nfiles]=$1
+        npages[$nfiles]=$(pdftk $1 dump_data | tail -n1 | awk '{print $2}')
+        [[ npages[$nfiles] -gt $maxpages ]] && maxpages=${npages[$nfiles]}
+        let "nfiles=nfiles+1"
+        if [[ $nfiles -gt 26 ]]; then
+            echo "OOPS: can only handle 26 files to be interleaved presently"
+            exit 1
+        fi
+    fi
+    shift
+done
+
+#show some info
+if [ $VERBOSE == 1 ]; then
+    #echo "letters: ${letters[*]}"
+    echo "infiles: ${infiles[*]}"
+    echo "npages: ${npages[*]}"
+    echo "maxpages: $maxpages"
+fi
+
+#do the deed
+#
+# there are nfiles circular buffers of pages of varying lengths, the number of
+# output pages is maxpages*nfiles.
+for i in $(seq 1 $maxpages); do
+    [[ $VERBOSE == 1 ]] && echo "page $i"
+    #assign each file a letter for referencing with pdftk
+    pre=""
+    #cat the appropriate page number of each file, looping through the shorter
+    #ones, to an aggregate collection of pages
+    post=""
+    for fnum in $(seq 0 $(($nfiles -1)) ); do
+        pre="$pre ${letters[$fnum]}=${infiles[$fnum]}"
+        post="$post ${letters[$fnum]}$((i % npages[$fnum] +1))"
+    done
+    pdftk $pre cat $post output $outfile-p$i.pdf
+done
+
+#cat all the aggregations together into the final page stream
+echo "putting all together"
+pdftk $outfile-p*.pdf cat output $outfile
+rm -f $outfile-p*.pdf
+
diff --git a/lcdoff b/lcdoff
new file mode 100755 (executable)
index 0000000..2a01805
--- /dev/null
+++ b/lcdoff
@@ -0,0 +1,2 @@
+#!/bin/bash
+xset dpms force off
diff --git a/note b/note
new file mode 100755 (executable)
index 0000000..fd81e9a
--- /dev/null
+++ b/note
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+if [ "$1" == "-h" ]; then
+    echo "Quick note taking function"
+    echo "Usage: note [-h] [-f otherFile] [- | note string]"
+    echo "-f file   Append note to FILE instead"
+    echo "other arguments are appended to \$NOTES_FILE environment variable"
+    echo "if no arguments, edit note file directly"
+    exit 1
+fi
+
+#TIMESTAMP=`date`
+TIMESTAMP=`date +"%F %k:%M:%S"`
+
+# export to a different note file
+if [ "$1" == "-f" ]; then
+    NOTES_FILE=$2
+    shift 2
+    echo "using file: $NOTES_FILE" >&2
+fi
+
+# create the time-stamped note
+cat << END_NOTE_TEXT >> $NOTES_FILE
+
+$TIMESTAMP
+----------------------------------------
+END_NOTE_TEXT
+
+#text is from stdin
+if [ "$1" == "-" ]; then
+    cat >> $NOTES_FILE
+else
+    echo $* >> $NOTES_FILE
+fi
+
+# edit the note if no (remaining) arguments
+if [ $# -eq 0 ]; then
+    $EDITOR + $NOTES_FILE
+fi
+
diff --git a/octopart.sh b/octopart.sh
new file mode 100755 (executable)
index 0000000..ade00b1
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+browser=${BROWSER:-"xdg-open"}
+
+encoded=$(echo "$1" | perl -MURI::Escape -lne 'print uri_escape($_)')
+echo $encoded
+
+$browser "http://octopart.com/parts/search?q=$encoded&js=on"
+
diff --git a/parent_has.sh b/parent_has.sh
new file mode 100755 (executable)
index 0000000..27ea180
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Dan White <dan@whiteaudio.com>
+
+function parent_has {
+# $1 - file/folder to look for in pwd and parents
+    if [ -e $1 ]; then
+        return 0
+    elif [ $PWD == "/" ]; then
+        return 1
+    fi
+
+    cd $(dirname $PWD)
+    parent_has "$1"
+}
+
+parent_has "$1"
+
diff --git a/sms b/sms
new file mode 100755 (executable)
index 0000000..58507b4
--- /dev/null
+++ b/sms
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Dan White <dan@whiteaudio.com>
+
+SMSTO=${SMSTO:-"dansms"}
+
+function usage {
+cat << EOF
+Usage: sms "subject" [filename | -]
+
+send the contents of stdin or 'filename' to \$SMSTO ($SMSTO)
+EOF
+}
+
+if [[ $# -eq 0 ]] || [[ $1 == "-h" ]] ; then
+    usage
+    exit 1
+fi
+
+SUBJECT=$1
+
+if [ -r "$2" ]; then
+    cat "$2" | email -s "$SUBJECT" $SMSTO
+else
+    email -b -s "$SUBJECT" $SMSTO
+fi
diff --git a/sppp b/sppp
new file mode 100755 (executable)
index 0000000..c553175
--- /dev/null
+++ b/sppp
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# preprocessor for spice files
+# lines start with "**" to trigger the parser
+# Example
+#   *spice netlist title
+#   **ifdef GNUCAP
+#
+#   *gnucap specific stuff
+#
+#   **else
+#
+#   *hspice specific stuff
+#
+#   **endif
+#   .end
+#
+gpp -U "" "" "(" "," ")" "(" ")" "#" "\\" \
+    -M "**" "\n" " " " " "\n" "(" ")" $@
+
diff --git a/tag b/tag
new file mode 100755 (executable)
index 0000000..9e5d288
--- /dev/null
+++ b/tag
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+# Dan White <dan@whiteaudio.com>
+
+"""Recurse from current or given directory and display all folders with
+tags."""
+
+import optparse
+import os
+import sys
+import re
+
+try:
+    import cStringIO as StringIO
+except ImportError:
+    import StringIO
+
+try:
+    import optcomplete
+except ImportError:
+    optcomplete = None
+
+#ignore tmp and hidden folders
+RE_DO_NOT_FOLLOW_DIR = re.compile(r'^tmp$|^\.')
+
+#tag prefix, these must match
+TAG_PREFIX = '.tag.'
+#RE_TAG = re.compile(r'^\.tag')
+RE_TAG = re.compile(r'^' + TAG_PREFIX.replace('.', '\.'))
+
+#
+# Options
+#
+optParser = optparse.OptionParser()
+optParser.add_option('-a', '--add', dest='add', action='store', type='string',
+                     help='add TAG to folder', metavar='TAG')
+
+optParser.add_option('-d', '--delete', dest='delete', action='store',
+                     type='string',
+                     help='remove TAG from folder', metavar='TAG')
+
+optParser.add_option('-l', '--list', dest='list', action='store_true',
+                     default=False,
+                     help="list tags in all folders which have them")
+
+optParser.add_option('-t', '--tag', dest='tag', action='store', type='string',
+                     help='list folders which have given comma-sep tag(s)')
+
+optParser.add_option('-r', '--recurse', dest='recurse', action='store_true',
+                     default=False,
+                     help='recurse into child folders')
+
+optParser.add_option('-R', '--no-recurse', dest='recurse', action='store_false',
+                     help='do not recurse into child folders (default)')
+
+_cwd = os.getcwd()
+_HOME = os.getenv('HOME')
+
+def herePath(p, base=None):
+    '''Return the given path relative to base'''
+    if base:
+        return p.replace(base,'.')
+    else:
+        return p
+
+
+def listTags(baseDir):
+    files = os.listdir(baseDir)
+    tags = [t.replace(TAG_PREFIX, '') for t in files if RE_TAG.match(t)]
+    tags.sort()
+    return tags
+
+
+def findTag(tag, baseDir):
+    s = StringIO.StringIO()
+    for (path, dirs, files) in os.walk(baseDir):
+        dirs[:] = [d for d in dirs if not RE_DO_NOT_FOLLOW_DIR.match(d)]
+        tags = [t.replace(TAG_PREFIX, '') for t in files if t.startswith(TAG_PREFIX)]
+        if tag in tags:
+            print>>s, path
+    return s.getvalue().rstrip()
+
+
+def addTag(tag, baseDir):
+    try:
+        open(baseDir + '/' + TAG_PREFIX + tag, 'r')
+        print "ee's already got one (%s)" % tag
+    except IOError:
+        t = open(baseDir + '/' + TAG_PREFIX + tag, 'w')
+        t.close()
+
+
+def deleteTag(tag, baseDir):
+    try:
+        os.remove(baseDir + '/' + TAG_PREFIX + tag)
+    except OSError:
+        print 'tag already not present (%s)' % tag
+
+
+
+def main():
+    if optcomplete:
+        optcomplete.autocomplete(optParser)
+
+    (opt, args) = optParser.parse_args()
+    arglen = len(args)
+    #print opt
+    #print args
+
+    taglist = []
+    if arglen == 0:
+        walkDir = _cwd
+    elif arglen == 1:
+        walkDir = os.path.expandvars(os.path.expanduser(args[0]))
+        walkDir = walkDir.rstrip(os.sep)
+    elif arglen >=2:
+        walkDir = os.path.expandvars(os.path.expanduser(args[0]))
+        walkDir = walkDir.rstrip(os.sep)
+        taglist = args[1:]
+
+    if opt.list:
+        if opt.recurse:
+            alltags = {}
+            for (path, dirs, files) in os.walk(walkDir):
+                dirs[:] = [d for d in dirs if not RE_DO_NOT_FOLLOW_DIR.match(d)]
+                tags = [t.replace(TAG_PREFIX,'') for t in files
+                        if RE_TAG.match(t)]
+                tags.sort()
+                if tags:
+                    for t in tags:
+                        if t in alltags:
+                            alltags[t].append(path)
+                        else:
+                            alltags[t] = [path]
+                    print '%s:' % herePath(path, walkDir)
+                    print '\n'.join(tags)
+            #usedtags = alltags.keys()
+            #usedtags.sort()
+            #print
+            #print 'tags defined at:'
+            #for t in usedtags:
+                #print '%s:' % t
+                #print '\n'.join(alltags[t])
+        else:
+            print '\n'.join(listTags(walkDir))
+    elif opt.tag:
+        for t in opt.tag.split(',') + taglist:
+            print 'adding', t
+            print findTag(t, walkDir)
+    elif opt.add:
+        for t in opt.add.split(',') + taglist:
+            print 'adding', t
+            addTag(t, walkDir)
+    elif opt.delete:
+        for t in opt.delete.split(','):
+            deleteTag(t, walkDir)
+
+if __name__ == '__main__':
+    main()
+
diff --git a/tdrec b/tdrec
new file mode 100755 (executable)
index 0000000..5e69327
--- /dev/null
+++ b/tdrec
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+# recursive todo - runs todo in all sub-directories which have a todo list in
+# them and only displays if there is actual output
+#
+# Dan White <dan@whiteaudio.com>
+# idea from Bash version by Brian Herlihy
+#
+
+import re
+import os
+import subprocess
+import sys
+
+#
+# semi-volatile options
+#
+
+#replaced with path to current .todo
+#HEADER_STRING = 'TODO %s' 
+HEADER_STRING = '\n=== %s ===' 
+
+#--force-colour necessary to keep color information
+DEFAULT_DEVTODO_OPTIONS = '--force-colour --filter -children'
+
+#do not recurse into these directories
+DO_NOT_FOLLOW_DIR_RE = re.compile(r'^tmp$|^\.|^Mail$')
+
+#re for finding the final newline from todo output immediately before
+#the final terminal color-changing code string
+LAST_NL_RE = re.compile(r'(\n)(\033\[0m$)')
+
+usage = '''\
+Usage: %s [devtodo options]
+Recursively displays devtodo .todo databases from the current directory.
+Default options are: %s '''
+
+#
+# display usage, pass options to devtodo, or use default options
+#
+if sys.argv[1:]:
+    #help if requested
+    if sys.argv[1] == '-h' or sys.argv[1] == '--help':
+        print usage % (os.path.basename(sys.argv[0]), DEFAULT_DEVTODO_OPTIONS)
+        sys.exit()
+    DEVTODO_OPTIONS = '--force-colour ' + ' '.join(sys.argv[1:])
+else:
+    DEVTODO_OPTIONS = DEFAULT_DEVTODO_OPTIONS
+
+DEVTODO_COMMAND = 'todo --database %s/.todo ' + DEVTODO_OPTIONS
+
+#
+# real functionality
+#
+def herePath(p, base=None):
+    '''Return the given path relative to base'''
+    if base:
+        return p.replace(base,'').lstrip('/')
+    else:
+        return p
+
+cwd = os.getcwd()
+for (dpath, dnames, fnames) in os.walk(cwd):
+    dnames[:] = [d for d in dnames if not DO_NOT_FOLLOW_DIR_RE.match(d)]
+    if '.todo' in fnames:
+        #f = os.popen(DEVTODO_COMMAND % dpath, 'r')
+        f = subprocess.Popen(DEVTODO_COMMAND % dpath, shell=True,
+                             stdout=subprocess.PIPE).stdout
+        todoOutput = f.read()
+        if todoOutput:
+            print HEADER_STRING % herePath(dpath, cwd)
+            print LAST_NL_RE.sub('\g<2>', todoOutput)
+
diff --git a/termcolors.sh b/termcolors.sh
new file mode 100755 (executable)
index 0000000..e15d528
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# from http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
+
+#
+#   This file echoes a bunch of color codes to the 
+#   terminal to demonstrate what's available.  Each 
+#   line is the color code of one forground color,
+#   out of 17 (default + 16 escapes), followed by a 
+#   test use of that color on all nine background 
+#   colors (default + 8 escapes).
+#
+
+T='gYw'   # The test text
+
+echo -e "\n                 40m     41m     42m     43m\
+     44m     45m     46m     47m";
+
+for FGs in '    m' '   1m' '  30m' '1;30m' '  31m' '1;31m' '  32m' \
+           '1;32m' '  33m' '1;33m' '  34m' '1;34m' '  35m' '1;35m' \
+           '  36m' '1;36m' '  37m' '1;37m';
+  do FG=${FGs// /}
+  echo -en " $FGs \033[$FG  $T  "
+  for BG in 40m 41m 42m 43m 44m 45m 46m 47m;
+    do echo -en "$EINS \033[$FG\033[$BG  $T  \033[0m";
+  done
+  echo;
+done
+echo
diff --git a/texify b/texify
new file mode 100755 (executable)
index 0000000..f34a7e7
--- /dev/null
+++ b/texify
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# texify [options] file.tex
+#   Runs latex on file, runs again if necessary.
+# outputs warnings and errors
+
+# 'rubber' works better...
+
+
+CLEAN=0
+if [ "$1" == "-c" ]; then
+    shift
+    CLEAN=1
+fi
+
+tmpfile=tmp`date +%F-%H%M%S`
+
+echo "Rerun" > $tmpfile
+while grep -q "Rerun\|exist, replaced" $tmpfile; do
+    #run LaTeX and catch output
+    echo -n "texify: running LaTeX..."
+    #latex -interaction=nonstopmode --output-format=pdf $* > $tmpfile
+    pdflatex -interaction nonstopmode \
+             -output-format pdf \
+             -halt-on-error \
+             $@ > $tmpfile
+    echo "done"
+
+    #quit on error
+    if grep -A4 "^!" $tmpfile; then
+        if grep "pdfTeX warning" $tmpfile; then
+            continue;
+        else
+            rm $tmpfile;
+            exit 1;
+        fi
+    fi
+done
+
+#only print warnings, if any
+grep -A1 Warning $tmpfile
+
+rm $tmpfile
+if [ $CLEAN -eq 1 ]; then
+    rm *.out *.toc *.aux *.log
+fi
+
diff --git a/textmail b/textmail
new file mode 100755 (executable)
index 0000000..ba81260
--- /dev/null
+++ b/textmail
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+MYSELF='dan'
+
+function usage {
+cat << EOF
+Usage: textmail 'subject' [filename]
+
+send the contents of stdin or 'filename' to \$MAILTO ($MAILTO)
+EOF
+}
+
+if [ $# -eq 0 ] || [ $1 == "-h" ]; then
+    usage
+    exit 1
+fi
+
+SUBJECT=$1
+MAILCMD="email -s $SUBJECT $MYSELF"
+MAILCMD="email -s $SUBJECT $MAILTO"
+
+if [ "$2" == "" ]; then
+    cat - | $MAILCMD
+else
+    cat $2 | $MAILCMD
+fi
diff --git a/vimpager b/vimpager
new file mode 100755 (executable)
index 0000000..35f64d1
--- /dev/null
+++ b/vimpager
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Shell script to start Vim with less.vim.
+# Read stdin if no arguments were given.
+
+files=$@
+if [ -z "$files" ]; then files="-"; fi
+
+less_vim() {
+       vim -R -c 'let no_plugin_maps = 1' \
+           -c 'runtime! macros/less.vim' \
+           -c 'set mouse=h' "$@"
+}
+
+do_ps() {
+       ps fauxw
+}
+
+pproc() {
+       if uname -s | grep -iq linux; then
+               ps -p $1 -o comm=
+       elif uname -s | grep -iq cygwin; then
+               ps -p $1 | sed -e 's/^I/ /' | grep -v PID
+       fi
+}
+
+ppid() {
+       if uname -s | grep -iq linux; then
+               ps -p $1 -o ppid=
+       elif uname -s | grep -iq cygwin; then
+               ps -p $1 | sed -e 's/^I/ /' | grep -v PID | awk '{print $2}'
+       fi
+}
+
+# Check if called from man or perldoc
+MAN_LIKE_PROGS="man\|pydoc\>\|ipython\|python"
+if do_ps | grep -q '\(man\|perl\|py\(doc\|thon\)\)\>'; then
+       proc=$$
+       while next_parent=`ppid $proc` && [ $next_parent != 1 ]; do
+        #echo `pproc $next_parent`
+               #if pproc $next_parent | grep -q 'man\|pydoc\>'; then
+               if pproc $next_parent | grep -q $MAN_LIKE_PROGS; then
+            #echo "found man-like-prog"
+                       perl -pi -e 's/\e\[[^m]*m//g' | col -b \
+                | less_vim -c 'set ft=man' -; exit
+            #less_vim -c 'set ft=man' -; exit
+        elif pproc $next_parent | grep -q 'perl\(doc\|$\)\>'; then
+            perl -pi -e 's/\e\[[^m]*m//g' | col -b \
+                | less_vim -c 'set ft=man' -; exit
+                       #col -b < $files | less_vim -c "set ft=man" -; exit
+               fi
+               proc=$next_parent
+       done
+fi
+
+#echo "not man-like"
+less_vim $files
diff --git a/vwf2pwl.py b/vwf2pwl.py
new file mode 100755 (executable)
index 0000000..c90ec80
--- /dev/null
@@ -0,0 +1,224 @@
+#!/usr/bin/python
+
+# Dan White <dan@whiteaudio.com>
+
+import os
+import sys
+import re
+
+from decimal import Decimal
+
+try:
+    import psyco
+    psyco.full()
+except ImportError:
+    pass
+
+def usage():
+    print >>sys.stderr, '''
+Usage: vwf2pwl.py digitalinputs.vwf
+
+vwf file format:
+    [one name=value parameter per line]
+    [space-separated column labels for voltage source names AND node names]
+    [one line per bit interval of 0 or 1 for each column, no spaces between]
+
+Example .vwf contents for testing an adder:
+    clockdelay=500p
+    clockrisefall = 100p
+    risefall=200p
+    bittime=1n
+    bitlow=0
+    bithigh=5
+    a3 a2 a1 a0 b3 b2 b1 b0
+    00000000
+    00010001
+    00010010
+    11111111
+    01011010
+    01011011
+
+Include the generated file, which also includes the Voltage-source definitons
+for the input nodes as:
+    .include "foo.pwl"
+
+The "clockdelay=" parameter, if present, also generates a voltage source for a
+clock as "Vclock clock 0 PWL ..." with a rising edge at every bittime with an
+offset of clockdelay.  Hence, set "clockdelay=" to the maximum setup time of
+your registers and the data on each line will be clocked in at the right time.
+Parameter "clockrisefall=" is optional to separately specify the clock rise/
+fall time.
+'''
+
+
+def info(s):
+    print 'INFO:', s
+
+
+def error(s):
+    print 'ERROR:', s
+    sys.exit(1)
+
+
+def warn(s):
+    print 'WARNING:', s
+
+
+def mkvwf(d):
+    t = Decimal('0.0')
+
+    #first bit interval starts at t=0, start from this value
+    lastbit = d[0]
+    bitv = Decimal(lastbit) * (bithigh - bitlow) + bitlow
+    s = '+ 0 %s' % str(bitv)
+    output(s)
+
+    trf = risefall
+    tb = bittime - risefall
+    t += trf + tb
+    for bit in d[1:]:
+        if bit != lastbit:
+            ti = t + trf
+            tf = ti + tb
+            lastbitv = Decimal(lastbit) * (bithigh - bitlow) + bitlow
+            bitv = Decimal(bit) * (bithigh - bitlow) + bitlow
+            output('+ %s %s' % (str(t), str(lastbitv)))
+            output('+ %s %s' % (str(ti), str(bitv)))
+            #output('+ %s %s' % (str(tf), str(bitv)))
+        
+        t += trf + tb
+        lastbit = bit
+
+
+RE_UNIT = re.compile(r'^([0-9e\+\-\.]+)(t|g|meg|x|k|mil|m|u|n|p|f)?')
+def unit(s):
+    """Takes a string and returns the equivalent float.
+    '3.0u' -> 3.0e-6"""
+    mult = {'t'  :Decimal('1.0e12'),
+            'g'  :Decimal('1.0e9'),
+            'meg':Decimal('1.0e6'),
+            'x'  :Decimal('1.0e6'),
+            'k'  :Decimal('1.0e3'),
+            'mil':Decimal('25.4e-6'),
+            'm'  :Decimal('1.0e-3'),
+            'u'  :Decimal('1.0e-6'),
+            'n'  :Decimal('1.0e-9'),
+            'p'  :Decimal('1.0e-12'),
+            'f'  :Decimal('1.0e-15')}
+
+    m = RE_UNIT.search(s.lower())
+    try:
+        if m.group(2):
+            return Decimal(Decimal(m.group(1)))*mult[m.group(2)]
+        else:
+            return Decimal(m.group(1))
+    except:
+        error("Bad unit: %s" % s)
+
+
+
+if len(sys.argv) < 2:
+    usage()
+    sys.exit(1)
+
+vwf = sys.argv[1]
+if not vwf.endswith('.vwf'):
+    usage()
+    print "Error: File must have a .vwf extension"
+    sys.exit(1)
+
+pwl = vwf.replace('.vwf', '.pwl')
+
+fvwf = open(vwf)
+fpwl = open(pwl, 'w')
+
+
+#read in the vwf definition file
+
+#get parameters
+requiredParams = ('risefall', 'bittime', 'bitlow', 'bithigh')
+params = {'clockdelay':None, 'clockrisefall':None}
+
+line = fvwf.readline()
+while '=' in line:
+    name, value = line.split('=')
+    name = name.strip()
+    value = value.strip()
+    params[name] = value
+    line = fvwf.readline()
+
+#check
+for p in requiredParams:
+    if p not in params:
+        error("%s is not specified, aborting." % p)
+
+info('Parameters:')
+for p,v in params.iteritems():
+    info('  %s = %s' % (p, v))
+
+if params['clockdelay']:
+    info("Adding a clock at 'clock' node.")
+
+#get column labels
+inputs = [c.strip() for c in line.strip().split()]
+info("Columns: %s" % inputs)
+
+#read in data
+data = {}
+for i in inputs:
+    data[i] = []
+
+for line in fvwf:
+    vector = line.strip()
+    if len(vector) != len(inputs):
+        error("Must have same # characters as column labels: %s" % line.strip())
+
+    i = 0
+    for bit in vector:
+        data[inputs[i]].append(bit)
+        i += 1
+
+#outputs
+output = lambda s: fpwl.write(s + '\n')
+
+#get the numbers
+risefall = unit(params['risefall'])
+bittime = unit(params['bittime'])
+bitlow = unit(params['bitlow'])
+bithigh = unit(params['bithigh'])
+
+#output clock definition if specified
+if params['clockdelay']:
+    #calculate clock high time
+    if params['clockrisefall']:
+        clockrisefall = unit(params['clockrisefall'])
+    else:
+        clockrisefall = risefall
+
+    clockhigh = Decimal('0.5') * (bittime - clockrisefall)
+    clockperiod = bittime
+
+    params['clockrisefall'] = str(clockrisefall)
+    params['clockhigh'] = str(clockhigh)
+    params['clockperiod'] = str(clockperiod)
+
+    clk = 'Vclock clock 0 pulse(%(bitlow)s %(bithigh)s %(clockdelay)s %(clockrisefall)s %(clockrisefall)s %(clockhigh)s %(clockperiod)s)' % params
+    info(clk)
+    output(clk)
+    output('')
+
+#output each input source
+for name in inputs:
+    d = data[name]
+    
+    s = 'V%s %s 0 PWL' % (name, name)
+    info(s)
+    output(s)
+
+    #first bit interval starts at t=0, start from this value
+    bit = d[0]
+    bitv = Decimal(bit) * (bithigh - bitlow) + bitlow
+
+    mkvwf(d)
+    output('')
+