Skip to content

Commit a5da02b

Browse files
author
André L F S Bacci
committed
Splitted entity file infraestructure.
1 parent eba8025 commit a5da02b

File tree

4 files changed

+229
-1
lines changed

4 files changed

+229
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Files generated by the configure script
22
.manual.xml
3+
.entities.ent
34
.revcheck.json
45
install-unix.xml
56
install-win.xml

configure.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,8 +738,16 @@ function getFileModificationHistory(): array {
738738

739739
globbetyglob("{$ac['basedir']}/scripts", 'make_scripts_executable');
740740

741-
$redir = ($ac['quiet'] == 'yes') ? ' > ' . (is_windows() ? 'nul' : '/dev/null') : '';
741+
{
742+
$cmd = escapeshellarg( $ac['PHP'] );
743+
$cmd .= ' ' . escapeshellarg( __DIR__ . '/scripts/entities.php' );
744+
$cmd .= ' ' . escapeshellarg( $ac['ROOTDIR'] . '/en/entities' );
745+
if ( $ac['LANG'] != 'en' )
746+
$cmd .= ' ' . escapeshellarg( $ac['ROOTDIR'] . '/' . $ac['LANG'] . '/entities' );
747+
passthru( $cmd );
748+
}
742749

750+
$redir = ($ac['quiet'] == 'yes') ? ' > ' . (is_windows() ? 'nul' : '/dev/null') : '';
743751
quietechorun("\"{$ac['PHP']}\" -q \"{$ac['basedir']}/scripts/file-entities.php\"{$redir}");
744752

745753

manual.xml.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<?xml version='1.0' encoding='@ENCODING@' ?>
22
<!DOCTYPE PHPDOC [
3+
4+
<!-- Entities collected with entities.php -->
5+
<!ENTITY % manual-entities SYSTEM "./.entities.ent">
6+
%manual-entities;
7+
38
<!-- Add translated specific definitions and snippets -->
49
@TRANSLATION_ONLY_INCL_BEGIN@
510
<!ENTITY % language-defs SYSTEM "../@LANGDIR@/language-defs.ent">

scripts/entities.php

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
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( "'" , '&apos;' , $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

Comments
 (0)