public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Gaius Mulley <gaiusmod2@gmail.com>
To: "Martin Liška" <mliska@suse.cz>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] 16/19 modula2 front end: bootstrap and documentation tools
Date: Fri, 14 Oct 2022 13:10:33 +0100	[thread overview]
Message-ID: <87k052ppvq.fsf@debian> (raw)
In-Reply-To: <11f42175-8e23-5da3-6a13-6172039bfca2@suse.cz> ("Martin =?utf-8?Q?Li=C5=A1ka=22's?= message of "Thu, 13 Oct 2022 11:12:16 +0200")

Martin Liška <mliska@suse.cz> writes:

>> This patch set contains the bootstrap linking tool as well as python3
>> scripts to automatically generate texi libraries section of the gm2
>> documentation.  In the fullness of time this will be changed to emit
>> sphinx.
>
> Yep, looking forward to it. I'm going to write an email with Sphinx transition
> schedule once Sphinx 5.3 gets released (should happen during the upcoming weekend).
>
> I have general comments about the Python scripts:
>
> 1) please follow the Python coding style and not the GCC one (I'm going to document
> it in https://gcc.gnu.org/codingconventions.html under a new Python section).
> The easiest approach is using flake8 and the following plugins:
>
> python3-flake8, python3-flake8-builtins, python3-flake8-bugbear,
> python3-flake8-import-order, python3-flake8-quotes

Hi Martin,

many thanks for the pointers to the style tool and python lint - I'll
reformat the code accordingly.

> plus, you might want to come up with a setup.cfg like we have in:
> ./maintainer-scripts/setup.cfg

yes sounds sensible.  Thanks for the detailed
observations/suggestions/improvements below - I agree with them all and
will fix/change the code and then repost the patch

regards,
Gaius


>> ------8<----------8<----------8<----------8<----------8<----------8<---- 
>> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/tidydates.py
>> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
>> +++ gcc-git-devel-modula2/gcc/m2/tools-src/tidydates.py	2022-10-07 20:21:18.682097332 +0100
>> @@ -0,0 +1,184 @@
>> +#!/usr/bin/env python3
>> +
>> +# utility to tidy dates and detect lack of copyright.
>> +
>> +# Copyright (C) 2016-2022 Free Software Foundation, Inc.
>> +#
>> +# This file is part of GNU Modula-2.
>> +#
>> +# GNU Modula-2 is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 3, or (at your option)
>> +# any later version.
>> +#
>> +# GNU Modula-2 is distributed in the hope that it will be useful,
>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +# GNU General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License
>> +# along with GNU Modula-2; see the file COPYING.  If not, write to the
>> +# Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
>> +# 02110-1301, USA.
>> +
>> +import os, sys
>> +
>> +maxLineLength = 60
>> +
>> +
>> +#
>> +#  visitDir - call func for each file below, dir, matching extension, ext.
>> +#
>> +
>> +def visitDir (dir, ext, func):
>> +    listOfFiles = os.listdir(dir)
>> +    listOfFiles.sort()
>> +    for file in listOfFiles:
>> +        if os.path.isfile(os.path.join(dir, file)):
>> +            l = len(ext)
>> +            if (len(file)>l) and (file[-l:] == ext):
>> +                func(os.path.join(dir, file))
>
> please use pathlib.Path(...).stem

>
>> +        elif os.path.isdir(os.path.join(dir, file)):
>> +            visitDir(os.path.join(dir, file), ext, func)
>> +
>> +#
>> +#  isYear - returns True if, year, is legal.
>> +#
>> +
>> +def isYear (year):
>> +    if len(year)==5:
>> +        year = year[:-1]
>> +    for c in year:
>> +        if not c.isdigit():
>> +            return False
>> +    return True
>> +
>> +
>> +#
>> +#  handleCopyright -
>> +#
>> +
>> +def handleCopyright (outfile, lines, n, leader1, leader2):
>> +    global maxLineLength
>> +    i = lines[n]
>> +    c = i.find('Copyright (C) ')+len('Copyright (C)')
>> +    outfile.write(i[:c])
>> +    d = i[c:].split()
>> +    start = c
>> +    seenDate = True
>> +    years = []
>> +    while seenDate:
>> +        if d == []:
>> +            n += 1
>> +            i = lines[n]
>> +            d = i[2:].split()
>> +        else:
>> +            e = d[0]
>> +            punctuation = ""
>
> Please unify "" and '', you only apostrophes.
>
>> +            if len(d)==1:
>> +                d = []
>> +            else:
>> +                d = d[1:]
>> +
>> +            if c>maxLineLength:
>> +                outfile.write('\n')
>> +                outfile.write(leader1)
>> +                outfile.write(leader2)
>> +                outfile.write(' '*(start-2))
>> +                c = start
>> +
>> +            if isYear(e):
>> +                if (e[-1]=='.') or (e[-1]==','):
>> +                    punctuation = e[-1]
>> +                    e = e[:-1]
>> +                else:
>> +                    punctuation = ""
>> +            else:
>> +                seenDate = False
>> +            if seenDate:
>> +                if not (e in years):
>> +                    c += len(e) + len(punctuation)
>> +                    outfile.write(' ')
>> +                    outfile.write(e)
>> +                    outfile.write(punctuation)
>> +                    years += [e]
>> +            else:
>> +                if start < c:
>> +                    outfile.write('\n')
>> +                    outfile.write(leader1)
>> +                    outfile.write(leader2)
>> +                    outfile.write(' '*(start-2))
>> +
>> +                outfile.write(' ')
>> +                outfile.write(e)
>> +                outfile.write(punctuation)
>> +                for w in d:
>> +                    outfile.write(' ')
>> +                    outfile.write(w)
>> +
>> +    outfile.write('\n')
>> +    return outfile, n+1
>> +
>> +#
>> +#  handleHeader - reads in the header of a file and inserts
>> +#                 a line break around the Copyright dates.
>> +#
>> +
>> +def handleHeader (file, leader1, leader2):
>> +    print("------------------------------")
>> +    l = open(file, 'r').readlines()
>> +    if len(l)>20:
>> +        outfile = open('tmptidy', 'w')
>
> use 'with open(...) as outfile:'
> https://docs.python.org/3/reference/compound_stmts.html#the-with-statement
>    
>
>> +        n = 0
>> +        for i in l:
>> +            if i.find('Copyright (C)')>=0:
>> +                outfile, n = handleCopyright(outfile, l, n, leader1, leader2)
>> +                outfile.writelines(l[n:])
>> +                outfile.close()
>> +                print("-> mv tmptidy", file)
>> +                command = "mv tmptidy %s" % file
>> +                os.system(command)
>
> shutil.move
>
>> +                return
>> +            else:
>> +                outfile.write(l[n])
>> +                n += 1
>> +        outfile.close()
>
> ... will be closed automatically by 'with' statement.
>
>> +        sys.stdout.write("%s:1:1 needs a Copyright notice..\n" % file)
>> +
>> +
>> +#
>> +#  bashTidy - tidy up dates using '#' comment
>> +#
>> +
>> +def bashTidy (file):
>
> Better putting comments here in function body.
>
>> +    handleHeader(file, '#', ' ')
>> +
>> +#
>> +#  cTidy - tidy up dates using '/* */' comments
>> +#
>> +
>> +def cTidy (file):
>> +    handleHeader(file, ' ', '*')
>> +
>> +#
>> +#  m2Tidy - tidy up dates using '(* *)' comments
>> +#
>> +
>> +def m2Tidy (file):
>> +    handleHeader(file, ' ', ' ')
>> +
>> +#
>> +#  main - for each file extension call the appropriate tidy
>> +#         routine.
>> +#
>> +
>> +def main ():
>> +    visitDir('.', '.in', bashTidy)
>> +    visitDir('.', '.py', bashTidy)
>> +    visitDir('.', '.c', cTidy)
>> +    visitDir('.', '.h', cTidy)
>> +    visitDir('.', '.def', m2Tidy)
>> +    visitDir('.', '.mod', m2Tidy)
>> +
>> +
>> +main ()
>> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/boilerplate.py
>> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
>> +++ gcc-git-devel-modula2/gcc/m2/tools-src/boilerplate.py	2022-10-07 20:21:18.682097332 +0100
>> @@ -0,0 +1,599 @@
>> +#!/usr/bin/env python3
>> +# 
>> +# boilerplate.py utility to rewrite the boilerplate with new dates.
>> +# 
>> +# Copyright (C) 2018-2022 Free Software Foundation, Inc.
>> +# Contributed by Gaius Mulley <gaius@glam.ac.uk>.
>> +# 
>> +# This file is part of GNU Modula-2.
>> +# 
>> +# GNU Modula-2 is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 3, or (at your option)
>> +# any later version.
>> +# 
>> +# GNU Modula-2 is distributed in the hope that it will be useful, but
>> +# WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +# General Public License for more details.
>> +# 
>> +# You should have received a copy of the GNU General Public License
>> +# along with GNU Modula-2; see the file COPYING3.  If not see
>> +# <http://www.gnu.org/licenses/>.
>> +#
>> +import sys
>> +import os
>> +import glob
>> +import sys, getopt, string
>> +import datetime
>> +
>> +forceGPL3x, forceGPL3 = False, False
>> +doModify, verbose = True, False,
>> +multiFilemode, updateAll, forceCheck = False, False, False
>> +
>> +summaryGiven, contributedBy, outputName = "", "", "-"
>> +errorCount = 0
>> +startDir = "."
>> +seenFiles = []
>> +
>> +
>> +#
>> +#  printf - keeps C programmers happy :-)
>> +#
>> +
>> +def printf (fmt, *args):
>> +    print(str (fmt) % args, end=' ')
>> +
>> +#
>> +#  error - issue an error message.
>> +#
>> +
>> +def error (fmt, *args):
>> +    global errorCount
>> +
>> +    print(str (fmt) % args, end=' ')
>> +    errorCount += 1
>> +
>> +
>> +def haltOnError ():
>> +    if errorCount > 0:
>> +        os.sys.exit (1)
>> +
>> +
>> +def basename (f):
>> +    b = f.split ("/")
>> +    return b[-1]
>> +
>> +
>> +#
>> +#  analyseComment -
>> +#
>> +
>> +def analyseComment (text, f):
>> +    start_date, end_date, contribution, summary, lic = None, None, None, None, None
>> +    if text.find ("Copyright ISO/IEC") > 0:
>> +        lic = "BSISO"
>> +        now = datetime.datetime.now ()
>> +        for d in range (1984, now.year+1):
>> +            if text.find (str (d)) > 0:
>> +                if start_date == None:
>> +                    start_date = str (d)
>> +                end_date = str (d)
>> +        return start_date, end_date, "", "", lic
>> +    elif text.find ("Copyright (C)") > 0:
>
> better 'Copyright (C)' in text, similarly at other places ..
>
>> +        if text.find ("GNU General Public License") > 0:
>> +            lic = "GPL"
>> +        elif text.find ("GNU Lesser General") > 0:
>> +            lic = "LGPL"
>> +        if text.find ("version 2.1") > 0:
>> +            lic += "v2.1"
>> +        elif text.find ("version 2") > 0:
>> +            lic += "v2"
>> +        elif text.find ("version 3") > 0:
>> +            lic += "v3"
>> +        if text.find ("GCC Runtime Library Exception") > 0:
>> +            lic += "x"
>> +        now = datetime.datetime.now ()
>> +        for d in range (1984, now.year+1):
>> +            if text.find (str (d)) > 0:
>> +                if start_date == None:
>> +                    start_date = str (d)
>> +                end_date = str (d)
>> +        if text.find ("ontributed by") > 0:
>> +            i = text.find ("ontributed by")
>> +            i += len ("ontributed by")
>> +            j = text.index (". ", i)
>> +            contribution = text[i:j]
>> +    if text.find (basename (f)) > 0:
>> +        i = text.find (basename (f))
>> +        j = text.find (". ", i)
>> +        if j < 0:
>> +            error ('summary of the file does not finish with a "."')
>> +            summary = text[i:]
>> +        else:
>> +            summary = text[i:j]
>> +    return start_date, end_date, contribution, summary, lic
>> +
>> +
>> +#
>> +#  analyseHeader -
>> +#
>> +
>> +def analyseHeader (f, start, end):
>> +    text = ""
>> +    if end == None:
>> +        for count, l in enumerate (open (f, "r").readlines ()):
>> +            parts = l.split (start)
>> +            if len (parts) > 1:
>> +                line = start.join (parts[1:])
>> +                line = line.rstrip ()
>> +                line = line.lstrip ()
>
> line = line.strip()
>
>> +                text += " "
>> +                text += line
>> +            elif (l.rstrip () != "") and (len (parts[0]) > 0):
>> +                return analyseComment (text, f), count
>> +    else:
>> +        inComment = False
>> +        for count, l in enumerate (open (f, "r").readlines ()):
>
> 'r' is default
>
>> +            while l != "":
>> +                l = l.strip ()
>> +                l = l.rstrip ()
>> +                if inComment:
>> +                    text += " "
>> +                    pos = l.find (end)
>
> better use https://docs.python.org/3/library/stdtypes.html?highlight=partition#str.partition
>
>> +                    if pos >= 0:
>> +                        text += l[:pos]
>> +                        l = l[pos:]
>> +                        inComment = False
>> +                    else:
>> +                        text += l
>> +                        l = ""
>> +                else:
>> +                    pos = l.find (start)
>> +                    if (pos >= 0) and (len (l) > len (start)):
>> +                        before = l[:pos]
>> +                        before = before.rstrip ()
>> +                        before = before.lstrip ()
>> +                        if before != "":
>> +                            return analyseComment (text, f), count
>> +                        l = l[pos + len (start):]
>> +                        inComment = True
>> +                    elif (l != "") and (l == end):
>> +                        l = ""
>> +                    else:
>> +                        return analyseComment (text, f), count
>> +    return [None, None, None, None, None], 0
>> +
>> +
>> +#
>> +#  addStop - add a full stop to a sentance.
>> +#
>> +
>> +def addStop (sentence):
>> +    if sentence is None:
>> +        return None
>> +    sentence = sentence.rstrip ()
>> +    if (len (sentence) > 0) and (sentence[-1] != "."):
>> +        return sentence + "."
>> +    return sentence
>> +
>> +
>> +GPLv3 = """
>> +%s
>> +
>> +Copyright (C) %s Free Software Foundation, Inc.
>> +Contributed by %s
>> +
>> +This file is part of GNU Modula-2.
>> +
>> +GNU Modula-2 is free software; you can redistribute it and/or modify
>> +it under the terms of the GNU General Public License as published by
>> +the Free Software Foundation; either version 3, or (at your option)
>> +any later version.
>> +
>> +GNU Modula-2 is distributed in the hope that it will be useful, but
>> +WITHOUT ANY WARRANTY; without even the implied warranty of
>> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +General Public License for more details.
>> +
>> +You should have received a copy of the GNU General Public License
>> +along with GNU Modula-2; see the file COPYING3.  If not see
>> +<http://www.gnu.org/licenses/>.
>> +"""
>> +
>> +GPLv3x = """
>> +%s
>> +
>> +Copyright (C) %s Free Software Foundation, Inc.
>> +Contributed by %s
>> +
>> +This file is part of GNU Modula-2.
>> +
>> +GNU Modula-2 is free software; you can redistribute it and/or modify
>> +it under the terms of the GNU General Public License as published by
>> +the Free Software Foundation; either version 3, or (at your option)
>> +any later version.
>> +
>> +GNU Modula-2 is distributed in the hope that it will be useful, but
>> +WITHOUT ANY WARRANTY; without even the implied warranty of
>> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +General Public License for more details.
>> +
>> +Under Section 7 of GPL version 3, you are granted additional
>> +permissions described in the GCC Runtime Library Exception, version
>> +3.1, as published by the Free Software Foundation.
>> +
>> +You should have received a copy of the GNU General Public License and
>> +a copy of the GCC Runtime Library Exception along with this program;
>> +see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>> +<http://www.gnu.org/licenses/>.
>> +"""
>> +
>> +LGPLv3 = """
>> +%s
>> +
>> +Copyright (C) %s Free Software Foundation, Inc.
>> +Contributed by %s
>> +
>> +This file is part of GNU Modula-2.
>> +
>> +GNU Modula-2 is free software: you can redistribute it and/or modify
>> +it under the terms of the GNU Lesser General Public License as
>> +published by the Free Software Foundation, either version 3 of the
>> +License, or (at your option) any later version.
>> +
>> +GNU Modula-2 is distributed in the hope that it will be useful, but
>> +WITHOUT ANY WARRANTY; without even the implied warranty of
>> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +Lesser General Public License for more details.
>> +
>> +You should have received a copy of the GNU Lesser General Public License
>> +along with GNU Modula-2.  If not, see <https://www.gnu.org/licenses/>.
>> +"""
>> +
>> +BSISO = """
>> +Library module defined by the International Standard
>> +   Information technology - programming languages
>> +   BS ISO/IEC 10514-1:1996E Part 1: Modula-2, Base Language.
>> +
>> +   Copyright ISO/IEC (International Organization for Standardization
>> +   and International Electrotechnical Commission) %s.
>> +
>> +   It may be freely copied for the purpose of implementation (see page
>> +   707 of the Information technology - Programming languages Part 1:
>> +   Modula-2, Base Language.  BS ISO/IEC 10514-1:1996).
>> +"""
>> +
>> +templates = { "GPLv3":GPLv3,
>> +              "GPLv3x":GPLv3x,
>> +              "LGPLv3":LGPLv3,
>> +              "LGPLv2.1":LGPLv3,
>> +              "BSISO":BSISO }
>> +
>> +
>> +def writeTemplate (fo, magic, start, end, dates, contribution, summary, lic):
>> +    if lic in templates:
>> +        if lic == "BSISO":
>> +            # non gpl but freely distributed for the implementation of a compiler
>> +            text = templates[lic] % (dates)
>> +            text = text.rstrip ()
>> +        else:
>> +            summary = summary.lstrip ()
>> +            contribution = contribution.lstrip ()
>> +            summary = addStop (summary)
>> +            contribution = addStop (contribution)
>> +            if magic != None:
>> +                fo.write (magic)
>> +                fo.write ("\n")
>> +            text = templates[lic] % (summary, dates, contribution)
>> +            text = text.rstrip ()
>> +        if end == None:
>> +            text = text.split ("\n")
>> +            for line in text:
>> +                fo.write (start)
>> +                fo.write (" ")
>> +                fo.write (line)
>> +                fo.write ("\n")
>> +        else:
>> +            text = text.lstrip ()
>> +            fo.write (start)
>> +            fo.write (" ")
>> +            fo.write (text)
>> +            fo.write ("  ")
>> +            fo.write (end)
>> +            fo.write ("\n")
>> +        # add a blank comment line for a script for eye candy.
>> +        if start == "#" and end == None:
>> +            fo.write (start)
>> +            fo.write ("\n")
>> +    else:
>> +        error ("no template found for: %s\n", lic)
>> +        os.sys.exit (1)
>> +    return fo
>> +
>> +
>> +def writeBoilerPlate (fo, magic, start, end, start_date, end_date, contribution, summary, gpl):
>> +    if start_date == end_date:
>> +        dates = start_date
>> +    else:
>> +        dates = "%s-%s" % (start_date, end_date)
>> +    return writeTemplate (fo, magic, start, end, dates, contribution, summary, gpl)
>> +
>> +
>> +def rewriteFile (f, magic, start, end, start_date, end_date, contribution, summary, gpl, lines):
>> +    l = open (f, "r").readlines ()[lines:]
>> +    text = "".join (l)
>> +    if outputName == "-":
>> +        fo = sys.stdout
>> +    else:
>> +        fo = open (f, "w")
>> +    fo = writeBoilerPlate (fo, magic, start, end, start_date, end_date, contribution, summary, gpl)
>> +    fo.write (text)
>> +    fo.flush ()
>> +    if outputName != "-":
>> +        fo.close ()
>> +
>> +
>> +#
>> +#  handleHeader - keep reading lines of file, f, looking for start, end
>> +#                 sequences and comments inside.  The comments are checked
>> +#                 for:  date, contribution, summary
>> +#
>> +
>> +def handleHeader (f, magic, start, end):
>> +    global date, contribution, summary, doModify, forceCheck, errorCount
>> +
>> +    errorCount = 0
>> +    [start_date, end_date, contribution, summary, lic], lines =  analyseHeader (f, start, end)
>> +    if lic == None:
>> +        error ("%s:1:no GPL found at the top of the file\n", f)
>> +    else:
>> +        if verbose:
>> +            printf ("copyright: %s\n", lic)
>
> f-string format might be better, but that's just a hint:
> https://docs.python.org/3/reference/lexical_analysis.html#f-strings
>
>> +            if (start_date != None) and (end_date != None):
>> +                if start_date == end_date:
>> +                    printf ("dates = %s\n", start_date)
>> +                else:
>> +                    printf ("dates = %s-%s\n", start_date, end_date)
>> +            if summary != None:
>> +                printf ("summary: %s\n", summary)
>> +            if contribution != None:
>> +                printf ("contribution: %s\n", contribution)
>> +        if start_date == None:
>
> I prefer 'if not start_date' (simiarly at other places).
>
>> +            error ("%s:1:no date found in the GPL at the top of the file\n", f)
>> +        if contribution == None:
>> +            if contributedBy == "":
>> +                error ("%s:1:no contribution found in the GPL at the top of the file\n", f)
>> +            else:
>> +                contribution = contributedBy
>> +        if summary == None:
>> +            if summaryGiven == "":
>> +                error ("%s:1:no single line summary found in the GPL at the top of the file\n", f)
>> +            else:
>> +                summary = summaryGiven
>> +    if errorCount == 0:
>> +        now = datetime.datetime.now ()
>> +        if doModify:
>> +            if lic == "BSISO":
>> +                # don't change the BS ISO license!
>> +                pass
>> +            elif forceGPL3x:
>> +                lic = "GPLv3x"
>> +            elif forceGPL3:
>> +                lic = "GPLv3"
>> +            rewriteFile (f, magic, start, end, start_date, str (now.year), contribution, summary, lic, lines)
>> +        elif forceCheck:
>> +            print(f, "suppressing change as requested", start_date, end_date, lic)
>> +    else:
>> +        printf ("too many errors, no modifications will occur\n")
>> +
>> +
>> +#
>> +#  bashTidy - tidy up dates using '#' comment
>> +#
>> +
>> +def bashTidy (f):
>> +    handleHeader (f, "#!/bin/bash", "#", None)
>> +
>> +
>> +#
>> +#  pythonTidy - tidy up dates using '#' comment
>> +#
>> +
>> +def pythonTidy (f):
>> +    handleHeader (f, "#!/usr/bin/env python3", '#', None)
>> +
>> +
>> +#
>> +#  bnfTidy - tidy up dates using '--' comment
>> +#
>> +
>> +def bnfTidy (f):
>> +    handleHeader (f, None, '--', None)
>> +
>> +
>> +#
>> +#  cTidy - tidy up dates using '/* */' comments
>> +#
>> +
>> +def cTidy (f):
>> +    handleHeader (f, None, '/*', '*/')
>> +
>> +#
>> +#  m2Tidy - tidy up dates using '(* *)' comments
>> +#
>> +
>> +def m2Tidy (f):
>> +    handleHeader (f, None, '(*', '*)')
>> +
>> +#
>> +#  inTidy - tidy up dates using '#' as a comment and check the first line for magic number.
>> +#
>> +
>> +def inTidy (f):
>> +    first = open (f, "r").readlines ()[0]
>> +    if (len (first) > 0) and (first[:2] == "#!"):
>> +        # magic number found, use this
>> +        handleHeader (f, first, "#", None)
>> +    else:
>> +        handleHeader (f, None, "#", None)
>> +
>> +
>> +#
>> +#  doVisit -
>> +#
>> +
>> +def doVisit (args, dirname, names):
>> +    global outputName
>> +    func, extension = args
>> +    for f in names:
>> +        if len (f) > len (extension) and f[-len (extension):] == extension:
>> +            # print os.path.join (dirname, f)
>> +            outputName = f
>> +            func (os.path.join (dirname, f))
>> +
>> +
>> +#
>> +#  visitDir - visit
>> +#
>> +
>> +def visitDir (startDir, extension, func):
>> +    global outputName, seenFiles
>> +    # os.walk (startDir, doVisit, [func, extension])
>> +    for dirName, subdirList, fileList in os.walk(startDir):
>> +        for fname in fileList:
>> +            if (len (fname) > len (extension)) and (fname[-len(extension):] == extension):
>
> Path(...).stem again would be better.
>
>> +                fullpath = os.path.join (dirName, fname)
>> +                outputName = fullpath
>> +                # printf ("outputName = %s\n", outputName)
>> +                if not (fullpath in seenFiles):
>> +                    seenFiles += [fullpath]
>> +                    func (fullpath)
>> +            # Remove the first entry in the list of sub-directories
>> +            # if there are any sub-directories present
>> +        if len(subdirList) > 0:
>> +            del subdirList[0]
>> +
>> +#
>> +#  findFiles - for each file extension call the appropriate tidy
>> +#              routine.
>> +#
>> +
>> +def findFiles ():
>> +    visitDir (startDir, '.h.in', cTidy)
>> +    visitDir (startDir, '.in', inTidy)
>> +    visitDir (startDir, '.sh', inTidy)
>> +    visitDir (startDir, '.py', pythonTidy)
>> +    visitDir (startDir, '.c', cTidy)
>> +    visitDir (startDir, '.h', cTidy)
>> +    visitDir (startDir, '.cc', cTidy)
>> +    visitDir (startDir, '.def', m2Tidy)
>> +    visitDir (startDir, '.mod', m2Tidy)
>> +    visitDir (startDir, '.bnf', bnfTidy)
>> +
>> +
>> +#
>> +#  usage - output very brief usage instructions.
>> +#
>> +
>> +def usage (code = 0):
>> +    print("boilerplate [-c contributionstring] [ -s summarystring ] [-d] [-v] [-g] [-x] [-o outputfile] inputfile.c")
>> +    print("  -o outputfile   (this must be before the final inputfile on the command line).")
>> +    print("  -c              a string which will be used as the contribution line.")
>> +    print("  -s              a string which will be used as the summary line.")
>> +    print("  -f              force a check to insist that the contribution, summary and GPL exists.")
>> +    print("  -g              change to GPLv3.")
>> +    print("  -x              change to GPLv3 with GCC runtime extension.")
>> +    print("  -r directory    recusively scan directory for known file extensions (.def, .mod, .c, .h, .py, .in, .sh).")
>> +    print("  -u              update all dates.")
>> +    print("  -v              verbose.")
>> +    print("  -N              do not modify any file")
>> +    os.sys.exit (code)
>
> https://docs.python.org/3/library/argparse.html would be much better, you get arguments parsing for free.
>
>> +
>> +
>> +#
>> +#  handleArguments - check the legal arguments.
>> +#
>> +
>> +def handleArguments ():
>> +    global multiFilemode, contributedBy, updateAll, forceCheck, outputName, verbose, startDir, doModify, forceGPL3, forceGPL3x, summaryGiven
>> +    try:
>> +        optlist, l = getopt.getopt (sys.argv[1:],':c:dfgho:r:s:uvxN')
>> +    except getopt.GetoptError:
>> +        usage (1)
>> +    for opt in optlist:
>> +        if opt[0] == '-c':
>> +            contributedBy = opt[1]
>> +        if opt[0] == '-s':
>> +            summaryGiven = opt[1]
>> +        if opt[0] == '-d':
>> +            debugging = True
>> +        if opt[0] == '-f':
>> +            forceCheck = True
>> +        if opt[0] == '-g':
>> +            forceGPL3 = True
>> +        if opt[0] == '-x':
>> +            forceGPL3x = True
>> +        if opt[0] == '-h':
>> +            usage ()
>> +        if opt[0] == '-r':
>> +            multiFilemode = True
>> +            startDir = opt[1]
>> +        if opt[0] == '-o':
>> +            outputName = opt[1]
>> +        if opt[0] == '-u':
>> +            updateAll = True
>> +        if opt[0] == '-v':
>> +            verbose = True
>> +        if opt[0] == '-N':
>> +            doModify = False
>> +    if l == []:
>> +        return None
>> +    return l[0]
>
> ^^^ this will be done automatically.
>
> Hope it's usefull.
>
> Thanks,
> Martin
>
>> +
>> +
>> +#
>> +#  hasExt - return True if, name, ends with, ext.
>> +#
>> +
>> +def hasExt (name, ext):
>> +    if len (name) > len (ext):
>> +        return name[-len (ext):] == ext
>> +    return False
>> +
>> +
>> +#
>> +#  singleFile - scan the single file for a GPL boilerplate which
>> +#               has a GPL, contribution field and a summary heading.
>> +#
>> +
>> +def singleFile (i):
>> +    if hasExt (i, ".def") or hasExt (i, ".mod"):
>> +        m2Tidy (i)
>> +    elif hasExt (i, ".h") or hasExt (i, ".c") or hasExt (i, ".cc"):
>> +        cTidy (i)
>> +    elif hasExt (i, ".in"):
>> +        inTidy (i)
>> +    elif hasExt (i, ".sh"):
>> +        inTidy (i)  # uses magic number for actual sh/bash
>> +    elif hasExt (i, ".py"):
>> +        pythonTidy (i)
>> +
>> +
>> +#
>> +#  main - handleArguments and then find source files.
>> +#
>> +
>> +def main ():
>> +    i = handleArguments ()
>> +    if multiFilemode:
>> +        findFiles ()
>> +    elif i == None:
>> +        print("an input file must be specified on the command line")
>> +        usage (1)
>> +    else:
>> +        singleFile (i)
>> +    haltOnError ()
>> +
>> +
>> +main ()
>> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/buildpg
>> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
>> +++ gcc-git-devel-modula2/gcc/m2/tools-src/buildpg	2022-10-07 20:21:18.682097332 +0100
>> @@ -0,0 +1,289 @@
>> +#!/bin/sh
>> +
>> +# Copyright (C) 2000-2022 Free Software Foundation, Inc.
>> +# This file is part of GNU Modula-2.
>> +#
>> +# GNU Modula-2 is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 3, or (at your option)
>> +# any later version.
>> +#
>> +# GNU Modula-2 is distributed in the hope that it will be useful,
>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +# GNU General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License
>> +# along with GNU Modula-2; see the file COPYING.  If not, write to the
>> +# Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
>> +# 02110-1301, USA.
>> +#
>> +
>> +# builds the pg.bnf from ppg.mod
>> +# usage buildpg ppg.mod destination [-e]
>> +#    -e   build without error recovery
>> +#
>> +PPGSRC=$1
>> +PPGDST=$2
>> +
>> +includeNonErrorChecking () {
>> +   sed -e "1,/StartNonErrorChecking/d" < $PPGSRC |\
>> +   sed -e "1,/EndNonErrorChecking/!d"
>> +}
>> +
>> +includeErrorChecking () {
>> +   sed -e "1,/StartErrorChecking/d" < $PPGSRC |\
>> +   sed -e "1,/EndErrorChecking/!d"
>> +}
>> +
>> +
>> +echo "% module" $PPGDST "begin"
>> +sed -e "1,/% declaration/!d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g"
>> +
>> +echo "% declaration" $PPGDST "begin"
>> +
>> +sed -e "1,/% declaration/d" < $PPGSRC | sed -e "1,/% rules/!d" | sed -e "s/ppg/${PPGDST}/g"
>> +
>> +if [ "$3" = "-e" ] ; then
>> +   includeNonErrorChecking
>> +   echo "% module" $PPGDST "end"
>> +   sed -e "1,/% module pg end/d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g"
>> +else
>> +   includeErrorChecking
>> +   echo "% module" $PPGDST "end"
>> +   sed -e "1,/% module pg end/d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g" |\
>> +   sed -e "s/WasNoError := Main() ;/Main({eoftok}) ;/"
>> +fi
>> +
>> +echo "% rules"
>> +
>> +cat << EOFEOF  | sed -e "s/ppg/${PPGDST}/g"
>> +error       'WarnError' 'WarnString'
>> +tokenfunc   'GetCurrentTokenType()'
>> +
>> +token   'identifier'  identtok      -- internal token
>> +token   'literal'     literaltok
>> +token   '%'           codetok
>> +token   ':='          lbecomestok
>> +token   '=:'          rbecomestok
>> +token   '|'           bartok
>> +token   '['           lsparatok
>> +token   ']'           rsparatok
>> +token   '{'           lcparatok   -- left  curly para
>> +token   '}'           rcparatok   -- right curly para
>> +token   '('           lparatok
>> +token   ')'           rparatok
>> +token   "error"       errortok
>> +token   "tokenfunc"   tfunctok
>> +token   "symfunc"     symfunctok
>> +token   '"'           dquotetok
>> +token   "'"           squotetok
>> +token   "module"      moduletok
>> +token   "begin"       begintok
>> +token   "rules"       rulestok
>> +token   "end"         endtok
>> +token   '<'           lesstok
>> +token   '>'           gretok
>> +token   "token"       tokentok
>> +token   "special"     specialtok
>> +token   "first"       firsttok
>> +token   "follow"      followtok
>> +token   "BNF"         BNFtok
>> +token   "FNB"         FNBtok
>> +token   "declaration" declarationtok
>> +token   "epsilon"     epsilontok
>> +token   ''            eoftok      -- internal token
>> +
>> +special Ident          first { < identtok > }   follow { }
>> +special Modula2Code    first { }                follow { '%' }
>> +special StartModName   first { < identtok > }   follow { }
>> +special EndModName     first { < identtok > }   follow { }
>> +special DoDeclaration  first { < identtok > }   follow { }
>> +special CollectLiteral first { < literaltok > } follow { }
>> +special CollectTok     first { < identtok > }   follow { }
>> +special DefineToken    first { < identtok > }   follow { }
>> +
>> +BNF
>> +
>> +Rules      := "%" "rules" { Defs } ExtBNF =:
>> +
>> +Special    := Ident
>> +              % VAR p: ProductionDesc ; %
>> +              %     p                           := NewProduction() ;
>> +                    p^.statement                := NewStatement() ;
>> +                    p^.statement^.followinfo^.calcfollow := TRUE ;
>> +                    p^.statement^.followinfo^.epsilon    := false ;
>> +                    p^.statement^.followinfo^.reachend   := false ;
>> +                    p^.statement^.ident         := CurrentIdent ;
>> +                    p^.statement^.expr          := NIL ;
>> +                    p^.firstsolved              := TRUE ;
>> +                    p^.followinfo^.calcfollow   := TRUE ;
>> +                    p^.followinfo^.epsilon      := false ;
>> +                    p^.followinfo^.reachend     := false %
>> +              First Follow [ "epsilon" % p^.statement^.followinfo^.epsilon  := true ;  (* these are not used - but they are displayed when debugging *)
>> +                                         p^.statement^.followinfo^.reachend := true ;
>> +                                         p^.followinfo^.epsilon  := true ;
>> +                                         p^.followinfo^.reachend := true
>> +                                       % ]
>> +              [ Literal % p^.description := LastLiteral % ]
>> +              =:
>> +
>> +Factor     := "%" Modula2Code "%" |
>> +              Ident % WITH CurrentFactor^ DO
>> +                         type  := id ;
>> +                         ident := CurrentIdent
>> +                      END ; % |
>> +              Literal % WITH CurrentFactor^ DO
>> +                           type   := lit ;
>> +                           string := LastLiteral ;
>> +                           IF GetSymKey(Aliases, LastLiteral)=NulName
>> +                           THEN
>> +                              WarnError1('no token defined for literal %s', LastLiteral)
>> +                           END
>> +                        END ; % |
>> +              "{" % WITH CurrentFactor^ DO
>> +                       type := mult ;
>> +                       expr := NewExpression() ;
>> +                       CurrentExpression := expr ;
>> +                    END ; %
>> +                    Expression "}" |
>> +              "[" % WITH CurrentFactor^ DO
>> +                       type := opt ;
>> +                       expr := NewExpression() ;
>> +                       CurrentExpression := expr ;
>> +                    END ; %
>> +                    Expression "]" |
>> +              "(" % WITH CurrentFactor^ DO
>> +                       type := sub ;
>> +                       expr := NewExpression() ;
>> +                       CurrentExpression := expr ;
>> +                    END ; %
>> +                    Expression ")" =:
>> +
>> +Statement  := % VAR i: IdentDesc ; %
>> +              Ident
>> +              % VAR p: ProductionDesc ; %
>> +              % p := FindDefinition(CurrentIdent^.name) ;
>> +                IF p=NIL
>> +                THEN
>> +                   p := NewProduction()
>> +                ELSE
>> +                   IF NOT ((p^.statement=NIL) OR (p^.statement^.expr=NIL))
>> +                   THEN
>> +                      WarnError1('already declared rule %s', CurrentIdent^.name)
>> +                   END
>> +                END ;
>> +                i := CurrentIdent ; %
>> +              ":="
>> +              % VAR e: ExpressionDesc ; %
>> +              % e := NewExpression() ;
>> +                CurrentExpression := e ; %
>> +              % VAR s: StatementDesc ; %
>> +              % s := NewStatement() ;
>> +                WITH s^ DO
>> +                   ident := i ;
>> +                   expr  := e
>> +                END ; %
>> +              Expression
>> +              % p^.statement := s ; %
>> +              "=:" =:
>> +
>> +Defs       := "special" Special | "token" Token | "error" ErrorProcedures |
>> +              "tokenfunc" TokenProcedure | "symfunc" SymProcedure =:
>> +ExtBNF     := "BNF" { Production } "FNB" =:
>> +Main       := Header Decls Footer Rules =:
>> +Header     := "%" "module" StartModName =:
>> +Decls      := "%" "declaration" DoDeclaration =:
>> +Footer     := "%" "module" EndModName =:
>> +
>> +First      := "first"  "{" { LitOrTokenOrIdent
>> +                             % WITH CurrentSetDesc^ DO
>> +                                  next := TailProduction^.first ;
>> +                               END ;
>> +                               TailProduction^.first := CurrentSetDesc
>> +                             %
>> +                           } "}" =:
>> +Follow     := "follow" "{" { LitOrTokenOrIdent
>> +                             % WITH CurrentSetDesc^ DO
>> +                                  next := TailProduction^.followinfo^.follow ;
>> +                               END ;
>> +                               TailProduction^.followinfo^.follow := CurrentSetDesc
>> +                             %
>> +                           } "}" =:
>> +LitOrTokenOrIdent := Literal % CurrentSetDesc := NewSetDesc() ;
>> +                               WITH CurrentSetDesc^ DO
>> +                                  type   := litel ;
>> +                                  string := LastLiteral ;
>> +                               END ;
>> +                              % |
>> +                     '<' CollectTok '>' |
>> +                     Ident % CurrentSetDesc := NewSetDesc() ;
>> +                             WITH CurrentSetDesc^ DO
>> +                                type   := idel ;
>> +                                ident  := CurrentIdent ;
>> +                             END ;
>> +                           % =:
>> +
>> +Literal    := '"' CollectLiteral '"' |
>> +              "'" CollectLiteral "'" =:
>> +
>> +CollectTok := % CurrentSetDesc := NewSetDesc() ;
>> +                WITH CurrentSetDesc^ DO
>> +                   type   := tokel ;
>> +                   string := GetCurrentToken() ;
>> +                END ;
>> +                IF NOT ContainsSymKey(Values, GetCurrentToken())
>> +                THEN
>> +                   AddEntry(Values, GetCurrentToken(), LargestValue) ;
>> +                   AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
>> +                   AddEntry(Aliases, GetCurrentToken(), GetCurrentToken()) ;
>> +                   AddEntry(ReverseAliases, GetCurrentToken(), GetCurrentToken()) ;
>> +                   INC(LargestValue)
>> +                END ;
>> +                AdvanceToken() ; % =:
>> +
>> +CollectLiteral := % LastLiteral := GetCurrentToken() ;
>> +                    AdvanceToken ; % =:
>> +
>> +DefineToken := %  AddEntry(Aliases, LastLiteral, GetCurrentToken()) ;
>> +                  AddEntry(ReverseAliases, GetCurrentToken(), LastLiteral) ;
>> +                  AddEntry(Values, GetCurrentToken(), LargestValue) ;
>> +                  AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
>> +                  INC(LargestValue) ;
>> +                  AdvanceToken ; % =:
>> +
>> +Token      := Literal DefineToken =:
>> +
>> +ErrorProcedures  := Literal % ErrorProcArray := LastLiteral %
>> +                    Literal % ErrorProcString := LastLiteral % =:
>> +TokenProcedure := Literal % TokenTypeProc := LastLiteral % =:
>> +SymProcedure   := Literal % SymIsProc := LastLiteral % =:
>> +
>> +Production := Statement =:
>> +Expression := % VAR t1, t2: TermDesc ;
>> +                    e     : ExpressionDesc ; %
>> +              % e := CurrentExpression ;
>> +                t1 := NewTerm() ;
>> +                CurrentTerm := t1 ; %
>> +                Term % e^.term := t1 ; %
>> +                { "|" % t2 := NewTerm() ;
>> +                        CurrentTerm := t2 %
>> +                        Term % t1^.next := t2 ;
>> +                               t1 := t2 % } =:
>> +
>> +Term       := % VAR    t1: TermDesc ; f1, f2: FactorDesc ; %
>> +              % CurrentFactor := NewFactor() ;
>> +                f1 := CurrentFactor ;
>> +                t1 := CurrentTerm ; %
>> +              Factor % t1^.factor := f1 ;
>> +                       f2 := NewFactor() ;
>> +                       CurrentFactor := f2 %
>> +              { Factor % f1^.next := f2 ;
>> +                         f1 := f2 ;
>> +                         f2 := NewFactor() ;
>> +                         CurrentFactor := f2 ; % }
>> +           =:
>> +
>> +FNB
>> +
>> +EOFEOF
>> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/calcpath
>> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
>> +++ gcc-git-devel-modula2/gcc/m2/tools-src/calcpath	2022-10-07 20:21:18.682097332 +0100
>> @@ -0,0 +1,51 @@
>> +#!/bin/sh
>> +
>> +# calcpath return a path which is $1/$2/$3 when $2 is relative and $2/$3 if absolute.
>> +
>> +# Copyright (C) 2021-2022 Free Software Foundation, Inc.
>> +# Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
>> +#
>> +# This file is part of GNU Modula-2.
>> +#
>> +# GNU Modula-2 is free software; you can redistribute it and/or modify it under
>> +# the terms of the GNU General Public License as published by the Free
>> +# Software Foundation; either version 3, or (at your option) any later
>> +# version.
>> +#
>> +# GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY
>> +# WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>> +# for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License along
>> +# with gm2; see the file COPYING.  If not, write to the Free Software
>> +# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *)
>> +
>> +
>> +Usage () {
>> +   echo "Usage: calcpath pathcomponent1 pathcomponent2 subdir"
>> +   echo -n "  if pathcomponent1 is relative then pathcomponent1/pathcomponet2/subdir is"
>> +   echo " returned"
>> +   echo "  otherwise pathcomponet2/subdir is returned"
>> +   echo "  the path is checked for legality in subdir."
>> +}
>> +
>> +
>> +if [ $# -eq 3 ]; then
>> +   if [ "$(echo $2 | cut -b 1)" = "." ] ; then
>> +       # relative path
>> +       the_path=$1/$2/$3
>> +   else
>> +       the_path=$2/$3
>> +   fi
>> +   cd $3
>> +   if realpath ${the_path} > /dev/null ; then
>> +       echo ${the_path}
>> +   else
>> +       echo "calcpath: error ${the_path} is not a valid path in subdirectory $3" 1>&2
>> +       exit 1
>> +   fi
>> +else
>> +   Usage
>> +   exit 1
>> +fi
>> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/makeSystem
>> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
>> +++ gcc-git-devel-modula2/gcc/m2/tools-src/makeSystem	2022-10-07 20:21:18.682097332 +0100
>> @@ -0,0 +1,108 @@
>> +#!/bin/sh
>> +
>> +# makeSystem creates a target SYSTEM.def using the appropriate dialect template.
>> +
>> +# Copyright (C) 2008-2022 Free Software Foundation, Inc.
>> +# Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
>> +#
>> +# This file is part of GNU Modula-2.
>> +#
>> +# GNU Modula-2 is free software; you can redistribute it and/or modify it under
>> +# the terms of the GNU General Public License as published by the Free
>> +# Software Foundation; either version 3, or (at your option) any later
>> +# version.
>> +#
>> +# GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY
>> +# WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>> +# for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License along
>> +# with gm2; see the file COPYING.  If not, write to the Free Software
>> +# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *)
>> +
>> +
>> +Usage () {
>> +   echo "Usage: makesystem dialectflag SYSTEM.def SYSTEM.mod librarypath compiler"
>> +}
>> +
>> +if [ $# -lt 6 ] ; then
>> +   Usage
>> +   exit 1
>> +fi
>> +
>> +DIALECT=$1
>> +SYSTEMDEF=$2
>> +SYSTEMMOD=$3
>> +LIBRARY=$4
>> +COMPILER=$5
>> +OUTPUTFILE=$6
>> +
>> +if [ "$COMPILER" = "" ] ; then
>> +    echo "parameter 5 of makeSystem is incorrect, GM2_FOR_TARGET was unset"
>> +    exit 1
>> +fi
>> +
>> +if [ "$DIALECT" != "-fiso" -a "$DIALECT" != "-fpim" ] ; then
>> +   Usage
>> +   echo "dialect must be -fiso or -fpim"
>> +   exit 1
>> +fi
>> +
>> +displayExportedTypes () {
>> +   n=1
>> +   c=0
>> +   for i in ${types} ; do
>> +      if [ $n -eq 1 ] ; then
>> +          n=0
>> +          echo -n "                 " >> ${OUTPUTFILE}
>> +      fi
>> +      echo -n "$i, " >> ${OUTPUTFILE}
>> +      if [ $c -eq 4 ] ; then
>> +          echo " " >> ${OUTPUTFILE}
>> +          n=1
>> +          c=0
>> +      fi
>> +      c=`expr $c + 1`
>> +   done
>> +   echo " " >> ${OUTPUTFILE}
>> +}
>> +
>> +displayBuiltinTypes () {
>> +   for i in ${types} ; do
>> +      echo "   $i ; " >> ${OUTPUTFILE}
>> +   done
>> +}
>> +
>> +displayStart () {
>> +   sed -e "1,/@SYSTEM_DATATYPES@/!d" < ${SYSTEMDEF} | \
>> +   sed -e "/@SYSTEM_DATATYPES@/d" >> ${OUTPUTFILE}
>> +}
>> +
>> +displayMiddle () {
>> +   sed -e "1,/@SYSTEM_DATATYPES@/d" < ${SYSTEMDEF} | \
>> +   sed -e "1,/@SYSTEM_TYPES@/!d" | \
>> +   sed -e "/@SYSTEM_TYPES@/d" >> ${OUTPUTFILE}
>> +}
>> +
>> +displayEnd () {
>> +   sed -e "1,/@SYSTEM_TYPES@/d" < ${SYSTEMDEF} >> ${OUTPUTFILE}
>> +}
>> +
>> +MINIMAL="-fno-scaffold-main -fno-scaffold-dynamic -fno-scaffold-static -fno-m2-plugin"
>> +
>> +rm -f ${OUTPUTFILE}
>> +if ${COMPILER} ${DIALECT} ${LIBRARY} ${MINIMAL} \
>> +	       -c -fdump-system-exports ${SYSTEMMOD} -o /dev/null 2>&1 > /dev/null ; then
>> +    types=`${COMPILER} ${DIALECT} ${LIBRARY} ${MINIMAL} -fno-m2-plugin -c -fdump-system-exports ${SYSTEMMOD} -o /dev/null | cut -f5 -d' '`
>> +    touch ${OUTPUTFILE}
>> +    displayStart
>> +    displayExportedTypes
>> +    displayMiddle
>> +    displayBuiltinTypes
>> +    displayEnd
>> +else
>> +    ${COMPILER} ${DIALECT} ${LIBRARY} ${MINIMAL} \
>> +		-c -fdump-system-exports ${SYSTEMMOD} -o /dev/null
>> +    exit $?
>> +fi
>> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/README
>> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
>> +++ gcc-git-devel-modula2/gcc/m2/tools-src/README	2022-10-07 20:21:18.682097332 +0100
>> @@ -0,0 +1,3 @@
>> +This directory contains miscellaneous scripts and programs (mklink.c)
>> +to allow for bootstrap linking and creating library documentation from
>> +sources.
>> \ No newline at end of file
>> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/mklink.c
>> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
>> +++ gcc-git-devel-modula2/gcc/m2/tools-src/mklink.c	2022-10-07 20:21:18.682097332 +0100
>> @@ -0,0 +1,810 @@
>> +/* mklink.c creates startup code and the link command line.
>> +
>> +Copyright (C) 2000-2022 Free Software Foundation, Inc.
>> +Contributed by Gaius Mulley <gaius@glam.ac.uk>.
>> +
>> +This file is part of GNU Modula-2.
>> +
>> +GNU Modula-2 is free software; you can redistribute it and/or modify
>> +it under the terms of the GNU General Public License as published by
>> +the Free Software Foundation; either version 3, or (at your option)
>> +any later version.
>> +
>> +GNU Modula-2 is distributed in the hope that it will be useful, but
>> +WITHOUT ANY WARRANTY; without even the implied warranty of
>> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +General Public License for more details.
>> +
>> +You should have received a copy of the GNU General Public License
>> +along with GNU Modula-2; see the file COPYING3.  If not see
>> +<http://www.gnu.org/licenses/>.  */
>> +
>> +
>> +#include "config.h"
>> +#include "system.h"
>> +
>> +#define MAX_FILE_NAME 8192
>> +#define MAXSTACK 4096
>> +#define STDIN 0
>> +#define STDOUT 1
>> +#define ENDOFILE ((char)-1)
>> +#define ERROR(X) \
>> +  (fprintf (stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) \
>> +   && (fflush (stderr)))
>> +#define DEBUG(X) \
>> +  ((Debug) && (fprintf (stderr, "%s\n", X) && (fflush (stderr))))
>> +
>> +#if !defined(TRUE)
>> +#define TRUE (1 == 1)
>> +#endif
>> +
>> +#if !defined(FALSE)
>> +#define FALSE (1 == 0)
>> +#endif
>> +
>> +typedef struct functlist
>> +{
>> +  char *functname;
>> +  struct functlist *next;
>> +} functList;
>> +
>> +/* Prototypes.  */
>> +
>> +static void ParseFileLinkCommand (void);
>> +static void ParseFileStartup (void);
>> +static void ParseFile (char *Name);
>> +static void ParseComments (void);
>> +static void CopyUntilEof (void);
>> +static void CopyUntilEol (void);
>> +static int IsSym (char *s);
>> +static int SymIs (char *s);
>> +static int FindString (char *String);
>> +static void GetNL (void);
>> +static char GetChar (void);
>> +static void ResetBuffer (void);
>> +static int GetSingleChar (char *ch);
>> +static int InRange (int Element, unsigned int Min, unsigned int Max);
>> +static char PutChar (char ch);
>> +static int IsSpace (char ch);
>> +static void SkipSpaces (void);
>> +static void SkipText (void);
>> +static void SilentSkipSpaces (void);
>> +static void SilentSkipText (void);
>> +static void PushBack (char *s);
>> +static int IsDigit (char ch);
>> +static void GetName (char *Name);
>> +static void OpenOutputFile (void);
>> +static void CloseFile (void);
>> +static void FindSource (char *Name);
>> +static void CopyUntilEolInto (char *Buffer);
>> +static void FindObject (char *Name);
>> +static int IsExists (char *Name);
>> +
>> +/* Global variables.  */
>> +
>> +static char *NameOfFile = NULL;
>> +static const char *NameOfMain = "main";
>> +static int StackPtr = 0;
>> +static char Stack[MAXSTACK];
>> +static int CurrentFile = STDIN;
>> +static int OutputFile;
>> +static int LinkCommandLine = FALSE;
>> +static int ProfilePCommand = FALSE;
>> +static int ProfilePGCommand = FALSE;
>> +static int ExitNeeded = TRUE;
>> +static char *libraries = NULL;
>> +static char *args = NULL;
>> +static functList *head = NULL;
>> +static functList *tail = NULL;
>> +static int langC = FALSE; /* FALSE = C++, TRUE = C.  */
>> +
>> +/* addLibrary - adds libname to the list of libraries to be linked.  */
>> +
>> +static void
>> +addLibrary (char *libname)
>> +{
>> +  if (libraries == NULL)
>> +    libraries = strdup (libname);
>> +  else
>> +    {
>> +      char *old = libraries;
>> +      char *newlib
>> +          = (char *)malloc (strlen (libname) + strlen (libraries) + 1 + 1);
>> +      strcpy (newlib, libraries);
>> +      strcat (newlib, " ");
>> +      strcat (newlib, libname);
>> +      libraries = newlib;
>> +      free (old);
>> +    }
>> +}
>> +
>> +/* addGccArg - adds arg to the list of gcc arguments.  */
>> +
>> +static void
>> +addGccArg (char *arg)
>> +{
>> +  if (args == NULL)
>> +    args = strdup (arg);
>> +  else
>> +    {
>> +      char *old = args;
>> +      char *newarg = (char *)malloc (strlen (old) + strlen (arg) + 1 + 1);
>> +      strcpy (newarg, old);
>> +      strcat (newarg, " ");
>> +      strcat (newarg, arg);
>> +      args = newarg;
>> +      free (old);
>> +    }
>> +}
>> +
>> +int
>> +main (int argc, char *argv[])
>> +{
>> +  int i;
>> +
>> +  if (argc >= 3)
>> +    {
>> +      if (strcmp (argv[1], "-l") == 0)
>> +	LinkCommandLine = TRUE;
>> +      else if (strcmp (argv[1], "-s") == 0)
>> +	LinkCommandLine = FALSE;
>> +      else
>> +        {
>> +          fprintf (stderr, "Usage: mklink (-l|-s) [--langc|--langc++] [--pg|-p] "
>> +                           "[--lib library] [--main name] [--exit] --name "
>> +                           "filename <modulelistfile>\n");
>> +          fprintf (stderr, "       must supply -l or -s option\n");
>> +          exit (1);
>> +        }
>> +      ProfilePCommand = FALSE;
>> +      ProfilePGCommand = FALSE;
>> +      i = 2;
>> +      while (i < argc - 1)
>> +        {
>> +          if (strcmp (argv[i], "--langc++") == 0)
>> +	    langC = FALSE;
>> +          else if (strcmp (argv[i], "--langc") == 0)
>> +	    langC = TRUE;
>> +          else if (strncmp (argv[i], "-f", 2) == 0)
>> +	    addGccArg (argv[i]);
>> +          else if (strcmp (argv[i], "--pg") == 0)
>> +	    ProfilePGCommand = TRUE;
>> +          else if (strcmp (argv[i], "-p") == 0)
>> +	    ProfilePCommand = TRUE;
>> +          else if (strcmp (argv[i], "--exit") == 0)
>> +	    ExitNeeded = FALSE;
>> +          else if (strcmp (argv[i], "--lib") == 0)
>> +            {
>> +              i++;
>> +              addLibrary (argv[i]);
>> +            }
>> +          else if (strcmp (argv[i], "--main") == 0)
>> +            {
>> +              i++;
>> +              NameOfMain = argv[i];
>> +            }
>> +          else if (strcmp (argv[i], "--name") == 0)
>> +            {
>> +              i++;
>> +              NameOfFile = argv[i];
>> +            }
>> +          i++;
>> +        }
>> +      ParseFile (argv[i]);
>> +    }
>> +  else
>> +    {
>> +      fprintf (stderr, "Usage: mklink (-l|-s) [--gcc|--g++] [--pg|-p] [--lib "
>> +                       "library] [--main name] [--exit] --name filename "
>> +                       "<modulelistfile>\n");
>> +      exit (1);
>> +    }
>> +  if (NameOfFile == NULL)
>> +    {
>> +      fprintf (stderr, "mklink must have a --name argument\n");
>> +      fprintf (stderr, "Usage: mklink (-l|-s) [--gcc|--g++] [--pg|-p] [--lib "
>> +                       "library] [--main name] [--exit] --name filename "
>> +                       "<modulelistfile>\n");
>> +      exit (1);
>> +    }
>> +  exit (0);
>> +}
>> +
>> +/* ParseFile - parses the input file and generates the output file.  */
>> +
>> +static void
>> +ParseFile (char *Name)
>> +{
>> +  FindSource (Name);
>> +  OpenOutputFile ();
>> +  if (LinkCommandLine)
>> +    ParseFileLinkCommand ();
>> +  else
>> +    ParseFileStartup ();
>> +  CloseFile ();
>> +}
>> +
>> +/* ParseFileLinkCommand - generates the link command.  */
>> +
>> +static void
>> +ParseFileLinkCommand (void)
>> +{
>> +  char name[MAX_FILE_NAME];
>> +  char *s = NULL;
>> +  char *l = NULL;
>> +  char *c = NULL;
>> +
>> +  s = getenv ("CC");
>> +  if (s == NULL)
>> +    {
>> +      if (langC)
>> +        printf ("gcc -g ");
>> +      else
>> +        printf ("g++ -g ");
>> +    }
>> +  else
>> +    printf ("%s -g ", s);
>> +
>> +  if (args != NULL)
>> +    printf ("%s ", args);
>> +
>> +  l = getenv ("LDFLAGS");
>> +  if (l != NULL)
>> +    printf ("%s ", l);
>> +
>> +  c = getenv ("CFLAGS");
>> +  if (c != NULL)
>> +    printf ("%s ", c);
>> +
>> +  if (ProfilePGCommand)
>> +    printf (" -pg");
>> +  else if (ProfilePCommand)
>> +    printf (" -p");
>> +
>> +  while (PutChar (GetChar ()) != (char)EOF)
>> +    {
>> +      CopyUntilEolInto (name);
>> +#if defined(XENIX)
>> +      name[10] = (char)0; /* truncate object file name.  */
>> +#endif
>> +      if ((strlen (name) > 0) && (name[0] != '#'))
>> +        FindObject (name);
>> +    }
>> +  printf (" %s\n", libraries);
>> +}
>> +
>> +/* FindObject - searches the M2PATH variable to find the object file.
>> +   If it finds the object file it prints it to stdout otherwise it
>> +   writes an error on stderr.  */
>> +
>> +static void
>> +FindObject (char *Name)
>> +{
>> +  char m2search[4096];
>> +  char m2path[4096];
>> +  char name[4096];
>> +  char exist[4096];
>> +  int s, p;
>> +
>> +  if (getenv ("M2PATH") == NULL)
>> +    strcpy (m2path, ".");
>> +  else
>> +    strcpy (m2path, getenv ("M2PATH"));
>> +
>> +  snprintf (name, sizeof (name), "%s.o", Name);
>> +  p = 0;
>> +  while (m2path[p] != (char)0)
>> +    {
>> +      s = 0;
>> +      while ((m2path[p] != (char)0) && (m2path[p] != ' '))
>> +        {
>> +          m2search[s] = m2path[p];
>> +          s++;
>> +          p++;
>> +        }
>> +      if (m2path[p] == ' ')
>> +	p++;
>> +      m2search[s] = (char)0;
>> +      snprintf (exist, sizeof (exist), "%s/%s", m2search, name);
>> +      if (IsExists (exist))
>> +        {
>> +          printf (" %s", exist);
>> +          return;
>> +        }
>> +    }
>> +  fprintf (stderr, "cannot find %s\n", name);
>> +}
>> +
>> +/* IsExists - returns true if a file, Name, exists.  It returns false
>> +   otherwise.  */
>> +
>> +static int
>> +IsExists (char *Name)
>> +{
>> +  struct stat buf;
>> +
>> +  return (stat (Name, &buf) == 0);
>> +}
>> +
>> +/* add_function - adds a name to the list of functions, in order.  */
>> +
>> +void
>> +add_function (char *name)
>> +{
>> +  functList *p = (functList *)malloc (sizeof (functList));
>> +  p->functname = (char *)malloc (strlen (name) + 1);
>> +  strcpy (p->functname, name);
>> +
>> +  if (head == NULL)
>> +    {
>> +      head = p;
>> +      tail = p;
>> +      p->next = NULL;
>> +    }
>> +  else
>> +    {
>> +      tail->next = p;
>> +      tail = p;
>> +      tail->next = NULL;
>> +    }
>> +}
>> +
>> +static void
>> +GenerateInitCalls (functList *p)
>> +{
>> +  while (p != NULL)
>> +    {
>> +      printf ("   _M2_%s_init (argc, argv, envp);\n", p->functname);
>> +      p = p->next;
>> +    }
>> +}
>> +
>> +static void
>> +GenerateFinishCalls (functList *p)
>> +{
>> +  if (p->next != NULL)
>> +    GenerateFinishCalls (p->next);
>> +  printf ("   _M2_%s_finish (argc, argv, envp);\n", p->functname);
>> +}
>> +
>> +static void
>> +GeneratePrototypes (functList *p)
>> +{
>> +  while (p != NULL)
>> +    {
>> +      if (langC)
>> +        {
>> +          printf ("extern void _M2_%s_init (int argc, char *argv[], char *envp[]);\n",
>> +                  p->functname);
>> +          printf ("extern void _M2_%s_finish (int argc, char *argv[], char *envp[]);\n",
>> +                  p->functname);
>> +        }
>> +      else
>> +        {
>> +          printf ("extern \"C\" void _M2_%s_init (int argc, char *argv[], char *envp[]);\n",
>> +                  p->functname);
>> +          printf ("extern \"C\" void _M2_%s_finish (int argc, char *argv[], char *envp[]);\n",
>> +                  p->functname);
>> +        }
>> +      p = p->next;
>> +    }
>> +}
>> +
>> +/* ParseFileStartup - generates the startup code.  */
>> +
>> +static void
>> +ParseFileStartup (void)
>> +{
>> +  char name[MAX_FILE_NAME];
>> +  functList *p;
>> +
>> +  while (PutChar (GetChar ()) != (char)EOF)
>> +    {
>> +      CopyUntilEolInto (name);
>> +      if ((strlen (name) > 0) && (strcmp (name, "mod_init") != 0)
>> +          && (name[0] != '#'))
>> +	add_function (name);
>> +    }
>> +  GeneratePrototypes (head);
>> +  printf ("extern");
>> +  if (!langC)
>> +    printf (" \"C\"");
>> +  printf (" void _exit(int);\n");
>> +
>> +  printf ("\n\nint %s(int argc, char *argv[], char *envp[])\n", NameOfMain);
>> +  printf ("{\n");
>> +  GenerateInitCalls (head);
>> +  GenerateFinishCalls (head);
>> +  if (ExitNeeded)
>> +    printf ("   _exit(0);\n");
>> +  printf ("   return(0);\n");
>> +  printf ("}\n");
>> +}
>> +
>> +/* OpenOutputFile - shut down stdout and open the new mod_init.c */
>> +
>> +static void
>> +OpenOutputFile (void)
>> +{
>> +  if (strcmp (NameOfFile, "-") != 0)
>> +    {
>> +      if (close (STDOUT) != 0)
>> +        {
>> +          ERROR ("Unable to close stdout");
>> +          exit (1);
>> +        }
>> +      OutputFile = creat (NameOfFile, 0666);
>> +      if (OutputFile != STDOUT)
>> +        {
>> +          ERROR ("Expected that the file descriptor should be 1");
>> +        }
>> +    }
>> +}
>> +
>> +/* CloseFile - flush and close the file.  */
>> +
>> +static void
>> +CloseFile (void)
>> +{
>> +#if 0
>> +  fflush(stdout);
>> +  if (close(STDOUT) != 0) {
>> +    ERROR("Unable to close our output file"); exit(1);
>> +  }
>> +#endif
>> +}
>> +
>> +/* CopyUntilEof - copies from the current input marker until ENDOFILE
>> +   is reached.  */
>> +
>> +static void
>> +CopyUntilEof (void)
>> +{
>> +  char ch;
>> +
>> +  while ((ch = GetChar ()) != ENDOFILE)
>> +    putchar (ch);
>> +}
>> +
>> +/* CopyUntilEol - copies from the current input marker until '\n' is
>> +   reached.  */
>> +
>> +static void
>> +CopyUntilEol (void)
>> +{
>> +  char ch;
>> +
>> +  while (((ch = GetChar ()) != '\n') && (ch != (char)EOF))
>> +    putchar (ch);
>> +  if (ch == '\n')
>> +    putchar (ch);
>> +}
>> +
>> +/* CopyUntilEolInto - copies from the current input marker until '\n'
>> +   is reached into a Buffer.  */
>> +
>> +static void
>> +CopyUntilEolInto (char *Buffer)
>> +{
>> +  char ch;
>> +  int i = 0;
>> +
>> +  while (((ch = GetChar ()) != '\n') && (ch != (char)EOF))
>> +    {
>> +      Buffer[i] = ch;
>> +      i++;
>> +    }
>> +  if ((ch == '\n') || (ch == (char)EOF))
>> +    Buffer[i] = (char)0;
>> +}
>> +
>> +/* IsSym - returns true if string, s, was found in the input stream.
>> +   The input stream is uneffected.  */
>> +
>> +static int
>> +IsSym (char *s)
>> +{
>> +  int i = 0;
>> +
>> +  while ((s[i] != (char)0) && (s[i] == PutChar (GetChar ())))
>> +    {
>> +      GetChar ();
>> +      i++;
>> +    }
>> +  if (s[i] == (char)0)
>> +    {
>> +      PushBack (s);
>> +      /* found s in input string.  */
>> +      return (TRUE);
>> +    }
>> +  else
>> +    {
>> +      /* push back the characters we have scanned.  */
>> +      if (i > 0)
>> +        {
>> +          do
>> +            {
>> +              i--;
>> +              PutChar (s[i]);
>> +            }
>> +          while (i > 0);
>> +        }
>> +      return (FALSE);
>> +    }
>> +}
>> +
>> +/* SymIs - returns true if string, s, was found in the input stream.
>> +   The token s is consumed from the input stream.  */
>> +
>> +static int
>> +SymIs (char *s)
>> +{
>> +  int i = 0;
>> +
>> +  while ((s[i] != (char)0) && (s[i] == PutChar (GetChar ())))
>> +    {
>> +      GetChar ();
>> +      i++;
>> +    }
>> +  if (s[i] == (char)0)
>> +    {
>> +      /* found s in input string.  */
>> +      return (TRUE);
>> +    }
>> +  else
>> +    {
>> +      /* push back the characters we have scanned.  */
>> +      if (i > 0)
>> +        {
>> +          do
>> +            {
>> +              i--;
>> +              PutChar (s[i]);
>> +            }
>> +          while (i > 0);
>> +        }
>> +      return (FALSE);
>> +    }
>> +}
>> +
>> +/* FindString - keeps on reading input until a string, String, is
>> +   matched.  If end of file is reached then FALSE is returned, otherwise
>> +   TRUE is returned.  */
>> +
>> +static int
>> +FindString (char *String)
>> +{
>> +  int StringIndex = 0;
>> +  int Found = FALSE;
>> +  int eof = FALSE;
>> +  char ch;
>> +
>> +  while ((!Found) && (!eof))
>> +    {
>> +      if (String[StringIndex] == (char)0)
>> +	/* must have found string.  */
>> +	Found = TRUE;
>> +      else
>> +        {
>> +          ch = GetChar ();
>> +          eof = (ch == ENDOFILE);
>> +          if (ch == String[StringIndex])
>> +	    StringIndex++;
>> +          else
>> +	    StringIndex = 0;
>> +        }
>> +    }
>> +  return (Found);
>> +}
>> +
>> +/* GetNL - keeps on reading input from until a new line is found.  */
>> +
>> +static void
>> +GetNL (void)
>> +{
>> +  char ch;
>> +
>> +  while ((ch = GetChar ()) != '\n')
>> +    putchar (ch);
>> +  putchar ('\n');
>> +}
>> +
>> +/* GetChar - returns the current character in input.  */
>> +
>> +static char
>> +GetChar (void)
>> +{
>> +  char ch;
>> +
>> +  if (StackPtr > 0)
>> +    {
>> +      StackPtr--;
>> +      return (Stack[StackPtr]);
>> +    }
>> +  else
>> +    {
>> +      if (GetSingleChar (&ch))
>> +	return (ch);
>> +      else
>> +	return (ENDOFILE);
>> +    }
>> +}
>> +
>> +#define MAXBUF 0x1000
>> +static int Pointer = 0;
>> +static int AmountRead = 0;
>> +static char Buffer[MAXBUF];
>> +
>> +/* ResetBuffer - resets the buffer information to an initial state.  */
>> +
>> +static void
>> +ResetBuffer (void)
>> +{
>> +  StackPtr = 0;
>> +  Pointer = 0;
>> +  AmountRead = 0;
>> +}
>> +
>> +/* GetSingleChar - gets a single character from input.  TRUE is
>> +   returned upon success.  */
>> +
>> +static int
>> +GetSingleChar (char *ch)
>> +{
>> +  if (Pointer == AmountRead)
>> +    {
>> +      AmountRead = read (CurrentFile, &Buffer, MAXBUF);
>> +      if (AmountRead < 0)
>> +	AmountRead = 0;
>> +      Pointer = 0;
>> +    }
>> +  if (Pointer == AmountRead)
>> +    {
>> +      *ch = ENDOFILE;
>> +      return (FALSE);
>> +    }
>> +  else
>> +    {
>> +      *ch = Buffer[Pointer];
>> +      Pointer++;
>> +      return (TRUE);
>> +    }
>> +}
>> +
>> +/* InRange - returns true if Element is within the range Min..Max.  */
>> +
>> +static int
>> +InRange (int Element, unsigned int Min, unsigned int Max)
>> +{
>> +  return ((Element >= Min) && (Element <= Max));
>> +}
>> +
>> +/* PutChar - pushes a character back onto input.  This character is
>> +   also returned.  */
>> +
>> +static char
>> +PutChar (char ch)
>> +{
>> +  if (StackPtr < MAXSTACK)
>> +    {
>> +      Stack[StackPtr] = ch;
>> +      StackPtr++;
>> +    }
>> +  else
>> +    {
>> +      ERROR ("Stack overflow in PutChar");
>> +    }
>> +  return (ch);
>> +}
>> +
>> +/* IsSpace - returns true if character, ch, is a space.  */
>> +
>> +static int
>> +IsSpace (char ch)
>> +{
>> +  return ((ch == ' ') || (ch == '\t'));
>> +}
>> +
>> +/* SkipSpaces - eats up spaces in input.  */
>> +
>> +static void
>> +SkipSpaces (void)
>> +{
>> +  while (IsSpace (PutChar (GetChar ())))
>> +    putchar (GetChar ());
>> +}
>> +
>> +/* SilentSkipSpaces - eats up spaces in input.  */
>> +
>> +static void
>> +SilentSkipSpaces (void)
>> +{
>> +  char ch;
>> +
>> +  while (IsSpace (PutChar (GetChar ())))
>> +    ch = GetChar (); /* throw away character.  */
>> +}
>> +
>> +/* SkipText - skips ascii text, it does not skip white spaces.  */
>> +
>> +static void
>> +SkipText (void)
>> +{
>> +  while (!IsSpace (PutChar (GetChar ())))
>> +    putchar (GetChar ());
>> +}
>> +
>> +/* SilentSkipText - skips ascii text, it does not skip white spaces.  */
>> +
>> +static void
>> +SilentSkipText (void)
>> +{
>> +  char ch;
>> +
>> +  while (!IsSpace (PutChar (GetChar ())))
>> +    ch = GetChar (); /* throw away character.  */
>> +}
>> +
>> +/* PushBack - pushes a string, backwards onto the input stack.  */
>> +
>> +static void
>> +PushBack (char *s)
>> +{
>> +  int i;
>> +
>> +  i = strlen (s);
>> +  while (i > 0)
>> +    {
>> +      i--;
>> +      PutChar (s[i]);
>> +    }
>> +}
>> +
>> +/* IsDigit - returns true if a character, ch, is a decimal digit.  */
>> +
>> +static int
>> +IsDigit (char ch)
>> +{
>> +  return (((ch >= '0') && (ch <= '9')));
>> +}
>> +
>> +/* GetName - returns the next name found.  */
>> +
>> +static void
>> +GetName (char *Name)
>> +{
>> +  int i;
>> +  char ch;
>> +
>> +  SkipSpaces ();
>> +  ch = GetChar ();
>> +  i = 0;
>> +  while (!IsSpace (ch))
>> +    {
>> +      Name[i] = ch;
>> +      i++;
>> +      ch = GetChar ();
>> +    }
>> +  Name[i] = '\0';
>> +}
>> +
>> +/* FindSource - open source file on StdIn.  */
>> +
>> +static void
>> +FindSource (char *Name)
>> +{
>> +  if (close (STDIN) != 0)
>> +    {
>> +      ERROR ("close on STDIN failed");
>> +    }
>> +  CurrentFile = open (Name, O_RDONLY);
>> +  if (CurrentFile < 0)
>> +    {
>> +      perror ("failed to open file");
>> +      exit (1);
>> +    }
>> +  if (CurrentFile != STDIN)
>> +    {
>> +      ERROR ("Expecting file descriptor value of 1");
>> +    }
>> +}
>> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/def2texi.py
>> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
>> +++ gcc-git-devel-modula2/gcc/m2/tools-src/def2texi.py	2022-10-07 20:21:18.682097332 +0100
>> @@ -0,0 +1,423 @@
>> +#!/usr/bin/env python3
>> +
>> +# def2texi.py creates texi library documentation for all exported procedures.
>> +# Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
>> +
>> +# Copyright (C) 2000-2022 Free Software Foundation, Inc.
>> +# This file is part of GNU Modula-2.
>> +#
>> +# GNU Modula-2 is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 3, or (at your option)
>> +# any later version.
>> +#
>> +# GNU Modula-2 is distributed in the hope that it will be useful,
>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +# GNU General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License
>> +# along with GNU Modula-2; see the file COPYING.  If not, write to the
>> +# Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
>> +# 02110-1301, USA.
>> +#
>> +
>> +import sys
>> +import os
>> +import glob
>> +import getopt
>> +
>> +libraryClassifications = [['gm2-libs','Base libraries',
>> +                           'Basic M2F compatible libraries'],
>> +                          ['gm2-libs-pim','PIM and Logitech 3.0 Compatible',
>> +                           'PIM and Logitech 3.0 compatible libraries'],
>> +                          ['gm2-libs-coroutines','PIM coroutine support',
>> +                           'PIM compatible process support'],
>> +                          ['gm2-libs-iso','M2 ISO Libraries',
>> +                           'ISO defined libraries']]
>> +
>> +def initState ():
>> +    global inVar, inType, inConst
>> +    inVar, inType, inConst = False, False, False
>> +
>> +
>> +#
>> +#  displayLibraryClass - displays a node for a library directory and invokes
>> +#                        a routine to summarize each module
>> +#
>> +
>> +def displayLibraryClass():
>> +    global buildDir, up
>> +    previous = ""
>> +
>> +    next=libraryClassifications[1][1]
>> +    i = 0
>> +    l = libraryClassifications[i]
>> +
>> +    while True:
>> +        print("@node " + l[1] + ", " + next + ", " + previous + ", " + up)
>> +        print("@section " + l[1])
>> +        print("")
>> +        displayModules(l[1], l[0], buildDir, sourceDir)
>> +        print("")
>> +        print("@c ---------------------------------------------------------------------")
>> +        previous = l[1]
>> +        i += 1
>> +        if i == len(libraryClassifications):
>> +            break
>> +        l = libraryClassifications[i]
>> +        if i+1 == len(libraryClassifications):
>> +            next = ""
>> +        else:
>> +            next = libraryClassifications[i+1][1]
>> +
>> +#
>> +#  displayMenu - displays the top level menu for library documentation
>> +#
>> +
>> +def displayMenu():
>> +    print("@menu")
>> +    for l in libraryClassifications:
>> +        print("* " + l[1] + "::" + l[2])
>> +    print("@end menu")
>> +
>> +    print("\n")
>> +    print("@c =====================================================================")
>> +    print("\n")
>> +
>> +
>> +#
>> +#  removeInitialComments - removes any (* *) at the top of the definition module
>> +#
>> +
>> +def removeInitialComments (file, line):
>> +    while (str.find(line, "*)") == -1):
>> +        line = file.readline()
>> +
>> +#
>> +#  removeFields - removes Author/Date/Last edit/SYSTEM/Revision fields from a comment within the start
>> +#                 of a definition module
>> +#
>> +
>> +def removeFields (file, line):
>> +    while (str.find(line, "*)") == -1):
>> +        if (str.find(line, "Author") != -1) and (str.find(line, ":") != -1):
>> +            line = file.readline()
>> +        elif (str.find(line, "Last edit") != -1) and (str.find(line, ":") != -1):
>> +            line = file.readline()
>> +        elif (str.find(line, "LastEdit") != -1) and (str.find(line, ":") != -1):
>> +            line = file.readline()
>> +        elif (str.find(line, "Last update") != -1) and (str.find(line, ":") != -1):
>> +            line = file.readline()
>> +        elif (str.find(line, "Date") != -1) and (str.find(line, ":") != -1):
>> +            line = file.readline()
>> +        elif (str.find(line, "Title") != -1) and (str.find(line, ":") != -1):
>> +            line = file.readline()
>> +        elif (str.find(line, "Revision") != -1) and (str.find(line, ":") != -1):
>> +            line = file.readline()
>> +        elif (str.find(line, "System") != -1) and (str.find(line, ":") != -1) and (str.find(line, "Description:") == -1):
>> +            line = file.readline()
>> +        elif (str.find(line, "SYSTEM") != -1) and (str.find(line, ":") != -1) and (str.find(line, "Description:") == -1):
>> +            line = file.readline()
>> +        else:
>> +           print(str.replace(str.replace(str.rstrip(line),
>> +                                            "{", "@{"), "}", "@}"))
>> +           line = file.readline()
>> +    print(str.rstrip(line))
>> +
>> +
>> +#
>> +#  checkIndex
>> +#
>> +
>> +def checkIndex (line):
>> +    global inVar, inType, inConst
>> +
>> +    words = str.split(line)
>> +    procedure = ""
>> +    if (len(words)>1) and (words[0] == "PROCEDURE"):
>> +        inConst = False
>> +        inType = False
>> +        inVar = False
>> +        if (words[1] == "__BUILTIN__") and (len(words)>2):
>> +            procedure = words[2]
>> +        else:
>> +            procedure = words[1]
>> +
>> +    if (len(line)>1) and (line[0:2] == '(*'):
>> +        inConst = False
>> +        inType = False
>> +        inVar = False
>> +    elif line == "VAR":
>> +        inConst = False
>> +        inVar = True
>> +        inType = False
>> +        return
>> +    elif line == "TYPE":
>> +        inConst = False
>> +        inType = True
>> +        inVar = False
>> +        return
>> +    elif line == "CONST":
>> +        inConst = True
>> +        inType = False
>> +        inVar = False
>> +
>> +    if inVar:
>> +        words = str.split(line, ',')
>> +        for word in words:
>> +            word = str.lstrip(word)
>> +            if word != "":
>> +                if str.find(word, ':') == -1:
>> +                    print("@findex " + word + " (var)")
>> +                elif len(word)>0:
>> +                    var = str.split(word, ':')
>> +                    if len(var)>0:
>> +                        print("@findex " + var[0] + " (var)")
>> +
>> +    if inType:
>> +        words = str.lstrip(line)
>> +        if str.find(words, '=') != -1:
>> +            word = str.split(words, "=")
>> +            if (len(word[0])>0) and (word[0][0] != '_'):
>> +                print("@findex " + str.rstrip(word[0]) + " (type)")
>> +        else:
>> +            word = str.split(words)
>> +            if (len(word)>1) and (word[1] == ';'):
>> +                # hidden type
>> +                if (len(word[0])>0) and (word[0][0] != '_'):
>> +                    print("@findex " + str.rstrip(word[0]) + " (type)")
>> +
>> +    if inConst:
>> +        words = str.split(line, ';')
>> +        for word in words:
>> +            word = str.lstrip(word)
>> +            if word != "":
>> +                if str.find(word, '=') != -1:
>> +                    var = str.split(word, '=')
>> +                    if len(var)>0:
>> +                        print("@findex " + var[0] + " (const)")
>> +
>> +    if procedure != "":
>> +        name = str.split(procedure, "(")
>> +        if name[0] != "":
>> +            proc = name[0]
>> +            if proc[-1] == ";":
>> +                proc = proc[:-1]
>> +            if proc != "":
>> +                print("@findex " + proc)
>> +
>> +
>> +#
>> +#  parseDefinition
>> +#
>> +
>> +def parseDefinition (dir, source, build, file, needPage):
>> +    print("")
>> +    f = open(findFile(dir, build, source, file), 'r')
>> +    initState()
>> +    line = f.readline()
>> +#   while (str.find(line, "(*") != -1):
>> +    while (str.find(line, "(*") != -1):
>> +        removeInitialComments(f, line)
>> +        line = f.readline()
>> +
>> +    while (str.find(line, "DEFINITION") == -1):
>> +        line = f.readline()
>> +
>> +    print("@example")
>> +    print(str.rstrip(line))
>> +    line = f.readline()
>> +    if len(str.rstrip(line)) == 0:
>> +        print(str.replace(str.replace(str.rstrip(line),
>> +                                            "{", "@{"), "}", "@}"))
>> +        line = f.readline()
>> +        if (str.find(line, "(*") != -1):
>> +            removeFields(f, line)
>> +        else:
>> +            print(str.rstrip(line))
>> +    else:
>> +        print(str.rstrip(line))
>> +
>> +    line = f.readline()
>> +    while line:
>> +        line = str.rstrip(line)
>> +        checkIndex(line)
>> +        print(str.replace(str.replace(line, "{", "@{"), "}", "@}"))
>> +        line = f.readline()
>> +    print("@end example")
>> +    if needPage:
>> +        print("@page")
>> +    f.close()
>> +
>> +def parseModules (up, dir, build, source, listOfModules):
>> +    previous = ""
>> +    i = 0
>> +    if len(listOfModules)>1:
>> +        next = dir + "/" + listOfModules[1][:-4]
>> +    else:
>> +        next = ""
>> +
>> +    while i<len(listOfModules):
>> +       print("@node " + dir + "/" + listOfModules[i][:-4] + ", " + next + ", " + previous + ", " + up)
>> +       print("@subsection " + dir + "/" + listOfModules[i][:-4])
>> +       parseDefinition(dir, source, build, listOfModules[i], True)
>> +       print("\n")
>> +       previous = dir + "/" + listOfModules[i][:-4]
>> +       i = i + 1
>> +       if i+1<len(listOfModules):
>> +           next = dir + "/" + listOfModules[i+1][:-4]
>> +       else:
>> +           next = ""
>> +
>> +
>> +#
>> +#  doCat - displays the contents of file, name, to stdout
>> +#
>> +
>> +def doCat (name):
>> +    file = open(name, 'r')
>> +    line = file.readline()
>> +    while line:
>> +        print(str.rstrip(line))
>> +        line = file.readline()
>> +    file.close()
>> +
>> +
>> +#
>> +#  moduleMenu - generates a simple menu for all definition modules
>> +#               in dir
>> +#
>> +
>> +def moduleMenu (dir, build, source):
>> +    print("@menu")
>> +    listOfFiles = []
>> +    if os.path.exists(os.path.join(source, dir)):
>> +        listOfFiles += os.listdir(os.path.join(source, dir))
>> +    if os.path.exists(os.path.join(source, dir)):
>> +        listOfFiles += os.listdir(os.path.join(build, dir))
>> +    listOfFiles = list(dict.fromkeys(listOfFiles).keys())
>> +    listOfFiles.sort()
>> +    for file in listOfFiles:
>> +        if foundFile(dir, build, source, file):
>> +            if (len(file)>4) and (file[-4:] == '.def'):
>> +                print("* " + dir + "/" + file[:-4] + "::" + file)
>> +    print("@end menu")
>> +    print("\n")
>> +
>> +
>> +#
>> +#  checkDirectory - returns True if dir exists in either build or source.
>> +#
>> +
>> +def checkDirectory (dir, build, source):
>> +    if os.path.isdir(build) and os.path.exists(os.path.join(build, dir)):
>> +        return True
>> +    elif os.path.isdir(source) and os.path.exists(os.path.join(source, dir)):
>> +        return True
>> +    else:
>> +        return False
>> +
>> +
>> +#
>> +#  foundFile - return True if file is found in build/dir/file or source/dir/file.
>> +#
>> +
>> +def foundFile (dir, build, source, file):
>> +    name = os.path.join(os.path.join(build, dir), file)
>> +    if os.path.exists(name):
>> +        return True
>> +    name = os.path.join(os.path.join(source, dir), file)
>> +    if os.path.exists(name):
>> +        return True
>> +    return False
>> +
>> +
>> +#
>> +#  findFile - return the path to file searching in build/dir/file first then source/dir/file.
>> +#
>> +
>> +def findFile (dir, build, source, file):
>> +    name1 = os.path.join(os.path.join(build, dir), file)
>> +    if os.path.exists(name1):
>> +        return name1
>> +    name2 = os.path.join(os.path.join(source, dir), file)
>> +    if os.path.exists(name2):
>> +        return name2
>> +    print("file cannot be found in either " + name1 + " or " + name2)
>> +    os.sys.exit(1)
>> +
>> +
>> +#
>> +#  displayModules - walks though the files in dir and parses
>> +#                   definition modules and includes README.texi
>> +#
>> +
>> +def displayModules(up, dir, build, source):
>> +    if checkDirectory(dir, build, source):
>> +        if foundFile(dir, build, source, "README.texi"):
>> +            doCat(findFile(dir, build, source, "README.texi"))
>> +
>> +        moduleMenu(dir, build, source)
>> +        listOfFiles = []
>> +        if os.path.exists(os.path.join(source, dir)):
>> +            listOfFiles += os.listdir(os.path.join(source, dir))
>> +        if os.path.exists(os.path.join(source, dir)):
>> +            listOfFiles += os.listdir(os.path.join(build, dir))
>> +        listOfFiles = list(dict.fromkeys(listOfFiles).keys())
>> +        listOfFiles.sort()
>> +        listOfModules = []
>> +        for file in listOfFiles:
>> +            if foundFile(dir, build, source, file):
>> +                if (len(file)>4) and (file[-4:] == '.def'):
>> +                    listOfModules += [file]
>> +        listOfModules.sort()
>> +        parseModules(up, dir, build, source, listOfModules)
>> +    else:
>> +        print("directory " + dir + " not found in either " + build + " or " + source)
>> +
>> +
>> +def displayCopyright ():
>> +    print("@c Copyright (C) 2000-2022 Free Software Foundation, Inc.")
>> +    print("@c This file is part of GNU Modula-2.")
>> +    print("""
>> +@c Permission is granted to copy, distribute and/or modify this document
>> +@c under the terms of the GNU Free Documentation License, Version 1.2 or
>> +@c any later version published by the Free Software Foundation.
>> +""")
>> +
>> +def Usage():
>> +    print("def2texi.py [-h][-bbuilddir][-uupnode][-ffilename]")
>> +
>> +def collectArgs():
>> +    buildDir="."
>> +    sourceDir="."
>> +    filename=""
>> +    up=""
>> +    try:
>> +        optlist, list = getopt.getopt(sys.argv[1:],':hb:f:s:u:')
>> +    except getopt.GetoptError:
>> +        Usage()
>> +        os.sys.exit(1)
>> +    for opt in optlist:
>> +        if opt[0] == '-h':
>> +            Usage()
>> +        if opt[0] == '-b':
>> +            buildDir = opt[1]
>> +        if opt[0] == '-f':
>> +            filename = opt[1]
>> +        if opt[0] == '-s':
>> +            sourceDir = opt[1]
>> +        if opt[0] == '-u':
>> +            up = opt[1]
>> +    return buildDir, sourceDir, filename, up
>> +
>> +
>> +buildDir, sourceDir, filename, up = collectArgs()
>> +
>> +if filename == "":
>> +    displayCopyright()
>> +    displayMenu()
>> +    displayLibraryClass()
>> +else:
>> +    parseDefinition('.', sourceDir, buildDir, filename, False)

  reply	other threads:[~2022-10-14 12:10 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-10 15:31 Gaius Mulley
2022-10-13  9:12 ` Martin Liška
2022-10-14 12:10   ` Gaius Mulley [this message]
2022-11-07 13:09     ` [PATCH v2 16/19] " Gaius Mulley
2022-11-07 13:47       ` Martin Liška
2022-11-08 13:22         ` Gaius Mulley
2022-11-24 11:53           ` Martin Liška
2022-11-24 14:30             ` Gaius Mulley
2022-11-25 16:25               ` Martin Liška
2022-11-25 17:10               ` David Malcolm
2022-11-27 16:51                 ` Gaius Mulley
2022-10-20 12:42 ` [PATCH] 16/19 " Martin Liška
2022-10-28 13:05   ` Gaius Mulley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87k052ppvq.fsf@debian \
    --to=gaiusmod2@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=mliska@suse.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).