mirror of
https://github.com/php/doc-base.git
synced 2026-03-24 07:12:14 +01:00
350 lines
9.4 KiB
PHP
350 lines
9.4 KiB
PHP
<?php /*
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2025 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| https://www.php.net/license/3_01.txt. |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net, so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Hartmut Holzgraefe <hholzgra@php.net> |
|
|
| Gabor Hojtsy <goba@php.net> |
|
|
| André L F S Bacci <ae@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
|
|
# Description
|
|
|
|
This script creates various "file entities", that is, DTD entities that
|
|
point to files and file listings, named and composed of:
|
|
|
|
- dir.dir.file : pulls in a dir/dir/file.xml
|
|
- dir.dif.entities.dir : pulls in XML files from dir/dir/dir/*.xml
|
|
|
|
In the original file-entities.php.in, the files are created at:
|
|
|
|
- doc-base/entities/file-entities.ent
|
|
- doc-en/reference/entities.*.xml
|
|
|
|
In new idempotent mode, files are created at:
|
|
|
|
- doc-base/temp/file-entites.ent
|
|
- doc-base/temp/file-entites/dir.dir.ent
|
|
|
|
The file entity for directories (file listings) are keep as individual
|
|
files instead to avoid these libxml errors, in some OS/versions:
|
|
|
|
- Detected an entity reference loop [1]
|
|
- Maximum entity amplification factor exceeded [2]
|
|
|
|
See LIBXML_LIMITS_HACK below. This workaround creates about a thousand
|
|
files per running, that slowsdows even more the manual building on HDD
|
|
systems.
|
|
|
|
[1] https://github.com/php/doc-base/pull/183
|
|
[2] https://github.com/php/doc-en/pull/4330
|
|
|
|
*/
|
|
|
|
// Setup
|
|
|
|
ini_set( 'display_errors' , 1 );
|
|
ini_set( 'display_startup_errors' , 1 );
|
|
error_reporting( E_ALL );
|
|
set_time_limit( 0 );
|
|
ob_implicit_flush();
|
|
|
|
const LIBXML_LIMITS_HACK = true;
|
|
|
|
// Usage
|
|
|
|
$root = realpain( __DIR__ . "/../.." );
|
|
$lang = "";
|
|
$chmonly = false;
|
|
$debug = false;
|
|
|
|
array_shift( $argv );
|
|
foreach( $argv as $arg )
|
|
{
|
|
if ( $arg == "--chmonly" )
|
|
{
|
|
$chmonly = true;
|
|
continue;
|
|
}
|
|
if ( $arg == "--debug" )
|
|
{
|
|
$debug = true;
|
|
continue;
|
|
}
|
|
$lang = $arg;
|
|
}
|
|
|
|
// Main
|
|
|
|
echo "Creating file-entities.ent... ";
|
|
|
|
$entities = [];
|
|
$mixedCase = [];
|
|
|
|
generate_file_entities( $root , "en" );
|
|
generate_list_entities( $root , "en" );
|
|
|
|
if ( $lang != "" )
|
|
generate_file_entities( $root , $lang );
|
|
|
|
pushEntity( "global.function-index", path: realpain( __DIR__ . "/.." ) . "/funcindex.xml" );
|
|
|
|
if ( ! $chmonly )
|
|
foreach( $entities as $ent )
|
|
if ( str_starts_with( $ent->name , "chmonly." ) )
|
|
$ent->path = '';
|
|
|
|
$outfile = realpain( __DIR__ . "/../temp/file-entities.ent" , touch: true );
|
|
|
|
$file = fopen( $outfile , "w" );
|
|
if ( ! $file )
|
|
{
|
|
echo "Failed to open $outfile\n.";
|
|
exit( 1 );
|
|
}
|
|
|
|
fputs( $file , "<!-- DON'T TOUCH - AUTOGENERATED BY file-entities.php -->\n\n" );
|
|
|
|
ksort( $entities );
|
|
|
|
foreach ( $entities as $ent )
|
|
writeEntity( $file , $ent );
|
|
|
|
fclose( $file );
|
|
echo "done\n";
|
|
exit( 0 );
|
|
|
|
|
|
|
|
class Entity
|
|
{
|
|
function __construct( public string $name , public string $text , public string $path ) {}
|
|
}
|
|
|
|
function pushEntity( string $name , string $text = '' , string $path = '' )
|
|
{
|
|
global $entities;
|
|
global $mixedCase;
|
|
|
|
$name = str_replace( '_' , '-' , $name );
|
|
$path = str_replace( '\\' , '/' , $path );
|
|
$ent = new Entity( $name , $text , $path );
|
|
$entities[ $name ] = $ent;
|
|
|
|
if ( ( $text == "" && $path == "" ) || ( $text != "" && $path != "" ) )
|
|
{
|
|
echo "Something went wrong on file-entities.php.\n";
|
|
exit( 1 );
|
|
}
|
|
|
|
$lname = strtolower( $name );
|
|
if ( isset( $mixedCase[ $lname ] ) && $mixedCase[ $lname ] != $name )
|
|
{
|
|
echo <<<END
|
|
\n\n
|
|
BROKEN BUILD on case insensitive file systems!
|
|
|
|
Detected file entities names, distinct only by case:
|
|
- {$mixedCase[ $lname ]}
|
|
- $name
|
|
|
|
This may PERMANENTLY BRICK manual build on Windows machines!
|
|
|
|
If you are seeing this message building doc-en, avoid committing any changes
|
|
on repository, and if it's already committed, revert and send a heads up on
|
|
mail lists, on how to fix the issue (refer to this message).
|
|
|
|
If you are seeing this message building a translation, this means that the
|
|
translation may have files or directories that differ from doc-en only by
|
|
upper or lower case letters. Find these differences and fix them at the git
|
|
level ('git mv"). After, delete the files and 'git restore' them, to see if
|
|
the 'git mv' worked.
|
|
|
|
This message only may be visible on non-Windows machines. Mixed cases inside
|
|
a repository, or between repositories, may only cause difficult to debug build
|
|
failures on Windows, without any other information. There is no easy fix for
|
|
this than a complete new checkout of the affected repository.
|
|
|
|
See: https://github.com/php/doc-en/pull/4330#issuecomment-2557306828\n\n
|
|
END;
|
|
exit( 1 );
|
|
}
|
|
$mixedCase[ $lname ] = $name;
|
|
}
|
|
|
|
function generate_file_entities( string $root , string $lang )
|
|
{
|
|
$path = "$root/$lang";
|
|
$test = realpain( $path );
|
|
if ( $test === false || is_dir( $path ) == false )
|
|
{
|
|
echo "Language directory not found: $path\n.";
|
|
exit( 1 );
|
|
}
|
|
$path = $test;
|
|
|
|
file_entities_recurse( $path , array() );
|
|
}
|
|
|
|
function file_entities_recurse( string $langroot , array $dirs )
|
|
{
|
|
$dir = rtrim( "$langroot/" . implode( '/' , $dirs ) , "/" );
|
|
$files = scandir( $dir );
|
|
$subdirs = [];
|
|
|
|
foreach( $files as $file )
|
|
{
|
|
if ( $file == "" )
|
|
continue;
|
|
if ( $file[0] == "." )
|
|
continue;
|
|
if ( $file == "entities" && count( $dirs ) == 0 )
|
|
continue;
|
|
|
|
$path = "$dir/$file";
|
|
|
|
if ( is_dir ( $path ) )
|
|
{
|
|
$subdirs[] = $file;
|
|
continue;
|
|
}
|
|
if ( str_ends_with( $file , ".xml" ) )
|
|
{
|
|
$name = implode( '.' , $dirs ) . "." . basename( $file , ".xml" );
|
|
$name = trim( $name , "." );
|
|
pushEntity( $name , path: $path );
|
|
}
|
|
}
|
|
|
|
foreach( $subdirs as $subdir )
|
|
{
|
|
$recurse = $dirs;
|
|
$recurse[] = $subdir;
|
|
file_entities_recurse( $langroot , $recurse );
|
|
}
|
|
}
|
|
|
|
function generate_list_entities( string $root , string $lang )
|
|
{
|
|
$path = "$root/$lang";
|
|
$test = realpain( $path );
|
|
if ( $test === false || is_dir( $path ) == false )
|
|
{
|
|
echo "Language directory not found: $path\n.";
|
|
exit( 1 );
|
|
}
|
|
$path = $test;
|
|
|
|
$dirs = [ "reference" ];
|
|
list_entities_recurse( $path , $dirs );
|
|
}
|
|
|
|
function list_entities_recurse( string $root , array $dirs )
|
|
{
|
|
$list = [];
|
|
|
|
$dir = rtrim( "$root/" . implode( '/' , $dirs ) , "/" );
|
|
$files = scandir( $dir );
|
|
$subdirs = [];
|
|
|
|
foreach( $files as $file )
|
|
{
|
|
if ( $file == "" )
|
|
continue;
|
|
if ( $file[0] == "." )
|
|
continue;
|
|
|
|
$path = "$dir/$file";
|
|
|
|
if ( is_dir ( $path ) )
|
|
{
|
|
$subdirs[] = $file;
|
|
continue;
|
|
}
|
|
|
|
if ( str_ends_with( $file , ".xml" ) )
|
|
{
|
|
$name = implode( '.' , $dirs ) . "." . basename( $file , ".xml" );
|
|
$name = trim( $name , "." );
|
|
$name = str_replace( '_' , '-' , $name );
|
|
$list[ $name ] = "&{$name};";
|
|
}
|
|
}
|
|
ksort( $list );
|
|
|
|
$copy = $dirs;
|
|
$last = array_pop( $copy );
|
|
$copy[] = "entities";
|
|
$copy[] = $last;
|
|
|
|
$name = implode( "." , $copy );
|
|
$text = implode( "\n" , $list );
|
|
|
|
if ( $text != "" )
|
|
{
|
|
if ( LIBXML_LIMITS_HACK )
|
|
{
|
|
static $entityDir = "";
|
|
if ( $entityDir == "" )
|
|
$entityDir = realpain( __DIR__ . "/../temp/file-entities" , mkdir: true );
|
|
|
|
$path = $entityDir . "/" . implode( '.' , $dirs ) . ".ent";
|
|
file_put_contents( $path , $text );
|
|
pushEntity( $name , path: $path );
|
|
}
|
|
else
|
|
pushEntity( $name , text: $text );
|
|
}
|
|
|
|
foreach( $subdirs as $subdir )
|
|
{
|
|
$recurse = $dirs;
|
|
$recurse[] = $subdir;
|
|
list_entities_recurse( $root , $recurse );
|
|
}
|
|
}
|
|
|
|
function writeEntity( $file , Entity $ent )
|
|
{
|
|
$name = $ent->name;
|
|
$text = $ent->text;
|
|
$path = $ent->path;
|
|
|
|
if ( $path == "" )
|
|
$line = "<!ENTITY $name '$text'>\n";
|
|
else
|
|
$line = "<!ENTITY $name SYSTEM '$path'>\n";
|
|
|
|
fwrite( $file , $line );
|
|
}
|
|
|
|
function realpain( string $path , bool $touch = false , bool $mkdir = false ) : string
|
|
{
|
|
// pain is real
|
|
|
|
// care for external XML tools (realpath() everywhere)
|
|
// care for Windows builds (foward slashes everywhere)
|
|
// avoid `cd` and chdir() like the plague
|
|
|
|
$path = str_replace( "\\" , '/' , $path );
|
|
|
|
if ( $mkdir && ! file_exists( $path ) )
|
|
mkdir( $path , recursive: true );
|
|
|
|
if ( $touch && ! file_exists( $path ) )
|
|
touch( $path );
|
|
|
|
$res = realpath( $path );
|
|
if ( is_string( $res ) )
|
|
$path = str_replace( "\\" , '/' , $res );
|
|
|
|
return $path;
|
|
}
|