maintenance.scantex

Outils d'analyse de fichiers sources ou produits par LateX.

Modifié le 22/01/23 @author: remy

Travaille dans le répertoire courant c'est à dire celui du dépôt à maintenir.

  1# -*- coding: utf-8 -*-
  2"""
  3Outils d'analyse de fichiers sources ou produits par LateX.
  4
  5Modifié le 22/01/23  @author: remy
  6
  7Travaille dans le répertoire courant c'est à dire celui du dépôt à maintenir.
  8"""
  9import os
 10import glob
 11
 12def latex2accent(texte):
 13    LatexAccent = {
 14        r"\IeC {\'e}": "é",
 15        r"\IeC {\'E}": "É",
 16        r"\IeC {\`e}": "è",
 17        r"\IeC {\^e}": "ê",
 18        r"\IeC {\^E}": "Ê",
 19        r"\IeC {\¨e}": "ë",
 20        r"\IeC {\¨E}": "Ë",
 21        r"\IeC {\`a}": "à",
 22        r"\IeC {\'A}": "À",
 23        r"\IeC {\^a}": "â",
 24        r"\IeC {\^A}": "Â",
 25        r"\IeC {\^i}": "î",
 26        r"\IeC {\^I}": "Î",
 27        r"\IeC {\¨i}": "ï",
 28        r"\IeC {\¨I}": "Ï",
 29        r"\IeC {\^o}": "ô",
 30        r"\IeC {\^O}": "Ô",
 31        r"\IeC {\^u}": "û",
 32        r"\IeC {\^U}": "Û",
 33        r"\IeC {\¨u}": "ü",
 34        r"\IeC {\¨U}": "Ü",
 35        r"\IeC {\c c}": "ç",
 36        r"\IeC {\oe}": "œ",
 37        r"\'e": "é",
 38        r"\`e": "è",
 39        r"\`a": "à"
 40    }
 41    for latex, accent in LatexAccent.items():
 42        texte = texte.replace(latex,accent)
 43    return texte
 44
 45def get_date_srce(nom):
 46    """
 47    Renvoie une date de source.
 48
 49    Fonction récursive.
 50    
 51    - Si le fichier ne contient ni input ni includegraphics,
 52        - renvoie la date de maj du fichier.
 53    - Sinon
 54         - renvoie la date la plus récente entre sa date de maj et celle
 55            des input et includegraphics.
 56    """
 57    try:
 58        date_srce = os.path.getmtime(nom)
 59    except FileNotFoundError:
 60        print(nom, ' pas trouvé')
 61        date_srce = 0
 62
 63    # date des sources tex inputtés
 64    try:
 65        liste = get_liste_inputs(nom)
 66    except UnicodeDecodeError:
 67        print(nom)
 68    for fic in liste:
 69        t = get_date_srce(fic)
 70        # print(fic,t)
 71        if t > date_srce:
 72            date_srce = t
 73
 74    # date des figures et des lignes de code incluses
 75    liste = get_liste_includegraphics(nom) + get_liste_lstinputlistings(nom)
 76    for fic in liste:
 77        try:
 78            t = os.path.getmtime(fic)
 79        except FileNotFoundError:
 80            print('Erreur : ', fic, ' pas trouvé')
 81            t = 0
 82        # print(fic, t)
 83        if t > date_srce:
 84            date_srce = t
 85    return date_srce
 86
 87
 88def get_liste_inputs(nom):
 89    """Renvoie la liste des sources tex dans des input."""
 90    fifi = open(nom, 'r')
 91    text = fifi.read()
 92    long = len(text)
 93    inputs = []
 94    c, cc = 0, 0  # compteurs dans la chaine de caractère
 95    while c != -1:
 96        c = text.find('\\input{', cc, long)
 97        if c != -1:
 98            c += 7
 99            cc = text.find('}', c, long)
100            nominput = text[c:cc]
101            if '.' not in nominput:
102                nominput += '.tex'
103            if nominput not in inputs:
104                inputs.append(nominput)
105    return inputs
106
107
108def get_liste_includegraphics(nom):
109    """Renvoie la liste des figures (pdf) dans des includegraphics."""
110    fifi = open(nom, 'r')
111    text = fifi.read()
112    long = len(text)
113    includes = []
114    c, cc = 0, 0  # compteurs dans la chaine de caractère
115    while c != -1:
116        c = text.find('\\includegraphics', cc, long)
117        if c != -1:
118            # il peut y avoir une option '[width= ]'
119            c = text.find('{', c, long)
120            c += 1
121            cc = text.find('}', c, long)
122            fig = text[c:cc]
123            # si pas d'extension on place .pdf
124            if not os.path.splitext(fig)[1]:
125                print('extension pdf manque dans', nom)
126                fig += '.pdf'
127            if fig not in includes:
128                includes.append(fig)
129    return includes
130
131
132def get_liste_lstinputlistings(nom):
133    """
134    Renvoie une liste des fichiers.
135
136    Ceux contenant des lignes de codes insérées par `lstinputlisting`.
137    """
138    fifi = open(nom, 'r')
139    text = fifi.read()
140    long = len(text)
141    lstinputs = []
142    c, cc = 0, 0  # compteurs dans la chaine de caractère
143    while c != -1:
144        c = text.find('\\lstinputlisting', cc, long)
145        if c != -1:
146            # il y a une option '[width= ] à sauter'
147            c = text.find('{', c, long)
148            c += 1
149            cc = text.find('}', c, long)
150            lstinput = text[c:cc]
151            # si pas d'extension on place .py
152            if not os.path.splitext(lstinput)[1]:
153                print('extension pdf manque dans', nom)
154                lstinput += '.py'
155            if lstinput not in lstinputs:
156                lstinputs.append(lstinput)
157    return lstinputs
158
159
160def aexec(src):
161    """Renvoie `Vrai` si un `input` plus récent que le `.pdf`."""
162    ext = os.path.splitext(src)[1]
163    img = src.replace(ext, '.pdf')
164    # print(img)
165    date_img = 0
166    date_src = get_date_srce(src)
167    if os.path.exists(img):
168        date_img = os.path.getmtime(img)
169    return date_src > date_img
170
171
172def acompiler(src, img):
173    """
174    Renvoie `Vrai` si `src` est à compiler.
175
176    C'est à dire si un `input` de la source est plus récent que l'image.
177
178    #### Parameters
179    
180    - src : .
181    - img : chaine de caractère représentant le nom du fichier image.
182
183    #### Returns
184
185    None.
186
187    """
188    # imgext = os.path.splitext(img)[1]
189    # print(img)
190    date_img = 0
191    date_src = get_date_srce(src)
192    if os.path.exists(img):
193        date_img = os.path.getmtime(img)
194        # if imgext == '.html':
195        #    print(img, date_src > date_img)
196
197    return date_src > date_img
198
199def get_liste_indexations(path_pattern):
200    """
201    Renvoie la liste des indexations.
202    
203    Examine les fichiers .idx créés par la commande d'indexation lors de la
204    compilation.
205    
206    #### Paramètres
207    
208    `path_pattern`: str,  pattern de la chaine de caractère des chemins des fichiers
209    idx d'index.'  
210    Exemple `auxdir/A*.idx`.
211    
212    #### Returns
213    
214    Une liste de couples `[nomfic, litteral]` où
215    - `nomfic` est un nom de fichier .tex
216    - `litteral` est une chaine de caractères indexée dans `nomfic`. 
217    """
218    
219    indexations = []
220    idxpaths = glob.glob(path_pattern)
221    for idxpath in idxpaths:
222        doc = os.path.basename(idxpath)
223        #doc = doc.removeprefix('A')
224        doc = doc.removesuffix(('.idx'))
225        f = open(idxpath)
226        for line in f:
227            if '\\indexentry{' in line:
228                line = line.removeprefix('\\indexentry{')
229                if '|hyperpage' in line :
230                    i = line.find('|hyperpage')
231                else:
232                    i = line.find('}')
233                line = line[0:i]
234                line = latex2accent(line)
235                indexations.append([doc,line])
236        f.close()
237    # print(indexations)
238    return indexations
239
240def get_liste_descriptions(description_pattern):
241    """
242    Renvoie la liste des descriptions.
243    
244
245    #### Parametres
246    description_pattern : dictionnaire 
247        {
248            'path_pattern': pattern des chemins des fichiers à examiner,
249            'tags': paire de balises entourant la description
250        }
251
252    #### Renvoie
253    
254    Liste de couples ['nom du document', 'description de document']
255
256    """
257    descriptions = []
258    path_pattern = description_pattern['path_pattern']
259    tags = description_pattern['tags']
260    nomfics = glob.glob(path_pattern)
261    for nomfic in nomfics:
262        file = open(nomfic)
263        fictex = file.read()
264        file.close()
265        if i:= fictex.find(tags[0]) >= 0:
266            i += len(tags[0]) - 1
267            j = fictex.find(tags[1]) 
268            nomfic = nomfic.removeprefix(path_pattern[0])
269            nomfic = nomfic.removesuffix('.tex')
270            descriptions.append([nomfic,fictex[i:j]])
271    return descriptions
272
273def get_entre_tags(nom,debut,fin):
274    """
275    Renvoie la chaine de caractère entre les tags.
276    """
277    fifi = open(nom, 'r')
278    text = fifi.read()
279    ind_debut = text.find(debut) + len(debut)
280    ind_fin = text.find(fin, ind_debut)
281    return text[ind_debut:ind_fin]
282
283    
def latex2accent(texte):
13def latex2accent(texte):
14    LatexAccent = {
15        r"\IeC {\'e}": "é",
16        r"\IeC {\'E}": "É",
17        r"\IeC {\`e}": "è",
18        r"\IeC {\^e}": "ê",
19        r"\IeC {\^E}": "Ê",
20        r"\IeC {\¨e}": "ë",
21        r"\IeC {\¨E}": "Ë",
22        r"\IeC {\`a}": "à",
23        r"\IeC {\'A}": "À",
24        r"\IeC {\^a}": "â",
25        r"\IeC {\^A}": "Â",
26        r"\IeC {\^i}": "î",
27        r"\IeC {\^I}": "Î",
28        r"\IeC {\¨i}": "ï",
29        r"\IeC {\¨I}": "Ï",
30        r"\IeC {\^o}": "ô",
31        r"\IeC {\^O}": "Ô",
32        r"\IeC {\^u}": "û",
33        r"\IeC {\^U}": "Û",
34        r"\IeC {\¨u}": "ü",
35        r"\IeC {\¨U}": "Ü",
36        r"\IeC {\c c}": "ç",
37        r"\IeC {\oe}": "œ",
38        r"\'e": "é",
39        r"\`e": "è",
40        r"\`a": "à"
41    }
42    for latex, accent in LatexAccent.items():
43        texte = texte.replace(latex,accent)
44    return texte
def get_date_srce(nom):
46def get_date_srce(nom):
47    """
48    Renvoie une date de source.
49
50    Fonction récursive.
51    
52    - Si le fichier ne contient ni input ni includegraphics,
53        - renvoie la date de maj du fichier.
54    - Sinon
55         - renvoie la date la plus récente entre sa date de maj et celle
56            des input et includegraphics.
57    """
58    try:
59        date_srce = os.path.getmtime(nom)
60    except FileNotFoundError:
61        print(nom, ' pas trouvé')
62        date_srce = 0
63
64    # date des sources tex inputtés
65    try:
66        liste = get_liste_inputs(nom)
67    except UnicodeDecodeError:
68        print(nom)
69    for fic in liste:
70        t = get_date_srce(fic)
71        # print(fic,t)
72        if t > date_srce:
73            date_srce = t
74
75    # date des figures et des lignes de code incluses
76    liste = get_liste_includegraphics(nom) + get_liste_lstinputlistings(nom)
77    for fic in liste:
78        try:
79            t = os.path.getmtime(fic)
80        except FileNotFoundError:
81            print('Erreur : ', fic, ' pas trouvé')
82            t = 0
83        # print(fic, t)
84        if t > date_srce:
85            date_srce = t
86    return date_srce

Renvoie une date de source.

Fonction récursive.

  • Si le fichier ne contient ni input ni includegraphics,
    • renvoie la date de maj du fichier.
  • Sinon
    • renvoie la date la plus récente entre sa date de maj et celle des input et includegraphics.
def get_liste_inputs(nom):
 89def get_liste_inputs(nom):
 90    """Renvoie la liste des sources tex dans des input."""
 91    fifi = open(nom, 'r')
 92    text = fifi.read()
 93    long = len(text)
 94    inputs = []
 95    c, cc = 0, 0  # compteurs dans la chaine de caractère
 96    while c != -1:
 97        c = text.find('\\input{', cc, long)
 98        if c != -1:
 99            c += 7
100            cc = text.find('}', c, long)
101            nominput = text[c:cc]
102            if '.' not in nominput:
103                nominput += '.tex'
104            if nominput not in inputs:
105                inputs.append(nominput)
106    return inputs

Renvoie la liste des sources tex dans des input.

def get_liste_includegraphics(nom):
109def get_liste_includegraphics(nom):
110    """Renvoie la liste des figures (pdf) dans des includegraphics."""
111    fifi = open(nom, 'r')
112    text = fifi.read()
113    long = len(text)
114    includes = []
115    c, cc = 0, 0  # compteurs dans la chaine de caractère
116    while c != -1:
117        c = text.find('\\includegraphics', cc, long)
118        if c != -1:
119            # il peut y avoir une option '[width= ]'
120            c = text.find('{', c, long)
121            c += 1
122            cc = text.find('}', c, long)
123            fig = text[c:cc]
124            # si pas d'extension on place .pdf
125            if not os.path.splitext(fig)[1]:
126                print('extension pdf manque dans', nom)
127                fig += '.pdf'
128            if fig not in includes:
129                includes.append(fig)
130    return includes

Renvoie la liste des figures (pdf) dans des includegraphics.

def get_liste_lstinputlistings(nom):
133def get_liste_lstinputlistings(nom):
134    """
135    Renvoie une liste des fichiers.
136
137    Ceux contenant des lignes de codes insérées par `lstinputlisting`.
138    """
139    fifi = open(nom, 'r')
140    text = fifi.read()
141    long = len(text)
142    lstinputs = []
143    c, cc = 0, 0  # compteurs dans la chaine de caractère
144    while c != -1:
145        c = text.find('\\lstinputlisting', cc, long)
146        if c != -1:
147            # il y a une option '[width= ] à sauter'
148            c = text.find('{', c, long)
149            c += 1
150            cc = text.find('}', c, long)
151            lstinput = text[c:cc]
152            # si pas d'extension on place .py
153            if not os.path.splitext(lstinput)[1]:
154                print('extension pdf manque dans', nom)
155                lstinput += '.py'
156            if lstinput not in lstinputs:
157                lstinputs.append(lstinput)
158    return lstinputs

Renvoie une liste des fichiers.

Ceux contenant des lignes de codes insérées par lstinputlisting.

def aexec(src):
161def aexec(src):
162    """Renvoie `Vrai` si un `input` plus récent que le `.pdf`."""
163    ext = os.path.splitext(src)[1]
164    img = src.replace(ext, '.pdf')
165    # print(img)
166    date_img = 0
167    date_src = get_date_srce(src)
168    if os.path.exists(img):
169        date_img = os.path.getmtime(img)
170    return date_src > date_img

Renvoie Vrai si un input plus récent que le .pdf.

def acompiler(src, img):
173def acompiler(src, img):
174    """
175    Renvoie `Vrai` si `src` est à compiler.
176
177    C'est à dire si un `input` de la source est plus récent que l'image.
178
179    #### Parameters
180    
181    - src : .
182    - img : chaine de caractère représentant le nom du fichier image.
183
184    #### Returns
185
186    None.
187
188    """
189    # imgext = os.path.splitext(img)[1]
190    # print(img)
191    date_img = 0
192    date_src = get_date_srce(src)
193    if os.path.exists(img):
194        date_img = os.path.getmtime(img)
195        # if imgext == '.html':
196        #    print(img, date_src > date_img)
197
198    return date_src > date_img

Renvoie Vrai si src est à compiler.

C'est à dire si un input de la source est plus récent que l'image.

Parameters

  • src : .
  • img : chaine de caractère représentant le nom du fichier image.

Returns

None.

def get_liste_indexations(path_pattern):
200def get_liste_indexations(path_pattern):
201    """
202    Renvoie la liste des indexations.
203    
204    Examine les fichiers .idx créés par la commande d'indexation lors de la
205    compilation.
206    
207    #### Paramètres
208    
209    `path_pattern`: str,  pattern de la chaine de caractère des chemins des fichiers
210    idx d'index.'  
211    Exemple `auxdir/A*.idx`.
212    
213    #### Returns
214    
215    Une liste de couples `[nomfic, litteral]` où
216    - `nomfic` est un nom de fichier .tex
217    - `litteral` est une chaine de caractères indexée dans `nomfic`. 
218    """
219    
220    indexations = []
221    idxpaths = glob.glob(path_pattern)
222    for idxpath in idxpaths:
223        doc = os.path.basename(idxpath)
224        #doc = doc.removeprefix('A')
225        doc = doc.removesuffix(('.idx'))
226        f = open(idxpath)
227        for line in f:
228            if '\\indexentry{' in line:
229                line = line.removeprefix('\\indexentry{')
230                if '|hyperpage' in line :
231                    i = line.find('|hyperpage')
232                else:
233                    i = line.find('}')
234                line = line[0:i]
235                line = latex2accent(line)
236                indexations.append([doc,line])
237        f.close()
238    # print(indexations)
239    return indexations

Renvoie la liste des indexations.

Examine les fichiers .idx créés par la commande d'indexation lors de la compilation.

Paramètres

path_pattern: str, pattern de la chaine de caractère des chemins des fichiers idx d'index.'
Exemple auxdir/A*.idx.

Returns

Une liste de couples [nomfic, litteral]

  • nomfic est un nom de fichier .tex
  • litteral est une chaine de caractères indexée dans nomfic.
def get_liste_descriptions(description_pattern):
241def get_liste_descriptions(description_pattern):
242    """
243    Renvoie la liste des descriptions.
244    
245
246    #### Parametres
247    description_pattern : dictionnaire 
248        {
249            'path_pattern': pattern des chemins des fichiers à examiner,
250            'tags': paire de balises entourant la description
251        }
252
253    #### Renvoie
254    
255    Liste de couples ['nom du document', 'description de document']
256
257    """
258    descriptions = []
259    path_pattern = description_pattern['path_pattern']
260    tags = description_pattern['tags']
261    nomfics = glob.glob(path_pattern)
262    for nomfic in nomfics:
263        file = open(nomfic)
264        fictex = file.read()
265        file.close()
266        if i:= fictex.find(tags[0]) >= 0:
267            i += len(tags[0]) - 1
268            j = fictex.find(tags[1]) 
269            nomfic = nomfic.removeprefix(path_pattern[0])
270            nomfic = nomfic.removesuffix('.tex')
271            descriptions.append([nomfic,fictex[i:j]])
272    return descriptions

Renvoie la liste des descriptions.

Parametres

description_pattern : dictionnaire { 'path_pattern': pattern des chemins des fichiers à examiner, 'tags': paire de balises entourant la description }

Renvoie

Liste de couples ['nom du document', 'description de document']

def get_entre_tags(nom, debut, fin):
274def get_entre_tags(nom,debut,fin):
275    """
276    Renvoie la chaine de caractère entre les tags.
277    """
278    fifi = open(nom, 'r')
279    text = fifi.read()
280    ind_debut = text.find(debut) + len(debut)
281    ind_fin = text.find(fin, ind_debut)
282    return text[ind_debut:ind_fin]

Renvoie la chaine de caractère entre les tags.