1
+ <?php
2
+ /*
3
+ +----------------------------------------------------------------------+
4
+ | Copyright (c) 1997-2023 The PHP Group |
5
+ +----------------------------------------------------------------------+
6
+ | This source file is subject to version 3.01 of the PHP license, |
7
+ | that is bundled with this package in the file LICENSE, and is |
8
+ | available through the world-wide-web at the following url: |
9
+ | https://www.php.net/license/3_01.txt. |
10
+ | If you did not receive a copy of the PHP license and are unable to |
11
+ | obtain it through the world-wide-web, please send a note to |
12
+ | [email protected] , so we can mail you a copy immediately. |
13
+ +----------------------------------------------------------------------+
14
+ | Authors: André L F S Bacci <ae php.net> |
15
+ +----------------------------------------------------------------------+
16
+ | Description: Collect individual entities into an entities.ent file. |
17
+ +----------------------------------------------------------------------+
18
+
19
+ # Conventions
20
+
21
+ * `.dnt`: Simple text, "do not translate" file;
22
+ * `.txt`: Simple text, translatable, untracked file;
23
+ * `.xml`: Full XML, translatable, tracked file.
24
+
25
+ Each entitiesDir is read in order, overwriting previous defined
26
+ entities with new ones (this is inverse of XML processing, where
27
+ overwriting entities are ignored).
28
+ */
29
+
30
+ if ( count ( $ argv ) < 2 || in_array ( '--help ' , $ argv ) || in_array ( '-h ' , $ argv ) )
31
+ {
32
+ fwrite ( STDERR , "\nUsage: {$ argv [0 ]} entitiesDir [entitiesDir] \n\n" );
33
+ return ;
34
+ }
35
+
36
+ $ generate = realpath ( __DIR__ . "/../.entities.ent " ); // sibling of .manual.xml
37
+ $ entities = []; // all entitites, already overriden
38
+ $ expected = []; // entities that are expected to be oversidem (translatins)
39
+ $ override = []; // overrides stattics
40
+
41
+ $ langs = [];
42
+ $ detail = false ;
43
+
44
+ for ( $ idx = 1 ; $ idx < count ( $ argv ) ; $ idx ++ )
45
+ if ( $ argv [$ idx ] == "--detail " )
46
+ $ detail = true ;
47
+ else
48
+ $ langs [] = $ argv [$ idx ];
49
+
50
+ if ( $ detail )
51
+ print "Creating file $ generate in verbose detail mode... \n" ;
52
+ else
53
+ print "Creating file $ generate... " ;
54
+
55
+ for ( $ run = 0 ; $ run < count ( $ langs ) ; $ run ++ )
56
+ parseDir ( $ langs [$ run ] , $ run > 0 );
57
+
58
+ dump ( $ entities );
59
+
60
+ [$ count , $ untranslated , $ overriden ] = verifyOverrides ( $ detail );
61
+
62
+ if ( $ detail )
63
+ {
64
+ print "Done. \n" ;
65
+ }
66
+ else
67
+ {
68
+ echo " done " ;
69
+ if ( $ untranslated + $ overriden > 0 )
70
+ echo ": $ count entities, $ untranslated untranslated, $ overriden orerriden " ;
71
+ echo ". \n" ;
72
+ }
73
+ exit ;
74
+
75
+
76
+
77
+ function parseDir ( string $ dir , bool $ expectedOverride )
78
+ {
79
+ if ( ! is_dir ( $ dir ) )
80
+ return ; // for now. When implanted in all languages: exit( "Not a directory: $dir\n" );
81
+
82
+ $ files = scandir ( $ dir );
83
+
84
+ foreach ( $ files as $ file )
85
+ {
86
+ if ( str_starts_with ( $ file , '. ' ) )
87
+ continue ;
88
+
89
+ $ path = realpath ( "$ dir/ $ file " );
90
+
91
+ if ( is_dir ( $ path ) )
92
+ continue ;
93
+
94
+ $ text = file_get_contents ( $ path );
95
+
96
+ if ( validate ( $ path , $ text , false ) )
97
+ {
98
+ push ( $ path , $ text , $ expectedOverride );
99
+ continue ;
100
+ }
101
+
102
+ $ frag = "<frag> $ text</frag> " ;
103
+ if ( validate ( $ path , $ frag , true ) )
104
+ {
105
+ push ( $ path , $ text , $ expectedOverride );
106
+ continue ;
107
+ }
108
+ }
109
+ }
110
+
111
+ function validate ( string $ path , string $ text , bool $ warn ) : bool
112
+ {
113
+ $ dom = new DOMDocument ( '1.0 ' , 'utf8 ' );
114
+ $ dom ->recover = true ;
115
+ $ dom ->resolveExternals = false ;
116
+ libxml_use_internal_errors ( true );
117
+
118
+ $ res = $ dom ->loadXML ( $ text );
119
+
120
+ $ err = libxml_get_errors ();
121
+ libxml_clear_errors ();
122
+
123
+ foreach ( $ err as $ item )
124
+ {
125
+ $ msg = $ item ->message ;
126
+ if ( str_starts_with ( $ msg , "Entity ' " ) && str_ends_with ( $ msg , "' not defined " ) )
127
+ continue ;
128
+
129
+ if ( $ warn )
130
+ {
131
+ fwrite ( STDERR , "\n XML load failed on entity file. " );
132
+ fwrite ( STDERR , "\n Path: $ path " );
133
+ fwrite ( STDERR , "\n Error: $ msg \n" );
134
+ }
135
+ return false ;
136
+ }
137
+ return true ;
138
+ }
139
+
140
+ function push ( string $ path , string $ contents , bool $ expectedOverride )
141
+ {
142
+ global $ entities ;
143
+ global $ expected ;
144
+ global $ override ;
145
+
146
+ $ info = pathinfo ( $ path );
147
+ $ name = $ info ["filename " ];
148
+
149
+ if ( $ expectedOverride )
150
+ $ expected [] = $ name ;
151
+
152
+ if ( ! isset ( $ override [$ name ] ) )
153
+ $ override [$ name ] = 0 ;
154
+ else
155
+ $ override [$ name ]++;
156
+
157
+ $ entities [$ name ] = $ contents ;
158
+ }
159
+
160
+ function dump ( array $ entities )
161
+ {
162
+ global $ generate ;
163
+
164
+ // In PHP 8.4 may be possible to construct an extended
165
+ // DOMEntity class with writable properties. For now,
166
+ // creating entities files directly as text.
167
+
168
+ $ file = fopen ( $ generate , "w " );
169
+ fputs ( $ file , "\n<!-- DO NOT COPY - Autogenerated by entities.php --> \n\n" );
170
+
171
+ foreach ( $ entities as $ name => $ text )
172
+ {
173
+ $ text = str_replace ( "' " , '' ' , $ text );
174
+ fputs ( $ file , "<!ENTITY $ name ' $ text'> \n\n" );
175
+ }
176
+ fclose ( $ file );
177
+ }
178
+
179
+ function verifyOverrides ( bool $ outputDetail )
180
+ {
181
+ global $ entities ;
182
+ global $ expected ;
183
+ global $ override ;
184
+
185
+ $ countGenerated = count ( $ entities );
186
+ $ countExpectedOverriden = 0 ;
187
+ $ countUnexpectedOverriden = 0 ;
188
+
189
+ foreach ( $ entities as $ name => $ text )
190
+ {
191
+ $ times = $ override [$ name ];
192
+
193
+ if ( isset ( $ expected [$ name ] ) )
194
+ {
195
+ if ( $ times != 1 )
196
+ {
197
+ $ countExpectedOverriden ++;
198
+ if ( $ outputDetail )
199
+ print "Expected override entity $ name overriden $ times times. \n" ;
200
+ }
201
+ }
202
+ else
203
+ {
204
+ if ( $ times != 0 )
205
+ {
206
+ $ countUnexpectedOverriden ++;
207
+ if ( $ outputDetail )
208
+ print "Unexpected override entity $ name overriden $ times times. \n" ;
209
+ }
210
+ }
211
+ }
212
+
213
+ return [$ countGenerated , $ countExpectedOverriden , $ countUnexpectedOverriden ];
214
+ }
0 commit comments