/* * gr - get record attributes */ static NuError GetRecordFunc(ExerciserState* pState, int argc, char** argv) { NuError err; const NuRecord* pRecord; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 2); err = NuGetRecord(ExerciserState_GetNuArchive(pState), strtol(argv[1], nil, 0), &pRecord); if (err == kNuErrNone) { printf("Exerciser: success, call returned:\n"); printf("\tfileSysID : %d\n", pRecord->recFileSysID); printf("\tfileSysInfo : 0x%04x ('%c')\n", pRecord->recFileSysInfo, NuGetSepFromSysInfo(pRecord->recFileSysInfo)); printf("\taccess : 0x%02lx\n", pRecord->recAccess); printf("\tfileType : 0x%04lx\n", pRecord->recFileType); printf("\textraType : 0x%04lx\n", pRecord->recExtraType); printf("\tcreateWhen : ...\n"); printf("\tmodWhen : ...\n"); /* too lazy */ printf("\tarchiveWhen : ...\n"); } return err; }
/* * ar - add an empty record */ static NuError AddRecordFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuRecordIdx recordIdx; NuFileDetails nuFileDetails; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 2); memset(&nuFileDetails, 0, sizeof(nuFileDetails)); nuFileDetails.threadID = 0; /* irrelevant */ nuFileDetails.storageName = argv[1]; nuFileDetails.fileSysID = kNuFileSysUnknown; nuFileDetails.fileSysInfo = (short) kFssep; nuFileDetails.access = kUnlocked; /* fileType, extraType, storageType, dates */ err = NuAddRecord(ExerciserState_GetNuArchive(pState), &nuFileDetails, &recordIdx); if (err == kNuErrNone) printf("Exerciser: success, new recordIdx=%ld\n", recordIdx); return err; }
/* * et - extract thread */ static NuError ExtractThreadFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuDataSink* pDataSink = nil; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 3); err = NuCreateDataSinkForFile(true, kNuConvertOff, argv[2], kFssep, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: data sink create failed\n"); goto bail; } err = NuExtractThread(ExerciserState_GetNuArchive(pState), strtol(argv[1], nil, 0), pDataSink); /* fall through with err */ bail: NuFreeDataSink(pDataSink); return err; }
/* * p - print */ static NuError PrintFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 1); return NuContents(ExerciserState_GetNuArchive(pState), PrintEntry); }
/* * t - test archive */ static NuError TestFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 1); return NuTest(ExerciserState_GetNuArchive(pState)); }
/* * pd - print debug */ static NuError PrintDebugFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 1); return NuDebugDumpArchive(ExerciserState_GetNuArchive(pState)); }
/* * sev - set value * * Currently takes numeric arguments. */ static NuError SetValueFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 3); return NuSetValue(ExerciserState_GetNuArchive(pState), (NuValueID) strtol(argv[1], NULL, 0), strtol(argv[2], NULL, 0)); }
/* * tr - test record */ static NuError TestRecordFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 2); return NuTestRecord(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0)); }
/* * re - rename record */ static NuError RenameFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 4); return NuRename(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0), argv[2], argv[3][0]); }
/* * sec - set error callback * * Use an error handler callback. */ static NuError SetErrorCallbackFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 1); NuSetErrorHandler(ExerciserState_GetNuArchive(pState), ErrorHandler); return kNuErrNone; }
/* * e - extract all files (selection-filtered) */ static NuError ExtractFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 1); NuSetSelectionFilter(ExerciserState_GetNuArchive(pState), SelectionFilter); return NuExtract(ExerciserState_GetNuArchive(pState)); }
/* * dt - delete thread */ static NuError DeleteThreadFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 2); return NuDeleteThread(ExerciserState_GetNuArchive(pState), strtol(argv[1], nil, 0)); }
/* * fl - flush changes to archive */ static NuError FlushFunc(ExerciserState* pState, int argc, char** argv) { NuError err; uint32_t flushStatus; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 1); err = NuFlush(ExerciserState_GetNuArchive(pState), &flushStatus); if (err != kNuErrNone) printf("Exerciser: flush failed, status flags=0x%04x\n", flushStatus); return err; }
/* * gev - get value * * Currently takes numeric arguments. We could be nice and accept the * things like "IgnoreCRC" for kNuValueIgnoreCRC, but not yet. */ static NuError GetValueFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuValue value; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 2); err = NuGetValue(ExerciserState_GetNuArchive(pState), (NuValueID) strtol(argv[1], NULL, 0), &value); if (err == kNuErrNone) printf(" --> %u\n", value); return err; }
/* * grip - get record idx by position */ static NuError GetRecordIdxByPositionFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuRecordIdx recIdx; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 2); err = NuGetRecordIdxByPosition(ExerciserState_GetNuArchive(pState), strtol(argv[1], nil, 0), &recIdx); if (err == kNuErrNone) printf("Exerciser: success, returned recordIdx=%ld\n", recIdx); return err; }
/* * cl - close archive */ static NuError CloseFunc(ExerciserState* pState, int argc, char** argv) { NuError err; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 1); err = NuClose(ExerciserState_GetNuArchive(pState)); if (err == kNuErrNone) { ExerciserState_SetNuArchive(pState, NULL); ExerciserState_SetArchivePath(pState, NULL); } return err; }
/* * ors - open streaming read-only */ static NuError OpenStreamingReadOnlyFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuArchive* pArchive; FILE* fp = nil; assert(ExerciserState_GetNuArchive(pState) == nil); assert(argc == 2); if ((fp = fopen(argv[1], kNuFileOpenReadOnly)) == nil) { err = errno ? (NuError)errno : kNuErrGeneric; fprintf(stderr, "Exerciser: unable to open '%s'\n", argv[1]); } else { err = NuStreamOpenRO(fp, &pArchive); if (err == kNuErrNone) { ExerciserState_SetNuArchive(pState, pArchive); ExerciserState_SetArchivePath(pState, argv[1]); fp = nil; } } if (fp != nil) fclose(fp); return err; }
/* * grin - get record idx by name */ static NuError GetRecordIdxByNameFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuRecordIdx recIdx; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 2); err = NuGetRecordIdxByName(ExerciserState_GetNuArchive(pState), argv[1], &recIdx); if (err == kNuErrNone) printf("Exerciser: success, returned recordIdx=%u\n", recIdx); return err; }
/* * upt - update pre-sized thread */ static NuError UpdatePresizedThreadFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuDataSource* pDataSource = NULL; char* lineBuf = NULL; long ourLen; int32_t maxLen; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 2); lineBuf = (char*)malloc(kNiceLineLen); assert(lineBuf != NULL); err = GetLine("Enter data for thread", lineBuf, kNiceLineLen); if (err != kNuErrNone) goto bail; ourLen = strlen(lineBuf); /* use "ourLen" for both buffer len and data len */ err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, ourLen, (uint8_t*)lineBuf, 0, ourLen, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: data source create failed (err=%d)\n", err); goto bail; } lineBuf = NULL; /* now owned by the library */ err = NuUpdatePresizedThread(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0), pDataSource, &maxLen); if (err == kNuErrNone) printf("Exerciser: success; function returned maxLen=%d\n", maxLen); bail: NuFreeDataSource(pDataSource); if (lineBuf != NULL) free(lineBuf); return err; }
/* * af - add file to archive */ static NuError AddFileFunc(ExerciserState* pState, int argc, char** argv) { NuFileDetails nuFileDetails; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 2); memset(&nuFileDetails, 0, sizeof(nuFileDetails)); nuFileDetails.threadID = kNuThreadIDDataFork; nuFileDetails.storageNameMOR = argv[1]; nuFileDetails.fileSysID = kNuFileSysUnknown; nuFileDetails.fileSysInfo = (short) kFssep; nuFileDetails.access = kUnlocked; /* fileType, extraType, storageType, dates */ return NuAddFile(ExerciserState_GetNuArchive(pState), argv[1], &nuFileDetails, false, NULL); }
/* * gmh - get master header */ static NuError GetMasterHeaderFunc(ExerciserState* pState, int argc, char** argv) { NuError err; const NuMasterHeader* pMasterHeader; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 1); err = NuGetMasterHeader(ExerciserState_GetNuArchive(pState), &pMasterHeader); if (err == kNuErrNone) { printf("Exerciser: success (version=%u, totalRecords=%lu, EOF=%lu)\n", pMasterHeader->mhMasterVersion, pMasterHeader->mhTotalRecords, pMasterHeader->mhMasterEOF); } return err; }
/* * sra - set record attributes * * Right now I'm only allowing changes to file type and aux type. This * could be adapted to do more easily, but the command handler has a * rigid notion of how many arguments each function should have, so * you'd need to list all of them every time. */ static NuError SetRecordAttrFunc(ExerciserState* pState, int argc, char** argv) { NuError err; const NuRecord* pRecord; NuRecordAttr recordAttr; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 4); err = NuGetRecord(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0), &pRecord); if (err != kNuErrNone) return err; printf("Exerciser: NuGetRecord succeeded, calling NuSetRecordAttr\n"); NuRecordCopyAttr(&recordAttr, pRecord); recordAttr.fileType = strtol(argv[2], NULL, 0); recordAttr.extraType = strtol(argv[3], NULL, 0); /*recordAttr.fileSysInfo = ':';*/ return NuSetRecordAttr(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0), &recordAttr); }
/* * orw - open read-write */ static NuError OpenReadWriteFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuArchive* pArchive; assert(ExerciserState_GetNuArchive(pState) == NULL); assert(argc == 2); err = NuOpenRW(argv[1], kTempFile, 0, &pArchive); if (err == kNuErrNone) { ExerciserState_SetNuArchive(pState, pArchive); ExerciserState_SetArchivePath(pState, argv[1]); } return err; }
/* * oro - open read-only */ static NuError OpenReadOnlyFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuArchive* pArchive; assert(ExerciserState_GetNuArchive(pState) == nil); assert(argc == 2); err = NuOpenRO(argv[1], &pArchive); if (err == kNuErrNone) { ExerciserState_SetNuArchive(pState, pArchive); ExerciserState_SetArchivePath(pState, argv[1]); } return err; }
/* * Parse a command from the user. * * "lineBuf" will be mangled. On success, "pFunc", "pArgc", and "pArgv" * will receive the results. */ static NuError ParseLine(char* lineBuf, ExerciserState* pState, CommandFunc* pFunc, int* pArgc, char*** pArgv) { NuError err = kNuErrSyntax; char* command; char* cp; int i; /* * Parse the strings. */ command = strtok(lineBuf, kWhitespace); if (command == nil) { /* no command; the user probably just hit "enter" on a blank line */ *pFunc = NothingFunc; *pArgc = 0; *pArgv = nil; err = kNuErrNone; goto bail; } /* no real need to be flexible; add 1 for command and one for nil */ *pArgv = (char**) malloc(sizeof(char*) * (kMaxArgs+2)); (*pArgv)[0] = command; *pArgc = 1; cp = strtok(nil, kWhitespace); while (cp != nil) { if (*pArgc >= kMaxArgs+1) { printf("ERROR: too many arguments\n"); goto bail; } (*pArgv)[*pArgc] = cp; (*pArgc)++; cp = strtok(nil, kWhitespace); } assert(*pArgc < kMaxArgs+2); (*pArgv)[*pArgc] = nil; /* * Look up the command. */ for (i = 0; i < (int)NELEM(gCommandTable); i++) { if (strcmp(command, gCommandTable[i].commandStr) == 0) break; } if (i == NELEM(gCommandTable)) { printf("ERROR: unrecognized command\n"); goto bail; } *pFunc = gCommandTable[i].func; /* * Check arguments and flags. */ if (*pArgc -1 != gCommandTable[i].expectedArgCount) { printf("ERROR: expected %d args, found %d\n", gCommandTable[i].expectedArgCount, *pArgc -1); goto bail; } if (gCommandTable[i].flags & kFlagArchiveReq) { if (ExerciserState_GetNuArchive(pState) == nil) { printf("ERROR: must have an archive open\n"); goto bail; } } if (gCommandTable[i].flags & kFlagNoArchiveReq) { if (ExerciserState_GetNuArchive(pState) != nil) { printf("ERROR: an archive is already open\n"); goto bail; } } /* * Looks good! */ err = kNuErrNone; bail: return err; }
/* * Interpret commands, do clever things. */ static NuError CommandLoop(void) { NuError err = kNuErrNone; ExerciserState* pState = ExerciserState_New(); CommandFunc func; char lineBuf[128]; int argc; char** argv = nil; while (1) { printf("\nEnter command (%s)> ", ExerciserState_GetArchiveFile(pState)); fflush(stdout); if (fgets(lineBuf, sizeof(lineBuf), stdin) == nil) { printf("\n"); break; } if (argv != nil) { free(argv); argv = nil; } func = nil; /* sanity check */ err = ParseLine(lineBuf, pState, &func, &argc, &argv); if (err != kNuErrNone) continue; assert(func != nil); if (func == QuitFunc) break; err = (*func)(pState, argc, argv); if (err < 0) printf("Exerciser: received error %d (%s)\n", err, NuStrError(err)); else if (err > 0) printf("Exerciser: received error %d\n", err); if (argv != nil) { free(argv); argv = nil; } } if (ExerciserState_GetNuArchive(pState) != nil) { /* ought to query the archive before saying something like this... */ printf("Exerciser: aborting any un-flushed changes in archive %s\n", ExerciserState_GetArchivePath(pState)); (void) NuAbort(ExerciserState_GetNuArchive(pState)); err = NuClose(ExerciserState_GetNuArchive(pState)); if (err != kNuErrNone) printf("Exerciser: got error %d closing archive\n", err); ExerciserState_SetNuArchive(pState, nil); } if (pState != nil) ExerciserState_Free(pState); if (argv != nil) free(argv); return kNuErrNone; }
/* * at - add thread to record */ static NuError AddThreadFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuDataSource* pDataSource = nil; char* lineBuf = nil; long ourLen, maxLen; NuThreadID threadID; NuThreadIdx threadIdx; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 3); lineBuf = (char*)malloc(kNiceLineLen); assert(lineBuf != nil); threadID = strtol(argv[2], nil, 0); if (NuThreadIDGetClass(threadID) == kNuThreadClassData) { /* load data from a file on disk */ maxLen = 0; err = GetLine("Enter filename", lineBuf, kNiceLineLen); if (err != kNuErrNone) goto bail; if (!lineBuf[0]) { fprintf(stderr, "Invalid filename\n"); err = kNuErrInvalidArg; goto bail; } err = NuCreateDataSourceForFile(kNuThreadFormatUncompressed, 0, lineBuf, false, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: file data source create failed (err=%d)\n", err); goto bail; } } else { if (threadID == kNuThreadIDFilename || threadID == kNuThreadIDComment) { /* select the buffer pre-size */ err = GetLine("Enter max buffer size", lineBuf, kNiceLineLen); if (err != kNuErrNone) goto bail; maxLen = strtol(lineBuf, nil, 0); if (maxLen <= 0) { fprintf(stderr, "Bad length\n"); err = kNuErrInvalidArg; goto bail; } } else { maxLen = 0; } err = GetLine("Enter the thread contents", lineBuf, kNiceLineLen); if (err != kNuErrNone) goto bail; ourLen = strlen(lineBuf); /* create a data source from the buffer */ err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, maxLen, (unsigned char*)lineBuf, 0, ourLen, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: buffer data source create failed (err=%d)\n", err); goto bail; } lineBuf = nil; /* now owned by the library */ } err = NuAddThread(ExerciserState_GetNuArchive(pState), strtol(argv[1], nil, 0), threadID, pDataSource, &threadIdx); if (err == kNuErrNone) { pDataSource = nil; /* library owns it now */ printf("Exerciser: success; function returned threadIdx=%ld\n", threadIdx); } bail: NuFreeDataSource(pDataSource); if (lineBuf != nil) free(lineBuf); return err; }