summaryrefslogtreecommitdiff
path: root/lemon/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'lemon/scripts')
-rw-r--r--lemon/scripts/Makefile.am7
-rwxr-xr-xlemon/scripts/bib2dox.py816
-rwxr-xr-xlemon/scripts/bootstrap.sh157
-rwxr-xr-xlemon/scripts/chg-len.py46
-rwxr-xr-xlemon/scripts/mk-release.sh49
-rwxr-xr-xlemon/scripts/unify-sources.sh390
-rwxr-xr-xlemon/scripts/valgrind-wrapper.sh22
7 files changed, 1487 insertions, 0 deletions
diff --git a/lemon/scripts/Makefile.am b/lemon/scripts/Makefile.am
new file mode 100644
index 0000000..ede305d
--- /dev/null
+++ b/lemon/scripts/Makefile.am
@@ -0,0 +1,7 @@
+EXTRA_DIST += \
+ scripts/bib2dox.py \
+ scripts/bootstrap.sh \
+ scripts/chg-len.py \
+ scripts/mk-release.sh \
+ scripts/unify-sources.sh \
+ scripts/valgrind-wrapper.sh
diff --git a/lemon/scripts/bib2dox.py b/lemon/scripts/bib2dox.py
new file mode 100755
index 0000000..0284a3e
--- /dev/null
+++ b/lemon/scripts/bib2dox.py
@@ -0,0 +1,816 @@
+#! /usr/bin/env python
+"""
+ BibTeX to Doxygen converter
+ Usage: python bib2dox.py bibfile.bib > bibfile.dox
+
+ This file is a part of LEMON, a generic C++ optimization library.
+
+ **********************************************************************
+
+ This code is the modification of the BibTeX to XML converter
+ by Vidar Bronken Gundersen et al.
+ See the original copyright notices below.
+
+ **********************************************************************
+
+ Decoder for bibliographic data, BibTeX
+ Usage: python bibtex2xml.py bibfile.bib > bibfile.xml
+
+ v.8
+ (c)2002-06-23 Vidar Bronken Gundersen
+ http://bibtexml.sf.net/
+ Reuse approved as long as this notification is kept.
+ Licence: GPL.
+
+ Contributions/thanks to:
+ Egon Willighagen, http://sf.net/projects/jreferences/
+ Richard Mahoney (for providing a test case)
+
+ Editted by Sara Sprenkle to be more robust and handle more bibtex features.
+ (c) 2003-01-15
+
+ 1. Changed bibtex: tags to bibxml: tags.
+ 2. Use xmlns:bibxml="http://bibtexml.sf.net/"
+ 3. Allow spaces between @type and first {
+ 4. "author" fields with multiple authors split by " and "
+ are put in separate xml "bibxml:author" tags.
+ 5. Option for Titles: words are capitalized
+ only if first letter in title or capitalized inside braces
+ 6. Removes braces from within field values
+ 7. Ignores comments in bibtex file (including @comment{ or % )
+ 8. Replaces some special latex tags, e.g., replaces ~ with ' '
+ 9. Handles bibtex @string abbreviations
+ --> includes bibtex's default abbreviations for months
+ --> does concatenation of abbr # " more " and " more " # abbr
+ 10. Handles @type( ... ) or @type{ ... }
+ 11. The keywords field is split on , or ; and put into separate xml
+ "bibxml:keywords" tags
+ 12. Ignores @preamble
+
+ Known Limitations
+ 1. Does not transform Latex encoding like math mode and special
+ latex symbols.
+ 2. Does not parse author fields into first and last names.
+ E.g., It does not do anything special to an author whose name is
+ in the form LAST_NAME, FIRST_NAME
+ In "author" tag, will show up as
+ <bibxml:author>LAST_NAME, FIRST_NAME</bibxml:author>
+ 3. Does not handle "crossref" fields other than to print
+ <bibxml:crossref>...</bibxml:crossref>
+ 4. Does not inform user of the input's format errors. You just won't
+ be able to transform the file later with XSL
+
+ You will have to manually edit the XML output if you need to handle
+ these (and unknown) limitations.
+
+"""
+
+import string, re
+
+# set of valid name characters
+valid_name_chars = '[\w\-:]'
+
+#
+# define global regular expression variables
+#
+author_rex = re.compile('\s+and\s+')
+rembraces_rex = re.compile('[{}]')
+capitalize_rex = re.compile('({[^}]*})')
+
+# used by bibtexkeywords(data)
+keywords_rex = re.compile('[,;]')
+
+# used by concat_line(line)
+concatsplit_rex = re.compile('\s*#\s*')
+
+# split on {, }, or " in verify_out_of_braces
+delimiter_rex = re.compile('([{}"])',re.I)
+
+field_rex = re.compile('\s*(\w*)\s*=\s*(.*)')
+data_rex = re.compile('\s*(\w*)\s*=\s*([^,]*),?')
+
+url_rex = re.compile('\\\url\{([^}]*)\}')
+
+#
+# styles for html formatting
+#
+divstyle = 'margin-top: -4ex; margin-left: 8em;'
+
+#
+# return the string parameter without braces
+#
+def transformurls(str):
+ return url_rex.sub(r'<a href="\1">\1</a>', str)
+
+#
+# return the string parameter without braces
+#
+def removebraces(str):
+ return rembraces_rex.sub('', str)
+
+#
+# latex-specific replacements
+# (do this after braces were removed)
+#
+def latexreplacements(line):
+ line = string.replace(line, '~', '&nbsp;')
+ line = string.replace(line, '\\\'a', '&aacute;')
+ line = string.replace(line, '\\"a', '&auml;')
+ line = string.replace(line, '\\\'e', '&eacute;')
+ line = string.replace(line, '\\"e', '&euml;')
+ line = string.replace(line, '\\\'i', '&iacute;')
+ line = string.replace(line, '\\"i', '&iuml;')
+ line = string.replace(line, '\\\'o', '&oacute;')
+ line = string.replace(line, '\\"o', '&ouml;')
+ line = string.replace(line, '\\\'u', '&uacute;')
+ line = string.replace(line, '\\"u', '&uuml;')
+ line = string.replace(line, '\\H o', '&otilde;')
+ line = string.replace(line, '\\H u', '&uuml;') # &utilde; does not exist
+ line = string.replace(line, '\\\'A', '&Aacute;')
+ line = string.replace(line, '\\"A', '&Auml;')
+ line = string.replace(line, '\\\'E', '&Eacute;')
+ line = string.replace(line, '\\"E', '&Euml;')
+ line = string.replace(line, '\\\'I', '&Iacute;')
+ line = string.replace(line, '\\"I', '&Iuml;')
+ line = string.replace(line, '\\\'O', '&Oacute;')
+ line = string.replace(line, '\\"O', '&Ouml;')
+ line = string.replace(line, '\\\'U', '&Uacute;')
+ line = string.replace(line, '\\"U', '&Uuml;')
+ line = string.replace(line, '\\H O', '&Otilde;')
+ line = string.replace(line, '\\H U', '&Uuml;') # &Utilde; does not exist
+
+ return line
+
+#
+# copy characters form a string decoding html expressions (&xyz;)
+#
+def copychars(str, ifrom, count):
+ result = ''
+ i = ifrom
+ c = 0
+ html_spec = False
+ while (i < len(str)) and (c < count):
+ if str[i] == '&':
+ html_spec = True;
+ if i+1 < len(str):
+ result += str[i+1]
+ c += 1
+ i += 2
+ else:
+ if not html_spec:
+ if ((str[i] >= 'A') and (str[i] <= 'Z')) or \
+ ((str[i] >= 'a') and (str[i] <= 'z')):
+ result += str[i]
+ c += 1
+ elif str[i] == ';':
+ html_spec = False;
+ i += 1
+
+ return result
+
+
+#
+# Handle a list of authors (separated by 'and').
+# It gives back an array of the follwing values:
+# - num: the number of authors,
+# - list: the list of the author names,
+# - text: the bibtex text (separated by commas and/or 'and')
+# - abbrev: abbreviation that can be used for indicate the
+# bibliography entries
+#
+def bibtexauthor(data):
+ result = {}
+ bibtex = ''
+ result['list'] = author_rex.split(data)
+ result['num'] = len(result['list'])
+ for i, author in enumerate(result['list']):
+ # general transformations
+ author = latexreplacements(removebraces(author.strip()))
+ # transform "Xyz, A. B." to "A. B. Xyz"
+ pos = author.find(',')
+ if pos != -1:
+ author = author[pos+1:].strip() + ' ' + author[:pos].strip()
+ result['list'][i] = author
+ bibtex += author + '#'
+ bibtex = bibtex[:-1]
+ if result['num'] > 1:
+ ix = bibtex.rfind('#')
+ if result['num'] == 2:
+ bibtex = bibtex[:ix] + ' and ' + bibtex[ix+1:]
+ else:
+ bibtex = bibtex[:ix] + ', and ' + bibtex[ix+1:]
+ bibtex = bibtex.replace('#', ', ')
+ result['text'] = bibtex
+
+ result['abbrev'] = ''
+ for author in result['list']:
+ pos = author.rfind(' ') + 1
+ count = 1
+ if result['num'] == 1:
+ count = 3
+ result['abbrev'] += copychars(author, pos, count)
+
+ return result
+
+
+#
+# data = title string
+# @return the capitalized title (first letter is capitalized), rest are capitalized
+# only if capitalized inside braces
+#
+def capitalizetitle(data):
+ title_list = capitalize_rex.split(data)
+ title = ''
+ count = 0
+ for phrase in title_list:
+ check = string.lstrip(phrase)
+
+ # keep phrase's capitalization the same
+ if check.find('{') == 0:
+ title += removebraces(phrase)
+ else:
+ # first word --> capitalize first letter (after spaces)
+ if count == 0:
+ title += check.capitalize()
+ else:
+ title += phrase.lower()
+ count = count + 1
+
+ return title
+
+
+#
+# @return the bibtex for the title
+# @param data --> title string
+# braces are removed from title
+#
+def bibtextitle(data, entrytype):
+ if entrytype in ('book', 'inbook'):
+ title = removebraces(data.strip())
+ else:
+ title = removebraces(capitalizetitle(data.strip()))
+ bibtex = title
+ return bibtex
+
+
+#
+# function to compare entry lists
+#
+def entry_cmp(x, y):
+ return cmp(x[0], y[0])
+
+
+#
+# print the XML for the transformed "filecont_source"
+#
+def bibtexdecoder(filecont_source):
+ filecont = []
+ file = []
+
+ # want @<alphanumeric chars><spaces>{<spaces><any chars>,
+ pubtype_rex = re.compile('@(\w*)\s*{\s*(.*),')
+ endtype_rex = re.compile('}\s*$')
+ endtag_rex = re.compile('^\s*}\s*$')
+
+ bracefield_rex = re.compile('\s*(\w*)\s*=\s*(.*)')
+ bracedata_rex = re.compile('\s*(\w*)\s*=\s*{(.*)},?')
+
+ quotefield_rex = re.compile('\s*(\w*)\s*=\s*(.*)')
+ quotedata_rex = re.compile('\s*(\w*)\s*=\s*"(.*)",?')
+
+ for line in filecont_source:
+ line = line[:-1]
+
+ # encode character entities
+ line = string.replace(line, '&', '&amp;')
+ line = string.replace(line, '<', '&lt;')
+ line = string.replace(line, '>', '&gt;')
+
+ # start entry: publication type (store for later use)
+ if pubtype_rex.match(line):
+ # want @<alphanumeric chars><spaces>{<spaces><any chars>,
+ entrycont = {}
+ entry = []
+ entrytype = pubtype_rex.sub('\g<1>',line)
+ entrytype = string.lower(entrytype)
+ entryid = pubtype_rex.sub('\g<2>', line)
+
+ # end entry if just a }
+ elif endtype_rex.match(line):
+ # generate doxygen code for the entry
+
+ # enty type related formattings
+ if entrytype in ('book', 'inbook'):
+ entrycont['title'] = '<em>' + entrycont['title'] + '</em>'
+ if not entrycont.has_key('author'):
+ entrycont['author'] = entrycont['editor']
+ entrycont['author']['text'] += ', editors'
+ elif entrytype == 'article':
+ entrycont['journal'] = '<em>' + entrycont['journal'] + '</em>'
+ elif entrytype in ('inproceedings', 'incollection', 'conference'):
+ entrycont['booktitle'] = '<em>' + entrycont['booktitle'] + '</em>'
+ elif entrytype == 'techreport':
+ if not entrycont.has_key('type'):
+ entrycont['type'] = 'Technical report'
+ elif entrytype == 'mastersthesis':
+ entrycont['type'] = 'Master\'s thesis'
+ elif entrytype == 'phdthesis':
+ entrycont['type'] = 'PhD thesis'
+
+ for eline in entrycont:
+ if eline != '':
+ eline = latexreplacements(eline)
+
+ if entrycont.has_key('pages') and (entrycont['pages'] != ''):
+ entrycont['pages'] = string.replace(entrycont['pages'], '--', '-')
+
+ if entrycont.has_key('author') and (entrycont['author'] != ''):
+ entry.append(entrycont['author']['text'] + '.')
+ if entrycont.has_key('title') and (entrycont['title'] != ''):
+ entry.append(entrycont['title'] + '.')
+ if entrycont.has_key('journal') and (entrycont['journal'] != ''):
+ entry.append(entrycont['journal'] + ',')
+ if entrycont.has_key('booktitle') and (entrycont['booktitle'] != ''):
+ entry.append('In ' + entrycont['booktitle'] + ',')
+ if entrycont.has_key('type') and (entrycont['type'] != ''):
+ eline = entrycont['type']
+ if entrycont.has_key('number') and (entrycont['number'] != ''):
+ eline += ' ' + entrycont['number']
+ eline += ','
+ entry.append(eline)
+ if entrycont.has_key('institution') and (entrycont['institution'] != ''):
+ entry.append(entrycont['institution'] + ',')
+ if entrycont.has_key('publisher') and (entrycont['publisher'] != ''):
+ entry.append(entrycont['publisher'] + ',')
+ if entrycont.has_key('school') and (entrycont['school'] != ''):
+ entry.append(entrycont['school'] + ',')
+ if entrycont.has_key('address') and (entrycont['address'] != ''):
+ entry.append(entrycont['address'] + ',')
+ if entrycont.has_key('edition') and (entrycont['edition'] != ''):
+ entry.append(entrycont['edition'] + ' edition,')
+ if entrycont.has_key('howpublished') and (entrycont['howpublished'] != ''):
+ entry.append(entrycont['howpublished'] + ',')
+ if entrycont.has_key('volume') and (entrycont['volume'] != ''):
+ eline = entrycont['volume'];
+ if entrycont.has_key('number') and (entrycont['number'] != ''):
+ eline += '(' + entrycont['number'] + ')'
+ if entrycont.has_key('pages') and (entrycont['pages'] != ''):
+ eline += ':' + entrycont['pages']
+ eline += ','
+ entry.append(eline)
+ else:
+ if entrycont.has_key('pages') and (entrycont['pages'] != ''):
+ entry.append('pages ' + entrycont['pages'] + ',')
+ if entrycont.has_key('year') and (entrycont['year'] != ''):
+ if entrycont.has_key('month') and (entrycont['month'] != ''):
+ entry.append(entrycont['month'] + ' ' + entrycont['year'] + '.')
+ else:
+ entry.append(entrycont['year'] + '.')
+ if entrycont.has_key('note') and (entrycont['note'] != ''):
+ entry.append(entrycont['note'] + '.')
+ if entrycont.has_key('url') and (entrycont['url'] != ''):
+ entry.append(entrycont['url'] + '.')
+
+ # generate keys for sorting and for the output
+ sortkey = ''
+ bibkey = ''
+ if entrycont.has_key('author'):
+ for author in entrycont['author']['list']:
+ sortkey += copychars(author, author.rfind(' ')+1, len(author))
+ bibkey = entrycont['author']['abbrev']
+ else:
+ bibkey = 'x'
+ if entrycont.has_key('year'):
+ sortkey += entrycont['year']
+ bibkey += entrycont['year'][-2:]
+ if entrycont.has_key('title'):
+ sortkey += entrycont['title']
+ if entrycont.has_key('key'):
+ sortkey = entrycont['key'] + sortkey
+ bibkey = entrycont['key']
+ entry.insert(0, sortkey)
+ entry.insert(1, bibkey)
+ entry.insert(2, entryid)
+
+ # add the entry to the file contents
+ filecont.append(entry)
+
+ else:
+ # field, publication info
+ field = ''
+ data = ''
+
+ # field = {data} entries
+ if bracedata_rex.match(line):
+ field = bracefield_rex.sub('\g<1>', line)
+ field = string.lower(field)
+ data = bracedata_rex.sub('\g<2>', line)
+
+ # field = "data" entries
+ elif quotedata_rex.match(line):
+ field = quotefield_rex.sub('\g<1>', line)
+ field = string.lower(field)
+ data = quotedata_rex.sub('\g<2>', line)
+
+ # field = data entries
+ elif data_rex.match(line):
+ field = field_rex.sub('\g<1>', line)
+ field = string.lower(field)
+ data = data_rex.sub('\g<2>', line)
+
+ if field == 'url':
+ data = '\\url{' + data.strip() + '}'
+
+ if field in ('author', 'editor'):
+ entrycont[field] = bibtexauthor(data)
+ line = ''
+ elif field == 'title':
+ line = bibtextitle(data, entrytype)
+ elif field != '':
+ line = removebraces(transformurls(data.strip()))
+
+ if line != '':
+ line = latexreplacements(line)
+ entrycont[field] = line
+
+
+ # sort entries
+ filecont.sort(entry_cmp)
+
+ # count the bibtex keys
+ keytable = {}
+ counttable = {}
+ for entry in filecont:
+ bibkey = entry[1]
+ if not keytable.has_key(bibkey):
+ keytable[bibkey] = 1
+ else:
+ keytable[bibkey] += 1
+
+ for bibkey in keytable.keys():
+ counttable[bibkey] = 0
+
+ # generate output
+ for entry in filecont:
+ # generate output key form the bibtex key
+ bibkey = entry[1]
+ entryid = entry[2]
+ if keytable[bibkey] == 1:
+ outkey = bibkey
+ else:
+ outkey = bibkey + chr(97 + counttable[bibkey])
+ counttable[bibkey] += 1
+
+ # append the entry code to the output
+ file.append('\\section ' + entryid + ' [' + outkey + ']')
+ file.append('<div style="' + divstyle + '">')
+ for line in entry[3:]:
+ file.append(line)
+ file.append('</div>')
+ file.append('')
+
+ return file
+
+
+#
+# return 1 iff abbr is in line but not inside braces or quotes
+# assumes that abbr appears only once on the line (out of braces and quotes)
+#
+def verify_out_of_braces(line, abbr):
+
+ phrase_split = delimiter_rex.split(line)
+
+ abbr_rex = re.compile( '\\b' + abbr + '\\b', re.I)
+
+ open_brace = 0
+ open_quote = 0
+
+ for phrase in phrase_split:
+ if phrase == "{":
+ open_brace = open_brace + 1
+ elif phrase == "}":
+ open_brace = open_brace - 1
+ elif phrase == '"':
+ if open_quote == 1:
+ open_quote = 0
+ else:
+ open_quote = 1
+ elif abbr_rex.search(phrase):
+ if open_brace == 0 and open_quote == 0:
+ return 1
+
+ return 0
+
+
+#
+# a line in the form phrase1 # phrase2 # ... # phrasen
+# is returned as phrase1 phrase2 ... phrasen
+# with the correct punctuation
+# Bug: Doesn't always work with multiple abbreviations plugged in
+#
+def concat_line(line):
+ # only look at part after equals
+ field = field_rex.sub('\g<1>',line)
+ rest = field_rex.sub('\g<2>',line)
+
+ concat_line = field + ' ='
+
+ pound_split = concatsplit_rex.split(rest)
+
+ phrase_count = 0
+ length = len(pound_split)
+
+ for phrase in pound_split:
+ phrase = phrase.strip()
+ if phrase_count != 0:
+ if phrase.startswith('"') or phrase.startswith('{'):
+ phrase = phrase[1:]
+ elif phrase.startswith('"'):
+ phrase = phrase.replace('"','{',1)
+
+ if phrase_count != length-1:
+ if phrase.endswith('"') or phrase.endswith('}'):
+ phrase = phrase[:-1]
+ else:
+ if phrase.endswith('"'):
+ phrase = phrase[:-1]
+ phrase = phrase + "}"
+ elif phrase.endswith('",'):
+ phrase = phrase[:-2]
+ phrase = phrase + "},"
+
+ # if phrase did have \#, add the \# back
+ if phrase.endswith('\\'):
+ phrase = phrase + "#"
+ concat_line = concat_line + ' ' + phrase
+
+ phrase_count = phrase_count + 1
+
+ return concat_line
+
+
+#
+# substitute abbreviations into filecont
+# @param filecont_source - string of data from file
+#
+def bibtex_replace_abbreviations(filecont_source):
+ filecont = filecont_source.splitlines()
+
+ # These are defined in bibtex, so we'll define them too
+ abbr_list = ['jan','feb','mar','apr','may','jun',
+ 'jul','aug','sep','oct','nov','dec']
+ value_list = ['January','February','March','April',
+ 'May','June','July','August','September',
+ 'October','November','December']
+
+ abbr_rex = []
+ total_abbr_count = 0
+
+ front = '\\b'
+ back = '(,?)\\b'
+
+ for x in abbr_list:
+ abbr_rex.append( re.compile( front + abbr_list[total_abbr_count] + back, re.I ) )
+ total_abbr_count = total_abbr_count + 1
+
+
+ abbrdef_rex = re.compile('\s*@string\s*{\s*('+ valid_name_chars +'*)\s*=(.*)',
+ re.I)
+
+ comment_rex = re.compile('@comment\s*{',re.I)
+ preamble_rex = re.compile('@preamble\s*{',re.I)
+
+ waiting_for_end_string = 0
+ i = 0
+ filecont2 = ''
+
+ for line in filecont:
+ if line == ' ' or line == '':
+ continue
+
+ if waiting_for_end_string:
+ if re.search('}',line):
+ waiting_for_end_string = 0
+ continue
+
+ if abbrdef_rex.search(line):
+ abbr = abbrdef_rex.sub('\g<1>', line)
+
+ if abbr_list.count(abbr) == 0:
+ val = abbrdef_rex.sub('\g<2>', line)
+ abbr_list.append(abbr)
+ value_list.append(string.strip(val))
+ abbr_rex.append( re.compile( front + abbr_list[total_abbr_count] + back, re.I ) )
+ total_abbr_count = total_abbr_count + 1
+ waiting_for_end_string = 1
+ continue
+
+ if comment_rex.search(line):
+ waiting_for_end_string = 1
+ continue
+
+ if preamble_rex.search(line):
+ waiting_for_end_string = 1
+ continue
+
+
+ # replace subsequent abbreviations with the value
+ abbr_count = 0
+
+ for x in abbr_list:
+
+ if abbr_rex[abbr_count].search(line):
+ if verify_out_of_braces(line,abbr_list[abbr_count]) == 1:
+ line = abbr_rex[abbr_count].sub( value_list[abbr_count] + '\g<1>', line)
+ # Check for # concatenations
+ if concatsplit_rex.search(line):
+ line = concat_line(line)
+ abbr_count = abbr_count + 1
+
+
+ filecont2 = filecont2 + line + '\n'
+ i = i+1
+
+
+ # Do one final pass over file
+
+ # make sure that didn't end up with {" or }" after the substitution
+ filecont2 = filecont2.replace('{"','{{')
+ filecont2 = filecont2.replace('"}','}}')
+
+ afterquotevalue_rex = re.compile('"\s*,\s*')
+ afterbrace_rex = re.compile('"\s*}')
+ afterbracevalue_rex = re.compile('(=\s*{[^=]*)},\s*')
+
+ # add new lines to data that changed because of abbreviation substitutions
+ filecont2 = afterquotevalue_rex.sub('",\n', filecont2)
+ filecont2 = afterbrace_rex.sub('"\n}', filecont2)
+ filecont2 = afterbracevalue_rex.sub('\g<1>},\n', filecont2)
+
+ return filecont2
+
+#
+# convert @type( ... ) to @type{ ... }
+#
+def no_outer_parens(filecont):
+
+ # do checking for open parens
+ # will convert to braces
+ paren_split = re.split('([(){}])',filecont)
+
+ open_paren_count = 0
+ open_type = 0
+ look_next = 0
+
+ # rebuild filecont
+ filecont = ''
+
+ at_rex = re.compile('@\w*')
+
+ for phrase in paren_split:
+ if look_next == 1:
+ if phrase == '(':
+ phrase = '{'
+ open_paren_count = open_paren_count + 1
+ else:
+ open_type = 0
+ look_next = 0
+
+ if phrase == '(':
+ open_paren_count = open_paren_count + 1
+
+ elif phrase == ')':
+ open_paren_count = open_paren_count - 1
+ if open_type == 1 and open_paren_count == 0:
+ phrase = '}'
+ open_type = 0
+
+ elif at_rex.search( phrase ):
+ open_type = 1
+ look_next = 1
+
+ filecont = filecont + phrase
+
+ return filecont
+
+
+#
+# make all whitespace into just one space
+# format the bibtex file into a usable form.
+#
+def bibtexwasher(filecont_source):
+
+ space_rex = re.compile('\s+')
+ comment_rex = re.compile('\s*%')
+
+ filecont = []
+
+ # remove trailing and excessive whitespace
+ # ignore comments
+ for line in filecont_source:
+ line = string.strip(line)
+ line = space_rex.sub(' ', line)
+ # ignore comments
+ if not comment_rex.match(line) and line != '':
+ filecont.append(' '+ line)
+
+ filecont = string.join(filecont, '')
+
+ # the file is in one long string
+
+ filecont = no_outer_parens(filecont)
+
+ #
+ # split lines according to preferred syntax scheme
+ #
+ filecont = re.sub('(=\s*{[^=]*)},', '\g<1>},\n', filecont)
+
+ # add new lines after commas that are after values
+ filecont = re.sub('"\s*,', '",\n', filecont)
+ filecont = re.sub('=\s*([\w\d]+)\s*,', '= \g<1>,\n', filecont)
+ filecont = re.sub('(@\w*)\s*({(\s*)[^,\s]*)\s*,',
+ '\n\n\g<1>\g<2>,\n', filecont)
+
+ # add new lines after }
+ filecont = re.sub('"\s*}','"\n}\n', filecont)
+ filecont = re.sub('}\s*,','},\n', filecont)
+
+
+ filecont = re.sub('@(\w*)', '\n@\g<1>', filecont)
+
+ # character encoding, reserved latex characters
+ filecont = re.sub('{\\\&}', '&', filecont)
+ filecont = re.sub('\\\&', '&', filecont)
+
+ # do checking for open braces to get format correct
+ open_brace_count = 0
+ brace_split = re.split('([{}])',filecont)
+
+ # rebuild filecont
+ filecont = ''
+
+ for phrase in brace_split:
+ if phrase == '{':
+ open_brace_count = open_brace_count + 1
+ elif phrase == '}':
+ open_brace_count = open_brace_count - 1
+ if open_brace_count == 0:
+ filecont = filecont + '\n'
+
+ filecont = filecont + phrase
+
+ filecont2 = bibtex_replace_abbreviations(filecont)
+
+ # gather
+ filecont = filecont2.splitlines()
+ i=0
+ j=0 # count the number of blank lines
+ for line in filecont:
+ # ignore blank lines
+ if line == '' or line == ' ':
+ j = j+1
+ continue
+ filecont[i] = line + '\n'
+ i = i+1
+
+ # get rid of the extra stuff at the end of the array
+ # (The extra stuff are duplicates that are in the array because
+ # blank lines were removed.)
+ length = len( filecont)
+ filecont[length-j:length] = []
+
+ return filecont
+
+
+def filehandler(filepath):
+ try:
+ fd = open(filepath, 'r')
+ filecont_source = fd.readlines()
+ fd.close()
+ except:
+ print 'Could not open file:', filepath
+ washeddata = bibtexwasher(filecont_source)
+ outdata = bibtexdecoder(washeddata)
+ print '/**'
+ print '\page references References'
+ print
+ for line in outdata:
+ print line
+ print '*/'
+
+
+# main program
+
+def main():
+ import sys
+ if sys.argv[1:]:
+ filepath = sys.argv[1]
+ else:
+ print "No input file"
+ sys.exit()
+ filehandler(filepath)
+
+if __name__ == "__main__": main()
+
+
+# end python script
diff --git a/lemon/scripts/bootstrap.sh b/lemon/scripts/bootstrap.sh
new file mode 100755
index 0000000..17960cf
--- /dev/null
+++ b/lemon/scripts/bootstrap.sh
@@ -0,0 +1,157 @@
+#!/bin/bash
+#
+# This file is a part of LEMON, a generic C++ optimization library.
+#
+# Copyright (C) 2003-2009
+# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+# (Egervary Research Group on Combinatorial Optimization, EGRES).
+#
+# Permission to use, modify and distribute this software is granted
+# provided that this copyright notice appears in all copies. For
+# precise terms see the accompanying LICENSE file.
+#
+# This software is provided "AS IS" with no warranty of any kind,
+# express or implied, and with no claim as to its suitability for any
+# purpose.
+
+
+if [ ! -f ~/.lemon-bootstrap ]; then
+ echo 'Create ~/.lemon-bootstrap'.
+ cat >~/.lemon-bootstrap <<EOF
+#
+# Default settings for bootstraping the LEMON source code repository
+#
+EOF
+fi
+
+source ~/.lemon-bootstrap
+if [ -f ../../../.lemon-bootstrap ]; then source ../../../.lemon-bootstrap; fi
+if [ -f ../../.lemon-bootstrap ]; then source ../../.lemon-bootstrap; fi
+if [ -f ../.lemon-bootstrap ]; then source ../.lemon-bootstrap; fi
+if [ -f ./.lemon-bootstrap ]; then source ./.lemon-bootstrap; fi
+
+
+function augment_config() {
+ if [ "x${!1}" == "x" ]; then
+ eval $1=$2
+ echo Add "'$1'" to '~/.lemon-bootstrap'.
+ echo >>~/.lemon-bootstrap
+ echo $3 >>~/.lemon-bootstrap
+ echo $1=$2 >>~/.lemon-bootstrap
+ fi
+}
+
+augment_config LEMON_INSTALL_PREFIX /usr/local \
+ "# LEMON installation prefix"
+
+augment_config GLPK_PREFIX /usr/local/ \
+ "# GLPK installation root prefix"
+
+augment_config COIN_OR_PREFIX /usr/local/coin-or \
+ "# COIN-OR installation root prefix (used for CLP/CBC)"
+
+augment_config SOPLEX_PREFIX /usr/local/soplex \
+ "# Soplex build prefix"
+
+
+function ask() {
+echo -n "$1 [$2]? "
+read _an
+if [ "x$_an" == "x" ]; then
+ ret="$2"
+else
+ ret=$_an
+fi
+}
+
+function yesorno() {
+ ret='rossz'
+ while [ "$ret" != "y" -a "$ret" != "n" -a "$ret" != "yes" -a "$ret" != "no" ]; do
+ ask "$1" "$2"
+ done
+ if [ "$ret" != "y" -a "$ret" != "yes" ]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
+if yesorno "External build" "n"
+then
+ CONFIGURE_PATH=".."
+else
+ CONFIGURE_PATH="."
+ if yesorno "Autoreconf" "y"
+ then
+ AUTORE=yes
+ else
+ AUTORE=no
+ fi
+fi
+
+if yesorno "Optimize" "n"
+then
+ opt_flags=' -O2'
+else
+ opt_flags=''
+fi
+
+if yesorno "Stop on warning" "y"
+then
+ werror_flags=' -Werror'
+else
+ werror_flags=''
+fi
+
+cxx_flags="CXXFLAGS=-ggdb$opt_flags$werror_flags"
+
+if yesorno "Check with valgrind" "n"
+then
+ valgrind_flags=' --enable-valgrind'
+else
+ valgrind_flags=''
+fi
+
+if [ -f ${GLPK_PREFIX}/include/glpk.h ]; then
+ if yesorno "Use GLPK" "y"
+ then
+ glpk_flag="--with-glpk=$GLPK_PREFIX"
+ else
+ glpk_flag="--without-glpk"
+ fi
+else
+ glpk_flag="--without-glpk"
+fi
+
+if [ -f ${COIN_OR_PREFIX}/include/coin/config_coinutils.h ]; then
+ if yesorno "Use COIN-OR (CBC/CLP)" "n"
+ then
+ coin_flag="--with-coin=$COIN_OR_PREFIX"
+ else
+ coin_flag="--without-coin"
+ fi
+else
+ coin_flag="--without-coin"
+fi
+
+if [ -f ${SOPLEX_PREFIX}/src/soplex.h ]; then
+ if yesorno "Use Soplex" "n"
+ then
+ soplex_flag="--with-soplex=$SOPLEX_PREFIX"
+ else
+ soplex_flag="--without-soplex"
+ fi
+else
+ soplex_flag="--without-soplex"
+fi
+
+if [ "x$AUTORE" == "xyes" ]; then
+ autoreconf -vif;
+fi
+${CONFIGURE_PATH}/configure --prefix=$LEMON_INSTALL_PREFIX \
+$valgrind_flags \
+"$cxx_flags" \
+$glpk_flag \
+$coin_flag \
+$soplex_flag \
+$*
diff --git a/lemon/scripts/chg-len.py b/lemon/scripts/chg-len.py
new file mode 100755
index 0000000..aa2be0f
--- /dev/null
+++ b/lemon/scripts/chg-len.py
@@ -0,0 +1,46 @@
+#! /usr/bin/env python
+#
+# This file is a part of LEMON, a generic C++ optimization library.
+#
+# Copyright (C) 2003-2009
+# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+# (Egervary Research Group on Combinatorial Optimization, EGRES).
+#
+# Permission to use, modify and distribute this software is granted
+# provided that this copyright notice appears in all copies. For
+# precise terms see the accompanying LICENSE file.
+#
+# This software is provided "AS IS" with no warranty of any kind,
+# express or implied, and with no claim as to its suitability for any
+# purpose.
+
+import sys
+
+from mercurial import ui, hg
+from mercurial import util
+
+util.rcpath = lambda : []
+
+if len(sys.argv)>1 and sys.argv[1] in ["-h","--help"]:
+ print """
+This utility just prints the length of the longest path
+in the revision graph from revison 0 to the current one.
+"""
+ exit(0)
+
+u = ui.ui()
+r = hg.repository(u, ".")
+N = r.changectx(".").rev()
+lengths=[0]*(N+1)
+for i in range(N+1):
+ p=r.changectx(i).parents()
+ if p[0]:
+ p0=lengths[p[0].rev()]
+ else:
+ p0=-1
+ if len(p)>1 and p[1]:
+ p1=lengths[p[1].rev()]
+ else:
+ p1=-1
+ lengths[i]=max(p0,p1)+1
+print lengths[N]
diff --git a/lemon/scripts/mk-release.sh b/lemon/scripts/mk-release.sh
new file mode 100755
index 0000000..d3439b1
--- /dev/null
+++ b/lemon/scripts/mk-release.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# This file is a part of LEMON, a generic C++ optimization library.
+#
+# Copyright (C) 2003-2009
+# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+# (Egervary Research Group on Combinatorial Optimization, EGRES).
+#
+# Permission to use, modify and distribute this software is granted
+# provided that this copyright notice appears in all copies. For
+# precise terms see the accompanying LICENSE file.
+#
+# This software is provided "AS IS" with no warranty of any kind,
+# express or implied, and with no claim as to its suitability for any
+# purpose.
+
+set -e
+
+if [ $# = 0 ]; then
+ echo "Usage: $0 release-id"
+ exit 1
+else
+ export LEMON_VERSION=$1
+fi
+
+echo '*****************************************************************'
+echo ' Start making release tarballs for version '${LEMON_VERSION}
+echo '*****************************************************************'
+
+autoreconf -vif
+./configure
+
+make
+make html
+make distcheck
+tar xf lemon-${LEMON_VERSION}.tar.gz
+zip -r lemon-${LEMON_VERSION}.zip lemon-${LEMON_VERSION}
+mv lemon-${LEMON_VERSION}/doc/html lemon-doc-${LEMON_VERSION}
+tar czf lemon-doc-${LEMON_VERSION}.tar.gz lemon-doc-${LEMON_VERSION}
+zip -r lemon-doc-${LEMON_VERSION}.zip lemon-doc-${LEMON_VERSION}
+tar czf lemon-nodoc-${LEMON_VERSION}.tar.gz lemon-${LEMON_VERSION}
+zip -r lemon-nodoc-${LEMON_VERSION}.zip lemon-${LEMON_VERSION}
+hg tag -m 'LEMON '${LEMON_VERSION}' released ('$(hg par --template="{node|short}")' tagged as r'${LEMON_VERSION}')' r${LEMON_VERSION}
+
+rm -rf lemon-${LEMON_VERSION} lemon-doc-${LEMON_VERSION}
+
+echo '*****************************************************************'
+echo ' Release '${LEMON_VERSION}' has been created'
+echo '*****************************************************************'
diff --git a/lemon/scripts/unify-sources.sh b/lemon/scripts/unify-sources.sh
new file mode 100755
index 0000000..6aae63a
--- /dev/null
+++ b/lemon/scripts/unify-sources.sh
@@ -0,0 +1,390 @@
+#!/bin/bash
+#
+# This file is a part of LEMON, a generic C++ optimization library.
+#
+# Copyright (C) 2003-2009
+# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+# (Egervary Research Group on Combinatorial Optimization, EGRES).
+#
+# Permission to use, modify and distribute this software is granted
+# provided that this copyright notice appears in all copies. For
+# precise terms see the accompanying LICENSE file.
+#
+# This software is provided "AS IS" with no warranty of any kind,
+# express or implied, and with no claim as to its suitability for any
+# purpose.
+
+YEAR=`date +%Y`
+HGROOT=`hg root`
+
+function hg_year() {
+ if [ -n "$(hg st $1)" ]; then
+ echo $YEAR
+ else
+ hg log -l 1 --template='{date|isodate}\n' $1 |
+ cut -d '-' -f 1
+ fi
+}
+
+# file enumaration modes
+
+function all_files() {
+ hg status -a -m -c |
+ cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
+ while read file; do echo $HGROOT/$file; done
+}
+
+function modified_files() {
+ hg status -a -m |
+ cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
+ while read file; do echo $HGROOT/$file; done
+}
+
+function changed_files() {
+ {
+ if [ -n "$HG_PARENT1" ]
+ then
+ hg status --rev $HG_PARENT1:$HG_NODE -a -m
+ fi
+ if [ -n "$HG_PARENT2" ]
+ then
+ hg status --rev $HG_PARENT2:$HG_NODE -a -m
+ fi
+ } | cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
+ sort | uniq |
+ while read file; do echo $HGROOT/$file; done
+}
+
+function given_files() {
+ for file in $GIVEN_FILES
+ do
+ echo $file
+ done
+}
+
+# actions
+
+function update_action() {
+ if ! diff -q $1 $2 >/dev/null
+ then
+ echo -n " [$3 updated]"
+ rm $2
+ mv $1 $2
+ CHANGED=YES
+ fi
+}
+
+function update_warning() {
+ echo -n " [$2 warning]"
+ WARNED=YES
+}
+
+function update_init() {
+ echo Update source files...
+ TOTAL_FILES=0
+ CHANGED_FILES=0
+ WARNED_FILES=0
+}
+
+function update_done() {
+ echo $CHANGED_FILES out of $TOTAL_FILES files has been changed.
+ echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
+}
+
+function update_begin() {
+ ((TOTAL_FILES++))
+ CHANGED=NO
+ WARNED=NO
+}
+
+function update_end() {
+ if [ $CHANGED == YES ]
+ then
+ ((++CHANGED_FILES))
+ fi
+ if [ $WARNED == YES ]
+ then
+ ((++WARNED_FILES))
+ fi
+}
+
+function check_action() {
+ if [ "$3" == 'tabs' ]
+ then
+ if echo $2 | grep -q -v -E 'Makefile\.am$'
+ then
+ PATTERN=$(echo -e '\t')
+ else
+ PATTERN=' '
+ fi
+ elif [ "$3" == 'trailing spaces' ]
+ then
+ PATTERN='\ +$'
+ else
+ PATTERN='*'
+ fi
+
+ if ! diff -q $1 $2 >/dev/null
+ then
+ if [ "$PATTERN" == '*' ]
+ then
+ diff $1 $2 | grep '^[0-9]' | sed "s|^\(.*\)c.*$|$2:\1: check failed: $3|g" |
+ sed "s/:\([0-9]*\),\([0-9]*\):\(.*\)$/:\1:\3 (until line \2)/g"
+ else
+ grep -n -E "$PATTERN" $2 | sed "s|^\([0-9]*\):.*$|$2:\1: check failed: $3|g"
+ fi
+ FAILED=YES
+ fi
+}
+
+function check_warning() {
+ if [ "$2" == 'long lines' ]
+ then
+ grep -n -E '.{81,}' $1 | sed "s|^\([0-9]*\):.*$|$1:\1: warning: $2|g"
+ else
+ echo "$1: warning: $2"
+ fi
+ WARNED=YES
+}
+
+function check_init() {
+ echo Check source files...
+ FAILED_FILES=0
+ WARNED_FILES=0
+ TOTAL_FILES=0
+}
+
+function check_done() {
+ echo $FAILED_FILES out of $TOTAL_FILES files has been failed.
+ echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
+
+ if [ $WARNED_FILES -gt 0 -o $FAILED_FILES -gt 0 ]
+ then
+ if [ "$WARNING" == 'INTERACTIVE' ]
+ then
+ echo -n "Are the files with errors/warnings acceptable? (yes/no) "
+ while read answer
+ do
+ if [ "$answer" == 'yes' ]
+ then
+ return 0
+ elif [ "$answer" == 'no' ]
+ then
+ return 1
+ fi
+ echo -n "Are the files with errors/warnings acceptable? (yes/no) "
+ done
+ elif [ "$WARNING" == 'WERROR' ]
+ then
+ return 1
+ fi
+ fi
+}
+
+function check_begin() {
+ ((TOTAL_FILES++))
+ FAILED=NO
+ WARNED=NO
+}
+
+function check_end() {
+ if [ $FAILED == YES ]
+ then
+ ((++FAILED_FILES))
+ fi
+ if [ $WARNED == YES ]
+ then
+ ((++WARNED_FILES))
+ fi
+}
+
+
+
+# checks
+
+function header_check() {
+ if echo $1 | grep -q -E 'Makefile\.am$'
+ then
+ return
+ fi
+
+ TMP_FILE=`mktemp`
+
+ (echo "/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-"$(hg_year $1)"
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided \"AS IS\" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+"
+ awk 'BEGIN { pm=0; }
+ pm==3 { print }
+ /\/\* / && pm==0 { pm=1;}
+ /[^:blank:]/ && (pm==0 || pm==2) { pm=3; print;}
+ /\*\// && pm==1 { pm=2;}
+ ' $1
+ ) >$TMP_FILE
+
+ "$ACTION"_action "$TMP_FILE" "$1" header
+}
+
+function tabs_check() {
+ if echo $1 | grep -q -v -E 'Makefile\.am$'
+ then
+ OLD_PATTERN=$(echo -e '\t')
+ NEW_PATTERN=' '
+ else
+ OLD_PATTERN=' '
+ NEW_PATTERN=$(echo -e '\t')
+ fi
+ TMP_FILE=`mktemp`
+ cat $1 | sed -e "s/$OLD_PATTERN/$NEW_PATTERN/g" >$TMP_FILE
+
+ "$ACTION"_action "$TMP_FILE" "$1" 'tabs'
+}
+
+function spaces_check() {
+ TMP_FILE=`mktemp`
+ cat $1 | sed -e 's/ \+$//g' >$TMP_FILE
+
+ "$ACTION"_action "$TMP_FILE" "$1" 'trailing spaces'
+}
+
+function long_lines_check() {
+ if cat $1 | grep -q -E '.{81,}'
+ then
+ "$ACTION"_warning $1 'long lines'
+ fi
+}
+
+# process the file
+
+function process_file() {
+ if [ "$ACTION" == 'update' ]
+ then
+ echo -n " $ACTION $1..."
+ else
+ echo " $ACTION $1..."
+ fi
+
+ CHECKING="header tabs spaces long_lines"
+
+ "$ACTION"_begin $1
+ for check in $CHECKING
+ do
+ "$check"_check $1
+ done
+ "$ACTION"_end $1
+ if [ "$ACTION" == 'update' ]
+ then
+ echo
+ fi
+}
+
+function process_all {
+ "$ACTION"_init
+ while read file
+ do
+ process_file $file
+ done < <($FILES)
+ "$ACTION"_done
+}
+
+while [ $# -gt 0 ]
+do
+
+ if [ "$1" == '--help' ] || [ "$1" == '-h' ]
+ then
+ echo -n \
+"Usage:
+ $0 [OPTIONS] [files]
+Options:
+ --dry-run|-n
+ Check the files, but do not modify them.
+ --interactive|-i
+ If --dry-run is specified and the checker emits warnings,
+ then the user is asked if the warnings should be considered
+ errors.
+ --werror|-w
+ Make all warnings into errors.
+ --all|-a
+ Check all source files in the repository.
+ --modified|-m
+ Check only the modified (and new) source files. This option is
+ useful to check the modification before making a commit.
+ --changed|-c
+ Check only the changed source files compared to the parent(s) of
+ the current hg node. This option is useful as hg hook script.
+ To automatically check all your changes before making a commit,
+ add the following section to the appropriate .hg/hgrc file.
+
+ [hooks]
+ pretxncommit.checksources = scripts/unify-sources.sh -c -n -i
+
+ --help|-h
+ Print this help message.
+ files
+ The files to check/unify. If no file names are given, the modified
+ source files will be checked/unified (just like using the
+ --modified|-m option).
+"
+ exit 0
+ elif [ "$1" == '--dry-run' ] || [ "$1" == '-n' ]
+ then
+ [ -n "$ACTION" ] && echo "Conflicting action options" >&2 && exit 1
+ ACTION=check
+ elif [ "$1" == "--all" ] || [ "$1" == '-a' ]
+ then
+ [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
+ FILES=all_files
+ elif [ "$1" == "--changed" ] || [ "$1" == '-c' ]
+ then
+ [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
+ FILES=changed_files
+ elif [ "$1" == "--modified" ] || [ "$1" == '-m' ]
+ then
+ [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
+ FILES=modified_files
+ elif [ "$1" == "--interactive" ] || [ "$1" == "-i" ]
+ then
+ [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
+ WARNING='INTERACTIVE'
+ elif [ "$1" == "--werror" ] || [ "$1" == "-w" ]
+ then
+ [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
+ WARNING='WERROR'
+ elif [ $(echo x$1 | cut -c 2) == '-' ]
+ then
+ echo "Invalid option $1" >&2 && exit 1
+ else
+ [ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1
+ GIVEN_FILES=$@
+ FILES=given_files
+ break
+ fi
+
+ shift
+done
+
+if [ -z $FILES ]
+then
+ FILES=modified_files
+fi
+
+if [ -z $ACTION ]
+then
+ ACTION=update
+fi
+
+process_all
diff --git a/lemon/scripts/valgrind-wrapper.sh b/lemon/scripts/valgrind-wrapper.sh
new file mode 100755
index 0000000..bbb1222
--- /dev/null
+++ b/lemon/scripts/valgrind-wrapper.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Run in valgrind, with leak checking enabled
+
+valgrind -q --leak-check=full "$@" 2> .valgrind-log
+
+# Save the test result
+
+result="$?"
+
+# Valgrind should generate no error messages
+
+log_contents="`cat .valgrind-log`"
+
+if [ "$log_contents" != "" ]; then
+ cat .valgrind-log >&2
+ result=1
+fi
+
+rm -f .valgrind-log
+
+exit $result