mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-08 19:32:39 +08:00
SET /FIRST DOSBox-X extension for demos like Out of Control with lazy ass environment block parsing
This commit is contained in:
parent
b3e0e4c6f9
commit
4a161b36a7
@ -1,4 +1,7 @@
|
||||
NEXT
|
||||
- Add SET /FIRST, a DOSBox-X extension, that takes the specified
|
||||
variable if it exists and moves it to the front of the environment
|
||||
block. (joncampbell123).
|
||||
- SET command processing has been cleaned up and streamlined.
|
||||
Added /ERASE command line switch to clear the environment
|
||||
block (DOSBox-X extension). (joncampbell123).
|
||||
|
@ -102,6 +102,7 @@ public:
|
||||
bool GetEnvNum(Bitu want_num,std::string & result); //! Return an environment variable by index
|
||||
Bitu GetEnvCount(void); //! Return the number of environmental variables
|
||||
bool SetEnv(const char * entry,const char * new_string); //! Set environment variable
|
||||
bool FirstEnv(const char * entry);
|
||||
bool EraseEnv(void);
|
||||
virtual void WriteOut(const char *format, const char * arguments);
|
||||
void WriteOut(const char * format,...); //! Write to standard output
|
||||
|
@ -497,6 +497,79 @@ void Program::DebugDumpEnv() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Program::FirstEnv(const char * entry) {
|
||||
PhysPt env_base,env_fence,env_scan,env_first,env_last;
|
||||
bool found = false;
|
||||
|
||||
if (dos_kernel_disabled) {
|
||||
LOG_MSG("BUG: Program::FirstEnv() called with DOS kernel disabled (such as OS boot).\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LocateEnvironmentBlock(env_base,env_fence,psp->GetEnvironment())) {
|
||||
LOG_MSG("Warning: GetEnvCount() was not able to locate the program's environment block\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string bigentry(entry);
|
||||
for (std::string::iterator it = bigentry.begin(); it != bigentry.end(); ++it) *it = toupper(*it);
|
||||
|
||||
env_scan = env_base;
|
||||
while (env_scan < env_fence) {
|
||||
/* "NAME" + "=" + "VALUE" + "\0" */
|
||||
/* end of the block is a NULL string meaning a \0 follows the last string's \0 */
|
||||
if (mem_readb(env_scan) == 0) break; /* normal end of block */
|
||||
|
||||
if (EnvPhys_StrCmp(env_scan,env_fence,bigentry.c_str()) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!EnvPhys_ScanUntilNextString(env_scan,env_fence)) break;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
env_first = env_scan;
|
||||
if (!EnvPhys_ScanUntilNextString(env_scan,env_fence)) return false;
|
||||
env_last = env_scan;
|
||||
|
||||
#if 0//DEBUG
|
||||
fprintf(stderr,"Env base=%x fence=%x first=%x last=%x\n",
|
||||
(unsigned int)env_base, (unsigned int)env_fence,
|
||||
(unsigned int)env_first, (unsigned int)env_last);
|
||||
#endif
|
||||
|
||||
assert(env_first <= env_last);
|
||||
|
||||
/* if the variable is already at the beginning, do nothing */
|
||||
if (env_first == env_base) return true;
|
||||
|
||||
{
|
||||
std::vector<uint8_t> tmp;
|
||||
tmp.resize(size_t(env_last-env_first));
|
||||
|
||||
/* save variable */
|
||||
for (size_t i=0;i < tmp.size();i++)
|
||||
tmp[i] = mem_readb(env_first+(PhysPt)i);
|
||||
|
||||
/* shift all variables prior to it forward over the variable, BACKWARDS */
|
||||
const size_t pl = size_t(env_first - env_base);
|
||||
assert((env_first-pl) == env_base);
|
||||
assert((env_last-pl) >= env_base);
|
||||
assert(env_first < env_last);
|
||||
assert(pl != 0);
|
||||
for (size_t i=0;i < pl;i++) mem_writeb(env_last-(i+1), mem_readb(env_first-(i+1)));
|
||||
|
||||
/* put the variable in at the beginning */
|
||||
assert((env_base+tmp.size()) == (env_last-pl));
|
||||
for (size_t i=0;i < tmp.size();i++)
|
||||
mem_writeb(env_base+(PhysPt)i,tmp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Program::EraseEnv(void) {
|
||||
PhysPt env_base,env_fence;
|
||||
size_t nsl = 0,el = 0,needs;
|
||||
|
@ -2733,7 +2733,8 @@ void DOS_Shell::CMD_SET(char * args) {
|
||||
show_all_env,
|
||||
set_env,
|
||||
show_env,
|
||||
erase_env
|
||||
erase_env,
|
||||
first_env
|
||||
};
|
||||
|
||||
op_mode_t op_mode = show_all_env;
|
||||
@ -2757,6 +2758,9 @@ void DOS_Shell::CMD_SET(char * args) {
|
||||
else if (sw == "ERASE") { /* DOSBox-X extension: Completely erase the environment block */
|
||||
op_mode = erase_env;
|
||||
}
|
||||
else if (sw == "FIRST") { /* DOSBox-X extension: Move the specified variable to the front of the environment block */
|
||||
op_mode = first_env;
|
||||
}
|
||||
else {
|
||||
WriteOut("Unknown switch /");
|
||||
WriteOut(sw.c_str());
|
||||
@ -2768,7 +2772,11 @@ void DOS_Shell::CMD_SET(char * args) {
|
||||
}
|
||||
}
|
||||
|
||||
if (op_mode == show_all_env) {
|
||||
if (op_mode == first_env) {
|
||||
if (*args == 0) return;
|
||||
readnonspc(env_name,args);
|
||||
}
|
||||
else if (op_mode == show_all_env) {
|
||||
if (*args != 0) {
|
||||
/* Most SET commands take the form NAME=VALUE */
|
||||
char *p = strchr(args,'=');
|
||||
@ -2814,6 +2822,10 @@ void DOS_Shell::CMD_SET(char * args) {
|
||||
if (!EraseEnv())
|
||||
WriteOut("Unable to erase environment block\n");
|
||||
break;
|
||||
case first_env:
|
||||
if (!FirstEnv(env_name.c_str()))
|
||||
WriteOut("Unable to move environment variable\n");
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user