modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2025-09-23 02:49:32 +04:00
parent 2e3b290d84
commit 2efb0687f1
4 changed files with 262 additions and 204 deletions

View File

@ -0,0 +1,84 @@
<?php
namespace nulib\app\cli;
use stdClass;
abstract class AbstractArgsParser {
/**
* consommer les arguments de $src en avançant l'index $srci et provisionner
* $dest à partir de $desti. si $desti est plus grand que 0, celà veut dire
* que $dest a déjà commencé à être provisionné, et qu'il faut continuer.
*
* $destmin est le nombre minimum d'arguments à consommer. $destmax est le
* nombre maximum d'arguments à consommer.
*
* $srci est la position de l'élément courant à consommer le cas échéant
* retourner le nombre d'arguments qui manquent (ou 0 si tous les arguments
* ont été consommés)
*
* pour les arguments optionnels, ils sont consommés tant qu'il y en a de
* disponible, ou jusqu'à la présence de '--'. Si $keepsep, l'argument '--'
* est gardé dans la liste des arguments optionnels.
*/
protected static function consume_args($src, &$srci, &$dest, $desti, $destmin, $destmax, bool $keepsep): int {
$srcmax = count($src);
# arguments obligatoires
while ($desti < $destmin) {
if ($srci < $srcmax) {
$dest[] = $src[$srci];
} else {
# pas assez d'arguments
return $destmin - $desti;
}
$srci++;
$desti++;
}
# arguments facultatifs
while ($desti < $destmax && $srci < $srcmax) {
$opt = $src[$srci];
if ($opt === "--") {
# fin des options facultatives
if ($keepsep) $dest[] = $opt;
$srci++;
break;
}
$dest[] = $opt;
$srci++;
$desti++;
}
return 0;
}
protected static function check_missing(?string $option, int $count) {
if ($count > 0) {
throw new ArgException("$option: nombre d'arguments insuffisant (manque $count)");
}
}
abstract function normalize(array $args): array;
/** @var object|array objet destination */
protected $dest;
protected function setDest(&$dest): void {
$this->dest =& $dest;
}
protected function unsetDest(): void {
unset($this->dest);
}
abstract function process(array $args);
function parse(&$dest, array $args=null): void {
if ($args === null) {
global $argv;
$args = array_slice($argv, 1);
}
$args = $this->normalize($args);
$dest ??= new stdClass();
$this->setDest($dest);
$this->process($args);
$this->unsetDest();
}
}

View File

@ -3,6 +3,9 @@ namespace nulib\app\cli;
use nulib\cl; use nulib\cl;
/**
* Class ArgDefs: une liste d'objets ArgDef
*/
abstract class ArgDefs implements IArgo { abstract class ArgDefs implements IArgo {
function __construct(array $defs) { function __construct(array $defs) {
$this->defs = $defs; $this->defs = $defs;
@ -64,61 +67,6 @@ abstract class ArgDefs implements IArgo {
return null; return null;
} }
/**
* consommer les arguments de $src en avançant l'index $srci et provisionner
* $dest à partir de $desti. si $desti est plus grand que 0, celà veut dire
* que $dest a déjà commencé à être provisionné, et qu'il faut continuer.
*
* $destmin est le nombre minimum d'arguments à consommer. $destmax est le
* nombre maximum d'arguments à consommer.
*
* $srci est la position de l'élément courant à consommer le cas échéant
* retourner le nombre d'arguments qui manquent (ou 0 si tous les arguments
* ont été consommés)
*
* pour les arguments optionnels, ils sont consommés tant qu'il y en a de
* disponible, ou jusqu'à la présence de '--'. Si $keepsep, l'argument '--'
* est gardé dans la liste des arguments optionnels.
*/
protected static function consume_args($src, &$srci, &$dest, $desti, $destmin, $destmax, bool $keepsep): int {
$srcmax = count($src);
# arguments obligatoires
while ($desti < $destmin) {
if ($srci < $srcmax) {
$dest[] = $src[$srci];
} else {
# pas assez d'arguments
return $destmin - $desti;
}
$srci++;
$desti++;
}
# arguments facultatifs
while ($desti < $destmax && $srci < $srcmax) {
$opt = $src[$srci];
if ($opt === "--") {
# fin des options facultatives
if ($keepsep) $dest[] = $opt;
$srci++;
break;
}
$dest[] = $opt;
$srci++;
$desti++;
}
return 0;
}
protected static function check_missing(?string $option, int $count) {
if ($count > 0) {
throw new ArgException("$option: nombre d'arguments insuffisant (manque $count)");
}
}
function normalize(array $args): array {
return $args;
}
function debugInfos(): array { function debugInfos(): array {
return array_map(function (IArgo $argo) { return array_map(function (IArgo $argo) {
return $argo->debugInfos(); return $argo->debugInfos();

View File

@ -55,6 +55,11 @@ class SimpleArgDefs extends ArgDefs {
protected array $index; protected array $index;
/** @return string[] */
function getOptions(): array {
return array_keys($this->index);
}
protected function setArgos(?array $argos): void { protected function setArgos(?array $argos): void {
$argos ??= []; $argos ??= [];
@ -117,155 +122,6 @@ class SimpleArgDefs extends ArgDefs {
return $this->index[$option] ?? null; return $this->index[$option] ?? null;
} }
function normalize(array $args): array {
$i = 0;
$max = count($args);
$options = [];
$remains = [];
$parseOpts = true;
while ($i < $max) {
$arg = $args[$i++];
if (!$parseOpts) {
# le reste n'est que des arguments
$remains[] = $arg;
continue;
}
if ($arg === "--") {
# fin des options
$parseOpts = false;
continue;
}
if (substr($arg, 0, 2) === "--") {
#######################################################################
# option longue
$pos = strpos($arg, "=");
if ($pos !== false) {
# option avec valeur
$option = substr($arg, 0, $pos);
$value = substr($arg, $pos + 1);
} else {
# option sans valeur
$option = $arg;
$value = null;
}
/** @var ArgDef $argDef */
$argDef = $this->index[$option] ?? null;
if ($argDef === null) {
# chercher une correspondance
$len = strlen($option);
$candidates = [];
foreach (array_keys($this->index) as $candidate) {
if (substr($candidate, 0, $len) === $option) {
$candidates[] = $candidate;
}
}
switch (count($candidates)) {
case 0:
throw new ArgException("$option: option invalide");
case 1:
$option = $candidates[0];
break;
default:
$candidates = implode(", ", $candidates);
throw new ArgException("$option: option ambigue (les options possibles sont $candidates)");
}
$argDef = $this->index[$option];
}
if ($argDef->haveArgs) {
$minArgs = $argDef->minArgs;
$maxArgs = $argDef->maxArgs;
$values = [];
if ($value !== null) {
$values[] = $value;
$offset = 1;
} elseif ($minArgs == 0) {
# cas particulier: la première valeur doit être collée à l'option
# si $maxArgs == 1
$offset = $maxArgs == 1 ? 1 : 0;
} else {
$offset = 0;
}
$this->check_missing($option,
self::consume_args($args, $i, $values, $offset, $minArgs, $maxArgs, true));
if ($minArgs == 0 && $maxArgs == 1) {
# cas particulier: la première valeur doit être collée à l'option
if (count($values) > 0) {
$options[] = "$option=$values[0]";
$values = array_slice($values, 1);
} else {
$options[] = $option;
}
} else {
$options[] = $option;
}
$options = array_merge($options, $values);
} elseif ($value !== null) {
throw new ArgException("$option: cette option ne prend pas d'arguments");
} else {
$options[] = $option;
}
} elseif (substr($arg, 0, 1) === "-") {
#######################################################################
# option courte
$pos = 1;
$len = strlen($arg);
while ($pos < $len) {
$option = "-".substr($arg, $pos, 1);
/** @var ArgDef $argDef */
$argDef = $this->index[$option] ?? null;
if ($argDef === null) {
throw new ArgException("$option: option invalide");
}
if ($argDef->haveArgs) {
$minArgs = $argDef->minArgs;
$maxArgs = $argDef->maxArgs;
$values = [];
if ($len > $pos + 1) {
$values[] = substr($arg, $pos + 1);
$offset = 1;
$pos = $len;
} elseif ($minArgs == 0) {
# cas particulier: la première valeur doit être collée à l'option
# si $maxArgs == 1
$offset = $maxArgs == 1 ? 1 : 0;
} else {
$offset = 0;
}
$this->check_missing($option,
self::consume_args($args, $i, $values, $offset, $minArgs, $maxArgs, true));
if ($minArgs == 0 && $maxArgs == 1) {
# cas particulier: la première valeur doit être collée à l'option
if (count($values) > 0) {
$options[] = "$option$values[0]";
$values = array_slice($values, 1);
} else {
$options[] = $option;
}
} else {
$options[] = $option;
}
$options = array_merge($options, $values);
} else {
$options[] = $option;
}
$pos++;
}
} else {
#XXX implémenter les commandes
#######################################################################
# argument
$remains[] = $arg;
}
}
return array_merge($options, ["--"], $remains);
}
function debugInfos(): array { function debugInfos(): array {
return [ return [
"argos" => array_map(function (IArgo $argo) { "argos" => array_map(function (IArgo $argo) {

View File

@ -0,0 +1,170 @@
<?php
namespace nulib\app\cli;
use stdClass;
class SimpleArgsParser extends AbstractArgsParser {
function __construct(array $defs) {
$this->argDefs = new SimpleArgDefs($defs);
}
protected SimpleArgDefs $argDefs;
protected function getArgDef(string $option): ?ArgDef {
return $this->argDefs->get($option);
}
protected function getOptions(): array {
return $this->argDefs->getOptions();
}
function normalize(array $args): array {
$i = 0;
$max = count($args);
$options = [];
$remains = [];
$parseOpts = true;
while ($i < $max) {
$arg = $args[$i++];
if (!$parseOpts) {
# le reste n'est que des arguments
$remains[] = $arg;
continue;
}
if ($arg === "--") {
# fin des options
$parseOpts = false;
continue;
}
if (substr($arg, 0, 2) === "--") {
#######################################################################
# option longue
$pos = strpos($arg, "=");
if ($pos !== false) {
# option avec valeur
$option = substr($arg, 0, $pos);
$value = substr($arg, $pos + 1);
} else {
# option sans valeur
$option = $arg;
$value = null;
}
$argDef = $this->getArgDef($option);
if ($argDef === null) {
# chercher une correspondance
$len = strlen($option);
$candidates = [];
foreach ($this->getOptions() as $candidate) {
if (substr($candidate, 0, $len) === $option) {
$candidates[] = $candidate;
}
}
switch (count($candidates)) {
case 0:
throw new ArgException("$option: option invalide");
case 1:
$option = $candidates[0];
break;
default:
$candidates = implode(", ", $candidates);
throw new ArgException("$option: option ambigue (les options possibles sont $candidates)");
}
$argDef = $this->getArgDef($option);
}
if ($argDef->haveArgs) {
$minArgs = $argDef->minArgs;
$maxArgs = $argDef->maxArgs;
$values = [];
if ($value !== null) {
$values[] = $value;
$offset = 1;
} elseif ($minArgs == 0) {
# cas particulier: la première valeur doit être collée à l'option
# si $maxArgs == 1
$offset = $maxArgs == 1 ? 1 : 0;
} else {
$offset = 0;
}
$this->check_missing($option,
self::consume_args($args, $i, $values, $offset, $minArgs, $maxArgs, true));
if ($minArgs == 0 && $maxArgs == 1) {
# cas particulier: la première valeur doit être collée à l'option
if (count($values) > 0) {
$options[] = "$option=$values[0]";
$values = array_slice($values, 1);
} else {
$options[] = $option;
}
} else {
$options[] = $option;
}
$options = array_merge($options, $values);
} elseif ($value !== null) {
throw new ArgException("$option: cette option ne prend pas d'arguments");
} else {
$options[] = $option;
}
} elseif (substr($arg, 0, 1) === "-") {
#######################################################################
# option courte
$pos = 1;
$len = strlen($arg);
while ($pos < $len) {
$option = "-".substr($arg, $pos, 1);
$argDef = $this->getArgDef($option);
if ($argDef === null) {
throw new ArgException("$option: option invalide");
}
if ($argDef->haveArgs) {
$minArgs = $argDef->minArgs;
$maxArgs = $argDef->maxArgs;
$values = [];
if ($len > $pos + 1) {
$values[] = substr($arg, $pos + 1);
$offset = 1;
$pos = $len;
} elseif ($minArgs == 0) {
# cas particulier: la première valeur doit être collée à l'option
# si $maxArgs == 1
$offset = $maxArgs == 1 ? 1 : 0;
} else {
$offset = 0;
}
$this->check_missing($option,
self::consume_args($args, $i, $values, $offset, $minArgs, $maxArgs, true));
if ($minArgs == 0 && $maxArgs == 1) {
# cas particulier: la première valeur doit être collée à l'option
if (count($values) > 0) {
$options[] = "$option$values[0]";
$values = array_slice($values, 1);
} else {
$options[] = $option;
}
} else {
$options[] = $option;
}
$options = array_merge($options, $values);
} else {
$options[] = $option;
}
$pos++;
}
} else {
#XXX implémenter les commandes
#######################################################################
# argument
$remains[] = $arg;
}
}
return array_merge($options, ["--"], $remains);
}
function process(array $args) {
}
}