Ferreteria/v0.6/clade/Sys/FileSys/Mode/@current/2026/05/09
Jump to navigation
Jump to search
enum eFileMode : string {
case READER = 'R'; // want to read from file
case WRITER = 'W'; // want to write to file
case CREATE = 'C'; // create if not found
case FOUND = 'F'; // what to do if file found (exists)
public function IsOptional() : bool { return $this->value == eTriState::SHRUG; }
public function Default() : object { return ($this == self::FOUND) ? eIfFound::SHRUG : eTriState::SHRUG; }
public function EnumForValue(string $ch) : eTriState | eIfFound {
return ($this == self::FOUND) ? eIfFound::tryFrom($ch) : eTriState::tryFrom($ch);
}
}
enum eTriState : string {
case SHRUG = '';
case OFF = '-';
case ON = '+';
public function IsRequired() : bool { return $this == self::ON; }
public function IsForbidden() : bool { return $this == self::OFF; }
}
enum eIfFound : string {
case SHRUG = ''; // not applicable / don't care
case FAIL = '!'; // fail/error
case ZERO = '0'; // reset file-length to zero (erase contents)
case EOF = '>'; // set file-pointer to EOF
}
/**
* PURPOSE: compilation of all modes for use in assembling a request string, so we don't have to "use" so many enum classes.
* It also doesn't include the SHRUG values, since those don't have any effect (and would cause a duplicate enum value error).
*/
enum eMode : string {
case FILE_READER = eFileMode::READER->value;
case FILE_WRITER = eFileMode::WRITER->value;
case FILE_CREATE = eFileMode::CREATE->value;
case FILE_FOUND = eFileMode::FOUND->value;
case FOUND_FAIL = eIfFound::FAIL->value; // fail/error
case FOUND_ZERO = eIfFound::ZERO->value; // reset file-length to zero (erase contents)
case FOUND_EOF = eIfFound::EOF->value; // set file-pointer to EOF
case FLAG_OFF = eTriState::OFF->value;
case FLAG_ON = eTriState::ON->value;
}
interface iMode extends BaseIface {
// SETUP
static function FromCodes(string $s) : self;
// ACCESS
function IsValid() : bool;
function NativeString() : ?string;
function CanCreate() : bool;
}
class cMode extends BaseClass implements SelfIface {
// ++ CONFIG: reference data ++ //
private const arModeMap = [
'r' => '+-- ', // reading only, from start of file
'r+' => '++- ', // reading and writing; place the file pointer at the beginning of the file.
'w' => '-++0', // writing only; start of file; truncate to zero length. If the file does not exist, attempt to create it.
'w+' => '+++0', // reading and writing; otherwise it has the same behavior as 'w'.
'a' => '-++>', // writing only; file pointer at end of file. Create if not found. fseek() has no effect, writes are always appended.
'a+' => '+++>', // reading and writing; file pointer at end of file. Create if not found. fseek() only affects reading, writes appended.
'x' => '-++!', // writing only; file pointer at start of file. FAIL if found; create if not found.
'x+' => '+++!', // reading and writing; otherwise it has the same behavior as 'x'.
'c' => '-++ ', // writing only. Create if not found. No action if found. File pointer at start of file.
'c+' => '+++ ', // same as 'c' except reading and writing
];
private const sModeChs = 'RWCF'; // This defines the order for the requirements in the ModeMap above.
private const IDX_CREATE = 2; // "C" position
// -- CONFIG -- //
// ++ SETUP ++ //
protected function __construct(){}
public static function FromCodes(string $s) : SelfIface {
$oThis = new static;
$oThis->RequestString = $s;
$oThis->ParseReqString($s);
return $oThis;
}
public static function FromNative(string $s) : SelfIface {
$oThis = new static;
$oThis->NativeString($s);
return $oThis;
}
// -- SETUP -- //
// ++ SETTINGS ++ //
private $sNative = NULL;
public function NativeString(string $s=NULL) : ?string { return is_null($s) ? $this->sNative : ($this->sNative = $s); }
public protected(set) string $RequestString;
private $sFlags = NULL;
public function FlagsString(string $s=NULL) : ?string { return is_null($s) ? $this->sFlags : ($this->sFlags = $s); }
public function IsValid() : bool { return is_string($this->sFlags) || is_string($this->sNative); }
// 2025-12-23 Can be made public if actually needed.
protected function MustCreate() : eTriState {
return eTriState::tryFrom($this->FlagsString()[self::IDX_CREATE]); // This result depends on the "CREATE" flag's value.
}
public function CanCreate() : bool { return $this->MustCreate() === eTriState::ON; }
// ++ SETTINGS: processing ++ //
protected function ParseReqString(string $sReq) {
if (strlen($sReq) === 0) return; // 2025-12-22 Should this throw an error?
$sReq = strtoupper(str_replace(' ','',$sReq)); // remove spaces, lowercase
$arModeOk = self::arModeMap; // allowable modes (to be winnowed down)
$sRem = $sReq;
while ($sRem !== '') {
$chType = $sRem[0];
if (strlen($sRem) === 1) {
echo "Syntax error: letter-code [$chType] is missing an operator.".CRLF;
} else {
$chOper = $sRem[1];
$sRem = substr($sRem,2); // remove 1st 2 characters
$eMode = eFileMode::tryFrom($chType);
$eVal = $eMode->EnumForValue($chOper);
#$this->AmHereShort("chType=[$chType] eMode: ".get_class($eMode).' eVal: '.get_class($eVal).' ('.$eVal->value.')');
if (is_null($eVal)) {
echo $this->CodingPrompt("The operator '$chOper' (for '$chType' in [$sReq]) returned NULL.");
} else {
// Filter available modes for this requirement:
$dxMode = strpos(self::sModeChs,$chType);
#$this->AmHereShort("mode-request to check: [$chType] -> index [$dxMode]");
foreach ($arModeOk as $sNatMode => $sReqs) {
#$this->AmHereShort("CHECKING $dxMode in [$sReqs] for [$sNatMode]");
if (isset($sReqs[$dxMode])) {
$chMapVal = $sReqs[$dxMode]; // check this mode's reqval
if ($chMapVal !== $chOper) {
// doesn't match requirement, so can't use it: remove from ok-list
unset($arModeOk[$sNatMode]);
#$this->AmHereShort("ELIMINATING $sNatMode");
}
}
}
#$this->AmHereShort('MODES REMAINING: '.count($arModeOk));
}
}
}
// If there are any entries left in $arModeOk, then we have a mode we can use.
if (count($arModeOk) > 0) {
// For now, we just use the first entry in what's left after winnowing.
// Save the native mode-string:
$arKeys = array_keys($arModeOk);
$sNative = $arKeys[0];
$this->NativeString($sNative);
// Save the flags-string:
$arVals = array_values($arModeOk);
$sFlags = $arVals[0];
$this->FlagsString($sFlags);
} else {
throw new \Exception("File mode-request '$sReq' did not match any valid modes.");
}
#$this->AmHereShort("NATIVE STRING: [".$this->NativeString().']');
}
// -- SETTINGS -- //
}