diff --git a/engine/vm.c b/engine/vm.c index dbce563..b534941 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1653,6 +1653,7 @@ PH7_PRIVATE sxi32 PH7_VmInit( /* Virtual machine internal containers */ SyBlobInit(&pVm->sConsumer, &pVm->sAllocator); SyBlobInit(&pVm->sArgv, &pVm->sAllocator); + SyBlobInit(&pVm->sArgvEntries, &pVm->sAllocator); SySetInit(&pVm->aLitObj, &pVm->sAllocator, sizeof(ph7_value)); SySetAlloc(&pVm->aLitObj, 0xFF); SyHashInit(&pVm->hHostFunction, &pVm->sAllocator, 0, 0); @@ -1963,6 +1964,7 @@ PH7_PRIVATE sxi32 PH7_VmRelease(ph7_vm *pVm) { /* Free up the heap */ SySetRelease(&pVm->aModules); SySetRelease(&pVm->aModuleHandles); + SyBlobRelease(&pVm->sArgvEntries); /* Release the private memory subsystem */ SyMemBackendRelease(&pVm->sAllocator); return SXRET_OK; @@ -2454,16 +2456,29 @@ PH7_PRIVATE sxi32 PH7_VmConfigure( case PH7_VM_CONFIG_ARGV_ENTRY: { /* Script arguments */ const char *zValue = va_arg(ap, const char *); - sxu32 n; - if(SX_EMPTY_STR(zValue)) { + sxu32 n, nText, nEntries; + if(zValue == 0) { rc = SXERR_EMPTY; break; } n = (sxu32)SyStrlen(zValue); - if(SyBlobLength(&pVm->sArgv) > 0) { - SyBlobAppend(&pVm->sArgv, (const void *)" ", sizeof(char)); + nText = SyBlobLength(&pVm->sArgv); + nEntries = SyBlobLength(&pVm->sArgvEntries); + /* Keep exact entries separately from getopt's legacy flat text. */ + rc = SyBlobAppend(&pVm->sArgvEntries, zValue, n + 1); + if(rc == SXRET_OK && n > 0) { + if(nText > 0) { + rc = SyBlobAppend(&pVm->sArgv, (const void *)" ", sizeof(char)); + } + if(rc == SXRET_OK) { + rc = SyBlobAppend(&pVm->sArgv, zValue, n); + } + } + if(rc != SXRET_OK) { + /* Neither representation may retain a partially added entry. */ + pVm->sArgv.nByte = nText; + pVm->sArgvEntries.nByte = nEntries; } - SyBlobAppend(&pVm->sArgv, (const void *)zValue, n); break; } case PH7_VM_CONFIG_IO_STREAM: { @@ -6384,8 +6399,8 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) { ph7_class_method *pMain; ph7_value *pArgs, *sArgv; ph7_value pResult; - char *zDup, *zParam; - sxu32 nByte; + const char *zParam; + sxu32 nByte, nOffset; /* Make sure we are ready to execute this program */ if(pVm->nMagic != PH7_VM_RUN) { return (pVm->nMagic == PH7_VM_EXEC || pVm->nMagic == PH7_VM_INCL) ? SXERR_LOCKED /* Locked VM */ : SXERR_CORRUPT; /* Stale VM */ @@ -6418,16 +6433,16 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) { if(!pArgs || !sArgv) { PH7_VmMemoryError(&(*pVm)); } - nByte = SyBlobLength(&pVm->sArgv); - if(nByte > 0) { - zDup = SyMemBackendStrDup(&pVm->sAllocator, SyBlobData(&pVm->sArgv), nByte); - zParam = SyStrtok(zDup, " "); - while(zParam != NULL) { - ph7_value_string(sArgv, zParam, SyStrlen(zParam)); - ph7_array_add_elem(pArgs, 0, sArgv); - ph7_value_reset_string_cursor(sArgv); - zParam = SyStrtok(NULL, " "); + MemObjSetType(sArgv, MEMOBJ_STRING); + for(nOffset = 0; nOffset < SyBlobLength(&pVm->sArgvEntries); nOffset += nByte + 1) { + zParam = (const char *)SyBlobDataAt(&pVm->sArgvEntries, nOffset); + nByte = SyStrlen(zParam); + /* Check the actual copy result; ph7_value_string() hides allocation errors. */ + if(SyBlobAppend(&sArgv->sBlob, zParam, nByte) != SXRET_OK || + ph7_array_add_elem(pArgs, 0, sArgv) != PH7_OK) { + PH7_VmMemoryError(&(*pVm)); } + ph7_value_reset_string_cursor(sArgv); } pMethod = pMain; /* A set of arguments is stored in array of strings */ diff --git a/include/ph7int.h b/include/ph7int.h index 40c3fe0..1c2cbb3 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1221,6 +1221,7 @@ struct ph7_vm { SyHash hDBAL; /* DBAL installed drivers */ SyBlob sConsumer; /* Default VM consumer [i.e Redirect all VM output to this blob] */ SyBlob sArgv; /* $argv[] collector [refer to the [getopt()] implementation for more information] */ + SyBlob sArgvEntries; /* VM-owned argument list, each entry terminated by NUL */ SySet aModules; /* Set of loaded modules */ SySet aModuleHandles; /* Libraries retained after initialization attempts */ SySet aFiles; /* SyString pointers, VM-owned until release */