pax_global_header00006660000000000000000000000064131610051650014510gustar00rootroot0000000000000052 comment=137cafa05b349bb57f8628a66158a6c8fd50506d nulib2-3.1.0/000077500000000000000000000000001316100516500127045ustar00rootroot00000000000000nulib2-3.1.0/.gitignore000066400000000000000000000001111316100516500146650ustar00rootroot00000000000000autom4te.cache *.o *.obj *.a *.lib *.dll *.exe *.exp *.pdb *~ *.swp tags nulib2-3.1.0/README.md000066400000000000000000000010001316100516500141520ustar00rootroot00000000000000NuLib2 ====== NuLib2 is a command-line file archiver for Apple II archives. It can operate on ShrinkIt and Binary II files (.shk, .sdk, .bxy, .bse, .bny, .bqy). NufxLib is a library of code that supports ShrinkIt archives. It's used by NuLib2 and CiderPress. A pre-built NuLib2 binary is available for x86 Windows. For Linux and Mac OS X systems, you can download the source code and build it. More information, including full documentation for NuLib2 and NufxLib, can be found on http://www.nulib.com/. nulib2-3.1.0/nufxlib/000077500000000000000000000000001316100516500143535ustar00rootroot00000000000000nulib2-3.1.0/nufxlib/.gitignore000066400000000000000000000003721316100516500163450ustar00rootroot00000000000000# config-generated sources Makefile config.h config.log config.status # generated binaries libnufx.a samples/exerciser samples/imgconv samples/launder samples/test-basic samples/test-extract samples/test-names samples/test-simple samples/test-twirl nulib2-3.1.0/nufxlib/Archive.c000066400000000000000000001114401316100516500161010ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Archive structure creation and manipulation. */ #include "NufxLibPriv.h" #ifdef HAVE_FCNTL_H # include #endif #ifndef O_BINARY # define O_BINARY 0 #endif /* master header identification */ static const uint8_t kNuMasterID[kNufileIDLen] = { 0x4e, 0xf5, 0x46, 0xe9, 0x6c, 0xe5 }; /* other identification; can be no longer than kNufileIDLen */ static const uint8_t kNuBinary2ID[] = { 0x0a, 0x47, 0x4c }; static const uint8_t kNuSHKSEAID[] = { 0xa2, 0x2e, 0x00 }; /* * Offsets to some interesting places in the wrappers. */ #define kNuBNYFileSizeLo 8 /* file size in 512-byte blocks (2B) */ #define kNuBNYFileSizeHi 114 /* ... (2B) */ #define kNuBNYEOFLo 20 /* file size in bytes (3B) */ #define kNuBNYEOFHi 116 /* ... (1B) */ #define kNuBNYDiskSpace 117 /* total space req'd; equiv FileSize (4B) */ #define kNuBNYFilesToFollow 127 /* (1B) #of files in rest of BNY file */ #define kNuSEAFunkySize 11938 /* length of archive + 68 (4B?) */ #define kNuSEAFunkyAdjust 68 /* ... adjustment to "FunkySize" */ #define kNuSEALength1 11946 /* length of archive (4B?) */ #define kNuSEALength2 12001 /* length of archive (4B?) */ #define kDefaultJunkSkipMax 1024 /* default junk scan size */ static void Nu_CloseAndFree(NuArchive* pArchive); /* * =========================================================================== * Archive and MasterHeader utility functions * =========================================================================== */ /* * Allocate and initialize a new NuArchive structure. */ static NuError Nu_NuArchiveNew(NuArchive** ppArchive) { Assert(ppArchive != NULL); /* validate some assumptions we make throughout the code */ Assert(sizeof(int) >= 2); Assert(sizeof(void*) >= sizeof(NuArchive*)); *ppArchive = Nu_Calloc(NULL, sizeof(**ppArchive)); if (*ppArchive == NULL) return kNuErrMalloc; (*ppArchive)->structMagic = kNuArchiveStructMagic; (*ppArchive)->recordIdxSeed = 1000; /* could be a random number */ (*ppArchive)->nextRecordIdx = (*ppArchive)->recordIdxSeed; /* * Initialize assorted values to defaults. We don't try to do any * system-specific values here; it's up to the application to decide * what is most appropriate for the current system. */ (*ppArchive)->valIgnoreCRC = false; #ifdef ENABLE_LZW (*ppArchive)->valDataCompression = kNuCompressLZW2; #else (*ppArchive)->valDataCompression = kNuCompressNone; #endif (*ppArchive)->valDiscardWrapper = false; (*ppArchive)->valEOL = kNuEOLLF; /* non-UNIX apps must override */ (*ppArchive)->valConvertExtractedEOL = kNuConvertOff; (*ppArchive)->valOnlyUpdateOlder = false; (*ppArchive)->valAllowDuplicates = false; (*ppArchive)->valHandleExisting = kNuMaybeOverwrite; (*ppArchive)->valModifyOrig = false; (*ppArchive)->valMimicSHK = false; (*ppArchive)->valMaskDataless = false; (*ppArchive)->valStripHighASCII = false; /* bug: this can't be set by application! */ (*ppArchive)->valJunkSkipMax = kDefaultJunkSkipMax; (*ppArchive)->valIgnoreLZW2Len = false; (*ppArchive)->valHandleBadMac = false; (*ppArchive)->messageHandlerFunc = gNuGlobalErrorMessageHandler; return kNuErrNone; } /* * Free up a NuArchive structure and its contents. */ static NuError Nu_NuArchiveFree(NuArchive* pArchive) { Assert(pArchive != NULL); Assert(pArchive->structMagic == kNuArchiveStructMagic); (void) Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->origRecordSet); pArchive->haveToc = false; (void) Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->copyRecordSet); (void) Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->newRecordSet); Nu_Free(NULL, pArchive->archivePathnameUNI); Nu_Free(NULL, pArchive->tmpPathnameUNI); Nu_Free(NULL, pArchive->compBuf); Nu_Free(NULL, pArchive->lzwCompressState); Nu_Free(NULL, pArchive->lzwExpandState); /* mark it as deceased to prevent further use, then free it */ pArchive->structMagic = kNuArchiveStructMagic ^ 0xffffffff; Nu_Free(NULL, pArchive); return kNuErrNone; } /* * Copy a NuMasterHeader struct. */ void Nu_MasterHeaderCopy(NuArchive* pArchive, NuMasterHeader* pDstHeader, const NuMasterHeader* pSrcHeader) { Assert(pArchive != NULL); Assert(pDstHeader != NULL); Assert(pSrcHeader != NULL); *pDstHeader = *pSrcHeader; } /* * Get a pointer to the archive master header (this is an API call). */ NuError Nu_GetMasterHeader(NuArchive* pArchive, const NuMasterHeader** ppMasterHeader) { if (ppMasterHeader == NULL) return kNuErrInvalidArg; *ppMasterHeader = &pArchive->masterHeader; return kNuErrNone; } /* * Allocate the general-purpose compression buffer, if needed. */ NuError Nu_AllocCompressionBufferIFN(NuArchive* pArchive) { Assert(pArchive != NULL); if (pArchive->compBuf != NULL) return kNuErrNone; pArchive->compBuf = Nu_Malloc(pArchive, kNuGenCompBufSize); if (pArchive->compBuf == NULL) return kNuErrMalloc; return kNuErrNone; } /* * Return a unique value. */ NuRecordIdx Nu_GetNextRecordIdx(NuArchive* pArchive) { return pArchive->nextRecordIdx++; } /* * Return a unique value. */ NuThreadIdx Nu_GetNextThreadIdx(NuArchive* pArchive) { return pArchive->nextRecordIdx++; /* just use the record counter */ } /* * =========================================================================== * Wrapper (SEA, BXY, BSE) functions * =========================================================================== */ /* * Copy the wrapper from the archive file to the temp file. */ NuError Nu_CopyWrapperToTemp(NuArchive* pArchive) { NuError err; Assert(pArchive->headerOffset); /* no wrapper to copy?? */ err = Nu_FSeek(pArchive->archiveFp, 0, SEEK_SET); BailError(err); err = Nu_FSeek(pArchive->tmpFp, 0, SEEK_SET); BailError(err); err = Nu_CopyFileSection(pArchive, pArchive->tmpFp, pArchive->archiveFp, pArchive->headerOffset); BailError(err); bail: return err; } /* * Fix up the wrapper. The SEA and BXY headers have some fields * set according to file length and archive attributes. * * Pass in the file pointer that will be written to. Wrappers are * assumed to start at offset 0. * * Wrappers must appear in this order: * Leading junk * Binary II * ShrinkIt SEA (Self-Extracting Archive) * * If they didn't, we wouldn't be this far. * * I have a Binary II specification, but don't have one for SEA, so I'm * making educated guesses based on the differences between archives. I'd * guess some of the SEA weirdness stems from some far-sighted support * for multiple archives within a single SEA wrapper. */ NuError Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp) { NuError err = kNuErrNone; Boolean hasBinary2, hasSea; uint8_t identBuf[kNufileIDLen]; uint32_t archiveLen, archiveLen512; Assert(pArchive->newMasterHeader.isValid); /* need new crc and len */ hasBinary2 = hasSea = false; switch (pArchive->archiveType) { case kNuArchiveNuFX: goto bail; case kNuArchiveNuFXInBNY: hasBinary2 = true; break; case kNuArchiveNuFXSelfEx: hasSea = true; break; case kNuArchiveNuFXSelfExInBNY: hasBinary2 = hasSea = true; break; default: if (pArchive->headerOffset != 0 && pArchive->headerOffset != pArchive->junkOffset) { Nu_ReportError(NU_BLOB, kNuErrNone, "Can't fix the wrapper??"); err = kNuErrInternal; goto bail; } else goto bail; } err = Nu_FSeek(fp, pArchive->junkOffset, SEEK_SET); BailError(err); if (hasBinary2) { /* sanity check - make sure it's Binary II */ Nu_ReadBytes(pArchive, fp, identBuf, kNufileIDLen); if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed reading BNY wrapper"); goto bail; } if (memcmp(identBuf, kNuBinary2ID, sizeof(kNuBinary2ID)) != 0) { err = kNuErrInternal; Nu_ReportError(NU_BLOB, kNuErrNone,"Didn't find Binary II wrapper"); goto bail; } /* archiveLen includes the SEA wrapper, if any, but excludes junk */ archiveLen = pArchive->newMasterHeader.mhMasterEOF + (pArchive->headerOffset - pArchive->junkOffset) - kNuBinary2BlockSize; archiveLen512 = (archiveLen + 511) / 512; err = Nu_FSeek(fp, kNuBNYFileSizeLo - kNufileIDLen, SEEK_CUR); BailError(err); Nu_WriteTwo(pArchive, fp, (uint16_t)(archiveLen512 & 0xffff)); err = Nu_FSeek(fp, kNuBNYFileSizeHi - (kNuBNYFileSizeLo+2), SEEK_CUR); BailError(err); Nu_WriteTwo(pArchive, fp, (uint16_t)(archiveLen512 >> 16)); err = Nu_FSeek(fp, kNuBNYEOFLo - (kNuBNYFileSizeHi+2), SEEK_CUR); BailError(err); Nu_WriteTwo(pArchive, fp, (uint16_t)(archiveLen & 0xffff)); Nu_WriteOne(pArchive, fp, (uint8_t)((archiveLen >> 16) & 0xff)); err = Nu_FSeek(fp, kNuBNYEOFHi - (kNuBNYEOFLo+3), SEEK_CUR); BailError(err); Nu_WriteOne(pArchive, fp, (uint8_t)(archiveLen >> 24)); err = Nu_FSeek(fp, kNuBNYDiskSpace - (kNuBNYEOFHi+1), SEEK_CUR); BailError(err); Nu_WriteFour(pArchive, fp, archiveLen512); /* probably ought to update "modified when" date/time field */ /* seek just past end of BNY wrapper */ err = Nu_FSeek(fp, kNuBinary2BlockSize - (kNuBNYDiskSpace+4), SEEK_CUR); BailError(err); if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed updating Binary II wrapper"); goto bail; } } if (hasSea) { /* sanity check - make sure it's SEA */ Nu_ReadBytes(pArchive, fp, identBuf, kNufileIDLen); if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed reading SEA wrapper"); goto bail; } if (memcmp(identBuf, kNuSHKSEAID, sizeof(kNuSHKSEAID)) != 0) { err = kNuErrInternal; Nu_ReportError(NU_BLOB, kNuErrNone, "Didn't find SEA wrapper"); goto bail; } archiveLen = pArchive->newMasterHeader.mhMasterEOF; err = Nu_FSeek(fp, kNuSEAFunkySize - kNufileIDLen, SEEK_CUR); BailError(err); Nu_WriteFour(pArchive, fp, archiveLen + kNuSEAFunkyAdjust); err = Nu_FSeek(fp, kNuSEALength1 - (kNuSEAFunkySize+4), SEEK_CUR); BailError(err); Nu_WriteTwo(pArchive, fp, (uint16_t)archiveLen); err = Nu_FSeek(fp, kNuSEALength2 - (kNuSEALength1+2), SEEK_CUR); BailError(err); Nu_WriteTwo(pArchive, fp, (uint16_t)archiveLen); /* seek past end of SEA wrapper */ err = Nu_FSeek(fp, kNuSEAOffset - (kNuSEALength2+2), SEEK_CUR); BailError(err); if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed updating SEA wrapper"); goto bail; } } bail: return kNuErrNone; } /* * Adjust wrapper-induced padding on the archive. * * GS/ShrinkIt v1.1 does some peculiar things with SEA (Self-Extracting * Archive) files. For no apparent reason, it always adds one extra 00 * byte to the end. When you combine SEA and BXY to make BSE, it will * leave that extra byte inside the BXY 128-byte padding area, UNLESS * the archive itself happens to be exactly 128 bytes, in which case * it throws the pad byte onto the end -- resulting in an archive that * isn't an exact multiple of 128. * * I've chosen to emulate the 1-byte padding "feature" of GSHK, but I'm * not going to try to emulate the quirky behavior described above. * * The SEA pad byte is added first, and then the 128-byte BXY padding * is considered. In the odd case described above, the file would be * 127 bytes larger with nufxlib than it is with GSHK. This shouldn't * require additional disk space to be used, assuming a filesystem block * size of at least 128 bytes. */ NuError Nu_AdjustWrapperPadding(NuArchive* pArchive, FILE* fp) { NuError err = kNuErrNone; Boolean hasBinary2, hasSea; hasBinary2 = hasSea = false; switch (pArchive->archiveType) { case kNuArchiveNuFX: goto bail; case kNuArchiveNuFXInBNY: hasBinary2 = true; break; case kNuArchiveNuFXSelfEx: hasSea = true; break; case kNuArchiveNuFXSelfExInBNY: hasBinary2 = hasSea = true; break; default: if (pArchive->headerOffset != 0 && pArchive->headerOffset != pArchive->junkOffset) { Nu_ReportError(NU_BLOB, kNuErrNone, "Can't check the padding??"); err = kNuErrInternal; goto bail; } else goto bail; } err = Nu_FSeek(fp, 0, SEEK_END); BailError(err); if (hasSea && pArchive->valMimicSHK) { /* throw on a single pad byte, for no apparent reason whatsoever */ Nu_WriteOne(pArchive, fp, 0); } if (hasBinary2) { /* pad out to the next 128-byte boundary */ long curOffset; err = Nu_FTell(fp, &curOffset); BailError(err); curOffset -= pArchive->junkOffset; /* don't factor junk into account */ DBUG(("+++ BNY needs %ld bytes of padding\n", curOffset & 0x7f)); if (curOffset & 0x7f) { int i; for (i = kNuBinary2BlockSize - (curOffset & 0x7f); i > 0; i--) Nu_WriteOne(pArchive, fp, 0); } } if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed updating wrapper padding"); goto bail; } bail: return err; } /* * =========================================================================== * Open an archive * =========================================================================== */ /* * Read the master header from the archive file. * * This also handles skipping the first 128 bytes of a .BXY file and the * front part of a self-extracting GSHK archive. * * We try to provide helpful messages about things that aren't archives, * but try to stay silent about files that are other types of archives. * That way, if the application is trying a series of libraries to find * one that will accept the file, we don't generate spurious complaints. * * Since there's a fair possibility that whoever is opening this file is * also interested in related formats, we try to return a meaningful error * code for stuff we recognize (especially Binary II). * * If at first we don't succeed, we keep trying further along until we * find something we recognize. We don't want to just scan for the * NuFile ID, because that might prevent this from working properly with * SEA archives which push the NuFX start out about 12K. We also wouldn't * be able to update the BNY/SEA wrappers correctly. So, we inch our way * along until we find something we recognize or get bored. * * On exit, the stream will be positioned just past the master header. */ static NuError Nu_ReadMasterHeader(NuArchive* pArchive) { NuError err; uint16_t crc; FILE* fp; NuMasterHeader* pHeader; Boolean isBinary2 = false; Boolean isSea = false; Assert(pArchive != NULL); fp = pArchive->archiveFp; /* saves typing */ pHeader = &pArchive->masterHeader; pArchive->junkOffset = 0; retry: pArchive->headerOffset = pArchive->junkOffset; Nu_ReadBytes(pArchive, fp, pHeader->mhNufileID, kNufileIDLen); /* may have read fewer than kNufileIDLen; that's okay */ if (memcmp(pHeader->mhNufileID, kNuBinary2ID, sizeof(kNuBinary2ID)) == 0) { int count; /* looks like a Binary II archive, might be BXY or BSE; seek forward */ err = Nu_SeekArchive(pArchive, fp, kNuBNYFilesToFollow - kNufileIDLen, SEEK_CUR); if (err != kNuErrNone) { err = kNuErrNotNuFX; /* probably too short to be BNY, so go ahead and whine */ Nu_ReportError(NU_BLOB, kNuErrNone, "Looks like a truncated Binary II archive?"); goto bail; } /* * Check "files to follow", so we can be sure this isn't a BNY that * just happened to have a .SHK as the first file. If it is, then * any updates to the archive will trash the rest of the BNY files. */ count = Nu_ReadOne(pArchive, fp); if (count != 0) { err = kNuErrIsBinary2; /*Nu_ReportError(NU_BLOB, kNuErrNone, "This is a Binary II archive with %d files in it", count+1);*/ DBUG(("This is a Binary II archive with %d files in it\n",count+1)); goto bail; } /* that was last item in BNY header, no need to seek */ Assert(kNuBNYFilesToFollow == kNuBinary2BlockSize -1); isBinary2 = true; pArchive->headerOffset += kNuBinary2BlockSize; Nu_ReadBytes(pArchive, fp, pHeader->mhNufileID, kNufileIDLen); } if (memcmp(pHeader->mhNufileID, kNuSHKSEAID, sizeof(kNuSHKSEAID)) == 0) { /* might be GSHK self-extracting; seek forward */ err = Nu_SeekArchive(pArchive, fp, kNuSEAOffset - kNufileIDLen, SEEK_CUR); if (err != kNuErrNone) { err = kNuErrNotNuFX; Nu_ReportError(NU_BLOB, kNuErrNone, "Looks like GS executable, not NuFX"); goto bail; } isSea = true; pArchive->headerOffset += kNuSEAOffset; Nu_ReadBytes(pArchive, fp, pHeader->mhNufileID, kNufileIDLen); } if (memcmp(kNuMasterID, pHeader->mhNufileID, kNufileIDLen) != 0) { /* * Doesn't look like a NuFX archive. Scan forward and see if we * can find the start past some leading junk. MacBinary headers * and chunks of HTTP seem popular on FTP sites. */ if ((pArchive->openMode == kNuOpenRO || pArchive->openMode == kNuOpenRW) && pArchive->junkOffset < (long)pArchive->valJunkSkipMax) { pArchive->junkOffset++; DBUG(("+++ scanning from offset %ld\n", pArchive->junkOffset)); err = Nu_SeekArchive(pArchive, fp, pArchive->junkOffset, SEEK_SET); BailError(err); goto retry; } err = kNuErrNotNuFX; if (isBinary2) { err = kNuErrIsBinary2; /*Nu_ReportError(NU_BLOB, kNuErrNone, "Looks like Binary II, not NuFX");*/ DBUG(("Looks like Binary II, not NuFX\n")); } else if (isSea) Nu_ReportError(NU_BLOB, kNuErrNone, "Looks like GS executable, not NuFX"); else if (Nu_HeaderIOFailed(pArchive, fp) != kNuErrNone) Nu_ReportError(NU_BLOB, kNuErrNone, "Couldn't read enough data, not NuFX?"); else Nu_ReportError(NU_BLOB, kNuErrNone, "Not a NuFX archive? Got 0x%02x%02x%02x%02x%02x%02x...", pHeader->mhNufileID[0], pHeader->mhNufileID[1], pHeader->mhNufileID[2], pHeader->mhNufileID[3], pHeader->mhNufileID[4], pHeader->mhNufileID[5]); goto bail; } if (pArchive->junkOffset != 0) { DBUG(("+++ found apparent start of archive at offset %ld\n", pArchive->junkOffset)); } crc = 0; pHeader->mhMasterCRC = Nu_ReadTwo(pArchive, fp); pHeader->mhTotalRecords = Nu_ReadFourC(pArchive, fp, &crc); pHeader->mhArchiveCreateWhen = Nu_ReadDateTimeC(pArchive, fp, &crc); pHeader->mhArchiveModWhen = Nu_ReadDateTimeC(pArchive, fp, &crc); pHeader->mhMasterVersion = Nu_ReadTwoC(pArchive, fp, &crc); Nu_ReadBytesC(pArchive, fp, pHeader->mhReserved1, kNufileMasterReserved1Len, &crc); pHeader->mhMasterEOF = Nu_ReadFourC(pArchive, fp, &crc); Nu_ReadBytesC(pArchive, fp, pHeader->mhReserved2, kNufileMasterReserved2Len, &crc); /* check for errors in any of the above reads */ if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed reading master header"); goto bail; } if (pHeader->mhMasterVersion > kNuMaxMHVersion) { err = kNuErrBadMHVersion; Nu_ReportError(NU_BLOB, err, "Bad Master Header version %u", pHeader->mhMasterVersion); goto bail; } /* compare the CRC */ if (!pArchive->valIgnoreCRC && crc != pHeader->mhMasterCRC) { if (!Nu_ShouldIgnoreBadCRC(pArchive, NULL, kNuErrBadMHCRC)) { err = kNuErrBadMHCRC; Nu_ReportError(NU_BLOB, err, "Stored MH CRC=0x%04x, calc=0x%04x", pHeader->mhMasterCRC, crc); goto bail; } } /* * Check for an unusual condition. GS/ShrinkIt appears to update * the archive structure in the disk file periodically as it writes, * so it's possible to get an apparently complete archive (with * correct CRCs in the master and record headers!) that is actually * only partially written. I did this by accident when archiving a * 3.5" disk across a slow AppleTalk network. The only obvious * indication of brain-damage, until you try to unpack the archive, * seems to be a bogus MasterEOF==48. * * Matthew Fischer found some archives that exhibit MasterEOF==0 * but are otherwise functional, suggesting that there might be a * version of ShrinkIt that created these without reporting an error. * One such archive was a disk image with no filename entry, suggesting * that it was created by an early version of P8 ShrinkIt. * * So, we only fail if the EOF equals 48. */ if (pHeader->mhMasterEOF == kNuMasterHeaderSize) { err = kNuErrNoRecords; Nu_ReportError(NU_BLOB, err, "Master EOF is %u, archive is probably truncated", pHeader->mhMasterEOF); goto bail; } /* * Set up a few things in the archive structure on our way out. */ if (isBinary2) { if (isSea) pArchive->archiveType = kNuArchiveNuFXSelfExInBNY; else pArchive->archiveType = kNuArchiveNuFXInBNY; } else { if (isSea) pArchive->archiveType = kNuArchiveNuFXSelfEx; else pArchive->archiveType = kNuArchiveNuFX; } if (isSea || isBinary2) { DBUG(("--- Archive isSea=%d isBinary2=%d type=%d\n", isSea, isBinary2, pArchive->archiveType)); } /*pArchive->origNumRecords = pHeader->mhTotalRecords;*/ pArchive->currentOffset = pArchive->headerOffset + kNuMasterHeaderSize; /*DBUG(("--- GOT: records=%ld, vers=%d, EOF=%ld, type=%d, hdrOffset=%ld\n", pHeader->mhTotalRecords, pHeader->mhMasterVersion, pHeader->mhMasterEOF, pArchive->archiveType, pArchive->headerOffset));*/ pHeader->isValid = true; bail: return err; } /* * Prepare the NuArchive and NuMasterHeader structures for use with a * newly-created archive. */ static void Nu_InitNewArchive(NuArchive* pArchive) { NuMasterHeader* pHeader; Assert(pArchive != NULL); pHeader = &pArchive->masterHeader; memcpy(pHeader->mhNufileID, kNuMasterID, kNufileIDLen); /*pHeader->mhMasterCRC*/ pHeader->mhTotalRecords = 0; Nu_SetCurrentDateTime(&pHeader->mhArchiveCreateWhen); /*pHeader->mhArchiveModWhen*/ pHeader->mhMasterVersion = kNuOurMHVersion; /*pHeader->mhReserved1*/ pHeader->mhMasterEOF = kNuMasterHeaderSize; /*pHeader->mhReserved2*/ pHeader->isValid = true; /* no need to use a temp file for a newly-created archive */ pArchive->valModifyOrig = true; } /* * Open an archive in streaming read-only mode. */ NuError Nu_StreamOpenRO(FILE* infp, NuArchive** ppArchive) { NuError err; NuArchive* pArchive = NULL; Assert(infp != NULL); Assert(ppArchive != NULL); err = Nu_NuArchiveNew(ppArchive); if (err != kNuErrNone) goto bail; pArchive = *ppArchive; pArchive->openMode = kNuOpenStreamingRO; pArchive->archiveFp = infp; pArchive->archivePathnameUNI = strdup("(stream)"); err = Nu_ReadMasterHeader(pArchive); BailError(err); bail: if (err != kNuErrNone) { if (pArchive != NULL) (void) Nu_NuArchiveFree(pArchive); *ppArchive = NULL; } return err; } /* * Open an archive in non-streaming read-only mode. */ NuError Nu_OpenRO(const UNICHAR* archivePathnameUNI, NuArchive** ppArchive) { NuError err; NuArchive* pArchive = NULL; FILE* fp = NULL; if (archivePathnameUNI == NULL || !strlen(archivePathnameUNI) || ppArchive == NULL) { return kNuErrInvalidArg; } *ppArchive = NULL; fp = fopen(archivePathnameUNI, kNuFileOpenReadOnly); if (fp == NULL) { Nu_ReportError(NU_BLOB, errno, "Unable to open '%s'", archivePathnameUNI); err = kNuErrFileOpen; goto bail; } err = Nu_NuArchiveNew(ppArchive); if (err != kNuErrNone) goto bail; pArchive = *ppArchive; pArchive->openMode = kNuOpenRO; pArchive->archiveFp = fp; fp = NULL; pArchive->archivePathnameUNI = strdup(archivePathnameUNI); err = Nu_ReadMasterHeader(pArchive); BailError(err); bail: if (err != kNuErrNone) { if (pArchive != NULL) { (void) Nu_CloseAndFree(pArchive); *ppArchive = NULL; } if (fp != NULL) fclose(fp); } return err; } /* * Open a temp file. If "fileName" contains six Xs ("XXXXXX"), it will * be treated as a mktemp-style template, and modified before use (so * pass a copy of the string in). * * Thought for the day: consider using Win32 SetFileAttributes() to make * temp files hidden. We will need to un-hide it before rolling it over. */ static NuError Nu_OpenTempFile(UNICHAR* fileNameUNI, FILE** pFp) { NuArchive* pArchive = NULL; /* dummy for NU_BLOB */ NuError err = kNuErrNone; int len; /* * If this is a mktemp-style template, use mktemp or mkstemp to fill in * the blanks. * * BUG: not all implementations of mktemp actually generate a unique * name. We probably need to do probing here. Some BSD variants like * to complain about mktemp, since it's generally a bad way to do * things. */ len = strlen(fileNameUNI); if (len > 6 && strcmp(fileNameUNI + len - 6, "XXXXXX") == 0) { #if defined(HAVE_MKSTEMP) && defined(HAVE_FDOPEN) int fd; DBUG(("+++ Using mkstemp\n")); /* this modifies the template *and* opens the file */ fd = mkstemp(fileNameUNI); if (fd < 0) { err = errno ? errno : kNuErrFileOpen; Nu_ReportError(NU_BLOB, kNuErrNone, "mkstemp failed on '%s'", fileNameUNI); goto bail; } DBUG(("--- Fd-opening temp file '%s'\n", fileNameUNI)); *pFp = fdopen(fd, kNuFileOpenReadWriteCreat); if (*pFp == NULL) { close(fd); err = errno ? errno : kNuErrFileOpen; goto bail; } /* file is open, we're done */ goto bail; #else char* result; DBUG(("+++ Using mktemp\n")); result = mktemp(fileNameUNI); if (result == NULL) { Nu_ReportError(NU_BLOB, kNuErrNone, "mktemp failed on '%s'", fileNameUNI); err = kNuErrInternal; goto bail; } /* now open the filename as usual */ #endif } DBUG(("--- Opening temp file '%s'\n", fileNameUNI)); #if defined(HAVE_FDOPEN) { int fd; fd = open(fileNameUNI, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0600); if (fd < 0) { err = errno ? errno : kNuErrFileOpen; goto bail; } *pFp = fdopen(fd, kNuFileOpenReadWriteCreat); if (*pFp == NULL) { close(fd); err = errno ? errno : kNuErrFileOpen; goto bail; } } #else if (access(fileNameUNI, F_OK) == 0) { err = kNuErrFileExists; goto bail; } *pFp = fopen(fileNameUNI, kNuFileOpenReadWriteCreat); if (*pFp == NULL) { err = errno ? errno : kNuErrFileOpen; goto bail; } #endif bail: return err; } /* * Open an archive in read-write mode, optionally creating it if it doesn't * exist. */ NuError Nu_OpenRW(const UNICHAR* archivePathnameUNI, const UNICHAR* tmpPathnameUNI, uint32_t flags, NuArchive** ppArchive) { NuError err; FILE* fp = NULL; FILE* tmpFp = NULL; NuArchive* pArchive = NULL; char* tmpPathDup = NULL; Boolean archiveExists; Boolean newlyCreated; if (archivePathnameUNI == NULL || !strlen(archivePathnameUNI) || tmpPathnameUNI == NULL || !strlen(tmpPathnameUNI) || ppArchive == NULL || (flags & ~(kNuOpenCreat|kNuOpenExcl)) != 0) { return kNuErrInvalidArg; } archiveExists = (access(archivePathnameUNI, F_OK) == 0); /* * Open or create archive file. */ if (archiveExists) { if ((flags & kNuOpenCreat) && (flags & kNuOpenExcl)) { err = kNuErrFileExists; Nu_ReportError(NU_BLOB, err, "File '%s' exists", archivePathnameUNI); goto bail; } fp = fopen(archivePathnameUNI, kNuFileOpenReadWrite); newlyCreated = false; } else { if (!(flags & kNuOpenCreat)) { err = kNuErrFileNotFound; Nu_ReportError(NU_BLOB, err, "File '%s' not found", archivePathnameUNI); goto bail; } fp = fopen(archivePathnameUNI, kNuFileOpenReadWriteCreat); newlyCreated = true; } if (fp == NULL) { if (errno == EACCES) err = kNuErrFileAccessDenied; else err = kNuErrFileOpen; Nu_ReportError(NU_BLOB, errno, "Unable to open '%s'", archivePathnameUNI); goto bail; } /* * Treat zero-length files as newly-created archives. */ if (archiveExists && !newlyCreated) { long length; err = Nu_GetFileLength(NULL, fp, &length); BailError(err); if (!length) { DBUG(("--- treating zero-length file as newly created archive\n")); newlyCreated = true; } } /* * Create a temp file. We don't need one for a newly-created archive, * at least not right away. It's possible the caller could add some * files, flush the changes, and then want to delete them without * closing and reopening the archive. * * So, create a temp file whether we think we need one or not. Won't * do any harm, and might save us some troubles later. */ tmpPathDup = strdup(tmpPathnameUNI); BailNil(tmpPathDup); err = Nu_OpenTempFile(tmpPathDup, &tmpFp); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed opening temp file '%s'", tmpPathnameUNI); goto bail; } err = Nu_NuArchiveNew(ppArchive); if (err != kNuErrNone) goto bail; pArchive = *ppArchive; pArchive->openMode = kNuOpenRW; pArchive->newlyCreated = newlyCreated; pArchive->archivePathnameUNI = strdup(archivePathnameUNI); pArchive->archiveFp = fp; fp = NULL; pArchive->tmpFp = tmpFp; tmpFp = NULL; pArchive->tmpPathnameUNI = tmpPathDup; tmpPathDup = NULL; if (archiveExists && !newlyCreated) { err = Nu_ReadMasterHeader(pArchive); BailError(err); } else { Nu_InitNewArchive(pArchive); } bail: if (err != kNuErrNone) { if (pArchive != NULL) { (void) Nu_CloseAndFree(pArchive); *ppArchive = NULL; } if (fp != NULL) fclose(fp); if (tmpFp != NULL) fclose(tmpFp); if (tmpPathDup != NULL) Nu_Free(pArchive, tmpPathDup); } return err; } /* * =========================================================================== * Update an archive * =========================================================================== */ /* * Write the NuFX master header at the current offset. */ NuError Nu_WriteMasterHeader(NuArchive* pArchive, FILE* fp, NuMasterHeader* pHeader) { NuError err; long crcOffset; uint16_t crc; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pHeader != NULL); Assert(pHeader->isValid); Assert(pHeader->mhMasterVersion == kNuOurMHVersion); crc = 0; Nu_WriteBytes(pArchive, fp, pHeader->mhNufileID, kNufileIDLen); err = Nu_FTell(fp, &crcOffset); BailError(err); Nu_WriteTwo(pArchive, fp, 0); Nu_WriteFourC(pArchive, fp, pHeader->mhTotalRecords, &crc); Nu_WriteDateTimeC(pArchive, fp, pHeader->mhArchiveCreateWhen, &crc); Nu_WriteDateTimeC(pArchive, fp, pHeader->mhArchiveModWhen, &crc); Nu_WriteTwoC(pArchive, fp, pHeader->mhMasterVersion, &crc); Nu_WriteBytesC(pArchive, fp, pHeader->mhReserved1, kNufileMasterReserved1Len, &crc); Nu_WriteFourC(pArchive, fp, pHeader->mhMasterEOF, &crc); Nu_WriteBytesC(pArchive, fp, pHeader->mhReserved2, kNufileMasterReserved2Len, &crc); /* go back and write the CRC (sadly, the seek will flush the stdio buf) */ pHeader->mhMasterCRC = crc; err = Nu_FSeek(fp, crcOffset, SEEK_SET); BailError(err); Nu_WriteTwo(pArchive, fp, pHeader->mhMasterCRC); /* check for errors in any of the above writes */ if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed writing master header"); goto bail; } DBUG(("--- Master header written successfully at %ld (crc=0x%04x)\n", crcOffset - kNufileIDLen, crc)); bail: return err; } /* * =========================================================================== * Close an archive * =========================================================================== */ /* * Close all open files, and free the memory associated with the structure. * * If it's a brand-new archive, and we didn't add anything to it, then we * want to remove the stub archive file. */ static void Nu_CloseAndFree(NuArchive* pArchive) { if (pArchive->archiveFp != NULL) { DBUG(("--- Closing archive\n")); fclose(pArchive->archiveFp); pArchive->archiveFp = NULL; } if (pArchive->tmpFp != NULL) { DBUG(("--- Closing and removing temp file\n")); fclose(pArchive->tmpFp); pArchive->tmpFp = NULL; Assert(pArchive->tmpPathnameUNI != NULL); if (remove(pArchive->tmpPathnameUNI) != 0) { Nu_ReportError(NU_BLOB, errno, "Unable to remove temp file '%s'", pArchive->tmpPathnameUNI); /* keep going */ } } if (pArchive->newlyCreated && Nu_RecordSet_IsEmpty(&pArchive->origRecordSet)) { DBUG(("--- Newly-created archive unmodified; removing it\n")); if (remove(pArchive->archivePathnameUNI) != 0) { Nu_ReportError(NU_BLOB, errno, "Unable to remove archive file '%s'", pArchive->archivePathnameUNI); } } Nu_NuArchiveFree(pArchive); } /* * Flush pending changes to the archive, then close it. */ NuError Nu_Close(NuArchive* pArchive) { NuError err = kNuErrNone; uint32_t flushStatus; Assert(pArchive != NULL); if (!Nu_IsReadOnly(pArchive)) err = Nu_Flush(pArchive, &flushStatus); if (err == kNuErrNone) Nu_CloseAndFree(pArchive); else { DBUG(("--- Close NuFlush status was 0x%4lx\n", flushStatus)); } if (err != kNuErrNone) { DBUG(("--- Nu_Close returning error %d\n", err)); } return err; } /* * =========================================================================== * Delete and replace an archive * =========================================================================== */ /* * Delete the archive file, which should already have been closed. */ NuError Nu_DeleteArchiveFile(NuArchive* pArchive) { Assert(pArchive != NULL); Assert(pArchive->archiveFp == NULL); Assert(pArchive->archivePathnameUNI != NULL); return Nu_DeleteFile(pArchive->archivePathnameUNI); } /* * Rename the temp file on top of the original archive. The temp file * should be closed, and the archive file should be deleted. */ NuError Nu_RenameTempToArchive(NuArchive* pArchive) { Assert(pArchive != NULL); Assert(pArchive->archiveFp == NULL); Assert(pArchive->tmpFp == NULL); Assert(pArchive->archivePathnameUNI != NULL); Assert(pArchive->tmpPathnameUNI != NULL); return Nu_RenameFile(pArchive->tmpPathnameUNI, pArchive->archivePathnameUNI); } nulib2-3.1.0/nufxlib/ArchiveIO.c000066400000000000000000000230731316100516500163350ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Functions for reading from and writing to the archive. These are * specialized functions that deal with byte ordering and CRC computation. * The functions associated with reading from an archive work equally well * with streaming archives. */ #include "NufxLibPriv.h" /* this makes valgrind and purify happy, at some tiny cost in speed */ #define CLEAN_INIT =0 /*#define CLEAN_INIT */ /* * =========================================================================== * Read and write * =========================================================================== */ /* * Read one byte, optionally computing a CRC. */ uint8_t Nu_ReadOneC(NuArchive* pArchive, FILE* fp, uint16_t* pCrc) { int ic; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); return (uint8_t) ic; } uint8_t Nu_ReadOne(NuArchive* pArchive, FILE* fp) { uint16_t dummyCrc CLEAN_INIT; return Nu_ReadOneC(pArchive, fp, &dummyCrc); } /* * Write one byte, optionally computing a CRC. */ void Nu_WriteOneC(NuArchive* pArchive, FILE* fp, uint8_t val, uint16_t* pCrc) { Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); putc(val, fp); } void Nu_WriteOne(NuArchive* pArchive, FILE* fp, uint8_t val) { uint16_t dummyCrc CLEAN_INIT; Nu_WriteOneC(pArchive, fp, val, &dummyCrc); } /* * Read two little-endian bytes, optionally computing a CRC. */ uint16_t Nu_ReadTwoC(NuArchive* pArchive, FILE* fp, uint16_t* pCrc) { int ic1, ic2; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); ic1 = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic1, *pCrc); ic2 = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic2, *pCrc); return ic1 | ic2 << 8; } uint16_t Nu_ReadTwo(NuArchive* pArchive, FILE* fp) { uint16_t dummyCrc CLEAN_INIT; return Nu_ReadTwoC(pArchive, fp, &dummyCrc); } /* * Write two little-endian bytes, optionally computing a CRC. */ void Nu_WriteTwoC(NuArchive* pArchive, FILE* fp, uint16_t val, uint16_t* pCrc) { int ic1, ic2; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); ic1 = val & 0xff; *pCrc = Nu_UpdateCRC16((uint8_t)ic1, *pCrc); ic2 = val >> 8; *pCrc = Nu_UpdateCRC16((uint8_t)ic2, *pCrc); putc(ic1, fp); putc(ic2, fp); } void Nu_WriteTwo(NuArchive* pArchive, FILE* fp, uint16_t val) { uint16_t dummyCrc CLEAN_INIT; Nu_WriteTwoC(pArchive, fp, val, &dummyCrc); } /* * Read four little-endian bytes, optionally computing a CRC. */ uint32_t Nu_ReadFourC(NuArchive* pArchive, FILE* fp, uint16_t* pCrc) { int ic1, ic2, ic3, ic4; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); ic1 = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic1, *pCrc); ic2 = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic2, *pCrc); ic3 = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic3, *pCrc); ic4 = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic4, *pCrc); return ic1 | ic2 << 8 | (uint32_t)ic3 << 16 | (uint32_t)ic4 << 24; } uint32_t Nu_ReadFour(NuArchive* pArchive, FILE* fp) { uint16_t dummyCrc CLEAN_INIT; return Nu_ReadFourC(pArchive, fp, &dummyCrc); } /* * Write four little-endian bytes, optionally computing a CRC. */ void Nu_WriteFourC(NuArchive* pArchive, FILE* fp, uint32_t val, uint16_t* pCrc) { int ic1, ic2, ic3, ic4; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); ic1 = val & 0xff; *pCrc = Nu_UpdateCRC16((uint8_t)ic1, *pCrc); ic2 = (val >> 8) & 0xff; *pCrc = Nu_UpdateCRC16((uint8_t)ic2, *pCrc); ic3 = (val >> 16) & 0xff; *pCrc = Nu_UpdateCRC16((uint8_t)ic3, *pCrc); ic4 = val >> 24; *pCrc = Nu_UpdateCRC16((uint8_t)ic4, *pCrc); putc(ic1, fp); putc(ic2, fp); putc(ic3, fp); putc(ic4, fp); } void Nu_WriteFour(NuArchive* pArchive, FILE* fp, uint32_t val) { uint16_t dummyCrc CLEAN_INIT; Nu_WriteFourC(pArchive, fp, val, &dummyCrc); } /* * Read an 8-byte NuFX Date/Time structure. * * I've chosen *not* to filter away the Y2K differences between P8 ShrinkIt * and GS/ShrinkIt. It's easy enough to deal with, and I figure the less * messing-with, the better. */ NuDateTime Nu_ReadDateTimeC(NuArchive* pArchive, FILE* fp, uint16_t* pCrc) { NuDateTime temp; int ic; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); temp.second = ic; ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); temp.minute = ic; ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); temp.hour = ic; ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); temp.year = ic; ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); temp.day = ic; ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); temp.month = ic; ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); temp.extra = ic; ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); temp.weekDay = ic; return temp; } NuDateTime Nu_ReadDateTime(NuArchive* pArchive, FILE* fp, uint16_t* pCrc) { uint16_t dummyCrc CLEAN_INIT; return Nu_ReadDateTimeC(pArchive, fp, &dummyCrc); } /* * Write an 8-byte NuFX Date/Time structure. */ void Nu_WriteDateTimeC(NuArchive* pArchive, FILE* fp, NuDateTime dateTime, uint16_t* pCrc) { int ic; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); ic = dateTime.second; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); ic = dateTime.minute; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); ic = dateTime.hour; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); ic = dateTime.year; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); ic = dateTime.day; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); ic = dateTime.month; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); ic = dateTime.extra; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); ic = dateTime.weekDay; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); } void Nu_WriteDateTime(NuArchive* pArchive, FILE* fp, NuDateTime dateTime) { uint16_t dummyCrc CLEAN_INIT; Nu_WriteDateTimeC(pArchive, fp, dateTime, &dummyCrc); } /* * Read N bytes from the stream, optionally computing a CRC. */ void Nu_ReadBytesC(NuArchive* pArchive, FILE* fp, void* vbuffer, long count, uint16_t* pCrc) { uint8_t* buffer = vbuffer; int ic; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); Assert(buffer != NULL); Assert(count > 0); while (count--) { ic = getc(fp); *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); *buffer++ = ic; } } void Nu_ReadBytes(NuArchive* pArchive, FILE* fp, void* vbuffer, long count) { uint16_t dummyCrc CLEAN_INIT; Nu_ReadBytesC(pArchive, fp, vbuffer, count, &dummyCrc); } /* * Write N bytes to the stream, optionally computing a CRC. */ void Nu_WriteBytesC(NuArchive* pArchive, FILE* fp, const void* vbuffer, long count, uint16_t* pCrc) { const uint8_t* buffer = vbuffer; int ic; Assert(pArchive != NULL); Assert(fp != NULL); Assert(pCrc != NULL); Assert(buffer != NULL); Assert(count > 0); while (count--) { ic = *buffer++; *pCrc = Nu_UpdateCRC16((uint8_t)ic, *pCrc); putc(ic, fp); } } void Nu_WriteBytes(NuArchive* pArchive, FILE* fp, const void* vbuffer, long count) { uint16_t dummyCrc CLEAN_INIT; Nu_WriteBytesC(pArchive, fp, vbuffer, count, &dummyCrc); } /* * =========================================================================== * General * =========================================================================== */ /* * Determine whether the stream completed the last set of operations * successfully. */ NuError Nu_HeaderIOFailed(NuArchive* pArchive, FILE* fp) { if (feof(fp) || ferror(fp)) return kNuErrFile; else return kNuErrNone; } /* * Seek around in an archive file. If this is a streaming-mode archive, * we only allow forward relative seeks, which are emulated with read calls. * * The values for "ptrname" are the same as for fseek(). */ NuError Nu_SeekArchive(NuArchive* pArchive, FILE* fp, long offset, int ptrname) { if (Nu_IsStreaming(pArchive)) { Assert(ptrname == SEEK_CUR); Assert(offset >= 0); /* OPT: might be faster to fread a chunk at a time */ while (offset--) (void) getc(fp); if (ferror(fp) || feof(fp)) return kNuErrFileSeek; } else { if (fseek(fp, offset, ptrname) < 0) return kNuErrFileSeek; } return kNuErrNone; } /* * Rewind an archive to the start of NuFX record data. * * Note that rewind(3S) resets the error indication, but this doesn't. */ NuError Nu_RewindArchive(NuArchive* pArchive) { Assert(pArchive != NULL); Assert(!Nu_IsStreaming(pArchive)); if (Nu_SeekArchive(pArchive, pArchive->archiveFp, pArchive->headerOffset + kNuMasterHeaderSize, SEEK_SET) != 0) return kNuErrFileSeek; pArchive->currentOffset = pArchive->headerOffset + kNuMasterHeaderSize; return kNuErrNone; } nulib2-3.1.0/nufxlib/Bzip2.c000066400000000000000000000215201316100516500155050ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Support for the "bzip2" (BTW+Huffman) algorithm, via "libbz2". * * This compression format is totally unsupported on the Apple II. This * is provided primarily for the benefit of Apple II emulators that want * a better storage format for disk images than SHK+LZW or a ZIP file. * * This code was developed and tested with libz2 version 1.0.2. Visit * http://sources.redhat.com/bzip2/ for more information. */ #include "NufxLibPriv.h" #ifdef ENABLE_BZIP2 #include "bzlib.h" #define kBZBlockSize 8 /* use 800K blocks */ #define kBZVerbosity 1 /* library verbosity level (0-4) */ /* * Alloc and free functions provided to libbz2. */ static void* Nu_bzalloc(void* opaque, int items, int size) { return Nu_Malloc(opaque, items * size); } static void Nu_bzfree(void* opaque, void* address) { Nu_Free(opaque, address); } /* * =========================================================================== * Compression * =========================================================================== */ /* * Compress "srcLen" bytes from "pStraw" to "fp". */ NuError Nu_CompressBzip2(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc) { NuError err = kNuErrNone; bz_stream bzstream; int bzerr; uint8_t* outbuf = NULL; Assert(pArchive != NULL); Assert(pStraw != NULL); Assert(fp != NULL); Assert(srcLen > 0); Assert(pDstLen != NULL); Assert(pCrc != NULL); err = Nu_AllocCompressionBufferIFN(pArchive); if (err != kNuErrNone) return err; /* allocate a similarly-sized buffer for the output */ outbuf = Nu_Malloc(pArchive, kNuGenCompBufSize); BailAlloc(outbuf); /* * Initialize the bz2lib stream. */ bzstream.bzalloc = Nu_bzalloc; bzstream.bzfree = Nu_bzfree; bzstream.opaque = pArchive; bzstream.next_in = NULL; bzstream.avail_in = 0; bzstream.next_out = outbuf; bzstream.avail_out = kNuGenCompBufSize; /* fourth arg is "workFactor"; set to zero for default (30) */ bzerr = BZ2_bzCompressInit(&bzstream, kBZBlockSize, kBZVerbosity, 0); if (bzerr != BZ_OK) { err = kNuErrInternal; if (bzerr == BZ_CONFIG_ERROR) { Nu_ReportError(NU_BLOB, err, "error configuring bz2lib"); } else { Nu_ReportError(NU_BLOB, err, "call to BZ2_bzCompressInit failed (bzerr=%d)", bzerr); } goto bail; } /* * Loop while we have data. */ do { uint32_t getSize; int action; /* should be able to read a full buffer every time */ if (bzstream.avail_in == 0 && srcLen) { getSize = (srcLen > kNuGenCompBufSize) ? kNuGenCompBufSize : srcLen; DBUG(("+++ reading %ld bytes\n", getSize)); err = Nu_StrawRead(pArchive, pStraw, pArchive->compBuf, getSize); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "bzip2 read failed"); goto bz_bail; } srcLen -= getSize; *pCrc = Nu_CalcCRC16(*pCrc, pArchive->compBuf, getSize); bzstream.next_in = pArchive->compBuf; bzstream.avail_in = getSize; } if (srcLen == 0) action = BZ_FINISH; /* tell libbz2 that we're done */ else action = BZ_RUN; /* more to come! */ bzerr = BZ2_bzCompress(&bzstream, action); if (bzerr != BZ_RUN_OK && bzerr != BZ_FINISH_OK && bzerr != BZ_STREAM_END) { err = kNuErrInternal; Nu_ReportError(NU_BLOB, err, "libbz2 compress call failed (bzerr=%d)", bzerr); goto bz_bail; } /* write when we're full or when we're done */ if (bzstream.avail_out == 0 || (bzerr == BZ_STREAM_END && bzstream.avail_out != kNuGenCompBufSize)) { DBUG(("+++ writing %d bytes\n", (uint8_t*)bzstream.next_out - outbuf)); err = Nu_FWrite(fp, outbuf, (uint8_t*)bzstream.next_out - outbuf); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "fwrite failed in bzip2"); goto bz_bail; } bzstream.next_out = outbuf; bzstream.avail_out = kNuGenCompBufSize; } } while (bzerr != BZ_STREAM_END); *pDstLen = bzstream.total_out_lo32; Assert(bzstream.total_out_hi32 == 0); /* no huge files for us */ bz_bail: BZ2_bzCompressEnd(&bzstream); /* free up any allocated structures */ bail: if (outbuf != NULL) Nu_Free(NULL, outbuf); return err; } /* * =========================================================================== * Expansion * =========================================================================== */ /* * Expand from "infp" to "pFunnel". */ NuError Nu_ExpandBzip2(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc) { NuError err = kNuErrNone; bz_stream bzstream; int bzerr; uint32_t compRemaining; uint8_t* outbuf; Assert(pArchive != NULL); Assert(pThread != NULL); Assert(infp != NULL); Assert(pFunnel != NULL); err = Nu_AllocCompressionBufferIFN(pArchive); if (err != kNuErrNone) return err; /* allocate a similarly-sized buffer for the output */ outbuf = Nu_Malloc(pArchive, kNuGenCompBufSize); BailAlloc(outbuf); compRemaining = pThread->thCompThreadEOF; /* * Initialize the libbz2 stream. */ bzstream.bzalloc = Nu_bzalloc; bzstream.bzfree = Nu_bzfree; bzstream.opaque = pArchive; bzstream.next_in = NULL; bzstream.avail_in = 0; bzstream.next_out = outbuf; bzstream.avail_out = kNuGenCompBufSize; /* third arg is "small" (set nonzero to reduce mem) */ bzerr = BZ2_bzDecompressInit(&bzstream, kBZVerbosity, 0); if (bzerr != BZ_OK) { err = kNuErrInternal; if (bzerr == BZ_CONFIG_ERROR) { Nu_ReportError(NU_BLOB, err, "error configuring libbz2"); } else { Nu_ReportError(NU_BLOB, err, "call to BZ2_bzDecompressInit failed (bzerr=%d)", bzerr); } goto bail; } /* * Loop while we have data. */ do { uint32_t getSize; /* read as much as we can */ if (bzstream.avail_in == 0) { getSize = (compRemaining > kNuGenCompBufSize) ? kNuGenCompBufSize : compRemaining; DBUG(("+++ reading %ld bytes (%ld left)\n", getSize, compRemaining)); err = Nu_FRead(infp, pArchive->compBuf, getSize); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "bzip2 read failed"); goto bz_bail; } compRemaining -= getSize; bzstream.next_in = pArchive->compBuf; bzstream.avail_in = getSize; } /* uncompress the data */ bzerr = BZ2_bzDecompress(&bzstream); if (bzerr != BZ_OK && bzerr != BZ_STREAM_END) { err = kNuErrInternal; Nu_ReportError(NU_BLOB, err, "libbz2 decompress call failed (bzerr=%d)", bzerr); goto bz_bail; } /* write every time there's anything (buffer will usually be full) */ if (bzstream.avail_out != kNuGenCompBufSize) { DBUG(("+++ writing %d bytes\n", (uint8_t*) bzstream.next_out - outbuf)); err = Nu_FunnelWrite(pArchive, pFunnel, outbuf, (uint8_t*)bzstream.next_out - outbuf); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "write failed in bzip2"); goto bz_bail; } if (pCrc != NULL) *pCrc = Nu_CalcCRC16(*pCrc, outbuf, (uint8_t*) bzstream.next_out - outbuf); bzstream.next_out = outbuf; bzstream.avail_out = kNuGenCompBufSize; } } while (bzerr == BZ_OK); Assert(bzerr == BZ_STREAM_END); /* other errors should've been caught */ Assert(bzstream.total_out_hi32 == 0); /* no huge files for us */ if (bzstream.total_out_lo32 != pThread->actualThreadEOF) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "size mismatch on expanded bzip2 file (%d vs %ld)", bzstream.total_out_lo32, pThread->actualThreadEOF); goto bz_bail; } bz_bail: BZ2_bzDecompressEnd(&bzstream); /* free up any allocated structures */ bail: if (outbuf != NULL) Nu_Free(NULL, outbuf); return err; } #endif /*ENABLE_BZIP2*/ nulib2-3.1.0/nufxlib/COPYING-LIB000066400000000000000000000027551316100516500160230ustar00rootroot00000000000000Copyright (C) 2007, Andy McFadden. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of project contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nulib2-3.1.0/nufxlib/ChangeLog.txt000066400000000000000000000242401316100516500167450ustar00rootroot000000000000002017/09/21 ***** v3.1.0 shipped ***** 2016/01/11 fadden - Fix handling of disk images (broken by previous change). 2015/12/26 fadden - Fix handling of entries with missing threads. - Improve handling of Mac OS X file type attributes. 2015/01/09 ***** v3.0.0 shipped ***** 2015/01/03 fadden - Mac OS X: replace Carbon FinderInfo calls with BSD xattr. - Mac OS X: fix resource fork naming. - Mac OS X: disable use of native resource forks. 2015/01/02 fadden - Distinguish Unicode and Mac OS Roman strings. 2014/12/22 fadden - Source code cleanup. 2014/10/30 ***** v2.2.2 shipped ***** 2014/10/28 fadden - Switched from CVS on sourceforge to github. - Updated configure scripts and makefiles. 2007/02/19 ***** v2.2.0 shipped ***** 2007/02/19 fadden - Auto-detect and handle "bad Mac" archives. - Switched from LGPL to BSD license. 2006/12/02 fadden - Check for overrun when unpacking RLE. 2006/02/18 ***** v2.1.1 shipped ***** 2006/02/18 fadden - Correct a wayward assert. (Changing the filetype of a file from an HFS disk, which has zero-length data fork, falsely triggered the assert.) 2005/09/17 ***** v2.1.0 shipped ***** 2005/09/17 fadden - Added "kNuValIgnoreLZW2Len" flag, which enables NuLib2 to handle archives created by an unknown but badly broken program. - Fixed build for gcc v4.0. 2004/10/11 ***** v2.0.3 shipped ***** 2004/09/25 fadden - Fixed: attempting to add files after deleting *all* entries in an archive would fail. - Removed use of a "ushort" from NufxLib.h. 2004/09/20 fadden - Corrected behavior after flush when original archive can't be deleted. 2004/09/09 fadden - Added header offset and junk offset to NuGetAttr. 2004/08/22 fadden - Fixed obscure bug when recompressing a GSHK-added zero-length file when "fake threads" is enabled. 2004/03/10 ***** v2.0.2 shipped ***** 2004/03/09 fadden - Set access permissions based on umask when extracting a "locked" file. My thanks to Matthew Fischer for sending a patch. - Reject archives with a MasterEOF == 48, not <= 48. There are some otherwise valid archives created by an old version of ShrinkIt that have MasterEOF==0. 2003/10/16 ***** v2.0.1 shipped ***** 2003/10/16 fadden - Added workaround for bad HFS option lists created by GSHK. - Added junk-skipping feature. Up to 1024 bytes of crud (e.g. MacBinary headers or HTTP remnants) will be searched for evidence of an archive. 2003/06/19 sheppy - Added support for resource forks and file and aux types when built for Mac OS X. 2003/03/18 ***** v2.0.0 shipped ***** 2003/03/10 fadden - Added support for automatic high-ASCII text stripping. 2003/02/23 fadden - Added test-twirl to samples. 2003/02/22 fadden - Turn off EOL conversion when extracting disk images. - Added NuTestRecord(). 2003/02/18 fadden - Added "original pathname" fields to NuFileDetails and NuErrorStatus. - Changed callback setters to return NuCallback instead of NuError. - Switched to case-sensitive filename comparisons. 2003/02/08 fadden - Upped version to v2.0.0. - Changed DataSource API. Removed "doClose" and added an optional callback function that handles releasing of resources. Necessary to make Win32 DLLs work right with unsuspecting apps. - Changed DataSource "copy" function to use refcounting. Still not quite right, but it'll do for now. Memory leaks in DataSource handling appear to be fixed. (I love valgrind.) 2003/01/10 fadden - Added version numbers to header. - Added kNuValueMaskThreadless to control handling of "threadless" records. Now records without threads can be silently "fixed" so the application does need to handle them specially. 2002/12/06 fadden - Made changes to allow NufxLib to be built as a Win32 DLL. 2002/10/20 ***** v1.1.0 shipped ***** 2002/10/10 fadden - changed behavior so that deleting all records is allowed 2002/10/09 fadden - added support for "bzip2" compression via libbz2 - added ability to selectively disable compression methods - added "-m" flag to samples/launder so you can specify compression 2002/09/30 fadden - added support for "deflate" compression via zlib 2002/09/27 fadden - added support for 12-bit and 16-bit LZC (UNIX compress) 2002/09/26 fadden - added support for SQueezed files (both compress and expand) 2002/09/23 fadden - ran the code through valgrind; found and fixed some minor bugs 2002/09/20 fadden - pulled the sources out and started fiddling with them again - changed hard tabs to spaces 2000/05/22 ***** v1.0.1 shipped ***** 2000/05/22 fadden - added workaround for buggy 140K DOS3.3 GSHK images 2000/05/18 ***** v1.0.0 shipped ***** 2000/05/18 fadden - updated version information to indicate final release 2000/03/25 ***** v0.6.1 shipped ***** 2000/03/25 fadden - Sheppy says Mac OS X PPC v1.02 and v1.2 work with minor SysDefs tweak 2000/03/05 ***** v0.6.0 (beta) shipped ***** 2000/03/05 fadden - modified NuOpenRW to call mktemp or mkstemp if tmpPath looks like a template - removed DEBUG_MSGS from default CFLAGS - updated version information to indicate beta release 2000/02/24 ***** v0.5.1 shipped ***** 2000/02/20 changes from Scott Blackman - portability fixes for DJGPP under Win95 2000/02/17 changes from Devin Reade - portability fixes for BSD, AIX, and others 2000/02/09 ***** v0.5.0 (alpha) shipped ***** 2000/02/08 fadden - tweaked the BeOS/PPC config around a little - deleted some commas to make "gcc -pendantic" happy 2000/02/06 fadden - include @CFLAGS@ in case somebody wants to override them 2000/02/06 ***** v0.4.0b shipped ***** 2000/02/06 fadden - added "install-shared" make target - portability fixes for HP/UX - configure.in test for presence of snprintf/vsnprintf declarations 2000/02/06 ***** v0.4.0a shipped ***** 2000/02/06 fadden - massaged configure.in for BeOS, and added some type casts for mwerks 2000/02/06 ***** v0.4.0 shipped ***** 2000/02/06 fadden - added value range checking to Nu_SetValue 2000/02/05 fadden - finished "test-basic" - added an "install" target to copy libnufx and NufxLib.h - added "mkinstalldirs" - fixed a memory leak in NuTest - made several implicit typecasts explicit for Visual C++'s benefit - renamed MiscStuff's replacement function to "Nu_function" - use "rb" or "wb" as fopen arg in sample code for Win32 2000/02/04 fadden - wrote a fair piece of "test-basic" - added "stickyErr" to "toBuffer" data sink so we can catch overruns 2000/02/02 fadden - minor changes to get it working under Win32 (Visual C++ 6.0) - added --enable-dmalloc to configuration - instead of constantly allocating 16K buffers, use pArchive->compBuf - ignore DataSink convertEOL value when doExpand is false 2000/02/01 fadden - added system-specific PATH_SEP define for samples (imgconv, exerciser) - set the pathname in ErrorStatus for CRC failures 2000/01/31 fadden - fixed a typo causing zero-byte GSHK-damaged files to report CRC errors - added support for DOS-ordered 2MG images to "imgconv" 2000/01/29 ***** v0.3.0 shipped ***** 2000/01/29 fadden - renamed "tests" to "samples" - changed library version to x.y.z format (major, minor, bug-fix) - added DEBUG_VERBOSE define, took some stuff out of DEBUG_MSGS 2000/01/28 fadden - make the Skip result work when an input file can't be opened - don't allow leading fssep chars in AddRecord - don't treat a multi-file BNY that happens to have a ShrinkIt archive in the first slot as a BXY - added "-t" flag (write to temp) to "launder" - in OpenReadWrite, treat zero-length archive files as newly-created - added workaround for GSHK's zero-byte data fork bug 2000/01/26 fadden - added status result flags to NuFlush - dropped kNuAbortAll and added kNuIgnore - implemented kNuValueIgnoreCRC - update the storageType whenever we change the record 2000/01/25 fadden - don't remove the temp file if the rename fails - Nu_ReportError now optionally uses a callback instead of stderr - pass NuArchive* and all the trimmings into Nu_ReportError so we can do the callback thing; required adding arguments to lots of places - clearly labeled BailError output as debug-only, then replaced most of the BailErrorQuiet calls with BailError - added global error message for when pArchive doesn't exist (e.g. Open) 2000/01/24 fadden - added args to "launder", and made it work right with 0-length threads - reject disk image threads that aren't a valid size - in NuFlush, recognize when a "copy" set hasn't had any changes made - AddThread no longer makes a copy of the DataSource 2000/01/24 ***** v0.2 shipped ***** 2000/01/23 fadden - added "sec" (Set ErrorHandler Callback) to exerciser - wrote "launder" test program - made "doExpand" option on data sinks work 2000/01/22 fadden - added OnlyUpdateOlder attribute and implemented for add and extract - made HandleExisting work for AddFile/AddRecord - AddThread's validation now blocks data and control threads in same record - AddFile and AddRecord now use same validation function as AddThread 2000/01/20 fadden - added Eric Shepherd's BeOS shared lib stuff to configure.in - restructed the progress updater, and made it work when adding files 2000/01/19 fadden - normalized SysDefs.h, changing UNIX to UNIX_LIKE and defining for BeOS - added "shared" target to makefile - added BeOS stuff to autoconf setup 2000/01/17 fadden - fixed Makefile issue preventing "tests" from working with old GNU make - fixed Lzw.c problem fouling up SunOS gcc v2.5.8 - discovered "<" vs "<=" flapping in GSHK, which I can't Mimic - fixed option list dump in debug print - properly return from all Malloc errors; abort is now debug-only again - lots of BeOS/Metrowerks "it's not gcc" changes from Eric Shepherd 2000/01/17 ***** v0.1 shipped ***** (much time passes) mid-1998 fadden - work begins nulib2-3.1.0/nufxlib/Charset.c000066400000000000000000000512651316100516500161210ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2014 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Miscellaneous NufxLib utility functions. */ #include "NufxLibPriv.h" /* * Convert Mac OS Roman to Unicode. Mapping comes from: * * http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT * * We use the "Control Pictures" block for the control characters * (0x00-0x1f, 0x7f --> 0x2400-0x241f, 0x2421). This is a bit nicer * than embedding control characters in filenames. */ static const uint16_t gMORToUnicode[256] = { /*0x00*/ 0x2400, // [control] NULL /*0x01*/ 0x2401, // [control] START OF HEADING /*0x02*/ 0x2402, // [control] START OF TEXT /*0x03*/ 0x2403, // [control] END OF TEXT /*0x04*/ 0x2404, // [control] END OF TRANSMISSION /*0x05*/ 0x2405, // [control] ENQUIRY /*0x06*/ 0x2406, // [control] ACKNOWLEDGE /*0x07*/ 0x2407, // [control] BELL /*0x08*/ 0x2408, // [control] BACKSPACE /*0x09*/ 0x2409, // [control] HORIZONTAL TABULATION /*0x0a*/ 0x240a, // [control] LINE FEED /*0x0b*/ 0x240b, // [control] VERTICAL TABULATION /*0x0c*/ 0x240c, // [control] FORM FEED /*0x0d*/ 0x240d, // [control] CARRIAGE RETURN /*0x0e*/ 0x240e, // [control] SHIFT OUT /*0x0f*/ 0x240f, // [control] SHIFT IN /*0x10*/ 0x2410, // [control] DATA LINK ESCAPE /*0x11*/ 0x2411, // [control] DEVICE CONTROL ONE /*0x12*/ 0x2412, // [control] DEVICE CONTROL TWO /*0x13*/ 0x2413, // [control] DEVICE CONTROL THREE /*0x14*/ 0x2414, // [control] DEVICE CONTROL FOUR /*0x15*/ 0x2415, // [control] NEGATIVE ACKNOWLEDGE /*0x16*/ 0x2416, // [control] SYNCHRONOUS IDLE /*0x17*/ 0x2417, // [control] END OF TRANSMISSION BLOCK /*0x18*/ 0x2418, // [control] CANCEL /*0x19*/ 0x2419, // [control] END OF MEDIUM /*0x1a*/ 0x241a, // [control] SUBSTITUTE /*0x1b*/ 0x241b, // [control] ESCAPE /*0x1c*/ 0x241c, // [control] FILE SEPARATOR /*0x1d*/ 0x241d, // [control] GROUP SEPARATOR /*0x1e*/ 0x241e, // [control] RECORD SEPARATOR /*0x1f*/ 0x241f, // [control] UNIT SEPARATOR /*0x20*/ 0x0020, // SPACE /*0x21*/ 0x0021, // EXCLAMATION MARK /*0x22*/ 0x0022, // QUOTATION MARK /*0x23*/ 0x0023, // NUMBER SIGN /*0x24*/ 0x0024, // DOLLAR SIGN /*0x25*/ 0x0025, // PERCENT SIGN /*0x26*/ 0x0026, // AMPERSAND /*0x27*/ 0x0027, // APOSTROPHE /*0x28*/ 0x0028, // LEFT PARENTHESIS /*0x29*/ 0x0029, // RIGHT PARENTHESIS /*0x2A*/ 0x002A, // ASTERISK /*0x2B*/ 0x002B, // PLUS SIGN /*0x2C*/ 0x002C, // COMMA /*0x2D*/ 0x002D, // HYPHEN-MINUS /*0x2E*/ 0x002E, // FULL STOP /*0x2F*/ 0x002F, // SOLIDUS /*0x30*/ 0x0030, // DIGIT ZERO /*0x31*/ 0x0031, // DIGIT ONE /*0x32*/ 0x0032, // DIGIT TWO /*0x33*/ 0x0033, // DIGIT THREE /*0x34*/ 0x0034, // DIGIT FOUR /*0x35*/ 0x0035, // DIGIT FIVE /*0x36*/ 0x0036, // DIGIT SIX /*0x37*/ 0x0037, // DIGIT SEVEN /*0x38*/ 0x0038, // DIGIT EIGHT /*0x39*/ 0x0039, // DIGIT NINE /*0x3A*/ 0x003A, // COLON /*0x3B*/ 0x003B, // SEMICOLON /*0x3C*/ 0x003C, // LESS-THAN SIGN /*0x3D*/ 0x003D, // EQUALS SIGN /*0x3E*/ 0x003E, // GREATER-THAN SIGN /*0x3F*/ 0x003F, // QUESTION MARK /*0x40*/ 0x0040, // COMMERCIAL AT /*0x41*/ 0x0041, // LATIN CAPITAL LETTER A /*0x42*/ 0x0042, // LATIN CAPITAL LETTER B /*0x43*/ 0x0043, // LATIN CAPITAL LETTER C /*0x44*/ 0x0044, // LATIN CAPITAL LETTER D /*0x45*/ 0x0045, // LATIN CAPITAL LETTER E /*0x46*/ 0x0046, // LATIN CAPITAL LETTER F /*0x47*/ 0x0047, // LATIN CAPITAL LETTER G /*0x48*/ 0x0048, // LATIN CAPITAL LETTER H /*0x49*/ 0x0049, // LATIN CAPITAL LETTER I /*0x4A*/ 0x004A, // LATIN CAPITAL LETTER J /*0x4B*/ 0x004B, // LATIN CAPITAL LETTER K /*0x4C*/ 0x004C, // LATIN CAPITAL LETTER L /*0x4D*/ 0x004D, // LATIN CAPITAL LETTER M /*0x4E*/ 0x004E, // LATIN CAPITAL LETTER N /*0x4F*/ 0x004F, // LATIN CAPITAL LETTER O /*0x50*/ 0x0050, // LATIN CAPITAL LETTER P /*0x51*/ 0x0051, // LATIN CAPITAL LETTER Q /*0x52*/ 0x0052, // LATIN CAPITAL LETTER R /*0x53*/ 0x0053, // LATIN CAPITAL LETTER S /*0x54*/ 0x0054, // LATIN CAPITAL LETTER T /*0x55*/ 0x0055, // LATIN CAPITAL LETTER U /*0x56*/ 0x0056, // LATIN CAPITAL LETTER V /*0x57*/ 0x0057, // LATIN CAPITAL LETTER W /*0x58*/ 0x0058, // LATIN CAPITAL LETTER X /*0x59*/ 0x0059, // LATIN CAPITAL LETTER Y /*0x5A*/ 0x005A, // LATIN CAPITAL LETTER Z /*0x5B*/ 0x005B, // LEFT SQUARE BRACKET /*0x5C*/ 0x005C, // REVERSE SOLIDUS /*0x5D*/ 0x005D, // RIGHT SQUARE BRACKET /*0x5E*/ 0x005E, // CIRCUMFLEX ACCENT /*0x5F*/ 0x005F, // LOW LINE /*0x60*/ 0x0060, // GRAVE ACCENT /*0x61*/ 0x0061, // LATIN SMALL LETTER A /*0x62*/ 0x0062, // LATIN SMALL LETTER B /*0x63*/ 0x0063, // LATIN SMALL LETTER C /*0x64*/ 0x0064, // LATIN SMALL LETTER D /*0x65*/ 0x0065, // LATIN SMALL LETTER E /*0x66*/ 0x0066, // LATIN SMALL LETTER F /*0x67*/ 0x0067, // LATIN SMALL LETTER G /*0x68*/ 0x0068, // LATIN SMALL LETTER H /*0x69*/ 0x0069, // LATIN SMALL LETTER I /*0x6A*/ 0x006A, // LATIN SMALL LETTER J /*0x6B*/ 0x006B, // LATIN SMALL LETTER K /*0x6C*/ 0x006C, // LATIN SMALL LETTER L /*0x6D*/ 0x006D, // LATIN SMALL LETTER M /*0x6E*/ 0x006E, // LATIN SMALL LETTER N /*0x6F*/ 0x006F, // LATIN SMALL LETTER O /*0x70*/ 0x0070, // LATIN SMALL LETTER P /*0x71*/ 0x0071, // LATIN SMALL LETTER Q /*0x72*/ 0x0072, // LATIN SMALL LETTER R /*0x73*/ 0x0073, // LATIN SMALL LETTER S /*0x74*/ 0x0074, // LATIN SMALL LETTER T /*0x75*/ 0x0075, // LATIN SMALL LETTER U /*0x76*/ 0x0076, // LATIN SMALL LETTER V /*0x77*/ 0x0077, // LATIN SMALL LETTER W /*0x78*/ 0x0078, // LATIN SMALL LETTER X /*0x79*/ 0x0079, // LATIN SMALL LETTER Y /*0x7A*/ 0x007A, // LATIN SMALL LETTER Z /*0x7B*/ 0x007B, // LEFT CURLY BRACKET /*0x7C*/ 0x007C, // VERTICAL LINE /*0x7D*/ 0x007D, // RIGHT CURLY BRACKET /*0x7E*/ 0x007E, // TILDE /*0x7f*/ 0x2421, // [control] DELETE /*0x80*/ 0x00C4, // LATIN CAPITAL LETTER A WITH DIAERESIS /*0x81*/ 0x00C5, // LATIN CAPITAL LETTER A WITH RING ABOVE /*0x82*/ 0x00C7, // LATIN CAPITAL LETTER C WITH CEDILLA /*0x83*/ 0x00C9, // LATIN CAPITAL LETTER E WITH ACUTE /*0x84*/ 0x00D1, // LATIN CAPITAL LETTER N WITH TILDE /*0x85*/ 0x00D6, // LATIN CAPITAL LETTER O WITH DIAERESIS /*0x86*/ 0x00DC, // LATIN CAPITAL LETTER U WITH DIAERESIS /*0x87*/ 0x00E1, // LATIN SMALL LETTER A WITH ACUTE /*0x88*/ 0x00E0, // LATIN SMALL LETTER A WITH GRAVE /*0x89*/ 0x00E2, // LATIN SMALL LETTER A WITH CIRCUMFLEX /*0x8A*/ 0x00E4, // LATIN SMALL LETTER A WITH DIAERESIS /*0x8B*/ 0x00E3, // LATIN SMALL LETTER A WITH TILDE /*0x8C*/ 0x00E5, // LATIN SMALL LETTER A WITH RING ABOVE /*0x8D*/ 0x00E7, // LATIN SMALL LETTER C WITH CEDILLA /*0x8E*/ 0x00E9, // LATIN SMALL LETTER E WITH ACUTE /*0x8F*/ 0x00E8, // LATIN SMALL LETTER E WITH GRAVE /*0x90*/ 0x00EA, // LATIN SMALL LETTER E WITH CIRCUMFLEX /*0x91*/ 0x00EB, // LATIN SMALL LETTER E WITH DIAERESIS /*0x92*/ 0x00ED, // LATIN SMALL LETTER I WITH ACUTE /*0x93*/ 0x00EC, // LATIN SMALL LETTER I WITH GRAVE /*0x94*/ 0x00EE, // LATIN SMALL LETTER I WITH CIRCUMFLEX /*0x95*/ 0x00EF, // LATIN SMALL LETTER I WITH DIAERESIS /*0x96*/ 0x00F1, // LATIN SMALL LETTER N WITH TILDE /*0x97*/ 0x00F3, // LATIN SMALL LETTER O WITH ACUTE /*0x98*/ 0x00F2, // LATIN SMALL LETTER O WITH GRAVE /*0x99*/ 0x00F4, // LATIN SMALL LETTER O WITH CIRCUMFLEX /*0x9A*/ 0x00F6, // LATIN SMALL LETTER O WITH DIAERESIS /*0x9B*/ 0x00F5, // LATIN SMALL LETTER O WITH TILDE /*0x9C*/ 0x00FA, // LATIN SMALL LETTER U WITH ACUTE /*0x9D*/ 0x00F9, // LATIN SMALL LETTER U WITH GRAVE /*0x9E*/ 0x00FB, // LATIN SMALL LETTER U WITH CIRCUMFLEX /*0x9F*/ 0x00FC, // LATIN SMALL LETTER U WITH DIAERESIS /*0xA0*/ 0x2020, // DAGGER /*0xA1*/ 0x00B0, // DEGREE SIGN /*0xA2*/ 0x00A2, // CENT SIGN /*0xA3*/ 0x00A3, // POUND SIGN /*0xA4*/ 0x00A7, // SECTION SIGN /*0xA5*/ 0x2022, // BULLET /*0xA6*/ 0x00B6, // PILCROW SIGN /*0xA7*/ 0x00DF, // LATIN SMALL LETTER SHARP S /*0xA8*/ 0x00AE, // REGISTERED SIGN /*0xA9*/ 0x00A9, // COPYRIGHT SIGN /*0xAA*/ 0x2122, // TRADE MARK SIGN /*0xAB*/ 0x00B4, // ACUTE ACCENT /*0xAC*/ 0x00A8, // DIAERESIS /*0xAD*/ 0x2260, // NOT EQUAL TO /*0xAE*/ 0x00C6, // LATIN CAPITAL LETTER AE /*0xAF*/ 0x00D8, // LATIN CAPITAL LETTER O WITH STROKE /*0xB0*/ 0x221E, // INFINITY /*0xB1*/ 0x00B1, // PLUS-MINUS SIGN /*0xB2*/ 0x2264, // LESS-THAN OR EQUAL TO /*0xB3*/ 0x2265, // GREATER-THAN OR EQUAL TO /*0xB4*/ 0x00A5, // YEN SIGN /*0xB5*/ 0x00B5, // MICRO SIGN /*0xB6*/ 0x2202, // PARTIAL DIFFERENTIAL /*0xB7*/ 0x2211, // N-ARY SUMMATION /*0xB8*/ 0x220F, // N-ARY PRODUCT /*0xB9*/ 0x03C0, // GREEK SMALL LETTER PI /*0xBA*/ 0x222B, // INTEGRAL /*0xBB*/ 0x00AA, // FEMININE ORDINAL INDICATOR /*0xBC*/ 0x00BA, // MASCULINE ORDINAL INDICATOR /*0xBD*/ 0x03A9, // GREEK CAPITAL LETTER OMEGA /*0xBE*/ 0x00E6, // LATIN SMALL LETTER AE /*0xBF*/ 0x00F8, // LATIN SMALL LETTER O WITH STROKE /*0xC0*/ 0x00BF, // INVERTED QUESTION MARK /*0xC1*/ 0x00A1, // INVERTED EXCLAMATION MARK /*0xC2*/ 0x00AC, // NOT SIGN /*0xC3*/ 0x221A, // SQUARE ROOT /*0xC4*/ 0x0192, // LATIN SMALL LETTER F WITH HOOK /*0xC5*/ 0x2248, // ALMOST EQUAL TO /*0xC6*/ 0x2206, // INCREMENT /*0xC7*/ 0x00AB, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK /*0xC8*/ 0x00BB, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK /*0xC9*/ 0x2026, // HORIZONTAL ELLIPSIS /*0xCA*/ 0x00A0, // NO-BREAK SPACE /*0xCB*/ 0x00C0, // LATIN CAPITAL LETTER A WITH GRAVE /*0xCC*/ 0x00C3, // LATIN CAPITAL LETTER A WITH TILDE /*0xCD*/ 0x00D5, // LATIN CAPITAL LETTER O WITH TILDE /*0xCE*/ 0x0152, // LATIN CAPITAL LIGATURE OE /*0xCF*/ 0x0153, // LATIN SMALL LIGATURE OE /*0xD0*/ 0x2013, // EN DASH /*0xD1*/ 0x2014, // EM DASH /*0xD2*/ 0x201C, // LEFT DOUBLE QUOTATION MARK /*0xD3*/ 0x201D, // RIGHT DOUBLE QUOTATION MARK /*0xD4*/ 0x2018, // LEFT SINGLE QUOTATION MARK /*0xD5*/ 0x2019, // RIGHT SINGLE QUOTATION MARK /*0xD6*/ 0x00F7, // DIVISION SIGN /*0xD7*/ 0x25CA, // LOZENGE /*0xD8*/ 0x00FF, // LATIN SMALL LETTER Y WITH DIAERESIS /*0xD9*/ 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS /*0xDA*/ 0x2044, // FRACTION SLASH /*0xDB*/ 0x00A4, // CURRENCY SIGN (was EURO SIGN) /*0xDC*/ 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK /*0xDD*/ 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK /*0xDE*/ 0xFB01, // LATIN SMALL LIGATURE FI /*0xDF*/ 0xFB02, // LATIN SMALL LIGATURE FL /*0xE0*/ 0x2021, // DOUBLE DAGGER /*0xE1*/ 0x00B7, // MIDDLE DOT /*0xE2*/ 0x201A, // SINGLE LOW-9 QUOTATION MARK /*0xE3*/ 0x201E, // DOUBLE LOW-9 QUOTATION MARK /*0xE4*/ 0x2030, // PER MILLE SIGN /*0xE5*/ 0x00C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX /*0xE6*/ 0x00CA, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX /*0xE7*/ 0x00C1, // LATIN CAPITAL LETTER A WITH ACUTE /*0xE8*/ 0x00CB, // LATIN CAPITAL LETTER E WITH DIAERESIS /*0xE9*/ 0x00C8, // LATIN CAPITAL LETTER E WITH GRAVE /*0xEA*/ 0x00CD, // LATIN CAPITAL LETTER I WITH ACUTE /*0xEB*/ 0x00CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX /*0xEC*/ 0x00CF, // LATIN CAPITAL LETTER I WITH DIAERESIS /*0xED*/ 0x00CC, // LATIN CAPITAL LETTER I WITH GRAVE /*0xEE*/ 0x00D3, // LATIN CAPITAL LETTER O WITH ACUTE /*0xEF*/ 0x00D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX /*0xF0*/ 0xF8FF, // Apple logo /*0xF1*/ 0x00D2, // LATIN CAPITAL LETTER O WITH GRAVE /*0xF2*/ 0x00DA, // LATIN CAPITAL LETTER U WITH ACUTE /*0xF3*/ 0x00DB, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX /*0xF4*/ 0x00D9, // LATIN CAPITAL LETTER U WITH GRAVE /*0xF5*/ 0x0131, // LATIN SMALL LETTER DOTLESS I /*0xF6*/ 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT /*0xF7*/ 0x02DC, // SMALL TILDE /*0xF8*/ 0x00AF, // MACRON /*0xF9*/ 0x02D8, // BREVE /*0xFA*/ 0x02D9, // DOT ABOVE /*0xFB*/ 0x02DA, // RING ABOVE /*0xFC*/ 0x00B8, // CEDILLA /*0xFD*/ 0x02DD, // DOUBLE ACUTE ACCENT /*0xFE*/ 0x02DB, // OGONEK /*0xFF*/ 0x02C7 // CARON }; /* * Static table, populated on first use. Provides the inverse map. * * An entry with 0x00 indicates no conversion. That's incorrect for * the entry for '\0', but since we're operating on null-terminated * strings that's never valid anyway. (It's possible for a filename * to contain 0x2400, but that would translate to 0x00, which we don't * allow; so it makes more sense to treat it as illegal.) */ static uint8_t gUnicodeToMOR[65536] = { 0xff /*indicates not initialized*/ }; static void Nu_GenerateUnicodeToMOR(void) { memset(gUnicodeToMOR, 0, sizeof(gUnicodeToMOR)); int i; for (i = 0; i < 256; i++) { int codePoint = gMORToUnicode[i]; Assert(codePoint >= 0 && codePoint < 65536); gUnicodeToMOR[codePoint] = i; } } /* * Converts stringMOR to Unicode, storing the output in bufUNI until it's * full. Null termination is guaranteed. If the buffer size is zero or * bufUNI is NULL, no string data is returned. * * Returns the number of bytes required to represent stringMOR in Unicode. */ size_t Nu_ConvertMORToUNI(const char* stringMOR, UNICHAR* bufUNI, size_t bufSize) { Assert(stringMOR != 0); #ifdef _WIN32 /* place-holder if we're not using UTF-16 yet */ Assert(sizeof(UNICHAR) == 1); size_t morLen = strlen(stringMOR) + 1; if (bufUNI != NULL && bufSize != 0) { size_t copyLen = morLen < bufSize ? morLen : bufSize; memcpy(bufUNI, stringMOR, copyLen); bufUNI[bufSize-1] = '\0'; } return morLen; #else /* * Convert Mac OS Roman to UTF-8. We only output full code points, * so if only the first byte of a UTF-8 sequence will fit we just * stop early. */ size_t uniLen = 0; Boolean doOutput = (bufUNI != NULL); while (*stringMOR != '\0') { // ASCII values just "convert" to themselves in this table uint16_t us = gMORToUnicode[(uint8_t)*stringMOR]; if (us < 0x80) { // single byte, no conversion if (uniLen+1 >= bufSize) { doOutput = false; } if (doOutput) { bufUNI[uniLen] = (char) us; } uniLen++; } else if (us < 0x7ff) { // two bytes if (uniLen+2 >= bufSize) { doOutput = false; } if (doOutput) { bufUNI[uniLen] = (us >> 6) | 0xc0; bufUNI[uniLen+1] = (us & 0x3f) | 0x80; } uniLen += 2; } else { // three bytes if (uniLen+3 >= bufSize) { doOutput = false; } if (doOutput) { bufUNI[uniLen] = (us >> 12) | 0xe0; bufUNI[uniLen+1] = ((us >> 6) & 0x3f) | 0x80; bufUNI[uniLen+2] = (us & 0x3f) | 0x80; } uniLen += 3; } stringMOR++; } // null-terminate if (doOutput && uniLen < bufSize) { bufUNI[uniLen] = '\0'; } uniLen++; return uniLen; #endif } /* * Decode a single Unicode code point from a UTF-8 string. This will * consume 1 to 4 bytes. If an error is detected, only one byte is * consumed, and the code point value will be 0xDCnn (invalid). * * cf. http://en.wikipedia.org/wiki/UTF-8#Sample_code */ static uint32_t Nu_DecodeUTF8(const char** pStr) { const uint8_t* str = (const uint8_t*) *pStr; uint32_t codePoint; uint32_t uc1, uc2, uc3, uc4; uc1 = *str++; if (uc1 < 0x80) { // single byte codePoint = uc1; } else if (uc1 < 0xc2) { // illegal: continuation or overlong 2-byte sequence goto fail; } else if (uc1 < 0xe0) { // 2-byte sequence uc2 = *str++; if ((uc2 & 0xc0) != 0x80) { goto fail; // not a continuation } codePoint = (uc1 << 6) + uc2 - 0x3080; } else if (uc1 < 0xf0) { // 3-byte sequence */ uc2 = *str++; if ((uc2 & 0xc0) != 0x80) { goto fail; // not a continuation } if (uc1 == 0xe0 && uc2 < 0xa0) { goto fail; // overlong } uc3 = *str++; if ((uc3 & 0xc0) != 0x80) { goto fail; // not a continuation } codePoint = (uc1 << 12) + (uc2 << 6) + uc3 - 0xE2080; } else if (uc1 < 0xf5) { uc2 = *str++; if ((uc2 & 0xc0) != 0x80) { goto fail; // not a continuation } if (uc1 == 0xf0 && uc2 < 0x90) { goto fail; // overlong } if (uc1 == 0xf4 && uc2 >= 0x90) { goto fail; // U+10FFFF } uc3 = *str++; if ((uc3 & 0xc0) != 0x80) { goto fail; // not a continuation } uc4 = *str++; if ((uc4 & 0xc0) != 0x80) { goto fail; // not a continuation } codePoint = (uc1 << 18) + (uc2 << 12) + (uc3 << 6) + uc4 - 0x3C82080; } else { // illegal: > U+10FFFF goto fail; } *pStr = (const UNICHAR*) str; return codePoint; fail: (*pStr)++; // advance one char only return 0xdc00 | uc1; } /* * Converts stringUNI to Mac OS Roman, storing the output in bufMOR * until it's full. Null termination is guaranteed. If the buffer * size is zero or bufMOR is NULL, no string data is returned. * * Returns the number of bytes required to represent stringUNI in MOR. */ size_t Nu_ConvertUNIToMOR(const UNICHAR* stringUNI, char* bufMOR, size_t bufSize) { Assert(stringUNI != 0); #ifdef _WIN32 /* * Place-holder if we're not using UTF-16 yet. This doesn't pass * tests that check for behavior with non-MOR Unicode values. */ Assert(sizeof(UNICHAR) == 1); size_t uniLen = strlen(stringUNI) + 1; if (bufMOR != NULL && bufSize != 0) { size_t copyLen = uniLen < bufSize ? uniLen : bufSize; memcpy(bufMOR, stringUNI, copyLen); bufMOR[bufSize-1] = '\0'; } return uniLen; #else /* * Convert UTF-8 to Mac OS Roman. If the code point doesn't have * a valid conversion (either because it's not in the table, or the * UTF-8 code is damaged) we just insert an ASCII '?'. */ if (gUnicodeToMOR[0] == 0xff) { Nu_GenerateUnicodeToMOR(); Assert(gUnicodeToMOR[0] != 0xff); } uint32_t codePoint; size_t morLen = 0; Boolean doOutput = (bufMOR != NULL); while (*stringUNI != '\0') { codePoint = Nu_DecodeUTF8(&stringUNI); char mc; if (codePoint < 0x80) { mc = (char) codePoint; } else if (codePoint < 0xffff) { // UTF-8 errors come back as 0xDCnn, which has no mapping in table mc = gUnicodeToMOR[codePoint]; if (mc == 0x00) { mc = '?'; } } else { // non-BMP code point mc = '?'; } if (morLen+1 >= bufSize) { doOutput = false; } if (doOutput) { bufMOR[morLen] = mc; } morLen++; } // null-terminate if (doOutput && morLen < bufSize) { bufMOR[morLen] = '\0'; } morLen++; return morLen; #endif } /* * Utility function that wraps NuConvertMORToUTF8, allocating a new * buffer to hold the converted string. The caller must free the result. * * Returns NULL if stringMOR is NULL or the conversion fails. */ UNICHAR* Nu_CopyMORToUNI(const char* stringMOR) { size_t uniLen; UNICHAR* uniBuf; if (stringMOR == NULL) { return NULL; } uniLen = Nu_ConvertMORToUNI(stringMOR, NULL, 0); if (uniLen == (size_t) -1) { return NULL; } uniBuf = (UNICHAR*) Nu_Malloc(NULL, uniLen); Nu_ConvertMORToUNI(stringMOR, uniBuf, uniLen); return uniBuf; } nulib2-3.1.0/nufxlib/Compress.c000066400000000000000000000340131316100516500163130ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Compress data into an archive. */ #include "NufxLibPriv.h" /* for ShrinkIt-mimic mode, don't compress files under 512 bytes */ #define kNuSHKLZWThreshold 512 /* * "Compress" an uncompressed thread. */ static NuError Nu_CompressUncompressed(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t *pCrc) { NuError err = kNuErrNone; /*uint8_t* buffer = NULL;*/ uint32_t count, getsize; Assert(pArchive != NULL); Assert(pStraw != NULL); Assert(fp != NULL); Assert(srcLen > 0); *pDstLen = srcLen; /* get this over with */ err = Nu_AllocCompressionBufferIFN(pArchive); BailError(err); if (pCrc != NULL) *pCrc = kNuInitialThreadCRC; count = srcLen; while (count) { getsize = (count > kNuGenCompBufSize) ? kNuGenCompBufSize : count; err = Nu_StrawRead(pArchive, pStraw, pArchive->compBuf, getsize); BailError(err); if (pCrc != NULL) *pCrc = Nu_CalcCRC16(*pCrc, pArchive->compBuf, getsize); err = Nu_FWrite(fp, pArchive->compBuf, getsize); BailError(err); count -= getsize; } bail: /*Nu_Free(pArchive, buffer);*/ return err; } /* * Compress from a data source to an archive. * * All archive-specified fields in "pThread" will be filled in, as will * "actualThreadEOF". The "nuThreadIdx" and "fileOffset" fields will * not be modified, and must be specified before calling here. * * If "sourceFormat" is uncompressed: * "targetFormat" will be used to compress the data * the data source length will be placed into pThread->thThreadEOF * the compressed size will be placed into pThread->thCompThreadEOF * the CRC is computed * * If "sourceFormat" is compressed: * the data will be copied without compression (targetFormat is ignored) * the data source "otherLen" value will be placed into pThread->thThreadEOF * the data source length will be placed into pThread->thCompThreadEOF * the CRC is retrieved from Nu_DataSourceGetRawCrc * * The actual format used will be placed in pThread->thThreadFormat, and * the CRC of the uncompressed data will be placed in pThread->thThreadCRC. * The remaining fields of "pThread", thThreadClass and thThreadKind, will * be set based on the fields in "pDataSource". * * Data will be written to "dstFp", which must be positioned at the * correct point in the output. The position is expected to match * pThread->fileOffset. * * On exit, the output file will be positioned after the last byte of the * output. (For a pre-sized buffer, this may not be the desired result.) */ NuError Nu_CompressToArchive(NuArchive* pArchive, NuDataSource* pDataSource, NuThreadID threadID, NuThreadFormat sourceFormat, NuThreadFormat targetFormat, NuProgressData* pProgressData, FILE* dstFp, NuThread* pThread) { NuError err; long origOffset; NuStraw* pStraw = NULL; NuDataSink* pDataSink = NULL; uint32_t srcLen = 0, dstLen = 0; uint16_t threadCrc; Assert(pArchive != NULL); Assert(pDataSource != NULL); /* okay if pProgressData is NULL */ Assert(dstFp != NULL); Assert(pThread != NULL); /* remember file offset, so we can back up if compression fails */ err = Nu_FTell(dstFp, &origOffset); BailError(err); Assert(origOffset == pThread->fileOffset); /* can get rid of ftell? */ /* fill in some thread fields */ threadCrc = kNuInitialThreadCRC; pThread->thThreadClass = NuThreadIDGetClass(threadID); pThread->thThreadKind = NuThreadIDGetKind(threadID); pThread->actualThreadEOF = (uint32_t)-1; /* nuThreadIdx and fileOffset should already be set */ /* * Get the input length. For "buffer" and "fp" sources, this is just * a value passed in. For "file" sources, this is the length of the * file on disk. The file should already have been opened successfully * by the caller. * * If the input file is zero bytes long, "store" it uncompressed and * bail immediately. * * (Our desire to store uncompressible data without compression clashes * with a passing interest in doing CRLF conversions on input data. We * want to know the length ahead of time, which potentially makes the * compression code simpler, but prevents us from doing the conversion * unless we pre-flight the conversion with a separate pass through the * input file. Of course, it's still possible for the application to * convert the file into a temp file and add from there, so all is * not lost.) */ srcLen = Nu_DataSourceGetDataLen(pDataSource); /*DBUG(("+++ input file length is %lu\n", srcLen));*/ /* * Create a "Straw" to slurp the input through and track progress. */ err = Nu_StrawNew(pArchive, pDataSource, pProgressData, &pStraw); BailError(err); if (!srcLen) { /* empty file! */ if (sourceFormat != kNuThreadFormatUncompressed) { DBUG(("ODD: empty source is compressed?\n")); } pThread->thThreadFormat = kNuThreadFormatUncompressed; pThread->thThreadCRC = threadCrc; pThread->thThreadEOF = 0; pThread->thCompThreadEOF = 0; pThread->actualThreadEOF = 0; goto done; /* send final progress message */ } if (sourceFormat == kNuThreadFormatUncompressed) { /* * Compress the input to the requested target format. */ /* for some reason, GSHK doesn't compress anything under 512 bytes */ if (pArchive->valMimicSHK && srcLen < kNuSHKLZWThreshold) targetFormat = kNuThreadFormatUncompressed; if (pProgressData != NULL) { if (targetFormat != kNuThreadFormatUncompressed) Nu_StrawSetProgressState(pStraw, kNuProgressCompressing); else Nu_StrawSetProgressState(pStraw, kNuProgressStoring); } err = Nu_ProgressDataCompressPrep(pArchive, pStraw, targetFormat, srcLen); BailError(err); switch (targetFormat) { case kNuThreadFormatUncompressed: err = Nu_CompressUncompressed(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); break; #ifdef ENABLE_SQ case kNuThreadFormatHuffmanSQ: err = Nu_CompressHuffmanSQ(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); break; #endif #ifdef ENABLE_LZW case kNuThreadFormatLZW1: err = Nu_CompressLZW1(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); break; case kNuThreadFormatLZW2: err = Nu_CompressLZW2(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); break; #endif #ifdef ENABLE_LZC case kNuThreadFormatLZC12: err = Nu_CompressLZC12(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); break; case kNuThreadFormatLZC16: err = Nu_CompressLZC16(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); break; #endif #ifdef ENABLE_DEFLATE case kNuThreadFormatDeflate: err = Nu_CompressDeflate(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); break; #endif #ifdef ENABLE_BZIP2 case kNuThreadFormatBzip2: err = Nu_CompressBzip2(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); break; #endif default: /* should've been blocked in Value.c */ Assert(0); err = kNuErrInternal; goto bail; } BailError(err); pThread->thThreadCRC = threadCrc; /* CRC of uncompressed data */ if (dstLen < srcLen || (dstLen == srcLen && targetFormat == kNuThreadFormatUncompressed)) { /* got smaller, or we didn't try to compress it; keep it */ pThread->thThreadEOF = srcLen; pThread->thCompThreadEOF = dstLen; pThread->thThreadFormat = targetFormat; } else { /* got bigger, store it uncompressed */ err = Nu_FSeek(dstFp, origOffset, SEEK_SET); BailError(err); err = Nu_StrawRewind(pArchive, pStraw); BailError(err); if (pProgressData != NULL) Nu_StrawSetProgressState(pStraw, kNuProgressStoring); err = Nu_ProgressDataCompressPrep(pArchive, pStraw, kNuThreadFormatUncompressed, srcLen); BailError(err); DBUG(("--- compression (%d) failed (%ld vs %ld), storing\n", targetFormat, dstLen, srcLen)); err = Nu_CompressUncompressed(pArchive, pStraw, dstFp, srcLen, &dstLen, &threadCrc); BailError(err); /* * This holds so long as the previous attempt at compressing * computed a CRC on the entire file (i.e. didn't stop early * when it noticed the output was larger than the input). If * this is always the case, then we can change "&threadCrc" * a few lines back to "NULL" and avoid re-computing the CRC. * If this is not always the case, remove this assert. */ Assert(threadCrc == pThread->thThreadCRC); pThread->thThreadEOF = srcLen; pThread->thCompThreadEOF = dstLen; pThread->thThreadFormat = kNuThreadFormatUncompressed; } } else { /* * Copy the already-compressed input. */ if (pProgressData != NULL) Nu_StrawSetProgressState(pStraw, kNuProgressCopying); err = Nu_ProgressDataCompressPrep(pArchive, pStraw, kNuThreadFormatUncompressed, srcLen); BailError(err); err = Nu_CompressUncompressed(pArchive, pStraw, dstFp, srcLen, &dstLen, NULL); BailError(err); pThread->thThreadEOF = Nu_DataSourceGetOtherLen(pDataSource); pThread->thCompThreadEOF = srcLen; pThread->thThreadFormat = sourceFormat; pThread->thThreadCRC = Nu_DataSourceGetRawCrc(pDataSource); } pThread->actualThreadEOF = pThread->thThreadEOF; done: DBUG(("+++ srcLen=%ld, dstLen=%ld, actual=%ld\n", srcLen, dstLen, pThread->actualThreadEOF)); /* make sure we send a final "success" progress message at 100% */ if (pProgressData != NULL) { (void) Nu_StrawSetProgressState(pStraw, kNuProgressDone); err = Nu_StrawSendProgressUpdate(pArchive, pStraw); BailError(err); } bail: (void) Nu_StrawFree(pArchive, pStraw); (void) Nu_DataSinkFree(pDataSink); return err; } /* * Copy pre-sized data into the archive at the current offset. * * All archive-specified fields in "pThread" will be filled in, as will * "actualThreadEOF". The "nuThreadIdx" and "fileOffset" fields will * not be modified. * * Pre-sized data is always uncompressed, and doesn't have a CRC. This * will copy the data, and then continue writing zeros to fill out the rest * of the pre-sized buffer. */ NuError Nu_CopyPresizedToArchive(NuArchive* pArchive, NuDataSource* pDataSource, NuThreadID threadID, FILE* dstFp, NuThread* pThread, char** ppSavedCopy) { NuError err = kNuErrNone; NuStraw* pStraw = NULL; uint32_t srcLen, bufferLen; uint32_t count, getsize; srcLen = Nu_DataSourceGetDataLen(pDataSource); bufferLen = Nu_DataSourceGetOtherLen(pDataSource); if (bufferLen < srcLen) { /* hey, this won't fit! */ DBUG(("--- can't fit %lu into buffer of %lu!\n", srcLen, bufferLen)); err = kNuErrPreSizeOverflow; goto bail; } DBUG(("+++ copying %lu into buffer of %lu\n", srcLen, bufferLen)); pThread->thThreadClass = NuThreadIDGetClass(threadID); pThread->thThreadFormat = kNuThreadFormatUncompressed; pThread->thThreadKind = NuThreadIDGetKind(threadID); pThread->thThreadCRC = 0; /* no CRC on pre-sized stuff */ pThread->thThreadEOF = srcLen; pThread->thCompThreadEOF = bufferLen; pThread->actualThreadEOF = srcLen; /* nuThreadIdx and fileOffset should already be set */ /* * Prepare to copy the data through a buffer. The "straw" thing * is a convenient way to deal with the dataSource, even though we * don't have a progress updater. */ err = Nu_StrawNew(pArchive, pDataSource, NULL, &pStraw); BailError(err); count = srcLen; err = Nu_AllocCompressionBufferIFN(pArchive); BailError(err); while (count) { getsize = (count > kNuGenCompBufSize) ? kNuGenCompBufSize : count; err = Nu_StrawRead(pArchive, pStraw, pArchive->compBuf, getsize); BailError(err); err = Nu_FWrite(dstFp, pArchive->compBuf, getsize); BailError(err); if (ppSavedCopy != NULL && *ppSavedCopy == NULL) { /* * Grab a copy of the filename for our own use. This assumes * that the filename fits in kNuGenCompBufSize, which is a * pretty safe thing to assume. */ Assert(threadID == kNuThreadIDFilename); Assert(count == getsize); *ppSavedCopy = Nu_Malloc(pArchive, getsize+1); BailAlloc(*ppSavedCopy); memcpy(*ppSavedCopy, pArchive->compBuf, getsize); (*ppSavedCopy)[getsize] = '\0'; /* make sure it's terminated */ } count -= getsize; } /* * Pad out the rest of the buffer. Could probably do this more * efficiently through the buffer we've allocated, but these regions * tend to be either 32 or 200 bytes. */ count = bufferLen - srcLen; while (count--) Nu_WriteOne(pArchive, dstFp, 0); bail: (void) Nu_StrawFree(pArchive, pStraw); /*Nu_Free(pArchive, buffer);*/ return err; } nulib2-3.1.0/nufxlib/Crc16.c000066400000000000000000000114111316100516500153730ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Compute 16-bit CRCs. Depending on the hardware, the table version * might be slower than the loop computation. */ #include "NufxLibPriv.h" #define CRC_TAB #ifdef CRC_TAB /* * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. * NOTE: First srgument must be in range 0 to 255. * Second argument is referenced twice. * * Programmers may incorporate any or all code into their programs, * giving proper credit within the source. Publication of the * source routines is permitted so long as proper credit is given * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, * Omen Technology. */ /*#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)*/ #define updcrc(cp, crc) ( (crctab[((crc >> 8) & 0xFF) ^ cp] ^ (crc << 8)) & 0xFFFF) /* crctab calculated by Mark G. Mendel, Network Systems Corporation */ const uint16_t gNuCrc16Table[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; #endif /* * Calculate CRC on a region * * A CRC is the result of a mathematical operation based on the * coefficients of a polynomial when multiplied by X^16 then divided by * the generator polynomial (X^16 + X^12 + X^5 + 1) using modulo two * arithmetic. * * This routine is a slightly modified verison of one found in: * _Advanced Programming Techniques for the Apple //gs Toolbox_ * By Morgan Davis and Dan Gookin (Compute! Publications, Inc.) * It can either calculate the CRC bit-by-bit or use a table. * * Depending on CPU architecture, one may be dramatically faster than * the other. */ uint16_t Nu_CalcCRC16(uint16_t seed, const uint8_t* ptr, int count) { uint16_t CRC = seed; #ifndef CRC_TAB int x; #endif do { #ifndef CRC_TAB CRC ^= *ptr++ << 8; /* XOR hi-byte of CRC w/dat */ for (x = 8; x; --x) /* Then, for 8 bit shifts... */ if (CRC & 0x8000) /* Test hi order bit of CRC */ CRC = CRC << 1 ^ 0x1021; /* if set, shift & XOR w/$1021 */ else CRC <<= 1; /* Else, just shift left once. */ #else CRC = Nu_UpdateCRC16(*ptr++, CRC); /* look up new value in table */ #endif } while (--count); return (CRC); } nulib2-3.1.0/nufxlib/Debug.c000066400000000000000000000316031316100516500155500ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Debugging functions. These are omitted from the non-debug build. */ #include "NufxLibPriv.h" #if defined(DEBUG_MSGS) /* pull a string out of one of the static arrays */ #define GetStaticString(index, staticArray) ( \ (index) >= NELEM(staticArray) ? "" : staticArray[index] \ ) /* thread's thread_class */ static const char* gThreadClassNames[] = { "message_thread", "control_thread", "data_thread", "filename_thread", }; /* thread's thread_format */ static const char* gThreadFormatNames[] = { "uncompressed", "Huffman Squeeze", "dynamic LZW/1", "dynamic LZW/2", "12-bit LZC", "16-bit LZC", "deflate", "bzip2" }; /* days of the week */ static const char* gDayNames[] = { "[ null ]", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; /* months of the year */ static const char* gMonths[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; #define kNuDateOutputLen 64 /* file_sys_id values */ static const char* gFileSysIDs[] = { "Reserved/unknown ($00)", "ProDOS/SOS", "DOS 3.3", "DOS 3.2", "Apple II Pascal", "Macintosh (HFS)", "Macintosh (MFS)", "LISA file system", "Apple CP/M", "Reserved 0x09", "MS-DOS", "High-Sierra", "ISO 9660", "AppleShare" }; /* * Convert a DateTime structure into something printable. * * The buffer passed in must hold at least kNuDateOutputLen bytes. * * Returns "buffer" for the benefit of printf() calls. */ static char* Nu_DebugDumpDate(const NuDateTime* pDateTime, char* buffer) { char* cp; /* is it valid? */ if (pDateTime->day > 30 || pDateTime->month > 11 || pDateTime->hour > 24 || pDateTime->minute > 59) { strcpy(buffer, " "); goto bail; } /* is it empty? */ if ((pDateTime->second | pDateTime->minute | pDateTime->hour | pDateTime->year | pDateTime->day | pDateTime->month | pDateTime->extra | pDateTime->weekDay) == 0) { strcpy(buffer, " [No Date] "); goto bail; } cp = buffer; /* only print weekDay if one was stored */ if (pDateTime->weekDay) { if (pDateTime->weekDay < NELEM(gDayNames)) sprintf(cp, "%s, ", gDayNames[pDateTime->weekDay]); else sprintf(cp, "??%d, ", pDateTime->weekDay); cp += strlen(cp); } sprintf(cp, "%02d-%s-%04d %02d:%02d:%02d", pDateTime->day+1, gMonths[pDateTime->month], pDateTime->year < 40 ? pDateTime->year + 2000 : pDateTime->year + 1900, pDateTime->hour, pDateTime->minute, pDateTime->second); bail: sprintf(buffer + strlen(buffer), " [s%d m%d h%d Y%d D%d M%d x%d w%d]", pDateTime->second, pDateTime->minute, pDateTime->hour, pDateTime->year, pDateTime->day, pDateTime->month, pDateTime->extra, pDateTime->weekDay); return buffer; } /* * Convert a buffer into a hexadecimal character string. * * The result will be 2x the size of the original, +1 for a null byte. */ static void ConvertToHexStr(const uint8_t* inBuf, int inLen, char* outBuf) { while (inLen--) { *outBuf++ = HexConv((*inBuf >> 4) & 0x0f); *outBuf++ = HexConv(*inBuf & 0x0f); inBuf++; } *outBuf = '\0'; } /* * Dump everything we know about pThread. */ void Nu_DebugDumpThread(const NuThread* pThread) { static const char* kInd = " "; NuThreadID threadID; const char* descr; Assert(pThread != NULL); printf("%sThreadClass: 0x%04x (%s)\n", kInd, pThread->thThreadClass, GetStaticString(pThread->thThreadClass, gThreadClassNames)); printf("%sThreadFormat: 0x%04x (%s)\n", kInd, pThread->thThreadFormat, GetStaticString(pThread->thThreadFormat, gThreadFormatNames)); threadID = NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind); switch (threadID) { case kNuThreadIDOldComment: descr = "old comment"; break; case kNuThreadIDComment: descr = "comment"; break; case kNuThreadIDIcon: descr = "icon"; break; case kNuThreadIDMkdir: descr = "mkdir"; break; case kNuThreadIDDataFork: descr = "data fork"; break; case kNuThreadIDDiskImage: descr = "disk image"; break; case kNuThreadIDRsrcFork: descr = "rsrc fork"; break; case kNuThreadIDFilename: descr = "filename"; break; default: descr = ""; break; } printf("%sThreadKind: 0x%04x (%s)\n", kInd, pThread->thThreadKind, descr); printf("%sThreadCRC: 0x%04x ThreadEOF: %u CompThreadEOF: %u\n", kInd, pThread->thThreadCRC, pThread->thThreadEOF, pThread->thCompThreadEOF); printf("%s*File data offset: %ld actualThreadEOF: %d\n", kInd, pThread->fileOffset, pThread->actualThreadEOF); } /* * Dump everything we know about pRecord, including its threads and ThreadMods. * * Changes to existing records are made to the "copy" set, not the "orig" * set. Pass in the "orig" copy in "pRecord", and optionally pass in the * "copy" set in "pXrefRecord" to glean data from both. */ static void Nu_DebugDumpRecord(NuArchive* pArchive, const NuRecord* pRecord, const NuRecord* pXrefRecord, Boolean isDeleted) { NuError err; /* dummy */ static const char* kInd = " "; char dateBuf[kNuDateOutputLen]; const NuThreadMod* pThreadMod; const NuThread* pThread; uint32_t idx; Assert(pRecord != NULL); /*printf("PTR: pRecord=0x%08lx pXrefRecord=0x%08lx\n", (long) pRecord, (long) pXrefRecord);*/ UNICHAR* filenameUNI = Nu_CopyMORToUNI(pRecord->filenameMOR); printf("%s%s%sFilename: '%s' (idx=%u)\n", kInd, isDeleted ? "[DEL] " : "", pXrefRecord != NULL && pXrefRecord->pThreadMods != NULL ? "[MOD] " : "", filenameUNI == NULL ? "" : filenameUNI, pRecord->recordIdx); free(filenameUNI); printf("%sHeaderID: '%.4s' VersionNumber: 0x%04x HeaderCRC: 0x%04x\n", kInd, pRecord->recNufxID, pRecord->recVersionNumber, pRecord->recHeaderCRC); printf("%sAttribCount: %u TotalThreads: %u\n", kInd, pRecord->recAttribCount, pRecord->recTotalThreads); printf("%sFileSysID: %u (%s) FileSysInfo: 0x%04x ('%c')\n", kInd, pRecord->recFileSysID, GetStaticString(pRecord->recFileSysID, gFileSysIDs), pRecord->recFileSysInfo, NuGetSepFromSysInfo(pRecord->recFileSysInfo)); /* do something fancy for ProDOS? */ printf("%sFileType: 0x%08x ExtraType: 0x%08x Access: 0x%08x\n", kInd, pRecord->recFileType, pRecord->recExtraType, pRecord->recAccess); printf("%sCreateWhen: %s\n", kInd, Nu_DebugDumpDate(&pRecord->recCreateWhen, dateBuf)); printf("%sModWhen: %s\n", kInd, Nu_DebugDumpDate(&pRecord->recModWhen, dateBuf)); printf("%sArchiveWhen: %s\n", kInd, Nu_DebugDumpDate(&pRecord->recArchiveWhen, dateBuf)); printf("%sStorageType: %u OptionSize: %u FilenameLength: %u\n", kInd, pRecord->recStorageType, pRecord->recOptionSize, pRecord->recFilenameLength); if (pRecord->recOptionSize) { char* outBuf = Nu_Malloc(pArchive, pRecord->recOptionSize * 2 +1); BailAlloc(outBuf); Assert(pRecord->recOptionList != NULL); ConvertToHexStr(pRecord->recOptionList, pRecord->recOptionSize, outBuf); printf("%sOptionList: [%s]\n", kInd, outBuf); Nu_Free(pArchive, outBuf); } printf("%s*ExtraCount: %d RecFileOffset: %ld RecHeaderLength: %d\n", kInd, pRecord->extraCount, pRecord->fileOffset, pRecord->recHeaderLength); for (idx = 0; idx < pRecord->recTotalThreads; idx++) { Boolean isFake; isFake = (idx >= pRecord->recTotalThreads - pRecord->fakeThreads); pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); printf("%s--Thread #%u (idx=%u)%s\n", kInd, idx, pThread->threadIdx, isFake ? " [FAKE]" : ""); Nu_DebugDumpThread(pThread); } if (pXrefRecord != NULL) pThreadMod = pXrefRecord->pThreadMods; else pThreadMod = pRecord->pThreadMods; /* probably empty */ if (pThreadMod != NULL) printf("%s*ThreadMods -----\n", kInd); while (pThreadMod != NULL) { switch (pThreadMod->entry.kind) { case kNuThreadModAdd: printf("%s *-ThreadMod ADD 0x%08x 0x%04x (sourceType=%d)\n", kInd, pThreadMod->entry.add.threadID, pThreadMod->entry.add.threadFormat, Nu_DataSourceGetType(pThreadMod->entry.add.pDataSource)); break; case kNuThreadModUpdate: printf("%s *-ThreadMod UPDATE %6d\n", kInd, pThreadMod->entry.update.threadIdx); break; case kNuThreadModDelete: printf("%s *-ThreadMod DELETE %6d\n", kInd, pThreadMod->entry.delete.threadIdx); break; case kNuThreadModUnknown: default: Assert(0); printf("%s++ThreadMod UNKNOWN\n", kInd); break; } pThreadMod = pThreadMod->pNext; } /*printf("%s*TotalLength: %ld TotalCompLength: %ld\n", kInd, pRecord->totalLength, pRecord->totalCompLength);*/ printf("%s*TotalCompLength: %u\n", kInd, pRecord->totalCompLength); printf("\n"); bail: return; } /* * Dump the records in a RecordSet. */ static void Nu_DebugDumpRecordSet(NuArchive* pArchive, const NuRecordSet* pRecordSet, const NuRecordSet* pXrefSet) { const NuRecord* pRecord; const NuRecord* pXrefRecord; Boolean doXref; long count; doXref = false; pXrefRecord = NULL; if (pXrefSet != NULL && Nu_RecordSet_GetLoaded(pXrefSet)) { pXrefRecord = Nu_RecordSet_GetListHead(pXrefSet); doXref = true; } /* dump every record, if we've loaded them */ count = Nu_RecordSet_GetNumRecords(pRecordSet); pRecord = Nu_RecordSet_GetListHead(pRecordSet); if (pRecord != NULL) { Assert(count != 0); while (count--) { Assert(pRecord != NULL); if (pXrefRecord != NULL && pRecord->recordIdx == pXrefRecord->recordIdx) { Nu_DebugDumpRecord(pArchive, pRecord, pXrefRecord, false); pXrefRecord = pXrefRecord->pNext; } else { Nu_DebugDumpRecord(pArchive, pRecord, NULL, doXref); } pRecord = pRecord->pNext; } } else { Assert(count == 0); } } /* * Dump the master header block. */ static void Nu_DebugDumpMH(const NuMasterHeader* pMasterHeader) { static const char* kInd = " "; char dateBuf1[kNuDateOutputLen]; Assert(pMasterHeader != NULL); printf("%sNufileID: '%.6s' MasterCRC: 0x%04x TotalRecords: %u\n", kInd, pMasterHeader->mhNufileID, pMasterHeader->mhMasterCRC, pMasterHeader->mhTotalRecords); printf("%sArchiveCreateWhen: %s\n", kInd, Nu_DebugDumpDate(&pMasterHeader->mhArchiveCreateWhen, dateBuf1)); printf("%sArchiveModWhen: %s\n", kInd, Nu_DebugDumpDate(&pMasterHeader->mhArchiveModWhen, dateBuf1)); printf("%sMasterVersion: %u MasterEOF: %u\n", kInd, pMasterHeader->mhMasterVersion, pMasterHeader->mhMasterEOF); } /* * Dump everything we know about pArchive. * * This will only print the records that we have seen so far. If the * application hasn't caused us to scan through all of the records in * the archive, then this won't be very interesting. This will never * show any records for streaming-mode archives. */ void Nu_DebugDumpAll(NuArchive* pArchive) { Assert(pArchive != NULL); printf("*Archive pathname: '%s'\n", pArchive->archivePathnameUNI); printf("*Archive type: %d\n", pArchive->archiveType); printf("*Header offset: %ld (junk offset=%ld)\n", pArchive->headerOffset, pArchive->junkOffset); printf("*Num records: %u orig, %u copy, %u new\n", Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet), Nu_RecordSet_GetNumRecords(&pArchive->copyRecordSet), Nu_RecordSet_GetNumRecords(&pArchive->newRecordSet)); printf("*NuRecordIdx seed: %u NuRecordIdx next: %u\n", pArchive->recordIdxSeed, pArchive->nextRecordIdx); /* master header */ Nu_DebugDumpMH(&pArchive->masterHeader); printf(" *ORIG record set (x-ref with COPY):\n"); Nu_DebugDumpRecordSet(pArchive, &pArchive->origRecordSet, &pArchive->copyRecordSet); printf(" *NEW record set:\n"); Nu_DebugDumpRecordSet(pArchive, &pArchive->newRecordSet, NULL); if (!Nu_RecordSet_GetLoaded(&pArchive->origRecordSet) && !Nu_RecordSet_GetLoaded(&pArchive->newRecordSet)) { printf("*** DEBUG: original records not loaded yet? ***\n"); } } #endif /*DEBUG_MSGS*/ nulib2-3.1.0/nufxlib/Deferred.c000066400000000000000000002532111316100516500162430ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Deferred write handling. */ #include "NufxLibPriv.h" /* * =========================================================================== * NuThreadMod functions * =========================================================================== */ /* * Alloc and initialize a new "add" ThreadMod. * * Caller is allowed to dispose of the data source, as this makes a copy. * * NOTE: threadFormat is how you want the data to be compressed. The * threadFormat passed to DataSource describes the source data. */ NuError Nu_ThreadModAdd_New(NuArchive* pArchive, NuThreadID threadID, NuThreadFormat threadFormat, NuDataSource* pDataSource, NuThreadMod** ppThreadMod) { Assert(ppThreadMod != NULL); Assert(pDataSource != NULL); *ppThreadMod = Nu_Calloc(pArchive, sizeof(**ppThreadMod)); if (*ppThreadMod == NULL) return kNuErrMalloc; (*ppThreadMod)->entry.kind = kNuThreadModAdd; (*ppThreadMod)->entry.add.used = false; (*ppThreadMod)->entry.add.threadIdx = Nu_GetNextThreadIdx(pArchive); (*ppThreadMod)->entry.add.threadID = threadID; (*ppThreadMod)->entry.add.threadFormat = threadFormat; (*ppThreadMod)->entry.add.pDataSource = Nu_DataSourceCopy(pDataSource); /* decide if this is a pre-sized thread [do we want to do this here??] */ (*ppThreadMod)->entry.add.isPresized = Nu_IsPresizedThreadID(threadID); return kNuErrNone; } /* * Alloc and initialize a new "update" ThreadMod. * * Caller is allowed to dispose of the data source. */ NuError Nu_ThreadModUpdate_New(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSource* pDataSource, NuThreadMod** ppThreadMod) { Assert(ppThreadMod != NULL); Assert(pDataSource != NULL); *ppThreadMod = Nu_Calloc(pArchive, sizeof(**ppThreadMod)); if (*ppThreadMod == NULL) return kNuErrMalloc; (*ppThreadMod)->entry.kind = kNuThreadModUpdate; (*ppThreadMod)->entry.update.used = false; (*ppThreadMod)->entry.update.threadIdx = threadIdx; (*ppThreadMod)->entry.update.pDataSource = Nu_DataSourceCopy(pDataSource); return kNuErrNone; } /* * Alloc and initialize a new "delete" ThreadMod. * * The "threadID" argument is really only needed for filename threads. We * use it when trying to track how many filename threads we really have. */ NuError Nu_ThreadModDelete_New(NuArchive* pArchive, NuThreadIdx threadIdx, NuThreadID threadID, NuThreadMod** ppThreadMod) { Assert(ppThreadMod != NULL); *ppThreadMod = Nu_Calloc(pArchive, sizeof(**ppThreadMod)); if (*ppThreadMod == NULL) return kNuErrMalloc; (*ppThreadMod)->entry.kind = kNuThreadModDelete; (*ppThreadMod)->entry.delete.used = false; (*ppThreadMod)->entry.delete.threadIdx = threadIdx; (*ppThreadMod)->entry.delete.threadID = threadID; return kNuErrNone; } /* * Free a single NuThreadMod. */ void Nu_ThreadModFree(NuArchive* pArchive, NuThreadMod* pThreadMod) { if (pThreadMod == NULL) return; switch (pThreadMod->entry.kind) { case kNuThreadModAdd: Nu_DataSourceFree(pThreadMod->entry.add.pDataSource); break; case kNuThreadModUpdate: Nu_DataSourceFree(pThreadMod->entry.update.pDataSource); break; default: break; } Nu_Free(pArchive, pThreadMod); } /* * Return a threadMod with a matching "threadIdx", if any. Because "add" * threads can't have a threadIdx that matches an existing thread, this * will only return updates and deletes. * * We don't allow more than one threadMod on the same thread, so we don't * have to deal with having more than one match. (To be safe, we go * ahead and do debug-only checks for multiple matches. There shouldn't * be more than three or four threads per record, so the extra search * isn't costly.) * * Returns "NULL" if nothing found. */ NuThreadMod* Nu_ThreadMod_FindByThreadIdx(const NuRecord* pRecord, NuThreadIdx threadIdx) { NuThreadMod* pThreadMod; NuThreadMod* pMatch = NULL; pThreadMod = pRecord->pThreadMods; while (pThreadMod) { switch (pThreadMod->entry.kind) { case kNuThreadModAdd: /* can't happen */ Assert(pThreadMod->entry.add.threadIdx != threadIdx); break; case kNuThreadModUpdate: if (pThreadMod->entry.update.threadIdx == threadIdx) { Assert(pMatch == NULL); pMatch = pThreadMod; } break; case kNuThreadModDelete: if (pThreadMod->entry.delete.threadIdx == threadIdx) { Assert(pMatch == NULL); pMatch = pThreadMod; } break; default: Assert(0); /* keep going, I guess */ } pThreadMod = pThreadMod->pNext; } return pMatch; } /* * =========================================================================== * ThreadMod list operations * =========================================================================== */ /* * Search for an "add" ThreadMod, by threadID. */ NuError Nu_ThreadModAdd_FindByThreadID(const NuRecord* pRecord, NuThreadID threadID, NuThreadMod** ppThreadMod) { NuThreadMod* pThreadMod; Assert(pRecord != NULL); Assert(ppThreadMod != NULL); pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { if (pThreadMod->entry.kind != kNuThreadModAdd) continue; if (pThreadMod->entry.add.threadID == threadID) { *ppThreadMod = pThreadMod; return kNuErrNone; } pThreadMod = pThreadMod->pNext; } return kNuErrNotFound; } /* * Free up the list of NuThreadMods in this record. */ void Nu_FreeThreadMods(NuArchive* pArchive, NuRecord* pRecord) { NuThreadMod* pThreadMod; NuThreadMod* pNext; Assert(pRecord != NULL); pThreadMod = pRecord->pThreadMods; if (pThreadMod == NULL) return; while (pThreadMod != NULL) { pNext = pThreadMod->pNext; Nu_ThreadModFree(pArchive, pThreadMod); pThreadMod = pNext; } pRecord->pThreadMods = NULL; } /* * =========================================================================== * Temporary structure for holding updated thread info * =========================================================================== */ /* used when constructing a new set of threads */ typedef struct { int numThreads; /* max #of threads */ int nextSlot; /* where the next one goes */ NuThread* pThreads; /* static-sized array */ } NuNewThreads; /* * Allocate and initialize a NuNewThreads struct. */ static NuError Nu_NewThreads_New(NuArchive* pArchive, NuNewThreads** ppNewThreads, long numThreads) { NuError err = kNuErrNone; *ppNewThreads = Nu_Malloc(pArchive, sizeof(**ppNewThreads)); BailAlloc(*ppNewThreads); (*ppNewThreads)->numThreads = numThreads; (*ppNewThreads)->nextSlot = 0; (*ppNewThreads)->pThreads = Nu_Malloc(pArchive, numThreads * sizeof(NuThread)); BailAlloc((*ppNewThreads)->pThreads); bail: return err; } /* * Free a NuNewThreads struct. */ static void Nu_NewThreads_Free(NuArchive* pArchive, NuNewThreads* pNewThreads) { if (pNewThreads != NULL) { Nu_Free(pArchive, pNewThreads->pThreads); Nu_Free(pArchive, pNewThreads); } } /* * Returns true if "pNewThreads" has room for another entry, false otherwise. */ static Boolean Nu_NewThreads_HasRoom(const NuNewThreads* pNewThreads) { if (pNewThreads->nextSlot < pNewThreads->numThreads) return true; else return false; } /* * Get the next available slot. The contents of the slot are first * initialized. * * The "next slot" marker is automatically advanced. */ static NuThread* Nu_NewThreads_GetNext(NuNewThreads* pNewThreads, NuArchive* pArchive) { NuThread* pThread; pThread = &pNewThreads->pThreads[pNewThreads->nextSlot]; memset(pThread, 0, sizeof(*pThread)); pThread->fileOffset = -1; /* mark as invalid */ /* advance slot */ pNewThreads->nextSlot++; Assert(pNewThreads->nextSlot <= pNewThreads->numThreads); return pThread; } /* * Return the #of threads we're meant to hold. */ static int Nu_NewThreads_GetNumThreads(const NuNewThreads* pNewThreads) { Assert(pNewThreads != NULL); return pNewThreads->numThreads; } /* * Total up the compressed EOFs of all threads. */ static uint32_t Nu_NewThreads_TotalCompThreadEOF(NuNewThreads* pNewThreads) { uint32_t compThreadEOF; int i; /* we should be all full up at this point; if not, we have a bug */ Assert(pNewThreads != NULL); Assert(pNewThreads->numThreads == pNewThreads->nextSlot); compThreadEOF = 0; for (i = 0; i < pNewThreads->numThreads; i++) compThreadEOF += pNewThreads->pThreads[i].thCompThreadEOF; return compThreadEOF; } /* * "Donate" the thread collection to the caller. This returns a pointer * to the thread array, and then nukes our copy of the pointer. This * allows us to transfer ownership of the storage to the caller. */ static NuThread* Nu_NewThreads_DonateThreads(NuNewThreads* pNewThreads) { NuThread* pThreads = pNewThreads->pThreads; pNewThreads->pThreads = NULL; return pThreads; } /* * =========================================================================== * Archive construction - Record-level functions * =========================================================================== */ /* * Copy an entire record (threads and all) from the source archive to the * current offset in the temp file. * * Pass in the record from the *copy* set, not the original. */ static NuError Nu_CopyArchiveRecord(NuArchive* pArchive, NuRecord* pRecord) { NuError err = kNuErrNone; long offsetAdjust; long outputOffset; int i; err = Nu_FTell(pArchive->tmpFp, &outputOffset); BailError(err); offsetAdjust = outputOffset - pRecord->fileOffset; DBUG(("--- Copying record '%s' (curOff=%ld adj=%ld)\n", pRecord->filename, outputOffset, offsetAdjust)); /* seek to the start point in the source file, and copy the whole thing */ err = Nu_FSeek(pArchive->archiveFp, pRecord->fileOffset, SEEK_SET); BailError(err); err = Nu_CopyFileSection(pArchive, pArchive->tmpFp, pArchive->archiveFp, pRecord->recHeaderLength + pRecord->totalCompLength); BailError(err); /* adjust the file offsets in the record header and in the threads */ pRecord->fileOffset += offsetAdjust; for (i = 0; i < (int)pRecord->recTotalThreads; i++) { NuThread* pThread = Nu_GetThread(pRecord, i); pThread->fileOffset += offsetAdjust; } Assert(outputOffset + pRecord->recHeaderLength + pRecord->totalCompLength == (uint32_t)ftell(pArchive->tmpFp)); Assert(pRecord->fileOffset == outputOffset); bail: return err; } /* * Count the number of threads that will eventually inhabit this record. * * Returns -1 on error. */ static NuError Nu_CountEventualThreads(const NuRecord* pRecord, long* pTotalThreads, long* pFilenameThreads) { const NuThreadMod* pThreadMod; const NuThread* pThread; long idx, numThreads, numFilenameThreads; /* * Number of threads is equal to: * the number of existing threads * MINUS the number of "delete" threadMods (you can't delete the same * thread more than once) * PLUS the number of "add" threadMods */ numThreads = pRecord->recTotalThreads; numFilenameThreads = 0; pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { switch (pThreadMod->entry.kind) { case kNuThreadModAdd: numThreads++; if (pThreadMod->entry.add.threadID == kNuThreadIDFilename) numFilenameThreads++; break; case kNuThreadModDelete: numThreads--; if (pThreadMod->entry.delete.threadID == kNuThreadIDFilename) numFilenameThreads--; break; case kNuThreadModUpdate: break; default: Assert(0); break; } pThreadMod = pThreadMod->pNext; } /* * If the record has more than one filename thread, we only keep * the first one, so remove it from our accounting here. It should * not have been possible to add a new filename thread when an * existing one was present, so we don't check the threadMods. */ for (idx = 0; idx < (long)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); if (NuGetThreadID(pThread) == kNuThreadIDFilename) numFilenameThreads++; } Assert(numFilenameThreads >= 0); if (numFilenameThreads > 1) { DBUG(("--- ODD: found multiple filename threads (%ld)\n", numFilenameThreads)); numThreads -= (numFilenameThreads -1); } /* * Records with no threads should've been screened out already. */ if (numThreads <= 0) return kNuErrInternal; *pTotalThreads = numThreads; *pFilenameThreads = numFilenameThreads; /* [should cap this at 1?] */ return kNuErrNone; } /* * Verify that all of the threads and threadMods in a record have * been touched. This is done after the record has been written to * the destination archive, in order to ensure that we don't leave * anything behind. * * All items, including things like duplicate filename threads that * we ignore, are marked "used" during processing, so we don't need * to be terribly bright here. */ static Boolean Nu_VerifyAllTouched(NuArchive* pArchive, const NuRecord* pRecord) { const NuThreadMod* pThreadMod; const NuThread* pThread; long idx; Assert(pArchive != NULL); Assert(pRecord != NULL); pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { Assert(pThreadMod->entry.generic.used == false || pThreadMod->entry.generic.used == true); if (!pThreadMod->entry.generic.used) return false; pThreadMod = pThreadMod->pNext; } for (idx = 0; idx < (long)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); Assert(pThread->used == false || pThread->used == true); if (!pThread->used) return false; } return true; } /* * Set the threadFilename field of a record to a new value. This does * not affect the record header filename. * * This call should only be made after an "add" or "update" threadMod has * successfully completed. * * "newName" must be allocated storage, Mac OS Roman charset. */ static void Nu_SetNewThreadFilename(NuArchive* pArchive, NuRecord* pRecord, char* newNameMOR) { Assert(pRecord != NULL); Assert(newNameMOR != NULL); Nu_Free(pArchive, pRecord->threadFilenameMOR); pRecord->threadFilenameMOR = newNameMOR; pRecord->filenameMOR = pRecord->threadFilenameMOR; } /* * If this is a disk image, we require that the uncompressed length * be equal to recExtraType * recStorageType (where recStorageType * is the block size, usually 512). If they haven't set those to * appropriate values, we'll set them on their behalf, so long as * the uncompressed size is a multiple of 512. */ static NuError Nu_UpdateDiskImageFields(NuArchive* pArchive, NuRecord* pRecord, long sourceLen) { NuError err = kNuErrNone; long actualLen; if (pRecord->recStorageType <= 13) pRecord->recStorageType = 512; actualLen = pRecord->recExtraType * pRecord->recStorageType; if (actualLen != sourceLen) { /* didn't match, see if we can fix it */ DBUG(("--- fixing up disk image size\n")); if ((sourceLen & 0x1ff) == 0) { pRecord->recStorageType = 512; pRecord->recExtraType = sourceLen / 512; } else { /* oh dear */ err = kNuErrBadData; Nu_ReportError(NU_BLOB, kNuErrNone,"disk image size of %ld invalid", sourceLen); /* fall through and out */ } } return err; } /* * As part of thread construction or in-place updating, handle a single * "update" threadMod. We have an existing thread, and are replacing * the contents of it with new data. * * "pThread" is a thread from the copy list or a "new" thread (a copy of * the thread from the "copy" list), and "pThreadMod" is a threadMod that * effects pThread. * * "fp" is a pointer into the archive at the offset where the data is * to be written. On exit, "fp" will point past the end of the pre-sized * buffer. * * Possible side-effects on "pRecord": threadFilename may be updated. */ static NuError Nu_ConstructArchiveUpdate(NuArchive* pArchive, FILE* fp, NuRecord* pRecord, NuThread* pThread, const NuThreadMod* pThreadMod) { NuError err; NuDataSource* pDataSource = NULL; uint32_t sourceLen; uint32_t threadBufSize; /* * We're going to copy the data out of the data source. Because * "update" actions only operate on pre-sized chunks, and the data * is never compressed, this should be straightforward. However, * we do need to make sure that the data will fit. * * I expect these to be small, and it's just a raw data copy, so no * progress updater is used. */ Assert(Nu_IsPresizedThreadID(NuGetThreadID(pThread))); Assert(pThread->thCompThreadEOF >= pThread->thThreadEOF); threadBufSize = pThread->thCompThreadEOF; pDataSource = pThreadMod->entry.update.pDataSource; Assert(pDataSource != NULL); err = Nu_DataSourcePrepareInput(pArchive, pDataSource); if (err == kNuErrSkipped) { /* something failed (during file open?), just skip this one */ DBUG(("--- skipping pre-sized thread update to %ld\n", pThread->threadIdx)); err = kNuErrNone; goto skip_update; } else if (err != kNuErrNone) goto bail; /* * Check to see if the data will fit. In some cases we can verify * the size during the UpdatePresizedThread call, but if it's being * added from a file we can't tell until now. * * We could be nice and give the user a chance to do something about * this, but frankly the application should have checked the file * size before handing it to us. */ sourceLen = Nu_DataSourceGetDataLen(pDataSource); if (sourceLen > pThread->thCompThreadEOF) { err = kNuErrPreSizeOverflow; Nu_ReportError(NU_BLOB, err, "can't fit %u bytes into %u-byte buffer", sourceLen, pThread->thCompThreadEOF); goto bail; } /* * During an update operation, the user's specification of "otherLen" * doesn't really matter, because we're not going to change the size * of the region in the archive. However, this size *is* used by * the code to figure out how big the buffer should be, and will * determine where the file pointer ends up when the call returns. * So, we jam in the "real" value. */ Nu_DataSourceSetOtherLen(pDataSource, pThread->thCompThreadEOF); if (NuGetThreadID(pThread) == kNuThreadIDFilename) { /* special handling for filename updates */ char* savedCopyMOR = NULL; err = Nu_CopyPresizedToArchive(pArchive, pDataSource, NuGetThreadID(pThread), fp, pThread, &savedCopyMOR); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "thread update failed"); goto bail; } Nu_SetNewThreadFilename(pArchive, pRecord, savedCopyMOR); } else { err = Nu_CopyPresizedToArchive(pArchive, pDataSource, NuGetThreadID(pThread), fp, pThread, NULL); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "thread update failed"); goto bail; } } Assert((uint32_t)ftell(fp) == pThread->fileOffset + threadBufSize); skip_update: Nu_DataSourceUnPrepareInput(pArchive, pDataSource); bail: return err; } /* * Handle all "add" threadMods in the current record. This is invoked both * when creating a new record from the "new" list or constructing a * modified record from the "copy" list. * * Writes to either the archiveFp or tmpFp; pass in the correct one, * properly positioned. * * If something goes wrong with one of the "adds", this will return * immediately with kNuErrSkipped. The caller is expected to abort the * entire record, so there's no point in continuing to process other * threads. * * Possible side-effects on "pRecord": disk image fields may be revised * (storage type, extra type), and threadFilename may be updated. */ static NuError Nu_HandleAddThreadMods(NuArchive* pArchive, NuRecord* pRecord, NuThreadID threadID, Boolean doKeepFirstOnly, NuNewThreads* pNewThreads, FILE* dstFp) { NuError err = kNuErrNone; NuProgressData progressData; NuProgressData* pProgressData; NuThreadMod* pThreadMod; NuThread* pNewThread; UNICHAR* pathnameUNIStorage = NULL; Boolean foundOne = false; /* * Now find all "add" threadMods with matching threadIDs. Allow * matching by wildcards, but don't re-use "used" entries. */ pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { if (pThreadMod->entry.kind == kNuThreadModAdd && !pThreadMod->entry.generic.used && (pThreadMod->entry.add.threadID == threadID || threadID == kNuThreadIDWildcard)) { DBUG(("+++ found ADD for 0x%08lx\n", pThreadMod->entry.add.threadID)); pThreadMod->entry.generic.used = true; /* if we're adding filename threads, stop after first one */ /* [shouldn't be able to happen... we only allow one filename!] */ if (doKeepFirstOnly && foundOne) { Assert(0); /* can this happen?? */ continue; } foundOne = true; if (!Nu_NewThreads_HasRoom(pNewThreads)) { Assert(0); err = kNuErrInternal; goto bail; } /* if this is a data thread, prepare the progress message */ pProgressData = NULL; if (NuThreadIDGetClass(pThreadMod->entry.add.threadID) == kNuThreadClassData) { /* * We're going to show the name as it appears in the * archive, rather than the name of the file we're * reading the data out of. We could do this differently * for a "file" data source, but we might as well be * consistent. * * [Actually, the above remark is bogus. During a bulk add * there's no other way to recover the original filename. * Do something different here for data sinks with * filenames attached. ++ATM 2003/02/17] */ pathnameUNIStorage = Nu_CopyMORToUNI(pRecord->filenameMOR); if (Nu_DataSourceGetType(pThreadMod->entry.add.pDataSource) == kNuDataSourceFromFile) { /* use on-disk filename */ err = Nu_ProgressDataInit_Compress(pArchive, &progressData, pRecord, Nu_DataSourceFile_GetPathname( pThreadMod->entry.add.pDataSource), pathnameUNIStorage); } else { /* use archive filename for both */ err = Nu_ProgressDataInit_Compress(pArchive, &progressData, pRecord, pathnameUNIStorage, pathnameUNIStorage); } BailError(err); /* send initial progress so they see name if "open" fails */ progressData.state = kNuProgressOpening; err = Nu_SendInitialProgress(pArchive, &progressData); BailError(err); pProgressData = &progressData; } /* get new thread storage, and init the thread's data offset */ /* (the threadIdx is set by GetNext) */ pNewThread = Nu_NewThreads_GetNext(pNewThreads, pArchive); pNewThread->threadIdx = pThreadMod->entry.add.threadIdx; err = Nu_FTell(dstFp, &pNewThread->fileOffset); BailError(err); /* this returns kNuErrSkipped if user elects to skip */ err = Nu_DataSourcePrepareInput(pArchive, pThreadMod->entry.add.pDataSource); BailError(err); /* * If they're adding a disk image thread, make sure the disk- * related fields in the record header are correct. */ if (pThreadMod->entry.add.threadID == kNuThreadIDDiskImage) { const NuDataSource* pDataSource = pThreadMod->entry.add.pDataSource; uint32_t uncompLen; if (Nu_DataSourceGetThreadFormat(pDataSource) == kNuThreadFormatUncompressed) { uncompLen = Nu_DataSourceGetDataLen(pDataSource); } else { uncompLen = Nu_DataSourceGetOtherLen(pDataSource); } err = Nu_UpdateDiskImageFields(pArchive, pRecord, uncompLen); BailError(err); } if (Nu_DataSourceGetType(pThreadMod->entry.add.pDataSource) == kNuDataSourceFromFile) { DBUG(("+++ ADDING from '%s' for '%s' (idx=%ld id=0x%08lx)\n", Nu_DataSourceFile_GetPathname(pThreadMod->entry.add.pDataSource), pRecord->filename, pThreadMod->entry.add.threadIdx, pThreadMod->entry.add.threadID)); } else { DBUG(("+++ ADDING from (type=%d) for '%s' (idx=%ld id=0x%08lx)\n", Nu_DataSourceGetType(pThreadMod->entry.add.pDataSource), pRecord->filename, pThreadMod->entry.add.threadIdx, pThreadMod->entry.add.threadID)); } if (pThreadMod->entry.add.threadID == kNuThreadIDFilename) { /* filenames are special */ char* savedCopyMOR = NULL; Assert(pThreadMod->entry.add.threadFormat == kNuThreadFormatUncompressed); err = Nu_CopyPresizedToArchive(pArchive, pThreadMod->entry.add.pDataSource, pThreadMod->entry.add.threadID, dstFp, pNewThread, &savedCopyMOR); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "fn thread add failed"); goto bail; } /* NOTE: on failure, "dropRecFilename" is still set. This doesn't matter though, since we'll either copy the original record, or abort the entire thing. At any rate, we can't just clear it, because we've already made space for the record header, and didn't include the filename in it. */ Nu_SetNewThreadFilename(pArchive, pRecord, savedCopyMOR); } else if (pThreadMod->entry.add.isPresized) { /* don't compress, just copy */ Assert(pThreadMod->entry.add.threadFormat == kNuThreadFormatUncompressed); err = Nu_CopyPresizedToArchive(pArchive, pThreadMod->entry.add.pDataSource, pThreadMod->entry.add.threadID, dstFp, pNewThread, NULL); /* fall through with err */ } else { /* compress (possibly by just copying) the source to dstFp */ err = Nu_CompressToArchive(pArchive, pThreadMod->entry.add.pDataSource, pThreadMod->entry.add.threadID, Nu_DataSourceGetThreadFormat( pThreadMod->entry.add.pDataSource), pThreadMod->entry.add.threadFormat, pProgressData, dstFp, pNewThread); /* fall through with err */ } if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "thread add failed"); goto bail; } Nu_DataSourceUnPrepareInput(pArchive, pThreadMod->entry.add.pDataSource); } pThreadMod = pThreadMod->pNext; } bail: Nu_Free(pArchive, pathnameUNIStorage); return err; } /* * Run through the list of threads and threadMods, looking for threads * with an ID that matches "threadID". When one is found, we take all * the appropriate steps to get the data into the archive. * * This takes into account the ThreadMods, including "delete" (ignore * existing thread), "update" (use data from threadMod instead of * existing thread), and "add" (use data from threadMod). * * Threads that are used or discarded will have a flag set so that * future examinations, notably those where "threadID" is a wildcard, * will ignore them. * * Always writes to the temp file. The temp file must be positioned in * the proper location. * * "pRecord" must be from the "copy" data set. */ static NuError Nu_ConstructArchiveThreads(NuArchive* pArchive, NuRecord* pRecord, NuThreadID threadID, Boolean doKeepFirstOnly, NuNewThreads* pNewThreads) { NuError err = kNuErrNone; NuThread* pThread; NuThreadMod* pThreadMod; Boolean foundOne = false; NuThread* pNewThread; int idx; /* * First, find any existing threads that match. If they have a * "delete" threadMod, ignore them; if they have an "update" threadMod, * use that instead. */ for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); DBUG(("+++ THREAD #%d (used=%d)\n", idx, pThread->used)); if (threadID == kNuThreadIDWildcard || threadID == NuGetThreadID(pThread)) { /* match! */ DBUG(("+++ MATCH THREAD #%d\n", idx)); if (pThread->used) continue; pThread->used = true; /* no matter what, we're done with this */ pThreadMod = Nu_ThreadMod_FindByThreadIdx(pRecord, pThread->threadIdx); if (pThreadMod != NULL) { /* * The thread has a related ThreadMod. Deal with it. */ pThreadMod->entry.generic.used = true; /* for Assert, later */ if (pThreadMod->entry.kind == kNuThreadModDelete) { /* this is a delete, ignore this thread */ DBUG(("+++ deleted %ld!\n", pThread->threadIdx)); continue; } else if (pThreadMod->entry.kind == kNuThreadModUpdate) { /* update pre-sized data in place */ DBUG(("+++ updating threadIdx=%ld\n", pThread->threadIdx)); /* only one filename per customer */ /* [does this make sense here??] */ if (doKeepFirstOnly && foundOne) continue; foundOne = true; /* add an entry in the new list of threads */ pNewThread = Nu_NewThreads_GetNext(pNewThreads, pArchive); Nu_CopyThreadContents(pNewThread, pThread); /* set the thread's file offset */ err = Nu_FTell(pArchive->tmpFp, &pNewThread->fileOffset); BailError(err); err = Nu_ConstructArchiveUpdate(pArchive, pArchive->tmpFp, pRecord, pNewThread, pThreadMod); BailError(err); } else { /* unknown ThreadMod type - this shouldn't happen! */ Assert(0); err = kNuErrInternal; goto bail; } } else { /* * Thread is unmodified. */ /* only one filename per customer */ if (doKeepFirstOnly && foundOne) continue; foundOne = true; /* * Copy the original data to the new location. Right now, * pThread->fileOffset has the correct offset for the * original file, and tmpFp is positioned at the correct * output offset. We want to seek the source file, replace * pThread->fileOffset with the *new* offset, and then * copy the data. * * This feels skankier than it really is because we're * using the thread in the "copy" set for two purposes. * It'd be cleaner to pass in the thread from the "orig" * set, but there's really not much value in doing so. * * [should this have a progress meter associated?] */ DBUG(("+++ just copying threadIdx=%ld\n", pThread->threadIdx)); err = Nu_FSeek(pArchive->archiveFp, pThread->fileOffset, SEEK_SET); BailError(err); err = Nu_FTell(pArchive->tmpFp, &pThread->fileOffset); BailError(err); err = Nu_CopyFileSection(pArchive, pArchive->tmpFp, pArchive->archiveFp, pThread->thCompThreadEOF); BailError(err); /* copy an entry over into the replacement thread list */ pNewThread = Nu_NewThreads_GetNext(pNewThreads, pArchive); Nu_CopyThreadContents(pNewThread, pThread); } } } /* no need to check for "add" mods; there can't be one for us */ if (doKeepFirstOnly && foundOne) goto bail; /* * Now handle any "add" threadMods. */ err = Nu_HandleAddThreadMods(pArchive, pRecord, threadID, doKeepFirstOnly, pNewThreads, pArchive->tmpFp); BailError(err); bail: return err; } /* * Construct a record in the temp file, based on the contents of the * original. Takes into account "dirty" headers and threadMod changes. * * Pass in the record from the *copy* set, not the original. The temp * file should be positioned at the correct spot. * * If something goes wrong, and the user wants to abort the record but * not the entire operation, we rewind the temp file to the initial * position. It's not possible to abandon part of a record; either you * get everything you asked for or nothing at all. We then return * kNuErrSkipped, which should cause the caller to simply copy the * previous record. */ static NuError Nu_ConstructArchiveRecord(NuArchive* pArchive, NuRecord* pRecord) { NuError err; NuNewThreads* pNewThreads = NULL; long threadDisp; long initialOffset, finalOffset; long numThreads, numFilenameThreads; int newHeaderSize; Assert(pArchive != NULL); Assert(pRecord != NULL); DBUG(("--- Reconstructing '%s'\n", pRecord->filename)); err = Nu_FTell(pArchive->tmpFp, &initialOffset); BailError(err); Assert(initialOffset != 0); /* * Figure out how large the record header is. This requires * measuring the static elements, the not-so-static elements like * the GS/OS option list and perhaps the filename, and getting an * accurate count of the number of threads. * * Since we're going to keep any option lists and extra junk stored in * the header originally, the size of the new base record header is * equal to the original recAttribCount. The attribute count conveniently * does *not* include the filename, so if we've moved it out of the * record header and into a thread, it won't affect us here. */ err = Nu_CountEventualThreads(pRecord, &numThreads, &numFilenameThreads); BailError(err); Assert(numThreads > 0); /* threadless records should already be gone */ if (numThreads <= 0) { err = kNuErrInternal; goto bail; } /* * Handle filename deletion. */ if (!numFilenameThreads && pRecord->threadFilenameMOR != NULL) { /* looks like a previously existing filename thread got removed */ DBUG(("--- Dropping thread filename '%s'\n", pRecord->threadFilenameMOR)); if (pRecord->filenameMOR == pRecord->threadFilenameMOR) pRecord->filenameMOR = NULL; /* don't point at freed memory! */ Nu_Free(pArchive, pRecord->threadFilenameMOR); pRecord->threadFilenameMOR = NULL; /* I don't think this is possible, but check it anyway */ if (pRecord->filenameMOR == NULL && pRecord->recFilenameMOR != NULL && !pRecord->dropRecFilename) { DBUG(("--- HEY, how did this happen?\n")); pRecord->filenameMOR = pRecord->recFilenameMOR; } } if (pRecord->filenameMOR == NULL) pRecord->filenameMOR = kNuDefaultRecordName; /* * Make a hole, including the header filename if we're not dropping it. * * This ignores fake vs. non-fake threads, because once we're done * writing they're all "real". */ newHeaderSize = pRecord->recAttribCount + numThreads * kNuThreadHeaderSize; if (!pRecord->dropRecFilename) newHeaderSize += pRecord->recFilenameLength; DBUG(("+++ new header size = %d\n", newHeaderSize)); err = Nu_FSeek(pArchive->tmpFp, newHeaderSize, SEEK_CUR); BailError(err); /* * It is important to arrange the threads in a specific order. For * example, we can have trouble doing a streaming archive read if the * filename isn't the first thread the collection. It's prudent to * mimic GSHK's behavior, so we act to ensure that things appear in * the following order: * * (1) filename thread * (2) comment thread(s) * (3) data thread with data fork * (4) data thread with disk image * (5) data thread with rsrc fork * (6) everything else * * If we ended up with two filename threads (perhaps some other aberrant * application created the archive; we certainly wouldn't do that), we * keep the first one. We're more lenient on propagating strange * multiple comment and data thread situations, even though the * thread updating mechanism in this library won't necessarily allow * such situations. */ err = Nu_NewThreads_New(pArchive, &pNewThreads, numThreads); BailError(err); err = Nu_ConstructArchiveThreads(pArchive, pRecord, kNuThreadIDFilename, true, pNewThreads); BailError(err); err = Nu_ConstructArchiveThreads(pArchive, pRecord, kNuThreadIDComment, false, pNewThreads); BailError(err); err = Nu_ConstructArchiveThreads(pArchive, pRecord, kNuThreadIDDataFork, false, pNewThreads); BailError(err); err = Nu_ConstructArchiveThreads(pArchive, pRecord, kNuThreadIDDiskImage, false, pNewThreads); BailError(err); err = Nu_ConstructArchiveThreads(pArchive, pRecord, kNuThreadIDRsrcFork, false, pNewThreads); BailError(err); err = Nu_ConstructArchiveThreads(pArchive, pRecord, kNuThreadIDWildcard, false, pNewThreads); BailError(err); /* * Perform some sanity checks. */ Assert(!Nu_NewThreads_HasRoom(pNewThreads)); /* verify that all threads and threadMods have been touched */ if (!Nu_VerifyAllTouched(pArchive, pRecord)) { err = kNuErrInternal; Assert(0); goto bail; } /* verify that file displacement is where it should be */ threadDisp = (long)Nu_NewThreads_TotalCompThreadEOF(pNewThreads); err = Nu_FTell(pArchive->tmpFp, &finalOffset); BailError(err); Assert(finalOffset > initialOffset); if (finalOffset - (initialOffset + newHeaderSize) != threadDisp) { Nu_ReportError(NU_BLOB, kNuErrNone, "ERROR: didn't end up where expected (%ld %ld %ld)", initialOffset, finalOffset, threadDisp); err = kNuErrInternal; Assert(0); goto bail; } /* * Free existing Threads and ThreadMods, and move the list from * pNewThreads over. */ Nu_Free(pArchive, pRecord->pThreads); Nu_FreeThreadMods(pArchive, pRecord); pRecord->pThreads = Nu_NewThreads_DonateThreads(pNewThreads); pRecord->recTotalThreads = Nu_NewThreads_GetNumThreads(pNewThreads); /* * Now, seek back and write the record header. */ err = Nu_FSeek(pArchive->tmpFp, initialOffset, SEEK_SET); BailError(err); err = Nu_WriteRecordHeader(pArchive, pRecord, pArchive->tmpFp); BailError(err); Assert(newHeaderSize == (int) pRecord->recHeaderLength); /* * Seek forward once again, so we are positioned at the correct * place to write the next record. */ err = Nu_FSeek(pArchive->tmpFp, finalOffset, SEEK_SET); BailError(err); /* update the record's fileOffset to reflect its new position */ DBUG(("+++ record shifted by %ld bytes\n", initialOffset - pRecord->fileOffset)); pRecord->fileOffset = initialOffset; bail: if (err == kNuErrSkipped) { /* * Something went wrong and they want to skip this record but * keep going otherwise. We need to back up in the file so the * original copy of the record can go here. */ err = Nu_FSeek(pArchive->tmpFp, initialOffset, SEEK_SET); if (err == kNuErrNone) err = kNuErrSkipped; /* tell the caller we skipped it */ } Nu_NewThreads_Free(pArchive, pNewThreads); return err; } /* * Construct a new record and add it to the original or temp file. The * new record has no threads but some number of threadMods. (This * function is a cousin to Nu_ConstructArchiveRecord.) "pRecord" must * come from the "new" record set. * * The original/temp file should be positioned at the correct spot. * * If something goes wrong, and the user wants to abort the record but * not the entire operation, we rewind the temp file to the initial * position and return kNuErrSkipped. */ static NuError Nu_ConstructNewRecord(NuArchive* pArchive, NuRecord* pRecord, FILE* fp) { NuError err; NuNewThreads* pNewThreads = NULL; NuThreadMod* pThreadMod; long threadDisp; long initialOffset, finalOffset; long numThreadMods, numFilenameThreads; int newHeaderSize; Assert(pArchive != NULL); Assert(pRecord != NULL); DBUG(("--- Constructing '%s'\n", pRecord->filename)); err = Nu_FTell(fp, &initialOffset); BailError(err); Assert(initialOffset != 0); /* * Quick sanity check: verify that the record has no threads of its * own, and all threadMods are "add" threadMods. While we're at it, * make ourselves useful by counting up the number of eventual * threads, and verify that there is exactly one filename thread. */ Assert(pRecord->pThreads == NULL); numThreadMods = 0; numFilenameThreads = 0; pThreadMod = pRecord->pThreadMods; while (pThreadMod) { if (pThreadMod->entry.kind != kNuThreadModAdd) { Nu_ReportError(NU_BLOB, kNuErrNone, "unexpected non-add threadMod"); err = kNuErrInternal; Assert(0); goto bail; } numThreadMods++; if (pThreadMod->entry.add.threadID == kNuThreadIDFilename) numFilenameThreads++; pThreadMod = pThreadMod->pNext; } Assert(numFilenameThreads <= 1); /* * If there's no filename thread, make one. We do this for brand-new * records when the application doesn't explicitly add a thread. */ if (!numFilenameThreads) { NuDataSource* pTmpDataSource = NULL; NuThreadMod* pNewThreadMod = NULL; int len, maxLen; /* * Generally speaking, the "add file" call should set the * filename. If somehow it didn't, assign a default. */ if (pRecord->filenameMOR == NULL) { pRecord->newFilenameMOR = strdup(kNuDefaultRecordName); pRecord->filenameMOR = pRecord->newFilenameMOR; } DBUG(("--- No filename thread found, adding one ('%s')\n", pRecord->filenameMOR)); /* * Create a trivial data source for the filename. The size of * the filename buffer is the larger of the filename length and * the default filename buffer size. This mimics GSHK's behavior. * (If we're really serious about renaming it, maybe we should * leave some extra space on the end...?) */ len = strlen(pRecord->filenameMOR); maxLen = len > kNuDefaultFilenameThreadSize ? len : kNuDefaultFilenameThreadSize; err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, maxLen, (const uint8_t*)pRecord->filenameMOR, 0, strlen(pRecord->filenameMOR), NULL, &pTmpDataSource); BailError(err); /* put in a new "add" threadMod (which copies the data source) */ err = Nu_ThreadModAdd_New(pArchive, kNuThreadIDFilename, kNuThreadFormatUncompressed, pTmpDataSource, &pNewThreadMod); Nu_DataSourceFree(pTmpDataSource); BailError(err); /* add it to the list */ Nu_RecordAddThreadMod(pRecord, pNewThreadMod); pNewThreadMod = NULL; numFilenameThreads++; numThreadMods++; } /* * Figure out how large the record header is. We don't generate * GS/OS option lists or "extra" data here, and we always put the * filename in a thread, so the size is constant. (If somebody * does a GS/OS or Mac port and wants to add option lists, it should * not be hard to adjust the size accordingly.) * * This initializes the record's attribCount. We use the "base size" * and add two for the (unused) filename length. */ pRecord->recAttribCount = kNuRecordHeaderBaseSize +2; newHeaderSize = pRecord->recAttribCount + numThreadMods * kNuThreadHeaderSize; DBUG(("+++ new header size = %d\n", newHeaderSize)); /* leave a hole */ err = Nu_FSeek(fp, newHeaderSize, SEEK_CUR); BailError(err); /* * It is important to arrange the threads in a specific order. See * the comments in Nu_ConstructArchiveRecord for the rationale. */ err = Nu_NewThreads_New(pArchive, &pNewThreads, numThreadMods); BailError(err); err = Nu_HandleAddThreadMods(pArchive, pRecord, kNuThreadIDFilename, true, pNewThreads, fp); BailError(err); err = Nu_HandleAddThreadMods(pArchive, pRecord, kNuThreadIDComment, false, pNewThreads, fp); BailError(err); err = Nu_HandleAddThreadMods(pArchive, pRecord, kNuThreadIDDataFork, false, pNewThreads, fp); BailError(err); err = Nu_HandleAddThreadMods(pArchive, pRecord, kNuThreadIDDiskImage, false, pNewThreads, fp); BailError(err); err = Nu_HandleAddThreadMods(pArchive, pRecord, kNuThreadIDRsrcFork, false, pNewThreads, fp); BailError(err); err = Nu_HandleAddThreadMods(pArchive, pRecord, kNuThreadIDWildcard, false, pNewThreads, fp); BailError(err); /* * Perform some sanity checks. */ Assert(!Nu_NewThreads_HasRoom(pNewThreads)); /* verify that all threads and threadMods have been touched */ if (!Nu_VerifyAllTouched(pArchive, pRecord)) { err = kNuErrInternal; Assert(0); goto bail; } /* verify that file displacement is where it should be */ threadDisp = Nu_NewThreads_TotalCompThreadEOF(pNewThreads); err = Nu_FTell(fp, &finalOffset); BailError(err); Assert(finalOffset > initialOffset); if (finalOffset - (initialOffset + newHeaderSize) != threadDisp) { Nu_ReportError(NU_BLOB, kNuErrNone, "ERROR: didn't end up where expected (%ld %ld %ld)", initialOffset, finalOffset, threadDisp); err = kNuErrInternal; Assert(0); goto bail; } /* * Install pNewThreads as the thread list. */ Assert(pRecord->pThreads == NULL && pRecord->recTotalThreads == 0); pRecord->pThreads = Nu_NewThreads_DonateThreads(pNewThreads); pRecord->recTotalThreads = Nu_NewThreads_GetNumThreads(pNewThreads); /* * Fill in misc record header fields. * * We could set recArchiveWhen here, if we wanted to override what * the application set, but I don't think there's any value in that. */ pRecord->fileOffset = initialOffset; /* * Now, seek back and write the record header. */ err = Nu_FSeek(fp, initialOffset, SEEK_SET); BailError(err); err = Nu_WriteRecordHeader(pArchive, pRecord, fp); BailError(err); /* * Seek forward once again, so we are positioned at the correct * place to write the next record. */ err = Nu_FSeek(fp, finalOffset, SEEK_SET); BailError(err); /* * Trash the threadMods. */ Nu_FreeThreadMods(pArchive, pRecord); bail: if (err == kNuErrSkipped) { /* * Something went wrong and they want to skip this record but * keep going otherwise. We need to back up in the file so the * next record can go here. */ err = Nu_FSeek(fp, initialOffset, SEEK_SET); if (err == kNuErrNone) err = kNuErrSkipped; /* tell the caller we skipped it */ } Nu_NewThreads_Free(pArchive, pNewThreads); return err; } /* * Update a given record in the original archive file. * * "pRecord" is the record from the "copy" set. It can have the * "dirtyHeader" flag set, and may have "update" threadMods, but * that's all. * * The position of pArchive->archiveFp on entry and on exit is not * defined. */ static NuError Nu_UpdateRecordInOriginal(NuArchive* pArchive, NuRecord* pRecord) { NuError err = kNuErrNone; NuThread* pThread; const NuThreadMod* pThreadMod; /* * Loop through all threadMods. */ pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { Assert(pThreadMod->entry.kind == kNuThreadModUpdate); /* find the thread associated with this threadMod */ err = Nu_FindThreadByIdx(pRecord, pThreadMod->entry.update.threadIdx, &pThread); BailError(err); /* should never happen */ /* seek to the appropriate spot */ err = Nu_FSeek(pArchive->archiveFp, pThread->fileOffset, SEEK_SET); BailError(err); /* do the update; this updates "pThread" with the new info */ err = Nu_ConstructArchiveUpdate(pArchive, pArchive->archiveFp, pRecord, pThread, pThreadMod); BailError(err); pThreadMod = pThreadMod->pNext; } /* * We have to write a new record header without disturbing * anything around it. Nothing we've done should've changed * the size of the record header, so just go ahead and write it. * * We have to do this regardless of "dirtyHeader", because we just * tweaked some of our threads around, and we need to rewrite the * thread headers (which updates the record header CRC, and so on). */ err = Nu_FSeek(pArchive->archiveFp, pRecord->fileOffset, SEEK_SET); BailError(err); err = Nu_WriteRecordHeader(pArchive, pRecord, pArchive->archiveFp); BailError(err); /* * Let's be paranoid and verify that the write didn't overflow * into the thread header. We compare our current offset against * the offset of the first thread. (If we're in a weird record * with no threads, we could compare against the offset of the * next record, but I don't want to deal with a case that should * never happen anyway.) */ DBUG(("--- record header wrote %ld bytes\n", pArchive->currentOffset - pRecord->fileOffset)); pThread = pRecord->pThreads; if (pThread != NULL && pArchive->currentOffset != pThread->fileOffset) { /* guess what, we just trashed the archive */ err = kNuErrDamaged; Nu_ReportError(NU_BLOB, err, "Bad record header write (off by %ld), archive damaged", pArchive->currentOffset - pThread->fileOffset); goto bail; } DBUG(("--- record header written safely\n")); /* * It's customary to throw out the thread mods when you're done. (I'm * not really sure why I'm doing this now, but here we are.) */ Nu_FreeThreadMods(pArchive, pRecord); bail: return err; } /* * =========================================================================== * Archive construction - main functions * =========================================================================== */ /* * Fill in the temp file with the contents of the original archive. The * file offsets and any other generated data in the "copy" set will be * updated as appropriate, so that the "copy" set can eventually replace * the "orig" set. * * On exit, pArchive->tmpFp will point at the archive EOF. */ static NuError Nu_CreateTempFromOriginal(NuArchive* pArchive) { NuError err = kNuErrNone; NuRecord* pRecord; Assert(pArchive->tmpFp != 0); Assert(ftell(pArchive->tmpFp) == 0); /* should be empty as well */ /* * Leave space for the master header and (if we're preserving it) any * header gunk. */ Assert(!pArchive->valDiscardWrapper || pArchive->headerOffset == 0); err = Nu_FSeek(pArchive->tmpFp, pArchive->headerOffset + kNuMasterHeaderSize, SEEK_SET); BailError(err); if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) { /* * Run through the "copy" records. If the original record header is * umodified, just copy it; otherwise write a new one with a new CRC. */ if (Nu_RecordSet_IsEmpty(&pArchive->copyRecordSet)) { /* new archive or all records deleted */ DBUG(("--- No records in 'copy' set\n")); goto bail; } pRecord = Nu_RecordSet_GetListHead(&pArchive->copyRecordSet); } else { /* * There's no "copy" set defined. If we have an "orig" set, we * must be doing nothing but add files to an existing archive * without the "modify orig" flag set. */ if (Nu_RecordSet_IsEmpty(&pArchive->origRecordSet)) { DBUG(("--- No records in 'copy' or 'orig' set\n")); goto bail; } pRecord = Nu_RecordSet_GetListHead(&pArchive->origRecordSet); } /* * Reconstruct or copy the records. It's probably not necessary * to reconstruct the entire record if we're just updating the * record header, but since all we do is copy the data anyway, * it's not much slower. */ while (pRecord != NULL) { if (!pRecord->dirtyHeader && pRecord->pThreadMods == NULL) { err = Nu_CopyArchiveRecord(pArchive, pRecord); BailError(err); } else { err = Nu_ConstructArchiveRecord(pArchive, pRecord); if (err == kNuErrSkipped) { /* * We're going to retain the original. This requires us * to copy the original record from the "orig" record set * and replace what we had in the "copy" set, so that at * the end of the day the "copy" set accurately reflects * what's in the archive. */ DBUG(("--- Skipping, copying %ld instead\n", pRecord->recordIdx)); err = Nu_RecordSet_ReplaceRecord(pArchive, &pArchive->copyRecordSet, pRecord, &pArchive->origRecordSet, &pRecord); BailError(err); err = Nu_CopyArchiveRecord(pArchive, pRecord); BailError(err); } BailError(err); } pRecord = pRecord->pNext; } bail: return err; } /* * Perform updates to certain items in the original archive. None of * the operations changes the position of items within. * * On exit, pArchive->archiveFp will point at the archive EOF. */ static NuError Nu_UpdateInOriginal(NuArchive* pArchive) { NuError err = kNuErrNone; NuRecord* pRecord; if (!Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) { /* * There's nothing for us to do; we probably just have a * bunch of new stuff being added. */ DBUG(("--- UpdateInOriginal: nothing to do\n")); goto done; } /* * Run through and process all the updates. */ pRecord = Nu_RecordSet_GetListHead(&pArchive->copyRecordSet); while (pRecord != NULL) { if (pRecord->dirtyHeader || pRecord->pThreadMods != NULL) { err = Nu_UpdateRecordInOriginal(pArchive, pRecord); BailError(err); } pRecord = pRecord->pNext; } done: /* seek to the end of the archive */ err = Nu_FSeek(pArchive->archiveFp, pArchive->headerOffset + pArchive->masterHeader.mhMasterEOF, SEEK_SET); BailError(err); bail: return err; } /* * Create new records for all items in the "new" list, writing them to * "fp" at the current offset. * * On completion, "fp" will point at the end of the archive. */ static NuError Nu_CreateNewRecords(NuArchive* pArchive, FILE* fp) { NuError err = kNuErrNone; NuRecord* pRecord; pRecord = Nu_RecordSet_GetListHead(&pArchive->newRecordSet); while (pRecord != NULL) { err = Nu_ConstructNewRecord(pArchive, pRecord, fp); if (err == kNuErrSkipped) { /* * We decided to skip this record, so delete it from "new". * * (I think this is the only time we delete something from the * "new" set...) */ NuRecord* pNextRecord = pRecord->pNext; DBUG(("--- Skipping, deleting new %ld\n", pRecord->recordIdx)); err = Nu_RecordSet_DeleteRecord(pArchive, &pArchive->newRecordSet, pRecord); Assert(err == kNuErrNone); BailError(err); pRecord = pNextRecord; } else { BailError(err); pRecord = pRecord->pNext; } } bail: return err; } /* * =========================================================================== * Archive update helpers * =========================================================================== */ /* * Determine if any "heavy updates" have been made. A "heavy" update is * one that requires us to create and rename a temp file. * * If the "copy" record set hasn't been loaded, we're done. If it has * been loaded, we scan through the list for thread mods other than updates * to pre-sized fields. We also have to check to see if any records were * deleted. * * At present, a "dirtyHeader" flag is not of itself cause to rebuild * the archive, so we don't test for it here. */ static Boolean Nu_NoHeavyUpdates(NuArchive* pArchive) { const NuRecord* pRecord; long count; /* if not loaded, then *no* changes were made to original records */ if (!Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) return true; /* * You can't add to "copy" set, so any deletions are visible by the * reduced record count. The function that deletes records from * which all threads have been removed should be called before we * get here. */ if (Nu_RecordSet_GetNumRecords(&pArchive->copyRecordSet) != Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet)) { return false; } /* * Run through the set of records, looking for a threadMod with a * change type we can't handle in place. */ count = Nu_RecordSet_GetNumRecords(&pArchive->copyRecordSet); pRecord = Nu_RecordSet_GetListHead(&pArchive->copyRecordSet); while (count--) { const NuThreadMod* pThreadMod; Assert(pRecord != NULL); pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { /* the only acceptable kind is "update" */ if (pThreadMod->entry.kind != kNuThreadModUpdate) return false; pThreadMod = pThreadMod->pNext; } pRecord = pRecord->pNext; } return true; } /* * Purge any records that don't have any threads. This has to take into * account pending modifications, so that we dispose of any records that * have had all of their threads deleted. * * Simplest approach is to count up the #of "delete" mods and subtract * it from the number of threads, skipping on if the record has any * "add" thread mods. */ static NuError Nu_PurgeEmptyRecords(NuArchive* pArchive, NuRecordSet* pRecordSet) { NuError err = kNuErrNone; NuRecord* pRecord; NuRecord** ppRecord; Assert(pArchive != NULL); Assert(pRecordSet != NULL); if (Nu_RecordSet_IsEmpty(pRecordSet)) return kNuErrNone; ppRecord = Nu_RecordSet_GetListHeadPtr(pRecordSet); Assert(ppRecord != NULL); Assert(*ppRecord != NULL); /* maintain a pointer to the pointer, so we can delete easily */ while (*ppRecord != NULL) { pRecord = *ppRecord; if (Nu_RecordIsEmpty(pArchive, pRecord)) { DBUG(("--- Purging empty record %06ld '%s' (0x%08lx-->0x%08lx)\n", pRecord->recordIdx, pRecord->filename, (uint32_t)ppRecord, (uint32_t)pRecord)); err = Nu_RecordSet_DeleteRecordPtr(pArchive, pRecordSet, ppRecord); BailError(err); /* pRecord is now invalid, and *ppRecord has been updated */ } else { ppRecord = &pRecord->pNext; } } bail: return err; } /* * Update the "new" master header block with the contents of the modified * archive, and write it to the file. * * Pass in a correctly positioned "fp" and the total length of the archive * file. */ static NuError Nu_UpdateMasterHeader(NuArchive* pArchive, FILE* fp, long archiveEOF) { NuError err; long numRecords; Nu_MasterHeaderCopy(pArchive, &pArchive->newMasterHeader, &pArchive->masterHeader); numRecords = 0; if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) numRecords += Nu_RecordSet_GetNumRecords(&pArchive->copyRecordSet); else numRecords += Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet); if (Nu_RecordSet_GetLoaded(&pArchive->newRecordSet)) numRecords += Nu_RecordSet_GetNumRecords(&pArchive->newRecordSet); #if 0 /* we allow delete-all now */ if (numRecords == 0) { /* don't allow empty archives */ DBUG(("--- UpdateMasterHeader didn't find any records\n")); err = kNuErrNoRecords; goto bail; } #endif pArchive->newMasterHeader.mhTotalRecords = numRecords; pArchive->newMasterHeader.mhMasterEOF = archiveEOF; pArchive->newMasterHeader.mhMasterVersion = kNuOurMHVersion; Nu_SetCurrentDateTime(&pArchive->newMasterHeader.mhArchiveModWhen); err = Nu_WriteMasterHeader(pArchive, fp, &pArchive->newMasterHeader); BailError(err); bail: return err; } /* * Reset the temp file to a known (empty) state. */ static NuError Nu_ResetTempFile(NuArchive* pArchive) { NuError err = kNuErrNone; /* read-only archives don't have a temp file */ if (Nu_IsReadOnly(pArchive)) return kNuErrNone; /* or kNuErrArchiveRO? */ Assert(pArchive != NULL); Assert(pArchive->tmpPathnameUNI != NULL); #if 0 /* keep the temp file around for examination */ if (pArchive->tmpFp != NULL) { DBUG(("--- NOT Resetting temp file\n")); fflush(pArchive->tmpFp); goto bail; } #endif DBUG(("--- Resetting temp file\n")); /* if we renamed the temp over the original, we need to open a new temp */ if (pArchive->tmpFp == NULL) { // as in Nu_OpenTempFile, skip the wchar conversion for the temp // file name, which we lazily assume to be ASCII pArchive->tmpFp = fopen(pArchive->tmpPathnameUNI, kNuFileOpenReadWriteCreat); if (pArchive->tmpFp == NULL) { err = errno ? errno : kNuErrFileOpen; Nu_ReportError(NU_BLOB, errno, "Unable to open temp file '%s'", pArchive->tmpPathnameUNI); goto bail; } } else { /* * Truncate the temp file. */ err = Nu_FSeek(pArchive->tmpFp, 0, SEEK_SET); BailError(err); err = Nu_TruncateOpenFile(pArchive->tmpFp, 0); if (err == kNuErrInternal) { /* do it the hard way if we don't have ftruncate or equivalent */ err = kNuErrNone; fclose(pArchive->tmpFp); pArchive->tmpFp = fopen(pArchive->tmpPathnameUNI, kNuFileOpenWriteTrunc); if (pArchive->tmpFp == NULL) { err = errno ? errno : kNuErrFileOpen; Nu_ReportError(NU_BLOB, err, "failed truncating tmp file"); goto bail; } fclose(pArchive->tmpFp); pArchive->tmpFp = fopen(pArchive->tmpPathnameUNI, kNuFileOpenReadWriteCreat); if (pArchive->tmpFp == NULL) { err = errno ? errno : kNuErrFileOpen; Nu_ReportError(NU_BLOB, err, "Unable to open temp file '%s'", pArchive->tmpPathnameUNI); goto bail; } } } bail: return err; } /* * Ensure that all of the threads and threadMods in a record are in * a pristine state, i.e. "threads" aren't marked used and "threadMods" * don't even exist. This is done as we are cleaning up the record sets * after a successful (or aborted) update. */ static NuError Nu_RecordResetUsedFlags(NuArchive* pArchive, NuRecord* pRecord) { NuThread* pThread; long idx; Assert(pArchive != NULL); Assert(pRecord != NULL); /* these should already be clear */ if (pRecord->pThreadMods) { Assert(0); return kNuErrInternal; } /* these might still be set */ for (idx = 0; idx < (long)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); pThread->used = false; } /* and this */ pRecord->dirtyHeader = false; return kNuErrNone; } /* * Invoke Nu_RecordResetUsedFlags on all records in a record set. */ static NuError Nu_ResetUsedFlags(NuArchive* pArchive, NuRecordSet* pRecordSet) { NuError err = kNuErrNone; NuRecord* pRecord; pRecord = Nu_RecordSet_GetListHead(pRecordSet); while (pRecord != NULL) { err = Nu_RecordResetUsedFlags(pArchive, pRecord); if (err != kNuErrNone) { Assert(0); break; } pRecord = pRecord->pNext; } return err; } /* * If nothing in the "copy" set has actually been disturbed, throw it out. */ static void Nu_ResetCopySetIfUntouched(NuArchive* pArchive) { const NuRecord* pRecord; /* have any records been deleted? */ if (Nu_RecordSet_GetNumRecords(&pArchive->copyRecordSet) != pArchive->masterHeader.mhTotalRecords) { return; } /* do we have any thread mods or dirty record headers? */ pRecord = Nu_RecordSet_GetListHead(&pArchive->copyRecordSet); while (pRecord != NULL) { if (pRecord->pThreadMods != NULL || pRecord->dirtyHeader) return; pRecord = pRecord->pNext; } /* looks like nothing has been touched */ DBUG(("--- copy set untouched, trashing it\n")); (void) Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->copyRecordSet); } /* * GSHK always adds a comment to the first new record added to an archive. * Imitate this behavior. */ static NuError Nu_AddCommentToFirstNewRecord(NuArchive* pArchive) { NuError err = kNuErrNone; NuRecord* pRecord; NuThreadMod* pThreadMod = NULL; NuThreadMod* pExistingThreadMod = NULL; NuDataSource* pDataSource = NULL; /* if there aren't any records there, skip this */ if (Nu_RecordSet_IsEmpty(&pArchive->newRecordSet)) goto bail; pRecord = Nu_RecordSet_GetListHead(&pArchive->newRecordSet); /* * See if this record already has a comment. If so, don't add * another one. */ err = Nu_ThreadModAdd_FindByThreadID(pRecord, kNuThreadIDComment, &pExistingThreadMod); if (err == kNuErrNone) { DBUG(("+++ record already has a comment, not adding another\n")); goto bail; /* already exists */ } err = kNuErrNone; /* create a new data source with nothing in it */ err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, kNuDefaultCommentSize, NULL, 0, 0, NULL, &pDataSource); BailError(err); Assert(pDataSource != NULL); /* create a new ThreadMod */ err = Nu_ThreadModAdd_New(pArchive, kNuThreadIDComment, kNuThreadFormatUncompressed, pDataSource, &pThreadMod); BailError(err); Assert(pThreadMod != NULL); /*pDataSource = NULL;*/ /* ThreadModAdd_New makes a copy */ /* add the thread mod to the record */ Nu_RecordAddThreadMod(pRecord, pThreadMod); pThreadMod = NULL; /* don't free on exit */ bail: Nu_ThreadModFree(pArchive, pThreadMod); Nu_DataSourceFree(pDataSource); return err; } /* * =========================================================================== * Main entry points * =========================================================================== */ /* * Force all deferred changes to occur. * * If the flush fails, the archive state may be aborted or even placed * into read-only mode to prevent problems from compounding. * * If the things this function is doing aren't making any sense at all, * read "NOTES.txt" for an introduction. */ NuError Nu_Flush(NuArchive* pArchive, uint32_t* pStatusFlags) { NuError err = kNuErrNone; Boolean canAbort = true; Boolean writeToTemp = true; Boolean deleteAll = false; long initialEOF, finalOffset; DBUG(("--- FLUSH\n")); if (pStatusFlags == NULL) return kNuErrInvalidArg; /* these do get set on error, so clear them no matter what */ *pStatusFlags = 0; if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetFileLength(pArchive, pArchive->archiveFp, &initialEOF); BailError(err); /* * Step 1: figure out if we have anything to do. If the "copy" and "new" * lists are empty, then there's nothing for us to do. * * As a special case, we test for an archive that had all of its * records deleted. This looks a lot like an archive that has had * nothing done, because we would have made a "copy" list and then * deleted all the records, leaving us with an empty list. (The * difference is that an untouched archive wouldn't have a "copy" * list allocated.) * * In some cases, such as doing a bulk delete that doesn't end up * matching anything or an attempted UpdatePresizedThread on a thread * that isn't actually pre-sized, we create the "copy" list but don't * actually change anything. We deal with that by frying the "copy" * list if it doesn't have anything interesting in it (i.e. it's an * exact match of the "orig" list). */ Nu_ResetCopySetIfUntouched(pArchive); if (Nu_RecordSet_IsEmpty(&pArchive->copyRecordSet) && Nu_RecordSet_IsEmpty(&pArchive->newRecordSet)) { if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) { DBUG(("--- All records deleted!\n")); #if 0 /* * Options: * (1) allow it, leaving an archive with nothing but a header * that will probably be rejected by other NuFX applications * (2) reject it, returning an error * (3) allow it, and just delete the original archive * * I dislike #1, and #3 can be implemented by the application * when it gets a #2. */ err = kNuErrAllDeleted; goto bail; #else /* * (4) go ahead and delete everything, then mark the archive * as brand new, so that closing the archive with new * records in it will trigger deletion of the archive file. */ deleteAll = true; #endif } else { DBUG(("--- Nothing pending\n")); goto flushed; } } /* if we have any changes, we certainly should have the TOC by now */ Assert(pArchive->haveToc); Assert(Nu_RecordSet_GetLoaded(&pArchive->origRecordSet)); /* * Step 2: purge any records from the "copy" and "new" lists that don't * have any threads. You can't delete threads from the "new" list, but * it's possible somebody called NuAddRecord and never put anything in it. */ err = Nu_PurgeEmptyRecords(pArchive, &pArchive->copyRecordSet); BailError(err); err = Nu_PurgeEmptyRecords(pArchive, &pArchive->newRecordSet); BailError(err); /* we checked delete-all actions above, so just check for empty */ if (Nu_RecordSet_IsEmpty(&pArchive->copyRecordSet) && Nu_RecordSet_IsEmpty(&pArchive->newRecordSet) && !deleteAll) { DBUG(("--- Nothing pending after purge\n")); goto flushed; } /* * Step 3: if we're in ShrinkIt-compatibility mode, add a comment * thread to the first record in the new list. GSHK does this every * time it adds files, regardless of the prior contents of the archive. */ if (pArchive->valMimicSHK) { err = Nu_AddCommentToFirstNewRecord(pArchive); BailError(err); } /* * Step 4: decide if we want to make changes in place, or write to * a temp file. Any deletions or additions to existing records will * require writing to a temp file. Additions of new records and * updates to pre-sized threads can be done in place. */ writeToTemp = true; if (pArchive->valModifyOrig && Nu_NoHeavyUpdates(pArchive)) writeToTemp = false; /* discard the wrapper, if desired */ if (writeToTemp && pArchive->valDiscardWrapper) pArchive->headerOffset = 0; /* * Step 5: handle updates to existing records. */ if (!writeToTemp) { /* * Step 5a: modifying in place, process all UPDATE ThreadMods now. */ DBUG(("--- No heavy updates found, updating in place\n")); if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) canAbort = false; /* modifying original, can't cleanly abort */ err = Nu_UpdateInOriginal(pArchive); if (err == kNuErrDamaged) *pStatusFlags |= kNuFlushCorrupted; if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "update to original failed"); goto bail; } } else { /* * Step 5b: not modifying in place, reconstruct the appropriate * parts of the original archive in the temp file, possibly copying * the front bits over first. Updates and thread-adds will be * done here. */ DBUG(("--- Updating to temp file (valModifyOrig=%ld)\n", pArchive->valModifyOrig)); err = Nu_CreateTempFromOriginal(pArchive); if (err != kNuErrNone) { DBUG(("--- Create temp from original failed\n")); goto bail; } } /* on completion, tmpFp (or archiveFp) points to current archive EOF */ /* * Step 6: add the new records from the "new" list, if any. Add a * filename thread to records where one wasn't provided. These records * are either added to the original archive or the temp file as * appropriate. */ if (writeToTemp) err = Nu_CreateNewRecords(pArchive, pArchive->tmpFp); else err = Nu_CreateNewRecords(pArchive, pArchive->archiveFp); BailError(err); /* on completion, tmpFp (or archiveFp) points to current archive EOF */ /* * Step 7: truncate the archive. This isn't strictly necessary. It * comes in handy if we were compressing the very last file and it * actually expanded. We went back and wrote the uncompressed data, * but there's a bunch of junk after it from the first try. * * On systems like Win32 that don't support ftruncate, this will fail, * so we just ignore the result. */ if (writeToTemp) { err = Nu_FTell(pArchive->tmpFp, &finalOffset); BailError(err); (void) Nu_TruncateOpenFile(pArchive->tmpFp, finalOffset); } else { err = Nu_FTell(pArchive->archiveFp, &finalOffset); BailError(err); (void) Nu_TruncateOpenFile(pArchive->archiveFp, finalOffset); } /* * Step 8: create an updated master header, and write it to the * appropriate file. The "newMasterHeader" field in pArchive will * hold the new header. */ Assert(!pArchive->newMasterHeader.isValid); if (writeToTemp) { err = Nu_FSeek(pArchive->tmpFp, pArchive->headerOffset, SEEK_SET); BailError(err); err = Nu_UpdateMasterHeader(pArchive, pArchive->tmpFp, finalOffset - pArchive->headerOffset); /* fall through with err */ } else { err = Nu_FSeek(pArchive->archiveFp, pArchive->headerOffset, SEEK_SET); BailError(err); err = Nu_UpdateMasterHeader(pArchive, pArchive->archiveFp, finalOffset - pArchive->headerOffset); /* fall through with err */ } if (err == kNuErrNoRecords && !deleteAll) { /* * Somehow we ended up without any records at all. If we managed * to get this far, it could only be because the user told us to * skip adding everything. */ Nu_ReportError(NU_BLOB, kNuErrNone, "no records in this archive"); goto bail; } else if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "failed writing master header"); goto bail; } Assert(pArchive->newMasterHeader.isValid); /* * Step 9: carry forward the BXY, SEA, or BSE header, if necessary. This * implicitly assumes that the header doesn't change size. If this * assumption is invalid, we'd need to adjust "headerOffset" earlier, * or do lots of data copying. Looks like Binary II and SEA headers * are both fixed size, so we should be okay. * * We also carry forward any unrecognized junk. */ if (pArchive->headerOffset) { if (writeToTemp) { if (!pArchive->valDiscardWrapper) { DBUG(("--- Preserving wrapper\n")); /* copy header to temp */ err = Nu_CopyWrapperToTemp(pArchive); BailError(err); /* update fields that require it */ err = Nu_UpdateWrapper(pArchive, pArchive->tmpFp); BailError(err); /* check the padding */ err = Nu_AdjustWrapperPadding(pArchive, pArchive->tmpFp); BailError(err); } } else { /* may need to tweak what's in place? */ DBUG(("--- Updating wrapper\n")); err = Nu_UpdateWrapper(pArchive, pArchive->archiveFp); BailError(err); /* should only be necessary if we've added new records */ err = Nu_AdjustWrapperPadding(pArchive, pArchive->archiveFp); BailError(err); } } /* * Step 10: if necessary, remove the original file and rename the * temp file over it. * * I'm not messing with access permissions on the archive file here, * because if they opened it read-write then the archive itself * must also be read-write (unless somebody snuck in and chmodded it * while we were busy). The temp file is certainly writable, so we * should be able to just leave it all alone. * * I'm closing both temp and archive before renaming, because on some * operating systems you can't do certain things with open files. */ if (writeToTemp) { canAbort = false; /* no going back */ *pStatusFlags |= kNuFlushSucceeded; /* temp file is fully valid */ fclose(pArchive->archiveFp); pArchive->archiveFp = NULL; err = Nu_DeleteArchiveFile(pArchive); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "unable to remove original archive"); Nu_ReportError(NU_BLOB, kNuErrNone, "New data is in '%s'", pArchive->tmpPathnameUNI); *pStatusFlags |= kNuFlushInaccessible; goto bail_reopen; /* must re-open archiveFp */ } fclose(pArchive->tmpFp); pArchive->tmpFp = NULL; err = Nu_RenameTempToArchive(pArchive); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "unable to rename temp file"); Nu_ReportError(NU_BLOB, kNuErrNone, "NOTE: only copy of archive is in '%s'", pArchive->tmpPathnameUNI); /* maintain Entry.c semantics (and keep them from removing temp) */ Nu_Free(pArchive, pArchive->archivePathnameUNI); pArchive->archivePathnameUNI = NULL; Nu_Free(pArchive, pArchive->tmpPathnameUNI); pArchive->tmpPathnameUNI = NULL; /* bail will put us into read-only mode, which is what we want */ goto bail; } bail_reopen: pArchive->archiveFp = fopen(pArchive->archivePathnameUNI, kNuFileOpenReadWrite); if (pArchive->archiveFp == NULL) { err = errno ? errno : -1; Nu_ReportError(NU_BLOB, err, "unable to reopen archive file '%s' after rename", pArchive->archivePathnameUNI); *pStatusFlags |= kNuFlushInaccessible; goto bail; /* the Entry.c funcs will obstruct further use */ } if (err != kNuErrNone) // earlier failure? goto bail; } else { fflush(pArchive->archiveFp); if (ferror(pArchive->archiveFp)) { err = kNuErrFileWrite; Nu_ReportError(NU_BLOB, kNuErrNone, "final archive flush failed"); *pStatusFlags |= kNuFlushCorrupted; goto bail; } canAbort = false; *pStatusFlags |= kNuFlushSucceeded; } Assert(canAbort == false); /* * Step 11: clean up data structures. If we have a "copy" list, then * throw out the "orig" list and move the "copy" list over it. Append * anything in the "new" list to it. Move the "new" master header * over the original. */ Assert(pArchive->newMasterHeader.isValid); Nu_MasterHeaderCopy(pArchive, &pArchive->masterHeader, &pArchive->newMasterHeader); if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) { err = Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->origRecordSet); BailError(err); err = Nu_RecordSet_MoveAllRecords(pArchive, &pArchive->origRecordSet, &pArchive->copyRecordSet); BailError(err); } err = Nu_RecordSet_MoveAllRecords(pArchive, &pArchive->origRecordSet, &pArchive->newRecordSet); BailError(err); err = Nu_ResetUsedFlags(pArchive, &pArchive->origRecordSet); BailError(err); flushed: /* * Step 12: reset the "copy" and "new" lists, and reset the temp file. * Clear out the "new" master header copy. */ err = Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->copyRecordSet); BailError(err); err = Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->newRecordSet); BailError(err); pArchive->newMasterHeader.isValid = false; err = Nu_ResetTempFile(pArchive); if (err != kNuErrNone) { /* can't NuAbort() our way out of a bad temp file */ canAbort = false; goto bail; } if (deleteAll) { /* there's nothing in it, so treat it like a newly-created archive */ /* (that way it gets deleted if the app closes without adding stuff) */ DBUG(("--- marking archive as newly created\n")); pArchive->newlyCreated = true; /*pArchive->valModifyOrig = true;*/ } bail: if (err != kNuErrNone) { if (canAbort) { (void) Nu_Abort(pArchive); Assert(!(*pStatusFlags & kNuFlushSucceeded)); *pStatusFlags |= kNuFlushAborted; /* * If we were adding to original archive, truncate it back if * we are able to do so. This retains any BXY/BSE wrapper padding. */ if (!writeToTemp) { NuError err2; err2 = Nu_TruncateOpenFile(pArchive->archiveFp, initialEOF); if (err2 == kNuErrNone) { DBUG(("+++ truncated orig archive back to %ld\n", initialEOF)); } else { DBUG(("+++ truncate orig failed (err=%d)\n", err2)); } } } else { Nu_ReportError(NU_BLOB, kNuErrNone, "disabling write access after failed update"); pArchive->openMode = kNuOpenRO; *pStatusFlags |= kNuFlushReadOnly; } } /* last-minute sanity check */ Assert(pArchive->origRecordSet.numRecords == 0 || (pArchive->origRecordSet.nuRecordHead != NULL && pArchive->origRecordSet.nuRecordTail != NULL)); return err; } /* * Abort any pending changes. */ NuError Nu_Abort(NuArchive* pArchive) { Assert(pArchive != NULL); if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; DBUG(("--- Aborting changes\n")); /* * Throw out the "copy" and "new" record sets, and reset the * temp file. */ (void) Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->copyRecordSet); (void) Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->newRecordSet); pArchive->newMasterHeader.isValid = false; return Nu_ResetTempFile(pArchive); } nulib2-3.1.0/nufxlib/Deflate.c000066400000000000000000000207721316100516500160730ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Support for the "deflate" algorithm, via the "zlib" library. * * This compression format is totally unsupported on the Apple II. This * is provided primarily for the benefit of Apple II emulators that want * a better storage format for disk images than SHK+LZW or a ZIP file. * * This code was developed and tested with ZLIB_VERSION "1.1.3". It is * expected to work with any version >= 1.1.3 and < 2.x. Please visit * http://www.zlib.org/ for more information. */ #include "NufxLibPriv.h" #ifdef ENABLE_DEFLATE #include "zlib.h" #define kNuDeflateLevel 9 /* use maximum compression */ /* * Alloc and free functions provided to zlib. */ static voidpf Nu_zalloc(voidpf opaque, uInt items, uInt size) { return Nu_Malloc(opaque, items * size); } static void Nu_zfree(voidpf opaque, voidpf address) { Nu_Free(opaque, address); } /* * =========================================================================== * Compression * =========================================================================== */ /* * Compress "srcLen" bytes from "pStraw" to "fp". */ NuError Nu_CompressDeflate(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc) { NuError err = kNuErrNone; z_stream zstream; int zerr; Bytef* outbuf = NULL; Assert(pArchive != NULL); Assert(pStraw != NULL); Assert(fp != NULL); Assert(srcLen > 0); Assert(pDstLen != NULL); Assert(pCrc != NULL); err = Nu_AllocCompressionBufferIFN(pArchive); if (err != kNuErrNone) return err; /* allocate a similarly-sized buffer for the output */ outbuf = Nu_Malloc(pArchive, kNuGenCompBufSize); BailAlloc(outbuf); /* * Initialize the zlib stream. */ zstream.zalloc = Nu_zalloc; zstream.zfree = Nu_zfree; zstream.opaque = pArchive; zstream.next_in = NULL; zstream.avail_in = 0; zstream.next_out = outbuf; zstream.avail_out = kNuGenCompBufSize; zstream.data_type = Z_UNKNOWN; zerr = deflateInit(&zstream, kNuDeflateLevel); if (zerr != Z_OK) { err = kNuErrInternal; if (zerr == Z_VERSION_ERROR) { Nu_ReportError(NU_BLOB, err, "installed zlib is not compatible with linked version (%s)", ZLIB_VERSION); } else { Nu_ReportError(NU_BLOB, err, "call to deflateInit failed (zerr=%d)", zerr); } goto bail; } /* * Loop while we have data. */ do { uint32_t getSize; int flush; /* should be able to read a full buffer every time */ if (zstream.avail_in == 0 && srcLen) { getSize = (srcLen > kNuGenCompBufSize) ? kNuGenCompBufSize : srcLen; DBUG(("+++ reading %ld bytes\n", getSize)); err = Nu_StrawRead(pArchive, pStraw, pArchive->compBuf, getSize); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "deflate read failed"); goto z_bail; } srcLen -= getSize; *pCrc = Nu_CalcCRC16(*pCrc, pArchive->compBuf, getSize); zstream.next_in = pArchive->compBuf; zstream.avail_in = getSize; } if (srcLen == 0) flush = Z_FINISH; /* tell zlib that we're done */ else flush = Z_NO_FLUSH; /* more to come! */ zerr = deflate(&zstream, flush); if (zerr != Z_OK && zerr != Z_STREAM_END) { err = kNuErrInternal; Nu_ReportError(NU_BLOB, err, "zlib deflate call failed (zerr=%d)", zerr); goto z_bail; } /* write when we're full or when we're done */ if (zstream.avail_out == 0 || (zerr == Z_STREAM_END && zstream.avail_out != kNuGenCompBufSize)) { DBUG(("+++ writing %d bytes\n", zstream.next_out - outbuf)); err = Nu_FWrite(fp, outbuf, zstream.next_out - outbuf); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "fwrite failed in deflate"); goto z_bail; } zstream.next_out = outbuf; zstream.avail_out = kNuGenCompBufSize; } } while (zerr == Z_OK); Assert(zerr == Z_STREAM_END); /* other errors should've been caught */ *pDstLen = zstream.total_out; z_bail: deflateEnd(&zstream); /* free up any allocated structures */ bail: if (outbuf != NULL) free(outbuf); return err; } /* * =========================================================================== * Expansion * =========================================================================== */ /* * Expand from "infp" to "pFunnel". */ NuError Nu_ExpandDeflate(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc) { NuError err = kNuErrNone; z_stream zstream; int zerr; uint32_t compRemaining; Bytef* outbuf; Assert(pArchive != NULL); Assert(pThread != NULL); Assert(infp != NULL); Assert(pFunnel != NULL); err = Nu_AllocCompressionBufferIFN(pArchive); if (err != kNuErrNone) return err; /* allocate a similarly-sized buffer for the output */ outbuf = Nu_Malloc(pArchive, kNuGenCompBufSize); BailAlloc(outbuf); compRemaining = pThread->thCompThreadEOF; /* * Initialize the zlib stream. */ zstream.zalloc = Nu_zalloc; zstream.zfree = Nu_zfree; zstream.opaque = pArchive; zstream.next_in = NULL; zstream.avail_in = 0; zstream.next_out = outbuf; zstream.avail_out = kNuGenCompBufSize; zstream.data_type = Z_UNKNOWN; zerr = inflateInit(&zstream); if (zerr != Z_OK) { err = kNuErrInternal; if (zerr == Z_VERSION_ERROR) { Nu_ReportError(NU_BLOB, err, "installed zlib is not compatible with linked version (%s)", ZLIB_VERSION); } else { Nu_ReportError(NU_BLOB, err, "call to inflateInit failed (zerr=%d)", zerr); } goto bail; } /* * Loop while we have data. */ do { uint32_t getSize; /* read as much as we can */ if (zstream.avail_in == 0) { getSize = (compRemaining > kNuGenCompBufSize) ? kNuGenCompBufSize : compRemaining; DBUG(("+++ reading %ld bytes (%ld left)\n", getSize, compRemaining)); err = Nu_FRead(infp, pArchive->compBuf, getSize); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "inflate read failed"); goto z_bail; } compRemaining -= getSize; zstream.next_in = pArchive->compBuf; zstream.avail_in = getSize; } /* uncompress the data */ zerr = inflate(&zstream, Z_NO_FLUSH); if (zerr != Z_OK && zerr != Z_STREAM_END) { err = kNuErrInternal; Nu_ReportError(NU_BLOB, err, "zlib inflate call failed (zerr=%d)", zerr); goto z_bail; } /* write every time there's anything (buffer will usually be full) */ if (zstream.avail_out != kNuGenCompBufSize) { DBUG(("+++ writing %d bytes\n", zstream.next_out - outbuf)); err = Nu_FunnelWrite(pArchive, pFunnel, outbuf, zstream.next_out - outbuf); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "write failed in inflate"); goto z_bail; } if (pCrc != NULL) *pCrc = Nu_CalcCRC16(*pCrc, outbuf, zstream.next_out - outbuf); zstream.next_out = outbuf; zstream.avail_out = kNuGenCompBufSize; } } while (zerr == Z_OK); Assert(zerr == Z_STREAM_END); /* other errors should've been caught */ if (zstream.total_out != pThread->actualThreadEOF) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "size mismatch on inflated file (%ld vs %u)", zstream.total_out, pThread->actualThreadEOF); goto z_bail; } z_bail: inflateEnd(&zstream); /* free up any allocated structures */ bail: if (outbuf != NULL) free(outbuf); return err; } #endif /*ENABLE_DEFLATE*/ nulib2-3.1.0/nufxlib/Entry.c000066400000000000000000000517271316100516500156340ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * All external entry points. */ #include "NufxLibPriv.h" /* * =========================================================================== * Misc utils * =========================================================================== */ /* * Set the busy flag. * * The busy flag is intended to prevent the caller from executing illegal * operations while inside a callback function. It is NOT intended to * allow concurrent access to the same archive from multiple threads, so * it does not follow all sorts of crazy semaphore semantics. If you * have the need, go ahead and fix it. */ static inline void Nu_SetBusy(NuArchive* pArchive) { pArchive->busy = true; } /* * Clear the busy flag. */ static inline void Nu_ClearBusy(NuArchive* pArchive) { pArchive->busy = false; } /* * Do a partial validation on NuArchive. Some calls, such as GetExtraData, * can be made during callback functions when the archive isn't fully * consistent. */ static NuError Nu_PartiallyValidateNuArchive(const NuArchive* pArchive) { if (pArchive == NULL) return kNuErrInvalidArg; if (pArchive->structMagic != kNuArchiveStructMagic) return kNuErrBadStruct; return kNuErrNone; } /* * Validate the NuArchive* argument passed in to us. */ static NuError Nu_ValidateNuArchive(const NuArchive* pArchive) { NuError err; err = Nu_PartiallyValidateNuArchive(pArchive); if (err != kNuErrNone) return err; /* explicitly block reentrant calls */ if (pArchive->busy) return kNuErrBusy; /* make sure the TOC state is consistent */ if (pArchive->haveToc) { if (pArchive->masterHeader.mhTotalRecords != 0) Assert(Nu_RecordSet_GetListHead(&pArchive->origRecordSet) != NULL); Assert(Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet) == pArchive->masterHeader.mhTotalRecords); } else { Assert(Nu_RecordSet_GetListHead(&pArchive->origRecordSet) == NULL); } /* make sure we have open files to work with */ Assert(pArchive->archivePathnameUNI == NULL || pArchive->archiveFp != NULL); if (pArchive->archivePathnameUNI != NULL && pArchive->archiveFp == NULL) return kNuErrInternal; Assert(pArchive->tmpPathnameUNI == NULL || pArchive->tmpFp != NULL); if (pArchive->tmpPathnameUNI != NULL && pArchive->tmpFp == NULL) return kNuErrInternal; /* further validations */ return kNuErrNone; } /* * =========================================================================== * Streaming and non-streaming read-only * =========================================================================== */ NUFXLIB_API NuError NuStreamOpenRO(FILE* infp, NuArchive** ppArchive) { NuError err; if (infp == NULL || ppArchive == NULL) return kNuErrInvalidArg; err = Nu_StreamOpenRO(infp, (NuArchive**) ppArchive); return err; } NUFXLIB_API NuError NuContents(NuArchive* pArchive, NuCallback contentFunc) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); if (Nu_IsStreaming(pArchive)) err = Nu_StreamContents(pArchive, contentFunc); else err = Nu_Contents(pArchive, contentFunc); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuExtract(NuArchive* pArchive) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); if (Nu_IsStreaming(pArchive)) err = Nu_StreamExtract(pArchive); else err = Nu_Extract(pArchive); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuTest(NuArchive* pArchive) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); if (Nu_IsStreaming(pArchive)) err = Nu_StreamTest(pArchive); else err = Nu_Test(pArchive); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuTestRecord(NuArchive* pArchive, NuRecordIdx recordIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_TestRecord(pArchive, recordIdx); Nu_ClearBusy(pArchive); } return err; } /* * =========================================================================== * Strictly non-streaming read-only * =========================================================================== */ NUFXLIB_API NuError NuOpenRO(const UNICHAR* archivePathnameUNI, NuArchive** ppArchive) { NuError err; err = Nu_OpenRO(archivePathnameUNI, (NuArchive**) ppArchive); return err; } NUFXLIB_API NuError NuExtractRecord(NuArchive* pArchive, NuRecordIdx recordIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_ExtractRecord(pArchive, recordIdx); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuExtractThread(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSink* pDataSink) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_ExtractThread(pArchive, threadIdx, pDataSink); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuGetRecord(NuArchive* pArchive, NuRecordIdx recordIdx, const NuRecord** ppRecord) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_GetRecord(pArchive, recordIdx, ppRecord); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuGetRecordIdxByName(NuArchive* pArchive, const char* nameMOR, NuRecordIdx* pRecordIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_GetRecordIdxByName(pArchive, nameMOR, pRecordIdx); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuGetRecordIdxByPosition(NuArchive* pArchive, uint32_t position, NuRecordIdx* pRecordIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_GetRecordIdxByPosition(pArchive, position, pRecordIdx); Nu_ClearBusy(pArchive); } return err; } /* * =========================================================================== * Read/Write * =========================================================================== */ NUFXLIB_API NuError NuOpenRW(const UNICHAR* archivePathnameUNI, const UNICHAR* tmpPathnameUNI, uint32_t flags, NuArchive** ppArchive) { NuError err; err = Nu_OpenRW(archivePathnameUNI, tmpPathnameUNI, flags, (NuArchive**) ppArchive); return err; } NUFXLIB_API NuError NuFlush(NuArchive* pArchive, uint32_t* pStatusFlags) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_Flush(pArchive, pStatusFlags); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuAbort(NuArchive* pArchive) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_Abort(pArchive); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuAddRecord(NuArchive* pArchive, const NuFileDetails* pFileDetails, NuRecordIdx* pRecordIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_AddRecord(pArchive, pFileDetails, pRecordIdx, NULL); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuAddThread(NuArchive* pArchive, NuRecordIdx recordIdx, NuThreadID threadID, NuDataSource* pDataSource, NuThreadIdx* pThreadIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_AddThread(pArchive, recordIdx, threadID, pDataSource, pThreadIdx); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuAddFile(NuArchive* pArchive, const UNICHAR* pathnameUNI, const NuFileDetails* pFileDetails, short isFromRsrcFork, NuRecordIdx* pRecordIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_AddFile(pArchive, pathnameUNI, pFileDetails, (Boolean)(isFromRsrcFork != 0), pRecordIdx); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuRename(NuArchive* pArchive, NuRecordIdx recordIdx, const char* pathnameMOR, char fssep) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_Rename(pArchive, recordIdx, pathnameMOR, fssep); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuSetRecordAttr(NuArchive* pArchive, NuRecordIdx recordIdx, const NuRecordAttr* pRecordAttr) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_SetRecordAttr(pArchive, recordIdx, pRecordAttr); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuUpdatePresizedThread(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSource* pDataSource, int32_t* pMaxLen) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_UpdatePresizedThread(pArchive, threadIdx, pDataSource, pMaxLen); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuDelete(NuArchive* pArchive) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_Delete(pArchive); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuDeleteRecord(NuArchive* pArchive, NuRecordIdx recordIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_DeleteRecord(pArchive, recordIdx); Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuDeleteThread(NuArchive* pArchive, NuThreadIdx threadIdx) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_DeleteThread(pArchive, threadIdx); Nu_ClearBusy(pArchive); } return err; } /* * =========================================================================== * General interfaces * =========================================================================== */ NUFXLIB_API NuError NuClose(NuArchive* pArchive) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { Nu_SetBusy(pArchive); err = Nu_Close(pArchive); /* on success, pArchive has been freed */ if (err != kNuErrNone) Nu_ClearBusy(pArchive); } return err; } NUFXLIB_API NuError NuGetMasterHeader(NuArchive* pArchive, const NuMasterHeader** ppMasterHeader) { NuError err; if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) err = Nu_GetMasterHeader(pArchive, ppMasterHeader); return err; } NUFXLIB_API NuError NuGetExtraData(NuArchive* pArchive, void** ppData) { NuError err; if (ppData == NULL) return kNuErrInvalidArg; if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone) *ppData = pArchive->extraData; return err; } NUFXLIB_API NuError NuSetExtraData(NuArchive* pArchive, void* pData) { NuError err; if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone) pArchive->extraData = pData; return err; } NUFXLIB_API NuError NuGetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue) { NuError err; if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone) return Nu_GetValue(pArchive, ident, pValue); return err; } NUFXLIB_API NuError NuSetValue(NuArchive* pArchive, NuValueID ident, NuValue value) { NuError err; if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone) return Nu_SetValue(pArchive, ident, value); return err; } NUFXLIB_API NuError NuGetAttr(NuArchive* pArchive, NuAttrID ident, NuAttr* pAttr) { NuError err; if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone) return Nu_GetAttr(pArchive, ident, pAttr); return err; } NUFXLIB_API NuError NuDebugDumpArchive(NuArchive* pArchive) { #if defined(DEBUG_MSGS) /* skip validation checks for this one */ Nu_DebugDumpAll(pArchive); return kNuErrNone; #else /* function doesn't exist */ return kNuErrGeneric; #endif } /* * =========================================================================== * Sources and Sinks * =========================================================================== */ NUFXLIB_API NuError NuCreateDataSourceForFile(NuThreadFormat threadFormat, uint32_t otherLen, const UNICHAR* pathnameUNI, short isFromRsrcFork, NuDataSource** ppDataSource) { return Nu_DataSourceFile_New(threadFormat, otherLen, pathnameUNI, (Boolean)(isFromRsrcFork != 0), ppDataSource); } NUFXLIB_API NuError NuCreateDataSourceForFP(NuThreadFormat threadFormat, uint32_t otherLen, FILE* fp, long offset, long length, NuCallback fcloseFunc, NuDataSource** ppDataSource) { return Nu_DataSourceFP_New(threadFormat, otherLen, fp, offset, length, fcloseFunc, ppDataSource); } NUFXLIB_API NuError NuCreateDataSourceForBuffer(NuThreadFormat threadFormat, uint32_t otherLen, const uint8_t* buffer, long offset, long length, NuCallback freeFunc, NuDataSource** ppDataSource) { return Nu_DataSourceBuffer_New(threadFormat, otherLen, buffer, offset, length, freeFunc, ppDataSource); } NUFXLIB_API NuError NuFreeDataSource(NuDataSource* pDataSource) { return Nu_DataSourceFree(pDataSource); } NUFXLIB_API NuError NuDataSourceSetRawCrc(NuDataSource* pDataSource, uint16_t crc) { if (pDataSource == NULL) return kNuErrInvalidArg; Nu_DataSourceSetRawCrc(pDataSource, crc); return kNuErrNone; } NUFXLIB_API NuError NuCreateDataSinkForFile(short doExpand, NuValue convertEOL, const UNICHAR* pathnameUNI, UNICHAR fssep, NuDataSink** ppDataSink) { return Nu_DataSinkFile_New((Boolean)(doExpand != 0), convertEOL, pathnameUNI, fssep, ppDataSink); } NUFXLIB_API NuError NuCreateDataSinkForFP(short doExpand, NuValue convertEOL, FILE* fp, NuDataSink** ppDataSink) { return Nu_DataSinkFP_New((Boolean)(doExpand != 0), convertEOL, fp, ppDataSink); } NUFXLIB_API NuError NuCreateDataSinkForBuffer(short doExpand, NuValue convertEOL, uint8_t* buffer, uint32_t bufLen, NuDataSink** ppDataSink) { return Nu_DataSinkBuffer_New((Boolean)(doExpand != 0), convertEOL, buffer, bufLen, ppDataSink); } NUFXLIB_API NuError NuFreeDataSink(NuDataSink* pDataSink) { return Nu_DataSinkFree(pDataSink); } NUFXLIB_API NuError NuDataSinkGetOutCount(NuDataSink* pDataSink, uint32_t* pOutCount) { if (pDataSink == NULL || pOutCount == NULL) return kNuErrInvalidArg; *pOutCount = Nu_DataSinkGetOutCount(pDataSink); return kNuErrNone; } /* * =========================================================================== * Non-archive operations * =========================================================================== */ NUFXLIB_API const char* NuStrError(NuError err) { return Nu_StrError(err); } NUFXLIB_API NuError NuGetVersion(int32_t* pMajorVersion, int32_t* pMinorVersion, int32_t* pBugVersion, const char** ppBuildDate, const char** ppBuildFlags) { return Nu_GetVersion(pMajorVersion, pMinorVersion, pBugVersion, ppBuildDate, ppBuildFlags); } NUFXLIB_API NuError NuTestFeature(NuFeature feature) { NuError err = kNuErrUnsupFeature; switch (feature) { case kNuFeatureCompressSQ: #ifdef ENABLE_SQ err = kNuErrNone; #endif break; case kNuFeatureCompressLZW: #ifdef ENABLE_LZW err = kNuErrNone; #endif break; case kNuFeatureCompressLZC: #ifdef ENABLE_LZC err = kNuErrNone; #endif break; case kNuFeatureCompressDeflate: #ifdef ENABLE_DEFLATE err = kNuErrNone; #endif break; case kNuFeatureCompressBzip2: #ifdef ENABLE_BZIP2 err = kNuErrNone; #endif break; default: err = kNuErrUnknownFeature; break; } return err; } NUFXLIB_API void NuRecordCopyAttr(NuRecordAttr* pRecordAttr, const NuRecord* pRecord) { pRecordAttr->fileSysID = pRecord->recFileSysID; /*pRecordAttr->fileSysInfo = pRecord->recFileSysInfo;*/ pRecordAttr->access = pRecord->recAccess; pRecordAttr->fileType = pRecord->recFileType; pRecordAttr->extraType = pRecord->recExtraType; pRecordAttr->createWhen = pRecord->recCreateWhen; pRecordAttr->modWhen = pRecord->recModWhen; pRecordAttr->archiveWhen = pRecord->recArchiveWhen; } NUFXLIB_API NuError NuRecordCopyThreads(const NuRecord* pNuRecord, NuThread** ppThreads) { if (pNuRecord == NULL || ppThreads == NULL) return kNuErrInvalidArg; Assert(pNuRecord->pThreads != NULL); *ppThreads = Nu_Malloc(NULL, pNuRecord->recTotalThreads * sizeof(NuThread)); if (*ppThreads == NULL) return kNuErrMalloc; memcpy(*ppThreads, pNuRecord->pThreads, pNuRecord->recTotalThreads * sizeof(NuThread)); return kNuErrNone; } NUFXLIB_API uint32_t NuRecordGetNumThreads(const NuRecord* pNuRecord) { if (pNuRecord == NULL) return -1; return pNuRecord->recTotalThreads; } NUFXLIB_API const NuThread* NuThreadGetByIdx(const NuThread* pNuThread, int32_t idx) { if (pNuThread == NULL) return NULL; return &pNuThread[idx]; /* can't range-check here */ } NUFXLIB_API short NuIsPresizedThreadID(NuThreadID threadID) { return Nu_IsPresizedThreadID(threadID); } NUFXLIB_API size_t NuConvertMORToUNI(const char* stringMOR, UNICHAR* bufUNI, size_t bufSize) { return Nu_ConvertMORToUNI(stringMOR, bufUNI, bufSize); } NUFXLIB_API size_t NuConvertUNIToMOR(const UNICHAR* stringUNI, char* bufMOR, size_t bufSize) { return Nu_ConvertUNIToMOR(stringUNI, bufMOR, bufSize); } /* * =========================================================================== * Callback setters * =========================================================================== */ NUFXLIB_API NuCallback NuSetSelectionFilter(NuArchive* pArchive, NuCallback filterFunc) { NuError err; NuCallback oldFunc = kNuInvalidCallback; /*Assert(!((uint32_t)filterFunc % 4));*/ if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { oldFunc = pArchive->selectionFilterFunc; pArchive->selectionFilterFunc = filterFunc; } return oldFunc; } NUFXLIB_API NuCallback NuSetOutputPathnameFilter(NuArchive* pArchive, NuCallback filterFunc) { NuError err; NuCallback oldFunc = kNuInvalidCallback; /*Assert(!((uint32_t)filterFunc % 4));*/ if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { oldFunc = pArchive->outputPathnameFunc; pArchive->outputPathnameFunc = filterFunc; } return oldFunc; } NUFXLIB_API NuCallback NuSetProgressUpdater(NuArchive* pArchive, NuCallback updateFunc) { NuError err; NuCallback oldFunc = kNuInvalidCallback; /*Assert(!((uint32_t)updateFunc % 4));*/ if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { oldFunc = pArchive->progressUpdaterFunc; pArchive->progressUpdaterFunc = updateFunc; } return oldFunc; } NUFXLIB_API NuCallback NuSetErrorHandler(NuArchive* pArchive, NuCallback errorFunc) { NuError err; NuCallback oldFunc = kNuInvalidCallback; /*Assert(!((uint32_t)errorFunc % 4));*/ if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { oldFunc = pArchive->errorHandlerFunc; pArchive->errorHandlerFunc = errorFunc; } return oldFunc; } NUFXLIB_API NuCallback NuSetErrorMessageHandler(NuArchive* pArchive, NuCallback messageHandlerFunc) { NuError err; NuCallback oldFunc = kNuInvalidCallback; /*Assert(!((uint32_t)messageHandlerFunc % 4));*/ if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) { oldFunc = pArchive->messageHandlerFunc; pArchive->messageHandlerFunc = messageHandlerFunc; } return oldFunc; } NUFXLIB_API NuCallback NuSetGlobalErrorMessageHandler(NuCallback messageHandlerFunc) { NuCallback oldFunc = kNuInvalidCallback; /*Assert(!((uint32_t)messageHandlerFunc % 4));*/ oldFunc = gNuGlobalErrorMessageHandler; gNuGlobalErrorMessageHandler = messageHandlerFunc; return oldFunc; } nulib2-3.1.0/nufxlib/Expand.c000066400000000000000000000154071316100516500157450ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Expand a thread from an archive. */ #include "NufxLibPriv.h" /* * "Expand" an uncompressed thread. */ static NuError Nu_ExpandUncompressed(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc) { NuError err; /*uint8_t* buffer = NULL;*/ uint32_t count, getsize; Assert(pArchive != NULL); Assert(pThread != NULL); Assert(infp != NULL); Assert(pFunnel != NULL); /* doesn't have to be same size as funnel, but it's not a bad idea */ /*buffer = Nu_Malloc(pArchive, kNuFunnelBufSize);*/ /*BailAlloc(buffer);*/ err = Nu_AllocCompressionBufferIFN(pArchive); BailError(err); /* quick assert for bad archive that should have been caught earlier */ /* (filename threads are uncompressed, but compThreadEOF is buf len) */ if (pThread->thThreadClass == kNuThreadClassData) Assert(pThread->actualThreadEOF == pThread->thCompThreadEOF); count = pThread->actualThreadEOF; while (count) { getsize = (count > kNuGenCompBufSize) ? kNuGenCompBufSize : count; err = Nu_FRead(infp, pArchive->compBuf, getsize); BailError(err); if (pCrc != NULL) *pCrc = Nu_CalcCRC16(*pCrc, pArchive->compBuf, getsize); err = Nu_FunnelWrite(pArchive, pFunnel, pArchive->compBuf, getsize); BailError(err); count -= getsize; } err = Nu_FunnelFlush(pArchive, pFunnel); BailError(err); bail: /*Nu_Free(pArchive, buffer);*/ return err; } /* * Copy the "raw" data out of the thread. Unlike the preceeding function, * this reads up to "thCompThreadEOF", and doesn't even try to compute a CRC. */ static NuError Nu_ExpandRaw(NuArchive* pArchive, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel) { NuError err; /*uint8_t* buffer = NULL;*/ uint32_t count, getsize; Assert(pArchive != NULL); Assert(pThread != NULL); Assert(infp != NULL); Assert(pFunnel != NULL); /* doesn't have to be same size as funnel, but it's not a bad idea */ /*buffer = Nu_Malloc(pArchive, kNuFunnelBufSize);*/ /*BailAlloc(buffer);*/ err = Nu_AllocCompressionBufferIFN(pArchive); BailError(err); count = pThread->thCompThreadEOF; while (count) { getsize = (count > kNuGenCompBufSize) ? kNuGenCompBufSize : count; err = Nu_FRead(infp, pArchive->compBuf, getsize); BailError(err); err = Nu_FunnelWrite(pArchive, pFunnel, pArchive->compBuf, getsize); BailError(err); count -= getsize; } err = Nu_FunnelFlush(pArchive, pFunnel); BailError(err); bail: /*Nu_Free(pArchive, buffer);*/ return err; } /* * Expand a thread from "infp" to "pFunnel", using the compression * and stream length specified by "pThread". */ NuError Nu_ExpandStream(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel) { NuError err = kNuErrNone; uint16_t calcCrc; uint16_t* pCalcCrc; if (!pThread->thThreadEOF && !pThread->thCompThreadEOF) { /* somebody stored an empty file! */ goto done; } /* * A brief history of the "threadCRC" field in the thread header: * record versions 0 and 1 didn't use the threadCRC field * record version 2 put the CRC of the compressed data in threadCRC * record version 3 put the CRC of the uncompressed data in threadCRC * * P8 ShrinkIt uses v1, GSHK uses v3. If something ever shipped with * v2, it didn't last long enough to leave an impression, so I'm not * going to support it. BTW, P8 ShrinkIt always uses LZW/1, which * puts a CRC in the compressed stream. Your uncompressed data is, * unfortunately, unprotected before v3. */ calcCrc = kNuInitialThreadCRC; pCalcCrc = NULL; if (Nu_ThreadHasCRC(pRecord->recVersionNumber, NuGetThreadID(pThread)) && !pArchive->valIgnoreCRC) { pCalcCrc = &calcCrc; } err = Nu_ProgressDataExpandPrep(pArchive, pFunnel, pThread); BailError(err); /* * If we're not expanding the data, use a simple copier. */ if (!Nu_FunnelGetDoExpand(pFunnel)) { Nu_FunnelSetProgressState(pFunnel, kNuProgressCopying); err = Nu_ExpandRaw(pArchive, pThread, infp, pFunnel); BailError(err); goto done; } Nu_FunnelSetProgressState(pFunnel, kNuProgressExpanding); switch (pThread->thThreadFormat) { case kNuThreadFormatUncompressed: Nu_FunnelSetProgressState(pFunnel, kNuProgressCopying); err = Nu_ExpandUncompressed(pArchive, pRecord, pThread, infp, pFunnel, pCalcCrc); break; #ifdef ENABLE_SQ case kNuThreadFormatHuffmanSQ: err = Nu_ExpandHuffmanSQ(pArchive, pRecord, pThread, infp, pFunnel, pCalcCrc); break; #endif #ifdef ENABLE_LZW case kNuThreadFormatLZW1: case kNuThreadFormatLZW2: err = Nu_ExpandLZW(pArchive, pRecord, pThread, infp, pFunnel, pCalcCrc); break; #endif #ifdef ENABLE_LZC case kNuThreadFormatLZC12: case kNuThreadFormatLZC16: err = Nu_ExpandLZC(pArchive, pRecord, pThread, infp, pFunnel, pCalcCrc); break; #endif #ifdef ENABLE_DEFLATE case kNuThreadFormatDeflate: err = Nu_ExpandDeflate(pArchive, pRecord, pThread, infp, pFunnel, pCalcCrc); break; #endif #ifdef ENABLE_BZIP2 case kNuThreadFormatBzip2: err = Nu_ExpandBzip2(pArchive, pRecord, pThread, infp, pFunnel, pCalcCrc); break; #endif default: err = kNuErrBadFormat; Nu_ReportError(NU_BLOB, err, "compression format %u not supported", pThread->thThreadFormat); break; } BailError(err); err = Nu_FunnelFlush(pArchive, pFunnel); BailError(err); /* * If we have a CRC to check, check it. */ if (pCalcCrc != NULL) { if (calcCrc != pThread->thThreadCRC) { if (!Nu_ShouldIgnoreBadCRC(pArchive, pRecord, kNuErrBadThreadCRC)) { err = kNuErrBadDataCRC; Nu_ReportError(NU_BLOB, err, "expected 0x%04x, got 0x%04x", pThread->thThreadCRC, calcCrc); goto bail; } } else { DBUG(("--- thread CRCs match\n")); } } done: /* make sure we send a final "success" progress message at 100% */ (void) Nu_FunnelSetProgressState(pFunnel, kNuProgressDone); err = Nu_FunnelSendProgressUpdate(pArchive, pFunnel); BailError(err); bail: return err; } nulib2-3.1.0/nufxlib/FileIO.c000066400000000000000000001260361316100516500156360ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Operations on output (i.e. non-archive) files, largely system-specific. * Portions taken from NuLib, including some code that Devin Reade worked on. * * It could be argued that "create file" should be a callback function, * since it is so heavily system-specific, and most of the other * system dependencies are handled by the application rather than the * NuFX library. It would also provide a cleaner solution for renaming * extracted files. However, the goal of the library is to do the work * for the application, not the other way around; and while it might be * nice to offload all direct file handling on the application, it * complicates rather than simplifies the interface. */ #include "NufxLibPriv.h" #ifdef MAC_LIKE # include #endif /* * For systems (e.g. Visual C++ 6.0) that don't have these standard values. */ #ifndef S_IRUSR # define S_IRUSR 0400 # define S_IWUSR 0200 # define S_IXUSR 0100 # define S_IRWXU (S_IRUSR|S_IWUSR|S_IXUSR) # define S_IRGRP (S_IRUSR >> 3) # define S_IWGRP (S_IWUSR >> 3) # define S_IXGRP (S_IXUSR >> 3) # define S_IRWXG (S_IRWXU >> 3) # define S_IROTH (S_IRGRP >> 3) # define S_IWOTH (S_IWGRP >> 3) # define S_IXOTH (S_IXGRP >> 3) # define S_IRWXO (S_IRWXG >> 3) #endif #ifndef S_ISREG # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* * =========================================================================== * DateTime conversions * =========================================================================== */ /* * Dates and times in a NuFX archive are always considered to be in the * local time zone. The use of GMT time stamps would have been more * appropriate for an archive, but local time works well enough. * * Regarding Y2K on the Apple II: * * Dave says P8 drivers should return year values in the range 0..99, where * 40..99 = 1940..1999, and 0..39 = 2000..2039. Year values 100..127 should * never be used. For ProDOS 8, the year 2000 is "00". * * The IIgs ReadTimeHex call uses "year minus 1900". For GS/OS, the year * 2000 is "100". * * The NuFX file type note says the archive format should work like * The IIgs ReadTimeHex call, which uses "year minus 1900" as its * format. GS/ShrinkIt v1.1 uses the IIgs date calls, and so stores the * year 2000 as "100". P8 ShrinkIt v3.4 uses the P8 mapping, and stores * it as "0". Neither really quite understands what the other is doing. * * For our purposes, we will follow the NuFX standard and emit "100" * for the year 2000, but will accept and understand "0" as well. */ #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) /* * Convert from local time in a NuDateTime struct to GMT seconds since 1970. * * If the conversion is invalid, "*pWhen" is set to zero. */ static void Nu_DateTimeToGMTSeconds(const NuDateTime* pDateTime, time_t* pWhen) { struct tm tmbuf; time_t when; Assert(pDateTime != NULL); Assert(pWhen != NULL); tmbuf.tm_sec = pDateTime->second; tmbuf.tm_min = pDateTime->minute; tmbuf.tm_hour = pDateTime->hour; tmbuf.tm_mday = pDateTime->day +1; tmbuf.tm_mon = pDateTime->month; tmbuf.tm_year = pDateTime->year; if (pDateTime->year < 40) tmbuf.tm_year += 100; /* P8 uses 0-39 for 2000-2039 */ tmbuf.tm_wday = 0; tmbuf.tm_yday = 0; tmbuf.tm_isdst = -1; /* let it figure DST and time zone */ #if defined(HAVE_MKTIME) when = mktime(&tmbuf); #elif defined(HAVE_TIMELOCAL) when = timelocal(&tmbuf); #else # error "need time converter" #endif if (when == (time_t) -1) *pWhen = 0; else *pWhen = when; } /* * Convert from GMT seconds since 1970 to local time in a NuDateTime struct. */ static void Nu_GMTSecondsToDateTime(const time_t* pWhen, NuDateTime *pDateTime) { struct tm* ptm; Assert(pWhen != NULL); Assert(pDateTime != NULL); #if defined(HAVE_LOCALTIME_R) && defined(USE_REENTRANT_CALLS) struct tm res; ptm = localtime_r(pWhen, &res); #else /* NOTE: not thread-safe */ ptm = localtime(pWhen); #endif pDateTime->second = ptm->tm_sec; pDateTime->minute = ptm->tm_min; pDateTime->hour = ptm->tm_hour; pDateTime->day = ptm->tm_mday -1; pDateTime->month = ptm->tm_mon; pDateTime->year = ptm->tm_year; pDateTime->extra = 0; pDateTime->weekDay = ptm->tm_wday +1; } #endif /* * Fill in the current time. */ void Nu_SetCurrentDateTime(NuDateTime* pDateTime) { Assert(pDateTime != NULL); #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) { time_t now = time(NULL); Nu_GMTSecondsToDateTime(&now, pDateTime); } #else #error "Port this" #endif } /* * Returns "true" if "pWhen1" is older than "pWhen2". Returns false if * "pWhen1" is the same age or newer than "pWhen2". * * On systems with mktime, it would be straightforward to convert the dates * to time in seconds, and compare them that way. However, I don't want * to rely on that function too heavily, so we just compare fields. */ Boolean Nu_IsOlder(const NuDateTime* pWhen1, const NuDateTime* pWhen2) { long result, year1, year2; /* adjust for P8 ShrinkIt Y2K problem */ year1 = pWhen1->year; if (year1 < 40) year1 += 100; year2 = pWhen2->year; if (year2 < 40) year2 += 100; result = year1 - year2; if (!result) result = pWhen1->month - pWhen2->month; if (!result) result = pWhen1->day - pWhen2->day; if (!result) result = pWhen1->hour - pWhen2->hour; if (!result) result = pWhen1->minute - pWhen2->minute; if (!result) result = pWhen1->second - pWhen2->second; if (result < 0) return true; return false; } /* * =========================================================================== * Get/set file info * =========================================================================== */ /* * System-independent (mostly) file info struct. */ typedef struct NuFileInfo { Boolean isValid; /* init to "false", set "true" after we get data */ Boolean isRegularFile; /* is this a regular file? */ Boolean isDirectory; /* is this a directory? */ Boolean isForked; /* does file have a non-empty resource fork? */ uint32_t dataEof; NuDateTime modWhen; mode_t unixMode; /* UNIX-style permissions */ } NuFileInfo; #define kDefaultFileType 0 /* "NON" */ #define kDefaultAuxType 0 /* $0000 */ /* * Determine whether the record has both data and resource forks. * * TODO: if we're not using "mask dataless", scanning threads may not * get the right answer, because GSHK omits theads for zero-length forks. * We could check pRecord->recStorageType, though we have to be careful * because that's overloaded for disk images. In any event, the result * from this method isn't relevant unless we're trying to use forked * files on the native filesystem. */ static Boolean Nu_IsForkedFile(NuArchive* pArchive, const NuRecord* pRecord) { const NuThread* pThread; NuThreadID threadID; Boolean gotData, gotRsrc; int i; gotData = gotRsrc = false; for (i = 0; i < (int)pRecord->recTotalThreads; i++) { pThread = Nu_GetThread(pRecord, i); Assert(pThread != NULL); threadID = NuMakeThreadID(pThread->thThreadClass,pThread->thThreadKind); if (threadID == kNuThreadIDDataFork) gotData = true; else if (threadID == kNuThreadIDRsrcFork) gotRsrc = true; } if (gotData && gotRsrc) return true; else return false; } #if defined(MAC_LIKE) # if defined(HAS_RESOURCE_FORKS) /* * String to append to the filename to access the resource fork. * * This appears to be the correct way to access the resource fork, since * at least OS X 10.1. Up until 10.7 ("Lion", July 2011), you could also * access the fork with "/rsrc". */ static const char kMacRsrcPath[] = "/..namedfork/rsrc"; /* * Generates the resource fork pathname from the file path. * * The caller must free the string returned. */ static UNICHAR* GetResourcePath(const UNICHAR* pathnameUNI) { Assert(pathnameUNI != NULL); // sizeof(kMacRsrcPath) includes the string and the terminating null byte const size_t bufLen = strlen(pathnameUNI) * sizeof(UNICHAR) + sizeof(kMacRsrcPath); char* buf; buf = (char*) malloc(bufLen); snprintf(buf, bufLen, "%s%s", pathnameUNI, kMacRsrcPath); return buf; } # endif /*HAS_RESOURCE_FORKS*/ /* * Due to historical reasons, the XATTR_FINDERINFO_NAME (defined to be * ``com.apple.FinderInfo'') extended attribute must be 32 bytes; see the * ATTR_CMN_FNDRINFO section in getattrlist(2). * * The FinderInfo block is the concatenation of a FileInfo structure * and an ExtendedFileInfo (or ExtendedFolderInfo) structure -- see * ATTR_CMN_FNDRINFO in getattrlist(2). * * All we're really interested in is the file type and creator code, * which are stored big-endian in the first 8 bytes. */ static const int kFinderInfoSize = 32; /* * Set the file type and creator type. */ static NuError Nu_SetFinderInfo(NuArchive* pArchive, const NuRecord* pRecord, const UNICHAR* pathnameUNI) { uint8_t fiBuf[kFinderInfoSize]; size_t actual = getxattr(pathnameUNI, XATTR_FINDERINFO_NAME, fiBuf, sizeof(fiBuf), 0, 0); if (actual == (size_t) -1 && errno == ENOATTR) { // doesn't yet have Finder info memset(fiBuf, 0, sizeof(fiBuf)); } else if (actual != kFinderInfoSize) { Nu_ReportError(NU_BLOB, errno, "Finder info on '%s' returned %d", pathnameUNI, (int) actual); return kNuErrFile; } uint8_t proType = (uint8_t) pRecord->recFileType; uint16_t proAux = (uint16_t) pRecord->recExtraType; /* * Attempt to use one of the convenience types. If nothing matches, * use the generic pdos/pXYZ approach. Note that PSYS/PS16 will * lose the file's aux type. * * I'm told this is from page 336 of _Programmer's Reference for * System 6.0_. */ uint8_t* fileTypeBuf = fiBuf; uint8_t* creatorBuf = fiBuf + 4; memcpy(creatorBuf, "pdos", 4); if (proType == 0x00 && proAux == 0x0000) { memcpy(fileTypeBuf, "BINA", 4); } else if (proType == 0x04 && proAux == 0x0000) { memcpy(fileTypeBuf, "TEXT", 4); } else if (proType == 0xff) { memcpy(fileTypeBuf, "PSYS", 4); } else if (proType == 0xb3 && (proAux & 0xff00) != 0xdb00) { memcpy(fileTypeBuf, "PS16", 4); } else if (proType == 0xd7 && proAux == 0x0000) { memcpy(fileTypeBuf, "MIDI", 4); } else if (proType == 0xd8 && proAux == 0x0000) { memcpy(fileTypeBuf, "AIFF", 4); } else if (proType == 0xd8 && proAux == 0x0001) { memcpy(fileTypeBuf, "AIFC", 4); } else if (proType == 0xe0 && proAux == 0x0005) { memcpy(creatorBuf, "dCpy", 4); memcpy(fileTypeBuf, "dImg", 4); } else { fileTypeBuf[0] = 'p'; fileTypeBuf[1] = proType; fileTypeBuf[2] = (uint8_t) (proAux >> 8); fileTypeBuf[3] = (uint8_t) proAux; } if (setxattr(pathnameUNI, XATTR_FINDERINFO_NAME, fiBuf, sizeof(fiBuf), 0, 0) != 0) { Nu_ReportError(NU_BLOB, errno, "Unable to set Finder info on '%s'", pathnameUNI); return kNuErrFile; } return kNuErrNone; } #endif /*MAC_LIKE*/ /* * Get the file info into a NuFileInfo struct. Fields which are * inappropriate for the current system are set to default values. */ static NuError Nu_GetFileInfo(NuArchive* pArchive, const UNICHAR* pathnameUNI, NuFileInfo* pFileInfo) { NuError err = kNuErrNone; Assert(pArchive != NULL); Assert(pathnameUNI != NULL); Assert(pFileInfo != NULL); pFileInfo->isValid = false; #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) { struct stat sbuf; int cc; cc = stat(pathnameUNI, &sbuf); if (cc) { if (errno == ENOENT) err = kNuErrFileNotFound; else err = kNuErrFileStat; goto bail; } pFileInfo->isRegularFile = false; if (S_ISREG(sbuf.st_mode)) pFileInfo->isRegularFile = true; pFileInfo->isDirectory = false; if (S_ISDIR(sbuf.st_mode)) pFileInfo->isDirectory = true; /* BUG: should check for 32-bit overflow from 64-bit off_t */ pFileInfo->dataEof = sbuf.st_size; pFileInfo->isForked = false; # if defined(MAC_LIKE) && defined(HAS_RESOURCE_FORKS) if (!pFileInfo->isDirectory) { /* * Check for the presence of a resource fork. You can check * these from a terminal with "ls -l@" -- look for the * "com.apple.ResourceFork" attribute. * * We can either use getxattr() and check for the presence of * the attribute, or get the file length with stat(). I * don't know if xattr has always worked with resource forks, * so we'll stick with stat for now. */ UNICHAR* rsrcPath = GetResourcePath(pathnameUNI); struct stat res_sbuf; if (stat(rsrcPath, &res_sbuf) == 0) { pFileInfo->isForked = (res_sbuf.st_size != 0); } free(rsrcPath); } # endif Nu_GMTSecondsToDateTime(&sbuf.st_mtime, &pFileInfo->modWhen); pFileInfo->unixMode = sbuf.st_mode; pFileInfo->isValid = true; } #else #error "Port this" #endif bail: return err; } /* * Determine whether a specific fork in the file exists. * * On systems that don't support forked files, the "checkRsrcFork" argument * is ignored. If forked files are supported, and we are extracting a * file with data and resource forks, we only claim it exists if it has * nonzero length. */ static NuError Nu_FileForkExists(NuArchive* pArchive, const UNICHAR* pathnameUNI, Boolean isForkedFile, Boolean checkRsrcFork, Boolean* pExists, NuFileInfo* pFileInfo) { NuError err = kNuErrNone; Assert(pArchive != NULL); Assert(pathnameUNI != NULL); Assert(checkRsrcFork == true || checkRsrcFork == false); Assert(pExists != NULL); Assert(pFileInfo != NULL); #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) # if !defined(MAC_LIKE) /* * On Unix and Windows we ignore "isForkedFile" and "checkRsrcFork". * The file must not exist at all. */ Assert(pArchive->lastFileCreatedUNI == NULL); # endif *pExists = true; err = Nu_GetFileInfo(pArchive, pathnameUNI, pFileInfo); if (err == kNuErrFileNotFound) { err = kNuErrNone; *pExists = false; } # if defined(MAC_LIKE) /* * On Mac OS X, we'll use the resource fork, but we may not want to * overwrite existing data. */ if (*pExists && checkRsrcFork) { *pExists = pFileInfo->isForked; } # endif #elif defined(__ORCAC__) /* * If the file doesn't exist, great. If it does, and "lastFileCreated" * matches up with this one, then we know that it exists because we * created it. * * This is great unless the record has two data forks or something * equally dopey, so we check to be sure that the fork we want to * put the data into is currently empty. * * It is possible, though asinine, for a Mac OS or GS/OS extraction * program to put the data and resource forks of a record into * separate files, so we can't just assume that because we wrote * the data fork to file A it is okay for file B to exist. That's * why we compare the pathname instead of just remembering that * we already created a file for this record. */ #error "Finish me" #else #error "Port this" #endif return err; } /* * Set the dates on a file according to what's in the record. */ static NuError Nu_SetFileDates(NuArchive* pArchive, const NuRecord* pRecord, const UNICHAR* pathnameUNI) { NuError err = kNuErrNone; Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(pathnameUNI != NULL); #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) { struct utimbuf utbuf; /* ignore create time, and set access time equal to mod time */ Nu_DateTimeToGMTSeconds(&pRecord->recModWhen, &utbuf.modtime); utbuf.actime = utbuf.modtime; /* only do it if the NuDateTime was valid */ if (utbuf.modtime) { if (utime(pathnameUNI, &utbuf) < 0) { Nu_ReportError(NU_BLOB, errno, "Unable to set time stamp on '%s'", pathnameUNI); err = kNuErrFileSetDate; goto bail; } } } #else #error "Port this" #endif bail: return err; } /* * Returns "true" if the record is locked (in the ProDOS sense). * * Bits 31-8 reserved, must be zero * Bit 7 (D) 1 = destroy enabled * Bit 6 (R) 1 = rename enabled * Bit 5 (B) 1 = file needs to be backed up * Bits 4-3 reserved, must be zero * Bit 2 (I) 1 = file is invisible * Bit 1 (W) 1 = write enabled * Bit 0 (R) 1 = read enabled * * A "locked" file would be 00?00001, "unlocked" 11?00011, with many * possible variations. For our purposes, we treat all files as unlocked * unless they match the classic "locked" bit pattern. */ static Boolean Nu_IsRecordLocked(const NuRecord* pRecord) { if (pRecord->recAccess == 0x21L || pRecord->recAccess == 0x01L) return true; else return false; } /* * Set the file access permissions based on what's in the record. * * This assumes that the file is currently writable, so we only need * to do something if the original file was "locked". */ static NuError Nu_SetFileAccess(NuArchive* pArchive, const NuRecord* pRecord, const UNICHAR* pathnameUNI) { NuError err = kNuErrNone; Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(pathnameUNI != NULL); #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) /* only need to do something if the file was "locked" */ if (Nu_IsRecordLocked(pRecord)) { mode_t mask; /* set it to 444, modified by umask */ mask = umask(0); umask(mask); //DBUG(("+++ chmod '%s' %03o (mask=%03o)\n", pathname, // (S_IRUSR | S_IRGRP | S_IROTH) & ~mask, mask)); if (chmod(pathnameUNI, (S_IRUSR | S_IRGRP | S_IROTH) & ~mask) < 0) { Nu_ReportError(NU_BLOB, errno, "unable to set access for '%s' to %03o", pathnameUNI, (int) mask); err = kNuErrFileSetAccess; goto bail; } } #else #error "Port this" #endif bail: return err; } /* * =========================================================================== * Create/open an output file * =========================================================================== */ /* * Prepare an existing file for writing. * * Generally this just involves ensuring that the file is writable. If * this is a convenient place to truncate it, we should do that too. * * 20150103: we don't seem to be doing the truncation here, so prepRsrc * is unused. */ static NuError Nu_PrepareForWriting(NuArchive* pArchive, const UNICHAR* pathnameUNI, Boolean prepRsrc, NuFileInfo* pFileInfo) { NuError err = kNuErrNone; Assert(pArchive != NULL); Assert(pathnameUNI != NULL); Assert(prepRsrc == true || prepRsrc == false); Assert(pFileInfo != NULL); Assert(pFileInfo->isValid == true); /* don't go playing with directories, pipes, etc */ if (pFileInfo->isRegularFile != true) return kNuErrNotRegularFile; #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) if (!(pFileInfo->unixMode & S_IWUSR)) { /* make it writable by owner, plus whatever it was before */ if (chmod(pathnameUNI, S_IWUSR | pFileInfo->unixMode) < 0) { Nu_ReportError(NU_BLOB, errno, "unable to set access for '%s'", pathnameUNI); err = kNuErrFileSetAccess; goto bail; } } return kNuErrNone; #else #error "Port this" #endif bail: return err; } /* * Invoke the system-dependent directory creation function. */ static NuError Nu_Mkdir(NuArchive* pArchive, const char* dir) { NuError err = kNuErrNone; Assert(pArchive != NULL); Assert(dir != NULL); #if defined(UNIX_LIKE) if (mkdir(dir, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH) < 0) { err = errno ? errno : kNuErrDirCreate; Nu_ReportError(NU_BLOB, err, "Unable to create dir '%s'", dir); goto bail; } #elif defined(WINDOWS_LIKE) if (mkdir(dir) < 0) { err = errno ? errno : kNuErrDirCreate; Nu_ReportError(NU_BLOB, err, "Unable to create dir '%s'", dir); goto bail; } #else #error "Port this" #endif bail: return err; } /* * Create a single subdirectory if it doesn't exist. If the next-highest * subdirectory level doesn't exist either, cut down the pathname and * recurse. */ static NuError Nu_CreateSubdirIFN(NuArchive* pArchive, const UNICHAR* pathStartUNI, const char* pathEnd, char fssep) { NuError err = kNuErrNone; NuFileInfo fileInfo; char* tmpBuf = NULL; Assert(pArchive != NULL); Assert(pathStartUNI != NULL); Assert(pathEnd != NULL); Assert(fssep != '\0'); /* pathStart might have whole path, but we only want up to "pathEnd" */ tmpBuf = strdup(pathStartUNI); tmpBuf[pathEnd - pathStartUNI +1] = '\0'; err = Nu_GetFileInfo(pArchive, tmpBuf, &fileInfo); if (err == kNuErrFileNotFound) { /* dir doesn't exist; move up a level and check parent */ pathEnd = strrchr(tmpBuf, fssep); if (pathEnd != NULL) { pathEnd--; Assert(pathEnd >= tmpBuf); err = Nu_CreateSubdirIFN(pArchive, tmpBuf, pathEnd, fssep); BailError(err); } /* parent is taken care of; create this one */ err = Nu_Mkdir(pArchive, tmpBuf); BailError(err); } else if (err != kNuErrNone) { goto bail; } else { /* file does exist, make sure it's a directory */ Assert(fileInfo.isValid == true); if (!fileInfo.isDirectory) { err = kNuErrNotDir; Nu_ReportError(NU_BLOB, err, "Unable to create path '%s'", tmpBuf); goto bail; } } bail: Nu_Free(pArchive, tmpBuf); return err; } /* * Create subdirectories, if needed. The paths leading up to the filename * in "pathname" will be created. * * If "pathname" is just a filename, or the set of directories matches * the last directory we created, we don't do anything. */ static NuError Nu_CreatePathIFN(NuArchive* pArchive, const UNICHAR* pathnameUNI, UNICHAR fssep) { NuError err = kNuErrNone; const char* pathStart; const char* pathEnd; Assert(pArchive != NULL); Assert(pathnameUNI != NULL); Assert(fssep != '\0'); pathStart = pathnameUNI; #if !defined(MAC_LIKE) /* On the Mac, if it's a full path, treat it like one */ // 20150103: not sure what use case this is for if (pathnameUNI[0] == fssep) pathStart++; #endif /* NOTE: not expecting names like "foo/bar/ack/", with terminating fssep */ pathEnd = strrchr(pathStart, fssep); if (pathEnd == NULL) { /* no subdirectory components found */ goto bail; } pathEnd--; Assert(pathEnd >= pathStart); if (pathEnd - pathStart < 0) goto bail; /* * On some filesystems, strncasecmp would be appropriate here. However, * this is meant solely as an optimization to avoid extra stat() calls, * so we want to use the most restrictive case. */ if (pArchive->lastDirCreatedUNI && strncmp(pathStart, pArchive->lastDirCreatedUNI, pathEnd - pathStart +1) == 0) { /* we created this one recently, don't do it again */ goto bail; } /* * Test to determine which directories exist. The most likely case * is that some or all of the components have already been created, * so we start with the last one and work backward. */ err = Nu_CreateSubdirIFN(pArchive, pathStart, pathEnd, fssep); BailError(err); bail: return err; } /* * Open the file for writing, possibly truncating it. */ static NuError Nu_OpenFileForWrite(NuArchive* pArchive, const UNICHAR* pathnameUNI, Boolean openRsrc, FILE** pFp) { #if defined(MAC_LIKE) && defined(HAS_RESOURCE_FORKS) if (openRsrc) { UNICHAR* rsrcPath = GetResourcePath(pathnameUNI); *pFp = fopen(rsrcPath, kNuFileOpenWriteTrunc); free(rsrcPath); } else { *pFp = fopen(pathnameUNI, kNuFileOpenWriteTrunc); } #else *pFp = fopen(pathnameUNI, kNuFileOpenWriteTrunc); #endif if (*pFp == NULL) return errno ? errno : -1; return kNuErrNone; } /* * Open an output file and prepare it for writing. * * There are a number of things to take into consideration, including * deal with "file exists" conditions, handling Mac/IIgs file types, * coping with resource forks on extended files, and handling the * "freshen" option that requires us to only update files that are * older than what we have. */ NuError Nu_OpenOutputFile(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, const UNICHAR* newPathnameUNI, UNICHAR newFssep, FILE** pFp) { NuError err = kNuErrNone; Boolean exists, isForkedFile, extractingRsrc = false; NuFileInfo fileInfo; NuErrorStatus errorStatus; NuResult result; Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(pThread != NULL); Assert(newPathnameUNI != NULL); Assert(pFp != NULL); /* set up some defaults, in case something goes wrong */ errorStatus.operation = kNuOpExtract; errorStatus.err = kNuErrInternal; errorStatus.sysErr = 0; errorStatus.message = NULL; errorStatus.pRecord = pRecord; errorStatus.pathnameUNI = newPathnameUNI; errorStatus.origPathname = NULL; errorStatus.filenameSeparator = newFssep; /*errorStatus.origArchiveTouched = false;*/ errorStatus.canAbort = true; errorStatus.canRetry = true; errorStatus.canIgnore = false; errorStatus.canSkip = true; errorStatus.canRename = true; errorStatus.canOverwrite = true; /* decide if this is a forked file (i.e. has *both* forks) */ isForkedFile = Nu_IsForkedFile(pArchive, pRecord); /* decide if we're extracting a resource fork */ if (NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind) == kNuThreadIDRsrcFork) { extractingRsrc = true; } /* * Determine whether the file and fork already exists. If the file * is one we just created, and the fork we want to write to is * empty, this will *not* set "exists". */ fileInfo.isValid = false; err = Nu_FileForkExists(pArchive, newPathnameUNI, isForkedFile, extractingRsrc, &exists, &fileInfo); BailError(err); if (exists) { Assert(fileInfo.isValid == true); /* * The file exists when it shouldn't. Decide what to do, based * on the options configured by the application. */ /* * Start by checking to see if we're willing to overwrite older files. * If not, see if the application wants to rename the file, or force * the overwrite. Most likely they'll just want to skip it. */ if ((pArchive->valOnlyUpdateOlder) && !Nu_IsOlder(&fileInfo.modWhen, &pRecord->recModWhen)) { if (pArchive->errorHandlerFunc != NULL) { errorStatus.err = kNuErrNotNewer; result = (*pArchive->errorHandlerFunc)(pArchive, &errorStatus); switch (result) { case kNuAbort: err = kNuErrAborted; goto bail; case kNuRetry: case kNuRename: err = kNuErrRename; goto bail; case kNuSkip: err = kNuErrSkipped; goto bail; case kNuOverwrite: break; /* fall back into main code */ case kNuIgnore: default: err = kNuErrSyntax; Nu_ReportError(NU_BLOB, err, "Wasn't expecting result %d here", result); goto bail; } } else { err = kNuErrNotNewer; goto bail; } } /* If they "might" allow overwrites, and they have an error-handling * callback defined, call that to find out what they want to do * here. Options include skipping the file, overwriting the file, * and extracting to a different file. */ if (pArchive->valHandleExisting == kNuMaybeOverwrite) { if (pArchive->errorHandlerFunc != NULL) { errorStatus.err = kNuErrFileExists; result = (*pArchive->errorHandlerFunc)(pArchive, &errorStatus); switch (result) { case kNuAbort: err = kNuErrAborted; goto bail; case kNuRetry: case kNuRename: err = kNuErrRename; goto bail; case kNuSkip: err = kNuErrSkipped; goto bail; case kNuOverwrite: break; /* fall back into main code */ case kNuIgnore: default: err = kNuErrSyntax; Nu_ReportError(NU_BLOB, err, "Wasn't expecting result %d here", result); goto bail; } } else { /* no error handler, return an error to the caller */ err = kNuErrFileExists; goto bail; } } else if (pArchive->valHandleExisting == kNuNeverOverwrite) { err = kNuErrSkipped; goto bail; } } else { /* * The file doesn't exist. If we're doing a "freshen" from the * archive, we don't want to create a new file, so we return an * error to the user instead. However, we give the application * a chance to straighten things out. Most likely they'll just * return kNuSkip. */ if (pArchive->valHandleExisting == kNuMustOverwrite) { DBUG(("+++ can't freshen nonexistent file '%s'\n", newPathnameUNI)); if (pArchive->errorHandlerFunc != NULL) { errorStatus.err = kNuErrDuplicateNotFound; /* give them a chance to rename */ result = (*pArchive->errorHandlerFunc)(pArchive, &errorStatus); switch (result) { case kNuAbort: err = kNuErrAborted; goto bail; case kNuRetry: case kNuRename: err = kNuErrRename; goto bail; case kNuSkip: err = kNuErrSkipped; goto bail; case kNuOverwrite: break; /* fall back into main code */ case kNuIgnore: default: err = kNuErrSyntax; Nu_ReportError(NU_BLOB, err, "Wasn't expecting result %d here", result); goto bail; } } else { /* no error handler, return an error to the caller */ err = kNuErrDuplicateNotFound; goto bail; } } } Assert(err == kNuErrNone); /* * After the above, if the file exists then we need to prepare it for * writing. On some systems -- notably those with forked files -- it * may be easiest to delete the entire file and start over. On * simpler systems, an (optional) chmod followed by an open that * truncates the file should be sufficient. * * If the file didn't exist, we need to be sure that the path leading * up to its eventual location exists. This might require creating * several directories. We distinguish the case of "file isn't there" * from "file is there but fork isn't" by seeing if we were able to * get valid file info. */ if (exists) { Assert(fileInfo.isValid == true); err = Nu_PrepareForWriting(pArchive, newPathnameUNI, extractingRsrc, &fileInfo); BailError(err); } else if (!fileInfo.isValid) { err = Nu_CreatePathIFN(pArchive, newPathnameUNI, newFssep); BailError(err); } /* * Open sesame. */ err = Nu_OpenFileForWrite(pArchive, newPathnameUNI, extractingRsrc, pFp); BailError(err); #if defined(HAS_RESOURCE_FORKS) pArchive->lastFileCreatedUNI = newPathnameUNI; #endif bail: if (err != kNuErrNone) { if (err != kNuErrSkipped && err != kNuErrRename && err != kNuErrFileExists) { Nu_ReportError(NU_BLOB, err, "Unable to open '%s'%s", newPathnameUNI, extractingRsrc ? " (rsrc fork)" : ""); } } return err; } /* * Close the output file, adjusting the modification date and access * permissions as needed. * * On GS/OS and Mac OS, we may need to set the file type here, depending on * how much we managed to do when the file was first created. IIRC, * the GS/OS Open call should allow setting the file type. * * BUG: on GS/OS, if we set the file access after writing the data fork, * we may not be able to open the same file for writing the rsrc fork. * We can't suppress setting the access permissions, because we don't know * if the application will want to write both forks to the same file, or * for that matter will want to write the resource fork at all. Looks * like we will have to be smart enough to reset the access permissions * when writing a rsrc fork to a file with just a data fork. This isn't * quite right, but it's close enough. */ NuError Nu_CloseOutputFile(NuArchive* pArchive, const NuRecord* pRecord, FILE* fp, const UNICHAR* pathnameUNI) { NuError err; Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(fp != NULL); fclose(fp); err = Nu_SetFileDates(pArchive, pRecord, pathnameUNI); BailError(err); #if defined(MAC_LIKE) /* could also do this earlier and pass the fd for fsetxattr */ /* NOTE: must do this before Nu_SetFileAccess */ err = Nu_SetFinderInfo(pArchive, pRecord, pathnameUNI); BailError(err); #endif err = Nu_SetFileAccess(pArchive, pRecord, pathnameUNI); BailError(err); bail: return kNuErrNone; } /* * =========================================================================== * Open an input file * =========================================================================== */ /* * Open the file for reading, in "binary" mode when necessary. */ static NuError Nu_OpenFileForRead(NuArchive* pArchive, const UNICHAR* pathnameUNI, Boolean openRsrc, FILE** pFp) { *pFp = fopen(pathnameUNI, kNuFileOpenReadOnly); if (*pFp == NULL) return errno ? errno : -1; return kNuErrNone; } /* * Open an input file and prepare it for reading. * * If the file can't be found, we give the application an opportunity to * skip the absent file, retry, or abort the whole thing. */ NuError Nu_OpenInputFile(NuArchive* pArchive, const UNICHAR* pathnameUNI, Boolean openRsrc, FILE** pFp) { NuError err = kNuErrNone; NuError openErr = kNuErrNone; NuErrorStatus errorStatus; NuResult result; Assert(pArchive != NULL); Assert(pathnameUNI != NULL); Assert(pFp != NULL); #if defined(MAC_LIKE) && defined(HAS_RESOURCE_FORKS) UNICHAR* rsrcPath = NULL; if (openRsrc) { rsrcPath = GetResourcePath(pathnameUNI); pathnameUNI = rsrcPath; } #endif retry: /* * Open sesame. */ err = Nu_OpenFileForRead(pArchive, pathnameUNI, openRsrc, pFp); if (err == kNuErrNone) /* success! */ goto bail; if (err == ENOENT) openErr = kNuErrFileNotFound; if (pArchive->errorHandlerFunc != NULL) { errorStatus.operation = kNuOpAdd; errorStatus.err = openErr; errorStatus.sysErr = 0; errorStatus.message = NULL; errorStatus.pRecord = NULL; errorStatus.pathnameUNI = pathnameUNI; errorStatus.origPathname = NULL; errorStatus.filenameSeparator = '\0'; /*errorStatus.origArchiveTouched = false;*/ errorStatus.canAbort = true; errorStatus.canRetry = true; errorStatus.canIgnore = false; errorStatus.canSkip = true; errorStatus.canRename = false; errorStatus.canOverwrite = false; DBUG(("--- invoking error handler function\n")); result = (*pArchive->errorHandlerFunc)(pArchive, &errorStatus); switch (result) { case kNuAbort: err = kNuErrAborted; goto bail; case kNuRetry: goto retry; case kNuSkip: err = kNuErrSkipped; goto bail; case kNuRename: case kNuOverwrite: case kNuIgnore: default: err = kNuErrSyntax; Nu_ReportError(NU_BLOB, err, "Wasn't expecting result %d here", result); goto bail; } } else { DBUG(("+++ no error callback in OpenInputFile\n")); } bail: if (err == kNuErrNone) { Assert(*pFp != NULL); } else { if (err != kNuErrSkipped && err != kNuErrRename && err != kNuErrFileExists) { Nu_ReportError(NU_BLOB, err, "Unable to open '%s'%s", pathnameUNI, openRsrc ? " (rsrc fork)" : ""); } } #if defined(MAC_LIKE) && defined(HAS_RESOURCE_FORKS) free(rsrcPath); #endif return err; } /* * =========================================================================== * Delete and rename files * =========================================================================== */ /* * Delete a file. */ NuError Nu_DeleteFile(const UNICHAR* pathnameUNI) { #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) int cc; DBUG(("--- Deleting '%s'\n", pathnameUNI)); cc = unlink(pathnameUNI); if (cc < 0) return errno ? errno : -1; else return kNuErrNone; #else #error "Port this" #endif } /* * Rename a file from "fromPath" to "toPath". */ NuError Nu_RenameFile(const UNICHAR* fromPathUNI, const UNICHAR* toPathUNI) { #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) int cc; DBUG(("--- Renaming '%s' to '%s'\n", fromPathUNI, toPathUNI)); cc = rename(fromPathUNI, toPathUNI); if (cc < 0) return errno ? errno : -1; else return kNuErrNone; #else #error "Port this" #endif } /* * =========================================================================== * NuError wrappers for std functions * =========================================================================== */ /* * Wrapper for ftell(). */ NuError Nu_FTell(FILE* fp, long* pOffset) { Assert(fp != NULL); Assert(pOffset != NULL); errno = 0; *pOffset = ftell(fp); if (*pOffset < 0) { Nu_ReportError(NU_NILBLOB, errno, "file ftell failed"); return errno ? errno : kNuErrFileSeek; } return kNuErrNone; } /* * Wrapper for fseek(). */ NuError Nu_FSeek(FILE* fp, long offset, int ptrname) { Assert(fp != NULL); Assert(ptrname == SEEK_SET || ptrname == SEEK_CUR || ptrname == SEEK_END); errno = 0; if (fseek(fp, offset, ptrname) < 0) { Nu_ReportError(NU_NILBLOB, errno, "file fseek(%ld, %d) failed", offset, ptrname); return errno ? errno : kNuErrFileSeek; } return kNuErrNone; } /* * Wrapper for fread(). Note the arguments resemble read(2) rather than the * slightly silly ones used by fread(3S). */ NuError Nu_FRead(FILE* fp, void* buf, size_t nbyte) { size_t result; errno = 0; result = fread(buf, nbyte, 1, fp); if (result != 1) return errno ? errno : kNuErrFileRead; return kNuErrNone; } /* * Wrapper for fwrite(). Note the arguments resemble write(2) rather than the * slightly silly ones used by fwrite(3S). */ NuError Nu_FWrite(FILE* fp, const void* buf, size_t nbyte) { size_t result; errno = 0; result = fwrite(buf, nbyte, 1, fp); if (result != 1) return errno ? errno : kNuErrFileWrite; return kNuErrNone; } /* * =========================================================================== * Misc functions * =========================================================================== */ /* * Copy a section from one file to another. */ NuError Nu_CopyFileSection(NuArchive* pArchive, FILE* dstFp, FILE* srcFp, long length) { NuError err; long readLen; Assert(pArchive != NULL); Assert(dstFp != NULL); Assert(srcFp != NULL); Assert(length >= 0); /* can be == 0, e.g. empty data fork from HFS */ /* nice big buffer, for speed... could use getc/putc for simplicity */ err = Nu_AllocCompressionBufferIFN(pArchive); BailError(err); DBUG(("+++ Copying %ld bytes\n", length)); while (length) { readLen = length > kNuGenCompBufSize ? kNuGenCompBufSize : length; err = Nu_FRead(srcFp, pArchive->compBuf, readLen); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Nu_FRead failed while copying file section " "(fp=0x%08lx, readLen=%ld, length=%ld, err=%d)\n", (long) srcFp, readLen, length, err); goto bail; } err = Nu_FWrite(dstFp, pArchive->compBuf, readLen); BailError(err); length -= readLen; } bail: return err; } /* * Find the length of an open file. * * On UNIX it would be easier to just call fstat(), but fseek is portable. * * Only useful for files < 2GB in size. * * (pArchive is only used for BailError message reporting, so it's okay * to call here with a NULL pointer if the archive isn't open yet.) */ NuError Nu_GetFileLength(NuArchive* pArchive, FILE* fp, long* pLength) { NuError err; long oldpos; Assert(fp != NULL); Assert(pLength != NULL); err = Nu_FTell(fp, &oldpos); BailError(err); err = Nu_FSeek(fp, 0, SEEK_END); BailError(err); err = Nu_FTell(fp, pLength); BailError(err); err = Nu_FSeek(fp, oldpos, SEEK_SET); BailError(err); bail: return err; } /* * Truncate an open file. This differs from ftruncate() in that it takes * a FILE* instead of an fd, and the length is a long instead of off_t. */ NuError Nu_TruncateOpenFile(FILE* fp, long length) { #if defined(HAVE_FTRUNCATE) if (ftruncate(fileno(fp), length) < 0) return errno ? errno : -1; return kNuErrNone; #elif defined(HAVE_CHSIZE) if (chsize(fileno(fp), length) < 0) return errno ? errno : -1; return kNuErrNone; #else /* not fatal; return this to indicate that it's an unsupported operation */ return kNuErrInternal; #endif } nulib2-3.1.0/nufxlib/Funnel.c000066400000000000000000000640521316100516500157550ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Implementation of NuFunnel, NuStraw and ProgressUpdater. */ #include "NufxLibPriv.h" /* * =========================================================================== * Progress updater * =========================================================================== */ /* * Initialize the fields in a ProgressData structure, prior to compressing * data into a record. * * The same structure will be used when expanding all threads in a given * record. */ NuError Nu_ProgressDataInit_Compress(NuArchive* pArchive, NuProgressData* pProgressData, const NuRecord* pRecord, const UNICHAR* origPathnameUNI, const UNICHAR* pathnameUNI) { const char* cp; Assert(pProgressData != NULL); Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(origPathnameUNI != NULL); Assert(pathnameUNI != NULL); pProgressData->pRecord = pRecord; pProgressData->origPathnameUNI = origPathnameUNI; pProgressData->pathnameUNI = pathnameUNI; cp = strrchr(pathnameUNI, NuGetSepFromSysInfo(pRecord->recFileSysInfo)); if (cp == NULL || *(cp+1) == '\0') pProgressData->filenameUNI = pProgressData->pathnameUNI; else pProgressData->filenameUNI = cp+1; pProgressData->operation = kNuOpAdd; pProgressData->state = kNuProgressPreparing; pProgressData->uncompressedLength = 0; pProgressData->uncompressedProgress = 0; pProgressData->compress.threadFormat = (NuThreadFormat)-1; /* ya know... if this is NULL, none of the above matters much */ pProgressData->progressFunc = pArchive->progressUpdaterFunc; return kNuErrNone; } /* * Initialize the fields in a ProgressData structure, prior to expanding * data from a record. * * The same structure will be used when expanding all threads in a given * record. */ NuError Nu_ProgressDataInit_Expand(NuArchive* pArchive, NuProgressData* pProgressData, const NuRecord* pRecord, const UNICHAR* newPathnameUNI, UNICHAR newFssep, const UNICHAR* origPathnameUNI, NuValue convertEOL) { const NuThread* pThreadIter; const char* cp; int i; Assert(pProgressData != NULL); Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(newPathnameUNI != NULL); Assert(origPathnameUNI != NULL); Assert(newFssep != 0); pProgressData->pRecord = pRecord; pProgressData->expand.pThread = NULL; pProgressData->origPathnameUNI = origPathnameUNI; pProgressData->pathnameUNI = newPathnameUNI; cp = strrchr(newPathnameUNI, newFssep); if (cp == NULL || *(cp+1) == '\0') pProgressData->filenameUNI = newPathnameUNI; else pProgressData->filenameUNI = cp+1; pProgressData->expand.convertEOL = convertEOL; /* total up the data threads */ pProgressData->expand.totalCompressedLength = 0; pProgressData->expand.totalUncompressedLength = 0; for (i = 0; i < (int)pRecord->recTotalThreads; i++) { pThreadIter = Nu_GetThread(pRecord, i); if (pThreadIter->thThreadClass != kNuThreadClassData) continue; pProgressData->expand.totalCompressedLength += pThreadIter->thCompThreadEOF; pProgressData->expand.totalUncompressedLength += pThreadIter->actualThreadEOF; } pProgressData->operation = kNuOpExtract; if (pArchive->testMode) pProgressData->operation = kNuOpTest; pProgressData->state = kNuProgressPreparing; pProgressData->uncompressedLength = 0; pProgressData->uncompressedProgress = 0; /* ya know... if this is NULL, none of the above matters much */ pProgressData->progressFunc = pArchive->progressUpdaterFunc; return kNuErrNone; } /* * Do the setup on a ProgressData prior to compressing a thread. */ NuError Nu_ProgressDataCompressPrep(NuArchive* pArchive, NuStraw* pStraw, NuThreadFormat threadFormat, uint32_t sourceLen) { NuProgressData* pProgressData; Assert(pArchive != NULL); Assert(pStraw != NULL); Assert(sourceLen < 32767*65536); pProgressData = pStraw->pProgress; if (pProgressData == NULL) return kNuErrNone; pProgressData->uncompressedLength = sourceLen; pProgressData->compress.threadFormat = threadFormat; return kNuErrNone; } /* * Do the setup on a ProgressData prior to expanding a thread. * * "pThread" is the thread being expanded. */ NuError Nu_ProgressDataExpandPrep(NuArchive* pArchive, NuFunnel* pFunnel, const NuThread* pThread) { NuProgressData* pProgressData; Assert(pArchive != NULL); Assert(pFunnel != NULL); Assert(pThread != NULL); pProgressData = pFunnel->pProgress; if (pProgressData == NULL) return kNuErrNone; /*pProgressData->compressedLength = pThread->thCompThreadEOF;*/ pProgressData->uncompressedLength = pThread->actualThreadEOF; pProgressData->expand.pThread = pThread; return kNuErrNone; } /* * Compute a completion percentage. */ static int Nu_ComputePercent(uint32_t total, uint32_t progress) { uint32_t perc; if (!total) return 0; if (total < 21474836) { perc = (progress * 100 + 50) / total; if (perc > 100) perc = 100; } else { perc = progress / (total / 100); if (perc > 100) perc = 100; } return (int) perc; } /* * Send the initial progress message, before the output file is opened * (when extracting) or the input file is opened (when adding). */ NuError Nu_SendInitialProgress(NuArchive* pArchive, NuProgressData* pProgress) { NuResult result; Assert(pArchive != NULL); Assert(pProgress != NULL); if (pProgress->progressFunc == NULL) return kNuErrNone; pProgress->percentComplete = Nu_ComputePercent( pProgress->uncompressedLength, pProgress->uncompressedProgress); result = (*pProgress->progressFunc)(pArchive, (NuProgressData*) pProgress); if (result == kNuSkip) return kNuErrSkipped; /* [dunno how well this works] */ if (result == kNuAbort) return kNuErrAborted; return kNuErrNone; } /* * =========================================================================== * NuFunnel object * =========================================================================== */ /* * Allocate and initialize a Funnel. */ NuError Nu_FunnelNew(NuArchive* pArchive, NuDataSink* pDataSink, NuValue convertEOL, NuValue convertEOLTo, NuProgressData* pProgress, NuFunnel** ppFunnel) { NuError err = kNuErrNone; NuFunnel* pFunnel = NULL; Assert(ppFunnel != NULL); Assert(pDataSink != NULL); Assert(convertEOL == kNuConvertOff || convertEOL == kNuConvertOn || convertEOL == kNuConvertAuto); pFunnel = Nu_Calloc(pArchive, sizeof(*pFunnel)); BailAlloc(pFunnel); pFunnel->buffer = Nu_Malloc(pArchive, kNuFunnelBufSize); BailAlloc(pFunnel->buffer); pFunnel->pDataSink = pDataSink; pFunnel->convertEOL = convertEOL; pFunnel->convertEOLTo = convertEOLTo; pFunnel->convertEOLFrom = kNuEOLUnknown; pFunnel->pProgress = pProgress; pFunnel->checkStripHighASCII = (pArchive->valStripHighASCII != 0); pFunnel->doStripHighASCII = false; /* determined on first write */ pFunnel->isFirstWrite = true; bail: if (err != kNuErrNone) Nu_FunnelFree(pArchive, pFunnel); else *ppFunnel = pFunnel; return err; } /* * Free a Funnel. * * The data should already have been written; it's not the duty of a * "free" function to flush data out. */ NuError Nu_FunnelFree(NuArchive* pArchive, NuFunnel* pFunnel) { if (pFunnel == NULL) return kNuErrNone; #ifdef DEBUG_MSGS if (pFunnel->bufCount) Nu_ReportError(NU_BLOB_DEBUG, kNuErrNone, "freeing non-empty funnel"); #endif Nu_Free(pArchive, pFunnel->buffer); Nu_Free(pArchive, pFunnel); return kNuErrNone; } #if 0 /* * Set the maximum amount of output we're willing to push through the * funnel. Attempts to write more than this many bytes will fail. This * allows us to bail out as soon as it's apparent that compression is * failing and is actually resulting in a larger file. */ void Nu_FunnelSetMaxOutput(NuFunnel* pFunnel, uint32_t maxBytes) { Assert(pFunnel != NULL); Assert(maxBytes > 0); pFunnel->outMax = maxBytes; if (pFunnel->outCount >= pFunnel->outMax) pFunnel->outMaxExceeded = true; else pFunnel->outMaxExceeded = false; } #endif /* * Check to see if this is a high-ASCII file. To qualify, EVERY * character must have its high bit set, except for spaces (0x20). * (The exception is courtesy Glen Bredon's "Merlin".) */ static Boolean Nu_CheckHighASCII(const NuFunnel* pFunnel, const uint8_t* buffer, uint32_t count) { Boolean isHighASCII; Assert(buffer != NULL); Assert(count != 0); Assert(pFunnel->checkStripHighASCII); isHighASCII = true; while (count--) { if ((*buffer & 0x80) == 0 && *buffer != 0x20) { isHighASCII = false; break; } buffer++; } return isHighASCII; } /* * Table determining what's a binary character and what isn't. It would * possibly be more compact to generate this from a simple description, * but I'm hoping static/const data will end up in the code segment and * save space on the heap. * * This corresponds to less-316's ISO-latin1 "8bcccbcc18b95.33b.". This * may be too loose by itself; we may want to require that the lower-ASCII * values appear in higher proportions than the upper-ASCII values. * Otherwise we run the risk of converting a binary file with specific * properties. (Note that "upper-ASCII" refers to umlauts and other * accented characters, not DOS 3.3 "high ASCII".) * * The auto-detect mechanism will never be perfect though, so there's not * much point in tweaking it to death. */ static const char gNuIsBinary[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, /* ^@-^O */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P-^_ */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* - / */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - ? */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* P - _ */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - DEL */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 */ }; #define kNuMaxUpperASCII 1 /* max #of binary chars per 100 bytes */ #define kNuMinConvThreshold 40 /* min of 40 chars for auto-detect */ /* * Decide, based on the contents of the buffer, whether we should do an * EOL conversion on the data. * * We need to decide if we are looking at text data, and if so, what kind * of line terminator is in use. * * If we don't have enough data to make a determination, don't mess with it. * (Thought for the day: add a "bias" flag, based on the NuRecord fileType, * that causes us to handle borderline or sub-min-threshold cases more * reasonably. If it's of type TXT, it's probably text.) * * We try to figure out whether it's CR, LF, or CRLF, so that we can * skip the CPU-intensive conversion process if it isn't necessary. * * We will also enable a "high-ASCII" stripper if requested. This is * only enabled when EOL conversions are enabled. * * Returns kConvEOLOff or kConvEOLOn, and sets pFunnel->doStripHighASCII * if pFunnel->CheckStripHighASCII is set. */ static NuValue Nu_DetermineConversion(NuFunnel* pFunnel, const uint8_t* buffer, uint32_t count) { uint32_t bufCount, numBinary, numLF, numCR; Boolean isHighASCII; uint8_t val; if (count < kNuMinConvThreshold) return kNuConvertOff; /* * Check to see if the buffer is all high-ASCII characters. If it is, * we want to strip characters before we test them below. */ if (pFunnel->checkStripHighASCII) { isHighASCII = Nu_CheckHighASCII(pFunnel, buffer, count); DBUG(("+++ determined isHighASCII=%d\n", isHighASCII)); } else { isHighASCII = false; DBUG(("+++ not even checking isHighASCII\n")); } bufCount = count; numBinary = numLF = numCR = 0; while (bufCount--) { val = *buffer++; if (isHighASCII) val &= 0x7f; if (gNuIsBinary[val]) numBinary++; if (val == kNuCharLF) numLF++; if (val == kNuCharCR) numCR++; } /* if #found is > #allowed, it's a binary file */ if (count < 100) { /* use simplified check on files between kNuMinConvThreshold and 100 */ if (numBinary > kNuMaxUpperASCII) return kNuConvertOff; } else if (numBinary > (count / 100) * kNuMaxUpperASCII) return kNuConvertOff; /* * If our "convert to" setting is the same as what we're converting * from, we can turn off the converter and speed things up. * * These are simplistic, but this is intended as an optimization. We * will blow it if the input has lots of CRs and LFs scattered about, * and they just happen to be in equal amounts, but it's not clear * to me that an automatic EOL conversion makes sense on that sort * of file anyway. * * None of this applies if we also need to do a high-ASCII conversion. */ if (isHighASCII) { pFunnel->doStripHighASCII = true; } else { if (numLF && !numCR) pFunnel->convertEOLFrom = kNuEOLLF; else if (!numLF && numCR) pFunnel->convertEOLFrom = kNuEOLCR; else if (numLF && numLF == numCR) pFunnel->convertEOLFrom = kNuEOLCRLF; else pFunnel->convertEOLFrom = kNuEOLUnknown; } return kNuConvertOn; } /* * Write a block of data to the appropriate output device. Test for * excessive data, and raise "outMaxExceeded" if we overrun. * * This is either a Funnel function or a DataSink function, depending on * your perspective. */ static inline void Nu_FunnelPutBlock(NuFunnel* pFunnel, const uint8_t* buf, uint32_t len) { Assert(pFunnel != NULL); Assert(pFunnel->pDataSink != NULL); Assert(buf != NULL); Assert(len > 0); #if 0 if (pFunnel->outMax) { if (pFunnel->outMaxExceeded) return; if (pFunnel->outCount + len > pFunnel->outMax) { pFunnel->outMaxExceeded = true; return; } } pFunnel->outCount += len; #endif Nu_DataSinkPutBlock(pFunnel->pDataSink, buf, len); } /* * Output the EOL marker requested for this system. */ static inline void Nu_PutEOL(NuFunnel* pFunnel) { uint8_t ch; if (pFunnel->convertEOLTo == kNuEOLCR) { ch = kNuCharCR; Nu_FunnelPutBlock(pFunnel, &ch, 1); } else if (pFunnel->convertEOLTo == kNuEOLLF) { ch = kNuCharLF; Nu_FunnelPutBlock(pFunnel, &ch, 1); } else if (pFunnel->convertEOLTo == kNuEOLCRLF) { ch = kNuCharCR; Nu_FunnelPutBlock(pFunnel, &ch, 1); ch = kNuCharLF; Nu_FunnelPutBlock(pFunnel, &ch, 1); } else { Assert(0); } } /* * Write a buffer of data, using the EOL conversion associated with the * funnel (if any). * * When converting to the system's EOL convention, we take anything * that looks like an EOL mark and convert it. Doesn't matter if it's * CR, LF, or CRLF; all three get converted to whatever the system uses. */ static NuError Nu_FunnelWriteConvert(NuFunnel* pFunnel, const uint8_t* buffer, uint32_t count) { NuError err = kNuErrNone; uint32_t progressCount = count; /*if (pFunnel->outMaxExceeded) return kNuErrOutMax;*/ if (pFunnel->isFirstWrite) { /* * This is the first write/flush we've done on this Funnel. * Check the data we have buffered to decide whether or not * we want to do text conversions. */ if (pFunnel->convertEOL == kNuConvertAuto) { pFunnel->convertEOL = Nu_DetermineConversion(pFunnel, buffer,count); DBUG(("+++ DetermineConversion --> %ld / %ld (%d)\n", pFunnel->convertEOL, pFunnel->convertEOLFrom, pFunnel->doStripHighASCII)); if (pFunnel->convertEOLFrom == pFunnel->convertEOLTo) { DBUG(("+++ Switching redundant converter off\n")); pFunnel->convertEOL = kNuConvertOff; } /* put it where the progress meter can see it */ if (pFunnel->pProgress != NULL) pFunnel->pProgress->expand.convertEOL = pFunnel->convertEOL; } else if (pFunnel->convertEOL == kNuConvertOn) { if (pFunnel->checkStripHighASCII) { /* assume this part of the buffer is representative */ pFunnel->doStripHighASCII = Nu_CheckHighASCII(pFunnel, buffer, count); } else { Assert(!pFunnel->doStripHighASCII); } DBUG(("+++ Converter is on, convHighASCII=%d\n", pFunnel->doStripHighASCII)); } } Assert(pFunnel->convertEOL != kNuConvertAuto); /* on or off now */ pFunnel->isFirstWrite = false; if (pFunnel->convertEOL == kNuConvertOff) { /* write it straight */ Nu_FunnelPutBlock(pFunnel, buffer, count); } else { /* do the EOL conversion and optional high-bit stripping */ Boolean lastCR = pFunnel->lastCR; /* make local copy */ uint8_t uch; int mask; if (pFunnel->doStripHighASCII) mask = 0x7f; else mask = 0xff; /* * We could get a significant speed improvement here by writing * non-EOL chars as a larger block instead of single bytes. */ while (count--) { uch = (*buffer) & mask; if (uch == kNuCharCR) { Nu_PutEOL(pFunnel); lastCR = true; } else if (uch == kNuCharLF) { if (!lastCR) Nu_PutEOL(pFunnel); lastCR = false; } else { Nu_FunnelPutBlock(pFunnel, &uch, 1); lastCR = false; } buffer++; } pFunnel->lastCR = lastCR; /* save copy */ } /*if (pFunnel->outMaxExceeded) err = kNuErrOutMax;*/ err = Nu_DataSinkGetError(pFunnel->pDataSink); /* update progress counter with pre-LFCR count */ if (err == kNuErrNone && pFunnel->pProgress != NULL) pFunnel->pProgress->uncompressedProgress += progressCount; return err; } /* * Flush any data currently in the funnel. */ NuError Nu_FunnelFlush(NuArchive* pArchive, NuFunnel* pFunnel) { NuError err = kNuErrNone; if (!pFunnel->bufCount) goto bail; err = Nu_FunnelWriteConvert(pFunnel, pFunnel->buffer, pFunnel->bufCount); BailError(err); pFunnel->bufCount = 0; err = Nu_FunnelSendProgressUpdate(pArchive, pFunnel); /* fall through with error */ bail: return err; } /* * Write a bunch of bytes into a funnel. They will be held in the buffer * if they fit, or flushed out the bottom if not. */ NuError Nu_FunnelWrite(NuArchive* pArchive, NuFunnel* pFunnel, const uint8_t* buffer, uint32_t count) { NuError err = kNuErrNone; /*pFunnel->inCount += count;*/ /* * If it will fit into the buffer, just copy it in. */ if (pFunnel->bufCount + count < kNuFunnelBufSize) { if (count == 1) /* minor optimization */ *(pFunnel->buffer + pFunnel->bufCount) = *buffer; else memcpy(pFunnel->buffer + pFunnel->bufCount, buffer, count); pFunnel->bufCount += count; goto bail; } else { /* * Won't fit. We have to flush what we have, and we can either * blow out what we were just given or put it at the start of * the buffer. */ if (pFunnel->bufCount) { err = Nu_FunnelFlush(pArchive, pFunnel); BailError(err); } else { err = Nu_FunnelSendProgressUpdate(pArchive, pFunnel); BailError(err); } Assert(pFunnel->bufCount == 0); if (count >= kNuFunnelBufSize / 4) { /* it's more than 25% of the buffer, just write it now */ err = Nu_FunnelWriteConvert(pFunnel, buffer, count); BailError(err); } else { memcpy(pFunnel->buffer, buffer, count); pFunnel->bufCount = count; } goto bail; } bail: return err; } /* * Set the Funnel's progress state. */ NuError Nu_FunnelSetProgressState(NuFunnel* pFunnel, NuProgressState state) { Assert(pFunnel != NULL); if (pFunnel->pProgress == NULL) return kNuErrNone; pFunnel->pProgress->state = state; return kNuErrNone; } /* * Send a progress update to the application, if they're interested. */ NuError Nu_FunnelSendProgressUpdate(NuArchive* pArchive, NuFunnel* pFunnel) { NuProgressData* pProgress; Assert(pArchive != NULL); Assert(pFunnel != NULL); pProgress = pFunnel->pProgress; if (pProgress == NULL) return kNuErrNone; /* no progress meter attached */ /* don't continue if they're not accepting progress messages */ if (pProgress->progressFunc == NULL) return kNuErrNone; /* other than the choice of arguments, it's pretty much the same story */ return Nu_SendInitialProgress(pArchive, pProgress); } /* * Pull the "doExpand" parameter out of the data source. */ Boolean Nu_FunnelGetDoExpand(NuFunnel* pFunnel) { Assert(pFunnel != NULL); Assert(pFunnel->pDataSink != NULL); return Nu_DataSinkGetDoExpand(pFunnel->pDataSink); } /* * =========================================================================== * NuStraw object * =========================================================================== */ /* * Allocate and initialize a Straw. */ NuError Nu_StrawNew(NuArchive* pArchive, NuDataSource* pDataSource, NuProgressData* pProgress, NuStraw** ppStraw) { NuError err = kNuErrNone; NuStraw* pStraw = NULL; Assert(ppStraw != NULL); Assert(pDataSource != NULL); pStraw = Nu_Calloc(pArchive, sizeof(*pStraw)); BailAlloc(pStraw); pStraw->pDataSource = pDataSource; pStraw->pProgress = pProgress; pStraw->lastProgress = 0; pStraw->lastDisplayed = 0; bail: if (err != kNuErrNone) Nu_StrawFree(pArchive, pStraw); else *ppStraw = pStraw; return err; } /* * Free a Straw. */ NuError Nu_StrawFree(NuArchive* pArchive, NuStraw* pStraw) { if (pStraw == NULL) return kNuErrNone; /* we don't own the data source or progress meter */ Nu_Free(pArchive, pStraw); return kNuErrNone; } /* * Set the Straw's progress state. */ NuError Nu_StrawSetProgressState(NuStraw* pStraw, NuProgressState state) { Assert(pStraw != NULL); Assert(pStraw->pProgress != NULL); pStraw->pProgress->state = state; return kNuErrNone; } /* * Send a progress update to the application, if they're interested. */ NuError Nu_StrawSendProgressUpdate(NuArchive* pArchive, NuStraw* pStraw) { NuProgressData* pProgress; Assert(pArchive != NULL); Assert(pStraw != NULL); pProgress = pStraw->pProgress; if (pProgress == NULL) return kNuErrNone; /* no progress meter attached */ /* don't continue if they're not accepting progress messages */ if (pProgress->progressFunc == NULL) return kNuErrNone; /* other than the choice of arguments, it's pretty much the same story */ return Nu_SendInitialProgress(pArchive, pProgress); } /* * Read data from a straw. */ NuError Nu_StrawRead(NuArchive* pArchive, NuStraw* pStraw, uint8_t* buffer, long len) { NuError err; Assert(pArchive != NULL); Assert(pStraw != NULL); Assert(buffer != NULL); Assert(len > 0); /* * No buffering going on, so this is straightforward. */ err = Nu_DataSourceGetBlock(pStraw->pDataSource, buffer, len); BailError(err); /* * Progress updating for adding is a little more complicated than * for extracting. When extracting, the funnel controls the size * of the output buffer, and only pushes an update when the output * buffer fills. Here, we don't know how much will be asked for at * a time, so we have to pace the updates or we risk flooding the * application. * * We also have another problem: we want to indicate how much data * has been processed, not how much data is *about* to be processed. * So we have to set the percentage based on how much was requested * on the previous call. (This assumes that whatever they asked for * last time has already been fully processed.) */ if (pStraw->pProgress != NULL) { pStraw->pProgress->uncompressedProgress = pStraw->lastProgress; pStraw->lastProgress += len; if (!pStraw->pProgress->uncompressedProgress || (pStraw->pProgress->uncompressedProgress - pStraw->lastDisplayed > (kNuFunnelBufSize * 3 / 4))) { err = Nu_StrawSendProgressUpdate(pArchive, pStraw); pStraw->lastDisplayed = pStraw->pProgress->uncompressedProgress; BailError(err); } } bail: return err; } /* * Rewind a straw. This rewinds the underlying data source, and resets * some progress counters. */ NuError Nu_StrawRewind(NuArchive* pArchive, NuStraw* pStraw) { Assert(pStraw != NULL); Assert(pStraw->pDataSource != NULL); pStraw->lastProgress = 0; pStraw->lastDisplayed = 0; return Nu_DataSourceRewind(pStraw->pDataSource); } nulib2-3.1.0/nufxlib/INSTALL000066400000000000000000000172301316100516500154070ustar00rootroot00000000000000Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. nulib2-3.1.0/nufxlib/Lzc.c000066400000000000000000001111601316100516500152470ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * This is the LZW implementation found in the UNIX "compress" command, * sometimes referred to as "LZC". GS/ShrinkIt v1.1 can unpack threads * in LZC format, P8 ShrinkIt cannot. The only other application that * is known to create LZC threads is the original NuLib. * * There's a lot of junk in here for the sake of smaller systems (e.g. MSDOS) * and pre-ANSI compilers. For the most part it has been left unchanged. * I have done some minor reformatting, and have undone the authors' * penchant for assigning variables inside function call statements, but * for the most part it is as it was. (A much cleaner implementation * could probably be derived by adapting the NufxLib Lzw.c code...) */ #include "NufxLibPriv.h" #ifdef ENABLE_LZC /*#define DEBUG_LZC*/ /* * Selected definitions from compress.h. */ typedef uint16_t CODE; typedef uint8_t UCHAR; typedef uint32_t INTCODE; typedef uint32_t HASH; typedef int FLAG; #ifndef FALSE /* let's get some sense to this */ #define FALSE 0 #define TRUE !FALSE #endif #define CONST const #ifndef FAR # define FAR #endif #define NULLPTR(type) ((type FAR *) NULL) #define ALLOCTYPE void #define INITBITS 9 #define MINBITS 12 #define MAXMAXBITS 16 #define MAXBITS MAXMAXBITS #define DFLTBITS MAXBITS #define UNUSED ((CODE)0) /* Indicates hash table value unused */ #define CLEAR ((CODE)256) /* Code requesting table to be cleared */ #define FIRSTFREE ((CODE)257) /* First free code for token encoding */ #define MAXTOKLEN 512 /* Max chars in token; size of buffer */ #define OK kNuErrNone /* Result codes from functions: */ #define BIT_MASK 0x1f #define BLOCK_MASK 0x80 #define CHECK_GAP 10000L /* ratio check interval, for COMP40 */ static UCHAR gNu_magic_header[] = { 0x1F,0x9D }; /* don't need these */ /*#define SPLIT_HT 1*/ /*#define SPLIT_PFX 1*/ /*#define COMP40 1*/ #define NOMEM kNuErrMalloc /* Ran out of memory */ #define TOKTOOBIG kNuErrBadData /* Token longer than MAXTOKLEN chars */ #define READERR kNuErrFileRead /* I/O error on input */ #define WRITEERR kNuErrFileWrite /* I/O error on output */ #define CODEBAD kNuErrBadData /* Infile contained a bad token code */ #define TABLEBAD kNuErrInternal /* The tables got corrupted (!) */ #define NOSAVING kNuErrNone /* no saving in file size */ /* * Normally in COMPUSI.UNI. */ static inline ALLOCTYPE FAR * Nu_LZC_emalloc(NuArchive* pArchive, uint32_t x, int y) { return Nu_Malloc(pArchive, x*y); } static inline void Nu_LZC_efree(NuArchive* pArchive, ALLOCTYPE FAR * ptr) { Nu_Free(pArchive, ptr); } /*@H************************ < COMPRESS API > **************************** * $@(#) compapi.c,v 4.3d 90/01/18 03:00:00 don Release ^ * * * * compress : compapi.c * * * * port by : Donald J. Gloistein * * * * Source, Documentation, Object Code: * * released to Public Domain. This code is based on code as documented * * below in release notes. * * * *--------------------------- Module Description --------------------------* * Contains source code for modified Lempel-Ziv method (LZW) compression * * and decompression. * * * * This code module can be maintained to keep current on releases on the * * Unix system. The command shell and dos modules can remain the same. * * * *--------------------------- Implementation Notes --------------------------* * * * compiled with : compress.h compress.fns compress.c * * linked with : compress.obj compusi.obj * * * * problems: * * * * * * CAUTION: Uses a number of defines for access and speed. If you change * * anything, make sure about side effects. * * * * Compression: * * Algorithm: use open addressing double hashing (no chaining) on the * * prefix code / next character combination. We do a variant of Knuth's * * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime * * secondary probe. Here, the modular division first probe is gives way * * to a faster exclusive-or manipulation. * * Also block compression with an adaptive reset was used in original code, * * whereby the code table is cleared when the compression ration decreases * * but after the table fills. This was removed from this edition. The table * * is re-sized at this point when it is filled , and a special CLEAR code is * * generated for the decompressor. This results in some size difference from * * straight version 4.0 joe Release. But it is fully compatible in both v4.0 * * and v4.01 * * * * Decompression: * * This routine adapts to the codes in the file building the "string" table * * on-the-fly; requiring no table to be stored in the compressed file. The * * tables used herein are shared with those of the compress() routine. * * * * Initials ---- Name --------------------------------- * * DjG Donald J. Gloistein, current port to MsDos 16 bit * * Plus many others, see rev.hst file for full list * * LvR Lyle V. Rains, many thanks for improved implementation * * of the compression and decompression routines. * *************************************************************************@H*/ #include /* * LZC state, largely variables with non-local scope. */ typedef struct LZCState { NuArchive* pArchive; int doCalcCRC; uint16_t crc; /* compression */ NuStraw* pStraw; FILE* outfp; long uncompRemaining; /* expansion */ FILE* infp; NuFunnel* pFunnel; uint16_t* pCrc; long compRemaining; /* * Globals from Compress sources. */ int offset; long int in_count ; /* length of input */ long int bytes_out; /* length of compressed output */ INTCODE prefxcode, nextfree; INTCODE highcode; INTCODE maxcode; HASH hashsize; int bits; char FAR *sfx; #if (SPLIT_PFX) CODE FAR *pfx[2]; #else CODE FAR *pfx; #endif #if (SPLIT_HT) CODE FAR *ht[2]; #else CODE FAR *ht; #endif #ifdef COMP40 long int ratio; long checkpoint; /* initialized to CHECK_GAP */ #endif #ifdef DEBUG_LZC int debug; /* initialized to FALSE */ #endif NuError exit_stat; int maxbits; /* initialized to DFLTBITS */ int block_compress; /* initialized to BLOCK_MASK */ /* * Static local variables. Some of these were explicitly initialized * to zero. */ INTCODE oldmaxcode; /* alloc_tables */ HASH oldhashsize; /* alloc_tables */ int oldbits; /* putcode */ UCHAR outbuf[MAXBITS]; /* putcode */ int prevbits; /* nextcode */ int size; /* nextcode */ UCHAR inbuf[MAXBITS]; /* nextcode */ } LZCState; /* * The following two parameter tables are the hash table sizes and * maximum code values for various code bit-lengths. The requirements * are that Hashsize[n] must be a prime number and Maxcode[n] must be less * than Maxhash[n]. Table occupancy factor is (Maxcode - 256)/Maxhash. * Note: I am using a lower Maxcode for 16-bit codes in order to * keep the hash table size less than 64k entries. */ static CONST HASH gNu_hs[] = { 0x13FF, /* 12-bit codes, 75% occupancy */ 0x26C3, /* 13-bit codes, 80% occupancy */ 0x4A1D, /* 14-bit codes, 85% occupancy */ 0x8D0D, /* 15-bit codes, 90% occupancy */ 0xFFD9 /* 16-bit codes, 94% occupancy, 6% of code values unused */ }; #define Hashsize(maxb) (gNu_hs[(maxb) -MINBITS]) static CONST INTCODE gNu_mc[] = { 0x0FFF, /* 12-bit codes */ 0x1FFF, /* 13-bit codes */ 0x3FFF, /* 14-bit codes */ 0x7FFF, /* 15-bit codes */ 0xEFFF /* 16-bit codes, 6% of code values unused */ }; #define Maxcode(maxb) (gNu_mc[(maxb) -MINBITS]) #ifdef __STDC__ #ifdef DEBUG_LZC #define allocx(type, ptr, size) \ (((ptr) = (type FAR *) Nu_LZC_emalloc(pArchive, (uint32_t)(size),sizeof(type))) == NULLPTR(type) \ ? (DBUG(("%s: "#ptr" -- ", "LZC")), NOMEM) : OK \ ) #else #define allocx(type,ptr,size) \ (((ptr) = (type FAR *) Nu_LZC_emalloc(pArchive, (uint32_t)(size),sizeof(type))) == NULLPTR(type) \ ? NOMEM : OK \ ) #endif #else #define allocx(type,ptr,size) \ (((ptr) = (type FAR *) Nu_LZC_emalloc(pArchive, (uint32_t)(size),sizeof(type))) == NULLPTR(type) \ ? NOMEM : OK \ ) #endif #define free_array(type,ptr,offset) \ if (ptr != NULLPTR(type)) { \ Nu_LZC_efree(pArchive, (ALLOCTYPE FAR *)((ptr) + (offset))); \ (ptr) = NULLPTR(type); \ } /* * Macro to allocate new memory to a pointer with an offset value. */ #define alloc_array(type, ptr, size, offset) \ ( allocx(type, ptr, (size) - (offset)) != OK \ ? NOMEM \ : (((ptr) -= (offset)), OK) \ ) /*static char FAR *sfx = NULLPTR(char) ;*/ #define suffix(code) pLzcState->sfx[code] #if (SPLIT_PFX) /*static CODE FAR *pfx[2] = {NULLPTR(CODE), NULLPTR(CODE)};*/ #else /*static CODE FAR *pfx = NULLPTR(CODE);*/ #endif #if (SPLIT_HT) /*static CODE FAR *ht[2] = {NULLPTR(CODE),NULLPTR(CODE)};*/ #else /*static CODE FAR *ht = NULLPTR(CODE);*/ #endif static int Nu_LZC_alloc_tables(LZCState* pLzcState, INTCODE newmaxcode, HASH newhashsize) { NuArchive* pArchive = pLzcState->pArchive; /*static INTCODE oldmaxcode = 0;*/ /*static HASH oldhashsize = 0;*/ if (newhashsize > pLzcState->oldhashsize) { #if (SPLIT_HT) free_array(CODE,pLzcState->ht[1], 0); free_array(CODE,pLzcState->ht[0], 0); #else free_array(CODE,pLzcState->ht, 0); #endif pLzcState->oldhashsize = 0; } if (newmaxcode > pLzcState->oldmaxcode) { #if (SPLIT_PFX) free_array(CODE,pLzcState->pfx[1], 128); free_array(CODE,pLzcState->pfx[0], 128); #else free_array(CODE,pLzcState->pfx, 256); #endif free_array(char,pLzcState->sfx, 256); if ( alloc_array(char, pLzcState->sfx, newmaxcode + 1, 256) #if (SPLIT_PFX) || alloc_array(CODE, pLzcState->pfx[0], (newmaxcode + 1) / 2, 128) || alloc_array(CODE, pLzcState->pfx[1], (newmaxcode + 1) / 2, 128) #else || alloc_array(CODE, pLzcState->pfx, (newmaxcode + 1), 256) #endif ) { pLzcState->oldmaxcode = 0; pLzcState->exit_stat = NOMEM; return(NOMEM); } pLzcState->oldmaxcode = newmaxcode; } if (newhashsize > pLzcState->oldhashsize) { if ( #if (SPLIT_HT) alloc_array(CODE, pLzcState->ht[0], (newhashsize / 2) + 1, 0) || alloc_array(CODE, pLzcState->ht[1], newhashsize / 2, 0) #else alloc_array(CODE, pLzcState->ht, newhashsize, 0) #endif ) { pLzcState->oldhashsize = 0; pLzcState->exit_stat = NOMEM; return(NOMEM); } pLzcState->oldhashsize = newhashsize; } return (OK); } # if (SPLIT_PFX) /* * We have to split pfx[] table in half, * because it's potentially larger than 64k bytes. */ # define prefix(code) (pLzcState->pfx[(code) & 1][(code) >> 1]) # else /* * Then pfx[] can't be larger than 64k bytes, * or we don't care if it is, so we don't split. */ # define prefix(code) (pLzcState->pfx[code]) # endif /* The initializing of the tables can be done quicker with memset() */ /* but this way is portable through out the memory models. */ /* If you use Microsoft halloc() to allocate the arrays, then */ /* include the pragma #pragma function(memset) and make sure that */ /* the length of the memory block is not greater than 64K. */ /* This also means that you MUST compile in a model that makes the */ /* default pointers to be far pointers (compact or large models). */ /* See the file COMPUSI.DOS to modify function emalloc(). */ # if (SPLIT_HT) /* * We have to split ht[] hash table in half, * because it's potentially larger than 64k bytes. */ # define probe(hash) (pLzcState->ht[(hash) & 1][(hash) >> 1]) # define init_tables() \ { \ hash = pLzcState->hashsize >> 1; \ pLzcState->ht[0][hash] = 0; \ while (hash--) pLzcState->ht[0][hash] = pLzcState->ht[1][hash] = 0; \ pLzcState->highcode = ~(~(INTCODE)0 << (pLzcState->bits = INITBITS)); \ pLzcState->nextfree = (pLzcState->block_compress ? FIRSTFREE : 256); \ } # else /* * Then ht[] can't be larger than 64k bytes, * or we don't care if it is, so we don't split. */ # define probe(hash) (pLzcState->ht[hash]) # define init_tables() \ { \ hash = pLzcState->hashsize; \ while (hash--) pLzcState->ht[hash] = 0; \ pLzcState->highcode = ~(~(INTCODE)0 << (pLzcState->bits = INITBITS)); \ pLzcState->nextfree = (pLzcState->block_compress ? FIRSTFREE : 256); \ } # endif /* * =========================================================================== * Compression * =========================================================================== */ static void Nu_prratio(long int num, long int den) { register int q; /* Doesn't need to be long */ if(num > 214748L) { /* 2147483647/10000 */ q = (int) (num / (den / 10000L)); } else { q = (int) (10000L * num / den); /* Long calculations, though */ } if (q < 0) { DBUG(("-")); q = -q; } DBUG(("%d.%02d%%", q / 100, q % 100)); } #ifdef COMP40 /* table clear for block compress */ /* this is for adaptive reset present in version 4.0 joe release */ /* DjG, sets it up and returns TRUE to compress and FALSE to not compress */ static int Nu_LZC_cl_block(LZCState* pLzcState) { register long int rat; pLzcState->checkpoint = pLzcState->in_count + CHECK_GAP; #ifdef DEBUG_LZC if ( pLzcState->debug ) { DBUG(( "count: %ld, ratio: ", pLzcState->in_count )); Nu_prratio ( pLzcState->in_count, pLzcState->bytes_out ); DBUG(( "\n")); } #endif if(pLzcState->in_count > 0x007fffff) { /* shift will overflow */ rat = pLzcState->bytes_out >> 8; if(rat == 0) /* Don't divide by zero */ rat = 0x7fffffff; else rat = pLzcState->in_count / rat; } else rat = (pLzcState->in_count << 8) / pLzcState->bytes_out; /* 8 fractional bits */ if ( rat > pLzcState->ratio ){ pLzcState->ratio = rat; return FALSE; } else { pLzcState->ratio = 0; #ifdef DEBUG_LZC if(pLzcState->debug) { DBUG(( "clear\n" )); } #endif return TRUE; /* clear the table */ } return FALSE; /* don't clear the table */ } #endif static CONST UCHAR gNu_rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; static void Nu_LZC_putcode(LZCState* pLzcState, INTCODE code, register int bits) { /*static int oldbits = 0;*/ /*static UCHAR outbuf[MAXBITS];*/ register UCHAR *buf; register int shift; if (bits != pLzcState->oldbits) { if (bits == 0) { /* bits == 0 means EOF, write the rest of the buffer. */ if (pLzcState->offset > 0) { fwrite(pLzcState->outbuf,1,(pLzcState->offset +7) >> 3, pLzcState->outfp); pLzcState->bytes_out += ((pLzcState->offset +7) >> 3); } pLzcState->offset = 0; pLzcState->oldbits = 0; fflush(pLzcState->outfp); return; } else { /* Change the code size. We must write the whole buffer, * because the expand side won't discover the size change * until after it has read a buffer full. */ if (pLzcState->offset > 0) { fwrite(pLzcState->outbuf, 1, pLzcState->oldbits, pLzcState->outfp); pLzcState->bytes_out += pLzcState->oldbits; pLzcState->offset = 0; } pLzcState->oldbits = bits; #ifdef DEBUG_LZC if ( pLzcState->debug ) { DBUG(( "\nChange to %d bits\n", bits )); } #endif /* DEBUG_LZC */ } } /* Get to the first byte. */ buf = pLzcState->outbuf + ((shift = pLzcState->offset) >> 3); if ((shift &= 7) != 0) { *(buf) |= (*buf & gNu_rmask[shift]) | (UCHAR)(code << shift); *(++buf) = (UCHAR)(code >> (8 - shift)); if (bits + shift > 16) *(++buf) = (UCHAR)(code >> (16 - shift)); } else { /* Special case for fast execution */ *(buf) = (UCHAR)code; *(++buf) = (UCHAR)(code >> 8); } if ((pLzcState->offset += bits) == (bits << 3)) { pLzcState->bytes_out += bits; fwrite(pLzcState->outbuf,1,bits,pLzcState->outfp); pLzcState->offset = 0; } return; } #define kNuLZCEOF (-1) /* * Get the next byte from the input straw. Also updates the CRC * if "doCalcCRC" is set to true. * * Returns kNuLZCEOF as the value when we're out of data. */ static NuError Nu_LZCGetcCRC(LZCState* pLzcState, int* pSym) { NuError err; uint8_t c; if (!pLzcState->uncompRemaining) { *pSym = kNuLZCEOF; return kNuErrNone; } err = Nu_StrawRead(pLzcState->pArchive, pLzcState->pStraw, &c, 1); if (err == kNuErrNone) { if (pLzcState->doCalcCRC) pLzcState->crc = Nu_CalcCRC16(pLzcState->crc, &c, 1); *pSym = c; pLzcState->uncompRemaining--; } return err; } /* * compress stdin to stdout */ static void Nu_LZC_compress(LZCState* pLzcState, uint32_t* pDstLen) { int c,adjbits; register HASH hash; register INTCODE code; HASH hashf[256]; Assert(pLzcState->outfp != NULL); pLzcState->maxcode = Maxcode(pLzcState->maxbits); pLzcState->hashsize = Hashsize(pLzcState->maxbits); #ifdef COMP40 /* Only needed for adaptive reset */ pLzcState->checkpoint = CHECK_GAP; pLzcState->ratio = 0; #endif adjbits = pLzcState->maxbits -10; for (c = 256; --c >= 0; ){ hashf[c] = ((( c &0x7) << 7) ^ c) << adjbits; } pLzcState->exit_stat = OK; if (Nu_LZC_alloc_tables(pLzcState, pLzcState->maxcode, pLzcState->hashsize)) /* exit_stat already set */ return; init_tables(); #if 0 /* if not zcat or filter */ if(is_list && !zcat_flg) { /* Open output file */ if (freopen(ofname, WRITE_FILE_TYPE, pLzcState->outfp) == NULL) { pLzcState->exit_stat = NOTOPENED; return; } if (!quiet) fprintf(stderr, "%s: ",ifname); /*#if 0*/ setvbuf(Xstdout,zbuf,_IOFBF,ZBUFSIZE); } #endif /* * Check the input stream for previously seen strings. We keep * adding characters to the previously seen prefix string until we * get a character which forms a new (unseen) string. We then send * the code for the previously seen prefix string, and add the new * string to our tables. The check for previous strings is done by * hashing. If the code for the hash value is unused, then we have * a new string. If the code is used, we check to see if the prefix * and suffix values match the current input; if so, we have found * a previously seen string. Otherwise, we have a hash collision, * and we try secondary hash probes until we either find the current * string, or we find an unused entry (which indicates a new string). */ if (1 /*!nomagic*/) { putc(gNu_magic_header[0], pLzcState->outfp); putc(gNu_magic_header[1], pLzcState->outfp); putc((char)(pLzcState->maxbits | pLzcState->block_compress), pLzcState->outfp); if(ferror(pLzcState->outfp)){ /* check it on entry */ pLzcState->exit_stat = WRITEERR; return; } pLzcState->bytes_out = 3L; /* includes 3-byte header mojo */ } else pLzcState->bytes_out = 0L; /* no 3-byte header mojo */ pLzcState->in_count = 1L; pLzcState->offset = 0; pLzcState->exit_stat = Nu_LZCGetcCRC(pLzcState, &c); if (pLzcState->exit_stat != kNuErrNone) return; pLzcState->prefxcode = (INTCODE)c; while (1) { pLzcState->exit_stat = Nu_LZCGetcCRC(pLzcState, &c); if (pLzcState->exit_stat != kNuErrNone) return; if (c == kNuLZCEOF) break; pLzcState->in_count++; hash = pLzcState->prefxcode ^ hashf[c]; /* I need to check that my hash value is within range * because my 16-bit hash table is smaller than 64k. */ if (hash >= pLzcState->hashsize) hash -= pLzcState->hashsize; if ((code = (INTCODE)probe(hash)) != UNUSED) { if (suffix(code) != (char)c || (INTCODE)prefix(code) != pLzcState->prefxcode) { /* hashdelta is subtracted from hash on each iteration of * the following hash table search loop. I compute it once * here to remove it from the loop. */ HASH hashdelta = (0x120 - c) << (adjbits); do { /* rehash and keep looking */ Assert(code >= FIRSTFREE && code <= pLzcState->maxcode); if (hash >= hashdelta) hash -= hashdelta; else hash += (pLzcState->hashsize - hashdelta); Assert(hash < pLzcState->hashsize); if ((code = (INTCODE)probe(hash)) == UNUSED) goto newcode; } while (suffix(code) != (char)c || (INTCODE)prefix(code) != pLzcState->prefxcode); } pLzcState->prefxcode = code; } else { newcode: { Nu_LZC_putcode(pLzcState, pLzcState->prefxcode, pLzcState->bits); code = pLzcState->nextfree; Assert(hash < pLzcState->hashsize); Assert(code >= FIRSTFREE); Assert(code <= pLzcState->maxcode + 1); if (code <= pLzcState->maxcode) { probe(hash) = (CODE)code; prefix(code) = (CODE)pLzcState->prefxcode; suffix(code) = (char)c; if (code > pLzcState->highcode) { pLzcState->highcode += code; ++pLzcState->bits; } pLzcState->nextfree = code + 1; } #ifdef COMP40 else if (pLzcState->in_count >= pLzcState->checkpoint && pLzcState->block_compress ) { if (Nu_LZC_cl_block(pLzcState)){ #else else if (pLzcState->block_compress){ #endif Nu_LZC_putcode(pLzcState, (INTCODE)c, pLzcState->bits); Nu_LZC_putcode(pLzcState, CLEAR, pLzcState->bits); init_tables(); pLzcState->exit_stat = Nu_LZCGetcCRC(pLzcState, &c); if (pLzcState->exit_stat != kNuErrNone) return; if (c == kNuLZCEOF) break; pLzcState->in_count++; #ifdef COMP40 } #endif } pLzcState->prefxcode = (INTCODE)c; } } } Nu_LZC_putcode(pLzcState, pLzcState->prefxcode, pLzcState->bits); Nu_LZC_putcode(pLzcState, CLEAR, 0); /* * Print out stats on stderr */ if(1 /*zcat_flg == 0 && !quiet*/) { #ifdef DEBUG_LZC DBUG(( "%ld chars in, (%ld bytes) out, compression factor: ", pLzcState->in_count, pLzcState->bytes_out )); Nu_prratio( pLzcState->in_count, pLzcState->bytes_out ); DBUG(( "\n")); DBUG(( "\tCompression as in compact: " )); Nu_prratio( pLzcState->in_count-pLzcState->bytes_out, pLzcState->in_count ); DBUG(( "\n")); DBUG(( "\tLargest code (of last block) was %d (%d bits)\n", pLzcState->prefxcode - 1, pLzcState->bits )); #else DBUG(( "Compression: " )); Nu_prratio( pLzcState->in_count-pLzcState->bytes_out, pLzcState->in_count ); #endif /* DEBUG_LZC */ } if(pLzcState->bytes_out > pLzcState->in_count) /* if no savings */ pLzcState->exit_stat = NOSAVING; *pDstLen = pLzcState->bytes_out; return ; } /* * NufxLib interface to LZC compression. */ static NuError Nu_CompressLZC(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc, int maxbits) { NuError err = kNuErrNone; LZCState lzcState; memset(&lzcState, 0, sizeof(lzcState)); lzcState.pArchive = pArchive; lzcState.pStraw = pStraw; lzcState.outfp = fp; lzcState.uncompRemaining = srcLen; if (pCrc == NULL) { lzcState.doCalcCRC = false; } else { lzcState.doCalcCRC = true; lzcState.crc = *pCrc; } lzcState.maxbits = maxbits; lzcState.block_compress = BLOCK_MASK; /* enabled */ Nu_LZC_compress(&lzcState, pDstLen); err = lzcState.exit_stat; DBUG(("+++ LZC_compress returned with %d\n", err)); #if (SPLIT_HT) free_array(CODE,lzcState.ht[1], 0); free_array(CODE,lzcState.ht[0], 0); #else free_array(CODE,lzcState.ht, 0); #endif #if (SPLIT_PFX) free_array(CODE,lzcState.pfx[1], 128); free_array(CODE,lzcState.pfx[0], 128); #else free_array(CODE,lzcState.pfx, 256); #endif free_array(char,lzcState.sfx, 256); if (pCrc != NULL) *pCrc = lzcState.crc; return err; } NuError Nu_CompressLZC12(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc) { return Nu_CompressLZC(pArchive, pStraw, fp, srcLen, pDstLen, pCrc, 12); } NuError Nu_CompressLZC16(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc) { return Nu_CompressLZC(pArchive, pStraw, fp, srcLen, pDstLen, pCrc, 16); } /* * =========================================================================== * Expansion * =========================================================================== */ /* * Write the next byte to the output funnel. Also updates the CRC * if "doCalcCRC" is set to true. * * Returns kNuLZCEOF as the value when we're out of data. */ static NuError Nu_LZCPutcCRC(LZCState* pLzcState, char c) { NuError err; err = Nu_FunnelWrite(pLzcState->pArchive, pLzcState->pFunnel, (uint8_t*) &c, 1); if (pLzcState->doCalcCRC) pLzcState->crc = Nu_CalcCRC16(pLzcState->crc, (uint8_t*) &c, 1); return err; } static int Nu_LZC_nextcode(LZCState* pLzcState, INTCODE* codeptr) /* Get the next code from input and put it in *codeptr. * Return (TRUE) on success, or return (FALSE) on end-of-file. * Adapted from COMPRESS V4.0. */ { /*static int prevbits = 0;*/ register INTCODE code; /*static int size;*/ /*static UCHAR inbuf[MAXBITS];*/ register int shift; UCHAR *bp; /* If the next entry is a different bit-size than the preceeding one * then we must adjust the size and scrap the old buffer. */ if (pLzcState->prevbits != pLzcState->bits) { pLzcState->prevbits = pLzcState->bits; pLzcState->size = 0; } /* If we can't read another code from the buffer, then refill it. */ shift = pLzcState->offset; if (pLzcState->size - shift < pLzcState->bits) { /* Read more input and convert size from # of bytes to # of bits */ long getSize; getSize = pLzcState->bits; if (getSize > pLzcState->compRemaining) getSize = pLzcState->compRemaining; if (!getSize) /* act like EOF */ return FALSE; pLzcState->size = fread(pLzcState->inbuf, 1, getSize, pLzcState->infp) << 3; if (pLzcState->size <= 0 || ferror(pLzcState->infp)) return(FALSE); pLzcState->compRemaining -= getSize; pLzcState->offset = shift = 0; } /* Get to the first byte. */ bp = pLzcState->inbuf + (shift >> 3); /* Get first part (low order bits) */ code = (*bp++ >> (shift &= 7)); /* high order bits. */ code |= *bp++ << (shift = 8 - shift); if ((shift += 8) < pLzcState->bits) code |= *bp << shift; *codeptr = code & pLzcState->highcode; pLzcState->offset += pLzcState->bits; return (TRUE); } static void Nu_LZC_decompress(LZCState* pLzcState, uint32_t compressedLen) { NuArchive* pArchive = pLzcState->pArchive; register int i; register INTCODE code; char sufxchar = 0; INTCODE savecode; FLAG fulltable = FALSE, cleartable; /*static*/ char *token= NULL; /* String buffer to build token */ /*static*/ int maxtoklen = MAXTOKLEN; int flags; Assert(pLzcState->infp != NULL); pLzcState->exit_stat = OK; if (compressedLen < 3) { /* not long enough to be valid! */ pLzcState->exit_stat = kNuErrBadData; Nu_ReportError(NU_BLOB, pLzcState->exit_stat, "thread too short to be valid LZC"); return; } pLzcState->compRemaining = compressedLen; /* * This comes out of "compress.c" rather than "compapi.c". */ if ((getc(pLzcState->infp)!=(gNu_magic_header[0] & 0xFF)) || (getc(pLzcState->infp)!=(gNu_magic_header[1] & 0xFF))) { DBUG(("not in compressed format\n")); pLzcState->exit_stat = kNuErrBadData; return; } flags = getc(pLzcState->infp); /* set -b from file */ pLzcState->block_compress = flags & BLOCK_MASK; pLzcState->maxbits = flags & BIT_MASK; if(pLzcState->maxbits > MAXBITS) { DBUG(("compressed with %d bits, can only handle %d bits\n", pLzcState->maxbits, MAXBITS)); pLzcState->exit_stat = kNuErrBadData; return; } pLzcState->compRemaining -= 3; /* Initialze the token buffer. */ token = (char*)Nu_Malloc(pArchive, maxtoklen); if (token == NULL) { pLzcState->exit_stat = NOMEM; return; } if (Nu_LZC_alloc_tables(pLzcState, pLzcState->maxcode = ~(~(INTCODE)0 << pLzcState->maxbits),0)) /* exit_stat already set */ return; #if 0 /* if not zcat or filter */ if(is_list && !zcat_flg) { /* Open output file */ if (freopen(ofname, WRITE_FILE_TYPE, stdout) == NULL) { pLzcState->exit_stat = NOTOPENED; return; } if (!quiet) fprintf(stderr, "%s: ",ifname); /*#if 0*/ setvbuf(stdout,xbuf,_IOFBF,XBUFSIZE); } #endif cleartable = TRUE; savecode = CLEAR; pLzcState->offset = 0; do { if ((code = savecode) == CLEAR && cleartable) { pLzcState->highcode = ~(~(INTCODE)0 << (pLzcState->bits = INITBITS)); fulltable = FALSE; pLzcState->nextfree = (cleartable = pLzcState->block_compress) == FALSE ? 256 : FIRSTFREE; if (!Nu_LZC_nextcode(pLzcState, &pLzcState->prefxcode)) break; /*putc((*/sufxchar = (char)pLzcState->prefxcode/*), stdout)*/; pLzcState->exit_stat = Nu_LZCPutcCRC(pLzcState, sufxchar); if (pLzcState->exit_stat != kNuErrNone) return; continue; } i = 0; if (code >= pLzcState->nextfree && !fulltable) { if (code != pLzcState->nextfree){ DBUG(("ERROR: code (0x%x) != nextfree (0x%x)\n", code, pLzcState->nextfree)); pLzcState->exit_stat = CODEBAD; return ; /* Non-existant code */ } /* Special case for sequence KwKwK (see text of article) */ code = pLzcState->prefxcode; token[i++] = sufxchar; } /* Build the token string in reverse order by chasing down through * successive prefix tokens of the current token. Then output it. */ while (code >= 256) { #ifdef DEBUG_LZC /* These are checks to ease paranoia. Prefix codes must decrease * monotonically, otherwise we must have corrupt tables. We can * also check that we haven't overrun the token buffer. */ if (code <= (INTCODE)prefix(code)){ pLzcState->exit_stat= TABLEBAD; return; } #endif if (i >= maxtoklen) { maxtoklen *= 2; /* double the size of the token buffer */ if ((token = Nu_Realloc(pArchive, token, maxtoklen)) == NULL) { pLzcState->exit_stat = TOKTOOBIG; return; } } token[i++] = suffix(code); code = (INTCODE)prefix(code); } /*putc(*/sufxchar = (char)code/*, stdout)*/; pLzcState->exit_stat = Nu_LZCPutcCRC(pLzcState, sufxchar); while (--i >= 0) { /*putc(token[i], stdout);*/ pLzcState->exit_stat = Nu_LZCPutcCRC(pLzcState, token[i]); } if (pLzcState->exit_stat != kNuErrNone) return; /* If table isn't full, add new token code to the table with * codeprefix and codesuffix, and remember current code. */ if (!fulltable) { code = pLzcState->nextfree; Assert(256 <= code && code <= pLzcState->maxcode); prefix(code) = (CODE)pLzcState->prefxcode; suffix(code) = sufxchar; pLzcState->prefxcode = savecode; if (code++ == pLzcState->highcode) { if (pLzcState->highcode >= pLzcState->maxcode) { fulltable = TRUE; --code; } else { ++pLzcState->bits; pLzcState->highcode += code; /* nextfree == highcode + 1 */ } } pLzcState->nextfree = code; } } while (Nu_LZC_nextcode(pLzcState, &savecode)); pLzcState->exit_stat = (ferror(pLzcState->infp))? READERR : OK; Nu_Free(pArchive, token); return ; } /* * NufxLib interface to LZC expansion. */ NuError Nu_ExpandLZC(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc) { NuError err = kNuErrNone; LZCState lzcState; memset(&lzcState, 0, sizeof(lzcState)); lzcState.pArchive = pArchive; lzcState.infp = infp; lzcState.pFunnel = pFunnel; if (pCrc == NULL) { lzcState.doCalcCRC = false; } else { lzcState.doCalcCRC = true; lzcState.crc = *pCrc; } Nu_LZC_decompress(&lzcState, pThread->thCompThreadEOF); err = lzcState.exit_stat; DBUG(("+++ LZC_decompress returned with %d\n", err)); #if (SPLIT_HT) free_array(CODE,lzcState.ht[1], 0); free_array(CODE,lzcState.ht[0], 0); #else free_array(CODE,lzcState.ht, 0); #endif #if (SPLIT_PFX) free_array(CODE,lzcState.pfx[1], 128); free_array(CODE,lzcState.pfx[0], 128); #else free_array(CODE,lzcState.pfx, 256); #endif free_array(char,lzcState.sfx, 256); if (pCrc != NULL) *pCrc = lzcState.crc; return err; } #endif /*ENABLE_LZC*/ nulib2-3.1.0/nufxlib/Lzw.c000066400000000000000000001533141316100516500153020ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * ShrinkIt LZW functions. The original code was developed by Kent Dickey * and Andy Nicholas. * * Unisys holds US patent #4,558,302 (filed June 20, 1983 and issued December * 10, 1985). A policy set in 1995 specifies the lifetime of a patent as * the longer of 20 years from the date of application or 17 years from the * date of grant, so the Unisys LZW patent expired on June 20, 2003 in the * USA. Patents in some other countries expire after July 7, 2004. * * An older note: * * The Unisys patent is one of many that covers LZW compression, but Unisys * is the only company actively attacking anyone who uses it. The statement * Unisys made regarding LZW (and, specifically, GIF and TIFF-LZW) says: * * Q: I use LZW in my programs, but not for GIF or TIFF graphics. What should * I do? * A: If you are not a business, and the programs are for your own personal * non-commercial or not-for-profit use, Unisys does not require you to * obtain a license. If they are used as part of a business and/or you sell * the programs for commercial or for-profit purposes, then you must contact * the Welch Patent Licensing Department at Unisys and explain your * circumstances. They will have a license agreement for your application of * their LZW algorithm. * * According to this, the use of LZW in NufxLib has never required a license. */ #include "NufxLibPriv.h" #ifdef ENABLE_LZW /* the LZW algorithms operate on 4K chunks */ #define kNuLZWBlockSize 4096 /* a little padding to avoid mysterious crashes on bad data */ #define kNuSafetyPadding 64 #define kNuLZWClearCode 0x0100 #define kNuLZWFirstCode 0x0101 /* sometimes we want to get *really* verbose rather late in a large archive */ #ifdef DEBUG_LZW static Boolean gNuDebugVerbose = true; #define DBUG_LZW(x) { if (gNuDebugVerbose) { DBUG(x); } } #else #define DBUG_LZW ((void)0) #endif /* * =========================================================================== * Compression * =========================================================================== */ /* * We use a hash function borrowed from UNIX compress, which is described * in the v4.3 sources as: * * Algorithm: use open addressing double hashing (no chaining) on the * prefix code / next character combination. We do a variant of Knuth's * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime * secondary probe. Here, the modular division first probe is gives way * to a faster exclusive-or manipulation. * * The function used to generate it is: * * int c, hashf[256]; * for (c = 256; --c >= 0; ) { * hashf[c] = (((c & 0x7) << 7) ^ c) << (maxbits-10); * } * * It is used with: * * hash = prefixcode ^ hashf[c]; \* c is char from getchar() *\ * * The value for kNuLZWHashSize determines the size of the hash table and * the % occupancy. We want a fair number of vacancies because we probe * when we collide. Using 5119 (0x13ff) with 12-bit codes yields 75% * occupancy. */ #define kNuLZWHashSize 5119 /* must be prime */ #define kNuLZWEntryUnused 0 /* indicates an unused hash entry */ #define kNuLZWHashFuncTblSize 256 /* one entry per char value */ #define kNuLZWDefaultVol 0xfe /* use this as volume number */ #define kNuLZWHashDelta 0x120 /* used in secondary hashing */ #define kNuLZWMinCode kNuLZWClearCode /* smallest 12-bit LZW code */ #define kNuLZWMaxCode 0x0fff /* largest 12-bit LZW code */ #define kNuLZW2StopCode 0x0ffd /* LZW/2 stops here */ /* * Mask of bits, from 0 to 8. */ static const int gNuBitMask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; #define kNuRLEDefaultEscape 0xdb /* ShrinkIt standard */ /* * This holds all of the "big" dynamic state, plus a few things that I * don't want to pass around. It's allocated once for each instance of * an open archive, and re-used. * * The hash table consists of three parts. We have a choice for some of * them, "ushort" or "uint". With "ushort" it uses less memory and is * more likely to fit in a CPU cache, but on some processors you have to * add instructions to manipulate 16-bit values in a 32-bit word. I'm * guessing "ushort" is better overall. */ typedef struct LZWCompressState { NuArchive* pArchive; uint16_t entry[kNuLZWHashSize]; /* uint or ushort */ uint16_t prefix[kNuLZWMaxCode+1]; /* uint or ushort */ uint8_t suffix[kNuLZWMaxCode+1]; uint16_t hashFunc[kNuLZWHashFuncTblSize]; /* uint or ushort */ uint8_t inputBuf[kNuLZWBlockSize]; /* 4K of raw input */ uint8_t rleBuf[kNuLZWBlockSize*2 + kNuSafetyPadding]; uint8_t lzwBuf[(kNuLZWBlockSize * 3) / 2 + kNuSafetyPadding]; uint16_t chunkCrc; /* CRC for LZW/1 */ /* LZW/2 state variables */ int nextFree; int codeBits; int highCode; Boolean initialClear; } LZWCompressState; /* * Allocate some "reusable" state for LZW compression. * * The only thing that really needs to be retained across calls is * the hash function. This way we don't have to re-create it for * every file, or store it statically in the binary. */ static NuError Nu_AllocLZWCompressState(NuArchive* pArchive) { NuError err; LZWCompressState* lzwState; int ic; Assert(pArchive != NULL); Assert(pArchive->lzwCompressState == NULL); /* allocate the general-purpose compression buffer, if needed */ err = Nu_AllocCompressionBufferIFN(pArchive); if (err != kNuErrNone) return err; pArchive->lzwCompressState = Nu_Malloc(pArchive, sizeof(LZWCompressState)); if (pArchive->lzwCompressState == NULL) return kNuErrMalloc; /* * The "hashFunc" table only needs to be set up once. */ lzwState = pArchive->lzwCompressState; for (ic = 256; --ic >= 0; ) lzwState->hashFunc[ic] = (((ic & 0x7) << 7) ^ ic) << 2; return kNuErrNone; } /* * Compress a block of input from lzwState->inputBuf to lzwState->rleBuf. * The size of the output is returned in "*pRLESize" (will be zero if the * block expanded instead of compressing). * * The maximum possible size of the output is 2x the original, which can * only occur if the input is an alternating sequence of RLE delimiters * and non-delimiters. It requires 3 bytes to encode a solitary 0xdb, * so you get (4096 / 2) non-delimiters plus (4096 / 2) * 3 RLE-encoded * delimiters. We deal with this by using an 8K output buffer, so we * don't have to watch for overflow in the inner loop. * * The RLE format is " ", where count is zero-based * (i.e. for three bytes we encode "2", allowing us to express 1-256). */ static NuError Nu_CompressBlockRLE(LZWCompressState* lzwState, int* pRLESize) { const uint8_t* inPtr = lzwState->inputBuf; const uint8_t* endPtr = inPtr + kNuLZWBlockSize; uint8_t* outPtr = lzwState->rleBuf; uint8_t matchChar; int matchCount; while (inPtr < endPtr) { matchChar = *inPtr; matchCount = 1; /* count up the matching chars */ while (*++inPtr == matchChar && inPtr < endPtr) matchCount++; if (matchCount > 3) { if (matchCount > 256) { /* rare case - really long match */ while (matchCount > 256) { *outPtr++ = kNuRLEDefaultEscape; *outPtr++ = matchChar; *outPtr++ = 255; matchCount -= 256; } /* take care of the odd bits -- which might not form a run! */ if (matchCount > 3) { *outPtr++ = kNuRLEDefaultEscape; *outPtr++ = matchChar; *outPtr++ = matchCount -1; } else { while (matchCount--) *outPtr++ = matchChar; } } else { /* common case */ *outPtr++ = kNuRLEDefaultEscape; *outPtr++ = matchChar; *outPtr++ = matchCount -1; } } else { if (matchChar == kNuRLEDefaultEscape) { /* encode 1-3 0xDBs */ *outPtr++ = kNuRLEDefaultEscape; *outPtr++ = kNuRLEDefaultEscape; *outPtr++ = matchCount -1; } else { while (matchCount--) *outPtr++ = matchChar; } } } *pRLESize = outPtr - lzwState->rleBuf; Assert(*pRLESize > 0 && *pRLESize < sizeof(lzwState->rleBuf)); return kNuErrNone; } /* * Clear the LZW table. Also resets the LZW/2 state. */ static void Nu_ClearLZWTable(LZWCompressState* lzwState) { Assert(lzwState != NULL); /*DBUG_LZW(("### clear table\n"));*/ /* reset table entries */ Assert(kNuLZWEntryUnused == 0); /* make sure this is okay */ memset(lzwState->entry, 0, sizeof(lzwState->entry)); /* reset state variables */ lzwState->nextFree = kNuLZWFirstCode; lzwState->codeBits = 9; lzwState->highCode = ~(~0 << lzwState->codeBits); /* a/k/a 0x01ff */ lzwState->initialClear = false; } /* * Write a variable-width LZW code to the output. "prefixCode" has the * value to write, and "codeBits" is the width. * * Data is written in little-endian order (lowest byte first). The * putcode function in LZC is probably faster, but the format isn't * compatible with SHK. * * The worst conceivable expansion for LZW is 12 bits of output for every * byte of input. Because we're using variable-width codes and LZW is * reasonably effective at finding matches, the actual expansion will * certainly be less. Throwing the extra 2K onto the end of the buffer * saves us from having to check for a buffer overflow here. * * On exit, "*pOutBuf" will point PAST the last byte we wrote (even if * it's a partial byte), and "*pAtBit" will contain the bit offset. * * (Turning this into a macro might speed things up.) */ static inline void Nu_LZWPutCode(uint8_t** pOutBuf, uint32_t prefixCode, int codeBits, int* pAtBit) { int atBit = *pAtBit; uint8_t* outBuf = *pOutBuf; /*DBUG_LZW(("### PUT: prefixCode=0x%04lx, codeBits=%d, atBit=%d\n", prefixCode, codeBits, atBit));*/ Assert(atBit >= 0 && atBit < sizeof(gNuBitMask)); if (atBit) { /* align the prefix code with the existing byte */ prefixCode <<= atBit; /* merge it with the buffer contents (if necessary) and write lo bits */ outBuf--; *outBuf = (uint8_t)((*outBuf & gNuBitMask[atBit]) | prefixCode); outBuf++; } else { /* nothing to merge with; write lo byte at next posn and advance */ *outBuf++ = (uint8_t)prefixCode; } /* codes are at least 9 bits, so we know we have to write one more */ *outBuf++ = (uint8_t)(prefixCode >> 8); /* in some cases, we may have to write yet another */ atBit += codeBits; if (atBit > 16) *outBuf++ = (uint8_t)(prefixCode >> 16); *pAtBit = atBit & 0x07; *pOutBuf = outBuf; } /* * Compress a block of data with LZW, from "inputBuf" to lzwState->lzwBuf. * * LZW/1 is just like LZW/2, except that for the former the table is * always cleared before this function is called. Because of this, the * table never fills completely, so none of the table-overflow code * ever happens. * * This function is patterned after the LZC compress function, rather * than the NuLib LZW code, because the NuLib code was abysmal (a rather * straight translation from 6502 assembly). This function differs from LZC * in a few areas in order to make the output match GS/ShrinkIt. * * There is a (deliberate) minor bug here: if a table clear is emitted * when there is only one character left in the input, nothing will be * added to the hash table (as there is nothing to add) but "nextFree" * will be advanced. This mimics GSHK's behavior, and accounts for the * "resetFix" logic in the expansion functions. Code 0x0101 is essentially * lost in this situation. */ static NuError Nu_CompressLZWBlock(LZWCompressState* lzwState, const uint8_t* inputBuf, int inputCount, int* pOutputCount) { int nextFree, ic, atBit, codeBits; int hash, hashDelta; int prefixCode, code, highCode; const uint8_t* inputEnd = inputBuf + inputCount; /* local copies of lzwState members, for speed */ const uint16_t* pHashFunc = lzwState->hashFunc; uint16_t* pEntry = lzwState->entry; uint16_t* pPrefix = lzwState->prefix; uint8_t* pSuffix = lzwState->suffix; uint8_t* outBuf = lzwState->lzwBuf; Assert(lzwState != NULL); Assert(inputBuf != NULL); Assert(inputCount > 0 && inputCount <= kNuLZWBlockSize); /* make sure nobody has been messing with the types */ Assert(sizeof(pHashFunc[0]) == sizeof(lzwState->hashFunc[0])); Assert(sizeof(pEntry[0]) == sizeof(lzwState->entry[0])); Assert(sizeof(pPrefix[0]) == sizeof(lzwState->prefix[0])); Assert(sizeof(pSuffix[0]) == sizeof(lzwState->suffix[0])); /*DBUG_LZW(("### START LZW (nextFree=0x%04x)\n", lzwState->nextFree));*/ atBit = 0; if (lzwState->initialClear) { /*DBUG_LZW(("### initialClear set\n"));*/ codeBits = lzwState->codeBits; Nu_LZWPutCode(&outBuf, kNuLZWClearCode, codeBits, &atBit); Nu_ClearLZWTable(lzwState); } table_cleared: /* recover our state (or get newly-cleared state) */ nextFree = lzwState->nextFree; codeBits = lzwState->codeBits; highCode = lzwState->highCode; prefixCode = *inputBuf++; /*DBUG_LZW(("### fchar=0x%02x\n", prefixCode));*/ while (inputBuf < inputEnd) { ic = *inputBuf++; /*DBUG_LZW(("### char=0x%02x\n", ic));*/ hash = prefixCode ^ pHashFunc[ic]; code = pEntry[hash]; if (code != kNuLZWEntryUnused) { /* something is here, either our prefix or a hash collision */ if (pSuffix[code] != ic || pPrefix[code] != prefixCode) { /* we've collided; do the secondary probe */ hashDelta = (kNuLZWHashDelta - ic) << 2; do { /* rehash and keep looking */ Assert(code >= kNuLZWMinCode && code <= kNuLZWMaxCode); if (hash >= hashDelta) hash -= hashDelta; else hash += kNuLZWHashSize - hashDelta; Assert(hash >= 0 && hash < kNuLZWHashSize); if ((code = pEntry[hash]) == kNuLZWEntryUnused) goto new_code; } while (pSuffix[code] != ic || pPrefix[code] != prefixCode); } /* else we found a matching string, and can keep searching */ prefixCode = code; } else { /* found an empty entry, add the prefix+suffix to the table */ new_code: Nu_LZWPutCode(&outBuf, prefixCode, codeBits, &atBit); Assert(outBuf < lzwState->lzwBuf + sizeof(lzwState->lzwBuf)); /*DBUG_LZW(("### outBuf now at +%d\n",outBuf - lzwState->lzwBuf));*/ code = nextFree; Assert(hash < kNuLZWHashSize); Assert(code >= kNuLZWMinCode); Assert(code <= kNuLZWMaxCode); /* * GSHK accepts 0x0ffd, and then sends the table clear * immediately. We could improve on GSHK's compression slightly * by using the entire table, but I want to generate the exact * same output as GSHK. (The decoder believes the table clear * is entry 0xffe, so we've got one more coming, and possibly * two if we tweak getcode slightly.) * * Experiments show that switching to 0xffe increases the size * of files that don't compress well, and decreases the size * of files that do. In both cases, the difference in size * is very small. */ Assert(code <= kNuLZW2StopCode); /*if (code <= kNuLZW2StopCode) {*/ /*DBUG_LZW(("### added new code 0x%04x prefix=0x%04x ch=0x%02x\n", code, prefixCode, ic));*/ pEntry[hash] = code; pPrefix[code] = prefixCode; pSuffix[code] = ic; /* * Check and see if it's time to increase the code size (note * we flip earlier than LZC by one here). */ if (code >= highCode) { highCode += code +1; codeBits++; } nextFree++; /*}*/ prefixCode = ic; /* if the table is full, clear it (only for LZW/2) */ if (code == kNuLZW2StopCode) { /* output last code */ Nu_LZWPutCode(&outBuf, prefixCode, codeBits, &atBit); if (inputBuf < inputEnd) { /* still have data, keep going */ Nu_LZWPutCode(&outBuf, kNuLZWClearCode, codeBits, &atBit); Nu_ClearLZWTable(lzwState); goto table_cleared; } else { /* no more input, hold table clear for next block */ DBUG(("--- RARE: block-end clear\n")); lzwState->initialClear = true; goto table_clear_finish; } } Assert(nextFree <= kNuLZW2StopCode); } } /* * Output the last code. Since there's no following character, we don't * need to add an entry to the table... whatever we've found is already * in there. */ Nu_LZWPutCode(&outBuf, prefixCode, codeBits, &atBit); /* * Update the counters so LZW/2 has continuity. */ Assert(nextFree <= kNuLZW2StopCode); if (nextFree >= highCode) { highCode += nextFree +1; codeBits++; } nextFree++; /* make room for the code we just wrote */ if (nextFree > kNuLZW2StopCode) { /* * The code we just wrote, which was part of a longer string already * in the tree, took the last entry in the table. We need to clear * the table, but we can't do it in this block. We will have to * emit a table clear as the very first thing in the next block. */ DBUG(("--- RARE: block-end inter clear\n")); lzwState->initialClear = true; } table_clear_finish: /* save state for next pass through */ lzwState->nextFree = nextFree; lzwState->codeBits = codeBits; lzwState->highCode = highCode; Assert(inputBuf == inputEnd); *pOutputCount = outBuf - lzwState->lzwBuf; /* if (*pOutputCount < inputCount) { DBUG_LZW(("### compressed from %d to %d\n", inputCount, *pOutputCount)); } else { DBUG_LZW(("### NO compression (%d to %d)\n", inputCount,*pOutputCount)); } */ return kNuErrNone; } /* * Compress ShrinkIt-style "LZW/1" and "LZW/2". * * "*pThreadCrc" should already be set to its initial value. On exit it * will contain the CRC of the uncompressed data. * * On exit, the output file will be positioned past the last byte written. */ static NuError Nu_CompressLZW(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pThreadCrc, Boolean isType2) { NuError err = kNuErrNone; LZWCompressState* lzwState; long initialOffset; const uint8_t* lzwInputBuf; uint32_t blockSize, rleSize, lzwSize; long compressedLen; Boolean keepLzw; Assert(pArchive != NULL); Assert(pStraw != NULL); Assert(fp != NULL); Assert(srcLen > 0); Assert(pDstLen != NULL); Assert(pThreadCrc != NULL); Assert(isType2 == true || isType2 == false); /* * Do some initialization and set-up. */ if (pArchive->lzwCompressState == NULL) { err = Nu_AllocLZWCompressState(pArchive); BailError(err); } Assert(pArchive->lzwCompressState != NULL); Assert(pArchive->compBuf != NULL); lzwState = pArchive->lzwCompressState; lzwState->pArchive = pArchive; compressedLen = 0; /* * And now for something ugly: for LZW/1 we have to compute the CRC * twice. Old versions of ShrinkIt used LZW/1 and put the CRC in * the compressed block while newer versions used LZW/2 and put the * CRC in the thread header. We're using LZW/1 with the newer record * format, so we need two CRCs. For some odd reason Andy N. decided * to use 0xffff as the initial value for the thread one, so we can't * just store the same thing in two places. * * Of course, this also means that an LZW/2 chunk stored in an old * pre-v3 record wouldn't have a CRC at all... * * LZW/1 is included here for completeness. I can't think of a reason * why you'd want to use it, really. */ lzwState->chunkCrc = kNuInitialChunkCRC; /* 0x0000 */ /* * An LZW/1 file starts off with a CRC of the data, which means we * have to compress the whole thing, then seek back afterward and * write the value. This annoyance went away in LZW/2. */ err = Nu_FTell(fp, &initialOffset); BailError(err); if (!isType2) { putc(0, fp); /* leave space for CRC */ putc(0, fp); compressedLen += 2; } putc(kNuLZWDefaultVol, fp); putc(kNuRLEDefaultEscape, fp); compressedLen += 2; if (isType2) Nu_ClearLZWTable(lzwState); while (srcLen) { /* * Fill up the input buffer. */ blockSize = (srcLen > kNuLZWBlockSize) ? kNuLZWBlockSize : srcLen; err = Nu_StrawRead(pArchive, pStraw, lzwState->inputBuf, blockSize); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "compression read failed"); goto bail; } /* * ShrinkIt was originally just going to be a 5.25" disk compressor, * so the compression functions were organized around 4K blocks (the * size of one track on a 5.25" disk). The block passed into the * RLE function is always 4K, so we zero out any extra space. */ if (blockSize < kNuLZWBlockSize) { memset(lzwState->inputBuf + blockSize, 0, kNuLZWBlockSize - blockSize); } /* * Compute the CRC. For LZW/1 this is on the entire 4K block, for * the "version 3" thread header CRC this is on just the "real" data. */ *pThreadCrc = Nu_CalcCRC16(*pThreadCrc, lzwState->inputBuf, blockSize); if (!isType2) { lzwState->chunkCrc = Nu_CalcCRC16(lzwState->chunkCrc, lzwState->inputBuf, kNuLZWBlockSize); } /* * Try to compress with RLE, from inputBuf to rleBuf. */ err = Nu_CompressBlockRLE(lzwState, (int*) &rleSize); BailError(err); if (rleSize < kNuLZWBlockSize) { lzwInputBuf = lzwState->rleBuf; } else { lzwInputBuf = lzwState->inputBuf; rleSize = kNuLZWBlockSize; } /* * Compress with LZW, into lzwBuf. */ if (!isType2) Nu_ClearLZWTable(lzwState); err = Nu_CompressLZWBlock(lzwState, lzwInputBuf, rleSize, (int*) &lzwSize); BailError(err); /* decide if we want to keep it, bearing in mind the LZW/2 header */ if (pArchive->valMimicSHK) { /* GSHK doesn't factor in header -- and *sometimes* uses "<=" !! */ keepLzw = (lzwSize < rleSize); } else { if (isType2) keepLzw = (lzwSize +2 < rleSize); else keepLzw = (lzwSize < rleSize); } /* * Write the compressed (or not) chunk. */ if (keepLzw) { /* * LZW succeeded. */ if (isType2) rleSize |= 0x8000; /* for LZW/2, set "LZW used" flag */ putc(rleSize & 0xff, fp); /* size after RLE */ putc(rleSize >> 8, fp); compressedLen += 2; if (isType2) { /* write compressed LZW len (+4 for header bytes) */ putc((lzwSize+4) & 0xff, fp); putc((lzwSize+4) >> 8, fp); compressedLen += 2; } else { /* set LZW/1 "LZW used" flag */ putc(1, fp); compressedLen++; } /* write data from LZW buffer */ err = Nu_FWrite(fp, lzwState->lzwBuf, lzwSize); BailError(err); compressedLen += lzwSize; } else { /* * LZW failed. */ putc(rleSize & 0xff, fp); /* size after RLE */ putc(rleSize >> 8, fp); compressedLen += 2; if (isType2) { /* clear LZW/2 table; we can't use it next time */ Nu_ClearLZWTable(lzwState); } else { /* set LZW/1 "LZW not used" flag */ putc(0, fp); compressedLen++; } /* write data from RLE or plain-input buffer */ err = Nu_FWrite(fp, lzwInputBuf, rleSize); BailError(err); compressedLen += rleSize; } /* * Update the counter and continue. */ srcLen -= blockSize; } /* * For LZW/1, go back and write the CRC. */ if (!isType2) { long curOffset; err = Nu_FTell(fp, &curOffset); BailError(err); err = Nu_FSeek(fp, initialOffset, SEEK_SET); BailError(err); putc(lzwState->chunkCrc & 0xff, fp); putc(lzwState->chunkCrc >> 8, fp); err = Nu_FSeek(fp, curOffset, SEEK_SET); BailError(err); } /* P8SHK and GSHK add an extra byte to LZW-compressed threads */ if (pArchive->valMimicSHK) { putc(0, fp); compressedLen++; } *pDstLen = compressedLen; bail: return err; } /* * Compress ShrinkIt-style "LZW/1". */ NuError Nu_CompressLZW1(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc) { return Nu_CompressLZW(pArchive, pStraw, fp, srcLen, pDstLen, pCrc, false); } /* * Compress ShrinkIt-style "LZW/2". */ NuError Nu_CompressLZW2(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc) { return Nu_CompressLZW(pArchive, pStraw, fp, srcLen, pDstLen, pCrc, true); } /* * =========================================================================== * Expansion * =========================================================================== */ /* if we don't have at least this much data, we try to read more */ /* (the "+3" is for the chunk header bytes) */ #define kNuLZWDesiredChunk (kNuLZWBlockSize + 3) /* * Static tables useful for bit manipulation. */ static const uint32_t gNuMaskTable[17] = { 0x0000, 0x01ff, 0x03ff, 0x03ff, 0x07ff, 0x07ff, 0x07ff, 0x07ff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff }; /* convert high byte of "entry" into a bit width */ static const uint32_t gNuBitWidth[17] = { 8,9,10,10,11,11,11,11,12,12,12,12,12,12,12,12,12 }; /* entry in the trie */ typedef struct TableEntry { uint8_t ch; uint32_t prefix; } TableEntry; /* * This holds all of the "big" dynamic state, plus a few things that I * don't want to pass around. It's allocated once for each instance of * an open archive, and re-used. */ typedef struct LZWExpandState { NuArchive* pArchive; TableEntry trie[4096-256]; /* holds from 9 bits to 12 bits */ uint8_t stack[kNuLZWBlockSize]; // some of these don't need to be 32 bits; they were "uint" before uint32_t entry; /* 16-bit index into table */ uint32_t oldcode; /* carryover state for LZW/2 */ uint32_t incode; /* carryover state for LZW/2 */ uint32_t finalc; /* carryover state for LZW/2 */ Boolean resetFix; /* work around an LZW/2 bug */ uint16_t chunkCrc; /* CRC we calculate for LZW/1 */ uint16_t fileCrc; /* CRC stored with file */ uint8_t diskVol; /* disk volume # */ uint8_t rleEscape; /* RLE escape char, usually 0xdb */ uint32_t dataInBuffer; /* #of bytes in compBuf */ uint8_t* dataPtr; /* current data offset */ uint8_t lzwOutBuf[kNuLZWBlockSize + kNuSafetyPadding]; uint8_t rleOutBuf[kNuLZWBlockSize + kNuSafetyPadding]; } LZWExpandState; /* * Allocate some "reusable" state for LZW expansion. */ static NuError Nu_AllocLZWExpandState(NuArchive* pArchive) { NuError err; Assert(pArchive != NULL); Assert(pArchive->lzwExpandState == NULL); /* allocate the general-purpose compression buffer, if needed */ err = Nu_AllocCompressionBufferIFN(pArchive); if (err != kNuErrNone) return err; pArchive->lzwExpandState = Nu_Malloc(pArchive, sizeof(LZWExpandState)); if (pArchive->lzwExpandState == NULL) return kNuErrMalloc; return kNuErrNone; } #ifdef NDEBUG # define Nu_LZWPush(uch) ( *stackPtr++ = (uch) ) # define Nu_LZWPop() ( *(--stackPtr) ) # define Nu_LZWStackEmpty() ( stackPtr == lzwState->stack ) #else # define Nu_LZWPush(uch) \ ( Nu_LZWPushCheck(uch, lzwState, stackPtr), *stackPtr++ = (uch) ) # define Nu_LZWPop() \ ( Nu_LZWPopCheck(lzwState, stackPtr), *(--stackPtr) ) # define Nu_LZWStackEmpty() ( stackPtr == lzwState->stack ) static inline void Nu_LZWPushCheck(uint8_t uch, const LZWExpandState* lzwState, const uint8_t* stackPtr) { if (stackPtr >= lzwState->stack + sizeof(lzwState->stack)) { Nu_ReportError(lzwState->NU_BLOB, kNuErrBadData, "stack overflow"); abort(); } } static inline void Nu_LZWPopCheck(const LZWExpandState* lzwState, const uint8_t* stackPtr) { if (stackPtr == lzwState->stack) { Nu_ReportError(lzwState->NU_BLOB, kNuErrBadData, "stack underflow"); abort(); } } #endif /* * Get the next LZW code from the input, advancing pointers as needed. * * This would be faster as a macro and less ugly with pass-by-reference. * Resorting to globals is unacceptable. Might be less ugly if we clumped * some stuff into a struct. Should be good enough as-is. * * Returns an integer up to 12 bits long. * * (Turning this into a macro might speed things up.) */ static inline uint32_t Nu_LZWGetCode(const uint8_t** pInBuf, uint32_t entry, int* pAtBit, uint32_t* pLastByte) { uint32_t numBits, startBit, lastBit; uint32_t value; numBits = (entry +1) >> 8; /* bit-width of next code */ startBit = *pAtBit; lastBit = startBit + gNuBitWidth[numBits]; /* * We need one or two bytes from the input. These have to be shifted * around and merged with the bits we already have (if any). */ if (!startBit) value = *(*pInBuf)++; else value = *pLastByte; if (lastBit > 16) { /* need two more bytes */ value |= *(*pInBuf)++ << 8; *pLastByte = *(*pInBuf)++; value |= (uint32_t) *pLastByte << 16; } else { /* only need one more byte */ *pLastByte = *(*pInBuf)++; value |= *pLastByte << 8; } *pAtBit = lastBit & 0x07; /*printf("| EX: value=$%06lx mask=$%04x return=$%03lx\n", value,gNuMaskTable[numBits], (value >> startBit) & gNuMaskTable[numBits]);*/ /*DBUG_LZW(("### getcode 0x%04lx\n", (value >> startBit) & gNuMaskTable[numBits]));*/ /* I believe ANSI allows shifting by zero bits, so don't test "!startBit" */ return (value >> startBit) & gNuMaskTable[numBits]; } /* * Expand an LZW/1 chunk. * * Reads from lzwState->dataPtr, writes to lzwState->lzwOutBuf. */ static NuError Nu_ExpandLZW1(LZWExpandState* lzwState, uint32_t expectedLen) { NuError err = kNuErrNone; TableEntry* tablePtr; int atBit; uint32_t entry, oldcode, incode, ptr; uint32_t lastByte, finalc; const uint8_t* inbuf; uint8_t* outbuf; uint8_t* outbufend; uint8_t* stackPtr; Assert(lzwState != NULL); Assert(expectedLen > 0 && expectedLen <= kNuLZWBlockSize); inbuf = lzwState->dataPtr; outbuf = lzwState->lzwOutBuf; outbufend = outbuf + expectedLen; tablePtr = lzwState->trie - 256; /* don't store 256 empties */ stackPtr = lzwState->stack; atBit = 0; lastByte = 0; entry = kNuLZWFirstCode; /* 0x101 */ finalc = oldcode = incode = Nu_LZWGetCode(&inbuf, entry, &atBit, &lastByte); *outbuf++ = incode; Assert(incode <= 0xff); if (incode > 0xff) { err = kNuErrBadData; Nu_ReportError(lzwState->NU_BLOB, err, "invalid initial LZW symbol"); goto bail; } while (outbuf < outbufend) { incode = ptr = Nu_LZWGetCode(&inbuf, entry, &atBit, &lastByte); /* handle KwKwK case */ if (ptr >= entry) { //DBUG_LZW(("### KwKwK (ptr=%d entry=%d)\n", ptr, entry)); if (ptr != entry) { /* bad code -- this would make us read uninitialized data */ DBUG(("--- bad code (ptr=%d entry=%d)\n", ptr, entry)); err = kNuErrBadData; return err; } Nu_LZWPush((uint8_t)finalc); ptr = oldcode; } /* fill the stack by chasing up the trie */ while (ptr > 0xff) { Nu_LZWPush(tablePtr[ptr].ch); ptr = tablePtr[ptr].prefix; Assert(ptr < 4096); } /* done chasing up, now dump the stack, starting with ptr */ finalc = ptr; *outbuf++ = ptr; /*printf("PUT 0x%02x\n", *(outbuf-1));*/ while (!Nu_LZWStackEmpty()) { *outbuf++ = Nu_LZWPop(); /*printf("POP/PUT 0x%02x\n", *(outbuf-1));*/ } /* add the new prefix to the trie -- last string plus new char */ Assert(finalc <= 0xff); tablePtr[entry].ch = finalc; tablePtr[entry].prefix = oldcode; entry++; oldcode = incode; } bail: if (outbuf != outbufend) { err = kNuErrBadData; Nu_ReportError(lzwState->NU_BLOB, err, "LZW expansion failed"); return err; } /* adjust input buffer */ lzwState->dataInBuffer -= (inbuf - lzwState->dataPtr); Assert(lzwState->dataInBuffer < 32767*65536); lzwState->dataPtr = (uint8_t*)inbuf; return err; } /* * Expand an LZW/2 chunk. Main difference from LZW/1 is that the state * is carried over from the previous block in most cases, and the table * is cleared explicitly. * * Reads from lzwState->dataPtr, writes to lzwState->lzwOutBuf. * * In some cases, "expectedInputUsed" will be -1 to indicate that the * value is not known. */ static NuError Nu_ExpandLZW2(LZWExpandState* lzwState, uint32_t expectedLen, uint32_t expectedInputUsed) { NuError err = kNuErrNone; TableEntry* tablePtr; int atBit; uint32_t entry, oldcode, incode, ptr; uint32_t lastByte, finalc; const uint8_t* inbuf; const uint8_t* inbufend; uint8_t* outbuf; uint8_t* outbufend; uint8_t* stackPtr; /*DBUG_LZW(("### LZW/2 block start (compIn=%d, rleOut=%d, entry=0x%04x)\n", expectedInputUsed, expectedLen, lzwState->entry));*/ Assert(lzwState != NULL); Assert(expectedLen > 0 && expectedLen <= kNuLZWBlockSize); inbuf = lzwState->dataPtr; inbufend = lzwState->dataPtr + expectedInputUsed; outbuf = lzwState->lzwOutBuf; outbufend = outbuf + expectedLen; entry = lzwState->entry; tablePtr = lzwState->trie - 256; /* don't store 256 empties */ stackPtr = lzwState->stack; atBit = 0; lastByte = 0; /* * If the table isn't empty, initialize from the saved state and * jump straight into the main loop. * * There's a funny situation that arises when a table clear is the * second-to-last code in the previous chunk. After we see the * table clear, we get the next code and use it to initialize "oldcode" * and "incode" -- but we don't advance "entry" yet. The way that * ShrinkIt originally worked, the next time we came through we'd * see what we thought was an empty table and we'd reinitialize. So * we use "resetFix" to keep track of this situation. */ if (entry != kNuLZWFirstCode || lzwState->resetFix) { /* table not empty */ oldcode = lzwState->oldcode; incode = lzwState->incode; finalc = lzwState->finalc; lzwState->resetFix = false; goto main_loop; } clear_table: /* table is either empty or was just explicitly cleared; reset */ entry = kNuLZWFirstCode; /* 0x0101 */ if (outbuf == outbufend) { /* block must've ended on a table clear */ DBUG(("--- RARE: ending clear\n")); /* reset values, mostly to quiet gcc's "used before init" warnings */ oldcode = incode = finalc = 0; goto main_loop; /* the while condition will fall through */ } finalc = oldcode = incode = Nu_LZWGetCode(&inbuf, entry, &atBit, &lastByte); *outbuf++ = incode; /*printf("PUT 0x%02x\n", *(outbuf-1));*/ if (incode > 0xff) { err = kNuErrBadData; Nu_ReportError(lzwState->NU_BLOB, err, "invalid initial LZW symbol"); goto bail; } if (outbuf == outbufend) { /* if we're out of data, raise the "reset fix" flag */ DBUG(("--- RARE: resetFix!\n")); lzwState->resetFix = true; /* fall through; the while condition will let us slip past */ } main_loop: while (outbuf < outbufend) { incode = ptr = Nu_LZWGetCode(&inbuf, entry, &atBit, &lastByte); //DBUG_LZW(("### read incode=0x%04x\n", incode)); if (incode == kNuLZWClearCode) /* table clear - 0x0100 */ goto clear_table; /* handle KwKwK case */ if (ptr >= entry) { //DBUG_LZW(("### KwKwK (ptr=%d entry=%d)\n", ptr, entry)); if (ptr != entry) { /* bad code -- this would make us read uninitialized data */ DBUG(("--- bad code (ptr=%d entry=%d)\n", ptr, entry)); err = kNuErrBadData; return err; } Nu_LZWPush((uint8_t)finalc); ptr = oldcode; } /* fill the stack by chasing up the trie */ while (ptr > 0xff) { Nu_LZWPush(tablePtr[ptr].ch); ptr = tablePtr[ptr].prefix; Assert(ptr < 4096); } /* done chasing up, now dump the stack, starting with ptr */ finalc = ptr; *outbuf++ = ptr; /*printf("PUT 0x%02x\n", *(outbuf-1));*/ while (!Nu_LZWStackEmpty()) { *outbuf++ = Nu_LZWPop(); /*printf("POP/PUT 0x%02x\n", *(outbuf-1));*/ } /* add the new prefix to the trie -- last string plus new char */ /*DBUG_LZW(("### entry 0x%04x gets prefix=0x%04x and ch=0x%02x\n", entry, oldcode, finalc));*/ Assert(finalc <= 0xff); tablePtr[entry].ch = finalc; tablePtr[entry].prefix = oldcode; entry++; oldcode = incode; } bail: /*DBUG_LZW(("### end of block\n"));*/ if (expectedInputUsed != (uint32_t) -1 && inbuf != inbufend) { /* data was corrupted; if we keep going this will get worse */ DBUG(("--- inbuf != inbufend in ExpandLZW2 (diff=%d)\n", inbufend - inbuf)); err = kNuErrBadData; return err; } Assert(outbuf == outbufend); /* adjust input buffer */ lzwState->dataInBuffer -= (inbuf - lzwState->dataPtr); Assert(lzwState->dataInBuffer < 32767*65536); lzwState->dataPtr = (uint8_t*)inbuf; /* save off local copies of stuff */ lzwState->entry = entry; lzwState->oldcode = oldcode; lzwState->incode = incode; lzwState->finalc = finalc; return err; } /* * Expands a chunk of RLEd data into 4K of output. */ static NuError Nu_ExpandRLE(LZWExpandState* lzwState, const uint8_t* inbuf, uint32_t expectedInputUsed) { NuError err = kNuErrNone; uint8_t *outbuf; uint8_t *outbufend; const uint8_t *inbufend; uint8_t uch, rleEscape; int count; outbuf = lzwState->rleOutBuf; outbufend = outbuf + kNuLZWBlockSize; inbufend = inbuf + expectedInputUsed; rleEscape = lzwState->rleEscape; while (outbuf < outbufend) { uch = *inbuf++; if (uch == rleEscape) { uch = *inbuf++; count = *inbuf++; if (outbuf + count >= outbufend) { /* don't overrun buffer */ Assert(outbuf != outbufend); break; } while (count-- >= 0) *outbuf++ = uch; } else { *outbuf++ = uch; } } if (outbuf != outbufend) { err = kNuErrBadData; Nu_ReportError(lzwState->NU_BLOB, err, "RLE output glitch (off by %d)", (int)(outbufend-outbuf)); goto bail; } if (inbuf != inbufend) { err = kNuErrBadData; Nu_ReportError(lzwState->NU_BLOB, err, "RLE input glitch (off by %d)", (int)(inbufend-inbuf)); goto bail; } bail: return err; } /* * Utility function to get a byte from the input buffer. */ static inline uint8_t Nu_GetHeaderByte(LZWExpandState* lzwState) { lzwState->dataInBuffer--; Assert(lzwState->dataInBuffer > 0); return *lzwState->dataPtr++; } /* * Expand ShrinkIt-style "LZW/1" and "LZW/2". * * This manages the input data buffer, passing chunks of compressed data * into the appropriate expansion function. * * Pass in NULL for "pThreadCrc" if no thread CRC is desired. Otherwise, * "*pThreadCrc" should already be set to its initial value. On exit it * will contain the CRC of the uncompressed data. */ NuError Nu_ExpandLZW(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pThreadCrc) { NuError err = kNuErrNone; Boolean isType2; LZWExpandState* lzwState; uint32_t compRemaining, uncompRemaining, minSize; Assert(pArchive != NULL); Assert(pThread != NULL); Assert(infp != NULL); Assert(pFunnel != NULL); /* * Do some initialization and set-up. */ if (pArchive->lzwExpandState == NULL) { err = Nu_AllocLZWExpandState(pArchive); BailError(err); } Assert(pArchive->lzwExpandState != NULL); Assert(pArchive->compBuf != NULL); lzwState = pArchive->lzwExpandState; lzwState->pArchive = pArchive; if (pThread->thThreadFormat == kNuThreadFormatLZW1) { isType2 = false; minSize = 7; /* crc-lo,crc-hi,vol,rle-delim,len-lo,len-hi,lzw-used */ lzwState->chunkCrc = kNuInitialChunkCRC; /* 0x0000 */ } else if (pThread->thThreadFormat == kNuThreadFormatLZW2) { isType2 = true; minSize = 4; /* vol,rle-delim,len-lo,len-hi */ } else { err = kNuErrBadFormat; goto bail; } uncompRemaining = pThread->actualThreadEOF; compRemaining = pThread->thCompThreadEOF; if (compRemaining < minSize) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "thread too short to be valid LZW"); goto bail; } if (compRemaining && !uncompRemaining) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "compressed data but no uncompressed data??"); goto bail; } /* * Read the LZW header out of the data stream. */ if (!isType2) { lzwState->fileCrc = getc(infp); lzwState->fileCrc |= getc(infp) << 8; compRemaining -= 2; } lzwState->diskVol = getc(infp); /* disk volume #; not really used */ lzwState->rleEscape = getc(infp); /* RLE escape char for this thread */ compRemaining -= 2; lzwState->dataInBuffer = 0; lzwState->dataPtr = NULL; /* reset pointers */ lzwState->entry = kNuLZWFirstCode; /* 0x0101 */ lzwState->resetFix = false; /*DBUG_LZW(("### LZW%d block, vol=0x%02x, rleEsc=0x%02x\n", isType2 +1, lzwState->diskVol, lzwState->rleEscape));*/ /* * Read large blocks of the source file into compBuf, taking care not * to read past the end of the thread data. * * The motivation for doing it this way rather than just reading the * next compressed chunk are (1) compBuf is considerably larger than * stdio BUFSIZ on most systems, and (2) for LZW/1 we don't know the * size of the compressed data anyway. * * We need to ensure that we have at least one full compressed chunk * in the buffer. Since the compressor will refuse to store the * compressed data if it grows, we know that we need 4K plus the * chunk header. * * Once we have what looks like a full chunk, invoke the LZW decoder. */ while (uncompRemaining) { Boolean rleUsed; Boolean lzwUsed; uint32_t getSize; uint32_t rleLen; /* length after RLE; 4096 if no RLE */ uint32_t lzwLen = 0; /* type 2 only */ uint32_t writeLen, inCount; const uint8_t* writeBuf; /* if we're low, and there's more data available, read more */ if (lzwState->dataInBuffer < kNuLZWDesiredChunk && compRemaining) { /* * First thing we do is slide the old data to the start of * the buffer. */ if (lzwState->dataInBuffer) { Assert(lzwState->dataPtr != NULL); Assert(pArchive->compBuf != lzwState->dataPtr); memmove(pArchive->compBuf, lzwState->dataPtr, lzwState->dataInBuffer); } lzwState->dataPtr = pArchive->compBuf; /* * Next we read as much as we can. */ if (kNuGenCompBufSize - lzwState->dataInBuffer < compRemaining) getSize = kNuGenCompBufSize - lzwState->dataInBuffer; else getSize = compRemaining; /*printf("+++ READING %ld\n", getSize);*/ err = Nu_FRead(infp, lzwState->dataPtr + lzwState->dataInBuffer, getSize); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "failed reading compressed data (%u bytes)", getSize); goto bail; } lzwState->dataInBuffer += getSize; compRemaining -= getSize; Assert(compRemaining < 32767*65536); Assert(lzwState->dataInBuffer <= kNuGenCompBufSize); } Assert(lzwState->dataInBuffer); /* * Read the LZW block header. */ if (isType2) { rleLen = Nu_GetHeaderByte(lzwState); rleLen |= Nu_GetHeaderByte(lzwState) << 8; lzwUsed = rleLen & 0x8000 ? true : false; rleLen &= 0x1fff; rleUsed = (rleLen != kNuLZWBlockSize); if (lzwUsed) { lzwLen = Nu_GetHeaderByte(lzwState); lzwLen |= Nu_GetHeaderByte(lzwState) << 8; lzwLen -= 4; /* don't include header bytes */ } } else { rleLen = Nu_GetHeaderByte(lzwState); rleLen |= Nu_GetHeaderByte(lzwState) << 8; lzwUsed = Nu_GetHeaderByte(lzwState); if (lzwUsed != 0 && lzwUsed != 1) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "garbled LZW header"); goto bail; } rleUsed = (rleLen != kNuLZWBlockSize); } /*DBUG_LZW(("### CHUNK rleLen=%d(%d) lzwLen=%d(%d) uncompRem=%ld\n", rleLen, rleUsed, lzwLen, lzwUsed, uncompRemaining));*/ if (uncompRemaining <= kNuLZWBlockSize) writeLen = uncompRemaining; /* last block */ else writeLen = kNuLZWBlockSize; #ifndef NDEBUG writeBuf = NULL; #endif /* * Decode the chunk, and point "writeBuf" at the uncompressed data. * * LZW always expands from the read buffer into lzwState->lzwOutBuf. * RLE expands from a specific buffer to lzwState->rleOutBuf. */ if (lzwUsed) { if (!isType2) { err = Nu_ExpandLZW1(lzwState, rleLen); } else { if (pRecord->isBadMac || pArchive->valIgnoreLZW2Len) { /* might be big-endian, might be okay; just ignore it */ lzwLen = (uint32_t) -1; } else if (lzwState->dataInBuffer < lzwLen) { /* rare -- GSHK will do this if you don't let it finish */ err = kNuErrBufferUnderrun; Nu_ReportError(NU_BLOB, err, "not enough compressed data " "-- archive truncated during creation?"); goto bail; } err = Nu_ExpandLZW2(lzwState, rleLen, lzwLen); } BailError(err); if (rleUsed) { err = Nu_ExpandRLE(lzwState, lzwState->lzwOutBuf, rleLen); BailError(err); writeBuf = lzwState->rleOutBuf; } else { writeBuf = lzwState->lzwOutBuf; } } else { if (rleUsed) { err = Nu_ExpandRLE(lzwState, lzwState->dataPtr, rleLen); BailError(err); writeBuf = lzwState->rleOutBuf; inCount = rleLen; } else { writeBuf = lzwState->dataPtr; inCount = writeLen; } /* * Advance the input buffer data pointers to consume the input. * The LZW expansion functions do this for us, but we're not * using LZW. */ lzwState->dataPtr += inCount; lzwState->dataInBuffer -= inCount; Assert(lzwState->dataInBuffer < 32767*65536); /* no LZW used, reset pointers */ lzwState->entry = kNuLZWFirstCode; /* 0x0101 */ lzwState->resetFix = false; } Assert(writeBuf != NULL); /* * Compute the CRC of the uncompressed data, and write it. For * LZW/1, the CRC of the last block includes the zeros that pad * it out to 4096 bytes. * * See commentary in the compression code for why we have to * compute two CRCs for LZW/1. */ if (pThreadCrc != NULL) { *pThreadCrc = Nu_CalcCRC16(*pThreadCrc, writeBuf, writeLen); } if (!isType2) { lzwState->chunkCrc = Nu_CalcCRC16(lzwState->chunkCrc, writeBuf, kNuLZWBlockSize); } /* write the data, possibly doing an EOL conversion */ err = Nu_FunnelWrite(pArchive, pFunnel, writeBuf, writeLen); if (err != kNuErrNone) { if (err != kNuErrAborted) Nu_ReportError(NU_BLOB, err, "unable to write output"); goto bail; } uncompRemaining -= writeLen; Assert(uncompRemaining < 32767*65536); } /* * It appears that ShrinkIt appends an extra byte after the last * LZW block. The byte is included in the compThreadEOF, but isn't * consumed by the LZW expansion routine, so it's usually harmless. * * It is *possible* for extra bytes to be here legitimately, but very * unlikely. The very last block is always padded out to 4K with * zeros. If you found a situation where that last block failed * to compress with RLE and LZW (perhaps the last block filled up * all but the last 2 or 3 bytes with uncompressible data), but * earlier data made the overall file compressible, you would have * a few stray bytes in the archive. * * This is a little easier to do if the last block has lots of single * 0xdb characters in it, since that requires RLE to escape them. * * Whatever the case, issue a warning if it looks like there's too * many of them. */ if (lzwState->dataInBuffer > 1) { DBUG(("--- Found %ld bytes following compressed data (compRem=%ld)\n", lzwState->dataInBuffer, compRemaining)); if (lzwState->dataInBuffer > 32) { Nu_ReportError(NU_BLOB, kNuErrNone, "(Warning) lots of fluff (%u)", lzwState->dataInBuffer); } } /* * We might be okay with stray bytes in the thread, but we're definitely * not okay with anything identified as compressed data being unused. */ if (compRemaining) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "not all compressed data was used (%u/%u)", compRemaining, lzwState->dataInBuffer); goto bail; } /* * ShrinkIt used to put the CRC in the stream and not in the thread * header. For LZW/1, we check the CRC here; for LZW/2, we hope it's * in the thread header. (As noted in the compression code, it's * possible to end up with two CRCs or no CRCs.) */ if (!isType2 && !pArchive->valIgnoreCRC) { if (lzwState->chunkCrc != lzwState->fileCrc) { if (!Nu_ShouldIgnoreBadCRC(pArchive, pRecord, kNuErrBadDataCRC)) { err = kNuErrBadDataCRC; Nu_ReportError(NU_BLOB, err, "expected 0x%04x, got 0x%04x (LZW/1)", lzwState->fileCrc, lzwState->chunkCrc); (void) Nu_FunnelFlush(pArchive, pFunnel); goto bail; } } else { DBUG(("--- LZW/1 CRCs match (0x%04x)\n", lzwState->chunkCrc)); } } bail: return err; } #endif /*ENABLE_LZW*/ nulib2-3.1.0/nufxlib/Makefile.in000066400000000000000000000104201316100516500164150ustar00rootroot00000000000000# # NuFX archive manipulation library # Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. # This is free software; you can redistribute it and/or modify it under the # terms of the BSD License, see the file COPYING-LIB. # # Makefile for nufxlib (should work with non-GNU "make"). # # You can use: # make (builds library and sample applications) # make shared (builds shared library if you're using GNU ld or similar) # # The shared library support currently leaves much to be desired. # # If you build with -DDEBUG_MSGS, nulib2 will be able to use the hidden # 'g' command, which generates a verbose archive dump for debugging. # # NufxLib install location. prefix = @prefix@ exec_prefix = @exec_prefix@ includedir = @includedir@ libdir = @libdir@ srcdir = @srcdir@ SHELL = @SHELL@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ CC = @CC@ AR = ar rcv #OPT = @CFLAGS@ -DNDEBUG OPT = @CFLAGS@ #OPT = @CFLAGS@ -DDEBUG_MSGS #OPT = @CFLAGS@ -DDEBUG_VERBOSE GCC_FLAGS = -Wall -Wwrite-strings -Wstrict-prototypes -Wpointer-arith -Wshadow CFLAGS = @BUILD_FLAGS@ -I. @DEFS@ -DOPTFLAGSTR="\"$(OPT)\"" SRCS = Archive.c ArchiveIO.c Bzip2.c Charset.c Compress.c Crc16.c \ Debug.c Deferred.c Deflate.c Entry.c Expand.c FileIO.c Funnel.c \ Lzc.c Lzw.c MiscStuff.c MiscUtils.c Record.c SourceSink.c \ Squeeze.c Thread.c Value.c Version.c OBJS = Archive.o ArchiveIO.o Bzip2.o Charset.o Compress.o Crc16.o \ Debug.o Deferred.o Deflate.o Entry.o Expand.o FileIO.o Funnel.o \ Lzc.o Lzw.o MiscStuff.o MiscUtils.o Record.o SourceSink.o \ Squeeze.o Thread.o Value.o Version.o STATIC_PRODUCT = libnufx.a SHARED_PRODUCT = libnufx.so PRODUCT = $(STATIC_PRODUCT) # # Build stuff # all: $(PRODUCT) samples @true install: $(STATIC_PRODUCT) $(srcdir)/mkinstalldirs $(libdir) $(INSTALL_DATA) $(STATIC_PRODUCT) $(libdir) $(srcdir)/mkinstalldirs $(includedir) $(INSTALL_DATA) NufxLib.h $(includedir) install-shared: $(SHARED_PRODUCT) $(srcdir)/mkinstalldirs $(libdir) $(INSTALL_DATA) $(SHARED_PRODUCT) $(libdir) $(srcdir)/mkinstalldirs $(includedir) $(INSTALL_DATA) NufxLib.h $(includedir) samples:: @echo "Building samples..." @(cd samples; set +e; unset CFLAGS OBJS; set -e; \ @SET_MAKE@ LIB_PRODUCT="../$(PRODUCT)" $(MAKE)) shared:: PRODUCT="$(SHARED_PRODUCT)" $(MAKE) -e $(STATIC_PRODUCT): $(OBJS) -rm -f $(STATIC_PRODUCT) $(SHARED_PRODUCT) $(AR) $@ $(OBJS) @RANLIB@ $@ # BUG: we need -fPIC, maybe -D_REENTRANT when compiling for this. # BUG: for Linux we may want -Wl,-soname,libnufx.so.1 on the link line. $(SHARED_PRODUCT): $(OBJS) -rm -f $(STATIC_PRODUCT) $(SHARED_PRODUCT) $(CC) @SHARE_FLAGS@ -o $@ $(OBJS) @LIBS@ clean: (cd samples; make clean) -rm -f *.o core -rm -f $(SHARED_PRODUCT) $(STATIC_PRODUCT) # build tags; assumes fancy GNU tag generation tags:: @ctags -R --totals * @#ctags *.[ch] distclean: clean (cd samples; make distclean) -rm -f Makefile Makefile.bak -rm -f config.log config.cache config.status config.h -rm -f tags # Make a tarfile with a backup of the essential files. We include "Makefile" # so that we can do a "make distclean" during packaging. baktar: @tar cvf nufxlib.tar *.txt COPYING-LIB INSTALL configure *.in Makefile \ Makefile.msc Makefile.dll install-sh config.guess config.sub \ mkinstalldirs *.[ch] samples/*.txt samples/Makefile* samples/*.[ch] @gzip -9 nufxlib.tar @mv -i nufxlib.tar.gz /home/fadden/BAK/ # dependency info COMMON_HDRS = NufxLibPriv.h NufxLib.h MiscStuff.h SysDefs.h Archive.o: Archive.c $(COMMON_HDRS) ArchiveIO.o: ArchiveIO.c $(COMMON_HDRS) Bzip2.o: Bzip2.c $(COMMON_HDRS) Charset.o: Charset.c $(COMMON_HDRS) Compress.o: Compress.c $(COMMON_HDRS) Crc16.o: Crc16.c $(COMMON_HDRS) Debug.o: Debug.c $(COMMON_HDRS) Deferred.o: Deferred.c $(COMMON_HDRS) Deflate.o: Deflate.c $(COMMON_HDRS) Entry.o: Entry.c $(COMMON_HDRS) Expand.o: Expand.c $(COMMON_HDRS) FileIO.o: FileIO.c $(COMMON_HDRS) Funnel.o: Funnel.c $(COMMON_HDRS) Lzc.o: Lzc.c $(COMMON_HDRS) Lzw.o: Lzw.c $(COMMON_HDRS) MiscStuff.o: MiscStuff.c $(COMMON_HDRS) MiscUtils.o: MiscUtils.c $(COMMON_HDRS) Record.o: Record.c $(COMMON_HDRS) SourceSink.o: SourceSink.c $(COMMON_HDRS) Squeeze.o: Squeeze.c $(COMMON_HDRS) Thread.o: Thread.c $(COMMON_HDRS) Value.o: Value.c $(COMMON_HDRS) Version.o: Version.c $(COMMON_HDRS) Makefile nulib2-3.1.0/nufxlib/Makefile.msc000066400000000000000000000122321316100516500165740ustar00rootroot00000000000000# Makefile for NufxLib using Microsoft Visual C++. This builds the library # as a static lib and as a DLL, and builds all samples. The test-basic # sample is built twice, once with the static lib, and once with the DLL. # # Tested with VS 2013 Pro. From the "VS2013 x86 Native Tools Command # Prompt", run "nmake -f makefile.msc". # # If you're including zlib support, place copies of zlib.h, zconf.h, # and the zlib library in this directory. # # Adapted from zlib's Makefile.msc. # TOP = . STATICLIB = nufxlib2.lib SHAREDLIB = nufxlib2.dll IMPLIB = nufxdll.lib CC = cl LD = link AR = lib # C compiler flags # -Fd: rename PDB file from "VCx0.pdb" (where 'x' is the version number); # allows DLL debug info to be separate from app debug info # -Ox: full optimization # -Oy-: disable frame pointer omission (for easier debugging) # -MD: create a multithreaded DLL using MSVCRT.lib; alternatively, # use -MDd to create a debug executable with MSVCRTD.lib # -nologo: suppress display of copyright banner # -W3: set warning level to 3 (all production-level warnings) # -Zi: generate a PDB file with full debugging info # # The OPTFLAGSTR define is used by Version.c to show how the library was # built. Defining NUFXLIB_EXPORTS enables the __declspec(dllexport) # macros that are required for creating the DLL. OPTFLAGS = -Ox -Oy- CFLAGS = -nologo -MD -W3 $(OPTFLAGS) -Zi -Fd"nufxlib" LIB_CFLAGS = -DOPTFLAGSTR="\"$(OPTFLAGS)\"" #-DNUFXLIB_EXPORTS # Warning suppression flags WFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE # Linker flags # -debug: creates debugging info for EXE or DLL in PDB file # -incremental:no: disable incremental linking, making the resulting library # a tad smaller # -nologo: suppress display of copyright banner # -opt:ref: eliminates unreferenced functions and data (default for non-debug # builds, but we've enabled debug info) LDFLAGS = -nologo -debug -incremental:no -opt:ref # Library creator flags ARFLAGS = -nologo ZLIB=1 !ifdef ZLIB # enable deflate support; requires zlib CFLAGS = $(CFLAGS) -DENABLE_DEFLATE LDFLAGS = $(LDFLAGS) zlib.lib !endif # object files OBJS = Archive.obj ArchiveIO.obj Bzip2.obj Charset.obj Compress.obj \ Crc16.obj Debug.obj Deferred.obj Deflate.obj Entry.obj Expand.obj \ FileIO.obj Funnel.obj Lzc.obj Lzw.obj MiscStuff.obj MiscUtils.obj \ Record.obj SourceSink.obj Squeeze.obj Thread.obj Value.obj Version.obj # build targets -- static library, dynamic library, and test programs all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ exerciser.exe imgconv.exe launder.exe test-basic.exe test-basic-d.exe \ test-extract.exe test-names.exe test-simple.exe test-twirl.exe clean: -del *.obj *.pdb *.exp -del $(STATICLIB) $(SHAREDLIB) $(IMPLIB) $(STATICLIB): $(OBJS) $(AR) $(ARFLAGS) -out:$@ $(OBJS) $(IMPLIB): $(SHAREDLIB) $(SHAREDLIB): $(OBJS) $(LD) $(LDFLAGS) -dll -def:nufxlib.def -implib:$(IMPLIB) -out:$@ \ $(OBJS) exerciser.exe: Exerciser.obj $(STATICLIB) $(LD) $(LDFLAGS) -out:$@ Exerciser.obj $(STATICLIB) imgconv.exe: ImgConv.obj $(STATICLIB) $(LD) $(LDFLAGS) -out:$@ ImgConv.obj $(STATICLIB) launder.exe: Launder.obj $(STATICLIB) $(LD) $(LDFLAGS) -out:$@ Launder.obj $(STATICLIB) test-basic.exe: TestBasic.obj $(STATICLIB) $(LD) $(LDFLAGS) -out:$@ TestBasic.obj $(STATICLIB) test-basic-d.exe: TestBasic.obj $(IMPLIB) $(LD) $(LDFLAGS) -out:$@ TestBasic.obj $(IMPLIB) test-extract.exe: TestExtract.obj $(STATICLIB) $(LD) $(LDFLAGS) -out:$@ TestExtract.obj $(STATICLIB) test-names.exe: TestNames.obj $(STATICLIB) $(LD) $(LDFLAGS) -out:$@ TestNames.obj $(STATICLIB) test-simple.exe: TestSimple.obj $(STATICLIB) $(LD) $(LDFLAGS) -out:$@ TestSimple.obj $(STATICLIB) test-twirl.exe: TestTwirl.obj $(STATICLIB) $(LD) $(LDFLAGS) -out:$@ TestTwirl.obj $(STATICLIB) # generic rules {$(TOP)}.c.obj: $(CC) -c $(WFLAGS) $(CFLAGS) $(LIB_CFLAGS) $< {$(TOP)/samples}.c.obj: $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< # dependency info COMMON_HDRS = NufxLibPriv.h NufxLib.h MiscStuff.h SysDefs.h Archive.obj: Archive.c $(COMMON_HDRS) ArchiveIO.obj: ArchiveIO.c $(COMMON_HDRS) Bzip2.obj: Bzip2.c $(COMMON_HDRS) Charset.obj: Charset.c $(COMMON_HDRS) Compress.obj: Compress.c $(COMMON_HDRS) Crc16.obj: Crc16.c $(COMMON_HDRS) Debug.obj: Debug.c $(COMMON_HDRS) Deferred.obj: Deferred.c $(COMMON_HDRS) Deflate.obj: Deflate.c $(COMMON_HDRS) Entry.obj: Entry.c $(COMMON_HDRS) Expand.obj: Expand.c $(COMMON_HDRS) FileIO.obj: FileIO.c $(COMMON_HDRS) Funnel.obj: Funnel.c $(COMMON_HDRS) Lzc.obj: Lzc.c $(COMMON_HDRS) Lzw.obj: Lzw.c $(COMMON_HDRS) MiscStuff.obj: MiscStuff.c $(COMMON_HDRS) MiscUtils.obj: MiscUtils.c $(COMMON_HDRS) Record.obj: Record.c $(COMMON_HDRS) SourceSink.obj: SourceSink.c $(COMMON_HDRS) Squeeze.obj: Squeeze.c $(COMMON_HDRS) Thread.obj: Thread.c $(COMMON_HDRS) Value.obj: Value.c $(COMMON_HDRS) Version.obj: Version.c $(COMMON_HDRS) Exerciser.obj: samples/Exerciser.c $(COMMON_HDRS) ImgConv.obj: samples/ImgConv.c $(COMMON_HDRS) Launder.obj: samples/Launder.c $(COMMON_HDRS) TestBasic.obj: samples/TestBasic.c $(COMMON_HDRS) TestExtract.obj: samples/TestExtract.c $(COMMON_HDRS) TestNames.obj: samples/TestNames.c $(COMMON_HDRS) TestSimple.obj: samples/TestSimple.c $(COMMON_HDRS) TestTwirl.obj: samples/TestTwirl.c $(COMMON_HDRS) nulib2-3.1.0/nufxlib/MiscStuff.c000066400000000000000000000056351316100516500164330ustar00rootroot00000000000000/* * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Misc stuff (shared between nufxlib and nulib2). This is a collection * of standard functions that aren't available in libc on this system. */ #include "SysDefs.h" #include "MiscStuff.h" #include #ifndef HAVE_STRERROR /* * Return a pointer to the appropriate string in the system table, or NULL * if the value is out of bounds. */ const char* Nu_strerror(int errnum) { extern int sys_nerr; extern char *sys_errlist[]; if (errnum < 0 || errnum > sys_nerr) return NULL; return sys_errlist[errnum]; } #endif #ifndef HAVE_MEMMOVE /* * Move a block of memory. Unlike memcpy, this is expected to work * correctly with overlapping blocks. * * This is a straightforward implementation. A much faster implementation, * from BSD, is available in the PGP 2.6.2 distribution, but this should * suffice for those few systems that don't have memmove. */ void* Nu_memmove(void* dst, const void* src, size_t n) { void* retval = dst; char* srcp = (char*)src; char* dstp = (char*)dst; /* you can normally get away with this if n==0 */ Assert(dst != NULL); Assert(src != NULL); if (dstp == srcp || !n) { /* nothing to do */ } else if (dstp > srcp) { /* start from the end */ (char*)dstp += n-1; (char*)srcp += n-1; while (n--) *dstp-- = *srcp--; } else { /* start from the front */ while (n--) *dstp++ = *srcp++; } return retval; } #endif #ifndef HAVE_STRTOUL /* * Perform strtol, but on an unsigned long. * * On systems that have strtol but don't have strtoul, the strtol * function doesn't clamp the return value, making it similar in * function to strtoul. The comparison is not exact, however, * because strtoul is expected to lots of fancy things (like set * errno to ERANGE). * * For our purposes here, strtol does all we need it to. Someday * we should replace this with a "real" version. */ unsigned long Nu_strtoul(const char *nptr, char **endptr, int base) { return strtol(nptr, endptr, base); } #endif #ifndef HAVE_STRCASECMP /* * Compare two strings, case-insensitive. */ int Nu_strcasecmp(const char *str1, const char *str2) { while (*str1 && *str2 && toupper(*str1) == toupper(*str2)) str1++, str2++; return (toupper(*str1) - toupper(*str2)); } #endif #ifndef HAVE_STRNCASECMP /* * Compare two strings, case-insensitive, stopping after "n" chars. */ int Nu_strncasecmp(const char *str1, const char *str2, size_t n) { while (n && *str1 && *str2 && toupper(*str1) == toupper(*str2)) str1++, str2++, n--; if (n) return (toupper(*str1) - toupper(*str2)); else return 0; /* no mismatch in first n chars */ } #endif nulib2-3.1.0/nufxlib/MiscStuff.h000066400000000000000000000051761316100516500164400ustar00rootroot00000000000000/* * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Misc stuff (shared between nufxlib and nulib2). This is a collection * of miscellaneous types and macros that I find generally useful. */ #ifndef NUFXLIB_MISCSTUFF_H #define NUFXLIB_MISCSTUFF_H #define VALGRIND /* assume we're using it */ #include "SysDefs.h" /* * Use our versions of functions if they don't exist locally. */ #ifndef HAVE_STRERROR #define strerror Nu_strerror const char* Nu_strerror(int errnum); #endif #ifndef HAVE_MEMMOVE #define memmove Nu_memmove void* Nu_memmove(void *dest, const void *src, size_t n); #endif #ifndef HAVE_STRTOUL #define strtoul Nu_strtoul unsigned long Nu_strtoul(const char *nptr, char **endptr, int base); #endif #ifndef HAVE_STRCASECMP #define strcasecmp Nu_strcasecmp int Nu_strcasecmp(const char *s1, const char *s2); #endif #ifndef HAVE_STRNCASECMP #define strncasecmp Nu_strncasecmp int Nu_strncasecmp(const char *s1, const char *s2, size_t n); #endif /* * Misc types. */ typedef unsigned char Boolean; #define false (0) #define true (!false) /* * Handy macros. */ /* compute #of elements in a static array */ #define NELEM(x) (sizeof(x) / sizeof((x)[0])) /* convert single hex digit char to number */ #define HexDigit(x) ( !isxdigit((int)(x)) ? -1 : \ (x) <= '9' ? (x) - '0' : toupper(x) +10 - 'A' ) /* convert number from 0-15 to hex digit */ #define HexConv(x) ( ((unsigned int)(x)) <= 15 ? \ ( (x) <= 9 ? (x) + '0' : (x) -10 + 'A') : -1 ) /* * Debug stuff. */ /* * Redefine this if you want assertions to do something other than default. * Changing the definition of assert is tough, because assert.h redefines * it every time it's included. On a Solaris 2.7 system I was using, gcc * pulled assert.h in with some of the system headers, and their definition * resulted in corrupted core dumps. */ #define Assert assert #if defined(DEBUG_VERBOSE) /* quick debug printf macro */ #define DBUG(args) printf args #else #define DBUG(args) ((void)0) #endif #if defined(NDEBUG) #define DebugFill(addr, len) ((void)0) #define DebugAbort() ((void)0) #else /* when debugging, fill Malloc blocks with junk, unless we're using Purify */ #if !defined(PURIFY) && !defined(VALGRIND) #define DebugFill(addr, len) memset(addr, 0xa3, len) #else #define DebugFill(addr, len) ((void)0) #endif #define DebugAbort() abort() #endif #define kInvalidPtr ((void*)0xa3a3a3a3) #endif /*NUFXLIB_MISCSTUFF_H*/ nulib2-3.1.0/nufxlib/MiscUtils.c000066400000000000000000000261171316100516500164420ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Miscellaneous NufxLib utility functions. */ #include "NufxLibPriv.h" /* * Big fat hairy global. Unfortunately this is unavoidable. */ NuCallback gNuGlobalErrorMessageHandler = NULL; static const char* kNufxLibName = "nufxlib"; /* * strerror() equivalent for NufxLib errors. */ const char* Nu_StrError(NuError err) { /* * BUG: this should be set up as per-thread storage in an MT environment. * I would be more inclined to worry about this if I was expecting * it to be used. So long as valid values are passed in, and the * switch statement is kept up to date, we should never have cause * to return this. * * An easier solution, should this present a problem for someone, would * be to have the function return NULL or "unknown error" when the * error value isn't recognized. I'd recommend leaving it as-is for * debug builds, though, as it's helpful to know *which* error is not * recognized. */ static char defaultMsg[32]; switch (err) { case kNuErrNone: return "(no error)"; case kNuErrGeneric: return "NufxLib generic error"; case kNuErrInternal: return "NufxLib internal error"; case kNuErrUsage: return "NufxLib usage error"; case kNuErrSyntax: return "NufxLib syntax error"; case kNuErrMalloc: return "NufxLib malloc error"; case kNuErrInvalidArg: return "Invalid arguments to NufxLib"; case kNuErrBadStruct: return "Bad NuArchive structure passed to NufxLib"; case kNuErrBusy: return "Attempted invalid reentrant call"; case kNuErrSkipped: return "Skipped by user"; case kNuErrAborted: return "Processing aborted"; case kNuErrRename: return "User wants to rename file"; case kNuErrFile: return "NufxLib trouble with a file"; case kNuErrFileOpen: return "NufxLib unable to open file"; case kNuErrFileClose: return "NufxLib unable to close file"; case kNuErrFileRead: return "NufxLib unable to read file"; case kNuErrFileWrite: return "NufxLib unable to write file"; case kNuErrFileSeek: return "NufxLib unable to seek file"; case kNuErrFileExists: return "File already exists"; case kNuErrFileNotFound: return "No such file or directory"; case kNuErrFileStat: return "Couldn't get file info"; case kNuErrFileNotReadable: return "Read access denied"; case kNuErrDirExists: return "Directory already exists"; case kNuErrNotDir: return "Not a directory"; case kNuErrNotRegularFile: return "Not a regular file"; case kNuErrDirCreate: return "Unable to create directory"; case kNuErrOpenDir: return "Unable to open directory"; case kNuErrReadDir: return "Unable to read directory"; case kNuErrFileSetDate: return "Unable to set file date"; case kNuErrFileSetAccess: return "Unable to set file access"; case kNuErrFileAccessDenied: return "Access denied"; case kNuErrNotNuFX: return "Input is not a NuFX archive"; case kNuErrBadMHVersion: return "Unrecognized Master Header version"; case kNuErrRecHdrNotFound: return "Next record not found"; case kNuErrNoRecords: return "No records in archive"; case kNuErrBadRecord: return "Bad data in record"; case kNuErrBadMHCRC: return "Bad Master Header CRC"; case kNuErrBadRHCRC: return "Bad Record header CRC"; case kNuErrBadThreadCRC: return "Bad Thread header CRC"; case kNuErrBadDataCRC: return "Data CRC mismatch"; case kNuErrBadFormat: return "Thread compression format unsupported"; case kNuErrBadData: return "Bad data found"; case kNuErrBufferOverrun: return "Buffer overrun"; case kNuErrBufferUnderrun: return "Buffer underrun"; case kNuErrOutMax: return "Output limit exceeded"; case kNuErrNotFound: return "Not found"; case kNuErrRecordNotFound: return "Record not found"; case kNuErrRecIdxNotFound: return "RecordIdx not found"; case kNuErrThreadIdxNotFound: return "ThreadIdx not found"; case kNuErrThreadIDNotFound: return "ThreadID not found"; case kNuErrRecNameNotFound: return "Record name not found"; case kNuErrRecordExists: return "Record already exists"; case kNuErrAllDeleted: return "Tried to delete all files"; case kNuErrArchiveRO: return "Archive is in read-only mode"; case kNuErrModRecChange: return "Attempt to alter a modified record"; case kNuErrModThreadChange: return "Attempt to alter a modified thread"; case kNuErrThreadAdd: return "Can't add conflicting threadID"; case kNuErrNotPreSized: return "Operation only permitted on pre-sized threads"; case kNuErrPreSizeOverflow: return "Data exceeds pre-sized thread size"; case kNuErrInvalidFilename: return "Invalid filename"; case kNuErrLeadingFssep: return "Storage name started with fssep char"; case kNuErrNotNewer: return "New item wasn't newer than existing"; case kNuErrDuplicateNotFound: return "Can only update an existing item"; case kNuErrDamaged: return "Original archive may have been damaged"; case kNuErrIsBinary2: return "This is a Binary II archive"; case kNuErrUnknownFeature: return "Unknown feature"; case kNuErrUnsupFeature: return "Feature not supported"; default: sprintf(defaultMsg, "(error=%d)", err); return defaultMsg; } } #define kNuHeftyBufSize 256 /* all error messages should fit in this */ #define kNuExtraGoodies 8 /* leave room for "\0" and other trivial chars*/ /* * Similar to perror(), but takes the error as an argument, and knows * about NufxLib errors as well as system errors. * * Depending on the compiler, "file", "line", and "function" may be NULL/zero. * * Calling here with "pArchive"==NULL is allowed, but should only be done * if the archive is inaccessible (perhaps because it failed to open). We * can't invoke the error message callback if the pointer is NULL. */ void Nu_ReportError(NuArchive* pArchive, const char* file, int line, const char* function, Boolean isDebug, NuError err, const UNICHAR* format, ...) { NuErrorMessage errorMessage; const char* msg; va_list args; char buf[kNuHeftyBufSize]; int count; #if !defined(HAVE_SNPRINTF) && defined(SPRINTF_RETURNS_INT) int cc; #endif Assert(format != NULL); va_start(args, format); #if defined(HAVE_VSNPRINTF) && defined(VSNPRINTF_DECLARED) count = vsnprintf(buf, sizeof(buf)-kNuExtraGoodies, format, args); #else #ifdef SPRINTF_RETURNS_INT count = vsprintf(buf, format, args); #else vsprintf(buf, format, args); count = strlen(buf); #endif #endif va_end(args); Assert(count > 0); if (count < 0) goto bail; /* print the error code data, if any */ if (err != kNuErrNone) { /* we know we have room for ": ", because of kNuExtraGoodies */ strcpy(buf+count, ": "); count += 2; msg = NULL; if (err >= 0) msg = strerror(err); if (msg == NULL) msg = Nu_StrError(err); #if defined(HAVE_SNPRINTF) && defined(SNPRINTF_DECLARED) if (msg == NULL) snprintf(buf+count, sizeof(buf) - count, "(unknown err=%d)", err); else snprintf(buf+count, sizeof(buf) - count, "%s", msg); #else #ifdef SPRINTF_RETURNS_INT if (msg == NULL) cc = sprintf(buf+count, "(unknown err=%d)", err); else cc = sprintf(buf+count, "%s", msg); Assert(cc > 0); count += cc; #else if (msg == NULL) sprintf(buf+count, "(unknown err=%d)", err); else sprintf(buf+count, "%s", msg); count += strlen(buf + count); #endif #endif } #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) || \ !defined(SNPRINTF_DELCARED) || !defined(VSNPRINTF_DECLARED) /* couldn't do it right, so check for overflow */ Assert(count <= kNuHeftyBufSize); #endif if ((pArchive != NULL && pArchive->messageHandlerFunc == NULL) || (pArchive == NULL && gNuGlobalErrorMessageHandler == NULL)) { if (isDebug) { fprintf(stderr, "%s: [%s:%d %s] %s\n", kNufxLibName, file, line, function, buf); } else { fprintf(stderr, "%s: ERROR: %s\n", kNufxLibName, buf); } } else { errorMessage.message = buf; errorMessage.err = err; errorMessage.isDebug = isDebug; errorMessage.file = file; errorMessage.line = line; errorMessage.function = function; if (pArchive == NULL) (void) (*gNuGlobalErrorMessageHandler)(pArchive, &errorMessage); else (void) (*pArchive->messageHandlerFunc)(pArchive, &errorMessage); } bail: return; } /* * Memory allocation wrappers. * * Under gcc these would be macros, but not all compilers can handle that. * * [ It should be possible to use mmalloc instead of malloc. Just tuck the * mmalloc descriptor into the NuArchive struct. ] */ #ifndef USE_DMALLOC void* Nu_Malloc(NuArchive* pArchive, size_t size) { void* _result; Assert(size > 0); _result = malloc(size); if (_result == NULL) { Nu_ReportError(NU_BLOB, kNuErrMalloc, "malloc(%u) failed", (unsigned int) size); DebugAbort(); /* leave a core dump if we're built for it */ } DebugFill(_result, size); return _result; } void* Nu_Calloc(NuArchive* pArchive, size_t size) { void* _cresult = Nu_Malloc(pArchive, size); memset(_cresult, 0, size); return _cresult; } void* Nu_Realloc(NuArchive* pArchive, void* ptr, size_t size) { void* _result; Assert(ptr != NULL); /* disallow this usage */ Assert(size > 0); /* disallow this usage */ _result = realloc(ptr, size); if (_result == NULL) { Nu_ReportError(NU_BLOB, kNuErrMalloc, "realloc(%u) failed", (unsigned int) size); DebugAbort(); /* leave a core dump if we're built for it */ } return _result; } void Nu_Free(NuArchive* pArchive, void* ptr) { if (ptr != NULL) free(ptr); } #endif /* * If somebody internal wants to set doClose on a buffer DataSource * (looks like "Rename" does), we need to supply a "free" callback. */ NuResult Nu_InternalFreeCallback(NuArchive* pArchive, void* args) { DBUG(("+++ internal free callback 0x%08lx\n", (long) args)); Nu_Free(NULL, args); return kNuOK; } nulib2-3.1.0/nufxlib/NOTES.md000066400000000000000000000377441316100516500156040ustar00rootroot00000000000000NufxLib NOTES ============= Last revised: 2015/01/04 The interface is documented in "nufxlibapi.html", available from the http://www.nulib.com/ web site. This discusses some of the internal design that may be of interest. Some familiarity with the NuFX file format is assumed. - - - ### Read-Write Data Structures ### For both read-only and read-write files (but not streaming read-only files), the archive is represented internally as a linked list of Records, each of which has an array of Threads attached. No attempt is made to optimize searches by filename, so use of the "replace existing entry when filenames match" option should be restricted to situations where it is necessary. Otherwise, O(N^2) behavior can result. Modifications, such as deletions, changes to filename threads, and additions of new records, are queued up in a separate list until a NuFlush call is issued. The list works much the same way as the temporary file: when the operation completes, the "new" list becomes the "original" list. If the operation is aborted, the "new" list is scrubbed, and the "original" list remains unmodified. Just as it is inefficient to write data to the temp file when it's not necessary to do so, it is inefficient to allocate a complete copy of the records from the original list if none are changed. As a result, there are actually two "new" lists, one with a copy of the original record list, and one with new additions. The "copy" list starts out uninitialized, and remains that way until one of the entries from the original list is modified. When that happens, the entire original list is duplicated, and the changes are made directly to members of the "copy" list. (This is important for really large archives, like a by-file archive with the entire contents of a hard drive, where the record index could be several megabytes in size.) It would be more *memory* efficient to simply maintain a list of what has changed. However, we can't disturb the "original" list in any way or we lose the ability to roll back quickly if the operation is aborted. Consequently, we need to create a new list of records that reflects the state of the new archive, so that when we rename the temp file over the original, we can simply "rename" the new record list over the original. Since we're going to need the new list eventually, we might as well create it as soon as it is needed, and deal with memory allocation failures up front rather than during the update process. (Some items, such as the record's file offset in the archive, have to be updated even for records that aren't themselves changing... which means we potentially need to modify all existing record structures, so we need a complete copy of the record list regardless of how little or how much has changed.) This also ties into the "modify original archive file directly if possible" option, which avoids the need for creating and renaming a temp file. If the only changes are updates to pre-sized records (e.g. renaming a file inside the archive, or updating a comment), or adding new records onto the end, there is little risk and possibly a huge efficiency gain in just modifying the archive in place. If none of the operations caused the "copy" list to be initialized, then clearly there's no need to write to a temp file. (It's not actually this simple, because updates to pre-sized threads are annotated in the "copy" list.) One of the goals was to be able to execute a sequence of operations like: open original archive read original archive modify archive flush (success) modify archive flush (failure, rollback) modify archive flush (success) close archive The archive is opened at the start and held open across many operations. There is never a need to re-read the entire archive. We could avoid the need to allocate two complete Record lists by requiring that the archive be re-scanned after changes are aborted; if we did that, we could just modify the original record list in place, and let the changes become "permanent" after a successful write. In many ways, though, its cleaner to have two lists. Archives with several thousand entries should be sufficiently rare, and virtual memory should be sufficiently plentiful, that this won't be a problem for anyone. Scanning repeatedly through a 15MB archive stored on a CD-ROM is likely to be very annoying though, so the design makes every attempt to avoid repeated scans of the archive. And in any event, this only applies to archive updates. The memory requirements for simple file extraction are minimal. In summary: - "orig" list has original set of records, and is not disturbed until the changes are committed. - "copy" list is created on first add/update/delete operation, and initially contains a complete copy of "orig". - "new" list contains all new additions to the archive, including new additions that replace existing entries (the existing entry is deleted from "copy" and then added to "new"). Each Record in the list has a "thread modification" list attached to it. Any changes to the record header or additions to the thread mod list are made in the "copy" set; the "original" set remains untouched. The thread mod list can have the following items in it: - delete thread (NuThreadIdx) - add thread (type, otherSize, format, +contents) - update pre-sized thread (NuThreadIdx, +contents) Contents are specified with a NuDataSource, which allows the application to indicate that the data is already compressed. This is useful for copying parts of records between archives without having to expand and recompress the data. Some interactions and concepts that are important to understand: When a file is added, the file type information will be placed in the "new" Record immediately (subject to some restrictions: adding a data fork always causes the type info to be updated, adding a rsrc fork only updates the type info if a data fork is not already present). Deleting a record results in the Record being removed from the "copy" list immediately. Future modify operations on that NuRecordIdx will fail. Future read operations will work just fine until the next NuFlush is issued, because read operations use the "original" list. Deleting all threads from a record results in the record being deleted, but not until the NuFlush call is issued. It is possible to delete all the existing threads and then add new ones. It is *not* allowed to delete a modified thread, modify a deleted thread, or delete a record that has been modified. This limitation was added to keep the system simple. Note this does not mean you can't delete a data fork and add a data fork; doing so results in operations on two threads with different NuThreadIdx values. What you can't do is update the filename thread and then delete it, or vice-versa. (If anyone can think of a reason why you'd want to rename a file and then delete it with the same NuFlush call, I'll figure out a way to support it.) Updating a filename thread is intercepted, and causes the Record's filename cache to be updated as well. Adding a filename thread for records where the filename is stored in the record itself cause the "in-record" filename to be zeroed. Adding a filename thread to a record that already has one isn't allowed; nufxlib restricts you to a single filename thread per record. Some actions on an archive are allowed but strongly discouraged. For example, deleting a filename thread but leaving the data threads behind is a valid thing to do, but leaves most archivers in a state of mild confusion. Deleting the data threads but leaving the filename thread is similarly perplexing. You can't call "update thread" on a thread that doesn't yet exist, even if an "add thread" call has been made. You can, however, call "add thread" on a newly created Record. When a new record is created because of a "create record" call, a filename thread is created automatically. It is not necessary to explicitly add the filename. Failures encountered while committing changes to a record cause all operations on that record to be rolled back. If, during a NuFlush, a file add fails, the user is given the option of aborting the entire operation or skipping the file in question (and perhaps retrying or other options as well). Aborting the flush causes a complete rollback. If only the thread mod operation is canceled, then all thread mods for that record are ignored. The temp file (or archive file) will have its file pointer reset to the original start of the record, and if the record already existed in the original archive, the full original record will be copied over. This may seem drastic, but it helps ensure that you don't end up with a record in a partially created state. If a failure occurs during an "update in place", it isn't possible to roll back all changes. If the failure was due to a bug in NufxLib, it is possible that the archive could be unrecoverably damaged. NufxLib tries to identify such situations, and will leave the archive open in read-only mode after rolling back any new file additions. - - - ### Updating Filenames ### Updating filenames is a small nightmare, because the filename can be either in the record header or in a filename thread. It's possible, but illogical, to have a single record with a filename in the record header and two or more filenames in threads. NufxLib will not automatically "fix" broken records, but it will prevent applications from creating situations that should not exist. - When reading an archive, NufxLib will use the filename from the first filename thread found. If no filename threads are found, the filename from the record header will be used. - If you add a filename thread to a record that has a filename in the record header, the header name will be removed. - If you update a filename thread in a record that has a filename in the record header, the header name will be left untouched. - Adding a filename thread is only allowed if no filename thread exists, or all existing filename threads have been deleted. - - - ### Unicode Filenames ### Modern operating systems support filenames with a broader range of characters than the Apple II did. This presents problems and opportunities. #### Background #### The Apple IIgs and old Macintoshes use the Mac OS Roman ("MOR") character set. This defines a set of characters outside the ASCII range, i.e. byte values with the high bit set. In addition to the usual collection of vowels with accents and umlauts, MOR has some less-common characters, including the Apple logo. On Windows, the high-ASCII values are generally interpreted according to Windows Code Page 1252 ("CP-1252"), which defines a similar set of vowels with accents and miscellaneous symbols. MOR and CP-1252 have some overlap, but you can't really translate one into the other. The standards-approved equivalent of CP-1252 is ISO-8859-1, though according to [wikipedia](http://en.wikipedia.org/wiki/Windows-1252) there was some confusion between the two. Modern operating systems support the Unicode Universal Character Set. This system allows for a very large number of characters (over a million), and includes definitions for all of the symbols in MOR and CP-1252. Each character is assigned a "code point", which is a numeric value between zero and 0x10FFFF. Most of the characters used in modern languages can be found in the Basic Multilingual Plane (BMP), which uses code points between zero and 0xFFFF (requiring only 16 bits). There are different ways of encoding code points. Consider, for example, Unicode LATIN SMALL LETTER A WITH ACUTE: MOR: 0x87 CP-1252: 0xE1 Unicode: U+00E1 UTF-16: 0x00E1 UTF-8: 0xC3 0xA1 Or the humble TRADE MARK SIGN: MOR: 0xAA CP-1252: 0x99 Unicode: U+2122 UTF-16: 0x2122 UTF-8: 0xE2 0x84 0xA2 Modern Linux and Mac OS X use UTF-8 encoding in filenames. Because it's a byte-oriented encoding, and 7-bit ASCII values are trivially represented as 7-bit ASCII values, all of the existing system and library calls work as they did before (i.e. if they took a `char*`, they still do). Windows uses UTF-16, which requires at least 16 bits per code point. Filenames are now "wide" strings, based on `wchar_t*`. Windows includes an elaborate system of defines based around the `TCHAR` type, which can be either `char` or `wchar_t` depending on whether a program is compiled with `_MBCS` (Multi-Byte Character System) or `_UNICODE`. A set of preprocessor definitions is provided that will map I/O function names, so you can call `_tfopen(TCHAR* ...)`, and the compiler will turn it into either `fopen(char* ...)` or `_wfopen(wchar_t* ...)`. MBCS is deprecated in favor of Unicode, so any new code should be strictly UTF-16 based. This means that, for code to work on both Linux and Windows, it has to work with incompatible filename string types and different I/O functions. #### Opening Archive Files #### On Linux and Mac OS X, NuLib2 can open any file named on the command line. On Windows, it's a bit trickier. The problem is that NuLib2 provides a `main()` function that is passed a vector of "narrow" strings. The filenames provided on the command line will be converted from wide to narrow, so unless the filename is entirely composed of ASCII or CP-1252 characters, some information will be lost and it will be impossible to open the file. NuLib2 must instead provide a `wmain()` function that takes wide strings. The strings must be stored and passed around as wide throughout the program, and passed into NufxLib this way (because NufxLib issues the actual _wopen call). This means that NufxLib API must take narrow strings when built for Linux, and wide strings when built for Windows. #### Adding/Extracting Mac OS Roman Files #### GS/ShrinkIt was designed to handle GS/OS files from HFS volumes, so NuFX archive filenames use the MOR character set. To preserve the encoding we could simply extract the values as-is and let them appear as whatever values happen to line up in CP-1252, which is what pre-3.0 NuLib2 did. It's much nicer to translate from MOR to Unicode when extracting, and convert back from Unicode to MOR when adding files to an archive. The key consideration is that the character set associated with a filename must be tracked. The code can't simply extract a filename from the archive and pass it to a 'creat()` call. Character set conversions must take place at appropriate times. With Windows it's a bit harder to confuse MOR and Unicode names, because one uses 8-bit characters and the other uses UTF-16, but the compiler doesn't catch everything. #### Current State #### NufxLib defines the UNICHAR type, which has a role very like TCHAR: it can be `char*` or `wchar_t*`, and can be accompanied by a set of preprocessor mappings that switch between I/O functions. The UNICHAR type will be determined based on a define provided from the compiler command line (perhaps `-DUSE_UTF16_FILENAMES`). The current version of NufxLib (v3.0.0) takes the first step, defining all filename strings as either UNICHAR or MOR, and converting between them as necessary. This, plus a few minor tweaks to NuLib2, was enough to get Unicode filename support working on Linux and Mac OS X. None of the work needed to make Windows work properly has been done. The string conversion functions are no-ops for Win32. As a result, NuLib2 for Windows treats filenames the same way in 3.x as it did in 2.x. There are some situations where things can go awry even with UNICHAR, most notably printf-style arguments. These are checked by gcc, but not by Visual Studio unless you run the static analyzer. A simple `printf("filename=%s\n", filename)` would be correct for narrow strings but wrong for wide strings. It will likely be necessary to define a filename format string (similar to `PRI64d` for 64-bit values) and switch between "%s" and "%ls". This is a fair bit of work and requires some amount of uglification to NuLib2 and NufxLib. Since Windows users can use CiderPress, and the vast majority of NuFX archives use ASCII-only ProDOS file names, it's not clear that the effort would be worthwhile. nulib2-3.1.0/nufxlib/NufxLib.h000066400000000000000000001045731316100516500161050ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * External interface (types, defines, and function prototypes). */ #ifndef NUFXLIB_NUFXLIB_H #define NUFXLIB_NUFXLIB_H #include #include #ifdef __cplusplus extern "C" { #endif /* * NufxLib version number. Compare these values (which represent the * version against which your application was compiled) to the values * returned by NuGetVersion (representing the version against which * your application is statically or dynamically linked). If the major * number doesn't match exactly, an existing interface has changed and you * should halt immediately. If the minor number from NuGetVersion is * less, there may be new interfaces, new features, or bug fixes missing * upon which your application depends, so you should halt immediately. * (If the minor number is greater, there are new features, but your * application will not be affected by them.) * * The "bug" version can usually be ignored, since it represents minor * fixes. Unless, of course, your code depends upon that fix. */ #define kNuVersionMajor 3 #define kNuVersionMinor 1 #define kNuVersionBug 0 /* * =========================================================================== * Types * =========================================================================== */ /* * Unicode character type. For Linux and Mac OS X, filenames use "narrow" * characters and UTF-8 encoding, which allows them to use standard file I/O * functions like fopen(). Windows uses UTF-16, which requires a different * character type and an alternative set of I/O functions like _wfopen(). * * The idea is that NufxLib API functions will operate on filenames with * the OS dominant method, so on Windows the API accepts UTF-16. This * definition is a bit like Windows TCHAR, but it's dependent on the OS, not * on whether _MBCS or _UNICODE is defined. * * The app can include "Unichar.h" to get definitions for functions that * switch between narrow and wide functions (e.g. "unistrlen()" becomes * strlen() or wcslen() as appropriate). * * We switch based on _WIN32, because we're not really switching on * filename-character size; the key issue is all the pesky wide I/O calls. */ #if defined(_WIN32) // TODO: complete this //# include //# define UNICHAR wchar_t # define UNICHAR char #else # define UNICHAR char #endif /* * Error values returned from functions. * * These are negative so that they don't conflict with system-defined * errors (like ENOENT). A NuError can hold either. */ typedef enum NuError { kNuErrNone = 0, kNuErrGeneric = -1, kNuErrInternal = -2, kNuErrUsage = -3, kNuErrSyntax = -4, kNuErrMalloc = -5, kNuErrInvalidArg = -6, kNuErrBadStruct = -7, kNuErrUnexpectedNil = -8, kNuErrBusy = -9, kNuErrSkipped = -10, /* processing skipped by request */ kNuErrAborted = -11, /* processing aborted by request */ kNuErrRename = -12, /* user wants to rename before extracting */ kNuErrFile = -20, kNuErrFileOpen = -21, kNuErrFileClose = -22, kNuErrFileRead = -23, kNuErrFileWrite = -24, kNuErrFileSeek = -25, kNuErrFileExists = -26, /* existed when it shouldn't */ kNuErrFileNotFound = -27, /* didn't exist when it should have */ kNuErrFileStat = -28, /* some sort of GetFileInfo failure */ kNuErrFileNotReadable = -29, /* bad access permissions */ kNuErrDirExists = -30, /* dir exists, don't need to create it */ kNuErrNotDir = -31, /* expected a dir, got a regular file */ kNuErrNotRegularFile = -32, /* expected regular file, got weirdness */ kNuErrDirCreate = -33, /* unable to create a directory */ kNuErrOpenDir = -34, /* error opening directory */ kNuErrReadDir = -35, /* error reading directory */ kNuErrFileSetDate = -36, /* unable to set file date */ kNuErrFileSetAccess = -37, /* unable to set file access permissions */ kNuErrFileAccessDenied = -38, /* equivalent to EACCES */ kNuErrNotNuFX = -40, /* 'NuFile' missing; not a NuFX archive? */ kNuErrBadMHVersion = -41, /* bad master header version */ kNuErrRecHdrNotFound = -42, /* 'NuFX' missing; corrupted archive? */ kNuErrNoRecords = -43, /* archive doesn't have any records */ kNuErrBadRecord = -44, /* something about the record looked bad */ kNuErrBadMHCRC = -45, /* bad master header CRC */ kNuErrBadRHCRC = -46, /* bad record header CRC */ kNuErrBadThreadCRC = -47, /* bad thread header CRC */ kNuErrBadDataCRC = -48, /* bad CRC detected in the data */ kNuErrBadFormat = -50, /* compression type not supported */ kNuErrBadData = -51, /* expansion func didn't like input */ kNuErrBufferOverrun = -52, /* overflowed a user buffer */ kNuErrBufferUnderrun = -53, /* underflowed a user buffer */ kNuErrOutMax = -54, /* output limit exceeded */ kNuErrNotFound = -60, /* (generic) search unsuccessful */ kNuErrRecordNotFound = -61, /* search for specific record failed */ kNuErrRecIdxNotFound = -62, /* search by NuRecordIdx failed */ kNuErrThreadIdxNotFound = -63, /* search by NuThreadIdx failed */ kNuErrThreadIDNotFound = -64, /* search by NuThreadID failed */ kNuErrRecNameNotFound = -65, /* search by storageName failed */ kNuErrRecordExists = -66, /* found existing record with same name */ kNuErrAllDeleted = -70, /* attempt to delete everything */ kNuErrArchiveRO = -71, /* archive is open in read-only mode */ kNuErrModRecChange = -72, /* tried to change modified record */ kNuErrModThreadChange = -73, /* tried to change modified thread */ kNuErrThreadAdd = -74, /* adding that thread creates a conflict */ kNuErrNotPreSized = -75, /* tried to update a non-pre-sized thread */ kNuErrPreSizeOverflow = -76, /* too much data */ kNuErrInvalidFilename = -77, /* invalid filename */ kNuErrLeadingFssep = -80, /* names in archives must not start w/sep */ kNuErrNotNewer = -81, /* item same age or older than existing */ kNuErrDuplicateNotFound = -82, /* "must overwrite" was set, but item DNE */ kNuErrDamaged = -83, /* original archive may have been damaged */ kNuErrIsBinary2 = -90, /* this looks like a Binary II archive */ kNuErrUnknownFeature =-100, /* attempt to test unknown feature */ kNuErrUnsupFeature = -101, /* feature not supported */ } NuError; /* * Return values from callback functions. */ typedef enum NuResult { kNuOK = 0, kNuSkip = 1, kNuAbort = 2, /*kNuAbortAll = 3,*/ kNuRetry = 4, kNuIgnore = 5, kNuRename = 6, kNuOverwrite = 7 } NuResult; /* * NuRecordIdxs are assigned to records in an archive. You may assume that * the values are unique, but that is all. */ typedef uint32_t NuRecordIdx; /* * NuThreadIdxs are assigned to threads within a record. Again, you may * assume that the values are unique within a record, but that is all. */ typedef uint32_t NuThreadIdx; /* * Thread ID, a combination of thread_class and thread_kind. Standard * values have explicit identifiers. */ typedef uint32_t NuThreadID; #define NuMakeThreadID(class, kind) /* construct a NuThreadID */ \ ((uint32_t)(class) << 16 | (uint32_t)(kind)) #define NuGetThreadID(pThread) /* pull NuThreadID out of NuThread */ \ (NuMakeThreadID((pThread)->thThreadClass, (pThread)->thThreadKind)) #define NuThreadIDGetClass(threadID) /* get threadClass from NuThreadID */ \ ((uint16_t) ((uint32_t)(threadID) >> 16)) #define NuThreadIDGetKind(threadID) /* get threadKind from NuThreadID */ \ ((uint16_t) ((threadID) & 0xffff)) #define kNuThreadClassMessage 0x0000 #define kNuThreadClassControl 0x0001 #define kNuThreadClassData 0x0002 #define kNuThreadClassFilename 0x0003 #define kNuThreadKindDataFork 0x0000 /* when class=data */ #define kNuThreadKindDiskImage 0x0001 /* when class=data */ #define kNuThreadKindRsrcFork 0x0002 /* when class=data */ #define kNuThreadIDOldComment NuMakeThreadID(kNuThreadClassMessage, 0x0000) #define kNuThreadIDComment NuMakeThreadID(kNuThreadClassMessage, 0x0001) #define kNuThreadIDIcon NuMakeThreadID(kNuThreadClassMessage, 0x0002) #define kNuThreadIDMkdir NuMakeThreadID(kNuThreadClassControl, 0x0000) #define kNuThreadIDDataFork NuMakeThreadID(kNuThreadClassData, kNuThreadKindDataFork) #define kNuThreadIDDiskImage NuMakeThreadID(kNuThreadClassData, kNuThreadKindDiskImage) #define kNuThreadIDRsrcFork NuMakeThreadID(kNuThreadClassData, kNuThreadKindRsrcFork) #define kNuThreadIDFilename NuMakeThreadID(kNuThreadClassFilename, 0x0000) #define kNuThreadIDWildcard NuMakeThreadID(0xffff, 0xffff) /* enumerate the possible values for thThreadFormat */ typedef enum NuThreadFormat { kNuThreadFormatUncompressed = 0x0000, kNuThreadFormatHuffmanSQ = 0x0001, kNuThreadFormatLZW1 = 0x0002, kNuThreadFormatLZW2 = 0x0003, kNuThreadFormatLZC12 = 0x0004, kNuThreadFormatLZC16 = 0x0005, kNuThreadFormatDeflate = 0x0006, /* NOTE: not in NuFX standard */ kNuThreadFormatBzip2 = 0x0007, /* NOTE: not in NuFX standard */ } NuThreadFormat; /* extract the filesystem separator char from the "file_sys_info" field */ #define NuGetSepFromSysInfo(sysInfo) \ ((UNICHAR) ((sysInfo) & 0xff)) /* return a file_sys_info with a replaced filesystem separator */ #define NuSetSepInSysInfo(sysInfo, newSep) \ ((uint16_t) (((sysInfo) & 0xff00) | ((newSep) & 0xff)) ) /* GS/OS-defined file system identifiers; sadly, UNIX is not among them */ typedef enum NuFileSysID { kNuFileSysUnknown = 0, /* NuFX spec says use this */ kNuFileSysProDOS = 1, kNuFileSysDOS33 = 2, kNuFileSysDOS32 = 3, kNuFileSysPascal = 4, kNuFileSysMacHFS = 5, kNuFileSysMacMFS = 6, kNuFileSysLisa = 7, kNuFileSysCPM = 8, kNuFileSysCharFST = 9, kNuFileSysMSDOS = 10, kNuFileSysHighSierra = 11, kNuFileSysISO9660 = 12, kNuFileSysAppleShare = 13 } NuFileSysID; /* simplified definition of storage types */ typedef enum NuStorageType { kNuStorageUnknown = 0, /* (used by ProDOS for deleted files) */ kNuStorageSeedling = 1, /* <= 512 bytes */ kNuStorageSapling = 2, /* < 128KB */ kNuStorageTree = 3, /* < 16MB */ kNuStoragePascalVol = 4, /* (embedded pascal volume; rare) */ kNuStorageExtended = 5, /* forked (any size) */ kNuStorageDirectory = 13, /* directory */ kNuStorageSubdirHeader = 14, /* (only used in subdir headers) */ kNuStorageVolumeHeader = 15, /* (only used in volume dir header) */ } NuStorageType; /* bit flags for NuOpenRW */ enum { kNuOpenCreat = 0x0001, kNuOpenExcl = 0x0002 }; /* * The actual NuArchive structure is opaque, and should only be visible * to the library. We define it here as an ambiguous struct. */ typedef struct NuArchive NuArchive; /* * Generic callback prototype. */ typedef NuResult (*NuCallback)(NuArchive* pArchive, void* args); /* * Parameters that affect archive operations. */ typedef enum NuValueID { kNuValueInvalid = 0, kNuValueIgnoreCRC = 1, kNuValueDataCompression = 2, kNuValueDiscardWrapper = 3, kNuValueEOL = 4, kNuValueConvertExtractedEOL = 5, kNuValueOnlyUpdateOlder = 6, kNuValueAllowDuplicates = 7, kNuValueHandleExisting = 8, kNuValueModifyOrig = 9, kNuValueMimicSHK = 10, kNuValueMaskDataless = 11, kNuValueStripHighASCII = 12, kNuValueJunkSkipMax = 13, kNuValueIgnoreLZW2Len = 14, kNuValueHandleBadMac = 15 } NuValueID; typedef uint32_t NuValue; /* * Enumerated values for things you pass in a NuValue. */ enum NuValueValue { /* for the truly retentive */ kNuValueFalse = 0, kNuValueTrue = 1, /* for kNuValueDataCompression */ kNuCompressNone = 10, kNuCompressSQ = 11, kNuCompressLZW1 = 12, kNuCompressLZW2 = 13, kNuCompressLZC12 = 14, kNuCompressLZC16 = 15, kNuCompressDeflate = 16, kNuCompressBzip2 = 17, /* for kNuValueEOL */ kNuEOLUnknown = 50, kNuEOLCR = 51, kNuEOLLF = 52, kNuEOLCRLF = 53, /* for kNuValueConvertExtractedEOL */ kNuConvertOff = 60, kNuConvertOn = 61, kNuConvertAuto = 62, /* for kNuValueHandleExisting */ kNuMaybeOverwrite = 90, kNuNeverOverwrite = 91, kNuAlwaysOverwrite = 93, kNuMustOverwrite = 94 }; /* * Pull out archive attributes. */ typedef enum NuAttrID { kNuAttrInvalid = 0, kNuAttrArchiveType = 1, kNuAttrNumRecords = 2, kNuAttrHeaderOffset = 3, kNuAttrJunkOffset = 4, } NuAttrID; typedef uint32_t NuAttr; /* * Archive types. */ typedef enum NuArchiveType { kNuArchiveUnknown, /* .??? */ kNuArchiveNuFX, /* .SHK (sometimes .SDK) */ kNuArchiveNuFXInBNY, /* .BXY */ kNuArchiveNuFXSelfEx, /* .SEA */ kNuArchiveNuFXSelfExInBNY, /* .BSE */ kNuArchiveBNY /* .BNY, .BQY - not supported */ } NuArchiveType; /* * Some common values for "locked" and "unlocked". Under ProDOS each bit * can be set independently, so don't use these defines to *interpret* * what you see. They're reasonable things to *set* the access field to. * * The defined bits are: * 0x80 'D' destroy enabled * 0x40 'N' rename enabled * 0x20 'B' file needs to be backed up * 0x10 (reserved, must be zero) * 0x08 (reserved, must be zero) * 0x04 'I' file is invisible * 0x02 'W' write enabled * 0x01 'R' read enabled */ #define kNuAccessLocked 0x21 #define kNuAccessUnlocked 0xe3 /* * NuFlush result flags. */ #define kNuFlushSucceeded (1L) #define kNuFlushAborted (1L << 1) #define kNuFlushCorrupted (1L << 2) #define kNuFlushReadOnly (1L << 3) #define kNuFlushInaccessible (1L << 4) /* * =========================================================================== * NuFX archive defintions * =========================================================================== */ typedef struct NuThreadMod NuThreadMod; /* dummy def for internal struct */ typedef union NuDataSource NuDataSource; /* dummy def for internal struct */ typedef union NuDataSink NuDataSink; /* dummy def for internal struct */ /* * NuFX Date/Time structure; same as TimeRec from IIgs "misctool.h". */ typedef struct NuDateTime { uint8_t second; /* 0-59 */ uint8_t minute; /* 0-59 */ uint8_t hour; /* 0-23 */ uint8_t year; /* year - 1900 */ uint8_t day; /* 0-30 */ uint8_t month; /* 0-11 */ uint8_t extra; /* (must be zero) */ uint8_t weekDay; /* 1-7 (1=sunday) */ } NuDateTime; /* * NuFX "thread" definition. * * Guaranteed not to have pointers in it. Can be copied with memcpy or * assignment. */ typedef struct NuThread { /* from the archive */ uint16_t thThreadClass; NuThreadFormat thThreadFormat; uint16_t thThreadKind; uint16_t thThreadCRC; /* comp or uncomp data; see rec vers */ uint32_t thThreadEOF; uint32_t thCompThreadEOF; /* extra goodies */ NuThreadIdx threadIdx; uint32_t actualThreadEOF; /* disk images might be off */ long fileOffset; /* fseek offset to data in shk */ /* internal use only */ uint16_t used; /* mark as uninteresting */ } NuThread; /* * NuFX "record" definition. * * (Note to developers: update Nu_AddRecord if this changes.) * * The filenames are in Mac OS Roman format. It's arguable whether MOR * strings should be part of the interface at all. However, the API * pre-dates the inclusion of Unicode support, and I'm leaving it alone. */ #define kNufxIDLen 4 /* len of 'NuFX' with funky MSBs */ #define kNuReasonableAttribCount 256 #define kNuReasonableFilenameLen 1024 #define kNuReasonableTotalThreads 16 #define kNuMaxRecordVersion 3 /* max we can handle */ #define kNuOurRecordVersion 3 /* what we write */ typedef struct NuRecord { /* version 0+ */ uint8_t recNufxID[kNufxIDLen]; uint16_t recHeaderCRC; uint16_t recAttribCount; uint16_t recVersionNumber; uint32_t recTotalThreads; NuFileSysID recFileSysID; uint16_t recFileSysInfo; uint32_t recAccess; uint32_t recFileType; uint32_t recExtraType; uint16_t recStorageType; /* NuStorage*,file_sys_block_size */ NuDateTime recCreateWhen; NuDateTime recModWhen; NuDateTime recArchiveWhen; /* option lists only in version 1+ */ uint16_t recOptionSize; uint8_t* recOptionList; /* NULL if v0 or recOptionSize==0 */ /* data specified by recAttribCount, not accounted for by option list */ int32_t extraCount; uint8_t* extraBytes; uint16_t recFilenameLength; /* usually zero */ char* recFilenameMOR; /* doubles as disk volume_name */ /* extra goodies; "dirtyHeader" does not apply to anything below */ NuRecordIdx recordIdx; /* session-unique record index */ char* threadFilenameMOR; /* extracted from filename thread */ char* newFilenameMOR; /* memorized during "add file" call */ const char* filenameMOR; /* points at recFilen or threadFilen */ uint32_t recHeaderLength; /* size of rec hdr, incl thread hdrs */ uint32_t totalCompLength; /* total len of data in archive file */ uint32_t fakeThreads; /* used by "MaskDataless" */ int isBadMac; /* malformed "bad mac" header */ long fileOffset; /* file offset of record header */ /* use provided interface to access this */ struct NuThread* pThreads; /* ptr to thread array */ /* private -- things the application shouldn't look at */ struct NuRecord* pNext; /* used internally */ NuThreadMod* pThreadMods; /* used internally */ short dirtyHeader; /* set in "copy" when hdr fields uptd */ short dropRecFilename; /* if set, we're dropping this name */ } NuRecord; /* * NuFX "master header" definition. * * The "mhReserved2" entry doesn't appear in my copy of the $e0/8002 File * Type Note, but as best as I can recall the MH block must be 48 bytes. */ #define kNufileIDLen 6 /* length of 'NuFile' with funky MSBs */ #define kNufileMasterReserved1Len 8 #define kNufileMasterReserved2Len 6 #define kNuMaxMHVersion 2 /* max we can handle */ #define kNuOurMHVersion 2 /* what we write */ typedef struct NuMasterHeader { uint8_t mhNufileID[kNufileIDLen]; uint16_t mhMasterCRC; uint32_t mhTotalRecords; NuDateTime mhArchiveCreateWhen; NuDateTime mhArchiveModWhen; uint16_t mhMasterVersion; uint8_t mhReserved1[kNufileMasterReserved1Len]; uint32_t mhMasterEOF; uint8_t mhReserved2[kNufileMasterReserved2Len]; /* private -- internal use only */ short isValid; } NuMasterHeader; /* * =========================================================================== * Misc declarations * =========================================================================== */ /* * Record attributes that can be changed with NuSetRecordAttr. This is * a small subset of the full record. */ typedef struct NuRecordAttr { NuFileSysID fileSysID; /*uint16_t fileSysInfo;*/ uint32_t access; uint32_t fileType; uint32_t extraType; NuDateTime createWhen; NuDateTime modWhen; NuDateTime archiveWhen; } NuRecordAttr; /* * Some additional details about a file. * * Ideally (from an API cleanliness perspective) the storage name would * be passed around as UTF-8 and converted internally. Passing it as * MOR required fewer changes to the library, and allows us to avoid * having to deal with illegal characters. */ typedef struct NuFileDetails { /* used during AddFile call */ NuThreadID threadID; /* data, rsrc, disk img? */ const void* origName; /* arbitrary pointer, usually a string */ /* these go straight into the NuRecord */ const char* storageNameMOR; NuFileSysID fileSysID; uint16_t fileSysInfo; uint32_t access; uint32_t fileType; uint32_t extraType; uint16_t storageType; /* use Unknown, or disk block size */ NuDateTime createWhen; NuDateTime modWhen; NuDateTime archiveWhen; } NuFileDetails; /* * Passed into the SelectionFilter callback. */ typedef struct NuSelectionProposal { const NuRecord* pRecord; const NuThread* pThread; } NuSelectionProposal; /* * Passed into the OutputPathnameFilter callback. */ typedef struct NuPathnameProposal { const UNICHAR* pathnameUNI; UNICHAR filenameSeparator; const NuRecord* pRecord; const NuThread* pThread; const UNICHAR* newPathnameUNI; UNICHAR newFilenameSeparator; /*NuThreadID newStorage;*/ NuDataSink* newDataSink; } NuPathnameProposal; /* used by error handler and progress updater to indicate what we're doing */ typedef enum NuOperation { kNuOpUnknown = 0, kNuOpAdd, kNuOpExtract, kNuOpTest, kNuOpDelete, /* not used for progress updates */ kNuOpContents /* not used for progress updates */ } NuOperation; /* state of progress when adding or extracting */ typedef enum NuProgressState { kNuProgressPreparing, /* not started yet */ kNuProgressOpening, /* opening files */ kNuProgressAnalyzing, /* analyzing data */ kNuProgressCompressing, /* compressing data */ kNuProgressStoring, /* storing (no compression) data */ kNuProgressExpanding, /* expanding data */ kNuProgressCopying, /* copying data (in or out) */ kNuProgressDone, /* all done, success */ kNuProgressSkipped, /* all done, we skipped this one */ kNuProgressAborted, /* all done, user cancelled the operation */ kNuProgressFailed /* all done, failure */ } NuProgressState; /* * Passed into the ProgressUpdater callback. All pointers become * invalid when the callback returns. * * [ Thought for the day: add an optional flag that causes us to only * call the progressFunc when the "percentComplete" changes by more * than a specified amount. ] */ typedef struct NuProgressData { /* what are we doing */ NuOperation operation; /* what specifically are we doing */ NuProgressState state; /* how far along are we */ short percentComplete; /* 0-100 */ /* original pathname (in archive for expand, on disk for compress) */ const UNICHAR* origPathnameUNI; /* processed pathname (PathnameFilter for expand, in-record for compress) */ const UNICHAR* pathnameUNI; /* basename of "pathname" (for convenience) */ const UNICHAR* filenameUNI; /* pointer to the record we're expanding from */ const NuRecord* pRecord; uint32_t uncompressedLength; /* size of uncompressed data */ uint32_t uncompressedProgress; /* #of bytes in/out */ struct { NuThreadFormat threadFormat; /* compression being applied */ } compress; struct { uint32_t totalCompressedLength; /* all "data" threads */ uint32_t totalUncompressedLength; /*uint32_t compressedLength; * size of compressed data */ /*uint32_t compressedProgress; * #of compressed bytes in/out*/ const NuThread* pThread; /* thread we're working on */ NuValue convertEOL; /* set if LF/CR conv is on */ } expand; /* pay no attention */ NuCallback progressFunc; } NuProgressData; /* * Passed into the ErrorHandler callback. */ typedef struct NuErrorStatus { NuOperation operation; /* were we adding, extracting, ?? */ NuError err; /* library error code */ int sysErr; /* system error code, if applicable */ const UNICHAR* message; /* (optional) message to user */ const NuRecord* pRecord; /* relevant record, if any */ const UNICHAR* pathnameUNI; /* problematic pathname, if any */ const void* origPathname; /* original pathname ref, if any */ UNICHAR filenameSeparator; /* fssep for pathname, if any */ /*char origArchiveTouched;*/ char canAbort; /* give option to abort */ /*char canAbortAll;*/ /* abort + discard all recent changes */ char canRetry; /* give option to retry same op */ char canIgnore; /* give option to ignore error */ char canSkip; /* give option to skip this file/rec */ char canRename; /* give option to rename file */ char canOverwrite; /* give option to overwrite file */ } NuErrorStatus; /* * Error message callback gets one of these. */ typedef struct NuErrorMessage { const char* message; /* the message itself (UTF-8) */ NuError err; /* relevant error code (may be none) */ short isDebug; /* set for debug-only messages */ /* these identify where the message originated if lib built w/debug set */ const char* file; /* source file (UTF-8) */ int line; /* line number */ const char* function; /* function name (might be NULL) */ } NuErrorMessage; /* * Options for the NuTestFeature function. */ typedef enum NuFeature { kNuFeatureUnknown = 0, kNuFeatureCompressSQ = 1, /* kNuThreadFormatHuffmanSQ */ kNuFeatureCompressLZW = 2, /* kNuThreadFormatLZW1 and LZW2 */ kNuFeatureCompressLZC = 3, /* kNuThreadFormatLZC12 and LZC16 */ kNuFeatureCompressDeflate = 4, /* kNuThreadFormatDeflate */ kNuFeatureCompressBzip2 = 5, /* kNuThreadFormatBzip2 */ } NuFeature; /* * =========================================================================== * Function prototypes * =========================================================================== */ /* * Win32 dll magic. */ #if defined(_WIN32) # include # if defined(NUFXLIB_EXPORTS) /* building the NufxLib DLL */ # define NUFXLIB_API __declspec(dllexport) # elif defined (NUFXLIB_DLL) /* building to link against the NufxLib DLL */ # define NUFXLIB_API __declspec(dllimport) # else /* using static libs */ # define NUFXLIB_API # endif #else /* not using Win32... hooray! */ # define NUFXLIB_API #endif /* streaming and non-streaming read-only interfaces */ NUFXLIB_API NuError NuStreamOpenRO(FILE* infp, NuArchive** ppArchive); NUFXLIB_API NuError NuContents(NuArchive* pArchive, NuCallback contentFunc); NUFXLIB_API NuError NuExtract(NuArchive* pArchive); NUFXLIB_API NuError NuTest(NuArchive* pArchive); /* strictly non-streaming read-only interfaces */ NUFXLIB_API NuError NuOpenRO(const UNICHAR* archivePathnameUNI, NuArchive** ppArchive); NUFXLIB_API NuError NuExtractRecord(NuArchive* pArchive, NuRecordIdx recordIdx); NUFXLIB_API NuError NuExtractThread(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSink* pDataSink); NUFXLIB_API NuError NuTestRecord(NuArchive* pArchive, NuRecordIdx recordIdx); NUFXLIB_API NuError NuGetRecord(NuArchive* pArchive, NuRecordIdx recordIdx, const NuRecord** ppRecord); NUFXLIB_API NuError NuGetRecordIdxByName(NuArchive* pArchive, const char* nameMOR, NuRecordIdx* pRecordIdx); NUFXLIB_API NuError NuGetRecordIdxByPosition(NuArchive* pArchive, uint32_t position, NuRecordIdx* pRecordIdx); /* read/write interfaces */ NUFXLIB_API NuError NuOpenRW(const UNICHAR* archivePathnameUNI, const UNICHAR* tempPathnameUNI, uint32_t flags, NuArchive** ppArchive); NUFXLIB_API NuError NuFlush(NuArchive* pArchive, uint32_t* pStatusFlags); NUFXLIB_API NuError NuAddRecord(NuArchive* pArchive, const NuFileDetails* pFileDetails, NuRecordIdx* pRecordIdx); NUFXLIB_API NuError NuAddThread(NuArchive* pArchive, NuRecordIdx recordIdx, NuThreadID threadID, NuDataSource* pDataSource, NuThreadIdx* pThreadIdx); NUFXLIB_API NuError NuAddFile(NuArchive* pArchive, const UNICHAR* pathnameUNI, const NuFileDetails* pFileDetails, short fromRsrcFork, NuRecordIdx* pRecordIdx); NUFXLIB_API NuError NuRename(NuArchive* pArchive, NuRecordIdx recordIdx, const char* pathnameMOR, char fssep); NUFXLIB_API NuError NuSetRecordAttr(NuArchive* pArchive, NuRecordIdx recordIdx, const NuRecordAttr* pRecordAttr); NUFXLIB_API NuError NuUpdatePresizedThread(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSource* pDataSource, int32_t* pMaxLen); NUFXLIB_API NuError NuDelete(NuArchive* pArchive); NUFXLIB_API NuError NuDeleteRecord(NuArchive* pArchive, NuRecordIdx recordIdx); NUFXLIB_API NuError NuDeleteThread(NuArchive* pArchive, NuThreadIdx threadIdx); /* general interfaces */ NUFXLIB_API NuError NuClose(NuArchive* pArchive); NUFXLIB_API NuError NuAbort(NuArchive* pArchive); NUFXLIB_API NuError NuGetMasterHeader(NuArchive* pArchive, const NuMasterHeader** ppMasterHeader); NUFXLIB_API NuError NuGetExtraData(NuArchive* pArchive, void** ppData); NUFXLIB_API NuError NuSetExtraData(NuArchive* pArchive, void* pData); NUFXLIB_API NuError NuGetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue); NUFXLIB_API NuError NuSetValue(NuArchive* pArchive, NuValueID ident, NuValue value); NUFXLIB_API NuError NuGetAttr(NuArchive* pArchive, NuAttrID ident, NuAttr* pAttr); NUFXLIB_API NuError NuDebugDumpArchive(NuArchive* pArchive); /* sources and sinks */ NUFXLIB_API NuError NuCreateDataSourceForFile(NuThreadFormat threadFormat, uint32_t otherLen, const UNICHAR* pathnameUNI, short isFromRsrcFork, NuDataSource** ppDataSource); NUFXLIB_API NuError NuCreateDataSourceForFP(NuThreadFormat threadFormat, uint32_t otherLen, FILE* fp, long offset, long length, NuCallback closeFunc, NuDataSource** ppDataSource); NUFXLIB_API NuError NuCreateDataSourceForBuffer(NuThreadFormat threadFormat, uint32_t otherLen, const uint8_t* buffer, long offset, long length, NuCallback freeFunc, NuDataSource** ppDataSource); NUFXLIB_API NuError NuFreeDataSource(NuDataSource* pDataSource); NUFXLIB_API NuError NuDataSourceSetRawCrc(NuDataSource* pDataSource, uint16_t crc); NUFXLIB_API NuError NuCreateDataSinkForFile(short doExpand, NuValue convertEOL, const UNICHAR* pathnameUNI, UNICHAR fssep, NuDataSink** ppDataSink); NUFXLIB_API NuError NuCreateDataSinkForFP(short doExpand, NuValue convertEOL, FILE* fp, NuDataSink** ppDataSink); NUFXLIB_API NuError NuCreateDataSinkForBuffer(short doExpand, NuValue convertEOL, uint8_t* buffer, uint32_t bufLen, NuDataSink** ppDataSink); NUFXLIB_API NuError NuFreeDataSink(NuDataSink* pDataSink); NUFXLIB_API NuError NuDataSinkGetOutCount(NuDataSink* pDataSink, uint32_t* pOutCount); /* miscellaneous non-archive operations */ NUFXLIB_API NuError NuGetVersion(int32_t* pMajorVersion, int32_t* pMinorVersion, int32_t* pBugVersion, const char** ppBuildDate, const char** ppBuildFlags); NUFXLIB_API const char* NuStrError(NuError err); NUFXLIB_API NuError NuTestFeature(NuFeature feature); NUFXLIB_API void NuRecordCopyAttr(NuRecordAttr* pRecordAttr, const NuRecord* pRecord); NUFXLIB_API NuError NuRecordCopyThreads(const NuRecord* pRecord, NuThread** ppThreads); NUFXLIB_API uint32_t NuRecordGetNumThreads(const NuRecord* pRecord); NUFXLIB_API const NuThread* NuThreadGetByIdx(const NuThread* pThread, int32_t idx); NUFXLIB_API short NuIsPresizedThreadID(NuThreadID threadID); NUFXLIB_API size_t NuConvertMORToUNI(const char* stringMOR, UNICHAR* bufUNI, size_t bufSize); NUFXLIB_API size_t NuConvertUNIToMOR(const UNICHAR* stringUNI, char* bufMOR, size_t bufSize); #define NuGetThread(pRecord, idx) ( (const NuThread*) \ ((uint32_t) (idx) < (pRecord)->recTotalThreads ? \ &(pRecord)->pThreads[(idx)] : NULL) \ ) /* callback setters */ #define kNuInvalidCallback ((NuCallback) 1) NUFXLIB_API NuCallback NuSetSelectionFilter(NuArchive* pArchive, NuCallback filterFunc); NUFXLIB_API NuCallback NuSetOutputPathnameFilter(NuArchive* pArchive, NuCallback filterFunc); NUFXLIB_API NuCallback NuSetProgressUpdater(NuArchive* pArchive, NuCallback updateFunc); NUFXLIB_API NuCallback NuSetErrorHandler(NuArchive* pArchive, NuCallback errorFunc); NUFXLIB_API NuCallback NuSetErrorMessageHandler(NuArchive* pArchive, NuCallback messageHandlerFunc); NUFXLIB_API NuCallback NuSetGlobalErrorMessageHandler(NuCallback messageHandlerFunc); #ifdef __cplusplus } #endif #endif /*NUFXLIB_NUFXLIB_H*/ nulib2-3.1.0/nufxlib/NufxLibPriv.h000066400000000000000000001067441316100516500167500ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Global internal declarations and definitions. */ #ifndef NUFXLIB_NUFXLIBPRIV_H #define NUFXLIB_NUFXLIBPRIV_H /* include files that everybody needs */ #include "SysDefs.h" #include "NufxLib.h" #include "MiscStuff.h" #ifdef USE_DMALLOC /* enable with something like "dmalloc -l logfile -i 100 medium" */ # include "dmalloc.h" #endif /* * =========================================================================== * NuArchive definition * =========================================================================== */ /* * Archives can be opened in streaming read-only, non-streaming read-only, * and non-streaming read-write mode. */ typedef enum NuOpenMode { kNuOpenUnknown, kNuOpenStreamingRO, kNuOpenRO, kNuOpenRW } NuOpenMode; #define Nu_IsStreaming(pArchive) ((pArchive)->openMode == kNuOpenStreamingRO) #define Nu_IsReadOnly(pArchive) ((pArchive)->openMode == kNuOpenStreamingRO ||\ (pArchive)->openMode == kNuOpenRO) #ifdef FOPEN_WANTS_B # define kNuFileOpenReadOnly "rb" # define kNuFileOpenReadWrite "r+b" # define kNuFileOpenWriteTrunc "wb" # define kNuFileOpenReadWriteCreat "w+b" #else # define kNuFileOpenReadOnly "r" # define kNuFileOpenReadWrite "r+" # define kNuFileOpenWriteTrunc "w" # define kNuFileOpenReadWriteCreat "w+" #endif /* * Some NuFX and Binary II definitions. */ #define kNuMasterHeaderSize 48 /* size of fixed-length master header */ #define kNuRecordHeaderBaseSize 58 /* size of rec hdr up to variable stuff */ #define kNuThreadHeaderSize 16 /* size of fixed-length thread header */ #define kNuDefaultFilenameThreadSize 32 /* default size of filename thred */ #define kNuDefaultCommentSize 200 /* size of GSHK-mimic comments */ #define kNuBinary2BlockSize 128 /* size of bxy header and padding */ #define kNuSEAOffset 0x2ee5 /* fixed(??) offset to data in SEA */ #define kNuInitialChunkCRC 0x0000 /* start for CRC in LZW/1 chunk */ #define kNuInitialThreadCRC 0xffff /* start for CRC in v3 thread header */ /* size of general-purpose compression buffer */ #define kNuGenCompBufSize 32768 #define kNuCharLF 0x0a #define kNuCharCR 0x0d /* * A list of records. Generally we use one of these for read-only * archives, and two for read-write. * * The "loaded" flag is set when we've made some use of the record set. * Relying on "numRecords" won't always work; for example, if the "copy" * record set was initialized from "orig", and then had all of its records * deleted, you couldn't look at "numRecords" and decide whether it was * appropriate to use "orig" or not. */ typedef struct NuRecordSet { Boolean loaded; uint32_t numRecords; NuRecord* nuRecordHead; NuRecord* nuRecordTail; } NuRecordSet; /* * Archive state. */ struct NuArchive { uint32_t structMagic; Boolean busy; NuOpenMode openMode; Boolean newlyCreated; UNICHAR* archivePathnameUNI; /* pathname or "(stream)" */ FILE* archiveFp; NuArchiveType archiveType; /* stuff before NuFX; both offsets are from 0, i.e. hdrOff includes junk */ long junkOffset; /* skip past leading junk */ long headerOffset; /* adjustment for BXY/SEA/BSE */ UNICHAR* tmpPathnameUNI; /* temp file, for writes */ FILE* tmpFp; /* used during initial processing; helps avoid ftell() calls */ long currentOffset; /* setting this changes Extract into Test */ Boolean testMode; /* clumsy way of remembering name used for other fork in forked file */ const UNICHAR* lastFileCreatedUNI; /* clumsy way to avoid trying to create the same subdir several times */ const UNICHAR* lastDirCreatedUNI; /* master header from the archive */ NuMasterHeader masterHeader; /* original */ NuMasterHeader newMasterHeader; /* working copy during update */ /* list of records from archive, plus some extra state */ NuRecordIdx recordIdxSeed; /* where the NuRecordIdxs start */ NuRecordIdx nextRecordIdx; /* next record gets this value */ Boolean haveToc; /* set if we have full TOC */ NuRecordSet origRecordSet; /* records from archive */ NuRecordSet copyRecordSet; /* copy of orig, for write ops */ NuRecordSet newRecordSet; /* newly-added records */ /* state for compression functions */ uint8_t* compBuf; /* large general-purpose buffer */ void* lzwCompressState; /* state for LZW/1 and LZW/2 */ void* lzwExpandState; /* state for LZW/1 and LZW/2 */ /* options and attributes that the user can set */ /* (these can be changed by a callback, so don't cache them internally) */ void* extraData; /* application-defined pointer */ NuValue valAllowDuplicates; /* allow dups when adding? */ NuValue valConvertExtractedEOL; /* convert EOL during extract? */ NuValue valDataCompression; /* how to compress when adding? */ NuValue valDiscardWrapper; /* remove BNY or SEA header? */ NuValue valEOL; /* EOL value to convert to */ NuValue valHandleExisting; /* how to deal with existing files*/ NuValue valIgnoreCRC; /* don't compute or test CRCs */ NuValue valMaskDataless; /* alter Records w/o data threads */ NuValue valMimicSHK; /* mimic some ShrinkIt quirks */ NuValue valModifyOrig; /* modify original arc in place? */ NuValue valOnlyUpdateOlder; /* modify original arc in place? */ NuValue valStripHighASCII; /* during EOL conv, strip hi bit? */ NuValue valJunkSkipMax; /* scan this far for header */ NuValue valIgnoreLZW2Len; /* don't verify LZW/II len field */ NuValue valHandleBadMac; /* handle "bad Mac" archives */ /* callback functions */ NuCallback selectionFilterFunc; NuCallback outputPathnameFunc; NuCallback progressUpdaterFunc; NuCallback errorHandlerFunc; NuCallback messageHandlerFunc; }; #define kNuArchiveStructMagic 0xc0edbabe #define kNuDefaultRecordName "UNKNOWN" /* use ASCII charset */ /* * =========================================================================== * ThreadMod definition * =========================================================================== */ /* operations we can perform on threads in a record */ typedef enum ThreadModKind { kNuThreadModUnknown = 0, kNuThreadModAdd, kNuThreadModUpdate, kNuThreadModDelete } ThreadModKind; /* * We attach a list of these to records we plan to modify. Care is taken * to ensure that they don't conflict, e.g. you can't update a thread * right after you delete it, nor delete one you have modified. */ struct NuThreadMod { union { ThreadModKind kind; struct { ThreadModKind kind; Boolean used; } generic; struct { ThreadModKind kind; Boolean used; Boolean isPresized; NuThreadIdx threadIdx; NuThreadID threadID; NuThreadFormat threadFormat; NuDataSource* pDataSource; } add; struct { ThreadModKind kind; Boolean used; NuThreadIdx threadIdx; NuDataSource* pDataSource; } update; struct { ThreadModKind kind; Boolean used; NuThreadIdx threadIdx; NuThreadID threadID; /* used for watching filename threads */ } delete; } entry; struct NuThreadMod* pNext; }; /* * =========================================================================== * NuFunnel/NuStraw definition * =========================================================================== */ #define kNuFunnelBufSize 16384 /* * File funnel definition. This is used for writing output to files * (so we can do things like pipe compressed output through an LF->CR * converter) and archive files (so we can halt compression when the * output size exceeds the uncompressed original). [ for various reasons, * I'm not using this on the archive anymore. ] * * Funnels are unidirectional. You write data into them with a * function call; the top-level action (which is usually compressing or * expanding data) reads from the input and crams things into the pipe. * We could fully abstract the concept, and write the compression * functions so that they operate as a Funnel filter, but it's much * easier to write block-oriented compression than stream-oriented (and * more to the point, the ShrinkIt LZW functions are very much * block-oriented). */ typedef struct NuFunnel { /* data storage */ uint8_t* buffer; /* kNuFunnelBufSize worth of storage */ long bufCount; /* #of bytes in buffer */ /* text conversion; if "auto", on first flush we convert to "on" or "off" */ NuValue convertEOL; /* on/off/auto */ NuValue convertEOLTo; /* EOL to switch to */ NuValue convertEOLFrom; /* EOL terminator we think we found */ Boolean checkStripHighASCII; /* do we want to check for it? */ Boolean doStripHighASCII; /* strip high ASCII during EOL conv */ Boolean lastCR; /* was last char a CR? */ Boolean isFirstWrite; /* cleared on first write */ #if 0 uint32_t inCount; /* total #of bytes in the top */ uint32_t outCount; /* total #of bytes out the bottom */ uint32_t outMax; /* flag an err when outCount exceeds this */ Boolean outMaxExceeded; /* in fact, it's this flag */ #endif /* update this when stuff happens */ NuProgressData* pProgress; /* data goeth out here */ NuDataSink* pDataSink; } NuFunnel; /* * File straw definition. This is used for slurping up input data. * * Mostly this is an encapsulation of an input source and a progress * updater, useful for reading uncompressed data and feeding it to a * compressor. It doesn't make sense to show a thermometer based on * compressed output, since we don't know how big the eventual result * will be, so we want to do it for the input. */ typedef struct NuStraw { /* update this when stuff happens */ NuProgressData* pProgress; /* data cometh in here */ NuDataSource* pDataSource; /* progress update fields */ uint32_t lastProgress; uint32_t lastDisplayed; } NuStraw; /*NuError Nu_CopyStreamToStream(FILE* outfp, FILE* infp, uint32_t count);*/ /* * =========================================================================== * Data source and sink abstractions * =========================================================================== */ /* * DataSource is used when adding data to an archive. */ typedef enum NuDataSourceType { kNuDataSourceUnknown = 0, kNuDataSourceFromFile, kNuDataSourceFromFP, kNuDataSourceFromBuffer } NuDataSourceType; typedef struct NuDataSourceCommon { NuDataSourceType sourceType; NuThreadFormat threadFormat; /* is it already compressed? */ uint16_t rawCrc; /* crc for already-compressed data*/ /*Boolean doClose; \* close on completion? */ uint32_t dataLen; /* length of data (var for buf) */ uint32_t otherLen; /* uncomp len or preset buf size */ int refCount; /* so we can copy structs */ } NuDataSourceCommon; union NuDataSource { NuDataSourceType sourceType; NuDataSourceCommon common; struct { NuDataSourceCommon common; UNICHAR* pathnameUNI; Boolean fromRsrcFork; /* temp storage; only valid when processing in library */ FILE* fp; } fromFile; struct { NuDataSourceCommon common; FILE* fp; long offset; /* starting offset */ NuCallback fcloseFunc; /* how to fclose the file */ } fromFP; struct { NuDataSourceCommon common; const uint8_t* buffer; /* non-const if doClose=true */ long offset; /* starting offset */ long curOffset; /* current offset */ long curDataLen; /* remaining data */ NuCallback freeFunc; /* how to free data */ } fromBuffer; }; /* * DataSink is used when extracting data from an archive. */ typedef enum NuDataSinkType { kNuDataSinkUnknown = 0, kNuDataSinkToFile, kNuDataSinkToFP, kNuDataSinkToBuffer, kNuDataSinkToVoid } NuDataSinkType; typedef struct NuDataSinkCommon { NuDataSinkType sinkType; Boolean doExpand; /* expand file? */ NuValue convertEOL; /* convert EOL? (req "expand") */ uint32_t outCount; } NuDataSinkCommon; union NuDataSink { NuDataSinkType sinkType; NuDataSinkCommon common; struct { NuDataSinkCommon common; UNICHAR* pathnameUNI; /* file to open */ UNICHAR fssep; /* temp storage; must be NULL except when processing in library */ FILE* fp; } toFile; struct { NuDataSinkCommon common; FILE* fp; } toFP; struct { NuDataSinkCommon common; uint8_t* buffer; uint32_t bufLen; /* max amount of data "buffer" holds */ NuError stickyErr; } toBuffer; }; /* * =========================================================================== * Function prototypes * =========================================================================== */ /* * This is a little unpleasant. This blob of stuff gets stuffed in as * the first arguments to Nu_ReportError, so we don't have to type them * in every time we use the function. It would've been much easier to * use a gcc-style varargs macro, but not everybody uses gcc. * * TODO: Visual C++ has vararg macros now; time to replace this. */ #ifdef HAS__FUNCTION__ # define _FUNCTION_ __FUNCTION__ #else # define _FUNCTION_ "" #endif #define NU_BLOB pArchive, __FILE__, __LINE__, _FUNCTION_, false #define NU_BLOB_DEBUG pArchive, __FILE__, __LINE__, _FUNCTION_, true #define NU_NILBLOB NULL, __FILE__, __LINE__, _FUNCTION_, false #ifdef DEBUG_MSGS # define DebugShowError(err) \ Nu_ReportError(pArchive, __FILE__, __LINE__, _FUNCTION_, \ true, err, "(DEBUG)"); #else # define DebugShowError(err) ((void)0) #endif /* * The BailError macro serves two purposes. First, it's a convenient * way to avoid typing, "if (err != kNuErrNone) goto bail;". Second, * when the library is built with debugging enabled, it vitually gives * us a stack trace of exiting functions. This makes it easier to debug * problems sent in as screen dumps via e-mail. */ #define BailError(err) { \ if ((err) != kNuErrNone) { \ /* [should this be debug-only, or all the time?] */ \ DebugShowError(err); \ goto bail; \ } \ } #define BailErrorQuiet(err) { \ if ((err) != kNuErrNone) \ goto bail; \ } #define BailNil(val) { \ if ((val) == NULL) { \ err = kNuErrUnexpectedNil; \ BailError(err); \ } \ } #define BailAlloc(val) { \ if ((val) == NULL) { \ err = kNuErrMalloc; \ BailError(err); \ } \ } /* * Internal function prototypes and inline functions. */ /* Archive.c */ void Nu_MasterHeaderCopy(NuArchive* pArchive, NuMasterHeader* pDstHeader, const NuMasterHeader* pSrcHeader); NuError Nu_GetMasterHeader(NuArchive* pArchive, const NuMasterHeader** ppMasterHeader); NuRecordIdx Nu_GetNextRecordIdx(NuArchive* pArchive); NuThreadIdx Nu_GetNextThreadIdx(NuArchive* pArchive); NuError Nu_CopyWrapperToTemp(NuArchive* pArchive); NuError Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp); NuError Nu_AdjustWrapperPadding(NuArchive* pArchive, FILE* fp); NuError Nu_AllocCompressionBufferIFN(NuArchive* pArchive); NuError Nu_StreamOpenRO(FILE* infp, NuArchive** ppArchive); NuError Nu_OpenRO(const UNICHAR* archivePathnameUNI, NuArchive** ppArchive); NuError Nu_OpenRW(const UNICHAR* archivePathnameUNI, const UNICHAR* tempPathnameUNI, uint32_t flags, NuArchive** ppArchive); NuError Nu_WriteMasterHeader(NuArchive* pArchive, FILE* fp, NuMasterHeader* pMasterHeader); NuError Nu_Close(NuArchive* pArchive); NuError Nu_Abort(NuArchive* pArchive); NuError Nu_RenameTempToArchive(NuArchive* pArchive); NuError Nu_DeleteArchiveFile(NuArchive* pArchive); /* ArchiveIO.c */ uint8_t Nu_ReadOneC(NuArchive* pArchive, FILE* fp, uint16_t* pCrc); uint8_t Nu_ReadOne(NuArchive* pArchive, FILE* fp); void Nu_WriteOneC(NuArchive* pArchive, FILE* fp, uint8_t val, uint16_t* pCrc); void Nu_WriteOne(NuArchive* pArchive, FILE* fp, uint8_t val); uint16_t Nu_ReadTwoC(NuArchive* pArchive, FILE* fp, uint16_t* pCrc); uint16_t Nu_ReadTwo(NuArchive* pArchive, FILE* fp); void Nu_WriteTwoC(NuArchive* pArchive, FILE* fp, uint16_t val, uint16_t* pCrc); void Nu_WriteTwo(NuArchive* pArchive, FILE* fp, uint16_t val); uint32_t Nu_ReadFourC(NuArchive* pArchive, FILE* fp, uint16_t* pCrc); uint32_t Nu_ReadFour(NuArchive* pArchive, FILE* fp); void Nu_WriteFourC(NuArchive* pArchive, FILE* fp, uint32_t val, uint16_t* pCrc); void Nu_WriteFour(NuArchive* pArchive, FILE* fp, uint32_t val); NuDateTime Nu_ReadDateTimeC(NuArchive* pArchive, FILE* fp, uint16_t* pCrc); NuDateTime Nu_ReadDateTime(NuArchive* pArchive, FILE* fp, uint16_t* pCrc); void Nu_WriteDateTimeC(NuArchive* pArchive, FILE* fp, NuDateTime dateTime, uint16_t* pCrc); void Nu_WriteDateTime(NuArchive* pArchive, FILE* fp, NuDateTime dateTime); void Nu_ReadBytesC(NuArchive* pArchive, FILE* fp, void* vbuffer, long count, uint16_t* pCrc); void Nu_ReadBytes(NuArchive* pArchive, FILE* fp, void* vbuffer, long count); void Nu_WriteBytesC(NuArchive* pArchive, FILE* fp, const void* vbuffer, long count, uint16_t* pCrc); void Nu_WriteBytes(NuArchive* pArchive, FILE* fp, const void* vbuffer, long count); NuError Nu_HeaderIOFailed(NuArchive* pArchive, FILE* fp); NuError Nu_SeekArchive(NuArchive* pArchive, FILE* fp, long offset, int ptrname); NuError Nu_RewindArchive(NuArchive* pArchive); /* Bzip2.c */ NuError Nu_CompressBzip2(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc); NuError Nu_ExpandBzip2(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc); /* Charset.c */ size_t Nu_ConvertMORToUNI(const char* stringMOR, UNICHAR* bufUNI, size_t bufSize); UNICHAR* Nu_CopyMORToUNI(const char* stringMOR); size_t Nu_ConvertUNIToMOR(const UNICHAR* stringUNI, char* bufMOR, size_t bufSize); /* Compress.c */ NuError Nu_CompressToArchive(NuArchive* pArchive, NuDataSource* pDataSource, NuThreadID threadID, NuThreadFormat sourceFormat, NuThreadFormat targetFormat, NuProgressData* progressData, FILE* dstFp, NuThread* pThread); NuError Nu_CopyPresizedToArchive(NuArchive* pArchive, NuDataSource* pDataSource, NuThreadID threadID, FILE* dstFp, NuThread* pThread, char** ppSavedCopy); /* Crc16.c */ extern const uint16_t gNuCrc16Table[256]; uint16_t Nu_CalcCRC16(uint16_t seed, const uint8_t* ptr, int count); /* * Update the CRC-16. * * _val (uint8_t) is the byte to add to the CRC. It's evaluated once. * _crc (uint16_t) is the previous CRC. It's evaluated twice. * Returns the updated CRC as a uint16_t. */ #define Nu_UpdateCRC16(_val, _crc) \ (gNuCrc16Table[(((_crc) >> 8) & 0xff) ^ (_val)] ^ ((_crc) << 8)) /* Debug.c */ #if defined(DEBUG_MSGS) || !defined(NDEBUG) void Nu_DebugDumpAll(NuArchive* pArchive); void Nu_DebugDumpThread(const NuThread* pThread); #endif /* Deferred.c */ NuError Nu_ThreadModAdd_New(NuArchive* pArchive, NuThreadID threadID, NuThreadFormat threadFormat, NuDataSource* pDataSource, NuThreadMod** ppThreadMod); NuError Nu_ThreadModUpdate_New(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSource* pDataSource, NuThreadMod** ppThreadMod); NuError Nu_ThreadModDelete_New(NuArchive* pArchive, NuThreadIdx threadIdx, NuThreadID threadID, NuThreadMod** ppThreadMod); void Nu_ThreadModFree(NuArchive* pArchive, NuThreadMod* pThreadMod); NuError Nu_ThreadModAdd_FindByThreadID(const NuRecord* pRecord, NuThreadID threadID, NuThreadMod** ppThreadMod); void Nu_FreeThreadMods(NuArchive* pArchive, NuRecord* pRecord); NuThreadMod* Nu_ThreadMod_FindByThreadIdx(const NuRecord* pRecord, NuThreadIdx threadIdx); NuError Nu_Flush(NuArchive* pArchive, uint32_t* pStatusFlags); /* Deflate.c */ NuError Nu_CompressDeflate(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc); NuError Nu_ExpandDeflate(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc); /* Expand.c */ NuError Nu_ExpandStream(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel); /* FileIO.c */ void Nu_SetCurrentDateTime(NuDateTime* pDateTime); Boolean Nu_IsOlder(const NuDateTime* pWhen1, const NuDateTime* pWhen2); NuError Nu_OpenOutputFile(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, const UNICHAR* newPathnameUNI, UNICHAR newFssep, FILE** pFp); NuError Nu_CloseOutputFile(NuArchive* pArchive, const NuRecord* pRecord, FILE* fp, const UNICHAR* pathnameUNI); NuError Nu_OpenInputFile(NuArchive* pArchive, const UNICHAR* pathnameUNI, Boolean openRsrc, FILE** pFp); NuError Nu_DeleteFile(const UNICHAR* pathnameUNI); NuError Nu_RenameFile(const UNICHAR* fromPathUNI, const UNICHAR* toPathUNI); NuError Nu_FTell(FILE* fp, long* pOffset); NuError Nu_FSeek(FILE* fp, long offset, int ptrname); NuError Nu_FRead(FILE* fp, void* buf, size_t nbyte); NuError Nu_FWrite(FILE* fp, const void* buf, size_t nbyte); NuError Nu_CopyFileSection(NuArchive* pArchive, FILE* dstFp, FILE* srcFp, long length); NuError Nu_GetFileLength(NuArchive* pArchive, FILE* fp, long* pLength); NuError Nu_TruncateOpenFile(FILE* fp, long length); /* Funnel.c */ NuError Nu_ProgressDataInit_Compress(NuArchive* pArchive, NuProgressData* pProgressData, const NuRecord* pRecord, const UNICHAR* origPathnameUNI, const UNICHAR* pathnameUNI); NuError Nu_ProgressDataInit_Expand(NuArchive* pArchive, NuProgressData* pProgressData, const NuRecord* pRecord, const UNICHAR* newPathnameUNI, UNICHAR newFssep, const UNICHAR* origPathnameUNI, NuValue convertEOL); NuError Nu_SendInitialProgress(NuArchive* pArchive, NuProgressData* pProgress); NuError Nu_FunnelNew(NuArchive* pArchive, NuDataSink* pDataSink, NuValue convertEOL, NuValue convertEOLTo, NuProgressData* pProgress, NuFunnel** ppFunnel); NuError Nu_FunnelFree(NuArchive* pArchive, NuFunnel* pFunnel); /*void Nu_FunnelSetMaxOutput(NuFunnel* pFunnel, uint32_t maxBytes);*/ NuError Nu_FunnelWrite(NuArchive* pArchive, NuFunnel* pFunnel, const uint8_t* buffer, uint32_t count); NuError Nu_FunnelFlush(NuArchive* pArchive, NuFunnel* pFunnel); NuError Nu_ProgressDataCompressPrep(NuArchive* pArchive, NuStraw* pStraw, NuThreadFormat threadFormat, uint32_t sourceLen); NuError Nu_ProgressDataExpandPrep(NuArchive* pArchive, NuFunnel* pFunnel, const NuThread* pThread); NuError Nu_FunnelSetProgressState(NuFunnel* pFunnel, NuProgressState state); NuError Nu_FunnelSendProgressUpdate(NuArchive* pArchive, NuFunnel* pFunnel); Boolean Nu_FunnelGetDoExpand(NuFunnel* pFunnel); NuError Nu_StrawNew(NuArchive* pArchive, NuDataSource* pDataSource, NuProgressData* pProgress, NuStraw** ppStraw); NuError Nu_StrawFree(NuArchive* pArchive, NuStraw* pStraw); NuError Nu_StrawSetProgressState(NuStraw* pStraw, NuProgressState state); NuError Nu_StrawSendProgressUpdate(NuArchive* pArchive, NuStraw* pStraw); NuError Nu_StrawRead(NuArchive* pArchive, NuStraw* pStraw, uint8_t* buffer, long len); NuError Nu_StrawRewind(NuArchive* pArchive, NuStraw* pStraw); /* Lzc.c */ NuError Nu_CompressLZC12(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc); NuError Nu_CompressLZC16(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc); NuError Nu_ExpandLZC(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc); /* Lzw.c */ NuError Nu_CompressLZW1(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc); NuError Nu_CompressLZW2(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc); NuError Nu_ExpandLZW(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pThreadCrc); /* MiscUtils.c */ /*extern const char* kNufxLibName;*/ extern NuCallback gNuGlobalErrorMessageHandler; const char* Nu_StrError(NuError err); void Nu_ReportError(NuArchive* pArchive, const char* file, int line, const char* function, Boolean isDebug, NuError err, const UNICHAR* format, ...) #if defined(__GNUC__) __attribute__ ((format(printf, 7, 8))) #endif ; #ifdef USE_DMALLOC /* want file and line numbers for calls */ # define Nu_Malloc(archive, size) malloc(size) # define Nu_Calloc(archive, size) calloc(1, size) # define Nu_Realloc(archive, ptr, size) realloc(ptr, size) # define Nu_Free(archive, ptr) (ptr != NULL ? free(ptr) : (void)0) #else void* Nu_Malloc(NuArchive* pArchive, size_t size); void* Nu_Calloc(NuArchive* pArchive, size_t size); void* Nu_Realloc(NuArchive* pArchive, void* ptr, size_t size); void Nu_Free(NuArchive* pArchive, void* ptr); #endif NuResult Nu_InternalFreeCallback(NuArchive* pArchive, void* args); /* Record.c */ void Nu_RecordAddThreadMod(NuRecord* pRecord, NuThreadMod* pThreadMod); Boolean Nu_RecordIsEmpty(NuArchive* pArchive, const NuRecord* pRecord); Boolean Nu_RecordSet_GetLoaded(const NuRecordSet* pRecordSet); uint32_t Nu_RecordSet_GetNumRecords(const NuRecordSet* pRecordSet); void Nu_RecordSet_SetNumRecords(NuRecordSet* pRecordSet, uint32_t val); void Nu_RecordSet_IncNumRecords(NuRecordSet* pRecordSet); NuRecord* Nu_RecordSet_GetListHead(const NuRecordSet* pRecordSet); NuRecord** Nu_RecordSet_GetListHeadPtr(NuRecordSet* pRecordSet); NuRecord* Nu_RecordSet_GetListTail(const NuRecordSet* pRecordSet); Boolean Nu_RecordSet_IsEmpty(const NuRecordSet* pRecordSet); NuError Nu_RecordSet_FreeAllRecords(NuArchive* pArchive, NuRecordSet* pRecordSet); NuError Nu_RecordSet_DeleteRecordPtr(NuArchive* pArchive, NuRecordSet* pRecordSet, NuRecord** ppRecord); NuError Nu_RecordSet_DeleteRecord(NuArchive* pArchive, NuRecordSet* pRecordSet, NuRecord* pRecord); NuError Nu_RecordSet_Clone(NuArchive* pArchive, NuRecordSet* pDstSet, const NuRecordSet* pSrcSet); NuError Nu_RecordSet_MoveAllRecords(NuArchive* pArchive, NuRecordSet* pDstSet, NuRecordSet* pSrcSet); NuError Nu_RecordSet_FindByIdx(const NuRecordSet* pRecordSet, NuRecordIdx rec, NuRecord** ppRecord); NuError Nu_RecordSet_FindByThreadIdx(NuRecordSet* pRecordSet, NuThreadIdx threadIdx, NuRecord** ppRecord, NuThread** ppThread); NuError Nu_RecordSet_ReplaceRecord(NuArchive* pArchive, NuRecordSet* pBadSet, NuRecord* pBadRecord, NuRecordSet* pGoodSet, NuRecord** ppGoodRecord); Boolean Nu_ShouldIgnoreBadCRC(NuArchive* pArchive, const NuRecord* pRecord, NuError err); NuError Nu_WriteRecordHeader(NuArchive* pArchive, NuRecord* pRecord, FILE* fp); NuError Nu_GetTOCIfNeeded(NuArchive* pArchive); NuError Nu_StreamContents(NuArchive* pArchive, NuCallback contentFunc); NuError Nu_StreamExtract(NuArchive* pArchive); NuError Nu_StreamTest(NuArchive* pArchive); NuError Nu_Contents(NuArchive* pArchive, NuCallback contentFunc); NuError Nu_Extract(NuArchive* pArchive); NuError Nu_ExtractRecord(NuArchive* pArchive, NuRecordIdx recIdx); NuError Nu_Test(NuArchive* pArchive); NuError Nu_TestRecord(NuArchive* pArchive, NuRecordIdx recIdx); NuError Nu_GetRecord(NuArchive* pArchive, NuRecordIdx recordIdx, const NuRecord** ppRecord); NuError Nu_GetRecordIdxByName(NuArchive* pArchive, const char* nameMOR, NuRecordIdx* pRecordIdx); NuError Nu_GetRecordIdxByPosition(NuArchive* pArchive, uint32_t position, NuRecordIdx* pRecordIdx); NuError Nu_FindRecordForWriteByIdx(NuArchive* pArchive, NuRecordIdx recIdx, NuRecord** ppFoundRecord); NuError Nu_AddFile(NuArchive* pArchive, const UNICHAR* pathnameUNI, const NuFileDetails* pFileDetails, Boolean fromRsrcFork, NuRecordIdx* pRecordIdx); NuError Nu_AddRecord(NuArchive* pArchive, const NuFileDetails* pFileDetails, NuRecordIdx* pRecordIdx, NuRecord** ppRecord); NuError Nu_Rename(NuArchive* pArchive, NuRecordIdx recIdx, const char* pathnameMOR, char fssepMOR); NuError Nu_SetRecordAttr(NuArchive* pArchive, NuRecordIdx recordIdx, const NuRecordAttr* pRecordAttr); NuError Nu_Delete(NuArchive* pArchive); NuError Nu_DeleteRecord(NuArchive* pArchive, NuRecordIdx rec); /* SourceSink.c */ NuError Nu_DataSourceFile_New(NuThreadFormat threadFormat, uint32_t otherLen, const UNICHAR* pathnameUNI, Boolean isFromRsrcFork, NuDataSource** ppDataSource); NuError Nu_DataSourceFP_New(NuThreadFormat threadFormat, uint32_t otherLen, FILE* fp, long offset, long length, NuCallback fcloseFunc, NuDataSource** ppDataSource); NuError Nu_DataSourceBuffer_New(NuThreadFormat threadFormat, uint32_t otherLen, const uint8_t* buffer, long offset, long length, NuCallback freeFunc, NuDataSource** ppDataSource); NuDataSource* Nu_DataSourceCopy(NuDataSource* pDataSource); NuError Nu_DataSourceFree(NuDataSource* pDataSource); NuDataSourceType Nu_DataSourceGetType(const NuDataSource* pDataSource); NuThreadFormat Nu_DataSourceGetThreadFormat(const NuDataSource* pDataSource); uint32_t Nu_DataSourceGetDataLen(const NuDataSource* pDataSource); uint32_t Nu_DataSourceGetOtherLen(const NuDataSource* pDataSource); void Nu_DataSourceSetOtherLen(NuDataSource* pDataSource, long otherLen); uint16_t Nu_DataSourceGetRawCrc(const NuDataSource* pDataSource); void Nu_DataSourceSetRawCrc(NuDataSource* pDataSource, uint16_t crc); NuError Nu_DataSourcePrepareInput(NuArchive* pArchive, NuDataSource* pDataSource); void Nu_DataSourceUnPrepareInput(NuArchive* pArchive, NuDataSource* pDataSource); const char* Nu_DataSourceFile_GetPathname(NuDataSource* pDataSource); NuError Nu_DataSourceGetBlock(NuDataSource* pDataSource, uint8_t* buf, uint32_t len); NuError Nu_DataSourceRewind(NuDataSource* pDataSource); NuError Nu_DataSinkFile_New(Boolean doExpand, NuValue convertEOL, const UNICHAR* pathnameUNI, UNICHAR fssep, NuDataSink** ppDataSink); NuError Nu_DataSinkFP_New(Boolean doExpand, NuValue convertEOL, FILE* fp, NuDataSink** ppDataSink); NuError Nu_DataSinkBuffer_New(Boolean doExpand, NuValue convertEOL, uint8_t* buffer, uint32_t bufLen, NuDataSink** ppDataSink); NuError Nu_DataSinkVoid_New(Boolean doExpand, NuValue convertEOL, NuDataSink** ppDataSink); NuError Nu_DataSinkFree(NuDataSink* pDataSink); NuDataSinkType Nu_DataSinkGetType(const NuDataSink* pDataSink); Boolean Nu_DataSinkGetDoExpand(const NuDataSink* pDataSink); NuValue Nu_DataSinkGetConvertEOL(const NuDataSink* pDataSink); uint32_t Nu_DataSinkGetOutCount(const NuDataSink* pDataSink); const char* Nu_DataSinkFile_GetPathname(const NuDataSink* pDataSink); UNICHAR Nu_DataSinkFile_GetFssep(const NuDataSink* pDataSink); FILE* Nu_DataSinkFile_GetFP(const NuDataSink* pDataSink); void Nu_DataSinkFile_SetFP(NuDataSink* pDataSink, FILE* fp); void Nu_DataSinkFile_Close(NuDataSink* pDataSink); NuError Nu_DataSinkPutBlock(NuDataSink* pDataSink, const uint8_t* buf, uint32_t len); NuError Nu_DataSinkGetError(NuDataSink* pDataSink); /* Squeeze.c */ NuError Nu_CompressHuffmanSQ(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc); NuError Nu_ExpandHuffmanSQ(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc); /* Thread.c */ NuThread* Nu_GetThread(const NuRecord* pRecord, int idx); void Nu_StripHiIfAllSet(char* str); Boolean Nu_IsPresizedThreadID(NuThreadID threadID); Boolean Nu_IsCompressibleThreadID(NuThreadID threadID); Boolean Nu_ThreadHasCRC(uint16_t recordVersion, NuThreadID threadID); NuError Nu_FindThreadByIdx(const NuRecord* pRecord, NuThreadIdx thread, NuThread** ppThread); NuError Nu_FindThreadByID(const NuRecord* pRecord, NuThreadID threadID, NuThread** ppThread); void Nu_CopyThreadContents(NuThread* pDstThread, const NuThread* pSrcThread); NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, uint16_t* pCrc); NuError Nu_WriteThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, FILE* fp, uint16_t* pCrc); NuError Nu_ComputeThreadData(NuArchive* pArchive, NuRecord* pRecord); NuError Nu_ScanThreads(NuArchive* pArchive, NuRecord* pRecord,long numThreads); NuError Nu_ExtractThreadBulk(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread); NuError Nu_SkipThread(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread); NuError Nu_ExtractThread(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSink* pDataSink); NuError Nu_OkayToAddThread(NuArchive* pArchive, const NuRecord* pRecord, NuThreadID threadID); NuError Nu_AddThread(NuArchive* pArchive, NuRecordIdx rec, NuThreadID threadID, NuDataSource* pDataSource, NuThreadIdx* pThreadIdx); NuError Nu_UpdatePresizedThread(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSource* pDataSource, int32_t* pMaxLen); NuError Nu_DeleteThread(NuArchive* pArchive, NuThreadIdx threadIdx); /* Value.c */ NuError Nu_GetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue); NuError Nu_SetValue(NuArchive* pArchive, NuValueID ident, NuValue value); NuError Nu_GetAttr(NuArchive* pArchive, NuAttrID ident, NuAttr* pAttr); NuThreadFormat Nu_ConvertCompressValToFormat(NuArchive* pArchive, NuValue compValue); /* Version.c */ NuError Nu_GetVersion(int32_t* pMajorVersion, int32_t* pMinorVersion, int32_t* pBugVersion, const char** ppBuildDate, const char** ppBuildFlags); #endif /*NUFXLIB_NUFXLIBPRIV_H*/ nulib2-3.1.0/nufxlib/README.txt000066400000000000000000000076051316100516500160610ustar00rootroot00000000000000NufxLib README, updated 2014/12/23 http://www.nulib.com/ See "COPYING-LIB" for distribution restrictions. UNIX ==== Run the "configure" script. Read through "INSTALL" if you haven't used one of these before, especially if you want to use a specific compiler or a particular set of compiler flags. You can disable specific compression methods with "--disable-METHOD" (run "sh ./configure --help" to see the possible options). By default, all methods are enabled except bzip2. Run "make depend" if you have makedepend, and then type "make". This will build the library and all of the programs in the "samples" directory. There are some useful programs in "samples", described in a README.txt file there. In particular, you should run samples/test-basic to verify that things are more or less working. If you want to install the library and header file into standard system locations (usually /usr/local), run "make install". To learn how to specify different locations, read the INSTALL document. There are some flags in "OPT" you may want to use. The "autoconf" default for @CFLAGS@ is "-g -O2". -DNDEBUG Disable assert() calls and extra tests. This will speed things up, but errors won't get caught until later on, making the root cause harder to locate. -DDEBUG_MSGS Enable debug messages. This increases the size of the executable, but shouldn't affect performance. When errors occur, more output is produced. The "debug dump" feature is enabled by this flag. -DDEBUG_VERBOSE (Implicitly sets DEBUG_MSGS.) Spray lots of debugging output. If you want to do benchmarks, use "-O2 -DNDEBUG". The recommended configuration is "-g -O2 -DDEBUG_MSGS", so that verbose debug output is available when errors occur. BeOS ==== This works just like the UNIX version, but certain defaults have been changed. Running configure without arguments under BeOS is equivalent to: ./configure --prefix=/boot --includedir='${prefix}/develop/headers' --libdir='${exec_prefix}/home/config/lib' --mandir='/tmp' --bindir='${exec_prefix}/home/config/bin' If you're using BeOS/PPC, it will also do: CC=cc CFLAGS='-proc 603 -opt full' Mac OS X ======== This works just like the UNIX version, but includes support for resource forks and Finder file/aux types. Tested with Xcode v5.1.1 and Mac OS 10.8.5. Win32 ===== If you're using an environment that supports "configure" scripts, such as DJGPP, follow the UNIX instructions. NufxLib has been tested with Microsoft Visual C++ 12 (Visual Studio 2013). To build NufxLib, run the "Visual Studio 2013 x86 Native Tools Command Prompt" shortcut to get a shell. Change to the nufxlib directory, then: nmake -f makefile.msc When the build finishes, run "test-basic.exe" to confirm things are working. If you want to have zlib support enabled, you will need to have zlib.h, zconf.h, and zlib.lib copied into the directory. See "makefile.msc" for more details. The makefile builds NufxLib as a static library and as a DLL. Other Notes =========== If you want to use the library in a multithreaded application, you should define "USE_REENTRANT_CALLS" to tell it to use reentrant versions of certain library calls. This defines _REENTRANT, which causes Solaris to add the appropriate goodies. (Seems to me you'd always want this on, but for some reason Solaris makes you take an extra step, so I'm not going to define it by default.) Originally, NufxLib / NuLib2 were intended to be usable natively on the Apple IIgs, so some of the design decisions were influenced by the need to minimize memory usage (e.g. being able to get a directory listing without holding the entire directory in memory) and interact with GS/OS (forked files have a single filename, files have type/auxtype). The IIgs port was never started. Legalese ======== NufxLib, a NuFX archive manipulation library. Copyright (C) 2000-2014 by Andy McFadden, All Rights Reserved. See COPYING for license. nulib2-3.1.0/nufxlib/Record.c000066400000000000000000002575551316100516500157600ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Record-level operations. */ #include "NufxLibPriv.h" /* * Local constants. */ static const uint8_t kNufxID[kNufxIDLen] = { 0x4e, 0xf5, 0x46, 0xd8 }; /* * =========================================================================== * Simple NuRecord stuff * =========================================================================== */ /* * Initialize the contents of a NuRecord. The goal here is to init the * things that a Nu_FreeRecordContents call will check, so that we don't * end up trying to free garbage. No need to memset() the whole thing. */ static NuError Nu_InitRecordContents(NuArchive* pArchive, NuRecord* pRecord) { Assert(pRecord != NULL); DebugFill(pRecord, sizeof(*pRecord)); pRecord->recOptionList = NULL; pRecord->extraBytes = NULL; pRecord->recFilenameMOR = NULL; pRecord->threadFilenameMOR = NULL; pRecord->newFilenameMOR = NULL; pRecord->pThreads = NULL; pRecord->pNext = NULL; pRecord->pThreadMods = NULL; pRecord->dirtyHeader = false; pRecord->dropRecFilename = false; pRecord->isBadMac = false; return kNuErrNone; } /* * Allocate and initialize a new NuRecord struct. */ static NuError Nu_RecordNew(NuArchive* pArchive, NuRecord** ppRecord) { Assert(ppRecord != NULL); *ppRecord = Nu_Malloc(pArchive, sizeof(**ppRecord)); if (*ppRecord == NULL) return kNuErrMalloc; return Nu_InitRecordContents(pArchive, *ppRecord); } /* * Free anything allocated within a record. Doesn't try to free the record * itself. */ static NuError Nu_FreeRecordContents(NuArchive* pArchive, NuRecord* pRecord) { Assert(pRecord != NULL); Nu_Free(pArchive, pRecord->recOptionList); Nu_Free(pArchive, pRecord->extraBytes); Nu_Free(pArchive, pRecord->recFilenameMOR); Nu_Free(pArchive, pRecord->threadFilenameMOR); Nu_Free(pArchive, pRecord->newFilenameMOR); Nu_Free(pArchive, pRecord->pThreads); /* don't Free(pRecord->pNext)! */ Nu_FreeThreadMods(pArchive, pRecord); (void) Nu_InitRecordContents(pArchive, pRecord); /* mark as freed */ return kNuErrNone; } /* * Free up a NuRecord struct. */ static NuError Nu_RecordFree(NuArchive* pArchive, NuRecord* pRecord) { if (pRecord == NULL) return kNuErrNone; (void) Nu_FreeRecordContents(pArchive, pRecord); Nu_Free(pArchive, pRecord); return kNuErrNone; } /* * Copy a field comprised of a buffer and a length from one structure to * another. It is assumed that the length value has already been copied. */ static NuError CopySizedField(NuArchive* pArchive, void* vppDst, const void* vpSrc, uint32_t len) { NuError err = kNuErrNone; uint8_t** ppDst = vppDst; const uint8_t* pSrc = vpSrc; Assert(ppDst != NULL); if (len) { Assert(pSrc != NULL); *ppDst = Nu_Malloc(pArchive, len); BailAlloc(*ppDst); memcpy(*ppDst, pSrc, len); } else { Assert(pSrc == NULL); *ppDst = NULL; } bail: return err; } /* * Make a copy of a record. */ static NuError Nu_RecordCopy(NuArchive* pArchive, NuRecord** ppDst, const NuRecord* pSrc) { NuError err; NuRecord* pDst; err = Nu_RecordNew(pArchive, ppDst); BailError(err); /* copy all the static fields, then copy or blank the "hairy" parts */ pDst = *ppDst; memcpy(pDst, pSrc, sizeof(*pSrc)); CopySizedField(pArchive, &pDst->recOptionList, pSrc->recOptionList, pSrc->recOptionSize); CopySizedField(pArchive, &pDst->extraBytes, pSrc->extraBytes, pSrc->extraCount); CopySizedField(pArchive, &pDst->recFilenameMOR, pSrc->recFilenameMOR, pSrc->recFilenameLength == 0 ? 0 : pSrc->recFilenameLength+1); CopySizedField(pArchive, &pDst->threadFilenameMOR, pSrc->threadFilenameMOR, pSrc->threadFilenameMOR == NULL ? 0 : strlen(pSrc->threadFilenameMOR) +1); CopySizedField(pArchive, &pDst->newFilenameMOR, pSrc->newFilenameMOR, pSrc->newFilenameMOR == NULL ? 0 : strlen(pSrc->newFilenameMOR) +1); CopySizedField(pArchive, &pDst->pThreads, pSrc->pThreads, pSrc->recTotalThreads * sizeof(*pDst->pThreads)); /* now figure out what the filename is supposed to point at */ if (pSrc->filenameMOR == pSrc->threadFilenameMOR) pDst->filenameMOR = pDst->threadFilenameMOR; else if (pSrc->filenameMOR == pSrc->recFilenameMOR) pDst->filenameMOR = pDst->recFilenameMOR; else if (pSrc->filenameMOR == pSrc->newFilenameMOR) pDst->filenameMOR = pDst->newFilenameMOR; else pDst->filenameMOR = pSrc->filenameMOR; /* probably static kDefault value */ pDst->pNext = NULL; /* these only hold for copy from orig... may need to remove */ Assert(pSrc->pThreadMods == NULL); Assert(!pSrc->dirtyHeader); bail: return err; } /* * Add a ThreadMod to the list in the NuRecord. * * In general, the order is not significant. However, if we're adding * a bunch of "add" threadMods for control threads to a record, their * order might be important. So, we want to add the threadMod to the * end of the list. * * I'm expecting these lists to be short, so walking down them is * acceptable. We could do simple optimizations, like only preserving * ordering for "add" threadMods, but even that seems silly. */ void Nu_RecordAddThreadMod(NuRecord* pRecord, NuThreadMod* pThreadMod) { NuThreadMod* pScanThreadMod; Assert(pRecord != NULL); Assert(pThreadMod != NULL); if (pRecord->pThreadMods == NULL) { pRecord->pThreadMods = pThreadMod; } else { pScanThreadMod = pRecord->pThreadMods; while (pScanThreadMod->pNext != NULL) pScanThreadMod = pScanThreadMod->pNext; pScanThreadMod->pNext = pThreadMod; } pThreadMod->pNext = NULL; } /* * Decide if a record is empty. An empty record is one that will have no * threads after all adds and deletes are processed. * * You can't delete something you just added or has been updated, and you * can't update something that has been deleted, so any "add" or "update" * items indicate that the thread isn't empty. * * You can't delete a thread more than once, or delete a thread that * doesn't exist, so all we need to do is count up the number of current * threads, subtract the number of deletes, and return "true" if the net * result is zero. */ Boolean Nu_RecordIsEmpty(NuArchive* pArchive, const NuRecord* pRecord) { const NuThreadMod* pThreadMod; int numThreads; Assert(pRecord != NULL); numThreads = pRecord->recTotalThreads; pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { switch (pThreadMod->entry.kind) { case kNuThreadModAdd: case kNuThreadModUpdate: return false; case kNuThreadModDelete: numThreads--; break; case kNuThreadModUnknown: default: Assert(0); return false; } pThreadMod = pThreadMod->pNext; } if (numThreads > 0) return false; else if (numThreads == 0) return true; else { Assert(0); Nu_ReportError(NU_BLOB, kNuErrInternal, "Thread counting failed (%d)", numThreads); return false; } } /* * =========================================================================== * NuRecordSet functions * =========================================================================== */ /* * Trivial getters and setters */ Boolean Nu_RecordSet_GetLoaded(const NuRecordSet* pRecordSet) { Assert(pRecordSet != NULL); return pRecordSet->loaded; } void Nu_RecordSet_SetLoaded(NuRecordSet* pRecordSet, Boolean val) { pRecordSet->loaded = val; } uint32_t Nu_RecordSet_GetNumRecords(const NuRecordSet* pRecordSet) { return pRecordSet->numRecords; } void Nu_RecordSet_SetNumRecords(NuRecordSet* pRecordSet, uint32_t val) { pRecordSet->numRecords = val; } void Nu_RecordSet_IncNumRecords(NuRecordSet* pRecordSet) { pRecordSet->numRecords++; } NuRecord* Nu_RecordSet_GetListHead(const NuRecordSet* pRecordSet) { return pRecordSet->nuRecordHead; } NuRecord** Nu_RecordSet_GetListHeadPtr(NuRecordSet* pRecordSet) { return &pRecordSet->nuRecordHead; } NuRecord* Nu_RecordSet_GetListTail(const NuRecordSet* pRecordSet) { return pRecordSet->nuRecordTail; } /* * Returns "true" if the record set has no records or hasn't ever been * used. */ Boolean Nu_RecordSet_IsEmpty(const NuRecordSet* pRecordSet) { if (!pRecordSet->loaded || pRecordSet->numRecords == 0) return true; return false; } /* * Free the list of records, and reset the record sets to initial state. */ NuError Nu_RecordSet_FreeAllRecords(NuArchive* pArchive, NuRecordSet* pRecordSet) { NuError err = kNuErrNone; NuRecord* pRecord; NuRecord* pNextRecord; if (!pRecordSet->loaded) { Assert(pRecordSet->nuRecordHead == NULL); Assert(pRecordSet->nuRecordTail == NULL); Assert(pRecordSet->numRecords == 0); return kNuErrNone; } DBUG(("+++ FreeAllRecords\n")); pRecord = pRecordSet->nuRecordHead; while (pRecord != NULL) { pNextRecord = pRecord->pNext; err = Nu_RecordFree(pArchive, pRecord); BailError(err); /* don't really expect this to fail */ pRecord = pNextRecord; } pRecordSet->nuRecordHead = pRecordSet->nuRecordTail = NULL; pRecordSet->numRecords = 0; pRecordSet->loaded = false; bail: return err; } /* * Add a new record to the end of the list. */ static NuError Nu_RecordSet_AddRecord(NuRecordSet* pRecordSet, NuRecord* pRecord) { Assert(pRecordSet != NULL); Assert(pRecord != NULL); /* if one is NULL, both must be NULL */ Assert(pRecordSet->nuRecordHead == NULL || pRecordSet->nuRecordTail != NULL); Assert(pRecordSet->nuRecordTail == NULL || pRecordSet->nuRecordHead != NULL); if (pRecordSet->nuRecordHead == NULL) { /* empty list */ pRecordSet->nuRecordHead = pRecordSet->nuRecordTail = pRecord; pRecordSet->loaded = true; Assert(!pRecordSet->numRecords); } else { pRecord->pNext = NULL; pRecordSet->nuRecordTail->pNext = pRecord; pRecordSet->nuRecordTail = pRecord; } pRecordSet->numRecords++; return kNuErrNone; } /* * Delete a record from the record set. Pass in a pointer to the pointer * to the record (usually either the head pointer or another record's * "pNext" pointer). * * (Should have a "heavy assert" mode where we verify that "ppRecord" * actually has something to do with pRecordSet.) */ NuError Nu_RecordSet_DeleteRecordPtr(NuArchive* pArchive, NuRecordSet* pRecordSet, NuRecord** ppRecord) { NuError err; NuRecord* pRecord; Assert(pRecordSet != NULL); Assert(ppRecord != NULL); Assert(*ppRecord != NULL); /* save a copy of the record we're freeing */ pRecord = *ppRecord; /* update the pHead or pNext pointer */ *ppRecord = (*ppRecord)->pNext; pRecordSet->numRecords--; /* if we're deleting the tail, we have to find the "new" last entry */ if (pRecord == pRecordSet->nuRecordTail) { if (pRecordSet->nuRecordHead == NULL) { /* this was the last entry; we're done */ pRecordSet->nuRecordTail = NULL; } else { /* walk through the list... delete bottom-up will be slow! */ pRecordSet->nuRecordTail = pRecordSet->nuRecordHead; while (pRecordSet->nuRecordTail->pNext != NULL) pRecordSet->nuRecordTail = pRecordSet->nuRecordTail->pNext; } } if (pRecordSet->numRecords) Assert(pRecordSet->nuRecordHead!=NULL && pRecordSet->nuRecordTail!=NULL); else Assert(pRecordSet->nuRecordHead==NULL && pRecordSet->nuRecordTail==NULL); err = Nu_RecordFree(pArchive, pRecord); return err; } /* * Delete a record from the record set. */ NuError Nu_RecordSet_DeleteRecord(NuArchive* pArchive, NuRecordSet* pRecordSet, NuRecord* pRecord) { NuError err; NuRecord** ppRecord; ppRecord = Nu_RecordSet_GetListHeadPtr(pRecordSet); Assert(ppRecord != NULL); Assert(*ppRecord != NULL); /* look for the record, so we can update his neighbors */ /* (this also ensures that the record really is in the set we think it is)*/ while (*ppRecord) { if (*ppRecord == pRecord) { err = Nu_RecordSet_DeleteRecordPtr(pArchive, pRecordSet, ppRecord); BailError(err); goto bail; } ppRecord = &((*ppRecord)->pNext); } DBUG(("--- Nu_RecordSet_DeleteRecord failed\n")); err = kNuErrNotFound; bail: return err; } /* * Make a clone of a record set. This is used to create the "copy" record * set out of the "orig" set. */ NuError Nu_RecordSet_Clone(NuArchive* pArchive, NuRecordSet* pDstSet, const NuRecordSet* pSrcSet) { NuError err = kNuErrNone; const NuRecord* pSrcRecord; NuRecord* pDstRecord; Assert(pDstSet != NULL); Assert(pSrcSet != NULL); Assert(Nu_RecordSet_GetLoaded(pDstSet) == false); Assert(Nu_RecordSet_GetLoaded(pSrcSet) == true); DBUG(("--- Cloning record set\n")); Nu_RecordSet_SetLoaded(pDstSet, true); /* copy each record over */ pSrcRecord = pSrcSet->nuRecordHead; while (pSrcRecord != NULL) { err = Nu_RecordCopy(pArchive, &pDstRecord, pSrcRecord); BailError(err); err = Nu_RecordSet_AddRecord(pDstSet, pDstRecord); BailError(err); pSrcRecord = pSrcRecord->pNext; } Assert(pDstSet->numRecords == pSrcSet->numRecords); bail: if (err != kNuErrNone) { Nu_RecordSet_FreeAllRecords(pArchive, pDstSet); } return err; } /* * Move all of the records from one record set to another. The records * from "pSrcSet" are appended to "pDstSet". * * On completion, "pSrcSet" will be empty and "unloaded". */ NuError Nu_RecordSet_MoveAllRecords(NuArchive* pArchive, NuRecordSet* pDstSet, NuRecordSet* pSrcSet) { NuError err = kNuErrNone; Assert(pDstSet != NULL); Assert(pSrcSet != NULL); /* move records over */ if (Nu_RecordSet_GetNumRecords(pSrcSet)) { Assert(pSrcSet->loaded); Assert(pSrcSet->nuRecordHead != NULL); Assert(pSrcSet->nuRecordTail != NULL); if (pDstSet->nuRecordHead == NULL) { /* empty dst list */ Assert(pDstSet->nuRecordTail == NULL); pDstSet->nuRecordHead = pSrcSet->nuRecordHead; pDstSet->nuRecordTail = pSrcSet->nuRecordTail; pDstSet->numRecords = pSrcSet->numRecords; pDstSet->loaded = true; } else { /* append to dst list */ Assert(pDstSet->loaded); Assert(pDstSet->nuRecordTail != NULL); pDstSet->nuRecordTail->pNext = pSrcSet->nuRecordHead; pDstSet->nuRecordTail = pSrcSet->nuRecordTail; pDstSet->numRecords += pSrcSet->numRecords; } } else { /* no records in src set */ Assert(pSrcSet->nuRecordHead == NULL); Assert(pSrcSet->nuRecordTail == NULL); if (pSrcSet->loaded) pDstSet->loaded = true; } /* nuke all pointers in original list */ pSrcSet->nuRecordHead = pSrcSet->nuRecordTail = NULL; pSrcSet->numRecords = 0; pSrcSet->loaded = false; return err; } /* * Find a record in the list by index. */ NuError Nu_RecordSet_FindByIdx(const NuRecordSet* pRecordSet, NuRecordIdx recIdx, NuRecord** ppRecord) { NuRecord* pRecord; pRecord = pRecordSet->nuRecordHead; while (pRecord != NULL) { if (pRecord->recordIdx == recIdx) { *ppRecord = pRecord; return kNuErrNone; } pRecord = pRecord->pNext; } return kNuErrRecIdxNotFound; } /* * Search for a specific thread in all records in the specified record set. */ NuError Nu_RecordSet_FindByThreadIdx(NuRecordSet* pRecordSet, NuThreadIdx threadIdx, NuRecord** ppRecord, NuThread** ppThread) { NuError err = kNuErrThreadIdxNotFound; NuRecord* pRecord; pRecord = Nu_RecordSet_GetListHead(pRecordSet); while (pRecord != NULL) { err = Nu_FindThreadByIdx(pRecord, threadIdx, ppThread); if (err == kNuErrNone) { *ppRecord = pRecord; break; } pRecord = pRecord->pNext; } Assert(err != kNuErrNone || (*ppRecord != NULL && *ppThread != NULL)); return err; } /* * Compare two record filenames. This comes into play when looking for * conflicts while adding records to an archive. * * Interesting issues: * - some filesystems are case-sensitive, some aren't * - the fssep may be different ('/', ':') for otherwise equivalent names * - system-dependent conversions could resolve two different names to * the same thing * * Some of these are out of our control. For now, I'm just doing a * case-insensitive comparison, since the most interesting case for us is * when the person is adding a data fork and a resource fork from the * same file during the same operation. * * [ Could run both names through the pathname conversion callback first? * Might be expensive. ] * * Returns an integer greater than, equal to, or less than 0, if the * string pointed to by name1 is greater than, equal to, or less than * the string pointed to by s2, respectively (i.e. same as strcmp). */ static int Nu_CompareRecordNames(const char* name1MOR, const char* name2MOR) { #ifdef NU_CASE_SENSITIVE return strcmp(name1MOR, name2MOR); #else return strcasecmp(name1MOR, name2MOR); #endif } /* * Find a record in the list by storageName. */ static NuError Nu_RecordSet_FindByName(const NuRecordSet* pRecordSet, const char* nameMOR, NuRecord** ppRecord) { NuRecord* pRecord; Assert(pRecordSet != NULL); Assert(pRecordSet->loaded); Assert(nameMOR != NULL); Assert(ppRecord != NULL); pRecord = pRecordSet->nuRecordHead; while (pRecord != NULL) { if (Nu_CompareRecordNames(pRecord->filenameMOR, nameMOR) == 0) { *ppRecord = pRecord; return kNuErrNone; } pRecord = pRecord->pNext; } return kNuErrRecNameNotFound; } /* * Find a record in the list by storageName, starting from the end and * searching backwards. * * Since we don't actually have a "prev" pointer in the record, we end * up scanning the entire list and keeping the last match. If this * causes a notable reduction in efficiency we'll have to fix this. */ static NuError Nu_RecordSet_ReverseFindByName(const NuRecordSet* pRecordSet, const char* nameMOR, NuRecord** ppRecord) { NuRecord* pRecord; NuRecord* pFoundRecord = NULL; Assert(pRecordSet != NULL); Assert(pRecordSet->loaded); Assert(nameMOR != NULL); Assert(ppRecord != NULL); pRecord = pRecordSet->nuRecordHead; while (pRecord != NULL) { if (Nu_CompareRecordNames(pRecord->filenameMOR, nameMOR) == 0) pFoundRecord = pRecord; pRecord = pRecord->pNext; } if (pFoundRecord != NULL) { *ppRecord = pFoundRecord; return kNuErrNone; } return kNuErrRecNameNotFound; } /* * We have a copy of the record in the "copy" set, but we've decided * (perhaps because the user elected to Skip a failed add) that we'd * rather have the original. * * Delete the record from the "copy" set, clone the "orig" record, and * insert the "orig" record into the same spot in the "copy" set. * * "ppNewRecord" will get a pointer to the newly-created clone. */ NuError Nu_RecordSet_ReplaceRecord(NuArchive* pArchive, NuRecordSet* pBadSet, NuRecord* pBadRecord, NuRecordSet* pGoodSet, NuRecord** ppNewRecord) { NuError err; NuRecord* pGoodRecord; NuRecord* pSiblingRecord; NuRecord* pNewRecord = NULL; Assert(pArchive != NULL); Assert(pBadSet != NULL); Assert(pBadRecord != NULL); Assert(pGoodSet != NULL); Assert(ppNewRecord != NULL); /* * Find a record in "pGoodSet" that has the same record index as * the "bad" record. */ err = Nu_RecordSet_FindByIdx(pGoodSet, pBadRecord->recordIdx, &pGoodRecord); BailError(err); /* * Clone the original. */ err = Nu_RecordCopy(pArchive, &pNewRecord, pGoodRecord); BailError(err); /* * Insert the new one into the "bad" record set, in the exact same * position. */ pNewRecord->pNext = pBadRecord->pNext; if (pBadSet->nuRecordTail == pBadRecord) pBadSet->nuRecordTail = pNewRecord; if (pBadSet->nuRecordHead == pBadRecord) pBadSet->nuRecordHead = pNewRecord; else { /* find the record that points to pBadRecord */ pSiblingRecord = pBadSet->nuRecordHead; while (pSiblingRecord->pNext != pBadRecord && pSiblingRecord != NULL) pSiblingRecord = pSiblingRecord->pNext; if (pSiblingRecord == NULL) { /* looks like "pBadRecord" wasn't part of "pBadSet" after all */ Assert(0); err = kNuErrInternal; goto bail; } pSiblingRecord->pNext = pNewRecord; } err = Nu_RecordFree(pArchive, pBadRecord); BailError(err); *ppNewRecord = pNewRecord; pNewRecord = NULL; /* don't free */ bail: if (pNewRecord != NULL) Nu_RecordFree(pArchive, pNewRecord); return err; } /* * =========================================================================== * Assorted utility functions * =========================================================================== */ /* * Ask the user if it's okay to ignore a bad CRC. If we can't ask the * user, return "false". */ Boolean Nu_ShouldIgnoreBadCRC(NuArchive* pArchive, const NuRecord* pRecord, NuError err) { NuErrorStatus errorStatus; NuResult result; Boolean retval = false; UNICHAR* pathnameUNI = NULL; Assert(pArchive->valIgnoreCRC == false); if (pArchive->errorHandlerFunc != NULL) { errorStatus.operation = kNuOpTest; /* mostly accurate */ errorStatus.err = err; errorStatus.sysErr = 0; errorStatus.message = NULL; errorStatus.pRecord = pRecord; errorStatus.pathnameUNI = NULL; errorStatus.origPathname = NULL; errorStatus.filenameSeparator = 0; if (pRecord != NULL) { pathnameUNI = Nu_CopyMORToUNI(pRecord->filenameMOR); errorStatus.pathnameUNI = pathnameUNI; errorStatus.filenameSeparator = NuGetSepFromSysInfo(pRecord->recFileSysInfo); } /*errorStatus.origArchiveTouched = false;*/ errorStatus.canAbort = true; errorStatus.canRetry = false; errorStatus.canIgnore = true; errorStatus.canSkip = false; errorStatus.canRename = false; errorStatus.canOverwrite = false; result = (*pArchive->errorHandlerFunc)(pArchive, &errorStatus); switch (result) { case kNuAbort: goto bail; case kNuIgnore: retval = true; goto bail; case kNuSkip: case kNuOverwrite: case kNuRetry: case kNuRename: default: Nu_ReportError(NU_BLOB, kNuErrSyntax, "Wasn't expecting result %d here", result); break; } } bail: Nu_Free(pArchive, pathnameUNI); return retval; } /* * Read the next NuFX record from the current offset in the archive stream. * This includes the record header and the thread header blocks. * * Pass in a NuRecord structure that will hold the data we read. */ static NuError Nu_ReadRecordHeader(NuArchive* pArchive, NuRecord* pRecord) { NuError err = kNuErrNone; uint16_t crc; FILE* fp; int bytesRead; Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(pRecord->pThreads == NULL); Assert(pRecord->pNext == NULL); fp = pArchive->archiveFp; pRecord->recordIdx = Nu_GetNextRecordIdx(pArchive); /* points to whichever filename storage we like best */ pRecord->filenameMOR = NULL; pRecord->fileOffset = pArchive->currentOffset; (void) Nu_ReadBytes(pArchive, fp, pRecord->recNufxID, kNufxIDLen); if (memcmp(kNufxID, pRecord->recNufxID, kNufxIDLen) != 0) { err = kNuErrRecHdrNotFound; Nu_ReportError(NU_BLOB, kNuErrNone, "Couldn't find start of next record"); goto bail; } /* * Read the static fields. */ crc = 0; pRecord->recHeaderCRC = Nu_ReadTwo(pArchive, fp); pRecord->recAttribCount = Nu_ReadTwoC(pArchive, fp, &crc); pRecord->recVersionNumber = Nu_ReadTwoC(pArchive, fp, &crc); pRecord->recTotalThreads = Nu_ReadFourC(pArchive, fp, &crc); pRecord->recFileSysID = Nu_ReadTwoC(pArchive, fp, &crc); pRecord->recFileSysInfo = Nu_ReadTwoC(pArchive, fp, &crc); pRecord->recAccess = Nu_ReadFourC(pArchive, fp, &crc); pRecord->recFileType = Nu_ReadFourC(pArchive, fp, &crc); pRecord->recExtraType = Nu_ReadFourC(pArchive, fp, &crc); pRecord->recStorageType = Nu_ReadTwoC(pArchive, fp, &crc); pRecord->recCreateWhen = Nu_ReadDateTimeC(pArchive, fp, &crc); pRecord->recModWhen = Nu_ReadDateTimeC(pArchive, fp, &crc); pRecord->recArchiveWhen = Nu_ReadDateTimeC(pArchive, fp, &crc); bytesRead = 56; /* 4-byte 'NuFX' plus the above */ /* * Do some sanity checks before we continue. */ if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed reading record header"); goto bail; } if (pRecord->recAttribCount > kNuReasonableAttribCount) { err = kNuErrBadRecord; Nu_ReportError(NU_BLOB, err, "Attrib count is huge (%u)", pRecord->recAttribCount); goto bail; } if (pRecord->recVersionNumber > kNuMaxRecordVersion) { err = kNuErrBadRecord; Nu_ReportError(NU_BLOB, err, "Unrecognized record version number (%u)", pRecord->recVersionNumber); goto bail; } if (pRecord->recTotalThreads > kNuReasonableTotalThreads) { err = kNuErrBadRecord; Nu_ReportError(NU_BLOB, err, "Unreasonable number of threads (%u)", pRecord->recTotalThreads); goto bail; } /* * Read the option list, if present. */ if (pRecord->recVersionNumber > 0) { pRecord->recOptionSize = Nu_ReadTwoC(pArchive, fp, &crc); bytesRead += 2; /* * It appears GS/ShrinkIt is creating bad option lists, claiming * 36 bytes of data when there's only room for 18. Since we don't * really pay attention to the option list */ if (pRecord->recOptionSize + bytesRead > pRecord->recAttribCount -2) { DBUG(("--- truncating option list from %d to %d\n", pRecord->recOptionSize, pRecord->recAttribCount -2 - bytesRead)); if (pRecord->recAttribCount -2 > bytesRead) pRecord->recOptionSize = pRecord->recAttribCount -2 - bytesRead; else pRecord->recOptionSize = 0; } /* this is the older test, which rejected funky archives */ if (pRecord->recOptionSize + bytesRead > pRecord->recAttribCount -2) { /* option size exceeds the total attribute area */ err = kNuErrBadRecord; Nu_ReportError(NU_BLOB, kNuErrBadRecord, "Option size (%u) exceeds attribs (%u,%u-2)", pRecord->recOptionSize, bytesRead, pRecord->recAttribCount); goto bail; } if (pRecord->recOptionSize) { pRecord->recOptionList = Nu_Malloc(pArchive,pRecord->recOptionSize); BailAlloc(pRecord->recOptionList); (void) Nu_ReadBytesC(pArchive, fp, pRecord->recOptionList, pRecord->recOptionSize, &crc); bytesRead += pRecord->recOptionSize; } } else { pRecord->recOptionSize = 0; pRecord->recOptionList = NULL; } /* last two bytes are the filename len; all else is "extra" */ pRecord->extraCount = (pRecord->recAttribCount -2) - bytesRead; Assert(pRecord->extraCount >= 0); /* * Some programs (for example, NuLib) may leave extra junk in here. This * is allowed by the archive spec. We may want to preserve it, so we * allocate space for it and read it if it exists. */ if (pRecord->extraCount) { pRecord->extraBytes = Nu_Malloc(pArchive, pRecord->extraCount); BailAlloc(pRecord->extraBytes); (void) Nu_ReadBytesC(pArchive, fp, pRecord->extraBytes, pRecord->extraCount, &crc); bytesRead += pRecord->extraCount; } /* * Read the in-record filename if one exists (likely in v0 records only). */ pRecord->recFilenameLength = Nu_ReadTwoC(pArchive, fp, &crc); bytesRead += 2; if (pRecord->recFilenameLength > kNuReasonableFilenameLen) { err = kNuErrBadRecord; Nu_ReportError(NU_BLOB, kNuErrBadRecord, "Filename length is huge (%u)", pRecord->recFilenameLength); goto bail; } if (pRecord->recFilenameLength) { pRecord->recFilenameMOR = Nu_Malloc(pArchive, pRecord->recFilenameLength +1); BailAlloc(pRecord->recFilenameMOR); (void) Nu_ReadBytesC(pArchive, fp, pRecord->recFilenameMOR, pRecord->recFilenameLength, &crc); pRecord->recFilenameMOR[pRecord->recFilenameLength] = '\0'; bytesRead += pRecord->recFilenameLength; Nu_StripHiIfAllSet(pRecord->recFilenameMOR); /* use the in-header one */ pRecord->filenameMOR = pRecord->recFilenameMOR; } /* * Read the threads records. The data is included in the record header * CRC, so we have to pass that in too. */ pRecord->fakeThreads = 0; err = Nu_ReadThreadHeaders(pArchive, pRecord, &crc); BailError(err); /* * After all is said and done, did we read the file without errors, * and does the CRC match? */ if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed reading late record header"); goto bail; } if (!pArchive->valIgnoreCRC && crc != pRecord->recHeaderCRC) { if (!Nu_ShouldIgnoreBadCRC(pArchive, pRecord, kNuErrBadRHCRC)) { err = kNuErrBadRHCRC; Nu_ReportError(NU_BLOB, err, "Stored RH CRC=0x%04x, calc=0x%04x", pRecord->recHeaderCRC, crc); Nu_ReportError(NU_BLOB_DEBUG, kNuErrNone, "--- Problematic record is id=%u", pRecord->recordIdx); goto bail; } } /* * Init or compute misc record fields. */ /* adjust "currentOffset" for the entire record header */ pArchive->currentOffset += bytesRead; pArchive->currentOffset += (pRecord->recTotalThreads - pRecord->fakeThreads) * kNuThreadHeaderSize; pRecord->recHeaderLength = bytesRead + pRecord->recTotalThreads * kNuThreadHeaderSize; pRecord->recHeaderLength -= pRecord->fakeThreads * kNuThreadHeaderSize; err = Nu_ComputeThreadData(pArchive, pRecord); BailError(err); /* check for "bad Mac" archives */ if (pArchive->valHandleBadMac) { if (pRecord->recFileSysInfo == '?' && pRecord->recFileSysID == kNuFileSysMacMFS) { DBUG(("--- using 'bad mac' handling\n")); pRecord->isBadMac = true; pRecord->recFileSysInfo = ':'; } } bail: if (err != kNuErrNone) (void)Nu_FreeRecordContents(pArchive, pRecord); return err; } /* * Update the record's storageType if it looks like it needs it, based on * the current set of threads. * * The rules we follow (stopping at the first match) are: * - If there's a disk thread, leave it alone. Disk block size issues * should already have been resolved. If we end up copying the same * bogus block size we were given initially, that's fine. * - If there's a resource fork, set the storageType to 5. * - If there's a data fork, set the storageType to 1-3. * - If there are no data-class threads at all, set the storageType to zero. * * This assumes that all updates have already been processed, i.e. there's * no lingering add or delete threadMods. This only examines the thread * array. * * NOTE: for data files (types 1, 2, and 3), the actual value may not match * up what ProDOS would use, because this doesn't test for sparseness. */ static void Nu_UpdateStorageType(NuArchive* pArchive, NuRecord* pRecord) { NuError err; NuThread* pThread; err = Nu_FindThreadByID(pRecord, kNuThreadIDDiskImage, &pThread); if (err == kNuErrNone) goto bail; err = Nu_FindThreadByID(pRecord, kNuThreadIDRsrcFork, &pThread); if (err == kNuErrNone) { DBUG(("--- setting storageType to %d (was %d)\n", kNuStorageExtended, pRecord->recStorageType)); pRecord->recStorageType = kNuStorageExtended; goto bail; } err = Nu_FindThreadByID(pRecord, kNuThreadIDDataFork, &pThread); if (err == kNuErrNone) { int newType; if (pThread->actualThreadEOF <= 512) newType = kNuStorageSeedling; else if (pThread->actualThreadEOF < 131072) newType = kNuStorageSapling; else newType = kNuStorageTree; DBUG(("--- setting storageType to %d (was %d)\n", newType, pRecord->recStorageType)); pRecord->recStorageType = newType; goto bail; } DBUG(("--- no stuff here, setting storageType to %d (was %d)\n", kNuStorageUnknown, pRecord->recStorageType)); pRecord->recStorageType = kNuStorageUnknown; bail: return; } /* * Write the record header to the current offset of the specified file. * This includes writing all of the thread headers. * * We don't "promote" records to newer versions, because that might * require expanding and CRCing data threads. Instead, we write the * record in a manner appropriate for the version. * * As a side effect, this may update the storageType to something appropriate. * * The position of the file pointer on exit is undefined. The position * past the end of the record will be stored in pArchive->currentOffset. */ NuError Nu_WriteRecordHeader(NuArchive* pArchive, NuRecord* pRecord, FILE* fp) { NuError err = kNuErrNone; uint16_t crc; long crcOffset; int bytesWritten; Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(fp != NULL); /* * Before we get started, let's make sure the storageType makes sense * for this record. */ Nu_UpdateStorageType(pArchive, pRecord); DBUG(("--- Writing record header (v=%d)\n", pRecord->recVersionNumber)); (void) Nu_WriteBytes(pArchive, fp, pRecord->recNufxID, kNufxIDLen); err = Nu_FTell(fp, &crcOffset); BailError(err); /* * Write the static fields. */ crc = 0; Nu_WriteTwo(pArchive, fp, 0); /* crc -- come back later */ Nu_WriteTwoC(pArchive, fp, pRecord->recAttribCount, &crc); Nu_WriteTwoC(pArchive, fp, pRecord->recVersionNumber, &crc); Nu_WriteFourC(pArchive, fp, pRecord->recTotalThreads, &crc); Nu_WriteTwoC(pArchive, fp, (uint16_t)pRecord->recFileSysID, &crc); Nu_WriteTwoC(pArchive, fp, pRecord->recFileSysInfo, &crc); Nu_WriteFourC(pArchive, fp, pRecord->recAccess, &crc); Nu_WriteFourC(pArchive, fp, pRecord->recFileType, &crc); Nu_WriteFourC(pArchive, fp, pRecord->recExtraType, &crc); Nu_WriteTwoC(pArchive, fp, pRecord->recStorageType, &crc); Nu_WriteDateTimeC(pArchive, fp, pRecord->recCreateWhen, &crc); Nu_WriteDateTimeC(pArchive, fp, pRecord->recModWhen, &crc); Nu_WriteDateTimeC(pArchive, fp, pRecord->recArchiveWhen, &crc); bytesWritten = 56; /* 4-byte 'NuFX' plus the above */ if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed writing record header"); goto bail; } /* * Write the option list, if present. */ if (pRecord->recVersionNumber > 0) { Nu_WriteTwoC(pArchive, fp, pRecord->recOptionSize, &crc); bytesWritten += 2; if (pRecord->recOptionSize) { Nu_WriteBytesC(pArchive, fp, pRecord->recOptionList, pRecord->recOptionSize, &crc); bytesWritten += pRecord->recOptionSize; } } /* * Preserve whatever miscellaneous junk was left in here by the last guy. * We don't know what this is or why it's here, but who knows, maybe * it's important. * * Besides, if we don't, we'll have to go back and fix the attrib count. */ if (pRecord->extraCount) { Nu_WriteBytesC(pArchive, fp, pRecord->extraBytes, pRecord->extraCount, &crc); bytesWritten += pRecord->extraCount; } /* * If the record has a filename in the header, write it, unless * recent changes have inspired us to drop the name from the header. * * Records that begin with no filename will have a default one * stuffed in, so it's possible for pRecord->filename to be set * already even if there wasn't one in the record. (In such cases, * we don't write a name.) */ if (pRecord->recFilenameLength && !pRecord->dropRecFilename) { Nu_WriteTwoC(pArchive, fp, pRecord->recFilenameLength, &crc); bytesWritten += 2; Nu_WriteBytesC(pArchive, fp, pRecord->recFilenameMOR, pRecord->recFilenameLength, &crc); } else { Nu_WriteTwoC(pArchive, fp, 0, &crc); bytesWritten += 2; } /* make sure we are where we thought we would be */ if (bytesWritten != pRecord->recAttribCount) { err = kNuErrInternal; Nu_ReportError(NU_BLOB, kNuErrNone, "Didn't write what was expected (%d vs %d)", bytesWritten, pRecord->recAttribCount); goto bail; } /* write the thread headers, and zero out "fake" thread count */ err = Nu_WriteThreadHeaders(pArchive, pRecord, fp, &crc); BailError(err); /* get the current file offset, for some computations later */ err = Nu_FTell(fp, &pArchive->currentOffset); BailError(err); /* go back and fill in the CRC */ pRecord->recHeaderCRC = crc; err = Nu_FSeek(fp, crcOffset, SEEK_SET); BailError(err); Nu_WriteTwo(pArchive, fp, pRecord->recHeaderCRC); /* * All okay? */ if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed writing late record header"); goto bail; } /* * Update values for misc record fields. */ Assert(pRecord->fakeThreads == 0); pRecord->recHeaderLength = bytesWritten + pRecord->recTotalThreads * kNuThreadHeaderSize; pRecord->recHeaderLength -= pRecord->fakeThreads * kNuThreadHeaderSize; err = Nu_ComputeThreadData(pArchive, pRecord); BailError(err); bail: return err; } /* * Prepare for a "walk" through the records. This is useful for the * "read the TOC as you go" method of archive use. */ static NuError Nu_RecordWalkPrepare(NuArchive* pArchive, NuRecord** ppRecord) { NuError err = kNuErrNone; Assert(pArchive != NULL); Assert(ppRecord != NULL); DBUG(("--- walk prep\n")); *ppRecord = NULL; if (!pArchive->haveToc) { /* might have tried and aborted earlier, rewind to start of records */ err = Nu_RewindArchive(pArchive); BailError(err); } bail: return err; } /* * Get the next record from the "orig" set in the archive. * * On entry, pArchive->archiveFp must point at the start of the next * record. On exit, it will point past the end of the record (headers and * all data) that we just read. * * If we have the TOC, we just pull it out of the structure. If we don't, * we read it from the archive file, and add it to the TOC being * constructed. */ static NuError Nu_RecordWalkGetNext(NuArchive* pArchive, NuRecord** ppRecord) { NuError err = kNuErrNone; Assert(pArchive != NULL); Assert(ppRecord != NULL); /*DBUG(("--- walk toc=%d\n", pArchive->haveToc));*/ if (pArchive->haveToc) { if (*ppRecord == NULL) *ppRecord = Nu_RecordSet_GetListHead(&pArchive->origRecordSet); else *ppRecord = (*ppRecord)->pNext; } else { *ppRecord = NULL; /* so we don't try to free it on exit */ /* allocate and fill in a new record */ err = Nu_RecordNew(pArchive, ppRecord); BailError(err); /* read data from archive file */ err = Nu_ReadRecordHeader(pArchive, *ppRecord); BailError(err); err = Nu_ScanThreads(pArchive, *ppRecord, (*ppRecord)->recTotalThreads); BailError(err); DBUG(("--- Found record '%s'\n", (*ppRecord)->filenameMOR)); /* add to list */ err = Nu_RecordSet_AddRecord(&pArchive->origRecordSet, *ppRecord); BailError(err); } bail: if (err != kNuErrNone && !pArchive->haveToc) { /* on failure, free whatever we allocated */ Nu_RecordFree(pArchive, *ppRecord); *ppRecord = NULL; } return err; } /* * Finish off a successful record walk by noting that we now have a * full table of contents. On an unsuccessful walk, blow away the TOC * if we don't have all of it. */ static NuError Nu_RecordWalkFinish(NuArchive* pArchive, NuError walkErr) { if (pArchive->haveToc) return kNuErrNone; if (walkErr == kNuErrNone) { pArchive->haveToc = true; /* mark as loaded, even if there weren't any entries (e.g. new arc) */ Nu_RecordSet_SetLoaded(&pArchive->origRecordSet, true); return kNuErrNone; } else { pArchive->haveToc = false; /* redundant */ return Nu_RecordSet_FreeAllRecords(pArchive, &pArchive->origRecordSet); } } /* * If we don't have the complete record listing from the archive in * the "orig" record set, go get it. * * Uses the "record walk" functions, because they're there. */ NuError Nu_GetTOCIfNeeded(NuArchive* pArchive) { NuError err = kNuErrNone; NuRecord* pRecord; uint32_t count; Assert(pArchive != NULL); if (pArchive->haveToc) goto bail; DBUG(("--- GetTOCIfNeeded\n")); err = Nu_RecordWalkPrepare(pArchive, &pRecord); BailError(err); count = pArchive->masterHeader.mhTotalRecords; while (count--) { err = Nu_RecordWalkGetNext(pArchive, &pRecord); BailError(err); } bail: (void) Nu_RecordWalkFinish(pArchive, err); return err; } /* * =========================================================================== * Streaming read-only operations * =========================================================================== */ /* * Run through the entire archive, pulling out the header bits, skipping * over the data bits, and calling "contentFunc" for each record. */ NuError Nu_StreamContents(NuArchive* pArchive, NuCallback contentFunc) { NuError err = kNuErrNone; NuRecord tmpRecord; NuResult result; uint32_t count; if (contentFunc == NULL) { err = kNuErrInvalidArg; goto bail; } Nu_InitRecordContents(pArchive, &tmpRecord); count = pArchive->masterHeader.mhTotalRecords; while (count--) { err = Nu_ReadRecordHeader(pArchive, &tmpRecord); BailError(err); err = Nu_ScanThreads(pArchive, &tmpRecord, tmpRecord.recTotalThreads); BailError(err); /*Nu_DebugDumpRecord(&tmpRecord); printf("\n");*/ /* let them display the contents */ result = (*contentFunc)(pArchive, &tmpRecord); if (result == kNuAbort) { err = kNuErrAborted; goto bail; } /* dispose of the entry */ (void) Nu_FreeRecordContents(pArchive, &tmpRecord); (void) Nu_InitRecordContents(pArchive, &tmpRecord); } bail: (void) Nu_FreeRecordContents(pArchive, &tmpRecord); return err; } /* * If we're trying to be compatible with ShrinkIt, and we tried to extract * a record that had nothing in it but comments and filenames, then we need * to create a zero-byte data file. * * GS/ShrinkIt v1.1 has a bug that causes it to store zero-byte data files * (and, for that matter, zero-byte resource forks) without a thread header. * It isn't able to extract them. This isn't so much a compatibility * thing as it is a bug-workaround thing. * * The record's storage type should tell us if it was an extended file or * a plain file. Not really important when extracting, but if we want * to recreate the original we need to re-add the resource fork so * NufxLib knows to make it an extended file. */ static NuError Nu_FakeZeroExtract(NuArchive* pArchive, NuRecord* pRecord, int threadKind) { NuError err; NuThread fakeThread; Assert(pRecord != NULL); DBUG(("--- found empty record, creating zero-byte file (kind=0x%04x)\n", threadKind)); fakeThread.thThreadClass = kNuThreadClassData; fakeThread.thThreadFormat = kNuThreadFormatUncompressed; fakeThread.thThreadKind = threadKind; fakeThread.thThreadCRC = kNuInitialThreadCRC; fakeThread.thThreadEOF = 0; fakeThread.thCompThreadEOF = 0; fakeThread.threadIdx = (NuThreadIdx)-1; /* shouldn't matter */ fakeThread.actualThreadEOF = 0; fakeThread.fileOffset = 0; /* shouldn't matter */ fakeThread.used = false; err = Nu_ExtractThreadBulk(pArchive, pRecord, &fakeThread); if (err == kNuErrSkipped) err = Nu_SkipThread(pArchive, pRecord, &fakeThread); return err; } /* * Run through the entire archive, extracting the contents. */ NuError Nu_StreamExtract(NuArchive* pArchive) { NuError err = kNuErrNone; NuRecord tmpRecord; Boolean needFakeData, needFakeRsrc; uint32_t count; long idx; /* reset this just to be safe */ pArchive->lastDirCreatedUNI = NULL; Nu_InitRecordContents(pArchive, &tmpRecord); count = pArchive->masterHeader.mhTotalRecords; while (count--) { /* * Read the record header (which includes the thread header blocks). */ err = Nu_ReadRecordHeader(pArchive, &tmpRecord); BailError(err); /* * We may need to pull the filename out of a thread, but we don't * want to blow past any data while we do it. There's no really * good way to deal with this, so we just assume that all NuFX * applications are nice and put the filename thread first. */ for (idx = 0; idx < (long)tmpRecord.recTotalThreads; idx++) { const NuThread* pThread = Nu_GetThread(&tmpRecord, idx); if (NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind) == kNuThreadIDFilename) { break; } } /* if we have fn, read it; either way, leave idx pointing at next */ if (idx < (long)tmpRecord.recTotalThreads) { idx++; /* want count, not index */ err = Nu_ScanThreads(pArchive, &tmpRecord, idx); BailError(err); } else idx = 0; if (tmpRecord.filenameMOR == NULL) { Nu_ReportError(NU_BLOB, kNuErrNone, "Couldn't find filename in record"); err = kNuErrBadRecord; goto bail; } /*Nu_DebugDumpRecord(&tmpRecord); printf("\n");*/ needFakeData = true; needFakeRsrc = (tmpRecord.recStorageType == kNuStorageExtended); /* extract all relevant (remaining) threads */ pArchive->lastFileCreatedUNI = NULL; for ( ; idx < (long)tmpRecord.recTotalThreads; idx++) { const NuThread* pThread = Nu_GetThread(&tmpRecord, idx); if (pThread->thThreadClass == kNuThreadClassData) { if (pThread->thThreadKind == kNuThreadKindDataFork) { needFakeData = false; } else if (pThread->thThreadKind == kNuThreadKindRsrcFork) { needFakeRsrc = false; } else if (pThread->thThreadKind == kNuThreadKindDiskImage) { /* needFakeRsrc shouldn't be set, but clear anyway */ needFakeData = needFakeRsrc = false; } err = Nu_ExtractThreadBulk(pArchive, &tmpRecord, pThread); if (err == kNuErrSkipped) { err = Nu_SkipThread(pArchive, &tmpRecord, pThread); BailError(err); } else if (err != kNuErrNone) goto bail; } else { DBUG(("IGNORING 0x%08lx from '%s'\n", NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind), tmpRecord.filename)); if (NuGetThreadID(pThread) != kNuThreadIDComment && NuGetThreadID(pThread) != kNuThreadIDFilename) { /* unknown stuff in record, skip thread fakery */ needFakeData = needFakeRsrc = false; } err = Nu_SkipThread(pArchive, &tmpRecord, pThread); BailError(err); } } /* * As in Nu_ExtractRecordByPtr, we need to synthesize empty forks for * cases where GSHK omitted the data thread entirely. */ Assert(!pArchive->valMaskDataless || (!needFakeData && !needFakeRsrc)); if (needFakeData) { err = Nu_FakeZeroExtract(pArchive, &tmpRecord, kNuThreadKindDataFork); BailError(err); } if (needFakeRsrc) { err = Nu_FakeZeroExtract(pArchive, &tmpRecord, kNuThreadKindRsrcFork); BailError(err); } /* dispose of the entry */ (void) Nu_FreeRecordContents(pArchive, &tmpRecord); (void) Nu_InitRecordContents(pArchive, &tmpRecord); } bail: (void) Nu_FreeRecordContents(pArchive, &tmpRecord); return err; } /* * Test the contents of an archive. Works just like extraction, but we * don't store anything. */ NuError Nu_StreamTest(NuArchive* pArchive) { NuError err; pArchive->testMode = true; err = Nu_StreamExtract(pArchive); pArchive->testMode = false; return err; } /* * =========================================================================== * Non-streaming read-only operations * =========================================================================== */ /* * Shove the archive table of contents through the callback function. * * This only walks through the "orig" list, so it does not reflect the * results of un-flushed changes. */ NuError Nu_Contents(NuArchive* pArchive, NuCallback contentFunc) { NuError err = kNuErrNone; NuRecord* pRecord; NuResult result; uint32_t count; if (contentFunc == NULL) { err = kNuErrInvalidArg; goto bail; } err = Nu_RecordWalkPrepare(pArchive, &pRecord); BailError(err); count = pArchive->masterHeader.mhTotalRecords; while (count--) { err = Nu_RecordWalkGetNext(pArchive, &pRecord); BailError(err); Assert(pRecord->filenameMOR != NULL); result = (*contentFunc)(pArchive, pRecord); if (result == kNuAbort) { err = kNuErrAborted; goto bail; } } bail: (void) Nu_RecordWalkFinish(pArchive, err); return err; } /* * Extract all interesting threads from a record, given a NuRecord pointer * into the archive data structure. * * This assumes random access, so it can't be used in streaming mode. */ static NuError Nu_ExtractRecordByPtr(NuArchive* pArchive, NuRecord* pRecord) { NuError err = kNuErrNone; Boolean needFakeData, needFakeRsrc; uint32_t idx; needFakeData = true; needFakeRsrc = (pRecord->recStorageType == kNuStorageExtended); Assert(!Nu_IsStreaming(pArchive)); /* we don't skip things we don't read */ Assert(pRecord != NULL); /* extract all relevant threads */ pArchive->lastFileCreatedUNI = NULL; for (idx = 0; idx < pRecord->recTotalThreads; idx++) { const NuThread* pThread = Nu_GetThread(pRecord, idx); if (pThread->thThreadClass == kNuThreadClassData) { if (pThread->thThreadKind == kNuThreadKindDataFork) { needFakeData = false; } else if (pThread->thThreadKind == kNuThreadKindRsrcFork) { needFakeRsrc = false; } else if (pThread->thThreadKind == kNuThreadKindDiskImage) { /* needFakeRsrc shouldn't be set, but clear anyway */ needFakeData = needFakeRsrc = false; } err = Nu_ExtractThreadBulk(pArchive, pRecord, pThread); if (err == kNuErrSkipped) { err = Nu_SkipThread(pArchive, pRecord, pThread); BailError(err); } else if (err != kNuErrNone) goto bail; } else { if (NuGetThreadID(pThread) != kNuThreadIDComment && NuGetThreadID(pThread) != kNuThreadIDFilename) { /* * This record has a thread we don't recognize. Disable * the thread fakery to avoid doing anything weird -- we * should only need to create zero-length files for * simple file records. */ needFakeData = needFakeRsrc = false; } DBUG(("IGNORING 0x%08lx from '%s'\n", NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind), pRecord->filenameMOR)); } } /* * GSHK creates empty threads for zero-length forks. It doesn't always * handle them correctly when extracting, so it appears this behavior * may not be intentional. * * We need to create an empty file for whichever forks are missing. * Could be the data fork, resource fork, or both. The only way to * know what's expected is to examine the file's storage type. * * If valMaskDataless is enabled, this won't fire, because we will have * "forged" the appropriate threads. * * Note there's another one of these below, in Nu_StreamExtract. */ Assert(!pArchive->valMaskDataless || (!needFakeData && !needFakeRsrc)); if (needFakeData) { err = Nu_FakeZeroExtract(pArchive, pRecord, kNuThreadKindDataFork); BailError(err); } if (needFakeRsrc) { err = Nu_FakeZeroExtract(pArchive, pRecord, kNuThreadKindRsrcFork); BailError(err); } bail: return err; } /* * Extract a big buncha files. */ NuError Nu_Extract(NuArchive* pArchive) { NuError err; NuRecord* pRecord = NULL; uint32_t count; long offset; /* reset this just to be safe */ pArchive->lastDirCreatedUNI = NULL; err = Nu_RecordWalkPrepare(pArchive, &pRecord); BailError(err); count = pArchive->masterHeader.mhTotalRecords; while (count--) { /* read the record and threads if we don't have them yet */ err = Nu_RecordWalkGetNext(pArchive, &pRecord); BailError(err); if (!pArchive->haveToc) { /* remember where the end of the record is */ err = Nu_FTell(pArchive->archiveFp, &offset); BailError(err); } /* extract one or more threads */ err = Nu_ExtractRecordByPtr(pArchive, pRecord); BailError(err); if (!pArchive->haveToc) { /* line us back up so RecordWalkGetNext can read the record hdr */ err = Nu_FSeek(pArchive->archiveFp, offset, SEEK_SET); BailError(err); } } bail: (void) Nu_RecordWalkFinish(pArchive, err); return err; } /* * Extract a single record. */ NuError Nu_ExtractRecord(NuArchive* pArchive, NuRecordIdx recIdx) { NuError err; NuRecord* pRecord; if (Nu_IsStreaming(pArchive)) return kNuErrUsage; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* find the correct record by index */ err = Nu_RecordSet_FindByIdx(&pArchive->origRecordSet, recIdx, &pRecord); BailError(err); Assert(pRecord != NULL); /* extract whatever looks promising */ err = Nu_ExtractRecordByPtr(pArchive, pRecord); BailError(err); bail: return err; } /* * Test the contents of an archive. Works just like extraction, but we * don't store anything. */ NuError Nu_Test(NuArchive* pArchive) { NuError err; pArchive->testMode = true; err = Nu_Extract(pArchive); pArchive->testMode = false; return err; } /* * Test a single record. */ NuError Nu_TestRecord(NuArchive* pArchive, NuRecordIdx recIdx) { NuError err; NuRecord* pRecord; if (Nu_IsStreaming(pArchive)) return kNuErrUsage; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* find the correct record by index */ err = Nu_RecordSet_FindByIdx(&pArchive->origRecordSet, recIdx, &pRecord); BailError(err); Assert(pRecord != NULL); /* extract whatever looks promising */ pArchive->testMode = true; err = Nu_ExtractRecordByPtr(pArchive, pRecord); pArchive->testMode = false; BailError(err); bail: return err; } /* * Return a pointer to a NuRecord. * * This pulls the record out of the "orig" set, so it will work even * for records that have been deleted. It will not reflect changes * made by previous "write" calls, not even SetRecordAttr. */ NuError Nu_GetRecord(NuArchive* pArchive, NuRecordIdx recordIdx, const NuRecord** ppRecord) { NuError err; if (recordIdx == 0 || ppRecord == NULL) return kNuErrInvalidArg; if (Nu_IsStreaming(pArchive)) return kNuErrUsage; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); err = Nu_RecordSet_FindByIdx(&pArchive->origRecordSet, recordIdx, (NuRecord**)ppRecord); if (err == kNuErrNone) { Assert(*ppRecord != NULL); } /* fall through with error */ bail: return err; } /* * Find the recordIdx of a record by storage name. */ NuError Nu_GetRecordIdxByName(NuArchive* pArchive, const char* nameMOR, NuRecordIdx* pRecordIdx) { NuError err; NuRecord* pRecord = NULL; if (pRecordIdx == NULL) return kNuErrInvalidArg; if (Nu_IsStreaming(pArchive)) return kNuErrUsage; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); err = Nu_RecordSet_FindByName(&pArchive->origRecordSet, nameMOR, &pRecord); if (err == kNuErrNone) { Assert(pRecord != NULL); *pRecordIdx = pRecord->recordIdx; } /* fall through with error */ bail: return err; } /* * Find the recordIdx of a record by zero-based position. */ NuError Nu_GetRecordIdxByPosition(NuArchive* pArchive, uint32_t position, NuRecordIdx* pRecordIdx) { NuError err; const NuRecord* pRecord; if (pRecordIdx == NULL) return kNuErrInvalidArg; if (Nu_IsStreaming(pArchive)) return kNuErrUsage; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); if (position >= Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet)) { err = kNuErrRecordNotFound; goto bail; } pRecord = Nu_RecordSet_GetListHead(&pArchive->origRecordSet); while (position--) { Assert(pRecord->pNext != NULL); pRecord = pRecord->pNext; } *pRecordIdx = pRecord->recordIdx; bail: return err; } /* * =========================================================================== * Read/write record operations (add, delete) * =========================================================================== */ /* * Find an existing record somewhere in the archive. If the "copy" set * exists it will be searched. If not, the "orig" set is searched, and * if an entry is found a "copy" set will be created. * * The goal is to always return something from the "copy" set, which we * could do easily by just creating the "copy" set and then searching in * it. However, we don't want to create the "copy" set if we don't have * to, so we search "orig" if "copy" doesn't exist yet. * * The record returned will always be from the "copy" set. An error result * is returned if the record isn't found. */ NuError Nu_FindRecordForWriteByIdx(NuArchive* pArchive, NuRecordIdx recIdx, NuRecord** ppFoundRecord) { NuError err; Assert(pArchive != NULL); Assert(ppFoundRecord != NULL); if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) { err = Nu_RecordSet_FindByIdx(&pArchive->copyRecordSet, recIdx, ppFoundRecord); } else { Assert(Nu_RecordSet_GetLoaded(&pArchive->origRecordSet)); err = Nu_RecordSet_FindByIdx(&pArchive->origRecordSet, recIdx, ppFoundRecord); *ppFoundRecord = NULL; /* can't delete from here */ } BailErrorQuiet(err); /* * The record exists. If we were looking in the "orig" set, we have * to create a "copy" set and return it from there. */ if (*ppFoundRecord == NULL) { err = Nu_RecordSet_Clone(pArchive, &pArchive->copyRecordSet, &pArchive->origRecordSet); BailError(err); err = Nu_RecordSet_FindByIdx(&pArchive->copyRecordSet, recIdx, ppFoundRecord); Assert(err == kNuErrNone && *ppFoundRecord != NULL); /* must succeed */ BailError(err); } bail: return err; } /* * Deal with the situation where we're trying to add a record with the * same name as an existing record. The existing record can't be in the * "new" list (that's handled differently) and can't already have been * deleted. * * This will either delete the existing record or return with an error. * * If we decide to delete the record, and the "orig" record set was * passed in, then the record will be deleted from the "copy" set (which * will be created only if necessary). */ static NuError Nu_HandleAddDuplicateRecord(NuArchive* pArchive, NuRecordSet* pRecordSet, NuRecord* pRecord, const NuFileDetails* pFileDetails) { NuError err = kNuErrNone; NuErrorStatus errorStatus; NuResult result; Assert(pRecordSet == &pArchive->origRecordSet || pRecordSet == &pArchive->copyRecordSet); Assert(pRecord != NULL); Assert(pFileDetails != NULL); Assert(pArchive->valAllowDuplicates == false); /* * If "only update older" is set, check the dates. Reject the * request if the archived file isn't older than the new file. This * tells the application that the request was rejected, but it's * okay for them to move on to the next file. */ if (pArchive->valOnlyUpdateOlder) { if (!Nu_IsOlder(&pRecord->recModWhen, &pFileDetails->modWhen)) return kNuErrNotNewer; } /* * The file exists when it shouldn't. Decide what to do, based * on the options configured by the application. * * If they "might" allow overwrites, and they have an error-handling * callback defined, call that to find out what they want to do * here. Options include skipping or overwriting the record. * * We don't currently allow renaming of records, though I suppose we * could. */ switch (pArchive->valHandleExisting) { case kNuMaybeOverwrite: if (pArchive->errorHandlerFunc != NULL) { errorStatus.operation = kNuOpAdd; errorStatus.err = kNuErrRecordExists; errorStatus.sysErr = 0; errorStatus.message = NULL; errorStatus.pRecord = pRecord; UNICHAR* pathnameUNI = Nu_CopyMORToUNI(pFileDetails->storageNameMOR); errorStatus.pathnameUNI = pathnameUNI; errorStatus.origPathname = pFileDetails->origName; errorStatus.filenameSeparator = NuGetSepFromSysInfo(pFileDetails->fileSysInfo); /*errorStatus.origArchiveTouched = false;*/ errorStatus.canAbort = true; errorStatus.canRetry = false; errorStatus.canIgnore = false; errorStatus.canSkip = true; errorStatus.canRename = false; errorStatus.canOverwrite = true; result = (*pArchive->errorHandlerFunc)(pArchive, &errorStatus); Nu_Free(pArchive, pathnameUNI); switch (result) { case kNuAbort: err = kNuErrAborted; goto bail; case kNuSkip: err = kNuErrSkipped; goto bail; case kNuOverwrite: break; /* fall back into main code */ case kNuRetry: case kNuRename: case kNuIgnore: default: err = kNuErrSyntax; Nu_ReportError(NU_BLOB, err, "Wasn't expecting result %d here", result); goto bail; } } else { /* no error handler, treat like NeverOverwrite */ err = kNuErrSkipped; goto bail; } break; case kNuNeverOverwrite: err = kNuErrSkipped; goto bail; case kNuMustOverwrite: case kNuAlwaysOverwrite: /* fall through to record deletion */ break; default: Assert(0); err = kNuErrInternal; goto bail; } err = kNuErrNone; /* * We're going to overwrite the existing record. To do this, we have * to start by deleting it from the "copy" list. * * If the copy set doesn't yet exist, we have to create it and find * the record in the new set. */ if (pRecordSet == &pArchive->origRecordSet) { Assert(!Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)); err = Nu_RecordSet_Clone(pArchive, &pArchive->copyRecordSet, &pArchive->origRecordSet); BailError(err); err = Nu_RecordSet_FindByIdx(&pArchive->copyRecordSet, pRecord->recordIdx, &pRecord); Assert(err == kNuErrNone && pRecord != NULL); /* must succeed */ BailError(err); } DBUG(("+++ deleting record %ld\n", pRecord->recordIdx)); err = Nu_RecordSet_DeleteRecord(pArchive,&pArchive->copyRecordSet, pRecord); BailError(err); bail: return err; } /* * Create a new record, filling in most of the blanks from "pFileDetails". * * The filename in pFileDetails->storageName will be remembered. If no * filename thread is added to this record before the next Flush call, a * filename thread will be generated from this name. * * This always creates a "version 3" record, regardless of what else is * in the archive. The filename is always in a thread. * * On success, the NuRecordIdx of the newly-created record will be placed * in "*pRecordIdx", and the NuThreadIdx of the filename thread will be * placed in "*pThreadIdx". If "*ppNewRecord" is non-NULL, it gets a pointer * to the newly-created record (this isn't part of the external interface). */ NuError Nu_AddRecord(NuArchive* pArchive, const NuFileDetails* pFileDetails, NuRecordIdx* pRecordIdx, NuRecord** ppNewRecord) { NuError err; NuRecord* pNewRecord = NULL; if (pFileDetails == NULL || pFileDetails->storageNameMOR == NULL || pFileDetails->storageNameMOR[0] == '\0' || NuGetSepFromSysInfo(pFileDetails->fileSysInfo) == 0) /* pRecordIdx may be NULL */ /* ppNewRecord may be NULL */ { err = kNuErrInvalidArg; goto bail; } if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* NuFX spec forbids leading fssep chars */ if (pFileDetails->storageNameMOR[0] == NuGetSepFromSysInfo(pFileDetails->fileSysInfo)) { err = kNuErrLeadingFssep; goto bail; } /* * If requested, look for an existing record. Look in the "copy" * list if we have it (so we don't complain if they've already deleted * the record), or in the "orig" list if we don't. Look in the "new" * list to see if it clashes with something we've just added. * * If this is a brand-new archive, there won't be an "orig" list * either. */ if (!pArchive->valAllowDuplicates) { NuRecordSet* pRecordSet; NuRecord* pFoundRecord; pRecordSet = &pArchive->copyRecordSet; if (!Nu_RecordSet_GetLoaded(pRecordSet)) pRecordSet = &pArchive->origRecordSet; Assert(Nu_RecordSet_GetLoaded(pRecordSet)); err = Nu_RecordSet_FindByName(pRecordSet, pFileDetails->storageNameMOR, &pFoundRecord); if (err == kNuErrNone) { /* handle the existing record */ DBUG(("--- Duplicate record found (%06ld) '%s'\n", pFoundRecord->recordIdx, pFoundRecord->filenameMOR)); err = Nu_HandleAddDuplicateRecord(pArchive, pRecordSet, pFoundRecord, pFileDetails); if (err != kNuErrNone) { /* for whatever reason, we're not replacing it */ DBUG(("--- Returning err=%d\n", err)); goto bail; } } else { /* if we *must* replace an existing file, we fail now */ if (pArchive->valHandleExisting == kNuMustOverwrite) { DBUG(("+++ can't freshen nonexistent '%s'\n", pFileDetails->storageName)); err = kNuErrDuplicateNotFound; goto bail; } } if (Nu_RecordSet_GetLoaded(&pArchive->newRecordSet)) { err = Nu_RecordSet_FindByName(&pArchive->newRecordSet, pFileDetails->storageNameMOR, &pFoundRecord); if (err == kNuErrNone) { /* we can't delete from the "new" list, so return an error */ err = kNuErrRecordExists; goto bail; } } /* clear "err" so we can continue */ err = kNuErrNone; } /* * Prepare the new record structure. */ err = Nu_RecordNew(pArchive, &pNewRecord); BailError(err); (void) Nu_InitRecordContents(pArchive, pNewRecord); memcpy(pNewRecord->recNufxID, kNufxID, kNufxIDLen); /*pNewRecord->recHeaderCRC*/ /*pNewRecord->recAttribCount*/ pNewRecord->recVersionNumber = kNuOurRecordVersion; pNewRecord->recTotalThreads = 0; pNewRecord->recFileSysID = pFileDetails->fileSysID; pNewRecord->recFileSysInfo = pFileDetails->fileSysInfo; pNewRecord->recAccess = pFileDetails->access; pNewRecord->recFileType = pFileDetails->fileType; pNewRecord->recExtraType = pFileDetails->extraType; pNewRecord->recStorageType = pFileDetails->storageType; pNewRecord->recCreateWhen = pFileDetails->createWhen; pNewRecord->recModWhen = pFileDetails->modWhen; pNewRecord->recArchiveWhen = pFileDetails->archiveWhen; pNewRecord->recOptionSize = 0; pNewRecord->extraCount = 0; pNewRecord->recFilenameLength = 0; pNewRecord->recordIdx = Nu_GetNextRecordIdx(pArchive); pNewRecord->threadFilenameMOR = NULL; pNewRecord->newFilenameMOR = strdup(pFileDetails->storageNameMOR); pNewRecord->filenameMOR = pNewRecord->newFilenameMOR; pNewRecord->recHeaderLength = -1; pNewRecord->totalCompLength = 0; pNewRecord->fakeThreads = 0; pNewRecord->fileOffset = -1; /* * Add it to the "new" record set. */ err = Nu_RecordSet_AddRecord(&pArchive->newRecordSet, pNewRecord); BailError(err); /* return values */ if (pRecordIdx != NULL) *pRecordIdx = pNewRecord->recordIdx; if (ppNewRecord != NULL) *ppNewRecord = pNewRecord; bail: return err; } /* * Add a new "add file" thread mod to the specified record. * * The caller should have already verified that there isn't another * "add file" thread mod with the same ThreadID. */ static NuError Nu_AddFileThreadMod(NuArchive* pArchive, NuRecord* pRecord, const UNICHAR* pathnameUNI, const NuFileDetails* pFileDetails, Boolean fromRsrcFork) { NuError err; NuThreadFormat threadFormat; NuDataSource* pDataSource = NULL; NuThreadMod* pThreadMod = NULL; Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(pathnameUNI != NULL); Assert(pFileDetails != NULL); Assert(fromRsrcFork == true || fromRsrcFork == false); if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; /* decide if this should be compressed; we know source isn't */ if (Nu_IsCompressibleThreadID(pFileDetails->threadID)) threadFormat = Nu_ConvertCompressValToFormat(pArchive, pArchive->valDataCompression); else threadFormat = kNuThreadFormatUncompressed; /* create a data source for this file, which is assumed uncompressed */ err = Nu_DataSourceFile_New(kNuThreadFormatUncompressed, 0, pathnameUNI, fromRsrcFork, &pDataSource); BailError(err); /* create a new ThreadMod */ err = Nu_ThreadModAdd_New(pArchive, pFileDetails->threadID, threadFormat, pDataSource, &pThreadMod); BailError(err); Assert(pThreadMod != NULL); /*pDataSource = NULL;*/ /* ThreadModAdd_New makes a copy */ /* add the thread mod to the record */ Nu_RecordAddThreadMod(pRecord, pThreadMod); pThreadMod = NULL; /* don't free on exit */ bail: if (pDataSource != NULL) Nu_DataSourceFree(pDataSource); if (pThreadMod != NULL) Nu_ThreadModFree(pArchive, pThreadMod); return err; } /* * Make note of a file to add. This goes beyond AddRecord and AddThread * calls by searching the list of newly-added files for matching pairs * of data and rsrc forks. This is independent of the "overwrite existing * files" feature. The comparison is made based on storageName. * * "fromRsrcFork" tells us how to open the source file, not what type * of thread the file should be stored as. * * If "pRecordIdx" is non-NULL, it will receive the newly assigned recordID. */ NuError Nu_AddFile(NuArchive* pArchive, const UNICHAR* pathnameUNI, const NuFileDetails* pFileDetails, Boolean fromRsrcFork, NuRecordIdx* pRecordIdx) { NuError err = kNuErrNone; NuRecordIdx recordIdx = 0; NuRecord* pRecord; if (pathnameUNI == NULL || pFileDetails == NULL || !(fromRsrcFork == true || fromRsrcFork == false)) { return kNuErrInvalidArg; } if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); if (pFileDetails->storageNameMOR == NULL) { err = kNuErrInvalidArg; Nu_ReportError(NU_BLOB, err, "Must specify storageName"); goto bail; } if (pFileDetails->storageNameMOR[0] == NuGetSepFromSysInfo(pFileDetails->fileSysInfo)) { err = kNuErrLeadingFssep; goto bail; } DBUG(("+++ ADDING '%s' (%s) 0x%02lx 0x%04lx threadID=0x%08lx\n", pathnameUNI, pFileDetails->storageName, pFileDetails->fileType, pFileDetails->extraType, pFileDetails->threadID)); /* * See if there's another record among the "new additions" with the * same storageName and compatible threads. * * If found, add a new thread in that record. If an incompatibility * exists (same fork already present, disk image is there, etc), either * create a new record or return with an error. * * We want to search from the *end* of the "new" list, so that if * duplicates are allowed we find the entry most likely to be paired * up with the fork currently being added. */ if (Nu_RecordSet_GetLoaded(&pArchive->newRecordSet)) { NuRecord* pNewRecord; err = Nu_RecordSet_ReverseFindByName(&pArchive->newRecordSet, pFileDetails->storageNameMOR, &pNewRecord); if (err == kNuErrNone) { /* is it okay to add it here? */ err = Nu_OkayToAddThread(pArchive, pNewRecord, pFileDetails->threadID); if (err == kNuErrNone) { /* okay to add it to this record */ DBUG((" attaching to existing record %06ld\n", pNewRecord->recordIdx)); err = Nu_AddFileThreadMod(pArchive, pNewRecord, pathnameUNI, pFileDetails, fromRsrcFork); BailError(err); recordIdx = pNewRecord->recordIdx; goto bail; /* we're done! */ } err = kNuErrNone; /* go a little farther */ /* * We found a brand-new record with the same name, but we * can't add this fork to that record. We can't delete the * item from the "new" list, so we can ignore HandleExisting. * If we don't allow duplicates, return an error; if we do, * then just continue with the normal processing path. */ if (!pArchive->valAllowDuplicates) { DBUG(("+++ found matching record in new list, no dups\n")); err = kNuErrRecordExists; goto bail; } } else if (err == kNuErrRecNameNotFound) { /* no match in "new" list, fall through to normal processing */ err = kNuErrNone; } else { /* general failure */ goto bail; } } /* * Wasn't found, invoke Nu_AddRecord. This will search through the * existing records, using the "allow duplicates" flag to cope with * any matches it finds. On success, we should have a brand-new record * to play with. */ err = Nu_AddRecord(pArchive, pFileDetails, &recordIdx, &pRecord); BailError(err); DBUG(("--- Added new record %06ld\n", recordIdx)); /* * Got the record, now add a data file thread. */ err = Nu_AddFileThreadMod(pArchive, pRecord, pathnameUNI, pFileDetails, fromRsrcFork); BailError(err); bail: if (err == kNuErrNone && pRecordIdx != NULL) *pRecordIdx = recordIdx; return err; } /* * Rename a record. There are three situations: * * (1) Record has the filename in a thread, and the field has enough * room to hold the new name. For this case we add an "update" threadMod * with the new data. * (2) Record has the filename in a thread, and there is not enough room * to hold the new name. Here, we add a "delete" threadMod for the * existing filename, and add an "add" threadMod for the new. * (3) Record stores the filename in the header. We zero out the filename * and add a filename thread. * * We don't actually check to see if the filename is changing. If you * want to rename something to the same thing, go right ahead. (This * provides a way for applications to "filter" records that have filenames * in the headers instead of a thread.) * * BUG: we shouldn't allow a disk image to be renamed to have a complex * path name (e.g. "dir1:dir2:foo"). However, we may not be able to catch * that here depending on pending operations. * * We might also want to screen out trailing fssep chars, though the NuFX * spec doesn't say they're illegal. */ NuError Nu_Rename(NuArchive* pArchive, NuRecordIdx recIdx, const char* pathnameMOR, char fssepMOR) { NuError err; NuRecord* pRecord; NuThread* pFilenameThread; const NuThreadMod* pThreadMod; NuThreadMod* pNewThreadMod = NULL; NuDataSource* pDataSource = NULL; long requiredCapacity, existingCapacity, newCapacity; Boolean doDelete, doAdd, doUpdate; if (recIdx == 0 || pathnameMOR == NULL || pathnameMOR[0] == '\0' || fssepMOR == '\0') { return kNuErrInvalidArg; } if (pathnameMOR[0] == fssepMOR) { err = kNuErrLeadingFssep; Nu_ReportError(NU_BLOB, err, "rename path"); goto bail; } if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* find the record in the "copy" set */ err = Nu_FindRecordForWriteByIdx(pArchive, recIdx, &pRecord); BailError(err); Assert(pRecord != NULL); /* look for a filename thread */ err = Nu_FindThreadByID(pRecord, kNuThreadIDFilename, &pFilenameThread); if (err != kNuErrNone) pFilenameThread = NULL; else if (err == kNuErrNone && pRecord->pThreadMods) { /* found a thread, check to see if it has been deleted (or modifed) */ Assert(pFilenameThread != NULL); pThreadMod = Nu_ThreadMod_FindByThreadIdx(pRecord, pFilenameThread->threadIdx); if (pThreadMod != NULL) { DBUG(("--- tried to modify threadIdx %ld, which has already been\n", pFilenameThread->threadIdx)); err = kNuErrModThreadChange; goto bail; } } /* * Looks like we're okay so far. Figure out what to do. */ doDelete = doAdd = doUpdate = false; newCapacity = existingCapacity = 0; requiredCapacity = strlen(pathnameMOR); if (pFilenameThread != NULL) { existingCapacity = pFilenameThread->thCompThreadEOF; if (existingCapacity >= requiredCapacity) { doUpdate = true; newCapacity = existingCapacity; } else { doDelete = doAdd = true; /* make sure they have a few bytes of leeway */ /*newCapacity = (requiredCapacity + kNuDefaultFilenameThreadSize) & (~(kNuDefaultFilenameThreadSize-1));*/ newCapacity = requiredCapacity + 8; } } else { doAdd = true; /*newCapacity = (requiredCapacity + kNuDefaultFilenameThreadSize) & (~(kNuDefaultFilenameThreadSize-1));*/ newCapacity = requiredCapacity + 8; } Assert(doAdd || doDelete || doUpdate); Assert(doDelete == false || doAdd == true); /* create a data source for the filename, if needed */ if (doAdd || doUpdate) { Assert(newCapacity); err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, newCapacity, (const uint8_t*)strdup(pathnameMOR), 0, requiredCapacity /*(strlen)*/, Nu_InternalFreeCallback, &pDataSource); BailError(err); } if (doDelete) { err = Nu_ThreadModDelete_New(pArchive, pFilenameThread->threadIdx, kNuThreadIDFilename, &pNewThreadMod); BailError(err); Nu_RecordAddThreadMod(pRecord, pNewThreadMod); pNewThreadMod = NULL; /* successful, don't free */ } if (doAdd) { err = Nu_ThreadModAdd_New(pArchive, kNuThreadIDFilename, kNuThreadFormatUncompressed, pDataSource, &pNewThreadMod); BailError(err); /*pDataSource = NULL;*/ /* ThreadModAdd_New makes a copy */ Nu_RecordAddThreadMod(pRecord, pNewThreadMod); pNewThreadMod = NULL; /* successful, don't free */ } if (doUpdate) { err = Nu_ThreadModUpdate_New(pArchive, pFilenameThread->threadIdx, pDataSource, &pNewThreadMod); BailError(err); /*pDataSource = NULL;*/ /* ThreadModAdd_New makes a copy */ Nu_RecordAddThreadMod(pRecord, pNewThreadMod); pNewThreadMod = NULL; /* successful, don't free */ } DBUG(("--- renaming '%s' to '%s' with delete=%d add=%d update=%d\n", pRecord->filenameMOR, pathnameMOR, doDelete, doAdd, doUpdate)); /* * Update the fssep, if necessary. (This is slightly silly -- we * have to rewrite the record header anyway since we're changing * threads around.) */ if (NuGetSepFromSysInfo(pRecord->recFileSysInfo) != fssepMOR) { DBUG(("--- and updating the fssep\n")); pRecord->recFileSysInfo = NuSetSepInSysInfo(pRecord->recFileSysInfo, fssepMOR); pRecord->dirtyHeader = true; } /* if we had a header filename, mark it for oblivion */ if (pFilenameThread == NULL) { DBUG(("+++ rename gonna drop the filename\n")); pRecord->dropRecFilename = true; } bail: Nu_ThreadModFree(pArchive, pNewThreadMod); Nu_DataSourceFree(pDataSource); return err; } /* * Update a record's attributes with the contents of pRecordAttr. */ NuError Nu_SetRecordAttr(NuArchive* pArchive, NuRecordIdx recordIdx, const NuRecordAttr* pRecordAttr) { NuError err; NuRecord* pRecord; if (pRecordAttr == NULL) return kNuErrInvalidArg; if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* pull the record out of the "copy" set */ err = Nu_FindRecordForWriteByIdx(pArchive, recordIdx, &pRecord); BailError(err); Assert(pRecord != NULL); pRecord->recFileSysID = pRecordAttr->fileSysID; /*pRecord->recFileSysInfo = pRecordAttr->fileSysInfo;*/ pRecord->recAccess = pRecordAttr->access; pRecord->recFileType = pRecordAttr->fileType; pRecord->recExtraType = pRecordAttr->extraType; pRecord->recCreateWhen = pRecordAttr->createWhen; pRecord->recModWhen = pRecordAttr->modWhen; pRecord->recArchiveWhen = pRecordAttr->archiveWhen; pRecord->dirtyHeader = true; bail: return err; } /* * Bulk-delete several records, using the selection filter callback. */ NuError Nu_Delete(NuArchive* pArchive) { NuError err; NuSelectionProposal selProposal; NuRecord* pNextRecord; NuRecord* pRecord; NuResult result; if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* * If we don't yet have a copy set, make one. */ if (!Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) { err = Nu_RecordSet_Clone(pArchive, &pArchive->copyRecordSet, &pArchive->origRecordSet); BailError(err); } /* * Run through the copy set. This is different from most other * operations, which run through the "orig" set. However, since * we're not interested in allowing the user to delete things that * have already been deleted, we might as well use this set. */ pNextRecord = Nu_RecordSet_GetListHead(&pArchive->copyRecordSet); while (pNextRecord != NULL) { pRecord = pNextRecord; pNextRecord = pRecord->pNext; /* * Deletion of modified records (thread adds, deletes, or updates) * isn't allowed. There's no point in showing the record to the * user. */ if (pRecord->pThreadMods != NULL) { DBUG(("+++ Skipping delete on a modified record\n")); continue; } /* * If a selection filter is defined, allow the user the opportunity * to select which files will be deleted, or abort the entire * operation. */ if (pArchive->selectionFilterFunc != NULL) { selProposal.pRecord = pRecord; selProposal.pThread = pRecord->pThreads; /* doesn't matter */ result = (*pArchive->selectionFilterFunc)(pArchive, &selProposal); if (result == kNuSkip) continue; if (result == kNuAbort) { err = kNuErrAborted; goto bail; } } /* * Do we want to allow this? (Same test as for DeleteRecord.) */ if (pRecord->pThreadMods != NULL || pRecord->dirtyHeader) { DBUG(("--- Tried to delete a modified record\n")); err = kNuErrModRecChange; goto bail; } err = Nu_RecordSet_DeleteRecord(pArchive, &pArchive->copyRecordSet, pRecord); BailError(err); } bail: return err; } /* * Delete an entire record. */ NuError Nu_DeleteRecord(NuArchive* pArchive, NuRecordIdx recIdx) { NuError err; NuRecord* pRecord; if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); err = Nu_FindRecordForWriteByIdx(pArchive, recIdx, &pRecord); BailError(err); /* * Deletion of modified records (thread adds, deletes, or updates) isn't * allowed. It probably wouldn't be hard to handle, but it's pointless. * Preventing the action maintains our general semantics of disallowing * conflicting actions on the same object. * * We also block it if the header is dirty (e.g. they changed the * record's filetype). This isn't necessary for correct operation, * but again it maintains the semantics. */ if (pRecord->pThreadMods != NULL || pRecord->dirtyHeader) { DBUG(("--- Tried to delete a modified record\n")); err = kNuErrModRecChange; goto bail; } err = Nu_RecordSet_DeleteRecord(pArchive,&pArchive->copyRecordSet, pRecord); BailError(err); bail: return err; } nulib2-3.1.0/nufxlib/SourceSink.c000066400000000000000000000537041316100516500166150ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Implementation of DataSource and DataSink objects. */ #include "NufxLibPriv.h" /* * =========================================================================== * NuDataSource * =========================================================================== */ /* * Allocate a new DataSource structure. */ static NuError Nu_DataSourceNew(NuDataSource** ppDataSource) { Assert(ppDataSource != NULL); *ppDataSource = Nu_Malloc(NULL, sizeof(**ppDataSource)); if (*ppDataSource == NULL) return kNuErrMalloc; (*ppDataSource)->sourceType = kNuDataSourceUnknown; return kNuErrNone; } /* * Make a copy of a DataSource. Actually just increments a reference count. * * What we *really* want to be doing is copying the structure (since we * can't guarantee copy-on-write semantics for the fields without adding * more stuff) and refcounting the underlying resource, so that "auto-free" * semantics work out right. * * We're okay for now, since for the most part we only do work on one * copy of each. (I wish I could remember why this copying thing was * needed in the first place.) Buffer sources are a little scary since * they include a "curOffset" value. * * Returns NULL on error. */ NuDataSource* Nu_DataSourceCopy(NuDataSource* pDataSource) { Assert(pDataSource->common.refCount >= 1); pDataSource->common.refCount++; return pDataSource; #if 0 /* we used to copy them -- very bad idea */ NuDataSource* pNewDataSource; Assert(pDataSource != NULL); if (Nu_DataSourceNew(&pNewDataSource) != kNuErrNone) return NULL; Assert(pNewDataSource != NULL); /* this gets most of it */ memcpy(pNewDataSource, pDataSource, sizeof(*pNewDataSource)); /* copy anything we're sure to free up */ if (pDataSource->sourceType == kNuDataSourceFromFile) { Assert(pDataSource->fromFile.fp == NULL); /* does this matter? */ pNewDataSource->fromFile.pathname = strdup(pDataSource->fromFile.pathname); } /* don't let the original free up the resources */ if (pDataSource->common.doClose) { DBUG(("--- clearing doClose on source-copy of data source\n")); pDataSource->common.doClose = false; } return pNewDataSource; #endif } /* * Free a data source structure, and any type-specific elements. */ NuError Nu_DataSourceFree(NuDataSource* pDataSource) { if (pDataSource == NULL) return kNuErrNone; Assert(pDataSource->common.refCount > 0); if (pDataSource->common.refCount > 1) { pDataSource->common.refCount--; return kNuErrNone; } switch (pDataSource->sourceType) { case kNuDataSourceFromFile: Nu_Free(NULL, pDataSource->fromFile.pathnameUNI); if (pDataSource->fromFile.fp != NULL) { fclose(pDataSource->fromFile.fp); pDataSource->fromFile.fp = NULL; } break; case kNuDataSourceFromFP: if (pDataSource->fromFP.fcloseFunc != NULL && pDataSource->fromFP.fp != NULL) { (*pDataSource->fromFP.fcloseFunc)(NULL, pDataSource->fromFP.fp); pDataSource->fromFP.fp = NULL; } break; case kNuDataSourceFromBuffer: if (pDataSource->fromBuffer.freeFunc != NULL) { (*pDataSource->fromBuffer.freeFunc)(NULL, (void*)pDataSource->fromBuffer.buffer); pDataSource->fromBuffer.buffer = NULL; } break; case kNuDataSourceUnknown: break; default: Assert(0); return kNuErrInternal; } Nu_Free(NULL, pDataSource); return kNuErrNone; } /* * Create a data source for an unopened file. */ NuError Nu_DataSourceFile_New(NuThreadFormat threadFormat, uint32_t otherLen, const UNICHAR* pathnameUNI, Boolean isFromRsrcFork, NuDataSource** ppDataSource) { NuError err; if (pathnameUNI == NULL || !(isFromRsrcFork == true || isFromRsrcFork == false) || ppDataSource == NULL) { return kNuErrInvalidArg; } err = Nu_DataSourceNew(ppDataSource); BailErrorQuiet(err); (*ppDataSource)->common.sourceType = kNuDataSourceFromFile; (*ppDataSource)->common.threadFormat = threadFormat; (*ppDataSource)->common.rawCrc = 0; (*ppDataSource)->common.dataLen = 0; /* to be filled in later */ (*ppDataSource)->common.otherLen = otherLen; (*ppDataSource)->common.refCount = 1; (*ppDataSource)->fromFile.pathnameUNI = strdup(pathnameUNI); (*ppDataSource)->fromFile.fromRsrcFork = isFromRsrcFork; (*ppDataSource)->fromFile.fp = NULL; /* to be filled in later */ bail: return err; } /* * Create a data source for an open file at a specific offset. The FILE* * must be seekable. */ NuError Nu_DataSourceFP_New(NuThreadFormat threadFormat, uint32_t otherLen, FILE* fp, long offset, long length, NuCallback fcloseFunc, NuDataSource** ppDataSource) { NuError err; if (fp == NULL || offset < 0 || length < 0 || ppDataSource == NULL) { return kNuErrInvalidArg; } if (otherLen && otherLen < (uint32_t)length) { DBUG(("--- rejecting FP len=%ld other=%ld\n", length, otherLen)); err = kNuErrPreSizeOverflow; goto bail; } err = Nu_DataSourceNew(ppDataSource); BailErrorQuiet(err); (*ppDataSource)->common.sourceType = kNuDataSourceFromFP; (*ppDataSource)->common.threadFormat = threadFormat; (*ppDataSource)->common.rawCrc = 0; (*ppDataSource)->common.dataLen = length; (*ppDataSource)->common.otherLen = otherLen; (*ppDataSource)->common.refCount = 1; (*ppDataSource)->fromFP.fp = fp; (*ppDataSource)->fromFP.offset = offset; (*ppDataSource)->fromFP.fcloseFunc = fcloseFunc; bail: return err; } /* * Create a data source for a buffer. * * We allow "buffer" to be NULL so long as "offset" and "length" are also * NULL. This is useful for creating empty pre-sized buffers, such as * blank comment fields. */ NuError Nu_DataSourceBuffer_New(NuThreadFormat threadFormat, uint32_t otherLen, const uint8_t* buffer, long offset, long length, NuCallback freeFunc, NuDataSource** ppDataSource) { NuError err; if (offset < 0 || length < 0 || ppDataSource == NULL) return kNuErrInvalidArg; if (buffer == NULL && (offset != 0 || length != 0)) return kNuErrInvalidArg; if (buffer == NULL) { DBUG(("+++ zeroing freeFunc for empty-buffer DataSource\n")); freeFunc = NULL; } if (otherLen && otherLen < (uint32_t)length) { DBUG(("--- rejecting buffer len=%ld other=%ld\n", length, otherLen)); err = kNuErrPreSizeOverflow; goto bail; } err = Nu_DataSourceNew(ppDataSource); BailErrorQuiet(err); (*ppDataSource)->common.sourceType = kNuDataSourceFromBuffer; (*ppDataSource)->common.threadFormat = threadFormat; (*ppDataSource)->common.rawCrc = 0; (*ppDataSource)->common.dataLen = length; (*ppDataSource)->common.otherLen = otherLen; (*ppDataSource)->common.refCount = 1; (*ppDataSource)->fromBuffer.buffer = buffer; (*ppDataSource)->fromBuffer.offset = offset; (*ppDataSource)->fromBuffer.curOffset = offset; (*ppDataSource)->fromBuffer.curDataLen = length; (*ppDataSource)->fromBuffer.freeFunc = freeFunc; bail: return err; } /* * Get the type of a NuDataSource. */ NuDataSourceType Nu_DataSourceGetType(const NuDataSource* pDataSource) { Assert(pDataSource != NULL); return pDataSource->sourceType; } /* * Get the threadFormat for a data source. */ NuThreadFormat Nu_DataSourceGetThreadFormat(const NuDataSource* pDataSource) { Assert(pDataSource != NULL); return pDataSource->common.threadFormat; } /* * Get "dataLen" from a dataSource. */ uint32_t Nu_DataSourceGetDataLen(const NuDataSource* pDataSource) { Assert(pDataSource != NULL); if (pDataSource->sourceType == kNuDataSourceFromFile) { /* dataLen can only be valid if file has been opened */ Assert(pDataSource->fromFile.fp != NULL); } return pDataSource->common.dataLen; } /* * Get "otherLen" from a dataSource. */ uint32_t Nu_DataSourceGetOtherLen(const NuDataSource* pDataSource) { Assert(pDataSource != NULL); return pDataSource->common.otherLen; } /* * Change the "otherLen" value. */ void Nu_DataSourceSetOtherLen(NuDataSource* pDataSource, long otherLen) { Assert(pDataSource != NULL && otherLen > 0); pDataSource->common.otherLen = otherLen; } /* * Get the "raw CRC" value. */ uint16_t Nu_DataSourceGetRawCrc(const NuDataSource* pDataSource) { Assert(pDataSource != NULL); return pDataSource->common.rawCrc; } /* * Set the "raw CRC" value. You would want to do this if the input was * already-compressed data, and you wanted to propagate the thread CRC. */ void Nu_DataSourceSetRawCrc(NuDataSource* pDataSource, uint16_t crc) { Assert(pDataSource != NULL); pDataSource->common.rawCrc = crc; } /* * Prepare a data source for action. */ NuError Nu_DataSourcePrepareInput(NuArchive* pArchive, NuDataSource* pDataSource) { NuError err = kNuErrNone; FILE* fileFp = NULL; /* * Doesn't apply to buffer sources. */ if (Nu_DataSourceGetType(pDataSource) == kNuDataSourceFromBuffer) goto bail; /* * FP sources can be used several times, so we need to seek them * to the correct offset before we begin. */ if (Nu_DataSourceGetType(pDataSource) == kNuDataSourceFromFP) { err = Nu_FSeek(pDataSource->fromFP.fp, pDataSource->fromFP.offset, SEEK_SET); goto bail; /* return this err */ } /* * We're adding from a file on disk. Open it. */ err = Nu_OpenInputFile(pArchive, pDataSource->fromFile.pathnameUNI, pDataSource->fromFile.fromRsrcFork, &fileFp); BailError(err); Assert(fileFp != NULL); pDataSource->fromFile.fp = fileFp; err = Nu_GetFileLength(pArchive, fileFp, (long*)&pDataSource->common.dataLen); BailError(err); if (pDataSource->common.otherLen && pDataSource->common.otherLen < pDataSource->common.dataLen) { DBUG(("--- Uh oh, looks like file len is too small for presized\n")); } bail: return err; } /* * Un-prepare a data source. This really only affects "file" sources, and * is only here so we don't end up with 200+ FILE* structures hanging around. * If we don't do this, the first resource we're likely to run out of is * file descriptors. * * It's not necessary to do this in all error cases -- the DataSource "Free" * call will take care of this eventually -- but for normal operation on * a large number of files, it's vital. */ void Nu_DataSourceUnPrepareInput(NuArchive* pArchive, NuDataSource* pDataSource) { if (Nu_DataSourceGetType(pDataSource) != kNuDataSourceFromFile) return; if (pDataSource->fromFile.fp != NULL) { fclose(pDataSource->fromFile.fp); pDataSource->fromFile.fp = NULL; pDataSource->common.dataLen = 0; } } /* * Get the pathname from a "from-file" dataSource. Returned string is UTF-8. */ const char* Nu_DataSourceFile_GetPathname(NuDataSource* pDataSource) { Assert(pDataSource != NULL); Assert(pDataSource->sourceType == kNuDataSourceFromFile); Assert(pDataSource->fromFile.pathnameUNI != NULL); return pDataSource->fromFile.pathnameUNI; } /* * Read a block of data from a dataSource. */ NuError Nu_DataSourceGetBlock(NuDataSource* pDataSource, uint8_t* buf, uint32_t len) { NuError err; Assert(pDataSource != NULL); Assert(buf != NULL); Assert(len > 0); switch (pDataSource->sourceType) { case kNuDataSourceFromFile: Assert(pDataSource->fromFile.fp != NULL); err = Nu_FRead(pDataSource->fromFile.fp, buf, len); if (feof(pDataSource->fromFile.fp)) Nu_ReportError(NU_NILBLOB, err, "EOF hit unexpectedly"); return err; case kNuDataSourceFromFP: err = Nu_FRead(pDataSource->fromFP.fp, buf, len); if (feof(pDataSource->fromFP.fp)) Nu_ReportError(NU_NILBLOB, err, "EOF hit unexpectedly"); return err; case kNuDataSourceFromBuffer: if ((long)len > pDataSource->fromBuffer.curDataLen) { /* buffer underrun */ return kNuErrBufferUnderrun; } memcpy(buf, pDataSource->fromBuffer.buffer + pDataSource->fromBuffer.curOffset, len); pDataSource->fromBuffer.curOffset += len; pDataSource->fromBuffer.curDataLen -= len; return kNuErrNone; default: Assert(false); return kNuErrInternal; } } /* * Rewind a data source to the start of its input. */ NuError Nu_DataSourceRewind(NuDataSource* pDataSource) { NuError err; Assert(pDataSource != NULL); switch (pDataSource->sourceType) { case kNuDataSourceFromFile: Assert(pDataSource->fromFile.fp != NULL); err = Nu_FSeek(pDataSource->fromFile.fp, 0, SEEK_SET); break; /* fall through with error */ case kNuDataSourceFromFP: err = Nu_FSeek(pDataSource->fromFP.fp, pDataSource->fromFP.offset, SEEK_SET); break; /* fall through with error */ case kNuDataSourceFromBuffer: pDataSource->fromBuffer.curOffset = pDataSource->fromBuffer.offset; pDataSource->fromBuffer.curDataLen = pDataSource->common.dataLen; err = kNuErrNone; break; default: Assert(false); err = kNuErrInternal; } return err; } /* * =========================================================================== * NuDataSink * =========================================================================== */ /* * Allocate a new DataSink structure. */ static NuError Nu_DataSinkNew(NuDataSink** ppDataSink) { Assert(ppDataSink != NULL); *ppDataSink = Nu_Malloc(NULL, sizeof(**ppDataSink)); if (*ppDataSink == NULL) return kNuErrMalloc; (*ppDataSink)->sinkType = kNuDataSinkUnknown; return kNuErrNone; } /* * Free a data sink structure, and any type-specific elements. */ NuError Nu_DataSinkFree(NuDataSink* pDataSink) { if (pDataSink == NULL) return kNuErrNone; switch (pDataSink->sinkType) { case kNuDataSinkToFile: Nu_DataSinkFile_Close(pDataSink); Nu_Free(NULL, pDataSink->toFile.pathnameUNI); break; case kNuDataSinkToFP: break; case kNuDataSinkToBuffer: break; case kNuDataSinkToVoid: break; case kNuDataSinkUnknown: break; default: Assert(0); return kNuErrInternal; } Nu_Free(NULL, pDataSink); return kNuErrNone; } /* * Create a data sink for an unopened file. */ NuError Nu_DataSinkFile_New(Boolean doExpand, NuValue convertEOL, const UNICHAR* pathnameUNI, UNICHAR fssep, NuDataSink** ppDataSink) { NuError err; if ((doExpand != true && doExpand != false) || (convertEOL != kNuConvertOff && convertEOL != kNuConvertOn && convertEOL != kNuConvertAuto) || pathnameUNI == NULL || fssep == 0 || ppDataSink == NULL) { return kNuErrInvalidArg; } err = Nu_DataSinkNew(ppDataSink); BailErrorQuiet(err); (*ppDataSink)->common.sinkType = kNuDataSinkToFile; (*ppDataSink)->common.doExpand = doExpand; if (doExpand) (*ppDataSink)->common.convertEOL = convertEOL; else (*ppDataSink)->common.convertEOL = kNuConvertOff; (*ppDataSink)->common.outCount = 0; (*ppDataSink)->toFile.pathnameUNI = strdup(pathnameUNI); (*ppDataSink)->toFile.fssep = fssep; (*ppDataSink)->toFile.fp = NULL; bail: return err; } /* * Create a data sink based on a file pointer. */ NuError Nu_DataSinkFP_New(Boolean doExpand, NuValue convertEOL, FILE* fp, NuDataSink** ppDataSink) { NuError err; if ((doExpand != true && doExpand != false) || (convertEOL != kNuConvertOff && convertEOL != kNuConvertOn && convertEOL != kNuConvertAuto) || fp == NULL || ppDataSink == NULL) { return kNuErrInvalidArg; } err = Nu_DataSinkNew(ppDataSink); BailErrorQuiet(err); (*ppDataSink)->common.sinkType = kNuDataSinkToFP; (*ppDataSink)->common.doExpand = doExpand; if (doExpand) (*ppDataSink)->common.convertEOL = convertEOL; else (*ppDataSink)->common.convertEOL = kNuConvertOff; (*ppDataSink)->common.outCount = 0; (*ppDataSink)->toFP.fp = fp; bail: return err; } /* * Create a data sink for a buffer in memory. */ NuError Nu_DataSinkBuffer_New(Boolean doExpand, NuValue convertEOL, uint8_t* buffer, uint32_t bufLen, NuDataSink** ppDataSink) { NuError err; if ((doExpand != true && doExpand != false) || (convertEOL != kNuConvertOff && convertEOL != kNuConvertOn && convertEOL != kNuConvertAuto) || buffer == NULL || bufLen == 0 || ppDataSink == NULL) { return kNuErrInvalidArg; } err = Nu_DataSinkNew(ppDataSink); BailErrorQuiet(err); (*ppDataSink)->common.sinkType = kNuDataSinkToBuffer; (*ppDataSink)->common.doExpand = doExpand; if (doExpand) (*ppDataSink)->common.convertEOL = convertEOL; else (*ppDataSink)->common.convertEOL = kNuConvertOff; (*ppDataSink)->common.convertEOL = convertEOL; (*ppDataSink)->common.outCount = 0; (*ppDataSink)->toBuffer.buffer = buffer; (*ppDataSink)->toBuffer.bufLen = bufLen; (*ppDataSink)->toBuffer.stickyErr = kNuErrNone; bail: return err; } /* * Create a data sink that goes nowhere. */ NuError Nu_DataSinkVoid_New(Boolean doExpand, NuValue convertEOL, NuDataSink** ppDataSink) { NuError err; Assert(doExpand == true || doExpand == false); Assert(ppDataSink != NULL); err = Nu_DataSinkNew(ppDataSink); BailErrorQuiet(err); (*ppDataSink)->common.sinkType = kNuDataSinkToVoid; (*ppDataSink)->common.doExpand = doExpand; (*ppDataSink)->common.convertEOL = convertEOL; (*ppDataSink)->common.outCount = 0; bail: return err; } /* * Get the type of a NuDataSink. */ NuDataSinkType Nu_DataSinkGetType(const NuDataSink* pDataSink) { Assert(pDataSink != NULL); return pDataSink->sinkType; } /* * Return the "doExpand" parameter from any kind of sink. */ Boolean Nu_DataSinkGetDoExpand(const NuDataSink* pDataSink) { return pDataSink->common.doExpand; } /* * Return the "convertEOL" parameter from any kind of sink. */ NuValue Nu_DataSinkGetConvertEOL(const NuDataSink* pDataSink) { return pDataSink->common.convertEOL; } /* * Return the #of bytes written to the sink. */ uint32_t Nu_DataSinkGetOutCount(const NuDataSink* pDataSink) { return pDataSink->common.outCount; } /* * Get "pathname" from a to-file sink. Returned string is UTF-8. */ const char* Nu_DataSinkFile_GetPathname(const NuDataSink* pDataSink) { Assert(pDataSink != NULL); Assert(pDataSink->sinkType == kNuDataSinkToFile); return pDataSink->toFile.pathnameUNI; } /* * Get "fssep" from a to-file sink. */ UNICHAR Nu_DataSinkFile_GetFssep(const NuDataSink* pDataSink) { Assert(pDataSink != NULL); Assert(pDataSink->sinkType == kNuDataSinkToFile); return pDataSink->toFile.fssep; } /* * Get the "fp" for a file sink. */ FILE* Nu_DataSinkFile_GetFP(const NuDataSink* pDataSink) { Assert(pDataSink != NULL); Assert(pDataSink->sinkType == kNuDataSinkToFile); return pDataSink->toFile.fp; } /* * Set the "fp" for a file sink. */ void Nu_DataSinkFile_SetFP(NuDataSink* pDataSink, FILE* fp) { Assert(pDataSink != NULL); Assert(pDataSink->sinkType == kNuDataSinkToFile); pDataSink->toFile.fp = fp; } /* * Close a to-file sink. */ void Nu_DataSinkFile_Close(NuDataSink* pDataSink) { Assert(pDataSink != NULL); if (pDataSink->toFile.fp != NULL) { fclose(pDataSink->toFile.fp); pDataSink->toFile.fp = NULL; } } /* * Write a block of data to a DataSink. */ NuError Nu_DataSinkPutBlock(NuDataSink* pDataSink, const uint8_t* buf, uint32_t len) { NuError err; Assert(pDataSink != NULL); Assert(buf != NULL); Assert(len > 0); switch (pDataSink->sinkType) { case kNuDataSinkToFile: Assert(pDataSink->toFile.fp != NULL); err = Nu_FWrite(pDataSink->toFile.fp, buf, len); if (err != kNuErrNone) return err; break; case kNuDataSinkToFP: Assert(pDataSink->toFP.fp != NULL); err = Nu_FWrite(pDataSink->toFP.fp, buf, len); if (err != kNuErrNone) return err; break; case kNuDataSinkToBuffer: if (len > pDataSink->toBuffer.bufLen) { /* buffer overrun; set a "sticky" error, like FILE* does */ err = kNuErrBufferOverrun; pDataSink->toBuffer.stickyErr = err; return err; } memcpy(pDataSink->toBuffer.buffer, buf, len); pDataSink->toBuffer.buffer += len; pDataSink->toBuffer.bufLen -= len; break; case kNuDataSinkToVoid: /* do nothing */ break; default: Assert(false); return kNuErrInternal; } pDataSink->common.outCount += len; return kNuErrNone; } /* * Figure out if one of our earlier writes has failed. */ NuError Nu_DataSinkGetError(NuDataSink* pDataSink) { NuError err = kNuErrNone; Assert(pDataSink != NULL); switch (pDataSink->sinkType) { case kNuDataSinkToFile: if (ferror(pDataSink->toFile.fp)) err = kNuErrFileWrite; break; case kNuDataSinkToFP: if (ferror(pDataSink->toFP.fp)) err = kNuErrFileWrite; break; case kNuDataSinkToBuffer: err = pDataSink->toBuffer.stickyErr; break; case kNuDataSinkToVoid: /* do nothing */ break; default: Assert(false); err = kNuErrInternal; break; } return err; } nulib2-3.1.0/nufxlib/Squeeze.c000066400000000000000000001040421316100516500161410ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Huffman/RLE "squeeze" compression, based on SQ/USQ. This format is * listed in the NuFX documentation, but to my knowledge has never * actually been used (until now). Neither P8 ShrinkIt v3.4 nor II Unshrink * handle the format correctly, so this is really only useful as an * experiment. * * The algorithm appears to date back to the CP/M days. This implementation * is based on "xsq"/"xusq" v1.7u by Richard Greenlaw (from December 1982). * The code was also present in ARC v5.x. * * The "nusq.c" implementation found in NuLib was by Marcel J.E. Mol, * who got it from Don Elton's sq3/usq2 programs for the Apple II. * * The SQ file format begins with this: * +00 magic number (0xff76) * +02 checksum on uncompressed data * +04 filename, ending with \0 * The NuFX format skips the above, starting immediately after it: * +00 node count * +02 node value array [node count], two bytes each * +xx data immediately follows array * * NuFX drops the magic number, checksum, and filename from the header, * since (with v3 records) all three are redundant. You can enable this * if you want to experiment with SQ-compatible output. */ #include "NufxLibPriv.h" #ifdef ENABLE_SQ /* if this is defined, create and unpack the full SQ header (debugging only) */ /* #define FULL_SQ_HEADER */ #define kNuSQMagic 0xff76 /* magic value for file header */ #define kNuSQRLEDelim 0x90 /* RLE delimiter */ #define kNuSQEOFToken 256 /* distinguished stop symbol */ #define kNuSQNumVals 257 /* 256 symbols + stop */ /* * =========================================================================== * Compression * =========================================================================== */ #define kNuSQNoChild (-1) /* indicates end of path through tree */ #define kNuSQNumNodes (kNuSQNumVals + kNuSQNumVals -1) #define kNuSQMaxCount 65535 /* max value you can store in 16 bits */ /* states for the RLE encoding */ typedef enum { kNuSQRLEStateUnknown = 0, kNuSQRLEStateNoHist, /* nothing yet */ kNuSQRLEStateSentChar, /* lastchar set, no lookahead yet */ kNuSQRLEStateSendNewC, /* found run of two, send 2nd w/o DLE */ kNuSQRLEStateSendCnt, /* newchar set, DLE sent, send count next */ } NuSQRLEState; /* nodes in the Huffman encoding tree */ typedef struct EncTreeNode { int weight; /* #of appearances */ int tdepth; /* length on longest path in tree */ int lchild, rchild; /* indexes to next level */ } EncTreeNode; /* * State during compression. */ typedef struct SQState { NuArchive* pArchive; int doCalcCRC; /* boolean; if set, compute CRC on input */ uint16_t crc; NuStraw* pStraw; long uncompRemaining; #ifdef FULL_SQ_HEADER uint16_t checksum; #endif /* * RLE state stuff. */ NuSQRLEState rleState; int lastSym; int likeCount; /* * Huffman state stuff. */ EncTreeNode node[kNuSQNumNodes]; int treeHead; /* index to head node of final tree */ /* encoding table */ int codeLen[kNuSQNumVals]; /* number of bits in code for symbol N */ uint16_t code[kNuSQNumVals]; /* bits for symbol N (first bit in lsb) */ uint16_t tmpCode; /* temporary code value */ } SQState; /* * Get the next byte from the input straw. Also updates the checksum * and SQ CRC, if "doCalcCRC" is set to true. * * This isn't exactly fast, but then this isn't exactly a fast algorithm, * and there's not much point in optimizing something that isn't going * to get used much. * * Returns kNuSQEOFToken as the value when we're out of data. */ static NuError Nu_SQGetcCRC(SQState* pSqState, int* pSym) { NuError err; uint8_t c; if (!pSqState->uncompRemaining) { *pSym = kNuSQEOFToken; return kNuErrNone; } err = Nu_StrawRead(pSqState->pArchive, pSqState->pStraw, &c, 1); if (err == kNuErrNone) { if (pSqState->doCalcCRC) { #ifdef FULL_SQ_HEADER pSqState->checksum += c; #endif pSqState->crc = Nu_CalcCRC16(pSqState->crc, &c, 1); } *pSym = c; pSqState->uncompRemaining--; } return err; } /* * Get the next byte from the post-RLE input stream. * * Returns kNuSQEOFToken in "*pSum" when we reach the end of the input. */ static NuError Nu_SQGetcRLE(SQState* pSqState, int* pSym) { NuError err = kNuErrNone; int likeCount, newSym; switch (pSqState->rleState) { case kNuSQRLEStateNoHist: /* No relevant history */ pSqState->rleState = kNuSQRLEStateSentChar; err = Nu_SQGetcCRC(pSqState, pSym); pSqState->lastSym = *pSym; break; case kNuSQRLEStateSentChar: /* lastChar is set, need lookahead */ switch (pSqState->lastSym) { case kNuSQRLEDelim: /* send all DLEs escaped; note this is horrible for a run of DLEs */ pSqState->rleState = kNuSQRLEStateNoHist; *pSym = 0; /* zero len is how we define an escaped DLE */ break; case kNuSQEOFToken: *pSym = kNuSQEOFToken; break; default: /* * Try for a run, using the character we previous read as * the base. Thus, if the next character we read matches, * we have a run of two. The count describes the total * length of the run, including the character we've already * emitted. */ likeCount = 0; do { likeCount++; err = Nu_SQGetcCRC(pSqState, &newSym); if (err != kNuErrNone) goto bail; } while (newSym == pSqState->lastSym && likeCount < 255); switch (likeCount) { case 1: /* not a run, return first one we got */ pSqState->lastSym = newSym; *pSym = newSym; break; case 2: /* not long enough for run; return second one next time thru */ pSqState->rleState = kNuSQRLEStateSendNewC; *pSym = pSqState->lastSym; /* 1st new one */ pSqState->lastSym = newSym; /* 2nd new one */ break; default: pSqState->rleState = kNuSQRLEStateSendCnt; pSqState->likeCount = likeCount; pSqState->lastSym = newSym; /* 1st one after the run */ *pSym = kNuSQRLEDelim; break; } } break; case kNuSQRLEStateSendNewC: /* send first char past a run of two */ pSqState->rleState = kNuSQRLEStateSentChar; *pSym = pSqState->lastSym; break; case kNuSQRLEStateSendCnt: /* Sent DLE for repeat sequence, send count */ pSqState->rleState = kNuSQRLEStateSendNewC; *pSym = pSqState->likeCount; break; default: { NuArchive* pArchive = pSqState->pArchive; err = kNuErrInternal; Nu_ReportError(NU_BLOB, err, "invalid state %d in SQ RLE encode", pSqState->rleState); break; } } bail: return err; } /* * Comment from xsq.c: * * This translation uses the Huffman algorithm to develop a * binary tree representing the decoding information for * a variable length bit string code for each input value. * Each string's length is in inverse proportion to its * frequency of appearance in the incoming data stream. * The encoding table is derived from the decoding table. * * The range of valid values into the Huffman algorithm are * the values of a byte stored in an integer plus the special * endfile value chosen to be an adjacent value. Overall, 0-SPEOF. * * The "node" array of structures contains the nodes of the * binary tree. The first NUMVALS nodes are the leaves of the * tree and represent the values of the data bytes being * encoded and the special endfile, SPEOF. * The remaining nodes become the internal nodes of the tree. * * In the original design it was believed that * a Huffman code would fit in the same number of * bits that will hold the sum of all the counts. * That was disproven by a user's file and was a rare but * infamous bug. This version attempts to choose among equally * weighted subtrees according to their maximum depths to avoid * unnecessarily long codes. In case that is not sufficient * to guarantee codes <= 16 bits long, we initially scale * the counts so the total fits in an unsigned integer, but * if codes longer than 16 bits are generated the counts are * rescaled to a lower ceiling and code generation is retried. */ /* * Return the greater of two integers. */ static int Nu_SQMax(int a, int b) { if (a > b) return a; else return b; } /* * Compare two trees, if a > b return true, else return false. * Priority is given to weight, then depth. "a" and "b" are heaps, * so we only need to look at the root element. */ static int Nu_SQCmpTrees(SQState* pSqState, int a, int b) { if (pSqState->node[a].weight > pSqState->node[b].weight) return true; if (pSqState->node[a].weight == pSqState->node[b].weight) if (pSqState->node[a].tdepth > pSqState->node[b].tdepth) return true; return false; } /* * heap() and adjust() maintain a list of binary trees as a * heap with the top indexing the binary tree on the list * which has the least weight or, in case of equal weights, * least depth in its longest path. The depth part is not * strictly necessary, but tends to avoid long codes which * might provoke rescaling. */ /* * Recursively make a heap from a heap with a new top. */ static void Nu_SQHeapAdjust(SQState* pSqState, int list[], int top, int bottom) { int k, temp; k = 2 * top + 1; /* left child of top */ temp = list[top]; /* remember root node of top tree */ if (k <= bottom) { if (k < bottom && Nu_SQCmpTrees(pSqState, list[k], list[k + 1])) k++; /* k indexes "smaller" child (in heap of trees) of top */ /* now make top index "smaller" of old top and smallest child */ if (Nu_SQCmpTrees(pSqState, temp, list[k])) { list[top] = list[k]; list[k] = temp; /* Make the changed list a heap */ Nu_SQHeapAdjust(pSqState, list, k, bottom); /*recursive*/ } } } /* * Create a heap. */ static void Nu_SQHeap(SQState* pSqState, int list[], int length) { int i; for (i = (length - 2) / 2; i >= 0; i--) Nu_SQHeapAdjust(pSqState, list, i, length - 1); } /* * Build the encoding tree. * * HUFFMAN ALGORITHM: develops the single element trees * into a single binary tree by forming subtrees rooted in * interior nodes having weights equal to the sum of weights of all * their descendents and having depth counts indicating the * depth of their longest paths. * * When all trees have been formed into a single tree satisfying * the heap property (on weight, with depth as a tie breaker) * then the binary code assigned to a leaf (value to be encoded) * is then the series of left (0) and right (1) * paths leading from the root to the leaf. * Note that trees are removed from the heaped list by * moving the last element over the top element and * reheaping the shorter list. */ static void Nu_SQBuildTree(SQState* pSqState, int list[], int len) { int freenode; /* next free node in tree */ EncTreeNode* frnp; /* free node pointer */ int lch, rch; /* temporaries for left, right children */ /* * Initialize index to next available (non-leaf) node. * Lower numbered nodes correspond to leaves (data values). */ freenode = kNuSQNumVals; while (len > 1) { /* * Take from list two btrees with least weight * and build an interior node pointing to them. * This forms a new tree. */ lch = list[0]; /* This one will be left child */ /* delete top (least) tree from the list of trees */ list[0] = list[--len]; Nu_SQHeapAdjust(pSqState, list, 0, len - 1); /* Take new top (least) tree. Reuse list slot later */ rch = list[0]; /* This one will be right child */ /* * Form new tree from the two least trees using * a free node as root. Put the new tree in the list. */ frnp = &pSqState->node[freenode]; /* address of next free node */ list[0] = freenode++; /* put at top for now */ frnp->lchild = lch; frnp->rchild = rch; frnp->weight = pSqState->node[lch].weight + pSqState->node[rch].weight; frnp->tdepth = 1 + Nu_SQMax(pSqState->node[lch].tdepth, pSqState->node[rch].tdepth); /* reheap list to get least tree at top*/ Nu_SQHeapAdjust(pSqState, list, 0, len - 1); } pSqState->treeHead = list[0]; /* head of final tree */ } /* * Recursive routine to walk the indicated subtree and level * and maintain the current path code in bstree. When a leaf * is found the entire code string and length are put into * the encoding table entry for the leaf's data value . * * Returns zero on success, nonzero if codes are too long. */ static int Nu_SQBuildEncTable(SQState* pSqState, int level, int root) { int l, r; l = pSqState->node[root].lchild; r = pSqState->node[root].rchild; if (l == kNuSQNoChild && r == kNuSQNoChild) { /* Leaf. Previous path determines bit string * code of length level (bits 0 to level - 1). * Ensures unused code bits are zero. */ pSqState->codeLen[root] = level; pSqState->code[root] = pSqState->tmpCode & (((uint16_t)~0) >> (16 - level)); return (level > 16) ? -1 : 0; } else { if (l != kNuSQNoChild) { /* Clear path bit and continue deeper */ pSqState->tmpCode &= ~(1 << level); /* NOTE RECURSION */ if (Nu_SQBuildEncTable(pSqState, level + 1, l) != 0) return -1; } if (r != kNuSQNoChild) { /* Set path bit and continue deeper */ pSqState->tmpCode |= 1 << level; /* NOTE RECURSION */ if (Nu_SQBuildEncTable(pSqState, level + 1, r) != 0) return -1; } } return 0; /* if we got here we're ok so far */ } /* * The count of number of occurrances of each input value * have already been prevented from exceeding MAXCOUNT. * Now we must scale them so that their sum doesn't exceed * ceiling and yet no non-zero count can become zero. * This scaling prevents errors in the weights of the * interior nodes of the Huffman tree and also ensures that * the codes will fit in an unsigned integer. Rescaling is * used if necessary to limit the code length. */ static void Nu_SQScale(SQState* pSqState, int ceiling) { int i; int wt, ovflw, divisor; uint16_t sum; int increased; /* flag */ do { for (i = sum = ovflw = 0; i < kNuSQNumVals; i++) { if (pSqState->node[i].weight > (ceiling - sum)) ovflw++; sum += pSqState->node[i].weight; } divisor = ovflw + 1; /* use the high 16 bits of the sum */ /* Ensure no non-zero values are lost */ increased = false; for (i = 0; i < kNuSQNumVals; i++) { wt = pSqState->node[i].weight; if (wt < divisor && wt != 0) { /* Don't fail to provide a code if it's used at all */ pSqState->node[i].weight = divisor; increased = true; } } } while(increased); /* scaling factor choosen and minimums are set; now do the downscale */ if (divisor > 1) { for (i = 0; i < kNuSQNumVals; i++) pSqState->node[i].weight /= divisor; } } /* * Build a frequency table from the post-RLE input stream, then generate * an encoding tree from the results. */ static NuError Nu_SQComputeHuffTree(SQState* pSqState) { NuError err = kNuErrNone; int btreeList[kNuSQNumVals]; /* list of intermediate binary trees */ int listLen; /* length of btreeList */ int ceiling; /* limit for scaling */ int i, sym, result; /* init tree */ for (i = 0; i < kNuSQNumNodes; i++) { pSqState->node[i].weight = 0; pSqState->node[i].tdepth = 0; pSqState->node[i].lchild = kNuSQNoChild; pSqState->node[i].rchild = kNuSQNoChild; } DBUG(("+++ SQ scanning...\n")); do { int* pWeight; err = Nu_SQGetcRLE(pSqState, &sym); if (err != kNuErrNone) goto bail; Assert(sym >= 0 && sym <= kNuSQEOFToken); pWeight = &pSqState->node[(unsigned)sym].weight; if (*pWeight != kNuSQMaxCount) (*pWeight)++; } while (sym != kNuSQEOFToken); DBUG(("+++ SQ generating tree...\n")); ceiling = kNuSQMaxCount; do { if (ceiling != kNuSQMaxCount) { DBUG(("+++ SQ rescaling\n")); } /* pick a divisor and scale everything to fit in "ceiling" */ Nu_SQScale(pSqState, ceiling); ceiling /= 2; /* in case we need to rescale */ /* * Build list of single node binary trees having * leaves for the input values with non-zero counts */ for (i = listLen = 0; i < kNuSQNumVals; i++) { if (pSqState->node[i].weight != 0) { pSqState->node[i].tdepth = 0; btreeList[listLen++] = i; } } /* * Arrange list of trees into a heap with the entry * indexing the node with the least weight a the top. */ Nu_SQHeap(pSqState, btreeList, listLen); /* convert the list of trees to a single decoding tree */ Nu_SQBuildTree(pSqState, btreeList, listLen); /* initialize encoding table */ for (i = 0; i < kNuSQNumVals; i++) pSqState->codeLen[i] = 0; /* * Recursively build the encoding table; returns non-zero (failure) * if any code is > 16 bits long. */ result = Nu_SQBuildEncTable(pSqState, 0, pSqState->treeHead); } while (result != 0); #if 0 { int jj; printf("init_huff\n"); for (jj = 0; jj < kNuSQNumNodes; jj++) { printf("NODE %d: w=%d d=%d l=%d r=%d\n", jj, pSqState->node[jj].weight, pSqState->node[jj].tdepth, pSqState->node[jj].lchild, pSqState->node[jj].rchild); } } #endif bail: return err; } /* * Compress data from input to output, using the values in the "code" * and "codeLen" arrays. */ static NuError Nu_SQCompressInput(SQState* pSqState, FILE* fp, long* pCompressedLen) { NuError err = kNuErrNone; int sym = kNuSQEOFToken-1; uint32_t bits, code; /* must hold at least 23 bits */ int codeLen, gotbits; long compressedLen; DBUG(("+++ SQ compressing\n")); Assert(sizeof(bits) >= 4); compressedLen = *pCompressedLen; bits = 0; gotbits = 0; while (sym != kNuSQEOFToken) { err = Nu_SQGetcRLE(pSqState, &sym); if (err != kNuErrNone) goto bail; code = pSqState->code[sym]; codeLen = pSqState->codeLen[sym]; bits |= code << gotbits; gotbits += codeLen; /* if we have more than a byte, output it */ while (gotbits > 7) { putc(bits & 0xff, fp); compressedLen++; bits >>= 8; gotbits -= 8; } } if (gotbits) { Assert(gotbits < 8); putc(bits & 0xff, fp); compressedLen++; } bail: *pCompressedLen = compressedLen; return err; } /* * Write a 16-bit value in little-endian order. */ static NuError Nu_SQWriteShort(FILE* outfp, short val) { NuError err; uint8_t tmpc; tmpc = val & 0xff; err = Nu_FWrite(outfp, &tmpc, 1); if (err != kNuErrNone) goto bail; tmpc = (val >> 8) & 0xff; err = Nu_FWrite(outfp, &tmpc, 1); if (err != kNuErrNone) goto bail; bail: return err; } /* * Compress "srcLen" bytes into SQ format, from "pStraw" to "fp". * * This requires two passes through the input. * * Bit of trivia: "sq3" on the Apple II self-destructs if you hand * it an empty file. "xsq" works fine, creating an empty tree that * "xusq" unpacks. */ NuError Nu_CompressHuffmanSQ(NuArchive* pArchive, NuStraw* pStraw, FILE* fp, uint32_t srcLen, uint32_t* pDstLen, uint16_t* pCrc) { NuError err = kNuErrNone; SQState sqState; long compressedLen; int i, j, numNodes; err = Nu_AllocCompressionBufferIFN(pArchive); if (err != kNuErrNone) return err; sqState.pArchive = pArchive; sqState.crc = 0; if (pCrc == NULL) { sqState.doCalcCRC = false; } else { sqState.doCalcCRC = true; sqState.crc = *pCrc; } #ifdef FULL_SQ_HEADER sqState.checksum = 0; #endif /* * Pass 1: analysis. Perform a frequency analysis on the post-RLE * input file. This will calculate the file CRCs as a side effect. */ sqState.rleState = kNuSQRLEStateNoHist; sqState.uncompRemaining = srcLen; sqState.pStraw = pStraw; (void) Nu_StrawSetProgressState(pStraw, kNuProgressAnalyzing); err = Nu_SQComputeHuffTree(&sqState); BailError(err); if (pCrc != NULL) *pCrc = sqState.crc; /* * Pass 2: compression. Using the encoding tree we computed, * compress the input with RLE and Huffman. Start by writing * the file header and rewinding the input file. */ sqState.doCalcCRC = false; /* don't need to re-compute */ sqState.rleState = kNuSQRLEStateNoHist; /* reset */ compressedLen = 0; /* rewind for next pass */ (void) Nu_StrawSetProgressState(pStraw, kNuProgressCompressing); err = Nu_StrawRewind(pArchive, pStraw); BailError(err); sqState.uncompRemaining = srcLen; #ifdef FULL_SQ_HEADER /* write file header */ err = Nu_SQWriteShort(fp, kNuSQMagic); BailError(err); compressedLen += 2; err = Nu_SQWriteShort(fp, sqState.checksum); BailError(err); compressedLen += 2; { static const char fakename[] = "s.qqq"; err = Nu_FWrite(fp, fakename, sizeof(fakename)); BailError(err); compressedLen += sizeof(fakename); } #endif /* * Original description: * Write out a simplified decoding tree. Only the interior * nodes are written. When a child is a leaf index * (representing a data value) it is recoded as * -(index + 1) to distinguish it from interior indexes * which are recoded as positive indexes in the new tree. * Note that this tree will be empty for an empty file. */ if (sqState.treeHead < kNuSQNumVals) numNodes = 0; else numNodes = sqState.treeHead - (kNuSQNumVals - 1); err = Nu_SQWriteShort(fp, (short) numNodes); BailError(err); compressedLen += 2; for (i = sqState.treeHead, j = 0; j < numNodes; j++, i--) { int l, r; l = sqState.node[i].lchild; r = sqState.node[i].rchild; l = l < kNuSQNumVals ? -(l + 1) : sqState.treeHead - l; r = r < kNuSQNumVals ? -(r + 1) : sqState.treeHead - r; err = Nu_SQWriteShort(fp, (short) l); BailError(err); err = Nu_SQWriteShort(fp, (short) r); BailError(err); compressedLen += 4; /*DBUG(("TREE %d: %d %d\n", j, l, r));*/ } /* * Convert the input to RLE/Huffman. */ err = Nu_SQCompressInput(&sqState, fp, &compressedLen); BailError(err); /* * Done! */ *pDstLen = compressedLen; bail: return err; } /* * =========================================================================== * Expansion * =========================================================================== */ /* * State during uncompression. */ typedef struct USQState { uint32_t dataInBuffer; uint8_t* dataPtr; int bitPosn; int bits; /* * Decoding tree; first "nodeCount" values are populated. Positive * values are indicies to another node in the tree, negative values * are literals (+1 because "negative zero" doesn't work well). */ int nodeCount; struct { short child[2]; /* left/right kids, must be signed 16-bit */ } decTree[kNuSQNumVals-1]; } USQState; /* * Decode the next symbol from the Huffman stream. */ static NuError Nu_USQDecodeHuffSymbol(USQState* pUsqState, int* pVal) { short val = 0; int bits, bitPosn; bits = pUsqState->bits; /* local copy */ bitPosn = pUsqState->bitPosn; do { if (++bitPosn > 7) { /* grab the next byte and use that */ bits = *pUsqState->dataPtr++; bitPosn = 0; if (!pUsqState->dataInBuffer--) return kNuErrBufferUnderrun; val = pUsqState->decTree[val].child[1 & bits]; } else { /* still got bits; shift right and use it */ val = pUsqState->decTree[val].child[1 & (bits >>= 1)]; } } while (val >= 0); /* val is negative literal; add one to make it zero-based then negate it */ *pVal = -(val + 1); pUsqState->bits = bits; pUsqState->bitPosn = bitPosn; return kNuErrNone; } /* * Read two bytes of signed data out of the buffer. */ static inline NuError Nu_USQReadShort(USQState* pUsqState, short* pShort) { if (pUsqState->dataInBuffer < 2) return kNuErrBufferUnderrun; *pShort = *pUsqState->dataPtr++; *pShort |= (*pUsqState->dataPtr++) << 8; pUsqState->dataInBuffer -= 2; return kNuErrNone; } /* * Expand "SQ" format. * * Because we have a stop symbol, knowing the uncompressed length of * the file is not essential. */ NuError Nu_ExpandHuffmanSQ(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, uint16_t* pCrc) { NuError err = kNuErrNone; USQState usqState; uint32_t compRemaining, getSize; #ifdef FULL_SQ_HEADER uint16_t magic, fileChecksum, checksum; #endif short nodeCount; int i, inrep; uint8_t lastc = 0; err = Nu_AllocCompressionBufferIFN(pArchive); if (err != kNuErrNone) return err; Assert(pArchive->compBuf != NULL); usqState.dataInBuffer = 0; usqState.dataPtr = pArchive->compBuf; usqState.bits = usqState.bitPosn = 0; compRemaining = pThread->thCompThreadEOF; #ifdef FULL_SQ_HEADER if (compRemaining < 8) #else if (compRemaining < 3) #endif { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "thread too short to be valid SQ data"); goto bail; } getSize = compRemaining; if (getSize > kNuGenCompBufSize) getSize = kNuGenCompBufSize; /* * Grab a big chunk. "compRemaining" is the amount of compressed * data left in the file, usqState.dataInBuffer is the amount of * compressed data left in the buffer. */ err = Nu_FRead(infp, usqState.dataPtr, getSize); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "failed reading compressed data (%u bytes)", getSize); goto bail; } usqState.dataInBuffer += getSize; compRemaining -= getSize; /* * Read the header. We assume that the header is less than * kNuGenCompBufSize bytes, which is pretty fair since the buffer is * currently 20x larger than the longest possible header (sq allowed * 300+ for the filename, plus 257*2 for the tree, plus misc). */ Assert(kNuGenCompBufSize > 1200); #ifdef FULL_SQ_HEADER err = Nu_USQReadShort(&usqState, &magic); BailError(err); if (magic != kNuSQMagic) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "bad magic number in SQ block"); goto bail; } err = Nu_USQReadShort(&usqState, &fileChecksum); BailError(err); checksum = 0; while (*usqState.dataPtr++ != '\0') usqState.dataInBuffer--; usqState.dataInBuffer--; #endif err = Nu_USQReadShort(&usqState, &nodeCount); BailError(err); if (nodeCount < 0 || nodeCount >= kNuSQNumVals) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "invalid decode tree in SQ (%d nodes)", nodeCount); goto bail; } usqState.nodeCount = nodeCount; /* initialize for possibly empty tree (only happens on an empty file) */ usqState.decTree[0].child[0] = -(kNuSQEOFToken+1); usqState.decTree[0].child[1] = -(kNuSQEOFToken+1); /* read the nodes, ignoring "read errors" until we're done */ for (i = 0; i < nodeCount; i++) { err = Nu_USQReadShort(&usqState, &usqState.decTree[i].child[0]); err = Nu_USQReadShort(&usqState, &usqState.decTree[i].child[1]); } if (err != kNuErrNone) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "SQ data looks truncated at tree"); goto bail; } usqState.bitPosn = 99; /* force an immediate read */ /* * Start pulling data out of the file. We have to Huffman-decode * the input, and then feed that into an RLE expander. * * A completely lopsided (and broken) Huffman tree could require * 256 tree descents, so we want to try to ensure we have at least 256 * bits in the buffer. Otherwise, we could get a false buffer underrun * indication back from DecodeHuffSymbol. * * The SQ sources actually guarantee that a code will fit entirely * in 16 bits, but there's no reason not to use the larger value. */ inrep = false; while (1) { int val; if (usqState.dataInBuffer < 65 && compRemaining) { /* * Less than 256 bits, but there's more in the file. * * First thing we do is slide the old data to the start of * the buffer. */ if (usqState.dataInBuffer) { Assert(pArchive->compBuf != usqState.dataPtr); memmove(pArchive->compBuf, usqState.dataPtr, usqState.dataInBuffer); } usqState.dataPtr = pArchive->compBuf; /* * Next we read as much as we can. */ if (kNuGenCompBufSize - usqState.dataInBuffer < compRemaining) getSize = kNuGenCompBufSize - usqState.dataInBuffer; else getSize = compRemaining; err = Nu_FRead(infp, usqState.dataPtr + usqState.dataInBuffer, getSize); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "failed reading compressed data (%u bytes)", getSize); goto bail; } usqState.dataInBuffer += getSize; compRemaining -= getSize; Assert(compRemaining < 32767*65536); Assert(usqState.dataInBuffer <= kNuGenCompBufSize); } err = Nu_USQDecodeHuffSymbol(&usqState, &val); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "failed decoding huff symbol"); goto bail; } if (val == kNuSQEOFToken) break; /* * Feed the symbol into the RLE decoder. */ if (inrep) { /* * Last char was RLE delim, handle this specially. We use * --val instead of val-- because we already emitted the * first occurrence of the char (right before the RLE delim). */ if (val == 0) { /* special case -- just an escaped RLE delim */ lastc = kNuSQRLEDelim; val = 2; } while (--val) { if (pCrc != NULL) *pCrc = Nu_CalcCRC16(*pCrc, &lastc, 1); err = Nu_FunnelWrite(pArchive, pFunnel, &lastc, 1); #ifdef FULL_SQ_HEADER checksum += lastc; #endif } inrep = false; } else { /* last char was ordinary */ if (val == kNuSQRLEDelim) { /* set a flag and catch the count the next time around */ inrep = true; } else { lastc = val; if (pCrc != NULL) *pCrc = Nu_CalcCRC16(*pCrc, &lastc, 1); err = Nu_FunnelWrite(pArchive, pFunnel, &lastc, 1); #ifdef FULL_SQ_HEADER checksum += lastc; #endif } } } if (inrep) { err = kNuErrBadData; Nu_ReportError(NU_BLOB, err, "got stop symbol when run length expected"); goto bail; } #ifdef FULL_SQ_HEADER /* verify the checksum stored in the SQ file */ if (checksum != fileChecksum && !pArchive->valIgnoreCRC) { if (!Nu_ShouldIgnoreBadCRC(pArchive, pRecord, kNuErrBadDataCRC)) { err = kNuErrBadDataCRC; Nu_ReportError(NU_BLOB, err, "expected 0x%04x, got 0x%04x (SQ)", fileChecksum, checksum); (void) Nu_FunnelFlush(pArchive, pFunnel); goto bail; } } else { DBUG(("--- SQ checksums match (0x%04x)\n", checksum)); } #endif /* * SQ2 adds an extra 0xff to the end, xsq doesn't. In any event, it * appears that having an extra byte at the end is okay. */ if (usqState.dataInBuffer > 1) { DBUG(("--- Found %ld bytes following compressed data (compRem=%ld)\n", usqState.dataInBuffer, compRemaining)); Nu_ReportError(NU_BLOB, kNuErrNone, "(Warning) unexpected fluff (%u)", usqState.dataInBuffer); } bail: return err; } #endif /*ENABLE_SQ*/ nulib2-3.1.0/nufxlib/SysDefs.h000066400000000000000000000057231316100516500161130ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * External type definitions and function prototypes. */ #ifndef NUFXLIB_SYSDEFS_H #define NUFXLIB_SYSDEFS_H #ifdef HAVE_CONFIG_H # include #endif #ifdef DEBUG_VERBOSE # define DEBUG_MSGS #endif /* these should exist everywhere */ #include #include #include #include #include #include /* basic Win32 stuff -- info-zip has much more complete defs */ #if defined(_WIN32) || defined(MSDOS) # define WINDOWS_LIKE # ifndef HAVE_CONFIG_H # define HAVE_FCNTL_H # define HAVE_MALLOC_H # define HAVE_STDLIB_H # define HAVE_SYS_STAT_H # undef HAVE_SYS_TIME_H # define HAVE_SYS_TYPES_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # define HAVE_SYS_UTIME_H # define HAVE_WINDOWS_H # define HAVE_FDOPEN # undef HAVE_FTRUNCATE # define HAVE_MEMMOVE # undef HAVE_MKSTEMP # define HAVE_MKTIME # define HAVE_SNPRINTF # undef HAVE_STRCASECMP # undef HAVE_STRNCASECMP # define HAVE_STRERROR # define HAVE_STRTOUL # define HAVE_VSNPRINTF # define SNPRINTF_DECLARED # define VSNPRINTF_DECLARED # define SPRINTF_RETURNS_INT # define inline /*Visual C++6.0 can't inline ".c" files*/ # define mode_t int # define ENABLE_SQ # define ENABLE_LZW # define ENABLE_LZC /*# define ENABLE_DEFLATE*/ /*# define ENABLE_BZIP2*/ # endif # include # include # define FOPEN_WANTS_B # define HAVE_CHSIZE # if _MSC_VER < 1900 /* no snprintf until Visual Studio 2015 */ # define snprintf _snprintf # define vsnprintf _vsnprintf # endif #endif #ifdef HAVE_MALLOC_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_UTIME_H # include #endif #ifdef HAVE_SYS_UTIME_H # include #endif #if defined(WINDOWS_LIKE) # ifndef F_OK # define F_OK 0 /* was 02 in <= v1.1.0 */ # endif #endif #if defined(__APPLE__) && defined(__MACH__) /* OS X */ # define MAC_LIKE # define UNIX_LIKE #endif #if defined(__unix__) || defined(__unix) || defined(__BEOS__) || \ defined(__hpux) || defined(_AIX) # define UNIX_LIKE /* standardize */ #endif #if defined(UNIX_LIKE) # ifdef USE_REENTRANT_CALLS # define _REENTRANT /* Solaris 2.x convention */ # endif #endif /* not currently using filesystem resource forks */ //#if defined(__ORCAC__) || defined(MAC_LIKE) //# define HAS_RESOURCE_FORKS //#endif /* __FUNCTION__ was missing from BeOS __MWERKS__, and might be gcc-only */ #ifdef __GNUC__ # define HAS__FUNCTION__ #endif #if defined(__linux__) # define HAS_MALLOC_CHECK_ #endif #endif /*NUFXLIB_SYSDEFS_H*/ nulib2-3.1.0/nufxlib/Thread.c000066400000000000000000001302361316100516500157330ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Thread-level operations. */ #include "NufxLibPriv.h" /* * =========================================================================== * Utils * =========================================================================== */ /* * Returns thread N, or NULL if the index is invalid. */ NuThread* Nu_GetThread(const NuRecord* pRecord, int idx) { if (idx >= (int)pRecord->recTotalThreads) return NULL; else return &pRecord->pThreads[idx]; } /* * ShrinkIt v3.0.0 had a bug where the filename thread would get created * with the high bits set. We want to undo that without stomping on * filenames that just happen to have a fancy character in them. If all * of the high bits are set, assume it's a "defective" name and clear * them all. If some aren't set, assume it's just a fancy filename. * * This high-bit-ism was also done for disk archives by most older versions * of ShrinkIt. */ void Nu_StripHiIfAllSet(char* str) { uint8_t* cp; for (cp = (uint8_t*)str; *cp != '\0'; cp++) if (!(*cp & 0x80)) return; for (cp = (uint8_t*)str; *cp != '\0'; cp++) *cp &= 0x7f; } /* * Decide if a thread is pre-sized (i.e. has a fixed maximum size with a * lesser amount of uncompressed data within) based on the threadID. */ Boolean Nu_IsPresizedThreadID(NuThreadID threadID) { if (threadID == kNuThreadIDFilename || threadID == kNuThreadIDComment) return true; else return false; } /* * Return an indication of whether the type of thread specified by ThreadID * should ever be compressed. Right now, that's only data-class threads. */ Boolean Nu_IsCompressibleThreadID(NuThreadID threadID) { if (NuThreadIDGetClass(threadID) == kNuThreadClassData) return true; else return false; } /* * Decide if the thread has a CRC, based on the record version and the * threadID. */ Boolean Nu_ThreadHasCRC(uint16_t recordVersion, NuThreadID threadID) { return recordVersion >= 3 && NuThreadIDGetClass(threadID) == kNuThreadClassData; } /* * Search through a given NuRecord for the specified thread. */ NuError Nu_FindThreadByIdx(const NuRecord* pRecord, NuThreadIdx thread, NuThread** ppThread) { NuThread* pThread; int idx; for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); if (pThread->threadIdx == thread) { *ppThread = pThread; return kNuErrNone; } } return kNuErrThreadIdxNotFound; } /* * Search through a given NuRecord for the first thread with a matching * threadID. */ NuError Nu_FindThreadByID(const NuRecord* pRecord, NuThreadID threadID, NuThread** ppThread) { NuThread* pThread; int idx; for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); if (NuGetThreadID(pThread) == threadID) { *ppThread = pThread; return kNuErrNone; } } return kNuErrThreadIDNotFound; } /* * Copy the contents of a NuThread. */ void Nu_CopyThreadContents(NuThread* pDstThread, const NuThread* pSrcThread) { Assert(pDstThread != NULL); Assert(pSrcThread != NULL); memcpy(pDstThread, pSrcThread, sizeof(*pDstThread)); } /* * =========================================================================== * Reading threads from the archive * =========================================================================== */ /* * Read a single thread header from the archive. */ static NuError Nu_ReadThreadHeader(NuArchive* pArchive, NuThread* pThread, uint16_t* pCrc) { FILE* fp; Assert(pArchive != NULL); Assert(pThread != NULL); Assert(pCrc != NULL); fp = pArchive->archiveFp; pThread->thThreadClass = Nu_ReadTwoC(pArchive, fp, pCrc); pThread->thThreadFormat = Nu_ReadTwoC(pArchive, fp, pCrc); pThread->thThreadKind = Nu_ReadTwoC(pArchive, fp, pCrc); pThread->thThreadCRC = Nu_ReadTwoC(pArchive, fp, pCrc); pThread->thThreadEOF = Nu_ReadFourC(pArchive, fp, pCrc); pThread->thCompThreadEOF = Nu_ReadFourC(pArchive, fp, pCrc); pThread->threadIdx = Nu_GetNextThreadIdx(pArchive); pThread->actualThreadEOF = 0; /* fix me later */ pThread->fileOffset = -1; /* mark as invalid */ pThread->used = 0xcfcf; /* init to invalid value */ return Nu_HeaderIOFailed(pArchive, fp); } /* * Read the threads from the current archive file position. * * The storage for the threads is allocated here, in one block. We could * have used a linked list like NuLib, but that doesn't really provide any * benefit for us, and adds complexity. */ NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, uint16_t* pCrc) { NuError err = kNuErrNone; NuThread* pThread; long count; Boolean needFakeData, needFakeRsrc; needFakeData = true; needFakeRsrc = (pRecord->recStorageType == kNuStorageExtended); Assert(pArchive != NULL); Assert(pRecord != NULL); Assert(pCrc != NULL); if (!pRecord->recTotalThreads) { /* not sure if this is reasonable, but we can handle it */ DBUG(("--- WEIRD: no threads in the record?\n")); goto bail; } pRecord->pThreads = Nu_Malloc(pArchive, pRecord->recTotalThreads * sizeof(NuThread)); BailAlloc(pRecord->pThreads); count = pRecord->recTotalThreads; pThread = pRecord->pThreads; while (count--) { err = Nu_ReadThreadHeader(pArchive, pThread, pCrc); BailError(err); if (pThread->thThreadClass == kNuThreadClassData) { if (pThread->thThreadKind == kNuThreadKindDataFork) { needFakeData = false; } else if (pThread->thThreadKind == kNuThreadKindRsrcFork) { needFakeRsrc = false; } else if (pThread->thThreadKind == kNuThreadKindDiskImage) { /* needFakeRsrc shouldn't be set, but clear anyway */ needFakeData = needFakeRsrc = false; } } /* * Some versions of ShrinkIt write an invalid thThreadEOF for disks, * so we have to figure out what it's supposed to be. */ if (NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind) == kNuThreadIDDiskImage) { if (pRecord->recStorageType <= 13) { /* supposed to be block size, but SHK v3.0.1 stored it wrong */ pThread->actualThreadEOF = pRecord->recExtraType * 512; } else if (pRecord->recStorageType == 256 && pRecord->recExtraType == 280 && pRecord->recFileSysID == kNuFileSysDOS33) { /* * Fix for less-common ShrinkIt problem: looks like an old * version of GS/ShrinkIt used 256 as the block size when * compressing DOS 3.3 images from 5.25" disks. If that * appears to be the case here, crank up the block size. */ DBUG(("--- no such thing as a 70K disk image!\n")); pThread->actualThreadEOF = pRecord->recExtraType * 512; } else { pThread->actualThreadEOF = pRecord->recExtraType * pRecord->recStorageType; } } else { pThread->actualThreadEOF = pThread->thThreadEOF; } pThread->used = false; pThread++; } /* * If "mask threadless" is set, create "fake" threads with empty * data and resource forks as needed. */ if ((needFakeData || needFakeRsrc) && pArchive->valMaskDataless) { int firstNewThread = pRecord->recTotalThreads; if (needFakeData) { pRecord->recTotalThreads++; pRecord->fakeThreads++; } if (needFakeRsrc) { pRecord->recTotalThreads++; pRecord->fakeThreads++; } pRecord->pThreads = Nu_Realloc(pArchive, pRecord->pThreads, pRecord->recTotalThreads * sizeof(NuThread)); BailAlloc(pRecord->pThreads); pThread = pRecord->pThreads + firstNewThread; if (needFakeData) { pThread->thThreadClass = kNuThreadClassData; pThread->thThreadFormat = kNuThreadFormatUncompressed; pThread->thThreadKind = kNuThreadKindDataFork; pThread->thThreadCRC = kNuInitialThreadCRC; pThread->thThreadEOF = 0; pThread->thCompThreadEOF = 0; pThread->threadIdx = Nu_GetNextThreadIdx(pArchive); pThread->actualThreadEOF = 0; pThread->fileOffset = -99999999; pThread->used = false; pThread++; } if (needFakeRsrc) { pThread->thThreadClass = kNuThreadClassData; pThread->thThreadFormat = kNuThreadFormatUncompressed; pThread->thThreadKind = kNuThreadKindRsrcFork; pThread->thThreadCRC = kNuInitialThreadCRC; pThread->thThreadEOF = 0; pThread->thCompThreadEOF = 0; pThread->threadIdx = Nu_GetNextThreadIdx(pArchive); pThread->actualThreadEOF = 0; pThread->fileOffset = -99999999; pThread->used = false; } } bail: return err; } /* * Write a single thread header to the archive. */ static NuError Nu_WriteThreadHeader(NuArchive* pArchive, const NuThread* pThread, FILE* fp, uint16_t* pCrc) { Assert(pArchive != NULL); Assert(pThread != NULL); Assert(fp != NULL); Assert(pCrc != NULL); Nu_WriteTwoC(pArchive, fp, pThread->thThreadClass, pCrc); Nu_WriteTwoC(pArchive, fp, (uint16_t)pThread->thThreadFormat, pCrc); Nu_WriteTwoC(pArchive, fp, pThread->thThreadKind, pCrc); Nu_WriteTwoC(pArchive, fp, pThread->thThreadCRC, pCrc); Nu_WriteFourC(pArchive, fp, pThread->thThreadEOF, pCrc); Nu_WriteFourC(pArchive, fp, pThread->thCompThreadEOF, pCrc); return Nu_HeaderIOFailed(pArchive, fp); } /* * Write the thread headers for the record at the current file position. * * Note this doesn't care whether a thread was "fake" or not. In * effect, we promote all threads to "real" status. We update the * "fake" count in pRecord accordingly. */ NuError Nu_WriteThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, FILE* fp, uint16_t* pCrc) { NuError err = kNuErrNone; NuThread* pThread; int idx; for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); err = Nu_WriteThreadHeader(pArchive, pThread, fp, pCrc); BailError(err); } if (pRecord->fakeThreads != 0) { DBUG(("+++ promoting %ld fake threads to real\n",pRecord->fakeThreads)); pRecord->fakeThreads = 0; } bail: return err; } /* * Compute miscellaneous thread information, like total size and file * offsets. Some values (like file offsets) will not be useful for * streaming archives. * * Requires that the pArchive->currentOffset be set to the offset * immediately after the last of the thread headers. */ NuError Nu_ComputeThreadData(NuArchive* pArchive, NuRecord* pRecord) { NuThread* pThread; long fileOffset, count; Assert(pArchive != NULL); Assert(pRecord != NULL); /*pRecord->totalLength = 0;*/ pRecord->totalCompLength = 0; fileOffset = pArchive->currentOffset; count = pRecord->recTotalThreads; pThread = pRecord->pThreads; while (count--) { pThread->fileOffset = fileOffset; /*pRecord->totalLength += pThread->thThreadEOF;*/ pRecord->totalCompLength += pThread->thCompThreadEOF; fileOffset += pThread->thCompThreadEOF; pThread++; } return kNuErrNone; } /* * Skip past some or all of the thread data in the archive. For file * archives, we scan all the threads, but for streaming archives we only * want to scan up to the filename thread. (If the filename thread comes * after one of the data threads, we have a problem!) * * The tricky part here is that we don't want to skip over a filename * thread. We actually want to read it in, so that we have something to * show to the application. (Someday I'll get AndyN for putting me * through this...) */ NuError Nu_ScanThreads(NuArchive* pArchive, NuRecord* pRecord, long numThreads) { NuError err = kNuErrNone; NuThread* pThread; FILE* fp; Assert(pArchive != NULL); Assert(pRecord != NULL); fp = pArchive->archiveFp; Assert(numThreads <= (long)pRecord->recTotalThreads); pThread = pRecord->pThreads; while (numThreads--) { if (pRecord->threadFilenameMOR == NULL && NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind) == kNuThreadIDFilename) { /* it's the first filename thread, read the whole thing */ if (pThread->thCompThreadEOF > kNuReasonableFilenameLen) { err = kNuErrBadRecord; Nu_ReportError(NU_BLOB, err, "Bad thread filename len (%u)", pThread->thCompThreadEOF); goto bail; } pRecord->threadFilenameMOR = Nu_Malloc(pArchive, pThread->thCompThreadEOF +1); BailAlloc(pRecord->threadFilenameMOR); /* note there is no CRC on a filename thread */ (void) Nu_ReadBytes(pArchive, fp, pRecord->threadFilenameMOR, pThread->thCompThreadEOF); if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Failed reading filename thread"); goto bail; } /* null-terminate on the actual len, not the buffer len */ pRecord->threadFilenameMOR[pThread->thThreadEOF] = '\0'; Nu_StripHiIfAllSet(pRecord->threadFilenameMOR); /* prefer this one over the record one, but only one should exist */ if (pRecord->filenameMOR != NULL) { DBUG(("--- HEY: got record filename and thread filename\n")); } pRecord->filenameMOR = pRecord->threadFilenameMOR; } else { /* not a filename (or not first filename), skip past it */ err = Nu_SeekArchive(pArchive, pArchive->archiveFp, pThread->thCompThreadEOF, SEEK_CUR); BailError(err); } pThread++; } /* * Should've had one by now. Supposedly, older versions of ShrinkIt * wouldn't prompt for a disk image name on DOS 3.3 volumes, so you'd * end up with a disk image that had no name attached. This will tend * to confuse things, so we go ahead and give it a name. */ if (pRecord->filenameMOR == NULL) { DBUG(("+++ no filename found, using default record name\n")); pRecord->filenameMOR = kNuDefaultRecordName; } pArchive->currentOffset += pRecord->totalCompLength; if (!Nu_IsStreaming(pArchive)) { Assert(pArchive->currentOffset == ftell(pArchive->archiveFp)); } bail: return err; } /* * Skip the thread. This only has meaning for streaming archives, and * assumes that the file pointer is set to the start of the thread's data * already. */ NuError Nu_SkipThread(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread) { NuError err; if (!Nu_IsStreaming(pArchive)) /* for debugging */ return kNuErrNone; /* for debugging */ Assert(Nu_IsStreaming(pArchive)); err = Nu_SeekArchive(pArchive, pArchive->archiveFp, pThread->thCompThreadEOF, SEEK_CUR); return err; } /* * =========================================================================== * Extract * =========================================================================== */ /* * Extract the thread to the specified file pointer. * * If the archive is a stream, the stream must be positioned at the * start of pThread's data. If not, it will be seeked first. */ static NuError Nu_ExtractThreadToDataSink(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, NuProgressData* pProgress, NuDataSink* pDataSink) { NuError err; NuFunnel* pFunnel = NULL; /* if it's not a stream, seek to the appropriate spot in the file */ if (!Nu_IsStreaming(pArchive)) { err = Nu_SeekArchive(pArchive, pArchive->archiveFp, pThread->fileOffset, SEEK_SET); if (err != kNuErrNone) { Nu_ReportError(NU_BLOB, err, "Unable to seek input to %ld", pThread->fileOffset); goto bail; } } /* * Set up an output funnel to write to. */ err = Nu_FunnelNew(pArchive, pDataSink, Nu_DataSinkGetConvertEOL(pDataSink), pArchive->valEOL, pProgress, &pFunnel); BailError(err); /* * Write it. */ err = Nu_ExpandStream(pArchive, pRecord, pThread, pArchive->archiveFp, pFunnel); if (err != kNuErrNone) { if (err != kNuErrSkipped && err != kNuErrAborted) Nu_ReportError(NU_BLOB, err, "ExpandStream failed"); goto bail; } bail: (void) Nu_FunnelFree(pArchive, pFunnel); return err; } /* * Extract the specified thread to "pDataSink". If the sink is to a file, * this will take care of opening (and, if appropriate, creating) the file. * * If we're operating on a streaming archive, the file pointer must be * positioned at the start of the thread's data. If not, it will be * seeked appropriately. * * This calls the "should we extract" and "what pathname should we use" * filters for every thread, which means we can reject specific kinds * of forks and/or give them different names. This is a good thing. */ static NuError Nu_ExtractThreadCommon(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread, NuDataSink* pDataSink) { NuError err = kNuErrNone; NuSelectionProposal selProposal; NuPathnameProposal pathProposal; NuProgressData progressData; NuProgressData* pProgressData; NuDataSink* pOrigDataSink; UNICHAR* newPathStorageUNI = NULL; UNICHAR* recFilenameStorageUNI = NULL; const UNICHAR* newPathnameUNI; NuResult result; uint8_t newFssep; Boolean doFreeSink = false; Assert(pRecord != NULL); Assert(pThread != NULL); Assert(pDataSink != NULL); memset(&progressData, 0, sizeof(progressData)); pProgressData = NULL; /* * If we're just trying to verify the archive contents, create a * data sink that goes nowhere at all. */ if (pArchive->testMode) { err = Nu_DataSinkVoid_New( Nu_DataSinkGetDoExpand(pDataSink), Nu_DataSinkGetConvertEOL(pDataSink), &pDataSink); BailError(err); doFreeSink = true; } pOrigDataSink = pDataSink; /* save a copy for the "retry" loop */ /* * Decide if we want to extract this thread. This is mostly for * use by the "bulk" extract, not the per-thread extract, but it * still applies if they so desire. */ if (pArchive->selectionFilterFunc != NULL) { selProposal.pRecord = pRecord; selProposal.pThread = pThread; result = (*pArchive->selectionFilterFunc)(pArchive, &selProposal); if (result == kNuSkip) return Nu_SkipThread(pArchive, pRecord, pThread); if (result == kNuAbort) { err = kNuErrAborted; goto bail; } } newPathnameUNI = NULL; newFssep = 0; recFilenameStorageUNI = Nu_CopyMORToUNI(pRecord->filenameMOR); retry_name: if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) { /* * We're extracting. Figure out the name of the file to write it to. * If they want to use the sleazy FILE* back door, create a new * data sink and use that instead. * * Start by resetting everything to defaults, in case this isn't * our first time through the "rename" loop. */ newPathnameUNI = Nu_DataSinkFile_GetPathname(pDataSink); newFssep = Nu_DataSinkFile_GetFssep(pDataSink); pDataSink = pOrigDataSink; /* if they don't have a pathname func defined, we just use default */ if (pArchive->outputPathnameFunc != NULL) { pathProposal.pathnameUNI = recFilenameStorageUNI; pathProposal.filenameSeparator = NuGetSepFromSysInfo(pRecord->recFileSysInfo); pathProposal.pRecord = pRecord; pathProposal.pThread = pThread; pathProposal.newPathnameUNI = NULL; pathProposal.newFilenameSeparator = '\0'; /*pathProposal.newStorage = (NuThreadID)-1;*/ pathProposal.newDataSink = NULL; result = (*pArchive->outputPathnameFunc)(pArchive, &pathProposal); if (result == kNuSkip) return Nu_SkipThread(pArchive, pRecord, pThread); if (result == kNuAbort) { err = kNuErrAborted; goto bail; } /* we don't own this string, so make a copy */ if (pathProposal.newPathnameUNI != NULL) { Nu_Free(pArchive, newPathStorageUNI); newPathStorageUNI = strdup(pathProposal.newPathnameUNI); newPathnameUNI = newPathStorageUNI; } else { newPathnameUNI = NULL; } if (pathProposal.newFilenameSeparator != '\0') newFssep = pathProposal.newFilenameSeparator; /* if they want to send this somewhere else, let them */ if (pathProposal.newDataSink != NULL) pDataSink = pathProposal.newDataSink; } /* at least one of these must be set */ Assert(!(newPathnameUNI == NULL && pathProposal.newDataSink == NULL)); } /* * Prepare the progress data if this is a data thread. */ if (newPathnameUNI == NULL) { /* using a data sink; get the pathname out of the record */ newPathnameUNI = recFilenameStorageUNI; newFssep = NuGetSepFromSysInfo(pRecord->recFileSysInfo); } if (pThread->thThreadClass == kNuThreadClassData) { pProgressData = &progressData; err = Nu_ProgressDataInit_Expand(pArchive, pProgressData, pRecord, newPathnameUNI, newFssep, recFilenameStorageUNI, Nu_DataSinkGetConvertEOL(pOrigDataSink)); BailError(err); /* send initial progress so they see the right name if "open" fails */ pProgressData->state = kNuProgressOpening; err = Nu_SendInitialProgress(pArchive, pProgressData); BailError(err); } if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) { /* * We're extracting to a file. Open it, creating it if necessary and * allowed. */ FILE* fileFp = NULL; err = Nu_OpenOutputFile(pArchive, pRecord, pThread, newPathnameUNI, newFssep, &fileFp); if (err == kNuErrRename) { /* they want to rename; the OutputPathname callback handles this */ Nu_Free(pArchive, newPathStorageUNI); newPathStorageUNI = NULL; /* reset these just to be careful */ newPathnameUNI = NULL; fileFp = NULL; goto retry_name; } else if (err != kNuErrNone) { goto bail; } Assert(fileFp != NULL); (void) Nu_DataSinkFile_SetFP(pDataSink, fileFp); DBUG(("+++ EXTRACTING 0x%08lx from '%s' at offset %0ld to '%s'\n", NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind), pRecord->filename, pThread->fileOffset, newPathname)); } else { DBUG(("+++ EXTRACTING 0x%08lx from '%s' at offset %0ld to sink\n", NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind), pRecord->filename, pThread->fileOffset)); } /* extract to the file */ err = Nu_ExtractThreadToDataSink(pArchive, pRecord, pThread, pProgressData, pDataSink); BailError(err); if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) { /* * Close the file, adjusting the modification date and access * permissions as appropriate. */ err = Nu_CloseOutputFile(pArchive, pRecord, Nu_DataSinkFile_GetFP(pDataSink), newPathnameUNI); Nu_DataSinkFile_SetFP(pDataSink, NULL); BailError(err); } bail: if (err != kNuErrNone && pProgressData != NULL) { /* send a final progress message, indicating failure */ if (err == kNuErrSkipped) pProgressData->state = kNuProgressSkipped; else if (err == kNuErrAborted) pProgressData->state = kNuProgressAborted; else pProgressData->state = kNuProgressFailed; (void) Nu_SendInitialProgress(pArchive, pProgressData); } /* if this was an ordinary file, and it's still open, close it */ if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) Nu_DataSinkFile_Close(pDataSink); Nu_Free(pArchive, newPathStorageUNI); Nu_Free(pArchive, recFilenameStorageUNI); if (doFreeSink) Nu_DataSinkFree(pDataSink); return err; } /* * Extract a thread from the archive as part of a "bulk" extract operation. * * Streaming archives must be properly positioned. */ NuError Nu_ExtractThreadBulk(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread) { NuError err; NuDataSink* pDataSink = NULL; UNICHAR* recFilenameStorageUNI = NULL; NuValue eolConv; /* * Create a file data sink for the file. We use whatever EOL conversion * is set as the default for the entire archive. (If you want to * specify your own EOL conversion for each individual file, you will * need to extract them individually, creating a data sink for each.) * * One exception: we turn EOL conversion off for disk image threads. * It's *very* unlikely this would be desirable, and could be a problem * if the user is extracting a collection of disks and files. */ eolConv = pArchive->valConvertExtractedEOL; if (NuGetThreadID(pThread) == kNuThreadIDDiskImage) eolConv = kNuConvertOff; recFilenameStorageUNI = Nu_CopyMORToUNI(pRecord->filenameMOR); err = Nu_DataSinkFile_New(true, eolConv, recFilenameStorageUNI, NuGetSepFromSysInfo(pRecord->recFileSysInfo), &pDataSink); BailError(err); err = Nu_ExtractThreadCommon(pArchive, pRecord, pThread, pDataSink); BailError(err); bail: if (pDataSink != NULL) { NuError err2 = Nu_DataSinkFree(pDataSink); if (err == kNuErrNone) err = err2; } Nu_Free(pArchive, recFilenameStorageUNI); return err; } /* * Extract a thread, given the IDs and a data sink. */ NuError Nu_ExtractThread(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSink* pDataSink) { NuError err; NuRecord* pRecord; NuThread* pThread; if (Nu_IsStreaming(pArchive)) return kNuErrUsage; if (threadIdx == 0 || pDataSink == NULL) return kNuErrInvalidArg; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* find the correct record and thread by index */ err = Nu_RecordSet_FindByThreadIdx(&pArchive->origRecordSet, threadIdx, &pRecord, &pThread); BailError(err); Assert(pRecord != NULL); /* extract away */ err = Nu_ExtractThreadCommon(pArchive, pRecord, pThread, pDataSink); BailError(err); bail: return err; } /* * =========================================================================== * Add/update/delete * =========================================================================== */ /* * Verify that a conflicting thread with the specified threadID does not * exist in this record, now or in the future. * * The set of interesting threads is equal to the current threads, minus * any that have been deleted, plus any that have been added already. * * If a matching threadID is found, this returns an error. */ static NuError Nu_FindNoFutureThread(NuArchive* pArchive, const NuRecord* pRecord, NuThreadID threadID) { NuError err = kNuErrNone; const NuThread* pThread; const NuThreadMod* pThreadMod; int idx; /* * Start by scanning the existing threads (if any). */ for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); if (NuGetThreadID(pThread) == threadID) { /* found a match, see if it has been deleted */ pThreadMod = Nu_ThreadMod_FindByThreadIdx(pRecord, pThread->threadIdx); if (pThreadMod != NULL && pThreadMod->entry.kind == kNuThreadModDelete) { /* it's deleted, ignore it */ continue; } DBUG(("--- found existing thread matching 0x%08lx\n", threadID)); err = kNuErrThreadAdd; goto bail; } } /* * Now look for "add" threadMods with a matching threadID. */ pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { if (pThreadMod->entry.kind == kNuThreadModAdd && pThreadMod->entry.add.threadID == threadID) { DBUG(("--- found 'add' threadMod matching 0x%08lx\n", threadID)); err = kNuErrThreadAdd; goto bail; } pThreadMod = pThreadMod->pNext; } bail: return err; } /* * Like Nu_FindNoFutureThread, but tests against a whole class. */ static NuError Nu_FindNoFutureThreadClass(NuArchive* pArchive, const NuRecord* pRecord, long threadClass) { NuError err = kNuErrNone; const NuThread* pThread; const NuThreadMod* pThreadMod; int idx; /* * Start by scanning the existing threads (if any). */ for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) { pThread = Nu_GetThread(pRecord, idx); Assert(pThread != NULL); if (pThread->thThreadClass == threadClass) { /* found a match, see if it has been deleted */ pThreadMod = Nu_ThreadMod_FindByThreadIdx(pRecord, pThread->threadIdx); if (pThreadMod != NULL && pThreadMod->entry.kind == kNuThreadModDelete) { /* it's deleted, ignore it */ continue; } DBUG(("--- Found existing thread matching 0x%04lx\n", threadClass)); err = kNuErrThreadAdd; goto bail; } } /* * Now look for "add" threadMods with a matching threadClass. */ pThreadMod = pRecord->pThreadMods; while (pThreadMod != NULL) { if (pThreadMod->entry.kind == kNuThreadModAdd && NuThreadIDGetClass(pThreadMod->entry.add.threadID) == threadClass) { DBUG(("--- Found 'add' threadMod matching 0x%04lx\n", threadClass)); err = kNuErrThreadAdd; goto bail; } pThreadMod = pThreadMod->pNext; } bail: return err; } /* * Find an existing thread somewhere in the archive. If the "copy" set * exists it will be searched. If not, the "orig" set is searched, and * if an entry is found a "copy" set will be created. * * The record and thread returned will always be from the "copy" set. An * error result is returned if the record and thread aren't found. */ static NuError Nu_FindThreadForWriteByIdx(NuArchive* pArchive, NuThreadIdx threadIdx, NuRecord** ppFoundRecord, NuThread** ppFoundThread) { NuError err; if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) { err = Nu_RecordSet_FindByThreadIdx(&pArchive->copyRecordSet, threadIdx, ppFoundRecord, ppFoundThread); } else { Assert(Nu_RecordSet_GetLoaded(&pArchive->origRecordSet)); err = Nu_RecordSet_FindByThreadIdx(&pArchive->origRecordSet, threadIdx, ppFoundRecord, ppFoundThread); *ppFoundThread = NULL; /* can't delete from here, wipe ptr */ } BailError(err); /* * The thread exists. If we were looking in the "orig" set, we have * to create a "copy" set, and delete it from that. */ if (*ppFoundThread == NULL) { err = Nu_RecordSet_Clone(pArchive, &pArchive->copyRecordSet, &pArchive->origRecordSet); BailError(err); err = Nu_RecordSet_FindByThreadIdx(&pArchive->copyRecordSet, threadIdx, ppFoundRecord, ppFoundThread); Assert(err == kNuErrNone && *ppFoundThread != NULL); /* must succeed */ BailError(err); } bail: return err; } /* * Determine if it's okay to add a thread of the type specified by * "threadID" into "pRecord". * * Returns with an error (kNuErrThreadAdd) if it's not okay. */ NuError Nu_OkayToAddThread(NuArchive* pArchive, const NuRecord* pRecord, NuThreadID threadID) { NuError err = kNuErrNone; /* * Check for class conflicts (can't mix data and control threads). */ if (NuThreadIDGetClass(threadID) == kNuThreadClassData) { err = Nu_FindNoFutureThreadClass(pArchive, pRecord, kNuThreadClassControl); BailError(err); } else if (NuThreadIDGetClass(threadID) == kNuThreadClassControl) { err = Nu_FindNoFutureThreadClass(pArchive, pRecord, kNuThreadClassData); BailError(err); } /* * Check for specific type conflicts. */ if (threadID == kNuThreadIDDataFork) { err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDataFork); BailError(err); err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage); BailError(err); } else if (threadID == kNuThreadIDRsrcFork) { err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDRsrcFork); BailError(err); err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage); BailError(err); } else if (threadID == kNuThreadIDDiskImage) { err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDataFork); BailError(err); err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDRsrcFork); BailError(err); err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage); BailError(err); } else if (threadID == kNuThreadIDFilename) { err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDFilename); BailError(err); } bail: return err; } /* * Add a new thread to a record. * * In some cases, you aren't allowed to add a thread whose type matches * one that already exists. This applies to data threads and filenames, * but not to comments, control threads, or IIgs icons. You also can't * add a disk image thread when there are data-class threads, or vice-versa. * * This is the first and last place we do this sort of checking. If * an illegal situation gets past this function, it will either get * caught with a fatal assert or (if NDEBUG is defined) not at all. * * On success, the NuThreadIdx of the newly-created record will be placed * in "*pThreadIdx", and "pDataSource" will be owned by NufxLib. */ NuError Nu_AddThread(NuArchive* pArchive, NuRecordIdx recIdx, NuThreadID threadID, NuDataSource* pDataSource, NuThreadIdx* pThreadIdx) { NuError err; NuRecord* pRecord; NuThreadMod* pThreadMod = NULL; NuThreadFormat threadFormat; /* okay for pThreadIdx to be NULL */ if (recIdx == 0 || pDataSource == NULL) return kNuErrInvalidArg; if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* * Find the record. If it doesn't exist in the copy set, check to * see if it's in the "new" set. */ err = Nu_FindRecordForWriteByIdx(pArchive, recIdx, &pRecord); if (err == kNuErrRecIdxNotFound && Nu_RecordSet_GetLoaded(&pArchive->newRecordSet)) { err = Nu_RecordSet_FindByIdx(&pArchive->newRecordSet, recIdx, &pRecord); } BailError(err); Assert(pRecord != NULL); /* * Do some tests, looking for specific types of threads that conflict * with what we're trying to add. */ err = Nu_OkayToAddThread(pArchive, pRecord, threadID); BailError(err); /* * Decide if we want to compress the data from this source. If the * data is already compressed (as indicated by the data source) or * this type of thread isn't compressible (e.g. it's a filename), then * we don't compress it. Otherwise, we use whatever compression mode * is currently configured. */ if (Nu_DataSourceGetThreadFormat(pDataSource) == kNuThreadFormatUncompressed && Nu_IsCompressibleThreadID(threadID)) { threadFormat = Nu_ConvertCompressValToFormat(pArchive, pArchive->valDataCompression); } else { threadFormat = kNuThreadFormatUncompressed; } DBUG(("--- using threadFormat = %d\n", threadFormat)); /* create a new ThreadMod (which makes a copy of the data source) */ err = Nu_ThreadModAdd_New(pArchive, threadID, threadFormat, pDataSource, &pThreadMod); BailError(err); Assert(pThreadMod != NULL); /* add the thread mod to the record */ Nu_RecordAddThreadMod(pRecord, pThreadMod); if (pThreadIdx != NULL) *pThreadIdx = pThreadMod->entry.add.threadIdx; pThreadMod = NULL; /* successful, don't free */ /* * If we've got a header filename and we're adding a filename thread, * we don't want to write the record header name when we reconstruct * the record. */ if (threadID == kNuThreadIDFilename && pRecord->recFilenameLength) { DBUG(("+++ gonna drop the filename\n")); pRecord->dropRecFilename = true; } bail: if (pThreadMod != NULL) Nu_ThreadModFree(pArchive, pThreadMod); if (err == kNuErrNone && pDataSource != NULL) { /* on success, we have ownership of the data source. ThreadMod made its own copy, so get rid of this one */ Nu_DataSourceFree(pDataSource); } return err; } /* * Update the contents of a pre-sized thread, such as a filename or * comment thread. * * The data from the source must fit within the limits of the existing * thread. The source data is never compressed, and must not come from * a compressed source. * * You aren't allowed to update threads that have been deleted. Updating * newly-added threads isn't possible, since they aren't really threads yet. */ NuError Nu_UpdatePresizedThread(NuArchive* pArchive, NuThreadIdx threadIdx, NuDataSource* pDataSource, int32_t* pMaxLen) { NuError err; NuThreadMod* pThreadMod = NULL; NuRecord* pFoundRecord; NuThread* pFoundThread; if (pDataSource == NULL) { err = kNuErrInvalidArg; goto bail; } /* presized threads always contain uncompressed data */ if (Nu_DataSourceGetThreadFormat(pDataSource) != kNuThreadFormatUncompressed) { err = kNuErrBadFormat; Nu_ReportError(NU_BLOB, err, "presized threads can't hold compressed data"); goto bail; } if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* * Find the thread in the "copy" set. (If there isn't a copy set, * make one.) */ err = Nu_FindThreadForWriteByIdx(pArchive, threadIdx, &pFoundRecord, &pFoundThread); BailError(err); if (!Nu_IsPresizedThreadID(NuGetThreadID(pFoundThread)) || !(pFoundThread->thCompThreadEOF >= pFoundThread->thThreadEOF)) { err = kNuErrNotPreSized; Nu_ReportError(NU_BLOB, err, "invalid thread for update"); goto bail; } if (pMaxLen != NULL) *pMaxLen = pFoundThread->thCompThreadEOF; /* * Check to see if somebody is trying to delete this, or has already * updated it. */ if (Nu_ThreadMod_FindByThreadIdx(pFoundRecord, threadIdx) != NULL) { DBUG(("--- Tried to modify a deleted or modified thread\n")); err = kNuErrModThreadChange; goto bail; } /* * Verify that "otherLen" in the data source is less than or equal * to our len, if we can. If the data source is a file on disk, * we're not really supposed to look at it until we flush. We * could sneak a peek right now, which would prevent us from aborting * the entire operation when it turns out the file won't fit, but * that violates our semantics (and besides, the application really * should've done that already). * * If the data source is from a file, we just assume it'll fit and * let the chips fall where they may later on. */ if (Nu_DataSourceGetType(pDataSource) != kNuDataSourceFromFile) { if (pFoundThread->thCompThreadEOF < Nu_DataSourceGetOtherLen(pDataSource)) { err = kNuErrPreSizeOverflow; Nu_ReportError(NU_BLOB, err, "can't put %u bytes into %u", Nu_DataSourceGetOtherLen(pDataSource), pFoundThread->thCompThreadEOF); goto bail; } /* check for zero-length and excessively long filenames */ if (NuGetThreadID(pFoundThread) == kNuThreadIDFilename && (Nu_DataSourceGetOtherLen(pDataSource) == 0 || Nu_DataSourceGetOtherLen(pDataSource) > kNuReasonableFilenameLen)) { err = kNuErrInvalidFilename; Nu_ReportError(NU_BLOB, err, "invalid filename (%u bytes)", Nu_DataSourceGetOtherLen(pDataSource)); goto bail; } } /* * Looks like it'll fit, and it's the right kind of data. Create * an "update" threadMod. Note this copies the data source. */ Assert(pFoundThread->thThreadFormat == kNuThreadFormatUncompressed); err = Nu_ThreadModUpdate_New(pArchive, threadIdx, pDataSource, &pThreadMod); BailError(err); Assert(pThreadMod != NULL); /* add the thread mod to the record */ Nu_RecordAddThreadMod(pFoundRecord, pThreadMod); /* * NOTE: changes to filename threads will be picked up later and * incorporated into the record's threadFilename. We don't worry * about the record header filename, because we might be doing an * update-in-place and that prevents us from removing the filename * (doing so would change the size of the archive). No need to * do any filename-specific changes here. */ bail: return err; } /* * Delete an individual thread. * * You aren't allowed to delete threads that have been updated. Deleting * newly-added threads isn't possible, since they aren't really threads yet. * * Don't worry about deleting filename threads here; we take care of that * later on. Besides, it's sort of handy to hang on to the filename for * as long as possible. */ NuError Nu_DeleteThread(NuArchive* pArchive, NuThreadIdx threadIdx) { NuError err; NuThreadMod* pThreadMod = NULL; NuRecord* pFoundRecord; NuThread* pFoundThread; if (Nu_IsReadOnly(pArchive)) return kNuErrArchiveRO; err = Nu_GetTOCIfNeeded(pArchive); BailError(err); /* * Find the thread in the "copy" set. (If there isn't a copy set, * make one.) */ err = Nu_FindThreadForWriteByIdx(pArchive, threadIdx, &pFoundRecord, &pFoundThread); BailError(err); /* * Deletion of modified threads (updates or previous deletes) isn't * allowed. Deletion of threads from deleted records can't happen, * because deleted records are completely removed from the "copy" set. */ if (Nu_ThreadMod_FindByThreadIdx(pFoundRecord, threadIdx) != NULL) { DBUG(("--- Tried to delete a deleted or modified thread\n")); err = kNuErrModThreadChange; goto bail; } /* * Looks good. Add a new "delete" ThreadMod to the list. */ err = Nu_ThreadModDelete_New(pArchive, threadIdx, NuGetThreadID(pFoundThread), &pThreadMod); BailError(err); Nu_RecordAddThreadMod(pFoundRecord, pThreadMod); pThreadMod = NULL; /* successful, don't free */ bail: Nu_ThreadModFree(pArchive, pThreadMod); return err; } nulib2-3.1.0/nufxlib/Value.c000066400000000000000000000237011316100516500155760ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Get/set certain values and attributes. */ #include "NufxLibPriv.h" #define kMaxJunkSkipMax 8192 /* * Get a configurable parameter. */ NuError Nu_GetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue) { NuError err = kNuErrNone; if (pValue == NULL) return kNuErrInvalidArg; switch (ident) { case kNuValueAllowDuplicates: *pValue = pArchive->valAllowDuplicates; break; case kNuValueConvertExtractedEOL: *pValue = pArchive->valConvertExtractedEOL; break; case kNuValueDataCompression: *pValue = pArchive->valDataCompression; break; case kNuValueDiscardWrapper: *pValue = pArchive->valDiscardWrapper; break; case kNuValueEOL: *pValue = pArchive->valEOL; break; case kNuValueHandleExisting: *pValue = pArchive->valHandleExisting; break; case kNuValueIgnoreCRC: *pValue = pArchive->valIgnoreCRC; break; case kNuValueMaskDataless: *pValue = pArchive->valMaskDataless; break; case kNuValueMimicSHK: *pValue = pArchive->valMimicSHK; break; case kNuValueModifyOrig: *pValue = pArchive->valModifyOrig; break; case kNuValueOnlyUpdateOlder: *pValue = pArchive->valOnlyUpdateOlder; break; case kNuValueStripHighASCII: *pValue = pArchive->valStripHighASCII; break; case kNuValueJunkSkipMax: *pValue = pArchive->valJunkSkipMax; break; case kNuValueIgnoreLZW2Len: *pValue = pArchive->valIgnoreLZW2Len; break; case kNuValueHandleBadMac: *pValue = pArchive->valHandleBadMac; break; default: err = kNuErrInvalidArg; Nu_ReportError(NU_BLOB, err, "Unknown ValueID %d requested", ident); goto bail; } bail: return err; } /* * Set a configurable parameter. */ NuError Nu_SetValue(NuArchive* pArchive, NuValueID ident, NuValue value) { NuError err = kNuErrInvalidArg; switch (ident) { case kNuValueAllowDuplicates: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueAllowDuplicates value %u", value); goto bail; } pArchive->valAllowDuplicates = value; break; case kNuValueConvertExtractedEOL: if (value < kNuConvertOff || value > kNuConvertAuto) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueConvertExtractedEOL value %u", value); goto bail; } pArchive->valConvertExtractedEOL = value; break; case kNuValueDataCompression: if (value < kNuCompressNone || value > kNuCompressBzip2) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueDataCompression value %u", value); goto bail; } pArchive->valDataCompression = value; break; case kNuValueDiscardWrapper: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueDiscardWrapper value %u", value); goto bail; } pArchive->valDiscardWrapper = value; break; case kNuValueEOL: if (value < kNuEOLUnknown || value > kNuEOLCRLF) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueEOL value %u", value); goto bail; } pArchive->valEOL = value; break; case kNuValueHandleExisting: if (value < kNuMaybeOverwrite || value > kNuMustOverwrite) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueHandleExisting value %u", value); goto bail; } pArchive->valHandleExisting = value; break; case kNuValueIgnoreCRC: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueIgnoreCRC value %u", value); goto bail; } pArchive->valIgnoreCRC = value; break; case kNuValueMaskDataless: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueMaskDataless value %u", value); goto bail; } pArchive->valMaskDataless = value; break; case kNuValueMimicSHK: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueMimicSHK value %u", value); goto bail; } pArchive->valMimicSHK = value; break; case kNuValueModifyOrig: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueModifyOrig value %u", value); goto bail; } pArchive->valModifyOrig = value; break; case kNuValueOnlyUpdateOlder: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueOnlyUpdateOlder value %u", value); goto bail; } pArchive->valOnlyUpdateOlder = value; break; case kNuValueStripHighASCII: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueStripHighASCII value %u", value); goto bail; } pArchive->valStripHighASCII = value; break; case kNuValueJunkSkipMax: if (value > kMaxJunkSkipMax) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueJunkSkipMax value %u", value); goto bail; } pArchive->valJunkSkipMax = value; break; case kNuValueIgnoreLZW2Len: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueIgnoreLZW2Len value %u", value); goto bail; } pArchive->valIgnoreLZW2Len = value; break; case kNuValueHandleBadMac: if (value != true && value != false) { Nu_ReportError(NU_BLOB, err, "Invalid kNuValueHandleBadMac value %u", value); goto bail; } pArchive->valHandleBadMac = value; break; default: Nu_ReportError(NU_BLOB, err, "Unknown ValueID %d requested", ident); goto bail; } err = kNuErrNone; bail: return err; } /* * Get an archive attribute. These are things that you would have to * pry into pArchive to get at (like the archive type) or get the master * header (like the number of records). */ NuError Nu_GetAttr(NuArchive* pArchive, NuAttrID ident, NuAttr* pAttr) { NuError err = kNuErrNone; if (pAttr == NULL) return kNuErrInvalidArg; switch (ident) { case kNuAttrArchiveType: *pAttr = pArchive->archiveType; break; case kNuAttrNumRecords: *pAttr = pArchive->masterHeader.mhTotalRecords; break; case kNuAttrHeaderOffset: *pAttr = pArchive->headerOffset; break; case kNuAttrJunkOffset: *pAttr = pArchive->junkOffset; break; default: err = kNuErrInvalidArg; Nu_ReportError(NU_BLOB, err, "Unknown AttrID %d requested", ident); goto bail; } bail: return err; } /* * Convert a NuValue compression type to a "phyiscal" ThreadFormat. * * Unsupported compression types cause a warning to be flagged. */ NuThreadFormat Nu_ConvertCompressValToFormat(NuArchive* pArchive, NuValue compValue) { NuThreadFormat threadFormat; Boolean unsup = false; switch (compValue) { case kNuCompressNone: threadFormat = kNuThreadFormatUncompressed; break; #ifdef ENABLE_SQ case kNuCompressSQ: threadFormat = kNuThreadFormatHuffmanSQ; break; #else case kNuCompressSQ: threadFormat = kNuThreadFormatHuffmanSQ; unsup = true; break; #endif #ifdef ENABLE_LZW case kNuCompressLZW1: threadFormat = kNuThreadFormatLZW1; break; case kNuCompressLZW2: threadFormat = kNuThreadFormatLZW2; break; #else case kNuCompressLZW1: threadFormat = kNuThreadFormatLZW1; unsup = true; break; case kNuCompressLZW2: threadFormat = kNuThreadFormatLZW2; unsup = true; break; #endif #ifdef ENABLE_LZC case kNuCompressLZC12: threadFormat = kNuThreadFormatLZC12; break; case kNuCompressLZC16: threadFormat = kNuThreadFormatLZC16; break; #else case kNuCompressLZC12: threadFormat = kNuThreadFormatLZC12; unsup = true; break; case kNuCompressLZC16: threadFormat = kNuThreadFormatLZC16; unsup = true; break; #endif #ifdef ENABLE_DEFLATE case kNuCompressDeflate: threadFormat = kNuThreadFormatDeflate; break; #else case kNuCompressDeflate: threadFormat = kNuThreadFormatDeflate; unsup = true; break; #endif #ifdef ENABLE_BZIP2 case kNuCompressBzip2: threadFormat = kNuThreadFormatBzip2; break; #else case kNuCompressBzip2: threadFormat = kNuThreadFormatBzip2; unsup = true; break; #endif default: Nu_ReportError(NU_BLOB, kNuErrInvalidArg, "Unknown compress value %u", compValue); Assert(false); return kNuThreadFormatUncompressed; } if (unsup) { Nu_ReportError(NU_BLOB, kNuErrNone, "Unsupported compression 0x%04x requested (%u), storing", threadFormat, compValue); return kNuThreadFormatUncompressed; } return threadFormat; } nulib2-3.1.0/nufxlib/Version.c000066400000000000000000000022031316100516500161410ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. */ #include "NufxLibPriv.h" /* executable was build on or after this date */ #ifdef __DATE__ static const char gNuBuildDate[] = __DATE__; #else static const char gNuBuildDate[] = "??? ?? ????"; #endif #ifdef OPTFLAGSTR static const char gNuBuildFlags[] = OPTFLAGSTR; #else static const char gNuBuildFlags[] = "-"; #endif /* * Return the version number, date built, and build flags. */ NuError Nu_GetVersion(int32_t* pMajorVersion, int32_t* pMinorVersion, int32_t* pBugVersion, const char** ppBuildDate, const char** ppBuildFlags) { if (pMajorVersion != NULL) *pMajorVersion = kNuVersionMajor; if (pMinorVersion != NULL) *pMinorVersion = kNuVersionMinor; if (pBugVersion != NULL) *pBugVersion = kNuVersionBug; if (ppBuildDate != NULL) *ppBuildDate = gNuBuildDate; if (ppBuildFlags != NULL) *ppBuildFlags = gNuBuildFlags; return kNuErrNone; } nulib2-3.1.0/nufxlib/config.guess000066400000000000000000001247531316100516500167040ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-08-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in *86) UNAME_PROCESSOR=i686 ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nulib2-3.1.0/nufxlib/config.h.in000066400000000000000000000066141316100516500164050ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. */ /* config.h.in. */ /* Define to empty if the keyword does not work. */ #undef const /* Define to empty if the keyword does not work. */ #undef inline /* Define to `int' if doesn't define. */ #undef mode_t /* Define to `long' if doesn't define. */ #undef off_t /* Define to `unsigned' if doesn't define. */ #undef size_t /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if your declares struct tm. */ #undef TM_IN_SYS_TIME /* Define to `int' if doesn't define. */ #undef mode_t /* Define to `long' if doesn't define. */ #undef off_t /* Define to `unsigned' if doesn't define. */ #undef size_t /* Define if you have the fdopen function. */ #undef HAVE_FDOPEN /* Define if you have the ftruncate function. */ #undef HAVE_FTRUNCATE /* Define if you have the localtime_r function. */ #undef HAVE_LOCALTIME_R /* Define if you have the memmove function. */ #undef HAVE_MEMMOVE /* Define if you have the mkdir function. */ #undef HAVE_MKDIR /* Define if you have the mkstemp function. */ #undef HAVE_MKSTEMP /* Define if you have the mktime function. */ #undef HAVE_MKTIME /* Define if you have the snprintf function. */ #undef HAVE_SNPRINTF /* Define if you have the strcasecmp function. */ #undef HAVE_STRCASECMP /* Define if you have the strncasecmp function. */ #undef HAVE_STRNCASECMP /* Define if you have the strerror function. */ #undef HAVE_STRERROR /* Define if you have the strtoul function. */ #undef HAVE_STRTOUL /* Define if you have the timelocal function. */ #undef HAVE_TIMELOCAL /* Define if you have the vsnprintf function. */ #undef HAVE_VSNPRINTF /* Define if you have the header file. */ #undef HAVE_FCNTL_H /* Define if you have the header file. */ #undef HAVE_MALLOC_H /* Define if you have the header file. */ #undef HAVE_STDLIB_H /* Define if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define if you have the header file. */ #undef HAVE_SYS_UTIME_H /* Define if you have the header file. */ #undef HAVE_UNISTD_H /* Define if you have the header file. */ #undef HAVE_UTIME_H /* Define if sprintf returns an int. */ #undef SPRINTF_RETURNS_INT /* Define if SNPRINTF is declared in stdio.h. */ #undef SNPRINTF_DECLARED /* Define if VSNPRINTF is declared in stdio.h. */ #undef VSNPRINTF_DECLARED /* Define to include SQ (Huffman+RLE) compression. */ #undef ENABLE_SQ /* Define to include LZW (ShrinkIt LZW/1 and LZW/2) compression. */ #undef ENABLE_LZW /* Define to include LZC (12-bit and 16-bit UNIX "compress") compression. */ #undef ENABLE_LZC /* Define to include deflate (zlib) compression (also need -l in Makefile). */ #undef ENABLE_DEFLATE /* Define to include bzip2 (libbz2) compression (also need -l in Makefile). */ #undef ENABLE_BZIP2 /* Define if we want to use the dmalloc library (also need -l in Makefile). */ #undef USE_DMALLOC nulib2-3.1.0/nufxlib/config.sub000066400000000000000000000757771316100516500163620ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-07-08' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | ms1 \ | msp430 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m32c) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | ms1-* \ | msp430-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; m32c-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nulib2-3.1.0/nufxlib/configure000077500000000000000000004665551316100516500163070ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="NufxLibPriv.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS SHARE_FLAGS BUILD_FLAGS EGREP GREP CPP RANLIB SET_MAKE INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_sq enable_lzw enable_lzc enable_deflate enable_bzip2 enable_dmalloc ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-sq disable SQ compression --disable-lzw disable LZW/1 and LZW/2 compression --disable-lzc disable 12- and 16-bit LZC compression --disable-deflate disable zlib deflate compression --enable-bzip2 enable libbz2 bzip2 compression --enable-dmalloc do dmalloc stuff Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in fcntl.h malloc.h stdlib.h sys/stat.h sys/time.h sys/types.h \ sys/utime.h unistd.h utime.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done LIBS="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define mode_t int _ACEOF fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi for ac_func in fdopen ftruncate memmove mkdir mkstemp mktime timelocal \ localtime_r snprintf strcasecmp strncasecmp strtoul strerror vsnprintf do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking if snprintf is declared" >&5 $as_echo_n "checking if snprintf is declared... " >&6; } if ${nufxlib_cv_snprintf_in_header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "snprintf" >/dev/null 2>&1; then : nufxlib_cv_snprintf_in_header=yes else nufxlib_cv_snprintf_in_header=no fi rm -f conftest* fi if test $nufxlib_cv_snprintf_in_header = "yes"; then $as_echo "#define SNPRINTF_DECLARED 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nufxlib_cv_snprintf_in_header" >&5 $as_echo "$nufxlib_cv_snprintf_in_header" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if vsnprintf is declared" >&5 $as_echo_n "checking if vsnprintf is declared... " >&6; } if ${nufxlib_cv_vsnprintf_in_header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "vsnprintf" >/dev/null 2>&1; then : nufxlib_cv_vsnprintf_in_header=yes else nufxlib_cv_vsnprintf_in_header=no fi rm -f conftest* fi if test $nufxlib_cv_vsnprintf_in_header = "yes"; then $as_echo "#define VSNPRINTF_DECLARED 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nufxlib_cv_vsnprintf_in_header" >&5 $as_echo "$nufxlib_cv_vsnprintf_in_header" >&6; } if test -z "$GCC"; then BUILD_FLAGS='$(OPT)' else BUILD_FLAGS='$(OPT) $(GCC_FLAGS)' fi SHARE_FLAGS='-shared' if test "$host_cpu" = "powerpc" -a "$host_os" = "beos"; then CC=cc GCC= CFLAGS='-proc 603 -opt full' SHARE_FLAGS='-shared -nostdlib' echo "forcing CC to \"$CC\" and CFLAGS to \"$CFLAGS\"" elif test "$host_os" = "beos"; then SHARE_FLAGS='-nostartfiles -Xlinker -soname="$@"' fi if test "$host_os" = "beos"; then if test "$prefix" = "NONE" -a \ "$includedir" = '${prefix}/include' -a \ "$libdir" = '${exec_prefix}/lib' -a \ "$bindir" = '${exec_prefix}/bin' -a \ "$mandir" = '${prefix}/man' then echo replacing install locations with BeOS values prefix=/boot includedir='${prefix}/develop/headers' libdir='${exec_prefix}/home/config/lib' bindir='${exec_prefix}/home/config/bin' mandir='/tmp' fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if sprintf returns int" >&5 $as_echo_n "checking if sprintf returns int... " >&6; } if ${nufxlib_cv_sprintf_returns_int+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : nufxlib_cv_sprintf_returns_int=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main(void) { int count; char buf[8]; count = sprintf(buf, "123"); /* should return three */ exit(count != 3); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : nufxlib_cv_sprintf_returns_int=yes else nufxlib_cv_sprintf_returns_int=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi if test $nufxlib_cv_sprintf_returns_int = "yes"; then $as_echo "#define SPRINTF_RETURNS_INT 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nufxlib_cv_sprintf_returns_int" >&5 $as_echo "$nufxlib_cv_sprintf_returns_int" >&6; } # Check whether --enable-sq was given. if test "${enable_sq+set}" = set; then : enableval=$enable_sq; else enable_sq=yes fi if test $enable_sq = "yes"; then $as_echo "#define ENABLE_SQ 1" >>confdefs.h fi # Check whether --enable-lzw was given. if test "${enable_lzw+set}" = set; then : enableval=$enable_lzw; else enable_lzw=yes fi if test $enable_lzw = "yes"; then $as_echo "#define ENABLE_LZW 1" >>confdefs.h fi # Check whether --enable-lzc was given. if test "${enable_lzc+set}" = set; then : enableval=$enable_lzc; else enable_lzc=yes fi if test $enable_lzc = "yes"; then $as_echo "#define ENABLE_LZC 1" >>confdefs.h fi # Check whether --enable-deflate was given. if test "${enable_deflate+set}" = set; then : enableval=$enable_deflate; else enable_deflate=yes fi if test $enable_deflate = "yes"; then got_zlibh=false { $as_echo "$as_me:${as_lineno-$LINENO}: checking for deflate in -lz" >&5 $as_echo_n "checking for deflate in -lz... " >&6; } if ${ac_cv_lib_z_deflate+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char deflate (); int main () { return deflate (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_deflate=yes else ac_cv_lib_z_deflate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_deflate" >&5 $as_echo "$ac_cv_lib_z_deflate" >&6; } if test "x$ac_cv_lib_z_deflate" = xyes; then : got_libz=true else got_libz=false fi if $got_libz; then ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : got_zlibh=true LIBS="$LIBS -lz" fi fi if $got_zlibh; then echo " (found libz and zlib.h, enabling deflate)" $as_echo "#define ENABLE_DEFLATE 1" >>confdefs.h else echo " (couldn't find libz and zlib.h, not enabling deflate)" fi fi # Check whether --enable-bzip2 was given. if test "${enable_bzip2+set}" = set; then : enableval=$enable_bzip2; else enable_bzip2=no fi if test $enable_bzip2 = "yes"; then got_bzlibh=false { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BZ2_bzCompress in -lbz2" >&5 $as_echo_n "checking for BZ2_bzCompress in -lbz2... " >&6; } if ${ac_cv_lib_bz2_BZ2_bzCompress+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbz2 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char BZ2_bzCompress (); int main () { return BZ2_bzCompress (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bz2_BZ2_bzCompress=yes else ac_cv_lib_bz2_BZ2_bzCompress=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 $as_echo "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes; then : got_libbz=true else got_libbz=false fi if $got_libbz; then ac_fn_c_check_header_mongrel "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" if test "x$ac_cv_header_bzlib_h" = xyes; then : got_bzlibh=true LIBS="$LIBS -lbz2" fi fi if $got_bzlibh; then echo " (found libbz2 and bzlib.h, enabling bzip2)" $as_echo "#define ENABLE_BZIP2 1" >>confdefs.h else echo " (couldn't find libbz2 and bzlib.h, not enabling bzip2)" fi fi # Check whether --enable-dmalloc was given. if test "${enable_dmalloc+set}" = set; then : enableval=$enable_dmalloc; echo "--- enabling dmalloc"; LIBS="$LIBS -L/usr/local/lib -ldmalloc"; $as_echo "#define USE_DMALLOC 1" >>confdefs.h fi ac_config_files="$ac_config_files Makefile samples/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "samples/Makefile") CONFIG_FILES="$CONFIG_FILES samples/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi nulib2-3.1.0/nufxlib/configure.in000066400000000000000000000153071316100516500166720ustar00rootroot00000000000000dnl NuFX archive manipulation library dnl Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. dnl This is free software; you can redistribute it and/or modify it under the dnl terms of the BSD License, see the file COPYING-LIB. dnl dnl Process this file with autoconf to produce a configure script. AC_INIT(NufxLibPriv.h) AC_CONFIG_HEADER(config.h) dnl Checks for programs. AC_CANONICAL_HOST dnl AC_PROG_AWK AC_PROG_CC AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PROG_RANLIB dnl Checks for header files. AC_CHECK_HEADERS(fcntl.h malloc.h stdlib.h sys/stat.h sys/time.h sys/types.h \ sys/utime.h unistd.h utime.h) LIBS="" dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_STRUCT_TM dnl Checks for library functions. AC_CHECK_FUNCS(fdopen ftruncate memmove mkdir mkstemp mktime timelocal \ localtime_r snprintf strcasecmp strncasecmp strtoul strerror vsnprintf) dnl Kent says: snprintf doesn't always have a declaration AC_MSG_CHECKING(if snprintf is declared) AC_CACHE_VAL(nufxlib_cv_snprintf_in_header, [ AC_EGREP_HEADER(snprintf, stdio.h, [nufxlib_cv_snprintf_in_header=yes], [nufxlib_cv_snprintf_in_header=no]) ]) if test $nufxlib_cv_snprintf_in_header = "yes"; then AC_DEFINE(SNPRINTF_DECLARED) fi AC_MSG_RESULT($nufxlib_cv_snprintf_in_header) dnl Kent says: vsnprintf doesn't always have a declaration AC_MSG_CHECKING(if vsnprintf is declared) AC_CACHE_VAL(nufxlib_cv_vsnprintf_in_header, [ AC_EGREP_HEADER(vsnprintf, stdio.h, [nufxlib_cv_vsnprintf_in_header=yes], [nufxlib_cv_vsnprintf_in_header=no]) ]) if test $nufxlib_cv_vsnprintf_in_header = "yes"; then AC_DEFINE(VSNPRINTF_DECLARED) fi AC_MSG_RESULT($nufxlib_cv_vsnprintf_in_header) dnl if we're using gcc, include gcc-specific warning flags if test -z "$GCC"; then BUILD_FLAGS='$(OPT)' else BUILD_FLAGS='$(OPT) $(GCC_FLAGS)' fi dnl --------------------------------------------------------------------------- dnl Some host-specific stuff. Variables you can test (set by the dnl AC_CANONICAL_HOST call earlier) look like this: dnl dnl $host = i686-pc-linux-gnu dnl $host_cpu = i686 dnl $host_vendor = pc dnl $host_os = linux-gnu dnl Figure out what the build and link flags should be; different for BeOS. dnl (Should really use the auto-shared-lib stuff, but that adds a whole dnl bunch of stuff.) SHARE_FLAGS='-shared' if test "$host_cpu" = "powerpc" -a "$host_os" = "beos"; then dnl BeOS/PPC, with Metrowerks compiler CC=cc GCC= CFLAGS='-proc 603 -opt full' SHARE_FLAGS='-shared -nostdlib' echo "forcing CC to \"$CC\" and CFLAGS to \"$CFLAGS\"" elif test "$host_os" = "beos"; then dnl BeOS/x86 SHARE_FLAGS='-nostartfiles -Xlinker -soname="$@"' fi AC_SUBST(BUILD_FLAGS) AC_SUBST(SHARE_FLAGS) dnl BeOS doesn't like /usr/local/include, and gets feisty about it. If libdir dnl and includedir are set to defaults, replace them with BeOS values. This dnl might be going a little too far... if test "$host_os" = "beos"; then if test "$prefix" = "NONE" -a \ "$includedir" = '${prefix}/include' -a \ "$libdir" = '${exec_prefix}/lib' -a \ "$bindir" = '${exec_prefix}/bin' -a \ "$mandir" = '${prefix}/man' then echo replacing install locations with BeOS values prefix=/boot includedir='${prefix}/develop/headers' libdir='${exec_prefix}/home/config/lib' bindir='${exec_prefix}/home/config/bin' mandir='/tmp' AC_SUBST(prefix) AC_SUBST(includedir) AC_SUBST(libdir) AC_SUBST(bindir) AC_SUBST(mandir) fi fi dnl Test to see if sprintf does something reasonable. I'm going to assume dnl that vsprintf and (if available) vsnprintf return the same thing. AC_MSG_CHECKING(if sprintf returns int) AC_CACHE_VAL(nufxlib_cv_sprintf_returns_int, [ AC_TRY_RUN([ #include int main(void) { int count; char buf[8]; count = sprintf(buf, "123"); /* should return three */ exit(count != 3); } ], [nufxlib_cv_sprintf_returns_int=yes], [nufxlib_cv_sprintf_returns_int=no], [nufxlib_cv_sprintf_returns_int=no]) ]) if test $nufxlib_cv_sprintf_returns_int = "yes"; then AC_DEFINE(SPRINTF_RETURNS_INT) fi AC_MSG_RESULT($nufxlib_cv_sprintf_returns_int) dnl dnl Allow selective disabling of compression algorithms. By default, dnl all are enabled. We do a little extra work for libz and libbz2 dnl because they're not built in. dnl dnl If we're creating a shared library, we need to explicitly link dnl against libz and/or libbz2 when those features are enabled. dnl AC_ARG_ENABLE(sq, [ --disable-sq disable SQ compression], [ ], [ enable_sq=yes ]) if test $enable_sq = "yes"; then AC_DEFINE(ENABLE_SQ) fi AC_ARG_ENABLE(lzw, [ --disable-lzw disable LZW/1 and LZW/2 compression], [ ], [ enable_lzw=yes ]) if test $enable_lzw = "yes"; then AC_DEFINE(ENABLE_LZW) fi AC_ARG_ENABLE(lzc, [ --disable-lzc disable 12- and 16-bit LZC compression], [ ], [ enable_lzc=yes ]) if test $enable_lzc = "yes"; then AC_DEFINE(ENABLE_LZC) fi AC_ARG_ENABLE(deflate, [ --disable-deflate disable zlib deflate compression], [ ], [ enable_deflate=yes ]) if test $enable_deflate = "yes"; then dnl Check for zlib. Make sure it comes with zlib.h. got_zlibh=false AC_CHECK_LIB(z, deflate, got_libz=true, got_libz=false) if $got_libz; then AC_CHECK_HEADER(zlib.h, got_zlibh=true LIBS="$LIBS -lz") fi if $got_zlibh; then echo " (found libz and zlib.h, enabling deflate)" AC_DEFINE(ENABLE_DEFLATE) else echo " (couldn't find libz and zlib.h, not enabling deflate)" fi fi AC_ARG_ENABLE(bzip2, [ --enable-bzip2 enable libbz2 bzip2 compression], [ ], [ enable_bzip2=no ]) if test $enable_bzip2 = "yes"; then dnl Check for libbz2. Make sure it comes with bzlib.h. dnl AC_CHECK_LIB(bz2, BZ2_bzCompress, dnl AC_CHECK_HEADER(bzlib.h, AC_DEFINE(ENABLE_BZIP2) LIBS="$LIBS -lbz2")) got_bzlibh=false AC_CHECK_LIB(bz2, BZ2_bzCompress, got_libbz=true, got_libbz=false) if $got_libbz; then AC_CHECK_HEADER(bzlib.h, got_bzlibh=true LIBS="$LIBS -lbz2") fi if $got_bzlibh; then echo " (found libbz2 and bzlib.h, enabling bzip2)" AC_DEFINE(ENABLE_BZIP2) else echo " (couldn't find libbz2 and bzlib.h, not enabling bzip2)" fi fi AC_ARG_ENABLE(dmalloc, [ --enable-dmalloc do dmalloc stuff], [ echo "--- enabling dmalloc"; LIBS="$LIBS -L/usr/local/lib -ldmalloc"; AC_DEFINE(USE_DMALLOC) ]) AC_OUTPUT(Makefile samples/Makefile) nulib2-3.1.0/nufxlib/install-sh000077500000000000000000000127361316100516500163700ustar00rootroot00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 nulib2-3.1.0/nufxlib/mkinstalldirs000077500000000000000000000012761316100516500171670ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Last modified: 1995-03-05 # Public domain errstatus=0 for file in ${1+"$@"} ; do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? fi if test ! -d "$pathcomp"; then errstatus=$lasterr fi pathcomp="$pathcomp/" done done exit $errstatus nulib2-3.1.0/nufxlib/nufxlib.def000066400000000000000000000033741316100516500165110ustar00rootroot00000000000000; NufxLib library exported symbols ; ; This is redundant with the __declspec(dllexport) declarations enabled ; with the NUFXLIB_EXPORTS symbol. If we're just building a DLL, there's ; no need for this file. However, the objects we're building are used for ; both the static library and the dynamic library, and we don't want to ; have exports in the static library. If we do, the linker will create ; .lib and .exp files for every executable we link against it. This is ; mostly harmless, but a tad messy. I don't expect the interface to change, ; so there's not much of a maintenance burden here. ; EXPORTS NuAbort NuAddFile NuAddRecord NuAddThread NuClose NuContents NuConvertMORToUNI NuConvertUNIToMOR NuCreateDataSinkForBuffer NuCreateDataSinkForFP NuCreateDataSinkForFile NuCreateDataSourceForBuffer NuCreateDataSourceForFP NuCreateDataSourceForFile NuDataSinkGetOutCount NuDataSourceSetRawCrc NuDebugDumpArchive NuDelete NuDeleteRecord NuDeleteThread NuExtract NuExtractRecord NuExtractThread NuFlush NuFreeDataSink NuFreeDataSource NuGetAttr NuGetExtraData NuGetMasterHeader NuGetRecord NuGetRecordIdxByName NuGetRecordIdxByPosition NuGetValue NuGetVersion NuIsPresizedThreadID NuOpenRO NuOpenRW NuRecordCopyAttr NuRecordCopyThreads NuRecordGetNumThreads NuRename NuSetErrorHandler NuSetErrorMessageHandler NuSetExtraData NuSetGlobalErrorMessageHandler NuSetOutputPathnameFilter NuSetProgressUpdater NuSetRecordAttr NuSetSelectionFilter NuSetValue NuStrError NuStreamOpenRO NuTest NuTestFeature NuTestRecord NuThreadGetByIdx NuUpdatePresizedThread nulib2-3.1.0/nufxlib/samples/000077500000000000000000000000001316100516500160175ustar00rootroot00000000000000nulib2-3.1.0/nufxlib/samples/Common.h000066400000000000000000000025401316100516500174210ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * Common functions for NuLib tests. */ #ifndef NUFXLIB_SAMPLES_COMMON_H #define NUFXLIB_SAMPLES_COMMON_H #include "SysDefs.h" /* might as well draft off the autoconf */ #include "NufxLib.h" #ifdef USE_DMALLOC # include "dmalloc.h" #endif #define NELEM(x) (sizeof(x) / sizeof((x)[0])) #ifndef __cplusplus #define false 0 #define true (!false) #endif #ifdef FOPEN_WANTS_B # define kNuFileOpenReadOnly "rb" # define kNuFileOpenReadWrite "r+b" # define kNuFileOpenWriteTrunc "wb" # define kNuFileOpenReadWriteCreat "w+b" #else # define kNuFileOpenReadOnly "r" # define kNuFileOpenReadWrite "r+" # define kNuFileOpenWriteTrunc "w" # define kNuFileOpenReadWriteCreat "w+" #endif /* * Figure out what path separator to use. * * NOTE: recent versions of Win32 will also accept '/'. */ #ifdef MSDOS # define PATH_SEP '\\' #endif #ifdef WIN32 # define PATH_SEP '\\' #endif #ifdef MACOS # define PATH_SEP ':' #endif #if defined(APW) || defined(__ORCAC__) # define PATH_SEP ':' #endif #ifndef PATH_SEP # define PATH_SEP '/' #endif #endif /*NUFXLIB_SAMPLES_COMMON_H*/ nulib2-3.1.0/nufxlib/samples/Exerciser.c000066400000000000000000001144641316100516500201260ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * NufxLib exerciser. Most library functions can be invoked directly from * the exerciser command line. * * This was written in C++ to evaluate the interaction between NufxLib and * the C++ language, i.e. to make sure that all type definitions and * function calls can be used without giving the compiler fits. This * file will compile as either "Exerciser.c" or "Exerciser.cpp". */ #include "NufxLib.h" #include "Common.h" #include /* not portable to other OSs, but not all that important anyway */ static const char kFssep = PATH_SEP; /* ProDOS access permissions */ #define kUnlocked 0xe3 #define kTempFile "exer-temp" #ifndef HAVE_STRCASECMP static int strcasecmp(const char *str1, const char *str2) { while (*str1 && *str2 && toupper(*str1) == toupper(*str2)) str1++, str2++; return (toupper(*str1) - toupper(*str2)); } #endif /* * =========================================================================== * ExerciserState object * =========================================================================== */ /* * Exerciser state. * * In case it isn't immediately apparent, this was written in C++ and * then converted back to C. */ typedef struct ExerciserState { NuArchive* pArchive; char* archivePath; const char* archiveFile; } ExerciserState; ExerciserState* ExerciserState_New(void) { ExerciserState* pExerState; pExerState = (ExerciserState*) malloc(sizeof(*pExerState)); if (pExerState == NULL) return NULL; pExerState->pArchive = NULL; pExerState->archivePath = NULL; pExerState->archiveFile = NULL; return pExerState; } void ExerciserState_Free(ExerciserState* pExerState) { if (pExerState == NULL) return; if (pExerState->pArchive != NULL) { printf("Exerciser: aborting open archive\n"); (void) NuAbort(pExerState->pArchive); (void) NuClose(pExerState->pArchive); } if (pExerState->archivePath != NULL) free(pExerState->archivePath); free(pExerState); } inline NuArchive* ExerciserState_GetNuArchive(const ExerciserState* pExerState) { return pExerState->pArchive; } inline void ExerciserState_SetNuArchive(ExerciserState* pExerState, NuArchive* newArchive) { pExerState->pArchive = newArchive; } inline char* ExerciserState_GetArchivePath(const ExerciserState* pExerState) { return pExerState->archivePath; } inline void ExerciserState_SetArchivePath(ExerciserState* pExerState, char* newPath) { if (pExerState->archivePath != NULL) free(pExerState->archivePath); if (newPath == NULL) { pExerState->archivePath = NULL; pExerState->archiveFile = NULL; } else { pExerState->archivePath = strdup(newPath); pExerState->archiveFile = strrchr(newPath, kFssep); if (pExerState->archiveFile != NULL) pExerState->archiveFile++; if (pExerState->archiveFile == NULL || *pExerState->archiveFile == '\0') pExerState->archiveFile = pExerState->archivePath; } } inline const char* ExerciserState_GetArchiveFile(const ExerciserState* pExerState) { if (pExerState->archiveFile == NULL) return "[no archive open]"; else return pExerState->archiveFile; } /* * =========================================================================== * Utility functions * =========================================================================== */ /* * NuContents callback function. Print the contents of an individual record. */ NuResult PrintEntry(NuArchive* pArchive, void* vpRecord) { const NuRecord* pRecord = (const NuRecord*) vpRecord; int idx; (void)pArchive; /* shut up, gcc */ printf("RecordIdx %u: '%s'\n", pRecord->recordIdx, pRecord->filenameMOR); for (idx = 0; idx < (int) pRecord->recTotalThreads; idx++) { const NuThread* pThread; NuThreadID threadID; const char* threadLabel; pThread = NuGetThread(pRecord, idx); assert(pThread != NULL); threadID = NuGetThreadID(pThread); switch (NuThreadIDGetClass(threadID)) { case kNuThreadClassMessage: threadLabel = "message class"; break; case kNuThreadClassControl: threadLabel = "control class"; break; case kNuThreadClassData: threadLabel = "data class"; break; case kNuThreadClassFilename: threadLabel = "filename class"; break; default: threadLabel = "(unknown class)"; break; } switch (threadID) { case kNuThreadIDComment: threadLabel = "comment"; break; case kNuThreadIDIcon: threadLabel = "icon"; break; case kNuThreadIDMkdir: threadLabel = "mkdir"; break; case kNuThreadIDDataFork: threadLabel = "data fork"; break; case kNuThreadIDDiskImage: threadLabel = "disk image"; break; case kNuThreadIDRsrcFork: threadLabel = "rsrc fork"; break; case kNuThreadIDFilename: threadLabel = "filename"; break; default: break; } printf(" ThreadIdx %u - 0x%08x (%s)\n", pThread->threadIdx, threadID, threadLabel); } return kNuOK; } #define kNiceLineLen 256 /* * Get a line of input, stripping the '\n' off the end. */ static NuError GetLine(const char* prompt, char* buffer, int bufferSize) { printf("%s> ", prompt); fflush(stdout); if (fgets(buffer, bufferSize, stdin) == NULL) return kNuErrGeneric; if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0'; return kNuErrNone; } /* * Selection filter for mass "extract" and "delete" operations. */ NuResult SelectionFilter(NuArchive* pArchive, void* vselFilt) { const NuSelectionProposal* selProposal = (NuSelectionProposal*) vselFilt; char buffer[8]; printf("%s (N/y)? ", selProposal->pRecord->filenameMOR); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) return kNuAbort; if (tolower(buffer[0]) == 'y') return kNuOK; else return kNuSkip; } /* * General-purpose error handler. */ NuResult ErrorHandler(NuArchive* pArchive, void* vErrorStatus) { const NuErrorStatus* pErrorStatus = (const NuErrorStatus*) vErrorStatus; char buffer[8]; NuResult result = kNuSkip; printf("Exerciser: error handler op=%d err=%d sysErr=%d message='%s'\n" "\tfilename='%s' '%c'(0x%02x)\n", pErrorStatus->operation, pErrorStatus->err, pErrorStatus->sysErr, pErrorStatus->message == NULL ? "(NULL)" : pErrorStatus->message, pErrorStatus->pathnameUNI, pErrorStatus->filenameSeparator, pErrorStatus->filenameSeparator); printf("\tValid options are:"); if (pErrorStatus->canAbort) printf(" a)bort"); if (pErrorStatus->canRetry) printf(" r)etry"); if (pErrorStatus->canIgnore) printf(" i)gnore"); if (pErrorStatus->canSkip) printf(" s)kip"); if (pErrorStatus->canRename) printf(" re)name"); if (pErrorStatus->canOverwrite) printf(" o)verwrite"); putc('\n', stdout); printf("Return what (a/r/i/s/e/o)? "); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { printf("Returning kNuSkip\n"); } else switch (buffer[0]) { case 'a': result = kNuAbort; break; case 'r': result = kNuRetry; break; case 'i': result = kNuIgnore; break; case 's': result = kNuSkip; break; case 'e': result = kNuRename; break; case 'o': result = kNuOverwrite; break; default: printf("Unknown value '%c', returning kNuSkip\n", buffer[0]); break; } return result; } /* * This gets called when a buffer DataSource is no longer needed. */ NuResult FreeCallback(NuArchive* pArchive, void* args) { free(args); return kNuOK; } /* * =========================================================================== * Command handlers * =========================================================================== */ typedef NuError (*CommandFunc)(ExerciserState* pState, int argc, char** argv); static NuError HelpFunc(ExerciserState* pState, int argc, char** argv); #if 0 static NuError GenericFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ printf("Generic! argc=%d\n", argc); return kNuErrNone; } #endif /* * Do nothing. Useful when the user just hits on a blank line. */ static NuError NothingFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ return kNuErrNone; } /* * q - quit * * Do nothing. This is used as a trigger for quitting the program. In * practice, we catch this earlier, and won't actually call here. */ static NuError QuitFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(0); return kNuErrNone; } /* * ab - abort current changes */ static NuError AbortFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 1); return NuAbort(ExerciserState_GetNuArchive(pState)); } /* * af - add file to archive */ static NuError AddFileFunc(ExerciserState* pState, int argc, char** argv) { NuFileDetails nuFileDetails; int fromRsrc = false; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 3); if (strcasecmp(argv[2], "true") == 0) { fromRsrc = true; } else if (strcasecmp(argv[2], "false") != 0) { fprintf(stderr, "WARNING: fromRsrc should be 'true' or 'false'\n"); /* ignore */ } memset(&nuFileDetails, 0, sizeof(nuFileDetails)); if (fromRsrc) { nuFileDetails.threadID = kNuThreadIDRsrcFork; } else { 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, fromRsrc, NULL); } /* * 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) != NULL); assert(argc == 2); memset(&nuFileDetails, 0, sizeof(nuFileDetails)); nuFileDetails.threadID = 0; /* irrelevant */ nuFileDetails.storageNameMOR = 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=%u\n", recordIdx); return err; } /* * at - add thread to record */ static NuError AddThreadFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuDataSource* pDataSource = NULL; char* lineBuf = NULL; long ourLen, maxLen; NuThreadID threadID; NuThreadIdx threadIdx; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 3); lineBuf = (char*)malloc(kNiceLineLen); assert(lineBuf != NULL); threadID = strtol(argv[2], NULL, 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, NULL, 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, (uint8_t*)lineBuf, 0, ourLen, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: buffer data source create failed (err=%d)\n", err); goto bail; } lineBuf = NULL; /* now owned by the library */ } err = NuAddThread(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0), threadID, pDataSource, &threadIdx); if (err == kNuErrNone) { pDataSource = NULL; /* library owns it now */ printf("Exerciser: success; function returned threadIdx=%u\n", threadIdx); } bail: NuFreeDataSource(pDataSource); if (lineBuf != NULL) free(lineBuf); 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; } /* * d - delete all records (selection-filtered) */ static NuError DeleteFunc(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 NuDelete(ExerciserState_GetNuArchive(pState)); } /* * dr - delete record */ static NuError DeleteRecordFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 2); return NuDeleteRecord(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0)); } /* * 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) != NULL); assert(argc == 2); return NuDeleteThread(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0)); } /* * 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)); } /* * er - extract record */ static NuError ExtractRecordFunc(ExerciserState* pState, int argc, char** argv) { (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); assert(argc == 2); return NuExtractRecord(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0)); } /* * et - extract thread */ static NuError ExtractThreadFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuDataSink* pDataSink = NULL; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != NULL); 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], NULL, 0), pDataSink); /* fall through with err */ bail: NuFreeDataSink(pDataSink); return err; } /* * 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; } /* * 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) != NULL); assert(argc == 1); err = NuGetMasterHeader(ExerciserState_GetNuArchive(pState), &pMasterHeader); if (err == kNuErrNone) { printf("Exerciser: success (version=%u, totalRecords=%u, EOF=%u)\n", pMasterHeader->mhMasterVersion, pMasterHeader->mhTotalRecords, pMasterHeader->mhMasterEOF); } return err; } /* * 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) != NULL); assert(argc == 2); err = NuGetRecord(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 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%02x\n", pRecord->recAccess); printf("\tfileType : 0x%04x\n", pRecord->recFileType); printf("\textraType : 0x%04x\n", pRecord->recExtraType); printf("\tcreateWhen : ...\n"); printf("\tmodWhen : ...\n"); /* too lazy */ printf("\tarchiveWhen : ...\n"); } 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; } /* * 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) != NULL); assert(argc == 2); err = NuGetRecordIdxByPosition(ExerciserState_GetNuArchive(pState), strtol(argv[1], NULL, 0), &recIdx); if (err == kNuErrNone) printf("Exerciser: success, returned recordIdx=%u\n", recIdx); return err; } /* * ocrw - open/create read-write */ static NuError OpenCreateReadWriteFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuArchive* pArchive; assert(ExerciserState_GetNuArchive(pState) == NULL); assert(argc == 2); err = NuOpenRW(argv[1], kTempFile, kNuOpenCreat|kNuOpenExcl, &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) == NULL); assert(argc == 2); err = NuOpenRO(argv[1], &pArchive); if (err == kNuErrNone) { ExerciserState_SetNuArchive(pState, pArchive); ExerciserState_SetArchivePath(pState, argv[1]); } return err; } /* * ors - open streaming read-only */ static NuError OpenStreamingReadOnlyFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuArchive* pArchive; FILE* fp = NULL; assert(ExerciserState_GetNuArchive(pState) == NULL); assert(argc == 2); if ((fp = fopen(argv[1], kNuFileOpenReadOnly)) == NULL) { 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 = NULL; } } if (fp != NULL) fclose(fp); return err; } /* * 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; } /* * 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); } /* * 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) != NULL); assert(argc == 1); return NuDebugDumpArchive(ExerciserState_GetNuArchive(pState)); } /* * 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) != NULL); assert(argc == 1); NuSetErrorHandler(ExerciserState_GetNuArchive(pState), ErrorHandler); return kNuErrNone; } /* * 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)); } /* * 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); } /* * 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)); } /* * 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)); } /* * 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; } /* * Command table. This drives the user interface. */ /* flags for the CommandTable */ #define kFlagArchiveReq (1L) /* must have archive open */ #define kFlagNoArchiveReq (1L<<1) /* must NOT have archive open */ /* command set */ static const struct { const char* commandStr; CommandFunc func; int expectedArgCount; const char* argumentList; uint32_t flags; const char* description; } gCommandTable[] = { { "--- exerciser commands ---", HelpFunc, 0, "", 0, "" }, { "?", HelpFunc, 0, "", 0, "Show help" }, { "h", HelpFunc, 0, "", 0, "Show help" }, { "q", QuitFunc, 0, "", 0, "Quit program (will abort un-flushed changes)" }, { "--- archive commands ---", HelpFunc, 0, "", 0, "" }, { "ab", AbortFunc, 0, "", kFlagArchiveReq, "Abort current changes" }, { "af", AddFileFunc, 2, "filename fromRsrc", kFlagArchiveReq, "Add file" }, { "ar", AddRecordFunc, 1, "storageName", kFlagArchiveReq, "Add record" }, { "at", AddThreadFunc, 2, "recordIdx threadID", kFlagArchiveReq, "Add thread to record" }, { "cl", CloseFunc, 0, "", kFlagArchiveReq, "Close archive after flushing any changes" }, { "d", DeleteFunc, 0, "", kFlagArchiveReq, "Delete all records" }, { "dr", DeleteRecordFunc, 1, "recordIdx", kFlagArchiveReq, "Delete record" }, { "dt", DeleteThreadFunc, 1, "threadIdx", kFlagArchiveReq, "Delete thread" }, { "e", ExtractFunc, 0, "", kFlagArchiveReq, "Extract all files" }, { "er", ExtractRecordFunc, 1, "recordIdx", kFlagArchiveReq, "Extract record" }, { "et", ExtractThreadFunc, 2, "threadIdx filename", kFlagArchiveReq, "Extract thread" }, { "fl", FlushFunc, 0, "", kFlagArchiveReq, "Flush changes" }, { "gev", GetValueFunc, 1, "ident", kFlagArchiveReq, "Get value" }, { "gmh", GetMasterHeaderFunc, 0, "", kFlagArchiveReq, "Get master header" }, { "gr", GetRecordFunc, 1, "recordIdx", kFlagArchiveReq, "Get record" }, { "grin", GetRecordIdxByNameFunc, 1, "name", kFlagArchiveReq, "Get recordIdx by name" }, { "grip", GetRecordIdxByPositionFunc, 1, "position", kFlagArchiveReq, "Get recordIdx by position" }, { "ocrw", OpenCreateReadWriteFunc, 1, "filename", kFlagNoArchiveReq, "Open/create archive read-write" }, { "oro", OpenReadOnlyFunc, 1, "filename", kFlagNoArchiveReq, "Open archive read-only" }, { "ors", OpenStreamingReadOnlyFunc, 1, "filename", kFlagNoArchiveReq, "Open archive streaming read-only" }, { "orw", OpenReadWriteFunc, 1, "filename", kFlagNoArchiveReq, "Open archive read-write" }, { "p", PrintFunc, 0, "", kFlagArchiveReq, "Print archive contents" }, { "pd", PrintDebugFunc, 0, "", kFlagArchiveReq, "Print debugging output (if available)" }, { "re", RenameFunc, 3, "recordIdx name sep", kFlagArchiveReq, "Rename record" }, { "sec", SetErrorCallbackFunc, 0, "", kFlagArchiveReq, "Set error callback" }, { "sev", SetValueFunc, 2, "ident value", kFlagArchiveReq, "Set value" }, { "sra", SetRecordAttrFunc, 3, "recordIdx type aux", kFlagArchiveReq, "Set record attributes" }, { "t", TestFunc, 0, "", kFlagArchiveReq, "Test archive" }, { "tr", TestRecordFunc, 1, "recordIdx", kFlagArchiveReq, "Test record" }, { "upt", UpdatePresizedThreadFunc, 1, "threadIdx", kFlagArchiveReq, "Update pre-sized thread" }, }; #define kMaxArgs 4 /* * Display a summary of available commands. */ static NuError HelpFunc(ExerciserState* pState, int argc, char** argv) { int i; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ printf("\nAvailable commands:\n"); for (i = 0; i < (int)NELEM(gCommandTable); i++) { printf(" %-4s %-21s %s\n", gCommandTable[i].commandStr, gCommandTable[i].argumentList, gCommandTable[i].description); } return kNuErrNone; } /* * =========================================================================== * Control * =========================================================================== */ static const char* kWhitespace = " \t\n"; /* * 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 == NULL) { /* no command; the user probably just hit "enter" on a blank line */ *pFunc = NothingFunc; *pArgc = 0; *pArgv = NULL; err = kNuErrNone; goto bail; } /* no real need to be flexible; add 1 for command and one for NULL */ *pArgv = (char**) malloc(sizeof(char*) * (kMaxArgs+2)); (*pArgv)[0] = command; *pArgc = 1; cp = strtok(NULL, kWhitespace); while (cp != NULL) { if (*pArgc >= kMaxArgs+1) { printf("ERROR: too many arguments\n"); goto bail; } (*pArgv)[*pArgc] = cp; (*pArgc)++; cp = strtok(NULL, kWhitespace); } assert(*pArgc < kMaxArgs+2); (*pArgv)[*pArgc] = NULL; /* * 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) == NULL) { printf("ERROR: must have an archive open\n"); goto bail; } } if (gCommandTable[i].flags & kFlagNoArchiveReq) { if (ExerciserState_GetNuArchive(pState) != NULL) { 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 = NULL; while (1) { printf("\nEnter command (%s)> ", ExerciserState_GetArchiveFile(pState)); fflush(stdout); if (fgets(lineBuf, sizeof(lineBuf), stdin) == NULL) { printf("\n"); break; } if (argv != NULL) { free(argv); argv = NULL; } func = NULL; /* sanity check */ err = ParseLine(lineBuf, pState, &func, &argc, &argv); if (err != kNuErrNone) continue; assert(func != NULL); 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 != NULL) { free(argv); argv = NULL; } } if (ExerciserState_GetNuArchive(pState) != NULL) { /* 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, NULL); } if (pState != NULL) ExerciserState_Free(pState); if (argv != NULL) free(argv); return kNuErrNone; } /* * Main entry point. * * We don't currently take any arguments, so this is pretty straightforward. */ int main(void) { NuError result; int32_t majorVersion, minorVersion, bugVersion; const char* nufxLibDate; const char* nufxLibFlags; (void) NuGetVersion(&majorVersion, &minorVersion, &bugVersion, &nufxLibDate, &nufxLibFlags); printf("NufxLib exerciser, linked with NufxLib v%d.%d.%d [%s]\n\n", majorVersion, minorVersion, bugVersion, nufxLibFlags); printf("Use 'h' or '?' for help, 'q' to quit.\n"); /* stuff useful when debugging lots */ if (unlink(kTempFile) == 0) fprintf(stderr, "NOTE: whacked exer-temp\n"); if (unlink("new.shk") == 0) fprintf(stderr, "NOTE: whacked new.shk\n"); #if defined(HAS_MALLOC_CHECK_) && !defined(USE_DMALLOC) /* * This is really nice to have on Linux and any other system that * uses the GNU libc/malloc stuff. It slows things down, but it * tells you when you do something dumb with malloc/realloc/free. * (Solaris 2.7 has a similar feature that is enabled by setting the * environment variable LD_PRELOAD to include watchmalloc.so. Other * OSs and 3rd-party malloc packages may have similar features.) * * This environment variable must be set when the program is launched. * Tweaking the environment within the program has no effect. * * Now that the Linux world has "valgrind", this is probably * unnecessary. */ { char* debugSet = getenv("MALLOC_CHECK_"); if (debugSet == NULL) printf("WARNING: MALLOC_CHECK_ not enabled\n\n"); } #endif result = CommandLoop(); exit(result != kNuErrNone); } nulib2-3.1.0/nufxlib/samples/ImgConv.c000066400000000000000000000442541316100516500175360ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * 2IMG <-> SHK converter. This is a practical example of using the * NufxLib Thread functions to add and extract data in the middle of a file. * * Conversions from 2IMG files do not work for raw nibble images. * Conversions from SHK archives only work if the disk image is in the * first record in the archive. (This is easy to fix, but I'm trying to * keep it simple.) */ #include "NufxLib.h" #include "Common.h" #ifndef HAVE_STRCASECMP static int strcasecmp(const char *str1, const char *str2) { while (*str1 && *str2 && toupper(*str1) == toupper(*str2)) str1++, str2++; return (toupper(*str1) - toupper(*str2)); } #endif #define kTempFile "imgconv.tmp" #define kLocalFssep PATH_SEP #define false 0 #define true (!false) /* * =========================================================================== * 2IMG stuff * =========================================================================== */ #define kImgMagic "2IMG" #define kMyCreator "NFXL" #define kImageFormatDOS 0 #define kImageFormatProDOS 1 #define kImageFormatNibble 2 /* * 2IMG header definition (http://www.magnet.ch/emutech/Tech/). */ typedef struct ImgHeader { char magic[4]; char creator[4]; uint16_t headerLen; uint16_t version; uint32_t imageFormat; uint32_t flags; uint32_t numBlocks; uint32_t dataOffset; uint32_t dataLen; uint32_t cmntOffset; uint32_t cmntLen; uint32_t creatorOffset; uint32_t creatorLen; uint32_t spare[4]; } ImgHeader; /* * Read a two-byte little-endian value. */ void ReadShortLE(FILE* fp, uint16_t* pBuf) { *pBuf = getc(fp); *pBuf += (uint16_t) getc(fp) << 8; } /* * Write a two-byte little-endian value. */ void WriteShortLE(FILE* fp, uint16_t val) { putc(val, fp); putc(val >> 8, fp); } /* * Read a four-byte little-endian value. */ void ReadLongLE(FILE* fp, uint32_t* pBuf) { *pBuf = getc(fp); *pBuf += (uint32_t) getc(fp) << 8; *pBuf += (uint32_t) getc(fp) << 16; *pBuf += (uint32_t) getc(fp) << 24; } /* * Write a four-byte little-endian value. */ void WriteLongLE(FILE* fp, uint32_t val) { putc(val, fp); putc(val >> 8, fp); putc(val >> 16, fp); putc(val >> 24, fp); } /* * Read the header from a 2IMG file. */ int ReadImgHeader(FILE* fp, ImgHeader* pHeader) { size_t ignored; ignored = fread(pHeader->magic, 4, 1, fp); ignored = fread(pHeader->creator, 4, 1, fp); ReadShortLE(fp, &pHeader->headerLen); ReadShortLE(fp, &pHeader->version); ReadLongLE(fp, &pHeader->imageFormat); ReadLongLE(fp, &pHeader->flags); ReadLongLE(fp, &pHeader->numBlocks); ReadLongLE(fp, &pHeader->dataOffset); ReadLongLE(fp, &pHeader->dataLen); ReadLongLE(fp, &pHeader->cmntOffset); ReadLongLE(fp, &pHeader->cmntLen); ReadLongLE(fp, &pHeader->creatorOffset); ReadLongLE(fp, &pHeader->creatorLen); ReadLongLE(fp, &pHeader->spare[0]); ReadLongLE(fp, &pHeader->spare[1]); ReadLongLE(fp, &pHeader->spare[2]); ReadLongLE(fp, &pHeader->spare[3]); (void) ignored; if (feof(fp) || ferror(fp)) return -1; if (strncmp(pHeader->magic, kImgMagic, 4) != 0) { fprintf(stderr, "ERROR: bad magic number on 2IMG file\n"); return -1; } if (pHeader->version > 1) { fprintf(stderr, "WARNING: might not be able to handle version=%d\n", pHeader->version); } return 0; } /* * Write the header to a 2IMG file. */ int WriteImgHeader(FILE* fp, ImgHeader* pHeader) { fwrite(pHeader->magic, 4, 1, fp); fwrite(pHeader->creator, 4, 1, fp); WriteShortLE(fp, pHeader->headerLen); WriteShortLE(fp, pHeader->version); WriteLongLE(fp, pHeader->imageFormat); WriteLongLE(fp, pHeader->flags); WriteLongLE(fp, pHeader->numBlocks); WriteLongLE(fp, pHeader->dataOffset); WriteLongLE(fp, pHeader->dataLen); WriteLongLE(fp, pHeader->cmntOffset); WriteLongLE(fp, pHeader->cmntLen); WriteLongLE(fp, pHeader->creatorOffset); WriteLongLE(fp, pHeader->creatorLen); WriteLongLE(fp, pHeader->spare[0]); WriteLongLE(fp, pHeader->spare[1]); WriteLongLE(fp, pHeader->spare[2]); WriteLongLE(fp, pHeader->spare[3]); if (ferror(fp)) return -1; return 0; } /* * Dump the contents of an ImgHeader. */ void DumpImgHeader(ImgHeader* pHeader) { printf("--- header contents:\n"); printf("\tmagic = '%.4s'\n", pHeader->magic); printf("\tcreator = '%.4s'\n", pHeader->creator); printf("\theaderLen = %d\n", pHeader->headerLen); printf("\tversion = %d\n", pHeader->version); printf("\timageFormat = %u\n", pHeader->imageFormat); printf("\tflags = 0x%08x\n", pHeader->flags); printf("\tnumBlocks = %u\n", pHeader->numBlocks); printf("\tdataOffset = %u\n", pHeader->dataOffset); printf("\tdataLen = %u\n", pHeader->dataLen); printf("\tcmntOffset = %u\n", pHeader->cmntOffset); printf("\tcmntLen = %u\n", pHeader->cmntLen); printf("\tcreatorOffset = %u\n", pHeader->creatorOffset); printf("\tcreatorLen = %u\n", pHeader->creatorLen); printf("\n"); } /* * =========================================================================== * Main functions * =========================================================================== */ typedef enum ArchiveKind { kKindUnknown, kKindShk, kKindImg } ArchiveKind; /* * This gets called when a buffer DataSource is no longer needed. */ NuResult FreeCallback(NuArchive* pArchive, void* args) { free(args); return kNuOK; } /* * This gets called when an "FP" DataSource is no longer needed. */ NuResult FcloseCallback(NuArchive* pArchive, void* args) { fclose((FILE*) args); return kNuOK; } /* * Create a data source for a ProDOS-ordered image. Since this is already * in the correct format, we just point at the correct offset in the 2MG file. * * This supplies an FcloseCallback so that we can exercise that feature * of NufxLib. We could just as easily not set it and call fclose() * ourselves, because the structure of this program is pretty simple. */ NuError CreateProdosSource(const ImgHeader* pHeader, FILE* fp, NuDataSource** ppDataSource) { return NuCreateDataSourceForFP(kNuThreadFormatUncompressed, 0, fp, pHeader->dataOffset, pHeader->dataLen, FcloseCallback,ppDataSource); } /* * Create a data source for a DOS-ordered image. This is a little harder, * since we have to reorder the blocks into ProDOS ordering for ShrinkIt. */ NuError CreateDosSource(const ImgHeader* pHeader, FILE* fp, NuDataSource** ppDataSource) { NuError err; char* diskBuffer = NULL; long offset; if (pHeader->dataLen % 4096) { fprintf(stderr, "ERROR: image size must be multiple of 4096 (%u isn't)\n", pHeader->dataLen); err = kNuErrGeneric; goto bail; } if (fseek(fp, pHeader->dataOffset, SEEK_SET) < 0) { err = errno; perror("fseek failed"); goto bail; } diskBuffer = malloc(pHeader->dataLen); if (diskBuffer == NULL) { fprintf(stderr, "ERROR: malloc(%u) failed\n", pHeader->dataLen); err = kNuErrMalloc; goto bail; } /* * Run through the image, reordering each track. This is a * reversible transformation, i.e. if you do this twice you're back * to ProDOS ordering. */ for (offset = 0; offset < (long) pHeader->dataLen; offset += 4096) { size_t ignored; ignored = fread(diskBuffer + offset + 0x0000, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0e00, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0d00, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0c00, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0b00, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0a00, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0900, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0800, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0700, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0600, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0500, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0400, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0300, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0200, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0100, 256, 1, fp); ignored = fread(diskBuffer + offset + 0x0f00, 256, 1, fp); (void) ignored; } if (feof(fp) || ferror(fp)) { err = errno ? errno : -1; fprintf(stderr, "ERROR: failed while reading source file\n"); goto bail; } /* * Create a data source for the buffer. We set the "doClose" flag to * "true", so NufxLib will free the buffer for us. */ err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, (const uint8_t*) diskBuffer, 0, pHeader->dataLen, FreeCallback, ppDataSource); if (err == kNuErrNone) diskBuffer = NULL; bail: if (diskBuffer != NULL) free(diskBuffer); return err; } /* * Convert a 2IMG file into a new SHK archive. * * This requires opening up the 2IMG file, verifying that it's okay, and * then creating a new disk image record and thread. */ int ConvertFromImgToShk(const char* srcName, const char* dstName) { NuError err; NuArchive* pArchive = NULL; NuDataSource* pDataSource = NULL; NuRecordIdx recordIdx; NuFileDetails fileDetails; ImgHeader header; FILE* fp = NULL; uint32_t flushStatus; char* storageName = NULL; char* cp; printf("Converting 2IMG file '%s' to ShrinkIt archive '%s'\n\n", srcName, dstName); err = kNuErrGeneric; fp = fopen(srcName, kNuFileOpenReadOnly); if (fp == NULL) { perror("fopen failed"); goto bail; } if (ReadImgHeader(fp, &header) < 0) { fprintf(stderr, "ERROR: header read failed\n"); goto bail; } DumpImgHeader(&header); if (header.imageFormat != kImageFormatDOS && header.imageFormat != kImageFormatProDOS) { fprintf(stderr, "ERROR: can only handle DOS and ProDOS images\n"); goto bail; } if (header.numBlocks > 1600) printf("WARNING: that's a big honking image!\n"); /* * Open a new archive read-write. This refuses to overwrite an * existing file. */ (void) unlink(kTempFile); err = NuOpenRW(dstName, kTempFile, kNuOpenCreat|kNuOpenExcl, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create archive (err=%d)\n", err); goto bail; } /* create the name that will be stored in the archive */ storageName = strdup(dstName); cp = strrchr(storageName, '.'); if (cp != NULL) *cp = '\0'; cp = strrchr(storageName, kLocalFssep); if (cp != NULL && *(cp+1) != '\0') cp++; else cp = storageName; /* * We can't say "add file", because NufxLib doesn't know what a 2MG * archive is. However, we can point a DataSource at the data in * the file, and construct the record manually. */ /* set up the contents of the NuFX Record */ memset(&fileDetails, 0, sizeof(fileDetails)); fileDetails.storageNameMOR = cp; fileDetails.fileSysID = kNuFileSysUnknown; /* DOS? ProDOS? */ fileDetails.fileSysInfo = kLocalFssep; fileDetails.access = kNuAccessUnlocked; fileDetails.extraType = header.numBlocks; fileDetails.storageType = 512; /* FIX - ought to set the file dates */ /* add a new record */ err = NuAddRecord(pArchive, &fileDetails, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create record (err=%d)\n", err); goto bail; } /* * Create a data source for the 2IMG file. We do this differently * for DOS and ProDOS, because we have to rearrange the sector * ordering for DOS-ordered images (ShrinkIt always uses ProDOS order). */ switch (header.imageFormat) { case kImageFormatDOS: err = CreateDosSource(&header, fp, &pDataSource); fp = NULL; break; case kImageFormatProDOS: err = CreateProdosSource(&header, fp, &pDataSource); fp = NULL; break; default: fprintf(stderr, "How the heck did I get here?"); err = kNuErrInternal; goto bail; } if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data source (err=%d)\n", err); goto bail; } /* add a disk image thread */ err = NuAddThread(pArchive, recordIdx, kNuThreadIDDiskImage, pDataSource, NULL); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create thread (err=%d)\n", err); goto bail; } pDataSource = NULL; /* library owns it now */ /* nothing happens until we Flush */ err = NuFlush(pArchive, &flushStatus); if (err != kNuErrNone) { fprintf(stderr, "ERROR: flush failed (err=%d, status=0x%04x)\n", err, flushStatus); goto bail; } err = NuClose(pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: close failed (err=%d)\n", err); goto bail; } pArchive = NULL; bail: if (pArchive != NULL) { (void)NuAbort(pArchive); (void)NuClose(pArchive); } NuFreeDataSource(pDataSource); if (storageName != NULL) free(storageName); if (fp != NULL) fclose(fp); return (err == kNuErrNone) ? 0 : -1; } /* * Convert an SHK archive into a 2IMG file. * * This takes a simple-minded approach and assumes that the first record * in the archive has the disk image in it. If it doesn't, we give up. */ int ConvertFromShkToImg(const char* srcName, const char* dstName) { NuError err; NuArchive* pArchive = NULL; NuDataSink* pDataSink = NULL; NuRecordIdx recordIdx; const NuRecord* pRecord; const NuThread* pThread = NULL; ImgHeader header; FILE* fp = NULL; int idx; printf("Converting ShrinkIt archive '%s' to 2IMG file '%s'\n\n", srcName, dstName); /* * Open the archive. */ err = NuOpenRO(srcName, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to open archive (err=%d)\n", err); goto bail; } /* get the first record */ err = NuGetRecordIdxByPosition(pArchive, 0, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to get first recordIdx (err=%d)\n", err); goto bail; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to get first record (err=%d)\n", err); goto bail; } /* find a disk image thread */ for (idx = 0; idx < (int)NuRecordGetNumThreads(pRecord); idx++) { pThread = NuGetThread(pRecord, idx); if (NuGetThreadID(pThread) == kNuThreadIDDiskImage) break; } if (idx == (int)NuRecordGetNumThreads(pRecord)) { fprintf(stderr, "ERROR: no disk image found in first record\n"); err = -1; goto bail; } /* * Looks good. Open the 2IMG file, and create the header. */ if (access(dstName, F_OK) == 0) { fprintf(stderr, "ERROR: output file already exists\n"); err = -1; goto bail; } fp = fopen(dstName, kNuFileOpenWriteTrunc); if (fp == NULL) { perror("fopen failed"); goto bail; } /* set up the 2MG header, based on the NuFX Record */ memset(&header, 0, sizeof(header)); memcpy(header.magic, kImgMagic, sizeof(header.magic)); memcpy(header.creator, kMyCreator, sizeof(header.creator)); header.headerLen = 64; header.version = 1; header.imageFormat = kImageFormatProDOS; /* always ProDOS-order */ header.numBlocks = pRecord->recExtraType; header.dataOffset = 64; /* old versions of ShrinkIt blew the threadEOF, so use NufxLib's "actual" */ header.dataLen = pThread->actualThreadEOF; DumpImgHeader(&header); if (WriteImgHeader(fp, &header) < 0) { fprintf(stderr, "ERROR: header write failed\n"); err = -1; goto bail; } /* * We want to expand the disk image thread into "fp" at the current * offset. */ err = NuCreateDataSinkForFP(true, kNuConvertOff, fp, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data sink (err=%d)\n", err); goto bail; } err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to extract thread (err=%d)\n", err); goto bail; } bail: if (pArchive != NULL) NuClose(pArchive); NuFreeDataSink(pDataSink); if (fp != NULL) fclose(fp); return (err == kNuErrNone) ? 0 : -1; } /* * Figure out what kind of archive this is by looking at the filename. */ ArchiveKind DetermineKind(const char* filename) { const char* dot; dot = strrchr(filename, '.'); if (dot == NULL) return kKindUnknown; if (strcasecmp(dot, ".shk") == 0 || strcasecmp(dot, ".sdk") == 0) return kKindShk; else if (strcasecmp(dot, ".2mg") == 0) return kKindImg; return kKindUnknown; } /* * Figure out what we want to do. */ int main(int argc, char** argv) { ArchiveKind kind; int cc; if (argc != 3) { fprintf(stderr, "Usage: %s (input.2mg|input.shk) output\n", argv[0]); exit(2); } kind = DetermineKind(argv[1]); if (kind == kKindUnknown) { fprintf(stderr, "ERROR: input name must end in '.shk' or '.2mg'\n"); exit(2); } if (kind == kKindShk) cc = ConvertFromShkToImg(argv[1], argv[2]); else cc = ConvertFromImgToShk(argv[1], argv[2]); if (cc) fprintf(stderr, "Failed\n"); else printf("Done!\n"); exit(cc != 0); } nulib2-3.1.0/nufxlib/samples/Launder.c000066400000000000000000000550711316100516500175650ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * Run an archive through the laundry. The net result is a duplicate * archive that matches the original in most respects. Extracting the * files from the duplicate will yield the same results as if they were * extracted from the original, but the duplicate archive may differ * in subtle ways (e.g. filename threads may be added, data may be * recompressed). * * This demonstrates copying threads around, both with and without * recompressing, between two archives that are open simultaneously. This * also tests NufxLib's thread ordering and verifies that you can abort * frequently with no adverse effects. * * NOTE: depending on the options you select, you may need to have enough * memory to hold the entire uncompressed contents of the original archive. * The memory requirements are reduced if you use the "copy only" flag, and * are virtually eliminated if you use "frequent flush". */ #include #include #include #include #include "NufxLib.h" #include "Common.h" #define kTempFile "tmp-laundry" #define kFlagCopyOnly (1) #define kFlagReverseThreads (1 << 1) #define kFlagFrequentFlush (1 << 2) #define kFlagFrequentAbort (1 << 3) /* implies FrequentFlush */ #define kFlagUseTmp (1 << 4) /* * Globals. */ char gSentRecordWarning = false; /* * This gets called when a buffer DataSource is no longer needed. */ NuResult FreeCallback(NuArchive* pArchive, void* args) { free(args); return kNuOK; } /* * Copy a thread, expanding and recompressing it. * * This assumes the library is configured for compression (it defaults * to LZW/2, so this is a reasonable assumption). */ NuError CopyThreadRecompressed(NuArchive* pInArchive, NuArchive* pOutArchive, long flags, const NuThread* pThread, long newRecordIdx) { NuError err = kNuErrNone; NuDataSource* pDataSource = NULL; NuDataSink* pDataSink = NULL; uint8_t* buffer = NULL; /* * Allocate a buffer large enough to hold all the uncompressed data, and * wrap a data sink around it. * * If the thread is zero bytes long, we can skip this part. */ if (pThread->actualThreadEOF) { buffer = malloc(pThread->actualThreadEOF); if (buffer == NULL) { err = kNuErrMalloc; goto bail; } err = NuCreateDataSinkForBuffer(true, kNuConvertOff, buffer, pThread->actualThreadEOF, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data sink (err=%d)\n", err); goto bail; } /* * Expand the data. For a pre-sized thread, this grabs only the * interesting part of the buffer. */ err = NuExtractThread(pInArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to extract thread %u (err=%d)\n", pThread->threadIdx, err); goto bail; } } /* * The expanded data is in the buffer, now create a data source that * describes it. * * This is complicated by the existence of pre-sized threads, which * require us to set "otherLen". * * We always use "actualThreadEOF" because "thThreadEOF" is broken * for disk archives created by certain versions of ShrinkIt. * * It's okay to pass in a NULL value for "buffer", so long as the * amount of data in the buffer is also zero. The library will do * the right thing. */ if (NuIsPresizedThreadID(NuGetThreadID(pThread))) { err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, pThread->thCompThreadEOF, buffer, 0, pThread->actualThreadEOF, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create pre-sized data source (err=%d)\n",err); goto bail; } } else { err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, buffer, 0, pThread->actualThreadEOF, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data source (err=%d)\n", err); goto bail; } } buffer = NULL; /* doClose was set, so it's owned by the data source */ /* * Schedule the data for addition to the record. */ err = NuAddThread(pOutArchive, newRecordIdx, NuGetThreadID(pThread), pDataSource, NULL); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to add thread (err=%d)\n", err); goto bail; } pDataSource = NULL; /* library owns it now */ bail: if (pDataSource != NULL) NuFreeDataSource(pDataSource); if (pDataSink != NULL) NuFreeDataSink(pDataSink); if (buffer != NULL) free(buffer); return err; } /* * Copy a thread from one archive to another without disturbing the * compression. * * There is a much more efficient way to do this: create an FP * data source using an offset within the archive file itself. * Since pInArchive->archiveFp isn't exposed, we can't use that, * but under most operating systems you aren't prevented from * opening the same file twice in read-only mode. The file offset * in pThread tells us where the data is. * * The method used below is less memory-efficient but more portable. * * This always extracts based on the compThreadEOF, which is * reliable but extracts a little more than we need on pre-sized * threads (filenames, comments). */ NuError CopyThreadUncompressed(NuArchive* pInArchive, NuArchive* pOutArchive, long flags, const NuThread* pThread, long newRecordIdx) { NuError err = kNuErrNone; NuDataSource* pDataSource = NULL; NuDataSink* pDataSink = NULL; uint8_t* buffer = NULL; /* * If we have some data files that were left uncompressed, perhaps * because of GSHK's "don't compress anything smaller than 512 bytes" * rule, NufxLib will try to compress them. We disable this * behavior by disabling compression. That way, stuff that is * already compressed will remain that way, and stuff that isn't * compressed won't be. (We really only need to do this once, at * the start of the program, but it's illustrative to do it here.) * * [ I don't understand this comment. It's necessary to disable * compression, but I don't see why uncompressed files are * special. ++ATM 20040821 ] */ err = NuSetValue(pOutArchive, kNuValueDataCompression, kNuCompressNone); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to set compression (err=%d)\n", err); goto bail; } /* * Allocate a buffer large enough to hold all the compressed data, and * wrap a data sink around it. */ buffer = malloc(pThread->thCompThreadEOF); if (buffer == NULL) { err = kNuErrMalloc; goto bail; } err = NuCreateDataSinkForBuffer(false, kNuConvertOff, buffer, pThread->thCompThreadEOF, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data sink (err=%d)\n", err); goto bail; } /* * Get the compressed data. For a pre-sized thread, this grabs the * entire contents of the buffer, including the padding. */ err = NuExtractThread(pInArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to extract thread %u (err=%d)\n", pThread->threadIdx, err); goto bail; } /* * The (perhaps compressed) data is in the buffer, now create a data * source that describes it. * * This is complicated by the existence of pre-sized threads. There * are two possibilities: * 1. We have a certain amount of non-pre-sized data (thCompThreadEOF) * that will expand out to a certain length (actualThreadEOF). * 2. We have a certain amount of pre-sized data (actualThreadEOF) * that will fit within a buffer (thCompThreadEOF). * As you can see, the arguments need to be reversed for pre-sized * threads. * * We always use "actualThreadEOF" because "thThreadEOF" is broken * for disk archives created by certain versions of ShrinkIt. */ if (NuIsPresizedThreadID(NuGetThreadID(pThread))) { err = NuCreateDataSourceForBuffer(pThread->thThreadFormat, pThread->thCompThreadEOF, buffer, 0, pThread->actualThreadEOF, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create pre-sized data source (err=%d)\n",err); goto bail; } } else { err = NuCreateDataSourceForBuffer(pThread->thThreadFormat, pThread->actualThreadEOF, buffer, 0, pThread->thCompThreadEOF, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data source (err=%d)\n", err); goto bail; } } buffer = NULL; /* doClose was set, so it's owned by the data source */ /* yes, this is a kluge... sigh */ err = NuDataSourceSetRawCrc(pDataSource, pThread->thThreadCRC); if (err != kNuErrNone) { fprintf(stderr, "ERROR: can't set source CRC (err=%d)\n", err); goto bail; } /* * Schedule the data for addition to the record. * * Note that NuAddThread makes a copy of the data source, and clears * "doClose" on our copy, so we are free to dispose of pDataSource. */ err = NuAddThread(pOutArchive, newRecordIdx, NuGetThreadID(pThread), pDataSource, NULL); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to add thread (err=%d)\n", err); goto bail; } pDataSource = NULL; /* library owns it now */ bail: if (pDataSource != NULL) NuFreeDataSource(pDataSource); if (pDataSink != NULL) NuFreeDataSink(pDataSink); if (buffer != NULL) free(buffer); return err; } /* * Copy a thread from one archive to another. * * Depending on "flags", this will either copy it raw or uncompress and * recompress. */ NuError CopyThread(NuArchive* pInArchive, NuArchive* pOutArchive, long flags, const NuThread* pThread, long newRecordIdx) { if (flags & kFlagCopyOnly) { return CopyThreadUncompressed(pInArchive, pOutArchive, flags, pThread, newRecordIdx); } else { return CopyThreadRecompressed(pInArchive, pOutArchive, flags, pThread, newRecordIdx); } } /* * Copy a record from the input to the output. * * This runs through the list of threads and copies each one individually. * It will copy them in the original order or in reverse order (the latter * of which will not usually have any effect since NufxLib imposes a * specific thread ordering on most common types) depending on "flags". */ NuError CopyRecord(NuArchive* pInArchive, NuArchive* pOutArchive, long flags, NuRecordIdx recordIdx) { NuError err = kNuErrNone; const NuRecord* pRecord; const NuThread* pThread; NuFileDetails fileDetails; NuRecordIdx newRecordIdx; long numThreads; int idx; /* * Grab the original record and see how many threads it has. */ err = NuGetRecord(pInArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to get recordIdx %u\n", recordIdx); goto bail; } /* * Pre-v3 records didn't put CRCs in the thread headers. If we just * copy the thread over without reprocessing the data, we won't compute * a CRC for the thread, and we will get CRC failures. */ if (!gSentRecordWarning && (flags & kFlagCopyOnly) && pRecord->recVersionNumber < 3) { printf("WARNING: pre-v3 records that aren't recompressed may exhibit CRC failures\n"); gSentRecordWarning = true; } numThreads = NuRecordGetNumThreads(pRecord); if (!numThreads) { fprintf(stderr, "WARNING: recordIdx=%u was empty\n", recordIdx); goto bail; } /* * Create a new record that looks just like the original. */ memset(&fileDetails, 0, sizeof(fileDetails)); fileDetails.storageNameMOR = pRecord->filenameMOR; fileDetails.fileSysID = pRecord->recFileSysID; fileDetails.fileSysInfo = pRecord->recFileSysInfo; fileDetails.access = pRecord->recAccess; fileDetails.fileType = pRecord->recFileType; fileDetails.extraType = pRecord->recExtraType; fileDetails.storageType = pRecord->recStorageType; fileDetails.createWhen = pRecord->recCreateWhen; fileDetails.modWhen = pRecord->recModWhen; fileDetails.archiveWhen = pRecord->recArchiveWhen; err = NuAddRecord(pOutArchive, &fileDetails, &newRecordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: NuAddRecord failed (err=%d)\n", err); goto bail; } /* * Copy the threads. */ if (flags & kFlagReverseThreads) { for (idx = numThreads-1; idx >= 0; idx--) { pThread = NuGetThread(pRecord, idx); assert(pThread != NULL); err = CopyThread(pInArchive, pOutArchive, flags, pThread, newRecordIdx); if (err != kNuErrNone) goto bail; } } else { for (idx = 0; idx < numThreads; idx++) { pThread = NuGetThread(pRecord, idx); assert(pThread != NULL); err = CopyThread(pInArchive, pOutArchive, flags, pThread, newRecordIdx); if (err != kNuErrNone) goto bail; } } bail: return err; } /* * Launder an archive from inFile to outFile. * * Returns 0 on success, nonzero on failure. */ int LaunderArchive(const char* inFile, const char* outFile, NuValue compressMethod, long flags) { NuError err = kNuErrNone; NuArchive* pInArchive = NULL; NuArchive* pOutArchive = NULL; const NuMasterHeader* pMasterHeader; NuRecordIdx recordIdx; uint32_t idx, flushStatus; err = NuOpenRO(inFile, &pInArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't open input archive '%s' (err=%d)\n", inFile, err); goto bail; } err = NuOpenRW(outFile, kTempFile, kNuOpenCreat|kNuOpenExcl, &pOutArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't open output archive '%s' (err=%d)\n", outFile, err); goto bail; } /* turn off "mimic GSHK" */ err = NuSetValue(pInArchive, kNuValueMimicSHK, true); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to disable GSHK quirks (err=%d)\n", err); goto bail; } /* allow duplicates, in case the original archive has them */ err = NuSetValue(pOutArchive, kNuValueAllowDuplicates, true); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't allow duplicates (err=%d)\n", err); goto bail; } /* set the compression method */ err = NuSetValue(pOutArchive, kNuValueDataCompression, compressMethod); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to set compression (err=%d)\n", err); goto bail; } if (flags & kFlagUseTmp) { err = NuSetValue(pOutArchive, kNuValueModifyOrig, false); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't disable modify orig (err=%d)\n", err); goto bail; } } err = NuGetMasterHeader(pInArchive, &pMasterHeader); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get master header (err=%d)\n", err); goto bail; } /* * Iterate through the set of records. */ for (idx = 0; idx < pMasterHeader->mhTotalRecords; idx++) { err = NuGetRecordIdxByPosition(pInArchive, idx, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record #%u (err=%d)\n", idx, err); goto bail; } err = CopyRecord(pInArchive, pOutArchive, flags, recordIdx); if (err != kNuErrNone) goto bail; /* * If "frequent abort" is set, abort what we just did and redo it. */ if (flags & kFlagFrequentAbort) { /*printf("(abort)\n");*/ err = NuAbort(pOutArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: abort failed (err=%d)\n", err); goto bail; } err = CopyRecord(pInArchive, pOutArchive, flags, recordIdx); if (err != kNuErrNone) goto bail; } /* * If "frequent abort" or "frequent flush" is set, flush after * each record is copied. */ if ((flags & kFlagFrequentAbort) || (flags & kFlagFrequentFlush)) { /*printf("(flush)\n");*/ err = NuFlush(pOutArchive, &flushStatus); if (err != kNuErrNone) { fprintf(stderr, "ERROR: flush failed (err=%d, status=0x%04x)\n", err, flushStatus); goto bail; } } } /* first and only flush if frequent-flushing wasn't enabled */ err = NuFlush(pOutArchive, &flushStatus); if (err != kNuErrNone) { fprintf(stderr, "ERROR: flush failed (err=%d, status=0x%04x)\n", err, flushStatus); goto bail; } bail: if (pInArchive != NULL) NuClose(pInArchive); if (pOutArchive != NULL) { if (err != kNuErrNone) NuAbort(pOutArchive); NuClose(pOutArchive); /* flush pending changes and close */ } return (err != kNuErrNone); } /* * Can't count on having getopt on non-UNIX platforms, so just use this * quick version instead. May not work exactly like getopt(), but it * does everything we need here. */ int myoptind = 0; char* myoptarg = NULL; const char* curchar = NULL; int skipnext = false; int mygetopt(int argc, char** argv, const char* optstr) { if (!myoptind) { myoptind = 1; if (argc <= 1) return EOF; curchar = argv[myoptind]; if (*curchar != '-') return EOF; } curchar++; if (*curchar == '\0') { myoptind++; if (skipnext) myoptind++; if (myoptind >= argc) return EOF; curchar = argv[myoptind]; if (*curchar != '-') return EOF; curchar++; } while (*optstr != '\0') { if (*optstr == *curchar) { /*printf("MATCHED '%c'\n", *optstr);*/ if (*(optstr+1) == ':') { skipnext = true; myoptarg = argv[myoptind+1]; /*printf("ATTACHED '%s'\n", myoptarg);*/ } return *curchar; } optstr++; } fprintf(stderr, "Unrecognized option '%c'\n", *curchar); return *curchar; } /* * Print usage info. */ void Usage(const char* argv0) { fprintf(stderr, "Usage: %s [-crfat] [-m method] infile.shk outfile.shk\n", argv0); fprintf(stderr, "\t-c : copy only, does not recompress data\n"); fprintf(stderr, "\t-r : copy threads in reverse order to test ordering\n"); fprintf(stderr, "\t-f : call Flush frequently to reduce memory usage\n"); fprintf(stderr, "\t-a : exercise nufxlib Abort code frequently\n"); fprintf(stderr, "\t-t : write to temp file instead of directly to outfile.shk\n"); fprintf(stderr, "\t[method] is one of {sq,lzw1,lzw2,lzc12,lzc16,deflate,bzip2}\n"); fprintf(stderr, "\tIf not specified, method defaults to lzw2\n"); } /* * Grab the name of an archive to read. */ int main(int argc, char** argv) { NuValue compressMethod = kNuCompressLZW2; int32_t major, minor, bug; const char* pBuildDate; long flags = 0; int errorFlag; int ic; int cc; (void) NuGetVersion(&major, &minor, &bug, &pBuildDate, NULL); printf("Using NuFX lib %d.%d.%d built on or after %s\n", major, minor, bug, pBuildDate); errorFlag = false; while ((ic = mygetopt(argc, argv, "crfatm:")) != EOF) { switch (ic) { case 'c': flags |= kFlagCopyOnly; break; case 'r': flags |= kFlagReverseThreads; break; case 'f': flags |= kFlagFrequentFlush; break; case 'a': flags |= kFlagFrequentAbort; break; case 't': flags |= kFlagUseTmp; break; case 'm': { struct { const char* str; NuValue val; NuFeature feature; } methods[] = { { "sq", kNuCompressSQ, kNuFeatureCompressSQ }, { "lzw1", kNuCompressLZW1, kNuFeatureCompressLZW }, { "lzw2", kNuCompressLZW2, kNuFeatureCompressLZW }, { "lzc12", kNuCompressLZC12, kNuFeatureCompressLZC }, { "lzc16", kNuCompressLZC16, kNuFeatureCompressLZC }, { "deflate", kNuCompressDeflate, kNuFeatureCompressDeflate}, { "bzip2", kNuCompressBzip2, kNuFeatureCompressBzip2 }, }; char* methodStr = myoptarg; int i; for (i = 0; i < NELEM(methods); i++) { if (strcmp(methods[i].str, methodStr) == 0) { compressMethod = methods[i].val; break; } } if (i == NELEM(methods)) { fprintf(stderr, "ERROR: unknown method '%s'\n", methodStr); errorFlag++; break; } if (NuTestFeature(methods[i].feature) != kNuErrNone) { fprintf(stderr, "ERROR: compression method '%s' not supported\n", methodStr); errorFlag++; break; } } break; default: errorFlag++; break; } } if (errorFlag || argc != myoptind+2) { Usage(argv[0]); exit(2); } cc = LaunderArchive(argv[myoptind], argv[myoptind+1], compressMethod,flags); if (cc == 0) printf("Success!\n"); else printf("Failed.\n"); exit(cc != 0); } nulib2-3.1.0/nufxlib/samples/Makefile.in000066400000000000000000000044441316100516500200720ustar00rootroot00000000000000# # Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. # This is free software; you can redistribute it and/or modify it under the # terms of the BSD, see the file COPYING. # # Makefile for nufxlib tests (should work with non-GNU make). # # This is normally invoked from the nufxlib makefile. # # If you invoke this directly, LIB_PRODUCT won't be defined, and it # won't automatically detect changes to the library. However, any # changes to the library should cause a re-build in here anyway if # you're running "make" from the library directory. # SHELL = /bin/sh CC = @CC@ AR = ar rcv #OPT = @CFLAGS@ -DNDEBUG OPT = @CFLAGS@ #OPT = @CFLAGS@ -DDEBUG_MSGS #OPT = @CFLAGS@ -DDEBUG_VERBOSE GCC_FLAGS = -Wall -Wwrite-strings -Wstrict-prototypes -Wpointer-arith -Wshadow CFLAGS = @BUILD_FLAGS@ -I. -I.. @DEFS@ #ALL_SRCS = $(wildcard *.c *.cpp) ALL_SRCS = Exerciser.c ImgConv.c Launder.c TestBasic.c \ TestExtract.c TestSimple.c TestTwirl.c NUFXLIB = -L.. -lnufx PRODUCTS = exerciser imgconv launder test-basic test-extract test-names \ test-simple test-twirl all: $(PRODUCTS) @true exerciser: Exerciser.o $(LIB_PRODUCT) $(CC) -o $@ Exerciser.o $(NUFXLIB) @LIBS@ imgconv: ImgConv.o $(LIB_PRODUCT) $(CC) -o $@ ImgConv.o $(NUFXLIB) @LIBS@ launder: Launder.o $(LIB_PRODUCT) $(CC) -o $@ Launder.o $(NUFXLIB) @LIBS@ test-basic: TestBasic.o $(LIB_PRODUCT) $(CC) -o $@ TestBasic.o $(NUFXLIB) @LIBS@ test-extract: TestExtract.o $(LIB_PRODUCT) $(CC) -o $@ TestExtract.o $(NUFXLIB) @LIBS@ test-names: TestNames.o $(LIB_PRODUCT) $(CC) -o $@ TestNames.o $(NUFXLIB) @LIBS@ test-simple: TestSimple.o $(LIB_PRODUCT) $(CC) -o $@ TestSimple.o $(NUFXLIB) @LIBS@ test-twirl: TestTwirl.o $(LIB_PRODUCT) $(CC) -o $@ TestTwirl.o $(NUFXLIB) @LIBS@ tags:: ctags --totals -R ../* @#ctags *.cpp ../*.c *.h ../*.h clean: -rm -f *.o core -rm -f $(PRODUCTS) distclean: clean -rm -f tags -rm -f Makefile Makefile.bak COMMON_HDRS = ../NufxLibPriv.h ../NufxLib.h ../MiscStuff.h ../SysDefs.h Exerciser.o: Exerciser.c $(COMMON_HDRS) ImgConv.o: ImgConv.c $(COMMON_HDRS) Launder.o: Launder.c $(COMMON_HDRS) TestBasic.o: TestBasic.c $(COMMON_HDRS) TestExtract.o: TestExtract.c $(COMMON_HDRS) TestNames.o: TestNames.c $(COMMON_HDRS) TestSimple.o: TestSimple.c $(COMMON_HDRS) TestTwirl.o: TestTwirl.c $(COMMON_HDRS) nulib2-3.1.0/nufxlib/samples/Makefile.msc000066400000000000000000000071651316100516500202510ustar00rootroot00000000000000# # Makefile for Microsoft C compilers. Tested against Visual C++ 6.0. # Not pretty but it seems to work. # # Run with "nmake /f Makefile.msc". Expects NufxLib to have been built # in "..". # # To build without debugging info, use "nmake nodebug=1". # To build with libz, use "nmake libz=1". # To build with libbz2, use "nmake libbz2=1". # If you're linking against nufxlib as a DLL, you don't need to specify # libraries. You probably need to specify DLL=1 and the same setting # of the NODEBUG flag as you used when building the DLL. If you don't, # "test-extract" will fail in the fwrite() call in Nu_FWrite, because # the non-debug /MD libc does something peculiar with FILE*. # # For libz/libbz2, you need to have the appropriate library either # in this directory or in a standard location that the linker can find. # # Windows magic TARGETOS = BOTH !include NUFXSRCDIR = .. LIB_PRODUCT = $(NUFXSRCDIR)\nufxlib2.lib !ifdef DLL ### build using the same libc as the DLL !ifdef NODEBUG #OPT = /D NUFXLIB_DLL /D NDEBUG /MD /Ogityb2 OPT = /D NUFXLIB_DLL /MD /Ogityb2 LIB_FLAGS = /nodefaultlib:libcd.lib /nologo setargv.obj !else #OPT = /D NUFXLIB_DLL /MDd /Od OPT = /D NUFXLIB_DLL /D DEBUG_MSGS /MDd /Od LIB_FLAGS = /nodefaultlib:libc.lib /nologo setargv.obj !endif !else ### build against static lib !ifdef NODEBUG #OPT = /D NDEBUG /ML /Ogityb2 OPT = /ML /Ogityb2 LIB_FLAGS = /nodefaultlib:libcd.lib /nologo libc.lib setargv.obj !else #OPT = /MLd /Od OPT = /D DEBUG_MSGS /MLd /Od LIB_FLAGS = /nodefaultlib:libc.lib /nologo libcd.lib setargv.obj !endif !endif BUILD_FLAGS = /W3 /GX /D "WIN32" /D "_CONSOLE" /I "$(NUFXSRCDIR)" !MESSAGE Using OPT = $(OPT) !ifdef LIBZ LIB_FLAGS = zlib.lib $(LIB_FLAGS) !endif !ifdef LIBBZ2 LIB_FLAGS = libbz2.lib $(LIB_FLAGS) !endif # how to compile sources .c.obj: @$(cc) $(cdebug) $(OPT) $(BUILD_FLAGS) $(cflags) $(cvars) -o $@ $< PRODUCTS = exerciser.exe imgconv.exe launder.exe test-basic.exe test-extract.exe test-simple.exe test-twirl.exe all: $(PRODUCTS) exerciser.exe: Exerciser.obj $(LIB_PRODUCT) $(link) $(ldebug) Exerciser.obj -out:$@ $(NUFXSRCDIR)\nufxlib2.lib $(LIB_FLAGS) imgconv.exe: ImgConv.obj $(LIB_PRODUCT) $(link) $(ldebug) ImgConv.obj -out:$@ $(NUFXSRCDIR)\nufxlib2.lib $(LIB_FLAGS) launder.exe: Launder.obj $(LIB_PRODUCT) $(link) $(ldebug) Launder.obj -out:$@ $(NUFXSRCDIR)\nufxlib2.lib $(LIB_FLAGS) test-basic.exe: TestBasic.obj $(LIB_PRODUCT) $(link) $(ldebug) TestBasic.obj -out:$@ $(NUFXSRCDIR)\nufxlib2.lib $(LIB_FLAGS) test-simple.exe: TestSimple.obj $(LIB_PRODUCT) $(link) $(ldebug) TestSimple.obj -out:$@ $(NUFXSRCDIR)\nufxlib2.lib $(LIB_FLAGS) test-extract.exe: TestExtract.obj $(LIB_PRODUCT) $(link) $(ldebug) TestExtract.obj -out:$@ $(NUFXSRCDIR)\nufxlib2.lib $(LIB_FLAGS) test-twirl.exe: TestTwirl.obj $(LIB_PRODUCT) $(link) $(ldebug) TestTwirl.obj -out:$@ $(NUFXSRCDIR)\nufxlib2.lib $(LIB_FLAGS) clean: -del *.obj -del *.pdb -del *.ilk -del *.exp -del exerciser.exe -del imgconv.exe -del launder.exe -del test-basic.exe -del test-simple.exe -del test-extract.exe -del test-twirl.exe Exerciser.obj: Exerciser.c Common.h $(NUFXSRCDIR)\NufxLib.h $(NUFXSRCDIR)\SysDefs.h ImgConv.obj: ImgConv.c Common.h $(NUFXSRCDIR)\NufxLib.h $(NUFXSRCDIR)\SysDefs.h Launder.obj: Launder.c Common.h $(NUFXSRCDIR)\NufxLib.h $(NUFXSRCDIR)\SysDefs.h TestBasic.obj: TestBasic.c Common.h $(NUFXSRCDIR)\NufxLib.h $(NUFXSRCDIR)\SysDefs.h TestSimple.obj: TestSimple.c Common.h $(NUFXSRCDIR)\NufxLib.h $(NUFXSRCDIR)\SysDefs.h TestExtract.obj: TestExtract.c Common.h $(NUFXSRCDIR)\NufxLib.h $(NUFXSRCDIR)\SysDefs.h TestTwirl.obj: TestTwirl.c Common.h $(NUFXSRCDIR)\NufxLib.h $(NUFXSRCDIR)\SysDefs.h nulib2-3.1.0/nufxlib/samples/README-S.txt000066400000000000000000000103461316100516500177210ustar00rootroot00000000000000NufxLib "samples" README This directory contains some test programs and useful sample code. test-basic ========== Basic tests. Run this to verify that things are working. On Win32 there will be a second executable, test-basic-d, that links against the DLL rather than the static library. exerciser ========= This program allows you to exercise all of NufxLib's basic functions. Run it without arguments and hit "?" for a list of commands. If you think you have found a bug in NufxLib, you can use this to narrow it down to a repeatable case. imgconv ======= A 2IMG disk image converter. You can convert ".2MG" files to ShrinkIt disk archives, and ShrinkIt disk archives to 2IMG format. imgconv uses a creator type of "NFXL". You can use it like this: % imgconv file.shk file.2mg or % imgconv file.2mg file.shk It figures out what to do based on the filename. It will recognize ".sdk" as a ShrinkIt archive. Limitations: works for DOS-ordered and ProDOS-ordered 2MG images, but not for raw nibble images. Converting from .shk only works if the first record in the archive is a disk image; you don't get to pick the one you want from an archive with several in it. launder ======= Run an archive through the laundry. This copies the entire contents of an archive thread-by-thread, reconstructing it such that the data matches the original even if the archive contents don't (e.g. records are updated to version 3, files may be recompressed with LZW/2, option lists are stripped out, etc). The basic usage is: % launder [-crfa] [-m method] infile.shk outfile.shk The flags are: -c Just copy data threads rather than recompressing them -r Add threads in reverse order -f Call NuFlush after every record -a Call NuAbort after every record, then re-do the record and call NuFlush -t Write to temp file, instead of writing directly into outfile.shk The "-m method" flag allows you to specify the compression method. Valid values are sq (SQueeze), lzw1 (ShrinkIt LZW/1), lzw2 (ShrinkIt LZW/2), lzc12 (12-bit UNIX "compress"), lzc16 (16-bit UNIX "compress"), deflate (zlib deflate), and bzip2 (libbz2 compression). The default is lzw2. If you use the "-c" flag with an archive created by P8 ShrinkIt or NuLib, the laundered archive may have CRC failures when you try to extract from it. This is because "launder" creates version 3 records, which are expected to have a valid CRC in the thread header. The only way to compute the CRC is to uncompress the data, which "launder" doesn't do when "-c" is set. The data itself is fine, it's just the thread CRC that's wrong (if the data were hosed, the LZW/1 CRC would be bad too). "launder" will issue a warning when it detects this situation. By default, launder will try to keep the entire archive in memory and flush all of the operations at the end. If you find that you're running out of memory on very large archives, you can reduce the memory requirements by specifying the "-f" flag. test-names ========== Tests Unicode filename handling. Run without arguments. (This currently fails on Win32 because the Unicode filename support is incomplete there.) test-simple =========== Simple test program. Give it the name of an archive, and it will display the contents. test-extract ============ Simple test program. Give it the name of an archive, and it will write all filename threads into "out.buf", "out.fp", and "out.file" using three different kinds of NuDataSinks. test-twirl ========== Like "launder", but not meant to be useful. This recompresses the file "in place", deleting and adding threads within existing records several times. The changes are periodically flushed, but the archive is never closed. The goal is to test repeated updates on an open archive. The CRC verification mechanism will fail on archives created with ProDOS 8 ShrinkIt. The older "version 1" records didn't have CRCs in the thread headers, so you will get a series of messages that look like this: ERROR: CRC mismatch: 0 old=0x0000 new=0x681b ERROR: CRC mismatch: 1 old=0x0000 new=0x5570 ERROR: CRC mismatch: 2 old=0x0000 new=0x4ec5 This will leave the original archive alone, making a copy of it named "TwirlCopy678" in the current directory. It overwrites its temp file, "TwirlTmp789", without prompting. nulib2-3.1.0/nufxlib/samples/TestBasic.c000066400000000000000000000754341316100516500200610ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * Test basic features of the library. Run this without arguments. */ #include #include #include "NufxLib.h" #include "Common.h" #define kTestArchive "nlbt.shk" #define kTestTempFile "nlbt.tmp" #define kNumEntries 3 /* how many records are we going to add? */ /* stick to ASCII characters for these -- not doing conversions just yet */ #define kTestEntryBytes "bytes" #define kTestEntryBytesUPPER "BYTES" #define kTestEntryEnglish "English" #define kTestEntryLong "three|is a fairly long filename, complete with" \ "punctuation and other nifty/bad stuff" #define kLocalFssep '|' /* * Globals. */ char gSuppressError = false; #define FAIL_OK gSuppressError = true; #define FAIL_BAD gSuppressError = false; /* * =========================================================================== * Helper functions * =========================================================================== */ /* * Get a single character of input from the user. */ static char TGetReplyChar(char defaultReply) { char tmpBuf[32]; if (fgets(tmpBuf, sizeof(tmpBuf), stdin) == NULL) return defaultReply; if (tmpBuf[0] == '\n' || tmpBuf[0] == '\r') return defaultReply; return tmpBuf[0]; } NuError AddSimpleRecord(NuArchive* pArchive, const char* filenameMOR, NuRecordIdx* pRecordIdx) { NuFileDetails fileDetails; memset(&fileDetails, 0, sizeof(fileDetails)); fileDetails.storageNameMOR = filenameMOR; fileDetails.fileSysInfo = kLocalFssep; fileDetails.access = kNuAccessUnlocked; return NuAddRecord(pArchive, &fileDetails, pRecordIdx); } /* * Display error messages... or not. */ NuResult ErrorMessageHandler(NuArchive* pArchive, void* vErrorMessage) { const NuErrorMessage* pErrorMessage = (const NuErrorMessage*) vErrorMessage; if (gSuppressError) return kNuOK; if (pErrorMessage->isDebug) { fprintf(stderr, "%sNufxLib says: [%s:%d %s] %s\n", pArchive == NULL ? "GLOBAL>" : "", pErrorMessage->file, pErrorMessage->line, pErrorMessage->function, pErrorMessage->message); } else { fprintf(stderr, "%sNufxLib says: %s\n", pArchive == NULL ? "GLOBAL>" : "", pErrorMessage->message); } return kNuOK; } /* * This gets called when a buffer DataSource is no longer needed. */ NuResult FreeCallback(NuArchive* pArchive, void* args) { free(args); return kNuOK; } /* * If the test file currently exists, ask the user if it's okay to remove * it. * * Returns 0 if the file was successfully removed, -1 if the file could not * be removed (because the unlink failed, or the user refused). */ int RemoveTestFile(const char* title, const char* fileName) { char answer; if (access(fileName, F_OK) == 0) { printf("%s '%s' exists, remove (y/n)? ", title, fileName); fflush(stdout); answer = TGetReplyChar('n'); if (tolower(answer) != 'y') return -1; if (unlink(fileName) < 0) { perror("unlink"); return -1; } } return 0; } /* * =========================================================================== * Tests * =========================================================================== */ /* * Make sure the flags that control how we open the file work right, * and verify that we handle existing zero-byte archive files correctly. */ int Test_OpenFlags(void) { NuError err; FILE* fp = NULL; NuArchive* pArchive = NULL; printf("... open zero-byte existing\n"); fp = fopen(kTestArchive, kNuFileOpenWriteTrunc); if (fp == NULL) { perror("fopen kTestArchive"); goto failed; } fclose(fp); fp = NULL; FAIL_OK; err = NuOpenRW(kTestArchive, kTestTempFile, kNuOpenCreat|kNuOpenExcl, &pArchive); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: file opened when it shouldn't have\n"); goto failed; } err = NuOpenRW(kTestArchive, kTestTempFile, kNuOpenCreat, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: file didn't open when it should have\n"); goto failed; } err = NuClose(pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: close failed\n"); goto failed; } pArchive = NULL; if (access(kTestArchive, F_OK) == 0) { fprintf(stderr, "ERROR: archive should have been removed but wasn't\n"); goto failed; } return 0; failed: if (pArchive != NULL) { NuAbort(pArchive); NuClose(pArchive); } return -1; } /* * Add some files to the archive. These will be used by later tests. */ int Test_AddStuff(NuArchive* pArchive) { NuError err; uint8_t* buf = NULL; NuDataSource* pDataSource = NULL; NuRecordIdx recordIdx; uint32_t status; int i; static const char* testMsg = "This is a nice test message that has linefeeds in it so we can\n" "see if the line conversion stuff is actually doing anything at\n" "all. It's certainly nice to know that everything works the way\n" "it's supposed to, which I suppose is why we have this nifty test\n" "program available. It sure would be nice if everybody tested\n" "their code, but where would Microsoft be without endless upgrades\n" "and service packs? Bugs are what America was built on, and\n" "anybody who says otherwise is a pinko commie lowlife. Verily.\n"; printf("... add 'bytes' record\n"); buf = malloc(131072); if (buf == NULL) goto failed; for (i = 0; i < 131072; i++) *(buf+i) = i & 0xff; FAIL_OK; err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, NULL, 0, 131072, FreeCallback, &pDataSource); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: that should've failed!\n"); goto failed; } /* * Create a data source for the big batch of bytes. */ err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, buf, 0, 131072, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'bytes' data source create failed (err=%d)\n", err); goto failed; } buf = NULL; /* now owned by library */ err = AddSimpleRecord(pArchive, kTestEntryBytes, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'bytes' record failed (err=%d)\n", err); goto failed; } err = NuAddThread(pArchive, recordIdx, kNuThreadIDDataFork, pDataSource, NULL); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'bytes' thread add failed (err=%d)\n", err); goto failed; } pDataSource = NULL; /* now owned by library */ /* * Create a data source for our lovely text message. */ printf("... add 'English' record\n"); err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, (const uint8_t*)testMsg, 0, strlen(testMsg), NULL, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'English' source create failed (err=%d)\n", err); goto failed; } FAIL_OK; err = NuAddThread(pArchive, recordIdx, kNuThreadIDDataFork, pDataSource, NULL); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: 'English' add should've conflicted!\n"); goto failed; } FAIL_OK; err = AddSimpleRecord(pArchive, kTestEntryBytes, &recordIdx); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: duplicates not allowed, should've failed\n"); goto failed; } err = AddSimpleRecord(pArchive, kTestEntryEnglish, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'English' record failed (err=%d)\n", err); goto failed; } err = NuAddThread(pArchive, recordIdx, kNuThreadIDDataFork, pDataSource, NULL); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'English' thread add failed (err=%d)\n", err); goto failed; } pDataSource = NULL; /* now owned by library */ /* * Create an empty file with a rather non-empty name. Add it as * a resource fork. */ printf("... add 'long' record\n"); err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, NULL, 0, 0, NULL, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'English' source create failed (err=%d)\n", err); goto failed; } err = AddSimpleRecord(pArchive, kTestEntryLong, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'long' record failed (err=%d)\n", err); goto failed; } err = NuAddThread(pArchive, recordIdx, kNuThreadIDRsrcFork, pDataSource, NULL); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'long' thread add failed (err=%d)\n", err); goto failed; } pDataSource = NULL; /* now owned by library */ /* * Flush changes. */ err = NuFlush(pArchive, &status); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't flush after add (err=%d, status=%u)\n", err, status); goto failed; } /* * Flush again; should succeed since it doesn't have to do anything. */ err = NuFlush(pArchive, &status); if (err != kNuErrNone) { fprintf(stderr, "ERROR: second add flush failed (err=%d, status=%u)\n", err, status); goto failed; } return 0; failed: if (pDataSource != NULL) NuFreeDataSource(pDataSource); if (buf != NULL) free(buf); return -1; } /* * Make sure that what we're seeing makes sense. */ NuResult TestContentsCallback(NuArchive* pArchive, void* vpRecord) { const NuRecord* pRecord = (NuRecord*) vpRecord; if (strcmp(pRecord->filenameMOR, kTestEntryBytes) == 0 || strcmp(pRecord->filenameMOR, kTestEntryEnglish) == 0 || strcmp(pRecord->filenameMOR, kTestEntryLong) == 0) { return kNuOK; } fprintf(stderr, "ERROR: found mystery entry '%s'\n", pRecord->filenameMOR); return kNuAbort; } /* * Verify that the contents look about right. */ int Test_Contents(NuArchive* pArchive) { NuError err; long posn; NuRecordIdx recordIdx; const NuRecord* pRecord; int cc; /* * First, do it with a callback. */ err = NuContents(pArchive, TestContentsCallback); if (err != kNuErrNone) goto failed; /* * Now step through the records with get-by-position and verify that * they're in the expected order. */ for (posn = 0; posn < kNumEntries; posn++) { err = NuGetRecordIdxByPosition(pArchive, posn, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record #%ld (err=%d)\n", posn, err); goto failed; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record index %u (err=%d)\n", recordIdx, err); goto failed; } assert(pRecord != NULL); switch (posn) { case 0: cc = strcmp(pRecord->filenameMOR, kTestEntryBytes); break; case 1: cc = strcmp(pRecord->filenameMOR, kTestEntryEnglish); break; case 2: cc = strcmp(pRecord->filenameMOR, kTestEntryLong); if (!cc) cc = !(pRecord->recStorageType == kNuStorageExtended); break; default: fprintf(stderr, "ERROR: somebody forgot to put a case here (%ld)\n", posn); cc = -1; } if (cc) { fprintf(stderr, "ERROR: got '%s' for %ld (%u), not expected\n", pRecord->filenameMOR, posn, recordIdx); goto failed; } } /* * Read one more past the end, should fail. */ FAIL_OK; err = NuGetRecordIdxByPosition(pArchive, posn, &recordIdx); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: too many records (%ld was ok)\n", posn); goto failed; } return 0; failed: return -1; } /* * Selection callback filter for "test". This gets called once per record, * twice per record for forked files. */ NuResult VerifySelectionCallback(NuArchive* pArchive, void* vpProposal) { NuError err; const NuSelectionProposal* pProposal = vpProposal; long count; if (pProposal->pRecord == NULL || pProposal->pThread == NULL || pProposal->pRecord->filenameMOR == NULL) { fprintf(stderr, "ERROR: unexpected NULL in proposal\n"); goto failed; } err = NuGetExtraData(pArchive, (void**) &count); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to get extra data (err=%d)\n", err); goto failed; } count++; err = NuSetExtraData(pArchive, (void*) count); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to inc extra data (err=%d)\n", err); goto failed; } return kNuOK; failed: return kNuAbort; } /* * Verify the archive contents. */ int Test_Verify(NuArchive* pArchive) { NuError err; long count; printf("... verifying CRCs\n"); if (NuSetSelectionFilter(pArchive, VerifySelectionCallback) == kNuInvalidCallback) { fprintf(stderr, "ERROR: unable to set selection filter\n"); goto failed; } err = NuSetExtraData(pArchive, (void*) 0); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to set extra data (err=%d)\n", err); goto failed; } err = NuTest(pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: verify failed (err=%d)\n", err); goto failed; } err = NuGetExtraData(pArchive, (void**) &count); if (err != kNuErrNone) { fprintf(stderr, "ERROR: last extra data get failed (err=%d)\n", err); goto failed; } /* the count will be one higher than the number of records because the last entry is forked, and each fork is tested separately */ if (count != kNumEntries + 1) { fprintf(stderr, "ERROR: verified %ld when expecting %d\n", count, kNumEntries); goto failed; } return 0; failed: return -1; } /* * Extract stuff. */ int Test_Extract(NuArchive* pArchive) { NuError err; NuRecordIdx recordIdx; const NuRecord* pRecord; const NuThread* pThread; NuDataSink* pDataSink = NULL; uint8_t* buf = NULL; printf("... extracting files\n"); /* * Tell it the current system uses CRLF, so it'll bloat up when we do * a text conversion. */ err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCRLF); /* * Extract "bytes". */ err = NuGetRecordIdxByName(pArchive, kTestEntryBytesUPPER, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't find '%s' (err=%d)\n", kTestEntryBytes, err); goto failed; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record index %u (err=%d)\n", recordIdx, err); goto failed; } assert(pRecord != NULL); /* we're not using ShrinkIt compat mode, so there should not be a comment */ pThread = NuGetThread(pRecord, 1); assert(pThread != NULL); if (NuGetThreadID(pThread) != kNuThreadIDDataFork) { fprintf(stderr, "ERROR: 'bytes' had unexpected threadID 0x%08x\n", NuGetThreadID(pThread)); goto failed; } buf = malloc(pThread->actualThreadEOF); if (buf == NULL) { fprintf(stderr, "ERROR: malloc(%u) failed\n",pThread->actualThreadEOF); goto failed; } /* * Try to extract it with text conversion off. */ err = NuCreateDataSinkForBuffer(true, kNuConvertOff, buf, pThread->actualThreadEOF, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't create data sink (err=%d)\n", err); goto failed; } err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't extract 'bytes' (off) (err=%d)\n", err); goto failed; } NuFreeDataSink(pDataSink); pDataSink = NULL; /* * Try to extract with "on" conversion, which should fail because the * buffer is too small. */ err = NuCreateDataSinkForBuffer(true, kNuConvertOn, buf, pThread->actualThreadEOF, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't create data sink (err=%d)\n", err); goto failed; } FAIL_OK; err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: managed to extract bloated 'bytes'?\n"); goto failed; } NuFreeDataSink(pDataSink); pDataSink = NULL; /* * Try to extract with "auto" conversion, which should conclude that * the input is text and not try to convert. */ err = NuCreateDataSinkForBuffer(true, kNuConvertAuto, buf, pThread->actualThreadEOF, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't create data sink (err=%d)\n", err); goto failed; } err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't extract 'bytes' (auto) (err=%d)\n", err); goto failed; } NuFreeDataSink(pDataSink); pDataSink = NULL; free(buf); buf = NULL; /* * Extract "English". */ err = NuGetRecordIdxByName(pArchive, kTestEntryEnglish, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't find '%s' (err=%d)\n", kTestEntryEnglish, err); goto failed; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record index %u (err=%d)\n", recordIdx, err); goto failed; } assert(pRecord != NULL); /* we're not using ShrinkIt compat mode, so there should not be a comment */ pThread = NuGetThread(pRecord, 1); assert(pThread != NULL); if (NuGetThreadID(pThread) != kNuThreadIDDataFork) { fprintf(stderr, "ERROR: 'English' had unexpected threadID 0x%08x\n", NuGetThreadID(pThread)); goto failed; } buf = malloc(pThread->actualThreadEOF); if (buf == NULL) { fprintf(stderr, "ERROR: malloc(%u) failed\n", pThread->actualThreadEOF); goto failed; } /* * Try to extract it with text conversion off. */ err = NuCreateDataSinkForBuffer(true, kNuConvertOff, buf, pThread->actualThreadEOF, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't create data sink (err=%d)\n", err); goto failed; } err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't extract 'bytes' (off) (err=%d)\n", err); goto failed; } NuFreeDataSink(pDataSink); pDataSink = NULL; /* * Try to extract with "auto" conversion, which should fail because the * buffer is too small, and the input looks like text. */ err = NuCreateDataSinkForBuffer(true, kNuConvertAuto, buf, pThread->actualThreadEOF, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't create data sink (err=%d)\n", err); goto failed; } FAIL_OK; err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: managed to extract bloated 'English'?\n"); goto failed; } NuFreeDataSink(pDataSink); pDataSink = NULL; /*Free(buf);*/ /*buf = NULL;*/ /* * Extract "long" (which is zero bytes). */ err = NuGetRecordIdxByName(pArchive, kTestEntryLong, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't find '%s' (err=%d)\n", kTestEntryLong, err); goto failed; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record index %u (err=%d)\n", recordIdx, err); goto failed; } assert(pRecord != NULL); /* we're not using ShrinkIt compat mode, so there should not be a comment */ pThread = NuGetThread(pRecord, 1); assert(pThread != NULL); if (NuGetThreadID(pThread) != kNuThreadIDRsrcFork) { fprintf(stderr, "ERROR: 'Long' had unexpected threadID 0x%08x\n", NuGetThreadID(pThread)); goto failed; } /* * Try it with text conversion on; shouldn't matter. */ err = NuCreateDataSinkForBuffer(true, kNuConvertOn, buf, 1, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't create data sink (err=%d)\n", err); goto failed; } err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't extract 'Long' (off) (err=%d)\n", err); goto failed; } NuFreeDataSink(pDataSink); pDataSink = NULL; free(buf); buf = NULL; return 0; failed: if (buf != NULL) free(buf); if (pDataSink != NULL) (void) NuFreeDataSink(pDataSink); return -1; } /* * Delete the first and last records. Does *not* flush the archive. */ int Test_Delete(NuArchive* pArchive) { NuError err; NuRecordIdx recordIdx; const NuRecord* pRecord; const NuThread* pThread = NULL; long count; int idx; printf("... deleting first and last\n"); /* * Delete all threads from the first record ("bytes"). */ err = NuGetRecordIdxByPosition(pArchive, 0, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't find #%d (err=%d)\n", 0, err); goto failed; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record index %u (err=%d)\n", recordIdx, err); goto failed; } assert(pRecord != NULL); assert(pRecord->recTotalThreads > 0); for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) { pThread = NuGetThread(pRecord, idx); assert(pThread != NULL); err = NuDeleteThread(pArchive, pThread->threadIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't delete thread #%d (%u) (err=%d)\n", idx, recordIdx, err); goto failed; } } /* try to re-delete the same thread */ assert(pThread != NULL); FAIL_OK; err = NuDeleteThread(pArchive, pThread->threadIdx); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: allowed to re-delete thread (%u) (err=%d)\n", recordIdx, err); goto failed; } /* try to delete the modified record */ FAIL_OK; err = NuDeleteRecord(pArchive, recordIdx); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: able to delete modified record (%u) (err=%d)\n", recordIdx, err); goto failed; } /* * Make sure the attr hasn't been updated yet. */ count = 0; err = NuGetAttr(pArchive, kNuAttrNumRecords, (uint32_t*) &count); if (count != kNumEntries) { fprintf(stderr, "ERROR: kNuAttrNumRecords %ld vs %d\n", count, kNumEntries); goto failed; } /* * Delete the last record ("long"). */ err = NuGetRecordIdxByPosition(pArchive, kNumEntries-1, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't find #%d (err=%d)\n", 0, err); goto failed; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record index %u (err=%d)\n", recordIdx, err); goto failed; } assert(pRecord != NULL); /* grab the first thread before we whack the record */ pThread = NuGetThread(pRecord, 0); assert(pThread != NULL); err = NuDeleteRecord(pArchive, recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to delete record #%d (%u) (err=%d)\n", kNumEntries-1, recordIdx, err); goto failed; } /* try to delete a thread from the deleted record */ FAIL_OK; err = NuDeleteThread(pArchive, pThread->threadIdx); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: allowed to delete from deleted (%u) (err=%d)\n", pThread->threadIdx, err); goto failed; } return 0; failed: return -1; } /* * Verify that the count in the master header has been updated. */ int Test_MasterCount(NuArchive* pArchive, long expected) { NuError err; const NuMasterHeader* pMasterHeader; printf("... checking master count\n"); err = NuGetMasterHeader(pArchive, &pMasterHeader); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get master header (err=%d)\n", err); goto failed; } if (pMasterHeader->mhTotalRecords != (uint32_t)expected) { fprintf(stderr, "ERROR: unexpected MH count (%u vs %ld)\n", pMasterHeader->mhTotalRecords, expected); goto failed; } return 0; failed: return -1; } /* * Run some tests. * * Returns 0 on success, -1 on error. */ int DoTests(void) { NuError err; NuArchive* pArchive = NULL; uint32_t status; int cc, result = 0; /* * Make sure we're starting with a clean slate. */ if (RemoveTestFile("Test archive", kTestArchive) < 0) { goto failed; } if (RemoveTestFile("Test temp file", kTestTempFile) < 0) { goto failed; } /* * Test some of the open flags. */ if (Test_OpenFlags() != 0) goto failed; /* * Create a new archive to play with. */ err = NuOpenRW(kTestArchive, kTestTempFile, kNuOpenCreat|kNuOpenExcl, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: NuOpenRW failed (err=%d)\n", err); goto failed; } if (NuSetErrorMessageHandler(pArchive, ErrorMessageHandler) == kNuInvalidCallback) { fprintf(stderr, "ERROR: couldn't set message handler\n"); goto failed; } /* * Add some test entries. */ if (Test_AddStuff(pArchive) != 0) goto failed; /* * Check the archive contents. */ printf("... checking contents\n"); if (Test_Contents(pArchive) != 0) goto failed; /* * Reopen it read-only. */ printf("... reopening archive read-only\n"); err = NuClose(pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: mid NuClose failed (err=%d)\n", err); goto failed; } pArchive = NULL; err = NuOpenRO(kTestArchive, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: NuOpenRO failed (err=%d)\n", err); goto failed; } if (NuSetErrorMessageHandler(pArchive, ErrorMessageHandler) == kNuInvalidCallback) { fprintf(stderr, "ERROR: couldn't set message handler\n"); goto failed; } /* * Make sure the TOC (i.e. list of files) is still what we expect. */ printf("... checking contents\n"); if (Test_Contents(pArchive) != 0) goto failed; /* * Verify the archive data. */ if (Test_Verify(pArchive) != 0) goto failed; /* * Extract the files. */ if (Test_Extract(pArchive) != 0) goto failed; /* * Reopen it read-write. */ printf("... reopening archive read-write\n"); err = NuClose(pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: late NuClose failed (err=%d)\n", err); goto failed; } pArchive = NULL; err = NuOpenRW(kTestArchive, kTestTempFile, 0, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: re-NuOpenRW failed (err=%d)\n", err); goto failed; } if (NuSetErrorMessageHandler(pArchive, ErrorMessageHandler) == kNuInvalidCallback) { fprintf(stderr, "ERROR: couldn't set message handler\n"); goto failed; } /* * Contents shouldn't have changed. */ printf("... checking contents\n"); if (Test_Contents(pArchive) != 0) goto failed; /* * Test deletion. */ if (Test_Delete(pArchive) != 0) goto failed; /* * Abort the changes and verify that nothing has changed. */ printf("... aborting changes\n"); err = NuAbort(pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: abort failed (err=%d)\n", err); goto failed; } printf("... checking contents\n"); if (Test_Contents(pArchive) != 0) goto failed; /* * Delete them again. */ if (Test_Delete(pArchive) != 0) goto failed; /* * Flush the deletions. This should remove the first and last records. */ err = NuFlush(pArchive, &status); if (err != kNuErrNone) { fprintf(stderr, "ERROR: flush failed (err=%d, status=%d)\n", err, status); goto failed; } /* * Check count in master header. */ if (Test_MasterCount(pArchive, kNumEntries-2) != 0) goto failed; /* * That's all, folks... */ NuClose(pArchive); pArchive = NULL; printf("... removing '%s'\n", kTestArchive); cc = unlink(kTestArchive); if (cc < 0) { perror("unlink kTestArchive"); goto failed; } leave: if (pArchive != NULL) { NuAbort(pArchive); NuClose(pArchive); } return result; failed: result = -1; goto leave; } /* * Crank away. */ int main(void) { int32_t major, minor, bug; const char* pBuildDate; const char* pBuildFlags; int cc; (void) NuGetVersion(&major, &minor, &bug, &pBuildDate, &pBuildFlags); printf("Using NuFX library v%d.%d.%d, built on or after\n" " %s with [%s]\n\n", major, minor, bug, pBuildDate, pBuildFlags); if (NuSetGlobalErrorMessageHandler(ErrorMessageHandler) == kNuInvalidCallback) { fprintf(stderr, "ERROR: can't set the global message handler"); exit(1); } printf("... starting tests\n"); cc = DoTests(); printf("... tests ended, %s\n", cc == 0 ? "SUCCESS" : "FAILURE"); exit(cc != 0); } nulib2-3.1.0/nufxlib/samples/TestExtract.c000066400000000000000000000271561316100516500204500ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * Test extraction of individual threads in various ways. The net result * of this is three files (out.file, out.fp, out.buf) that contain the * result of writing all filenames in an archive to the same data sink. * * This gathers up information on the contents of the archive via a * callback, and then emits all of the data at once. * * (This was originally written in C++, and converted to C after I repented.) */ #include #include #include #include #include "NufxLib.h" #include "Common.h" /*#define false 0*/ /*#define true (!false)*/ #define kHappySize 2408 /* * =========================================================================== * ArchiveRecord * =========================================================================== */ /* * Track an archive record. */ typedef struct ArchiveRecord { char* filenameMOR; NuRecordIdx recordIdx; long numThreads; NuThread* pThreads; struct ArchiveRecord* pNext; } ArchiveRecord; /* * Alloc a new ArchiveRecord. */ ArchiveRecord* ArchiveRecord_New(const NuRecord* pRecord) { ArchiveRecord* pArcRec = NULL; pArcRec = malloc(sizeof(*pArcRec)); if (pArcRec == NULL) return NULL; if (pRecord->filenameMOR == NULL) pArcRec->filenameMOR = strdup(""); else pArcRec->filenameMOR = strdup(pRecord->filenameMOR); pArcRec->recordIdx = pRecord->recordIdx; pArcRec->numThreads = NuRecordGetNumThreads(pRecord); (void) NuRecordCopyThreads(pRecord, &pArcRec->pThreads); pArcRec->pNext = NULL; return pArcRec; } /* * Free up an ArchiveRecord. */ void ArchiveRecord_Free(ArchiveRecord* pArcRec) { if (pArcRec == NULL) return; if (pArcRec->filenameMOR != NULL) free(pArcRec->filenameMOR); if (pArcRec->pThreads != NULL) free(pArcRec->pThreads); free(pArcRec); } /* * Find a thread with a matching NuThreadID. */ const NuThread* ArchiveRecord_FindThreadByID(const ArchiveRecord* pArcRec, NuThreadID threadID) { const NuThread* pThread; int i; for (i = 0; i < pArcRec->numThreads; i++) { pThread = NuThreadGetByIdx(pArcRec->pThreads, i); if (NuGetThreadID(pThread) == threadID) return pThread; } return NULL; } const char* ArchiveRecord_GetFilename(const ArchiveRecord* pArcRec) { return pArcRec->filenameMOR; } NuRecordIdx ArchiveRecord_GetRecordIdx(const ArchiveRecord* pArcRec) { return pArcRec->recordIdx; } long ArchiveRecord_GetNumThreads(const ArchiveRecord* pArcRec) { return pArcRec->numThreads; } const NuThread* ArchiveRecord_GetThread(const ArchiveRecord* pArcRec, int idx) { if (idx < 0 || idx >= pArcRec->numThreads) return NULL; return NuThreadGetByIdx(pArcRec->pThreads, idx); } void ArchiveRecord_SetNext(ArchiveRecord* pArcRec, ArchiveRecord* pNextRec) { pArcRec->pNext = pNextRec; } ArchiveRecord* ArchiveRecord_GetNext(const ArchiveRecord* pArcRec) { return pArcRec->pNext; } /* * =========================================================================== * ArchiveData * =========================================================================== */ /* * A collection of records. */ typedef struct ArchiveData { long numRecords; ArchiveRecord* pRecordHead; ArchiveRecord* pRecordTail; } ArchiveData; ArchiveData* ArchiveData_New(void) { ArchiveData* pArcData; pArcData = malloc(sizeof(*pArcData)); if (pArcData == NULL) return NULL; pArcData->numRecords = 0; pArcData->pRecordHead = pArcData->pRecordTail = NULL; return pArcData; } void ArchiveData_Free(ArchiveData* pArcData) { ArchiveRecord* pNext; if (pArcData == NULL) return; printf("*** Deleting %ld records!\n", pArcData->numRecords); while (pArcData->pRecordHead != NULL) { pNext = ArchiveRecord_GetNext(pArcData->pRecordHead); ArchiveRecord_Free(pArcData->pRecordHead); pArcData->pRecordHead = pNext; } free(pArcData); } ArchiveRecord* ArchiveData_GetRecordHead(const ArchiveData* pArcData) { return pArcData->pRecordHead; } /* add an ArchiveRecord to the list pointed at by ArchiveData */ void ArchiveData_AddRecord(ArchiveData* pArcData, ArchiveRecord* pRecord) { assert(pRecord != NULL); assert((pArcData->pRecordHead == NULL && pArcData->pRecordTail == NULL) || (pArcData->pRecordHead != NULL && pArcData->pRecordTail != NULL)); if (pArcData->pRecordHead == NULL) { /* first */ pArcData->pRecordHead = pArcData->pRecordTail = pRecord; } else { /* not first, add to end */ ArchiveRecord_SetNext(pArcData->pRecordTail, pRecord); pArcData->pRecordTail = pRecord; } pArcData->numRecords++; } /* dump the contents of the ArchiveData to stdout */ void ArchiveData_DumpContents(const ArchiveData* pArcData) { ArchiveRecord* pArcRec; pArcRec = pArcData->pRecordHead; while (pArcRec != NULL) { const NuThread* pThread; int i, count; printf("%5u '%s'\n", ArchiveRecord_GetRecordIdx(pArcRec), ArchiveRecord_GetFilename(pArcRec)); count = ArchiveRecord_GetNumThreads(pArcRec); for (i = 0; i < count; i++) { pThread = ArchiveRecord_GetThread(pArcRec, i); printf(" %5u 0x%04x 0x%04x\n", pThread->threadIdx, pThread->thThreadClass, pThread->thThreadKind); } pArcRec = ArchiveRecord_GetNext(pArcRec); } } /* * =========================================================================== * Main stuff * =========================================================================== */ /* * Callback function to collect archive information. */ NuResult GatherContents(NuArchive* pArchive, void* vpRecord) { NuRecord* pRecord = (NuRecord*) vpRecord; ArchiveData* pArchiveData = NULL; ArchiveRecord* pArchiveRecord = ArchiveRecord_New(pRecord); NuGetExtraData(pArchive, (void**)&pArchiveData); assert(pArchiveData != NULL); printf("*** Filename = '%s'\n", pRecord->filenameMOR == NULL ? "" : pRecord->filenameMOR); ArchiveData_AddRecord(pArchiveData, pArchiveRecord); return kNuOK; } /* * Copy the filename thread from every record to "pDataSink". */ NuError ReadAllFilenameThreads(NuArchive* pArchive, ArchiveData* pArchiveData, NuDataSink* pDataSink) { NuError err = kNuErrNone; ArchiveRecord* pArchiveRecord; const NuThread* pThread; pArchiveRecord = ArchiveData_GetRecordHead(pArchiveData); while (pArchiveRecord != NULL) { pThread = ArchiveRecord_FindThreadByID(pArchiveRecord, kNuThreadIDFilename); if (pThread != NULL) { err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "*** Extract failed (%d)\n", err); goto bail; } } pArchiveRecord = ArchiveRecord_GetNext(pArchiveRecord); } bail: return err; } /* extract every filename thread into a single file, overwriting each time */ NuError ExtractToFile(NuArchive* pArchive, ArchiveData* pArchiveData) { NuError err; NuDataSink* pDataSink = NULL; err = NuCreateDataSinkForFile(true, kNuConvertOff, "out.file", PATH_SEP, &pDataSink); if (err != kNuErrNone) goto bail; err = NuSetValue(pArchive, kNuValueHandleExisting, kNuAlwaysOverwrite); if (err != kNuErrNone) goto bail; err = ReadAllFilenameThreads(pArchive, pArchiveData, pDataSink); if (err != kNuErrNone) goto bail; bail: (void) NuFreeDataSink(pDataSink); if (err == kNuErrNone) printf("*** File write complete\n"); return err; } /* extract every filename thread into a FILE*, appending */ NuError ExtractToFP(NuArchive* pArchive, ArchiveData* pArchiveData) { NuError err; FILE* fp = NULL; NuDataSink* pDataSink = NULL; if ((fp = fopen("out.fp", kNuFileOpenWriteTrunc)) == NULL) return kNuErrFileOpen; err = NuCreateDataSinkForFP(true, kNuConvertOff, fp, &pDataSink); if (err != kNuErrNone) goto bail; err = ReadAllFilenameThreads(pArchive, pArchiveData, pDataSink); if (err != kNuErrNone) goto bail; bail: (void) NuFreeDataSink(pDataSink); if (fp != NULL) fclose(fp); if (err == kNuErrNone) printf("*** FP write complete\n"); return err; } /* extract every filename thread into a buffer, advancing as we go */ NuError ExtractToBuffer(NuArchive* pArchive, ArchiveData* pArchiveData) { NuError err; uint8_t buffer[kHappySize]; NuDataSink* pDataSink = NULL; uint32_t count; err = NuCreateDataSinkForBuffer(true, kNuConvertOff, buffer, kHappySize, &pDataSink); if (err != kNuErrNone) goto bail; err = ReadAllFilenameThreads(pArchive, pArchiveData, pDataSink); if (err != kNuErrNone) { if (err == kNuErrBufferOverrun) fprintf(stderr, "*** Hey, buffer wasn't big enough!\n"); goto bail; } /* write the buffer to a file */ (void) NuDataSinkGetOutCount(pDataSink, &count); if (count > 0) { FILE* fp; if ((fp = fopen("out.buf", kNuFileOpenWriteTrunc)) != NULL) { printf("*** Writing %u bytes\n", count); if (fwrite(buffer, count, 1, fp) != 1) err = kNuErrFileWrite; fclose(fp); } } else { printf("*** No data found!\n"); } bail: (void) NuFreeDataSink(pDataSink); return err; } /* * Do file stuff. */ int DoFileStuff(const UNICHAR* filenameUNI) { NuError err; NuArchive* pArchive = NULL; ArchiveData* pArchiveData = ArchiveData_New(); err = NuOpenRO(filenameUNI, &pArchive); if (err != kNuErrNone) goto bail; NuSetExtraData(pArchive, pArchiveData); printf("*** Gathering contents!\n"); err = NuContents(pArchive, GatherContents); if (err != kNuErrNone) goto bail; printf("*** Dumping contents!\n"); ArchiveData_DumpContents(pArchiveData); err = ExtractToFile(pArchive, pArchiveData); if (err != kNuErrNone) goto bail; err = ExtractToFP(pArchive, pArchiveData); if (err != kNuErrNone) goto bail; err = ExtractToBuffer(pArchive, pArchiveData); if (err != kNuErrNone) goto bail; bail: if (err != kNuErrNone) fprintf(stderr, "*** ERROR: got error %d\n", err); if (pArchive != NULL) { NuError err2 = NuClose(pArchive); if (err == kNuErrNone && err2 != kNuErrNone) err = err2; } ArchiveData_Free(pArchiveData); return err; } /* * Grab the name of an archive to read. If no name was provided, use stdin. */ int main(int argc, char** argv) { int32_t major, minor, bug; const char* pBuildDate; FILE* infp = NULL; int cc; (void) NuGetVersion(&major, &minor, &bug, &pBuildDate, NULL); printf("Using NuFX lib %d.%d.%d built on or after %s\n", major, minor, bug, pBuildDate); if (argc == 2) { infp = fopen(argv[1], kNuFileOpenReadOnly); if (infp == NULL) { perror("fopen failed"); exit(1); } } else { fprintf(stderr, "ERROR: you have to specify a filename\n"); exit(2); } cc = DoFileStuff(argv[1]); if (infp != NULL) fclose(infp); exit(cc != 0); } nulib2-3.1.0/nufxlib/samples/TestNames.c000066400000000000000000000370151316100516500200740ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * Test local and storage names with Unicode and Mac OS Roman content. * * On Windows, opening files with fancy filenames requires UTF-16 and * special functions. On Linux and Mac OS X we're just writing UTF-8 data, * so they don't really need to do anything special other than be 8-bit * clean. NufxLib functions take UTF-8 strings, so on Windows we define * everything in UTF-16 and convert to UTF-8. (We need the UTF-16 form so * we can use "wide" I/O functions to confirm that the file was created * with the correct name.) * * To see files with the correct appearance with "ls", you may need to * do something like: * * % LC_ALL=en_US.UTF-8 ls * * (Many users set LC_ALL=POSIX to avoid GNU grep slowdowns and altered * sort ordering in ls.) */ #include #include #include "NufxLib.h" #include "Common.h" /* * Test filenames. * * The local filename (kTestArchive) contains non-MOR Unicode values * (two Japanese characters that Google Translate claims form the verb * "shrink"). The temp file name is similar. * * The entry name uses a mix of simple ASCII, CP1252 MOR, and * non-CP1252 MOR characters: fl ligature, double dagger, copyright symbol, * Apple logo (the latter of which doesn't have a glyph on Windows or Linux). * All of the characters have MOR translations. */ #ifdef USE_UTF16 const UNICHAR kTestArchive[] = L"nlTest\u7e2e\u3080.shk"; const UNICHAR kTestEntryName[] = L"nl-test\u2013\ufb01_\u2021_\u00a9\uf8ff!"; const UNICHAR kTestTempFile[] = L"nlTest\4e00\u6642\u30d5\u30a1\u30a4\u30eb.tmp"; #else const UNICHAR kTestArchive[] = "nlTest\xe7\xb8\xae\xe3\x82\x80.shk"; const UNICHAR kTestEntryName[] = "nl-test\xe2\x80\x93\xef\xac\x81_\xe2\x80\xa1_" "\xc2\xa9\xef\xa3\xbf!"; const UNICHAR kTestTempFile[] = "nlTest\xe4\xb8\x80\xe6\x99\x82\xe3\x83\x95" "\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab.tmp"; #endif const UNICHAR kLocalFssep = '|'; /* * =========================================================================== * Helper functions * =========================================================================== */ /* * Get a single character of input from the user. */ static char TGetReplyChar(char defaultReply) { char tmpBuf[32]; if (fgets(tmpBuf, sizeof(tmpBuf), stdin) == NULL) return defaultReply; if (tmpBuf[0] == '\n' || tmpBuf[0] == '\r') return defaultReply; return tmpBuf[0]; } NuError AddSimpleRecord(NuArchive* pArchive, const char* fileNameMOR, NuRecordIdx* pRecordIdx) { NuFileDetails fileDetails; memset(&fileDetails, 0, sizeof(fileDetails)); fileDetails.storageNameMOR = fileNameMOR; fileDetails.fileSysInfo = kLocalFssep; fileDetails.access = kNuAccessUnlocked; return NuAddRecord(pArchive, &fileDetails, pRecordIdx); } /* * Display error messages... or not. */ NuResult ErrorMessageHandler(NuArchive* pArchive, void* vErrorMessage) { const NuErrorMessage* pErrorMessage = (const NuErrorMessage*) vErrorMessage; //if (gSuppressError) // return kNuOK; if (pErrorMessage->isDebug) { fprintf(stderr, "%sNufxLib says: [%s:%d %s] %s\n", pArchive == NULL ? "GLOBAL>" : "", pErrorMessage->file, pErrorMessage->line, pErrorMessage->function, pErrorMessage->message); } else { fprintf(stderr, "%sNufxLib says: %s\n", pArchive == NULL ? "GLOBAL>" : "", pErrorMessage->message); } return kNuOK; } #ifdef USE_UTF16 TODO - use _waccess, _wunlink, etc. #else int RemoveTestFile(const char* title, const char* fileName) { char answer; if (access(fileName, F_OK) == 0) { printf("%s '%s' exists, remove (y/n)? ", title, fileName); fflush(stdout); answer = TGetReplyChar('n'); if (tolower(answer) != 'y') return -1; if (unlink(fileName) < 0) { perror("unlink"); return -1; } } return 0; } #endif /* * Utility function that wraps NuConvertUNIToMOR, allocating a new * buffer to hold the converted string. The caller must free the result. */ char* CopyUNIToMOR(const UNICHAR* stringUNI) { size_t morLen; char* morBuf; morLen = NuConvertUNIToMOR(stringUNI, NULL, 0); if (morLen == (size_t) -1) { return NULL; } morBuf = (char*) malloc(morLen); (void) NuConvertUNIToMOR(stringUNI, morBuf, morLen); return morBuf; } /* * Utility function that wraps NuConvertMORToUNI, allocating a new * buffer to hold the converted string. The caller must free the result. */ UNICHAR* CopyMORToUNI(const char* stringMOR) { size_t uniLen; char* uniBuf; uniLen = NuConvertMORToUNI(stringMOR, NULL, 0); if (uniLen == (size_t) -1) { return NULL; } uniBuf = (UNICHAR*) malloc(uniLen); (void) NuConvertMORToUNI(stringMOR, uniBuf, uniLen); return uniBuf; } /* * =========================================================================== * Tests * =========================================================================== */ void DumpMorString(const char* str) { printf("(%d) ", (int) strlen(str)); while (*str != '\0') { if (*str >= 0x20 && *str < 0x7f) { putchar(*str); } else { printf("\\x%02x", (uint8_t) *str); } str++; } putchar('\n'); } void DumpUnicharString(const UNICHAR* str) { printf("(%d) ", (int) strlen(str)); while (*str != '\0') { if (*str >= 0x20 && *str < 0x7f) { putchar(*str); } else { if (sizeof(UNICHAR) == 1) { printf("\\x%02x", (uint8_t) *str); } else { printf("\\u%04x", (uint16_t) *str); } } str++; } putchar('\n'); } /* * Some basic string conversion unit tests. * * TODO: test with short buffer, make sure we don't get partial code * points when converting to Unicode */ int TestStringConversion(void) { static const char kMORTest[] = "test\xe0\xe9\xed\xf3\xfa#\xf0\xb0"; size_t outLen; char morBuf[512]; UNICHAR uniBuf[512]; // convert test string to Unicode memset(uniBuf, 0xcc, sizeof(uniBuf)); //printf("MOR: "); DumpMorString(kMORTest); outLen = NuConvertMORToUNI(kMORTest, NULL, 0); //printf("outLen is %u\n", (unsigned int) outLen); if (NuConvertMORToUNI(kMORTest, uniBuf, sizeof(uniBuf)) != outLen) { fprintf(stderr, "Inconsistent MORToUNI len\n"); return -1; } //printf("UNI: "); DumpUnicharString(uniBuf); if (strlen(uniBuf) + 1 != outLen) { fprintf(stderr, "Expected length != actual length\n"); return -1; } // convert Unicode back to MOR memset(morBuf, 0xcc, sizeof(morBuf)); outLen = NuConvertUNIToMOR(uniBuf, NULL, 0); //printf("outLen is %u\n", (unsigned int) outLen); if (NuConvertUNIToMOR(uniBuf, morBuf, sizeof(morBuf)) != outLen) { fprintf(stderr, "Inconsistent UNIToMOR len\n"); return -1; } //printf("MOR: "); DumpMorString(morBuf); if (strlen(morBuf) + 1 != outLen) { fprintf(stderr, "Expected length != actual length\n"); return -1; } // check vs. original if (strcmp(kMORTest, morBuf) != 0) { fprintf(stderr, "Test string corrupted by double conversion\n"); return -1; } #ifdef USE_UTF16 static const UNICHAR kNonMorUniStr[] = L"nlTest\u7e2e\u3080.shk"; static const UNICHAR kBadUniStr[] = L"nlTest\u7e2e\x30"; #else static const UNICHAR kNonMorUniStr[] = "nlTest\xe7\xb8\xae\xe3\x82\x80.shk"; static const UNICHAR kBadUniStr[] = "nlTest\x81\xe7"; #endif static const char kNonMorExpected[] = "nlTest??.shk"; static const char kBadExpected[] = "nlTest??"; NuConvertUNIToMOR(kNonMorUniStr, morBuf, sizeof(morBuf)); if (strcmp(morBuf, kNonMorExpected) != 0) { fprintf(stderr, "Non-MOR string conversion failed\n"); return -1; } NuConvertUNIToMOR(kBadUniStr, morBuf, sizeof(morBuf)); if (strcmp(morBuf, kBadExpected) != 0) { fprintf(stderr, "Bad UNI string conversion failed\n"); return -1; } printf("... string conversion tests successful\n"); return 0; } /* * Create a new entry and give it a trivial data fork. */ int AddTestEntry(NuArchive* pArchive, const char* entryNameMOR) { NuDataSource* pDataSource = NULL; NuRecordIdx recordIdx; static const char* kTestMsg = "Hello, world!\n"; uint32_t status; NuError err; /* * Add our test entry. */ err = AddSimpleRecord(pArchive, entryNameMOR, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: add record failed (err=%d)\n", err); goto failed; } err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, (const uint8_t*)kTestMsg, 0, strlen(kTestMsg), NULL, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: source create failed (err=%d)\n", err); goto failed; } err = NuAddThread(pArchive, recordIdx, kNuThreadIDDataFork, pDataSource, NULL); if (err != kNuErrNone) { fprintf(stderr, "ERROR: thread add failed (err=%d)\n", err); goto failed; } pDataSource = NULL; /* now owned by library */ /* * Flush changes. */ err = NuFlush(pArchive, &status); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't flush after add (err=%d, status=%u)\n", err, status); goto failed; } return 0; failed: if (pDataSource != NULL) NuFreeDataSource(pDataSource); return -1; } /* * Extract the file we created. */ int TestExtract(NuArchive* pArchive, const char* entryNameMOR) { const NuRecord* pRecord; NuRecordIdx recordIdx; NuError err; err = NuGetRecordIdxByName(pArchive, entryNameMOR, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't find '%s' (err=%d)\n", entryNameMOR, err); return -1; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record index %u (err=%d)\n", recordIdx, err); return -1; } assert(pRecord != NULL); const NuThread* pThread = NULL; uint32_t idx; for (idx = 0; idx < NuRecordGetNumThreads(pRecord); idx++) { pThread = NuGetThread(pRecord, idx); if (NuGetThreadID(pThread) == kNuThreadIDDataFork) break; } if (pThread == NULL) { fprintf(stderr, "ERROR: no data thread?\n"); return -1; } /* * Prepare the output file. */ UNICHAR* entryNameUNI = CopyMORToUNI(entryNameMOR); NuDataSink* pDataSink = NULL; err = NuCreateDataSinkForFile(true, kNuConvertOff, entryNameUNI, kLocalFssep, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data sink for file (err=%d)\n", err); free(entryNameUNI); return -1; } err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: extract failed (err=%d)\n", err); (void) NuFreeDataSink(pDataSink); free(entryNameUNI); return -1; } (void) NuFreeDataSink(pDataSink); printf("... confirming extraction of '%s'\n", entryNameUNI); if (access(entryNameUNI, F_OK) != 0) { fprintf(stderr, "ERROR: unable to read '%s' (err=%d)\n", entryNameUNI, errno); free(entryNameUNI); return -1; } if (unlink(entryNameUNI) < 0) { perror("unlink test entry"); free(entryNameUNI); return -1; } free(entryNameUNI); return 0; } /* * Run some tests. * * Returns 0 on success, -1 on error. */ int DoTests(void) { NuError err; NuArchive* pArchive = NULL; char* testEntryNameMOR = NULL; int result = 0; if (TestStringConversion() < 0) { goto failed; } /* * Make sure we're starting with a clean slate. */ if (RemoveTestFile("Test archive", kTestArchive) < 0) { goto failed; } if (RemoveTestFile("Test temp file", kTestTempFile) < 0) { goto failed; } if (RemoveTestFile("Test entry", kTestEntryName) < 0) { goto failed; } testEntryNameMOR = CopyUNIToMOR(kTestEntryName); /* * Create a new archive to play with. */ err = NuOpenRW(kTestArchive, kTestTempFile, kNuOpenCreat|kNuOpenExcl, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: NuOpenRW failed (err=%d)\n", err); goto failed; } if (NuSetErrorMessageHandler(pArchive, ErrorMessageHandler) == kNuInvalidCallback) { fprintf(stderr, "ERROR: couldn't set message handler\n"); goto failed; } /* * Add a single entry. */ if (AddTestEntry(pArchive, testEntryNameMOR) != 0) { goto failed; } printf("... checking presence of '%s' and '%s'\n", kTestArchive, kTestTempFile); if (access(kTestTempFile, F_OK) != 0) { /* in theory, NufxLib doesn't need to use the temp file we provide, so this test isn't entirely sound */ fprintf(stderr, "ERROR: did not find %s (err=%d)\n", kTestTempFile, err); goto failed; } /* * Close it and confirm that the file has the expected name. */ err = NuClose(pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: mid NuClose failed (err=%d)\n", err); goto failed; } pArchive = NULL; if (access(kTestArchive, F_OK) != 0) { fprintf(stderr, "ERROR: did not find %s (err=%d)\n", kTestArchive, err); goto failed; } /* * Reopen it read-only. */ printf("... reopening archive read-only\n"); err = NuOpenRO(kTestArchive, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: NuOpenRO failed (err=%d)\n", err); goto failed; } if (NuSetErrorMessageHandler(pArchive, ErrorMessageHandler) == kNuInvalidCallback) { fprintf(stderr, "ERROR: couldn't set message handler\n"); goto failed; } /* * Extract the file. */ if (TestExtract(pArchive, testEntryNameMOR) < 0) { goto failed; } /* * That's all, folks... */ NuClose(pArchive); pArchive = NULL; printf("... removing '%s'\n", kTestArchive); if (unlink(kTestArchive) < 0) { perror("unlink kTestArchive"); goto failed; } leave: if (pArchive != NULL) { NuAbort(pArchive); NuClose(pArchive); } free(testEntryNameMOR); return result; failed: result = -1; goto leave; } /* * Start here. */ int main(void) { int32_t major, minor, bug; const char* pBuildDate; const char* pBuildFlags; int cc; (void) NuGetVersion(&major, &minor, &bug, &pBuildDate, &pBuildFlags); printf("Using NuFX library v%d.%d.%d, built on or after\n" " %s with [%s]\n\n", major, minor, bug, pBuildDate, pBuildFlags); if (NuSetGlobalErrorMessageHandler(ErrorMessageHandler) == kNuInvalidCallback) { fprintf(stderr, "ERROR: can't set the global message handler"); exit(1); } printf("... starting tests\n"); cc = DoTests(); printf("... tests ended, %s\n", cc == 0 ? "SUCCESS" : "FAILURE"); exit(cc != 0); } nulib2-3.1.0/nufxlib/samples/TestSimple.c000066400000000000000000000055421316100516500202620ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * Simple test program. Opens an archive, dumps the contents. * * If the first argument is "-", this will read from stdin. Otherwise, * the first argument is taken to be an archive filename, and opened. */ #include #include "NufxLib.h" #include "Common.h" /* * Callback function to display the contents of a single record. * * "pRecord->filename" is the record's filename, whether from the record * header, a filename thread, or a default value ("UNKNOWN", stuffed in * when a record has no filename at all). */ NuResult ShowContents(NuArchive* pArchive, void* vpRecord) { const NuRecord* pRecord = (NuRecord*) vpRecord; size_t bufLen = NuConvertMORToUNI(pRecord->filenameMOR, NULL, 0); if (bufLen == (size_t) -1) { fprintf(stderr, "GLITCH: unable to convert '%s'\n", pRecord->filenameMOR); } else { UNICHAR* buf = (UNICHAR*) malloc(bufLen); NuConvertMORToUNI(pRecord->filenameMOR, buf, bufLen); printf("*** Filename = '%s'\n", buf); free(buf); } return kNuOK; } /* * Dump the contents from the streaming input. * * If we're not interested in handling an archive on stdin, we could just * pass the filename in here and use NuOpenRO instead. */ int DoStreamStuff(FILE* fp) { NuError err; NuArchive* pArchive = NULL; err = NuStreamOpenRO(fp, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to open stream archive (err=%d)\n", err); goto bail; } printf("*** Streaming contents!\n"); err = NuContents(pArchive, ShowContents); if (err != kNuErrNone) { fprintf(stderr, "ERROR: NuContents failed (err=%d)\n", err); goto bail; } bail: if (pArchive != NULL) { NuError err2 = NuClose(pArchive); if (err == kNuErrNone) err = err2; } return err; } /* * Grab the name of an archive to read. If "-" was given, use stdin. */ int main(int argc, char** argv) { int32_t major, minor, bug; const char* pBuildDate; FILE* infp = NULL; int cc; (void) NuGetVersion(&major, &minor, &bug, &pBuildDate, NULL); printf("Using NuFX lib %d.%d.%d built on or after %s\n", major, minor, bug, pBuildDate); if (argc != 2) { fprintf(stderr, "Usage: %s (archive-name|-)\n", argv[0]); exit(2); } if (strcmp(argv[1], "-") == 0) infp = stdin; else { infp = fopen(argv[1], kNuFileOpenReadOnly); if (infp == NULL) { fprintf(stderr, "ERROR: unable to open '%s'\n", argv[1]); exit(1); } } cc = DoStreamStuff(infp); exit(cc != 0); } nulib2-3.1.0/nufxlib/samples/TestTwirl.c000066400000000000000000000465331316100516500201370ustar00rootroot00000000000000/* * NuFX archive manipulation library * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING.LIB. * * Recompress records in place, several times, possibly deleting records * or threads as we go. The goal is to perform a large number of operations * that modify the archive without closing and reopening it. * * Depending on which #defines are enabled, this can be very destructive, * so a copy of the archive is made before processing begins. */ #include #include #include #include #include "NufxLib.h" #include "Common.h" /* copy the archive to this file before starting */ static const char* kWorkFileName = "TwirlCopy678"; static const char* kTempFileName = "TwirlTmp789"; /* after loading this much stuff into memory, flush changes */ const int kMaxHeldLen = 1024 * 1024; /* * A list of CRCs. */ typedef struct CRCList { int numEntries; uint16_t* entries; } CRCList; /* * Returns true if the compression type is supported, false otherwise. */ int CompressionSupported(NuValue compression) { int result; switch (compression) { case kNuCompressNone: result = true; break; case kNuCompressSQ: result = (NuTestFeature(kNuFeatureCompressSQ) == kNuErrNone); break; case kNuCompressLZW1: case kNuCompressLZW2: result = (NuTestFeature(kNuFeatureCompressLZW) == kNuErrNone); break; case kNuCompressLZC12: case kNuCompressLZC16: result = (NuTestFeature(kNuFeatureCompressLZC) == kNuErrNone); break; case kNuCompressDeflate: result = (NuTestFeature(kNuFeatureCompressDeflate) == kNuErrNone); break; case kNuCompressBzip2: result = (NuTestFeature(kNuFeatureCompressBzip2) == kNuErrNone); break; default: assert(false); result = false; } /*printf("Returning %d for %ld\n", result, compression);*/ return result; } /* * This gets called when a buffer DataSource is no longer needed. */ NuResult FreeCallback(NuArchive* pArchive, void* args) { free(args); return kNuOK; } /* * Dump a CRC list. */ void DumpCRCs(const CRCList* pCRCList) { int i; printf(" NumEntries: %d\n", pCRCList->numEntries); for (i = 0; i < pCRCList->numEntries; i++) printf(" %5d: 0x%04x\n", i, pCRCList->entries[i]); } /* * Free a CRC list. */ void FreeCRCs(CRCList* pCRCList) { if (pCRCList == NULL) return; free(pCRCList->entries); free(pCRCList); } /* * Gather a list of CRCs from the archive. * * We assume there are at most two data threads (e.g. data fork and rsrc * fork) in a record. * * Returns the list on success, NULL on failure. */ CRCList* GatherCRCs(NuArchive* pArchive) { NuError err = kNuErrNone; const NuMasterHeader* pMasterHeader; CRCList* pCRCList = NULL; uint16_t* pEntries = NULL; long recCount, maxCRCs; long recIdx, crcIdx; int i; pCRCList = malloc(sizeof(*pCRCList)); if (pCRCList == NULL) { fprintf(stderr, "ERROR: couldn't alloc CRC list\n"); err = kNuErrGeneric; goto bail; } memset(pCRCList, 0, sizeof(*pCRCList)); /* get record count out of master header, just for fun */ err = NuGetMasterHeader(pArchive, &pMasterHeader); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get master header (err=%d)\n", err); goto bail; } recCount = pMasterHeader->mhTotalRecords; maxCRCs = recCount * 2; pEntries = malloc(sizeof(*pEntries) * maxCRCs); if (pEntries == NULL) { fprintf(stderr, "ERROR: unable to alloc CRC list (%ld entries)\n", maxCRCs); err = kNuErrGeneric; goto bail; } pCRCList->entries = pEntries; for (i = 0; i < maxCRCs; i++) pEntries[i] = 0xdead; /* * Enumerate our way through the records. If something was disturbed * we should end up in a different place and the CRCs will be off. */ crcIdx = 0; for (recIdx = 0; recIdx < recCount; recIdx++) { NuRecordIdx recordIdx; const NuRecord* pRecord; const NuThread* pThread; err = NuGetRecordIdxByPosition(pArchive, recIdx, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record #%ld (err=%d)\n", recIdx, err); goto bail; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to get recordIdx %u\n", recordIdx); goto bail; } if (NuRecordGetNumThreads(pRecord) == 0) { fprintf(stderr, "ERROR: not expecting empty record (%u)!\n", recordIdx); err = kNuErrGeneric; goto bail; } int rsrcCrcIdx = -1; for (i = 0; i < (int)NuRecordGetNumThreads(pRecord); i++) { pThread = NuGetThread(pRecord, i); if (pThread->thThreadClass == kNuThreadClassData) { if (crcIdx >= maxCRCs) { fprintf(stderr, "ERROR: CRC buffer exceeded\n"); assert(false); err = kNuErrGeneric; goto bail; } /* * Ensure that the data fork CRC comes first. Otherwise * we can fail if it gets rearranged. This is only a * problem for GSHK-created archives that don't have * threads for every fork, so "mask dataless" is create * fake entries. * * The correct way to do this is to store a tuple * { thread-kind, crc }, but that's more work. */ if (pThread->thThreadKind == kNuThreadKindRsrcFork) { rsrcCrcIdx = crcIdx; } if (pThread->thThreadKind == kNuThreadKindDataFork && rsrcCrcIdx != -1) { /* this is the data fork, we've already seen the resource fork; swap entries */ pEntries[crcIdx++] = pEntries[rsrcCrcIdx]; pEntries[rsrcCrcIdx] = pThread->thThreadCRC; } else { pEntries[crcIdx++] = pThread->thThreadCRC; } } } } pCRCList->numEntries = crcIdx; DumpCRCs(pCRCList); bail: if (err != kNuErrNone) { FreeCRCs(pCRCList); pCRCList = NULL; } return pCRCList; } /* * Compare the current set of CRCs against our saved list. If any of * the records or threads were deleted or rearranged, this will fail. * I happen to think this is a *good* thing: if something is the least * bit screwy, I want to know about it. * * Unfortunately, if we *deliberately* delete records, this can't * help us with the survivors. * * Returns 0 on success, nonzero on failure. */ int CompareCRCs(NuArchive* pArchive, const CRCList* pOldCRCList) { CRCList* pNewCRCList = NULL; int result = -1; int badCrc = 0; int i; pNewCRCList = GatherCRCs(pArchive); if (pNewCRCList == NULL) { fprintf(stderr, "ERROR: unable to gather new list\n"); goto bail; } if (pOldCRCList->numEntries != pNewCRCList->numEntries) { fprintf(stderr, "ERROR: numEntries mismatch: %d vs %d\n", pOldCRCList->numEntries, pNewCRCList->numEntries); goto bail; } for (i = 0; i < pNewCRCList->numEntries; i++) { if (pOldCRCList->entries[i] != pNewCRCList->entries[i]) { fprintf(stderr, "ERROR: CRC mismatch: %5d old=0x%04x new=0x%04x\n", i, pOldCRCList->entries[i], pNewCRCList->entries[i]); badCrc = 1; } } if (!badCrc) { printf(" Matched %d CRCs\n", pOldCRCList->numEntries); result = 0; } bail: FreeCRCs(pNewCRCList); return result; } /* * Recompress a single thread. * * This entails (1) extracting the existing thread, (2) deleting the * thread, and (3) adding the extracted data. * * All of this good stuff gets queued up until the next NuFlush call. */ NuError RecompressThread(NuArchive* pArchive, const NuRecord* pRecord, const NuThread* pThread) { NuError err = kNuErrNone; NuDataSource* pDataSource = NULL; NuDataSink* pDataSink = NULL; uint8_t* buf = NULL; if (pThread->actualThreadEOF == 0) { buf = malloc(1); if (buf == NULL) { fprintf(stderr, "ERROR: failed allocating trivial buffer\n"); err = kNuErrGeneric; goto bail; } } else { /* * Create a buffer and data sink to hold the data. */ buf = malloc(pThread->actualThreadEOF); if (buf == NULL) { fprintf(stderr, "ERROR: failed allocating %u bytes\n", pThread->actualThreadEOF); err = kNuErrGeneric; goto bail; } err = NuCreateDataSinkForBuffer(true, kNuConvertOff, buf, pThread->actualThreadEOF, &pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data sink (err=%d)\n",err); goto bail; } /* * Extract the data. */ err = NuExtractThread(pArchive, pThread->threadIdx, pDataSink); if (err != kNuErrNone) { fprintf(stderr, "ERROR: failed extracting thread %u in '%s': %s\n", pThread->threadIdx, pRecord->filenameMOR, NuStrError(err)); goto bail; } } /* * Delete the existing thread. */ err = NuDeleteThread(pArchive, pThread->threadIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to delete thread %u\n", pThread->threadIdx); goto bail; } /* * Create a data source for the new thread. Specify a callback to free * the buffer when NufxLib is done with it. */ err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, buf, 0, pThread->actualThreadEOF, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data source (err=%d)\n", err); goto bail; } buf = NULL; /* * Create replacement thread. */ err = NuAddThread(pArchive, pRecord->recordIdx, NuGetThreadID(pThread), pDataSource, NULL); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to add new thread ID=0x%08x (err=%d)\n", NuGetThreadID(pThread), err); goto bail; } pDataSource = NULL; /* now owned by NufxLib */ bail: NuFreeDataSink(pDataSink); NuFreeDataSource(pDataSource); free(buf); return err; } /* * Recompress a single record. * * The amount of data we're holding in memory as a result of the * recompression is placed in "*pLen". */ NuError RecompressRecord(NuArchive* pArchive, NuRecordIdx recordIdx, long* pLen) { NuError err = kNuErrNone; const NuRecord* pRecord; const NuThread* pThread; int i; printf(" Recompressing %u\n", recordIdx); *pLen = 0; err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to get record %u (err=%d)\n", recordIdx, err); goto bail; } for (i = 0; i < (int)NuRecordGetNumThreads(pRecord); i++) { pThread = NuGetThread(pRecord, i); if (pThread->thThreadClass == kNuThreadClassData) { /*printf(" Recompressing %d (threadID=0x%08lx)\n", i, NuGetThreadID(pThread));*/ err = RecompressThread(pArchive, pRecord, pThread); if (err != kNuErrNone) { fprintf(stderr, "ERROR: failed recompressing thread %u " " in record %u (err=%d)\n", pThread->threadIdx, pRecord->recordIdx, err); goto bail; } *pLen += pThread->actualThreadEOF; } else { /*printf(" Skipping %d (threadID=0x%08lx)\n", i, NuGetThreadID(pThread));*/ } } bail: return err; } /* * Recompress every data thread in the archive. */ NuError RecompressArchive(NuArchive* pArchive, NuValue compression) { NuError err = kNuErrNone; NuRecordIdx* pIndices = NULL; NuAttr countAttr; long heldLen; long idx; err = NuSetValue(pArchive, kNuValueDataCompression, compression); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to set compression to %u (err=%d)\n", compression, err); goto bail; } printf("Recompressing threads with compression type %u\n", compression); err = NuGetAttr(pArchive, kNuAttrNumRecords, &countAttr); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to get numRecords (err=%d)\n", err); goto bail; } if (countAttr == 0) { printf("No records found!\n"); goto bail; } /* * Get all of the indices up front. This way, if something causes a * record to "disappear" during processing, we will know about it. */ pIndices = malloc(countAttr * sizeof(*pIndices)); if (pIndices == NULL) { fprintf(stderr, "ERROR: malloc on %u indices failed\n", countAttr); err = kNuErrGeneric; goto bail; } for (idx = 0; idx < (int)countAttr; idx++) { err = NuGetRecordIdxByPosition(pArchive, idx, &pIndices[idx]); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record #%ld (err=%d)\n", idx, err); goto bail; } } /* * Walk through the index list, handling each record individually. */ heldLen = 0; for (idx = 0; idx < (int)countAttr; idx++) { long recHeldLen; err = RecompressRecord(pArchive, pIndices[idx], &recHeldLen); if (err != kNuErrNone) { fprintf(stderr, "ERROR: failed recompressing record %u (err=%d)\n", pIndices[idx], err); goto bail; } heldLen += recHeldLen; if (heldLen > kMaxHeldLen) { uint32_t statusFlags; printf(" (flush)\n"); err = NuFlush(pArchive, &statusFlags); if (err != kNuErrNone) { fprintf(stderr, "ERROR: intra-recompress flush failed: %s\n", NuStrError(err)); goto bail; } heldLen = 0; } } bail: free(pIndices); return err; } /* * Initiate the twirling. */ int TwirlArchive(const char* filename) { NuError err = kNuErrNone; NuArchive* pArchive = NULL; CRCList* pCRCList = NULL; int compression; int cc; /* * Open the archive after removing any temp file remnants. */ cc = unlink(kTempFileName); if (cc == 0) printf("Removed stale temp file '%s'\n", kTempFileName); err = NuOpenRW(filename, kTempFileName, 0, &pArchive); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to open archive '%s': %s\n", filename, NuStrError(err)); goto bail; } /* * Mask records with no data threads, so we don't have to * special-case them. */ err = NuSetValue(pArchive, kNuValueMaskDataless, true); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't mask dataless (err=%d)\n", err); goto bail; } pCRCList = GatherCRCs(pArchive); if (pCRCList == NULL) { fprintf(stderr, "ERROR: unable to get CRC list\n"); goto bail; } /* * For each type of compression, recompress the entire archive. */ for (compression = kNuCompressNone; compression <= kNuCompressBzip2; compression++) { uint32_t statusFlags; if (!CompressionSupported(compression)) continue; err = RecompressArchive(pArchive, compression); if (err != kNuErrNone) { fprintf(stderr, "ERROR: recompress failed: %s\n", NuStrError(err)); goto bail; } err = NuFlush(pArchive, &statusFlags); if (err != kNuErrNone) { fprintf(stderr, "ERROR: post-recompress flush failed: %s\n", NuStrError(err)); goto bail; } } /* * Same thing, reverse order. We want to start with the same one we * ended on above, so we can practice skipping over things. */ for (compression = kNuCompressBzip2; compression >= kNuCompressNone; compression--) { uint32_t statusFlags; if (!CompressionSupported(compression)) continue; err = RecompressArchive(pArchive, compression); if (err != kNuErrNone) { fprintf(stderr, "ERROR: recompress2 failed: %s\n", NuStrError(err)); goto bail; } err = NuFlush(pArchive, &statusFlags); if (err != kNuErrNone) { fprintf(stderr, "ERROR: post-recompress flush2 failed: %s\n", NuStrError(err)); goto bail; } } if (CompareCRCs(pArchive, pCRCList) != 0) { fprintf(stderr, "ERROR: CRCs didn't match\n"); goto bail; } printf("Done!\n"); bail: FreeCRCs(pCRCList); if (pArchive != NULL) { NuAbort(pArchive); NuClose(pArchive); } return (err != kNuErrNone); } /* * Copy from the current offset in "srcfp" to a new file called * "outFileName". Returns a writable file descriptor for the new file * on success, or NULL on error. * * (Note "CopyFile()" exists under Win32.) */ FILE* MyCopyFile(const char* outFileName, FILE* srcfp) { char buf[24576]; FILE* outfp; size_t count; outfp = fopen(outFileName, kNuFileOpenWriteTrunc); if (outfp == NULL) { fprintf(stderr, "ERROR: unable to open '%s' (err=%d)\n", outFileName, errno); return NULL; } while (!feof(srcfp)) { count = fread(buf, 1, sizeof(buf), srcfp); if (count == 0) break; if (fwrite(buf, 1, count, outfp) != count) { fprintf(stderr, "ERROR: failed writing outfp (err=%d)\n", errno); fclose(outfp); return NULL; } } if (ferror(srcfp)) { fprintf(stderr, "ERROR: failed reading srcfp (err=%d)\n", errno); fclose(outfp); return NULL; } return outfp; } /* * Let's get started. */ int main(int argc, char** argv) { int32_t major, minor, bug; const char* pBuildDate; FILE* srcfp = NULL; FILE* infp = NULL; int cc; /* don't buffer output */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); (void) NuGetVersion(&major, &minor, &bug, &pBuildDate, NULL); printf("Using NuFX lib %d.%d.%d built on or after %s\n\n", major, minor, bug, pBuildDate); if (argc == 2) { srcfp = fopen(argv[1], kNuFileOpenReadOnly); if (srcfp == NULL) { perror("fopen failed"); exit(1); } } else { fprintf(stderr, "ERROR: you have to specify a filename\n"); exit(2); } printf("Copying '%s' to '%s'\n", argv[1], kWorkFileName); infp = MyCopyFile(kWorkFileName, srcfp); if (infp == NULL) { fprintf(stderr, "Copy failed, bailing.\n"); exit(1); } fclose(srcfp); fclose(infp); cc = TwirlArchive(kWorkFileName); exit(cc != 0); } nulib2-3.1.0/nulib2/000077500000000000000000000000001316100516500140775ustar00rootroot00000000000000nulib2-3.1.0/nulib2/.gitignore000066400000000000000000000000621316100516500160650ustar00rootroot00000000000000Makefile config.h config.log config.status nulib2 nulib2-3.1.0/nulib2/Add.c000066400000000000000000000052531316100516500147400ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Add files to or update files in the archive. */ #include "NuLib2.h" static NuError AddToArchive(NulibState* pState, NuArchive* pArchive); /* * Add the specified files to a new or existing archive. */ NuError DoAdd(NulibState* pState) { NuError err; NuArchive* pArchive = NULL; uint32_t flushStatus; Assert(pState != NULL); err = OpenArchiveReadWrite(pState); if (err != kNuErrNone) goto bail; pArchive = NState_GetNuArchive(pState); Assert(pArchive != NULL); NState_SetMatchCount(pState, 0); /* tell them about the list of files */ err = AddToArchive(pState, pArchive); if (err != kNuErrNone) goto bail; /*(void)NuDebugDumpArchive(pArchive);*/ if (!NState_GetMatchCount(pState)) printf("%s: no records matched\n", gProgName); bail: if (pArchive != NULL) { NuError err2; #if 0 if (err != kNuErrNone) { printf("Attempting to flush changes in spite of errors...\n"); err = kNuErrNone; } #endif if (err == kNuErrNone) { err = NuFlush(pArchive, &flushStatus); if (err != kNuErrNone) { if (flushStatus & kNuFlushSucceeded) { ReportError(err, "Changes were successfully written, but something " "failed afterward"); } else { ReportError(err, "Unable to flush archive changes (status=0x%04x)", flushStatus); } NuAbort(pArchive); } } else { NuAbort(pArchive); } err2 = NuClose(pArchive); Assert(err2 == kNuErrNone); } return err; } /* * Add the requested files to the specified archive. * * This just results in NuAddFile calls; the deferred write operation * isn't initiated. */ static NuError AddToArchive(NulibState* pState, NuArchive* pArchive) { NuError err = kNuErrNone; char* const* pSpec; int i; Assert(pState != NULL); Assert(pArchive != NULL); if (!NState_GetFilespecCount(pState)) { err = kNuErrSyntax; ReportError(err, "no files were specified"); } pSpec = NState_GetFilespecPointer(pState); for (i = NState_GetFilespecCount(pState); i > 0; i--, pSpec++) { err = AddFile(pState, pArchive, *pSpec); if (err != kNuErrNone) goto bail; } bail: return err; } nulib2-3.1.0/nulib2/ArcUtils.c000066400000000000000000000702011316100516500157710ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Common archive-related utility functions. */ #include "NuLib2.h" /* * =========================================================================== * Output pathnames * =========================================================================== */ /* * General-purpose output pathname filter, invoked by nufxlib via a * callback. Normalizes the pathname to match the current OS requirements. * * If we're extracting to stdout, this fills in the "newFp" field instead. * * The buffer we return to the archive library will be overwritten the * next time this function gets called. This is expected. */ static NuResult OutputPathnameFilter(NuArchive* pArchive, void* vproposal) { NuPathnameProposal* pathProposal = vproposal; NulibState* pState; const UNICHAR* newPathnameUNI; NuRecordIdx renameFromIdx; UNICHAR* renameToStrUNI; UNICHAR* resultBufUNI; Assert(pArchive != NULL); (void) NuGetExtraData(pArchive, (void**) &pState); Assert(pState != NULL); /* handle extract-to-pipe */ if (NState_GetCommand(pState) == kCommandExtractToPipe) { pathProposal->newDataSink = NState_GetPipeSink(pState); NState_SetSuppressOutput(pState, true); return kNuOK; } /* * If they're trying to rename this file, do so now. We don't run * the output through the normalizer; if the user typed it, assume * that it's okay (and let the OS tell them if it isn't). */ renameToStrUNI = NState_GetRenameToStr(pState); if (renameToStrUNI != NULL) { renameFromIdx = NState_GetRenameFromIdx(pState); if (renameFromIdx == pathProposal->pRecord->recordIdx) { /* right source file, proceed with the rename */ NState_SetTempPathnameLen(pState, strlen(renameToStrUNI) +1); resultBufUNI = NState_GetTempPathnameBuf(pState); Assert(resultBufUNI != NULL); strcpy(resultBufUNI, renameToStrUNI); pathProposal->newPathnameUNI = resultBufUNI; } /* free up renameToStrUNI */ NState_SetRenameToStr(pState, NULL); goto bail; } /* * Convert the pathname into something suitable for the current OS. */ newPathnameUNI = NormalizePath(pState, pathProposal); if (newPathnameUNI == NULL) { ReportError(kNuErrNone, "unable to convert pathname"); return kNuAbort; } pathProposal->newPathnameUNI = newPathnameUNI; bail: return kNuOK; } /* * =========================================================================== * User input * =========================================================================== */ /* * Get a single character from the input. * * For portability, I'm just getting a line of input and keeping the * first character. A fancier version would play with line disciplines * so you wouldn't have to hit "return". */ static char GetReplyChar(char defaultReply) { char tmpBuf[32]; if (fgets(tmpBuf, sizeof(tmpBuf), stdin) == NULL) return defaultReply; if (tmpBuf[0] == '\n' || tmpBuf[0] == '\r') return defaultReply; return tmpBuf[0]; } #define kMaxInputLen 128 /* * Get a string back from the user. * * String returned should be freed by the caller. */ static char* GetReplyString(const char* prompt) { char buf[kMaxInputLen]; char* result; int len; printf("%s", prompt); fflush(stdout); result = fgets(buf, sizeof(buf), stdin); if (result == NULL || feof(stdin) || ferror(stdin) || buf[0] == '\0' || buf[0] == '\n') { return NULL; } /* nuke the terminating '\n', which is lots of fun in filenames */ len = strlen(buf); if (buf[len-1] == '\n') buf[len-1] = '\0'; return strdup(buf); } /* * Get a one-line comment from the user, of at most "maxLen" bytes. * * If the user enters a blank line, return "NULL". * * A pointer to a newly-allocated buffer is returned. */ char* GetSimpleComment(NulibState* pState, const char* pathname, int maxLen) { char* buf = NULL; char* result; int len; buf = Malloc(maxLen); if (buf == NULL) return NULL; printf("Enter one-line comment for '%s'\n: ", pathname); fflush(stdout); result = fgets(buf, maxLen, stdin); if (result == NULL || feof(stdin) || ferror(stdin) || buf[0] == '\0' || buf[0] == '\n') { Free(buf); return NULL; } /* nuke the terminating '\n', which we don't need */ len = strlen(buf); if (buf[len-1] == '\n') buf[len-1] = '\0'; return buf; } /* * =========================================================================== * Callbacks (progress updates, error handling, record selection) * =========================================================================== */ #define kMaxDisplayLen 60 /* * Returns "true" if the filespec in "spec" matches what's in "pRecord". * * (Someday "spec" might be a regexp.) */ static Boolean SpecMatchesRecord(NulibState* pState, const char* spec, const NuRecord* pRecord) { #ifdef NU_CASE_SENSITIVE if (NState_GetModRecurse(pState)) return (strncmp(spec, pRecord->filename, strlen(spec)) == 0); else return (strcmp(spec, pRecord->filename) == 0); #else if (NState_GetModRecurse(pState)) return (strncasecmp(spec, pRecord->filenameMOR, strlen(spec)) == 0); else return (strcasecmp(spec, pRecord->filenameMOR) == 0); #endif } /* * Determine whether the current record we're examining is described by * the file specification given on the command line. * * If no filespec was provided, then all records are "specified". * * We pass the entire NuRecord in because we may want to allow * extraction by criteria other than name, e.g. all text files or all * files archived before a certain date. */ Boolean IsSpecified(NulibState* pState, const NuRecord* pRecord) { char* const* pSpec; int i; if (!NState_GetFilespecCount(pState)) return true; pSpec = NState_GetFilespecPointer(pState); for (i = NState_GetFilespecCount(pState); i > 0; i--, pSpec++) { if (SpecMatchesRecord(pState, *pSpec, pRecord)) return true; } return false; } /* * General-purpose selection filter, invoked as a callback. Compares the * selection proposal with the filenames in "filespec". */ NuResult SelectionFilter(NuArchive* pArchive, void* vproposal) { const NuSelectionProposal* selProposal = vproposal; NulibState* pState; Assert(pArchive != NULL); (void) NuGetExtraData(pArchive, (void**) &pState); Assert(pState != NULL); if (IsSpecified(pState, selProposal->pRecord)) { NState_IncMatchCount(pState); /* we don't get progress notifications for delete, so do it here */ if (NState_GetCommand(pState) == kCommandDelete) { printf("Deleting %s\n", selProposal->pRecord->filenameMOR); } return kNuOK; } else { return kNuSkip; } } /* * Print a three-digit progress percentage; range is 0% to 100%. */ void PrintPercentage(uint32_t total, uint32_t progress) { uint32_t perc; if (!total) { /*printf(" %%");*/ printf(" "); return; } if (total < 21474836) { perc = (progress * 100 + 50) / total; if (perc > 100) perc = 100; } else { perc = progress / (total / 100); if (perc > 100) perc = 100; } printf("%3d%%", perc); } /* * Show our progress, unless we're expanding to a pipe. Invoked as a * callback by nufxlib. */ NuResult ProgressUpdater(NuArchive* pArchive, void* vProgress) { const NuProgressData* pProgress = vProgress; NulibState* pState; const char* percStr; const char* actionStr; char nameBuf[kMaxDisplayLen+1]; Boolean showName, eolConv; Assert(pArchive != NULL); (void) NuGetExtraData(pArchive, (void**) &pState); Assert(pState != NULL); if (NState_GetSuppressOutput(pState)) return kNuOK; percStr = NULL; showName = false; eolConv = false; switch (pProgress->operation) { case kNuOpAdd: switch (pProgress->state) { case kNuProgressPreparing: case kNuProgressOpening: actionStr = "adding "; showName = true; break; case kNuProgressAnalyzing: actionStr = "analyzing "; break; case kNuProgressCompressing: actionStr = "compressing"; break; case kNuProgressStoring: actionStr = "storing "; break; default: actionStr = "?????? "; break; } break; case kNuOpExtract: switch (pProgress->state) { case kNuProgressPreparing: case kNuProgressOpening: actionStr = "extracting"; showName = true; break; case kNuProgressExpanding: actionStr = "expanding "; break; case kNuProgressCopying: actionStr = "extracting"; break; default: actionStr = "?????? "; break; } if (pProgress->expand.convertEOL == kNuConvertOn) eolConv = true; break; case kNuOpTest: switch (pProgress->state) { case kNuProgressPreparing: case kNuProgressOpening: showName = true; /* no break */ case kNuProgressExpanding: case kNuProgressCopying: actionStr = "verifying"; break; default: actionStr = "?????? "; break; } break; default: Assert(0); actionStr = "????"; } switch (pProgress->state) { case kNuProgressDone: actionStr = NULL; percStr = "DONE\n"; break; case kNuProgressSkipped: actionStr = NULL; percStr = "SKIP\n"; break; case kNuProgressAborted: /* not currently possible in NuLib2 */ actionStr = NULL; percStr = "CNCL\n"; break; case kNuProgressFailed: actionStr = NULL; percStr = "FAIL\n"; break; default: break; } if (showName) { /* * Use "pathname" (whole thing) rather than "filename" (file part). * Could also use "origPathname", but I like to show what they're * getting instead of what they're giving. */ int len = strlen(pProgress->pathnameUNI); if (len < sizeof(nameBuf)) { strcpy(nameBuf, pProgress->pathnameUNI); } else { nameBuf[0] = nameBuf[1] = '.'; strncpy(nameBuf+2, pProgress->pathnameUNI + len - (sizeof(nameBuf)-3), sizeof(nameBuf)-3); nameBuf[sizeof(nameBuf)-1] = '\0'; } } if (actionStr == NULL && percStr != NULL) { printf("\r%s", percStr); } else if (actionStr != NULL && percStr == NULL) { if (percStr == NULL) { putc('\r', stdout); PrintPercentage(pProgress->uncompressedLength, pProgress->uncompressedProgress); if (showName) printf(" %s%c %s", actionStr, eolConv ? '+' : ' ', nameBuf); else printf(" %s%c", actionStr, eolConv ? '+' : ' '); } } else { Assert(0); printf("????\n"); } fflush(stdout); /*printf(" %ld \n", pProgress->uncompressedProgress);*/ /*usleep(250000);*/ return kNuOK; } /* * Decide whether or not to replace an existing file (during extract) * or record (during add). */ static NuResult HandleReplaceExisting(NulibState* pState, NuArchive* pArchive, const NuErrorStatus* pErrorStatus) { NuResult result = kNuOK; char* renameName; char reply; Assert(pState != NULL); Assert(pErrorStatus != NULL); Assert(pErrorStatus->pathnameUNI != NULL); Assert(pErrorStatus->canOverwrite); Assert(pErrorStatus->canSkip); Assert(pErrorStatus->canAbort); if (NState_GetInputUnavailable(pState)) { putc('\n', stdout); ReportError(pErrorStatus->err, "Giving up"); result = kNuAbort; goto bail; } while (1) { printf("\n Replace %s? [y]es, [n]o, [A]ll, [N]one", pErrorStatus->pathnameUNI); if (pErrorStatus->canRename) /* renaming record adds not allowed */ printf(", [r]ename: "); else printf(": "); fflush(stdout); reply = GetReplyChar('n'); switch (reply) { case 'y': result = kNuOverwrite; goto bail; case 'n': result = kNuSkip; goto bail; case 'A': (void) NuSetValue(pArchive, kNuValueHandleExisting, kNuAlwaysOverwrite); result = kNuOverwrite; goto bail; case 'N': (void) NuSetValue(pArchive, kNuValueHandleExisting, kNuNeverOverwrite); result = kNuSkip; goto bail; case 'r': if (!pErrorStatus->canRename) { printf("Response not acceptable\n"); break; /* continue in "while" loop */ } renameName = GetReplyString("New name: "); if (renameName == NULL) break; /* continue in "while" loop */ if (pErrorStatus->pRecord == NULL) { ReportError(kNuErrNone, "Unexpected NULL record"); break; /* continue in "while" loop */ } NState_SetRenameFromIdx(pState, pErrorStatus->pRecord->recordIdx); NState_SetRenameToStr(pState, renameName); result = kNuRename; goto bail; case 'q': /* stealth option to quit */ case 'Q': result = kNuAbort; goto bail; default: printf("Response not understood -- please use y/n/A/N/r\n"); break; /* continue in "while" loop */ } } bail: return result; } /* * Found a bad CRC... should we press onward? * * Note pErrorStatus->pathname may be NULL if the error was found in the * master header or in the record header. */ static NuResult HandleBadCRC(NulibState* pState, NuArchive* pArchive, const NuErrorStatus* pErrorStatus) { NuResult result = kNuOK; char reply; Assert(pState != NULL); Assert(pErrorStatus != NULL); if (NState_GetInputUnavailable(pState)) { putc('\n', stderr); ReportError(pErrorStatus->err, "Giving up"); result = kNuAbort; goto bail; } while (1) { if (pErrorStatus->pathnameUNI != NULL) fprintf(stderr, "\n Found a bad CRC in %s\n", pErrorStatus->pathnameUNI); else fprintf(stderr, "\n Found a bad CRC in the archive\n"); fprintf(stderr, " Archive may be damaged, continue anyway? [y]es, [n]o: "); fflush(stderr); reply = GetReplyChar('n'); switch (reply) { case 'y': result = kNuIgnore; goto bail; case 'n': case 'N': result = kNuAbort; goto bail; default: fprintf(stderr, "Response not understood -- please use y/n\n"); break; /* continue in "while" loop */ } } bail: return result; } /* * Tried to add a nonexistent file; continue? * * To make this happen, you need to: * - nulib2 aer lots-of-files another-file * - remove another-file while nulib2 is still processing lots-of-files * * The trick is to delete a file explicitly mentioned on the command line * after NuFlush starts to do its thing. Otherwise, we're just using * the system equivalent of readdir to scan a directory, so deleting a * file just means it won't get added. */ static NuResult HandleAddNotFound(NulibState* pState, NuArchive* pArchive, const NuErrorStatus* pErrorStatus) { NuResult result = kNuOK; char reply; Assert(pState != NULL); Assert(pErrorStatus != NULL); Assert(pErrorStatus->pathnameUNI != NULL); if (NState_GetInputUnavailable(pState)) { putc('\n', stdout); ReportError(pErrorStatus->err, "Giving up"); result = kNuAbort; goto bail; } while (1) { fprintf(stderr, "\n Couldn't find %s, continue? [y]es, [n]o: ", pErrorStatus->pathnameUNI); fflush(stderr); reply = GetReplyChar('n'); switch (reply) { case 'y': result = kNuSkip; goto bail; case 'n': case 'N': result = kNuAbort; goto bail; default: fprintf(stderr, "Response not understood -- please use y/n\n"); break; /* continue in "while" loop */ } } bail: return result; } /* * Something failed, and the user may want to choose how to handle it. * Invoked as a callback. */ NuResult ErrorHandler(NuArchive* pArchive, void* vErrorStatus) { const NuErrorStatus* pErrorStatus = vErrorStatus; NulibState* pState; NuResult result; Assert(pArchive != NULL); (void) NuGetExtraData(pArchive, (void**) &pState); Assert(pState != NULL); /* default action is to abort the current operation */ result = kNuAbort; /* * When extracting, the error handler callback gets invoked for several * different problems because we might want to rename the file. Also, * because extractions are done with "bulk" calls, returning an * individual error message would be meaningless. * * When adding files, the NuAddFile and NuAddRecord calls can return * immediate, specific results for a single add. The only reasons for * calling here are to decide if an existing record should be replaced * or not (without even an option to rename), or to decide what to do * when the NuFlush call runs into a problem while adding a file. */ if (pErrorStatus->operation == kNuOpExtract) { if (pErrorStatus->err == kNuErrFileExists) { result = HandleReplaceExisting(pState, pArchive, pErrorStatus); } else if (pErrorStatus->err == kNuErrNotNewer) { /* if we were expecting this, it's okay */ if (NState_GetModFreshen(pState) || NState_GetModUpdate(pState)) { printf("\rSKIP\n"); result = kNuSkip; } else { DBUG(("WEIRD one\n")); } } else if (pErrorStatus->err == kNuErrDuplicateNotFound) { /* if we were expecting this, it's okay */ if (NState_GetModFreshen(pState)) { printf("\rSKIP\n"); result = kNuSkip; } else { DBUG(("WEIRD two\n")); } } } else if (pErrorStatus->operation == kNuOpAdd) { if (pErrorStatus->err == kNuErrRecordExists) { /* if they want to update or freshen, don't hassle them */ if (NState_GetModFreshen(pState) || NState_GetModUpdate(pState)) result = kNuOverwrite; else result = HandleReplaceExisting(pState, pArchive, pErrorStatus); } else if (pErrorStatus->err == kNuErrFileNotFound) { /* file was specified with NuAdd but removed during NuFlush */ result = HandleAddNotFound(pState, pArchive, pErrorStatus); } } else if (pErrorStatus->operation == kNuOpTest) { if (pErrorStatus->err == kNuErrBadMHCRC || pErrorStatus->err == kNuErrBadRHCRC || pErrorStatus->err == kNuErrBadThreadCRC || pErrorStatus->err == kNuErrBadDataCRC) { result = HandleBadCRC(pState, pArchive, pErrorStatus); } } return result; } #if 0 /* * Display an error message. * * (This was just a test to see if it worked... NufxLib's default behavior * is fine for NuLib2.) */ NuResult ErrorMessageHandler(NuArchive* pArchive, void* vErrorMessage) { const NuErrorMessage* pErrorMessage = (const NuErrorMessage*) vErrorMessage; fprintf(stderr, "%s%d %3d %s:%d %s %s\n", pArchive == NULL ? "(GLOBAL)" : "", pErrorMessage->isDebug, pErrorMessage->err, pErrorMessage->file, pErrorMessage->line, pErrorMessage->function, pErrorMessage->message); return kNuOK; } #endif /* * =========================================================================== * Open an archive * =========================================================================== */ /* an archive name of "-" indicates we want to use stdin */ static const char* kStdinArchive = "-"; /* * Determine whether the access bits on the record make it a read-only * file or not. * * Uses a simplified view of the access flags. */ Boolean IsRecordReadOnly(const NuRecord* pRecord) { if (pRecord->recAccess == 0x21L || pRecord->recAccess == 0x01L) return true; else return false; } /* * Returns "true" if "archiveName" is the name we use to represent stdin. */ Boolean IsFilenameStdin(const char* archiveName) { Assert(archiveName != NULL); return (strcmp(archiveName, kStdinArchive) == 0); } #define BailError(err) { if (err != kNuErrNone) goto bail; } /* * Open the archive in read-only mode. We use "file mode" for a file, or * "streaming mode" for stdin. */ NuError OpenArchiveReadOnly(NulibState* pState) { NuError err; NuArchive* pArchive = NULL; Assert(pState != NULL); if (IsFilenameStdin(NState_GetArchiveFilename(pState))) { err = NuStreamOpenRO(stdin, &pArchive); if (err != kNuErrNone) { ReportError(err, "unable to open stdin archive"); if (err == kNuErrIsBinary2) err = kNuErrNotNuFX; /* we can't seek back, so forget BNY */ goto bail; } /* * Since the archive is on stdin, we can't ask the user questions. * On a UNIX system we could open /dev/tty, but that's not portable, * and I don't think archives on stdin are going to be popular * enough to make this worth doing. */ NState_SetInputUnavailable(pState, true); } else { err = NuOpenRO(NState_GetArchiveFilename(pState), &pArchive); if (err != kNuErrNone) { if (err != kNuErrIsBinary2) { ReportError(err, "unable to open '%s'", NState_GetArchiveFilename(pState)); } goto bail; } } /* introduce them */ NState_SetNuArchive(pState, pArchive); err = NuSetExtraData(pArchive, pState); NuSetSelectionFilter(pArchive, SelectionFilter); NuSetOutputPathnameFilter(pArchive, OutputPathnameFilter); NuSetProgressUpdater(pArchive, ProgressUpdater); NuSetErrorHandler(pArchive, ErrorHandler); /*NuSetErrorMessageHandler(pArchive, ErrorMessageHandler);*/ /* set the EOL conversion */ if (NState_GetModConvertAll(pState)) err = NuSetValue(pArchive, kNuValueConvertExtractedEOL, kNuConvertOn); else if (NState_GetModConvertText(pState)) err = NuSetValue(pArchive, kNuValueConvertExtractedEOL, kNuConvertAuto); else err = NuSetValue(pArchive, kNuValueConvertExtractedEOL, kNuConvertOff); BailError(err); /* if we're converting EOL, we probably ought to do this too */ err = NuSetValue(pArchive, kNuValueStripHighASCII, true); BailError(err); /* handle "-s" flag */ if (NState_GetModOverwriteExisting(pState)) { err = NuSetValue(pArchive, kNuValueHandleExisting, kNuAlwaysOverwrite); BailError(err); } /* handle "-f" and "-u" flags (this overrides "-s" during extraction) */ if (NState_GetModFreshen(pState) || NState_GetModUpdate(pState)) { err = NuSetValue(pArchive, kNuValueOnlyUpdateOlder, true); BailError(err); } if (NState_GetModFreshen(pState)) { err = NuSetValue(pArchive, kNuValueHandleExisting, kNuMustOverwrite); BailError(err); } DBUG(("--- enabling ShrinkIt compatibility mode\n")); err = NuSetValue(pArchive, kNuValueMimicSHK, true); BailError(err); /* handy for some malformed archives */ err = NuSetValue(pArchive, kNuValueHandleBadMac, true); BailError(err); /* DBUG(("--- enabling 'mask dataless' mode\n")); err = NuSetValue(pArchive, kNuValueMaskDataless, true); BailError(err); */ if (strcmp(SYSTEM_DEFAULT_EOL, "\r") == 0) err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCR); else if (strcmp(SYSTEM_DEFAULT_EOL, "\n") == 0) err = NuSetValue(pArchive, kNuValueEOL, kNuEOLLF); else if (strcmp(SYSTEM_DEFAULT_EOL, "\r\n") == 0) err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCRLF); else { Assert(0); err = kNuErrInternal; ReportError(err, "Unknown SYSTEM_DEFAULT_EOL '%s'", SYSTEM_DEFAULT_EOL); goto bail; } BailError(err); bail: if (err != kNuErrNone && pArchive != NULL) { /* clean up */ (void) NuClose(pArchive); NState_SetNuArchive(pState, NULL); } return err; } /* * Open the archive in read-write mode, for purposes of adding, deleting, * or updating files. We don't plan on extracting anything with this. * * "Streaming mode" isn't allowed. */ NuError OpenArchiveReadWrite(NulibState* pState) { NuError err = kNuErrNone; NuArchive* pArchive = NULL; char* tempName = NULL; Assert(pState != NULL); Assert(IsFilenameStdin(NState_GetArchiveFilename(pState)) == false); tempName = MakeTempArchiveName(pState); if (tempName == NULL) goto bail; DBUG(("TEMP NAME = '%s'\n", tempName)); err = NuOpenRW(NState_GetArchiveFilename(pState), tempName, kNuOpenCreat, &pArchive); if (err != kNuErrNone) { ReportError(err, "unable to open '%s'", NState_GetArchiveFilename(pState)); goto bail; } /* introduce them */ NState_SetNuArchive(pState, pArchive); err = NuSetExtraData(pArchive, pState); BailError(err); NuSetSelectionFilter(pArchive, SelectionFilter); NuSetProgressUpdater(pArchive, ProgressUpdater); NuSetErrorHandler(pArchive, ErrorHandler); /*NuSetErrorMessageHandler(pArchive, ErrorMessageHandler);*/ /* handle "-0" flag */ if (NState_GetModNoCompression(pState)) { err = NuSetValue(pArchive, kNuValueDataCompression, kNuCompressNone); BailError(err); } /* handle "-z" flag */ if (NState_GetModCompressDeflate(pState)) { err = NuSetValue(pArchive, kNuValueDataCompression, kNuCompressDeflate); BailError(err); } /* handle "-zz" flag */ if (NState_GetModCompressBzip2(pState)) { err = NuSetValue(pArchive, kNuValueDataCompression, kNuCompressBzip2); BailError(err); } /* handle "-f" and "-u" flags */ /* (BUG: if "-f" is set, creating a new archive is impossible) */ if (NState_GetModFreshen(pState) || NState_GetModUpdate(pState)) { err = NuSetValue(pArchive, kNuValueOnlyUpdateOlder, true); BailError(err); } if (NState_GetModFreshen(pState)) { err = NuSetValue(pArchive, kNuValueHandleExisting, kNuMustOverwrite); BailError(err); } DBUG(("--- enabling ShrinkIt compatibility mode\n")); err = NuSetValue(pArchive, kNuValueMimicSHK, true); BailError(err); /* this probably isn't needed here, but set it anyway */ if (strcmp(SYSTEM_DEFAULT_EOL, "\r") == 0) err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCR); else if (strcmp(SYSTEM_DEFAULT_EOL, "\n") == 0) err = NuSetValue(pArchive, kNuValueEOL, kNuEOLLF); else if (strcmp(SYSTEM_DEFAULT_EOL, "\r\n") == 0) err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCRLF); else { Assert(0); err = kNuErrInternal; ReportError(err, "Unknown SYSTEM_DEFAULT_EOL '%s'", SYSTEM_DEFAULT_EOL); goto bail; } BailError(err); /*(void) NuSetValue(pArchive, kNuValueAllowDuplicates, true);*/ bail: Free(tempName); if (err != kNuErrNone && pArchive != NULL) { /* clean up */ NuAbort(pArchive); (void) NuClose(pArchive); NState_SetNuArchive(pState, NULL); } return err; } nulib2-3.1.0/nulib2/Binary2.c000066400000000000000000001214101316100516500155500ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Binary II support. * * The BNY format is significantly different from the NuFX format, so * support wasn't included in NufxLib. Since there's no reason to * create BNY archives when SHK is available, I've only implemented * data extraction features. * * (Technically, BNY isn't an archive format. It was a way to encapsulate * file attributes and file data for transmission over a modem, and was * meant to be added and stripped on the fly.) * * TO DO: add "junk skipping" like NufxLib has. */ #include "NuLib2.h" #ifdef HAVE_FCNTL_H # include #endif #ifndef O_BINARY # define O_BINARY 0 #endif /* how to open a file */ #ifdef FOPEN_WANTS_B # define kFileOpenReadOnly "rb" #else # define kFileOpenReadOnly "r" #endif /* * =========================================================================== * Utility functions * =========================================================================== */ /* * Open a file read-only. We abstract this so we get "r" vs "rb" right. * (Moves this to SysUtils.c if anybody else needs it.) */ NuError OpenFileReadOnly(const char* filename, FILE** pFp) { NuError err = kNuErrNone; *pFp = fopen(filename, kFileOpenReadOnly); if (*pFp == NULL) err = errno ? errno : kNuErrFileOpen; return err; } /* * Determine whether the current file we're examining is described by * the file specification given on the command line. * * If no filespec was provided, then all records are "specified". */ Boolean NameIsSpecified(NulibState* pState, const char* filename) { char* const* pSpec; int i; if (!NState_GetFilespecCount(pState)) return true; pSpec = NState_GetFilespecPointer(pState); for (i = NState_GetFilespecCount(pState); i > 0; i--, pSpec++) { #ifdef NU_CASE_SENSITIVE if (NState_GetModRecurse(pState)) { if (strncmp(*pSpec, filename, strlen(*pSpec)) == 0) return true; } else { if (strcmp(*pSpec, filename) == 0) return true; } #else if (NState_GetModRecurse(pState)) { if (strncasecmp(*pSpec, filename, strlen(*pSpec)) == 0) return true; } else { if (strcasecmp(*pSpec, filename) == 0) return true; } #endif } return false; } /* * =========================================================================== * Binary II goodies * =========================================================================== */ /* * State for the currently open Binary II archive. */ typedef struct BNYArchive { NulibState* pState; FILE* fp; Boolean first; } BNYArchive; #define kBNYBlockSize 128 /* BNY files are broken into blocks */ #define kBNYMaxFileName 64 #define kBNYMaxNativeName 48 #define kBNYFlagCompressed (1<<7) #define kBNYFlagEncrypted (1<<6) #define kBNYFlagSparse (1) /* * An entry in a Binary II archive. Each archive is essentially a stream * of files; only the "filesToFollow" value gives any indication that * something else follows this entry. */ typedef struct BNYEntry { uint16_t access; uint16_t fileType; uint32_t auxType; uint8_t storageType; uint32_t fileSize; /* in 512-byte blocks */ uint16_t prodosModDate; uint16_t prodosModTime; NuDateTime modWhen; /* computed from previous two fields */ uint16_t prodosCreateDate; uint16_t prodosCreateTime; NuDateTime createWhen; /* computed from previous two fields */ uint32_t eof; uint32_t realEOF; /* eof is bogus for directories */ char fileName[kBNYMaxFileName+1]; /* ASCII only */ char nativeName[kBNYMaxNativeName+1]; uint32_t diskSpace; /* in 512-byte blocks */ uint8_t osType; /* not exactly same as NuFileSysID */ uint16_t nativeFileType; uint8_t phantomFlag; uint8_t dataFlags; /* advisory flags */ uint8_t version; uint8_t filesToFollow; /* #of files after this one */ uint8_t blockBuf[kBNYBlockSize]; } BNYEntry; /* * Test for the magic number on a file in SQueezed format. */ static inline Boolean IsSqueezed(uint8_t one, uint8_t two) { return (one == 0x76 && two == 0xff); } /* * Test if this entry is a directory. */ static inline Boolean IsDir(BNYEntry* pEntry) { /* * NuLib and "unblu.c" compared against file type 15 (DIR), so I'm * going to do that too, but it would probably be better to compare * against storageType 0x0d. */ return (pEntry->fileType == 15); } /* * Initialize a BNYArchive structure. */ static BNYArchive* BNYInit(NulibState* pState) { BNYArchive* pBny; pBny = Malloc(sizeof(*pBny)); memset(pBny, 0, sizeof(*pBny)); pBny->pState = pState; return pBny; } /* * Free up a BNYArchive, disposing of anything inside it. */ static void BNYFree(BNYArchive* pBny) { /* don't need to do this on stdin, but won't really hurt */ if (pBny->fp != NULL) fclose(pBny->fp); Free(pBny); } /* * Open a Binary II archive read-only. Might be a file on disk or a * stream on stdin. */ static NuError BNYOpenReadOnly(BNYArchive* pBny) { NuError err = kNuErrNone; NulibState* pState; Assert(pBny != NULL); Assert(pBny->pState != NULL); Assert(pBny->fp == NULL); pState = pBny->pState; if (IsFilenameStdin(NState_GetArchiveFilename(pState))) { pBny->fp = stdin; /* * Since the archive is on stdin, we can't ask the user questions. * On a UNIX system we could open /dev/tty, but that's not portable, * and I don't think archives on stdin are going to be popular * enough to make this worth doing. */ NState_SetInputUnavailable(pState, true); } else { err = OpenFileReadOnly(NState_GetArchiveFilename(pState), &pBny->fp); if (err != kNuErrNone) { ReportError(err, "unable to open '%s'", NState_GetArchiveFilename(pState)); goto bail; } } bail: return err; } /* * Wrapper for fread(). Note the arguments resemble read(2) rather * than fread(3S). */ static NuError BNYRead(BNYArchive* pBny, void* buf, size_t nbyte) { size_t result; Assert(pBny != NULL); Assert(buf != NULL); Assert(nbyte > 0); Assert(pBny->fp != NULL); errno = 0; result = fread(buf, 1, nbyte, pBny->fp); if (result != nbyte) return errno ? errno : kNuErrFileRead; return kNuErrNone; } /* * Seek within an archive. Because we need to handle streaming archives, * and don't need to special-case anything, we only allow relative * forward seeks. */ static NuError BNYSeek(BNYArchive* pBny, long offset) { Assert(pBny != NULL); Assert(pBny->fp != NULL); Assert(pBny->pState != NULL); Assert(offset > 0); /*DBUG(("--- seeking forward %ld bytes\n", offset));*/ if (IsFilenameStdin(NState_GetArchiveFilename(pBny->pState))) { /* OPT: might be faster to fread a chunk at a time */ while (offset--) (void) getc(pBny->fp); if (ferror(pBny->fp) || feof(pBny->fp)) return kNuErrFileSeek; } else { if (fseek(pBny->fp, offset, SEEK_CUR) < 0) return kNuErrFileSeek; } return kNuErrNone; } /* * Convert from ProDOS compact date format to the expanded DateTime format. */ static void BNYConvertDateTime(uint16_t prodosDate, uint16_t prodosTime, NuDateTime* pWhen) { pWhen->second = 0; pWhen->minute = prodosTime & 0x3f; pWhen->hour = (prodosTime >> 8) & 0x1f; pWhen->day = (prodosDate & 0x1f) -1; pWhen->month = ((prodosDate >> 5) & 0x0f) -1; pWhen->year = (prodosDate >> 9) & 0x7f; if (pWhen->year < 40) pWhen->year += 100; /* P8 uses 0-39 for 2000-2039 */ pWhen->extra = 0; pWhen->weekDay = 0; } /* * Decode a Binary II header. * * See the File Type Note for $e0/8000 to decipher the buffer offsets * and meanings. */ static NuError BNYDecodeHeader(BNYArchive* pBny, BNYEntry* pEntry) { NuError err = kNuErrNone; uint8_t* raw; int len; Assert(pBny != NULL); Assert(pEntry != NULL); raw = pEntry->blockBuf; if (raw[0] != 0x0a || raw[1] != 0x47 || raw[2] != 0x4c || raw[18] != 0x02) { err = kNuErrBadData; ReportError(err, "this doesn't look like a Binary II header"); goto bail; } pEntry->access = raw[3] | raw[111] << 8; pEntry->fileType = raw[4] | raw[112] << 8; pEntry->auxType = raw[5] | raw[6] << 8 | raw[109] << 16 | raw[110] << 24; pEntry->storageType = raw[7]; pEntry->fileSize = raw[8] | raw[9] << 8; pEntry->prodosModDate = raw[10] | raw[11] << 8; pEntry->prodosModTime = raw[12] | raw[13] << 8; BNYConvertDateTime(pEntry->prodosModDate, pEntry->prodosModTime, &pEntry->modWhen); pEntry->prodosCreateDate = raw[14] | raw[15] << 8; pEntry->prodosCreateTime = raw[16] | raw[17] << 8; BNYConvertDateTime(pEntry->prodosCreateDate, pEntry->prodosCreateTime, &pEntry->createWhen); pEntry->eof = raw[20] | raw[21] << 8 | raw[22] << 16 | raw[116] << 24; len = raw[23]; if (len > kBNYMaxFileName) { err = kNuErrBadData; ReportError(err, "invalid filename length %d", len); goto bail; } memcpy(pEntry->fileName, &raw[24], len); pEntry->fileName[len] = '\0'; pEntry->nativeName[0] = '\0'; if (len <= 15 && raw[39] != 0) { len = raw[39]; if (len > kBNYMaxNativeName) { err = kNuErrBadData; ReportError(err, "invalid filename length %d", len); goto bail; } memcpy(pEntry->nativeName, &raw[40], len); pEntry->nativeName[len] = '\0'; } pEntry->diskSpace = raw[117] | raw[118] << 8 | raw[119] << 16 | raw[120] << 24; pEntry->osType = raw[121]; pEntry->nativeFileType = raw[122] | raw[123] << 8; pEntry->phantomFlag = raw[124]; pEntry->dataFlags = raw[125]; pEntry->version = raw[126]; pEntry->filesToFollow = raw[127]; /* directories are given an EOF but don't actually have any content */ if (IsDir(pEntry)) pEntry->realEOF = 0; else pEntry->realEOF = pEntry->eof; bail: return err; } /* * Normalize the pathname by running it through the usual NuLib2 * function. The trick here is that the function usually takes a * NuPathnameProposal, which we don't happen to have handy. Rather * than generalize the NuLib2 code, we just create a fake proposal, * which is a bit dicey but shouldn't break too easily. * * This takes care of -e, -ee, and -j. * * We return the new path, which is stored in NulibState's temporary * filename buffer. */ const char* BNYNormalizePath(BNYArchive* pBny, BNYEntry* pEntry) { NuPathnameProposal pathProposal; NuRecord fakeRecord; NuThread fakeThread; /* make uninitialized data obvious */ memset(&fakeRecord, 0xa1, sizeof(fakeRecord)); memset(&fakeThread, 0xa5, sizeof(fakeThread)); pathProposal.pathnameUNI = pEntry->fileName; pathProposal.filenameSeparator = '/'; /* BNY always uses ProDOS conv */ pathProposal.pRecord = &fakeRecord; pathProposal.pThread = &fakeThread; pathProposal.newPathnameUNI = NULL; pathProposal.newFilenameSeparator = '\0'; pathProposal.newDataSink = NULL; /* need the filetype and auxtype for -e/-ee */ fakeRecord.recFileType = pEntry->fileType; fakeRecord.recExtraType = pEntry->auxType; /* need the components of a ThreadID */ fakeThread.thThreadClass = kNuThreadClassData; fakeThread.thThreadKind = 0x0000; /* data fork */ return NormalizePath(pBny->pState, &pathProposal); } /* * Copy all data from the Binary II file to "outfp", reading in 128-byte * blocks. We need to read multiples of 128 bytes so that we're ready to * read the next entry without additional seeking. * * Some programs (like ProTERM) apply a 128-byte header without padding * out the file length, so we may come up short at the end of the file. * * Uses pEntry->blockBuf, which already has the first 128 bytes in it. */ static NuError BNYCopyBlocks(BNYArchive* pBny, BNYEntry* pEntry, FILE* outfp) { NuError err = kNuErrNone; long bytesLeft; Assert(pEntry->realEOF > 0); bytesLeft = pEntry->realEOF; while (bytesLeft > 0) { long toWrite; toWrite = bytesLeft; if (toWrite > kBNYBlockSize) toWrite = kBNYBlockSize; if (outfp != NULL) { if (fwrite(pEntry->blockBuf, toWrite, 1, outfp) != 1) { err = errno ? errno : kNuErrFileWrite; ReportError(err, "BNY write failed"); goto bail; } } bytesLeft -= toWrite; if (bytesLeft) { size_t actual; errno = 0; actual = fread(pEntry->blockBuf, 1, kBNYBlockSize, pBny->fp); if (actual != kBNYBlockSize) { /* failure or partial read */ if (actual != bytesLeft) { err = errno ? errno : kNuErrFileRead; ReportError(err, "BNY read failed"); goto bail; } else { DBUG(("+++ partial read %d/%d\n", actual, kBNYBlockSize)); } } } } bail: return err; } /* * =========================================================================== * Unsqueeze * =========================================================================== */ /* * This was ripped fairly directly from Squeeze.c in NufxLib. Because * there's relatively little code, and providing direct access to the * compression functions is a little unwieldy, I've cut & pasted the * necessary pieces here. */ #define FULL_SQ_HEADER #define kSqBufferSize 8192 /* must be enough to hold full SQ header */ #define kNuSQMagic 0xff76 /* magic value for file header */ #define kNuSQRLEDelim 0x90 /* RLE delimiter */ #define kNuSQEOFToken 256 /* distinguished stop symbol */ #define kNuSQNumVals 257 /* 256 symbols + stop */ /* * State during uncompression. */ typedef struct USQState { uint32_t dataInBuffer; uint8_t* dataPtr; int bitPosn; int bits; /* * Decoding tree; first "nodeCount" values are populated. Positive * values are indicies to another node in the tree, negative values * are literals (+1 because "negative zero" doesn't work well). */ int nodeCount; struct { short child[2]; /* left/right kids, must be signed 16-bit */ } decTree[kNuSQNumVals-1]; } USQState; /* * Decode the next symbol from the Huffman stream. */ static NuError USQDecodeHuffSymbol(USQState* pUsqState, int* pVal) { short val = 0; int bits, bitPosn; bits = pUsqState->bits; /* local copy */ bitPosn = pUsqState->bitPosn; do { if (++bitPosn > 7) { /* grab the next byte and use that */ bits = *pUsqState->dataPtr++; bitPosn = 0; if (!pUsqState->dataInBuffer--) return kNuErrBufferUnderrun; val = pUsqState->decTree[val].child[1 & bits]; } else { /* still got bits; shift right and use it */ val = pUsqState->decTree[val].child[1 & (bits >>= 1)]; } } while (val >= 0); /* val is negative literal; add one to make it zero-based then negate it */ *pVal = -(val + 1); pUsqState->bits = bits; pUsqState->bitPosn = bitPosn; return kNuErrNone; } /* * Read two bytes of signed data out of the buffer. */ static inline NuError USQReadShort(USQState* pUsqState, short* pShort) { if (pUsqState->dataInBuffer < 2) return kNuErrBufferUnderrun; *pShort = *pUsqState->dataPtr++; *pShort |= (*pUsqState->dataPtr++) << 8; pUsqState->dataInBuffer -= 2; return kNuErrNone; } /* * Expand "SQ" format. * * Because we have a stop symbol, knowing the uncompressed length of * the file is not essential. */ static NuError BNYUnSqueeze(BNYArchive* pBny, BNYEntry* pEntry, FILE* outfp) { NuError err = kNuErrNone; USQState usqState; uint32_t compRemaining, getSize; #ifdef FULL_SQ_HEADER uint16_t magic, fileChecksum, checksum; #endif short nodeCount; int i, inrep; uint8_t* tmpBuf = NULL; uint8_t lastc = 0; tmpBuf = Malloc(kSqBufferSize); if (tmpBuf == NULL) { err = kNuErrMalloc; goto bail; } usqState.dataInBuffer = 0; usqState.dataPtr = tmpBuf; usqState.bits = 0; compRemaining = pEntry->realEOF; #ifdef FULL_SQ_HEADER if (compRemaining < 8) #else if (compRemaining < 3) #endif { err = kNuErrBadData; ReportError(err, "too short to be valid SQ data"); goto bail; } /* * Round up to the nearest 128-byte boundary. We need to read * everything out of the file in case this is a streaming archive. * Because the compressed data has an embedded stop symbol, it's okay * to "overrun" the expansion code. */ compRemaining = ((compRemaining + kBNYBlockSize-1) / kBNYBlockSize) * kBNYBlockSize; /* want to grab up to kSqBufferSize bytes */ if (compRemaining > kSqBufferSize) getSize = kSqBufferSize; else getSize = compRemaining; /* copy the <= 128 bytes we already have into the general buffer */ memcpy(usqState.dataPtr, pEntry->blockBuf, kBNYBlockSize); if (getSize > kBNYBlockSize) { getSize -= kBNYBlockSize; compRemaining -= kBNYBlockSize; usqState.dataInBuffer += kBNYBlockSize; } else { Assert(compRemaining <= kBNYBlockSize); usqState.dataInBuffer = getSize; getSize = 0; compRemaining = 0; } /* temporarily advance dataPtr past the block we copied in */ usqState.dataPtr += kBNYBlockSize; /* * Grab a big chunk. "compRemaining" is the amount of compressed * data left in the file, usqState.dataInBuffer is the amount of * compressed data left in the buffer. * * We always want to read 128-byte blocks. */ if (getSize) { Assert(getSize <= kSqBufferSize); err = BNYRead(pBny, usqState.dataPtr, getSize); if (err != kNuErrNone) { ReportError(err, "failed reading compressed data (%u bytes)", getSize); goto bail; } usqState.dataInBuffer += getSize; if (getSize > compRemaining) compRemaining = 0; else compRemaining -= getSize; } /* reset dataPtr */ usqState.dataPtr = tmpBuf; /* * Read the header. We assume that the header will fit in the * compression buffer ( sq allowed 300+ for the filename, plus * 257*2 for the tree, plus misc). */ Assert(kSqBufferSize > 1200); #ifdef FULL_SQ_HEADER err = USQReadShort(&usqState, (short*) &magic); if (err != kNuErrNone) goto bail; if (magic != kNuSQMagic) { err = kNuErrBadData; ReportError(err, "bad magic number in SQ block"); goto bail; } err = USQReadShort(&usqState, (short*) &fileChecksum); if (err != kNuErrNone) goto bail; checksum = 0; /* skip over the filename */ while (*usqState.dataPtr++ != '\0') usqState.dataInBuffer--; usqState.dataInBuffer--; #endif err = USQReadShort(&usqState, &nodeCount); if (err != kNuErrNone) goto bail; if (nodeCount < 0 || nodeCount >= kNuSQNumVals) { err = kNuErrBadData; ReportError(err, "invalid decode tree in SQ (%d nodes)", nodeCount); goto bail; } usqState.nodeCount = nodeCount; /* initialize for possibly empty tree (only happens on an empty file) */ usqState.decTree[0].child[0] = -(kNuSQEOFToken+1); usqState.decTree[0].child[1] = -(kNuSQEOFToken+1); /* read the nodes, ignoring "read errors" until we're done */ for (i = 0; i < nodeCount; i++) { err = USQReadShort(&usqState, &usqState.decTree[i].child[0]); err = USQReadShort(&usqState, &usqState.decTree[i].child[1]); } if (err != kNuErrNone) { err = kNuErrBadData; ReportError(err, "SQ data looks truncated at tree"); goto bail; } usqState.bitPosn = 99; /* force an immediate read */ /* * Start pulling data out of the file. We have to Huffman-decode * the input, and then feed that into an RLE expander. * * A completely lopsided (and broken) Huffman tree could require * 256 tree descents, so we want to try to ensure we have at least 256 * bits in the buffer. Otherwise, we could get a false buffer underrun * indication back from DecodeHuffSymbol. * * The SQ sources actually guarantee that a code will fit entirely * in 16 bits, but there's no reason not to use the larger value. */ inrep = false; while (1) { int val; if (usqState.dataInBuffer < 65 && compRemaining) { /* * Less than 256 bits, but there's more in the file. * * First thing we do is slide the old data to the start of * the buffer. */ if (usqState.dataInBuffer) { Assert(tmpBuf != usqState.dataPtr); memmove(tmpBuf, usqState.dataPtr, usqState.dataInBuffer); } usqState.dataPtr = tmpBuf; /* * Next we read as much as we can. */ if (kSqBufferSize - usqState.dataInBuffer < compRemaining) getSize = kSqBufferSize - usqState.dataInBuffer; else getSize = compRemaining; Assert(getSize <= kSqBufferSize); err = BNYRead(pBny, usqState.dataPtr + usqState.dataInBuffer, getSize); if (err != kNuErrNone) { ReportError(err, "failed reading compressed data (%u bytes)", getSize); goto bail; } usqState.dataInBuffer += getSize; if (getSize > compRemaining) compRemaining = 0; else compRemaining -= getSize; Assert(compRemaining < 32767*65536); Assert(usqState.dataInBuffer <= kSqBufferSize); } err = USQDecodeHuffSymbol(&usqState, &val); if (err != kNuErrNone) { ReportError(err, "failed decoding huff symbol"); goto bail; } if (val == kNuSQEOFToken) break; /* * Feed the symbol into the RLE decoder. */ if (inrep) { /* * Last char was RLE delim, handle this specially. We use * --val instead of val-- because we already emitted the * first occurrence of the char (right before the RLE delim). */ if (val == 0) { /* special case -- just an escaped RLE delim */ lastc = kNuSQRLEDelim; val = 2; } while (--val) { /*if (pCrc != NULL) *pCrc = Nu_CalcCRC16(*pCrc, &lastc, 1);*/ if (outfp != NULL) putc(lastc, outfp); #ifdef FULL_SQ_HEADER checksum += lastc; #endif } inrep = false; } else { /* last char was ordinary */ if (val == kNuSQRLEDelim) { /* set a flag and catch the count the next time around */ inrep = true; } else { lastc = val; /*if (pCrc != NULL) *pCrc = Nu_CalcCRC16(*pCrc, &lastc, 1);*/ if (outfp != NULL) putc(lastc, outfp); #ifdef FULL_SQ_HEADER checksum += lastc; #endif } } } if (inrep) { err = kNuErrBadData; ReportError(err, "got stop symbol when run length expected"); goto bail; } #ifdef FULL_SQ_HEADER /* verify the checksum stored in the SQ file */ if (checksum != fileChecksum) { err = kNuErrBadDataCRC; ReportError(err, "expected 0x%04x, got 0x%04x (SQ)", fileChecksum, checksum); goto bail; } else { DBUG(("--- SQ checksums match (0x%04x)\n", checksum)); } #endif /* * Gobble up any unused bytes in the last 128-byte block. There * shouldn't be more than that left over. */ if (compRemaining > kSqBufferSize) { err = kNuErrBadData; ReportError(err, "wow: found %u bytes left over", compRemaining); goto bail; } if (compRemaining) { DBUG(("+++ slurping up last %ld bytes\n", compRemaining)); err = BNYRead(pBny, tmpBuf, compRemaining); if (err != kNuErrNone) { ReportError(err, "failed reading leftovers"); goto bail; } } bail: if (outfp != NULL) fflush(outfp); Free(tmpBuf); return err; } /* * =========================================================================== * Iterators * =========================================================================== */ typedef NuError (*BNYIteratorFunc)(BNYArchive* pBny, BNYEntry* pEntry, Boolean* consumedFlag); /* * Iterate through a Binary II archive, calling "func" to perform * operations on the file. */ static NuError BNYIterate(NulibState* pState, BNYIteratorFunc func) { NuError err = kNuErrNone; BNYArchive* pBny = NULL; BNYEntry entry; Boolean consumed; int first = true; int toFollow; Assert(pState != NULL); Assert(func != NULL); NState_SetMatchCount(pState, 0); pBny = BNYInit(pState); if (pBny == NULL) { err = kNuErrMalloc; goto bail; } err = BNYOpenReadOnly(pBny); if (err != kNuErrNone) goto bail; toFollow = 1; /* assume 1 file in archive */ pBny->first = true; while (toFollow) { err = BNYRead(pBny, entry.blockBuf, sizeof(entry.blockBuf)); if (err != kNuErrNone) { ReportError(err, "failed while reading header in '%s'", NState_GetArchiveFilename(pState)); goto bail; } err = BNYDecodeHeader(pBny, &entry); if (err != kNuErrNone) { if (first) ReportError(err, "not a Binary II archive?"); goto bail; } /* * If the file has one or more blocks, read the first block now. * This will allow the various functions to evaluate the file * contents for SQueeze compression. */ if (entry.realEOF != 0) { err = BNYRead(pBny, entry.blockBuf, sizeof(entry.blockBuf)); if (err != kNuErrNone) { ReportError(err, "failed while reading '%s'", NState_GetArchiveFilename(pState)); goto bail; } } /* * Invoke the appropriate function if this file was requested. */ consumed = false; if (NameIsSpecified(pBny->pState, entry.fileName)) { NState_IncMatchCount(pState); err = (*func)(pBny, &entry, &consumed); if (err != kNuErrNone) goto bail; pBny->first = false; } /* * If they didn't "consume" the entire BNY entry, we need to * do it for them. We've already read the first block (if it * existed), so we don't need to eat that one again. */ if (!consumed) { int nblocks = (entry.realEOF + kBNYBlockSize-1) / kBNYBlockSize; if (nblocks > 1) { err = BNYSeek(pBny, (nblocks-1) * kBNYBlockSize); if (err != kNuErrNone) { ReportError(err, "failed while seeking forward"); goto bail; } } } if (!first) { if (entry.filesToFollow != toFollow -1) { ReportError(kNuErrNone, "WARNING: filesToFollow %d, expected %d\n", entry.filesToFollow, toFollow -1); } } toFollow = entry.filesToFollow; first = false; } if (!NState_GetMatchCount(pState)) printf("%s: no records match\n", gProgName); bail: if (pBny != NULL) BNYFree(pBny); if (err != kNuErrNone) { DBUG(("--- Iterator returning failure %d\n", err)); } return err; } /* * Get a quick table of contents. */ static NuError BNYListShort(BNYArchive* pBny, BNYEntry* pEntry, Boolean* pConsumedFlag) { NuError err = kNuErrNone; printf("%s\n", pEntry->fileName); return err; } /* * Get a verbose listing of contents. */ static NuError BNYListVerbose(BNYArchive* pBny, BNYEntry* pEntry, Boolean* pConsumedFlag) { NuError err = kNuErrNone; Boolean isSqueezed, isReadOnly; NulibState* pState; char date1[kDateOutputLen]; int len; pState = pBny->pState; if (pBny->first) { const char* ccp; if (IsFilenameStdin(NState_GetArchiveFilename(pState))) ccp = ""; else ccp = FilenameOnly(pState, NState_GetArchiveFilename(pState)); printf("%-59.59s Files:%5u\n\n", ccp, pEntry->filesToFollow+1); printf(" Name Type Auxtyp Modified" " Fmat Length\n"); printf("-------------------------------------------------" "----------------------\n"); } isSqueezed = false; if (pEntry->realEOF && IsSqueezed(pEntry->blockBuf[0], pEntry->blockBuf[1])) isSqueezed = true; len = strlen(pEntry->fileName); isReadOnly = pEntry->access == 0x21L || pEntry->access == 0x01L; if (len <= 27) { printf("%c%-27.27s ", isReadOnly ? '+' : ' ', pEntry->fileName); } else { printf("%c..%-25.25s ", isReadOnly ? '+' : ' ', pEntry->fileName + len - 25); } printf("%s $%04X ", GetFileTypeString(pEntry->fileType), pEntry->auxType); printf("%s ", FormatDateShort(&pEntry->modWhen, date1)); if (isSqueezed) printf("squ "); else printf("unc "); printf("%8u", pEntry->realEOF); printf("\n"); if (!pEntry->filesToFollow) { /* last entry, print footer */ printf("-------------------------------------------------" "----------------------\n"); } return err; } /* * Get a verbose table of contents. */ static NuError BNYListDebug(BNYArchive* pBny, BNYEntry* pEntry, Boolean* pConsumedFlag) { NuError err = kNuErrNone; printf("File name: '%s' Native name: '%s' BNY Version %d\n", pEntry->fileName, pEntry->nativeName, pEntry->version); printf(" Phantom: %s DataFlags: 0x%02x (%s%s%s)\n", pEntry->phantomFlag ? "YES" : "no", pEntry->dataFlags, pEntry->dataFlags & kBNYFlagCompressed ? "compr" : "", pEntry->dataFlags & kBNYFlagEncrypted ? "encry" : "", pEntry->dataFlags & kBNYFlagSparse ? "sparse" : ""); printf(" Modified %d/%02d/%02d %02d:%02d Created %d/%02d/%02d %02d:%02d\n", pEntry->modWhen.year+1900, pEntry->modWhen.month, pEntry->modWhen.day, pEntry->modWhen.hour, pEntry->modWhen.minute, pEntry->createWhen.year+1900, pEntry->createWhen.month, pEntry->createWhen.day, pEntry->createWhen.hour, pEntry->createWhen.minute); printf(" FileType: 0x%04x AuxType: 0x%08x StorageType: 0x%02x\n", pEntry->fileType, pEntry->auxType, pEntry->storageType); printf(" EOF: %u FileSize: %u blocks DiskSpace: %u blocks\n", pEntry->eof, pEntry->fileSize, pEntry->diskSpace); printf(" Access: 0x%04x OSType: %d NativeFileType: 0x%04x\n", pEntry->access, pEntry->osType, pEntry->nativeFileType); if (pEntry->realEOF) { printf(" *File begins 0x%02x 0x%02x%s\n", pEntry->blockBuf[0], pEntry->blockBuf[1], IsSqueezed(pEntry->blockBuf[0], pEntry->blockBuf[1]) ? " (probably SQueezed)" : ""); } printf(" FilesToFollow: %d\n", pEntry->filesToFollow); return err; } /* quick enum to simplify our lives a bit */ typedef enum { kBNYExtNormal, kBNYExtPipe, kBNYExtTest } ExtMode; /* * Handle "extraction" of a directory. */ static NuError BNYExtractDirectory(BNYArchive* pBny, BNYEntry* pEntry, ExtMode extMode) { NuError err = kNuErrNone; const char* newName; Boolean isDir; const char* actionStr = "HOSED"; if (extMode == kBNYExtTest) { actionStr = "skipping "; } else if (NState_GetModJunkPaths(pBny->pState)) { actionStr = "skipping "; } else { /* * Using the normalized name of a directory is a problem * when "-e" is set. Since Binary II officially only * allows ProDOS names, and everything under the sun that * supports "long" filenames can handle 15 chars of * [A-Z][a-z][0-9][.], I'm going to skip the normalization * step. * * The "right" way to handle this is to ignore the directory * entries and just create any directories for the fully * normalized pathname generated below. */ /*newName = BNYNormalizePath(pBny, pEntry);*/ newName = pEntry->fileName; if (newName == NULL) goto bail; err = TestFileExistence(newName, &isDir); if (err == kNuErrNone) { if (isDir) { actionStr = "skipping "; } else { err = kNuErrFileExists; ReportError(err, "unable to create directory '%s'", newName); goto bail; } } else if (err == kNuErrFileNotFound) { err = Mkdir(newName); if (err == kNuErrNone) { actionStr = "creating "; } else { ReportError(err, "failed creating directory '%s'", newName); } } } if (!NState_GetSuppressOutput(pBny->pState)) { printf("\rDONE %s %s (directory)\n", actionStr, pEntry->fileName); } bail: return err; } /* * Handle "extract", "extract to pipe", and "test". */ static NuError BNYExtract(BNYArchive* pBny, BNYEntry* pEntry, Boolean* pConsumedFlag) { NuError err = kNuErrNone; NulibState* pState; ExtMode extMode; const char* actionStr = "HOSED"; FILE* outfp = NULL; Boolean eolConv; pState = pBny->pState; switch (NState_GetCommand(pState)) { case kCommandExtract: extMode = kBNYExtNormal; break; case kCommandExtractToPipe: extMode = kBNYExtPipe; break; case kCommandTest: extMode = kBNYExtTest; break; default: err = kNuErrInternal; ReportError(err, "unexpected command %d in BNYExtract", NState_GetCommand(pState)); Assert(0); goto bail; } /*eolConv = NState_GetModConvertAll(pState);*/ eolConv = false; /* maybe someday */ /* * Binary II requires that all directories be listed explicitly. * If we see one, create it. */ if (IsDir(pEntry)) { err = BNYExtractDirectory(pBny, pEntry, extMode); goto bail; } /* * Open the file, taking various command line flags into account. * If we're writing to a pipe, just use that. If we're in test * mode, the output goes nowhere. */ if (extMode == kBNYExtPipe) { outfp = stdout; } else if (extMode == kBNYExtNormal) { /* * Normalize the filename. If the file is squeezed, and it ends * with ".QQ", strip off the .QQ part. (The SQ format actually * includes a filename within, but it could be confusing to use * that instead of the name in the BNY archive, so I've decided to * ignore it.) */ const char* newName; Boolean isDir; char* ext; /* if we find .qq on a squeezed file, just stomp the copy in pEntry */ if (strlen(pEntry->fileName) > 3) { ext = pEntry->fileName + strlen(pEntry->fileName) -3; if (IsSqueezed(pEntry->blockBuf[0], pEntry->blockBuf[1]) && strcasecmp(ext, ".qq") == 0) { *ext = '\0'; } } newName = BNYNormalizePath(pBny, pEntry); if (newName == NULL) goto bail; err = TestFileExistence(newName, &isDir); if (err == kNuErrNone) { /* file exists, what to do? */ if (isDir) { err = kNuErrFileExists; ReportError(err, "unable to replace directory '%s'", newName); goto bail; } if (!NState_GetModOverwriteExisting(pState)) { err = kNuErrFileExists; ReportError(err, "unable to overwrite '%s' (try '-s'?)", newName); goto bail; } } else if (err != kNuErrFileNotFound) { ReportError(err, "stat failed on '%s'", newName); goto bail; } else { Assert(err == kNuErrFileNotFound); err = kNuErrNone; } /* open it, overwriting anything present */ outfp = fopen(newName, "w"); if (outfp == NULL) { err = kNuErrFileOpen; goto bail; } } else { /* outfp == NULL means we're in test mode */ Assert(outfp == NULL); } /* * Show initial progress update message ("extracting" or "expanding", * depending on whether or not the file was squeezed). */ if (IsSqueezed(pEntry->blockBuf[0], pEntry->blockBuf[1])) actionStr = "expanding "; else actionStr = "extracting"; if (extMode == kBNYExtTest) actionStr = "verifying"; if (!NState_GetSuppressOutput(pState)) { printf("\r 0%% %s%c %s", actionStr, eolConv ? '+' : ' ', pEntry->fileName); } /* * Extract the file. Send the output, perhaps with EOL conversion, * to the output file. * * Thought for the day: assuming a file is Squeezed based only on * the magic number is bogus. If we get certain classes of failures, * and this isn't a streaming archive, we should back up and just * extract it as a plain file. * * If the file is empty, don't do anything. */ if (pEntry->realEOF) { if (IsSqueezed(pEntry->blockBuf[0], pEntry->blockBuf[1])) err = BNYUnSqueeze(pBny, pEntry, outfp); else err = BNYCopyBlocks(pBny, pEntry, outfp); if (err != kNuErrNone) goto bail; } /* * Show final progress update. */ if (!NState_GetSuppressOutput(pState)) { printf("\rDONE\n"); } *pConsumedFlag = true; bail: if (outfp != NULL && outfp != stdout) { #if defined(MAC_LIKE) if (SetFinderInfo(fileno(outfp), pEntry->fileType, pEntry->auxType) != kNuErrNone) { fprintf(stderr, "WARNING: unable to set finder info\n"); } #endif fclose(outfp); } return err; } /* * =========================================================================== * Entry points from NuLib2 * =========================================================================== */ NuError BNYDoExtract(NulibState* pState) { if (NState_GetModConvertText(pState) || NState_GetModConvertAll(pState)) { fprintf(stderr, "%s: Binary II extraction doesn't support '-l' or '-ll'\n", gProgName); return kNuErrSyntax; } if (NState_GetModUpdate(pState) || NState_GetModFreshen(pState)) { fprintf(stderr, "%s: Binary II extraction doesn't support '-f' or '-u'\n", gProgName); return kNuErrSyntax; } if (NState_GetModComments(pState)) { fprintf(stderr, "%s: Binary II extraction doesn't support '-c'\n", gProgName); return kNuErrSyntax; } if (NState_GetCommand(pState) == kCommandExtractToPipe) NState_SetSuppressOutput(pState, true); return BNYIterate(pState, BNYExtract); } NuError BNYDoTest(NulibState* pState) { return BNYIterate(pState, BNYExtract); } NuError BNYDoListShort(NulibState* pState) { return BNYIterate(pState, BNYListShort); } NuError BNYDoListVerbose(NulibState* pState) { return BNYIterate(pState, BNYListVerbose); } NuError BNYDoListDebug(NulibState* pState) { return BNYIterate(pState, BNYListDebug); } nulib2-3.1.0/nulib2/COPYING000066400000000000000000000027501316100516500151360ustar00rootroot00000000000000Copyright (C) 2007, Andy McFadden. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of project contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nulib2-3.1.0/nulib2/ChangeLog.txt000066400000000000000000000153511316100516500164740ustar00rootroot000000000000002017/09/21 ***** v3.1.0 shipped ***** 2015/12/26 fadden - Fix handling of entries with missing threads. - Improve handling of Mac OS X file type attributes. - Updated "recognized extensions" table. 2015/01/09 ***** v3.0.0 shipped ***** 2015/01/03 fadden - Mac OS X: get file/aux type from FinderInfo when adding files. - Mac OS X: set file type and creator when extracting from Binary ][. 2015/01/02 fadden - Distinguish Unicode and Mac OS Roman strings. 2014/12/22 fadden - Source code cleanup. 2014/10/30 ***** v2.2.2 shipped ***** 2014/10/28 fadden - Switched from CVS on sourceforge to github. - Updated configure scripts and makefiles. 2009/01/13 fadden - Handle files wrapped in Binary ][ by ProTERM. - (This was marked as 2.2.1, but not delivered as a formal release.) 2007/02/19 ***** v2.2.0 shipped ***** 2007/02/19 fadden - Enable "bad Mac" handling. - Switched from GPL to BSD license. 2006/02/18 ***** v2.1.1 shipped ***** 2006/02/18 fadden - Fix handling of MS-DOS reserved names. Besides handling names like "con", we also need to handle "con.foo.txt". 2005/09/17 ***** v2.1.0 shipped ***** 2004/10/11 ***** v2.0.3 shipped ***** 2004/03/10 ***** v2.0.2 shipped ***** 2003/10/16 ***** v2.0.1 shipped ***** 2003/03/18 ***** v2.0.0 shipped ***** 2003/02/18 fadden - When extracting with "-ee", disk images now have ".PO" appended. - Resurrected HandleAddNotFound(). - Switched to case-sensitive filename comparisons. 2003/02/08 fadden - Upped version to v2.0.0. - Many fixes to pathname handling: - Correctly handle '%' when preservation is OFF. - Accept 4-char extensions in '-ee' without risk of buffer overflow. - Fixed broken assert when converting long %xx names. - Store "AUX" as "%00AUX" when preserving Win32 names (vs. "_AUX"). - Always store files with ':' as path separator. - Recognize that some Win32 variants (Win2K and later at the least) will accept both '/' and '\' as pathname separators. - Correctly convert ".//foo" to "foo" instead of "/foo". - Tracked changes to NufxLib DataSource API. 2003/01/10 fadden - Check NufxLib "compiled" version against "linked" version. 2002/12/06 fadden - Made minor changes to allow linking NufxLib in as a DLL. 2002/10/20 ***** v1.1.0 shipped ***** 2002/10/10 fadden - added fancy help text (-h) 2002/10/09 fadden - added "-zz" flag to specify libbz2's "bzip2" compression 2002/10/08 fadden - added Binary II support 2002/09/30 fadden - added "-z" flag to specify zlib's "deflate" compression (the "secret" debug dump command is now -g) 2002/09/26 fadden - progress updater now shows "analyzing" for scan pass of SQ 2002/09/23 fadden - ran the code through valgrind; found and fixed some minor bugs 2002/09/20 fadden - pulled the sources out and started fiddling with them again - changed hard tabs to spaces 2000/05/22 ***** v1.0.1 shipped (no changes - version follows nufxlib) ***** 2000/05/18 ***** v1.0.0 shipped ***** 2000/05/18 fadden - added nulib2 to set of things stripped by "distbin" - updated version information to indicate final release 2000/03/25 ***** v0.6.1 shipped ***** 2000/03/25 fadden - Sheppy says Mac OS X PPC v1.02 and v1.2 work with minor SysDefs tweak 2000/03/05 ***** v0.6.0 (beta) shipped ***** 2000/03/05 fadden - don't call mktemp(), just pass template into NuOpenRW - removed DEBUG_MSGS from default CFLAGS - updated version information to indicate beta release 2000/02/24 ***** v0.5.1 shipped ***** 2000/02/20 changes from Scott Blackman - portability fixes for DJGPP under Win95 2000/02/17 changes from Devin Reade - portability fixes for BSD, AIX, and others - added "distbin" target 2000/02/09 ***** v0.5.0 (alpha) shipped ***** 2000/02/09 fadden - changed the comparison used when extracting/deleting a list of files from strcasecmp to strcmp, since NufxLib does case-sensitive compares. - fixed the percentage for files and archives larger than 21MB 2000/02/08 fadden - tweaked the BeOS/PPC config around a little - deleted some commas to make "gcc -pedantic" happy - changed version to x.y.z format here too - generalized the "aux" handling to include all MS-DOS device names 2000/02/06 fadden - include @CFLAGS@ in case somebody wants to override them 2000/02/06 ***** v0.4b shipped ***** 2000/02/06 fadden - added "install-shared" make target - portability fixes for HP/UX 2000/02/06 ***** v0.4a shipped ***** 2000/02/06 fadden - massaged configure.in for BeOS, and added some type casts for mwerks 2000/02/06 ***** v0.4 shipped ***** 2000/02/05 fadden - added "mkinstalldirs" to install target - added Win32 makefile - made a few implicit typecasts explicit for Visual C++'s benefit - change "aux" to "_aux", because FAT filesystems choke on it 2000/02/04 fadden - added Win32 recursive directory descent 2000/02/02 fadden - minor changes to get it working under Win32 (Visual C++ 6.0) - added --enable-dmalloc to configuration 2000/02/01 fadden - screen out leading "./", and junk the path if ".." shows up in path - don't try to add comments to records we're skipping - set kNuValueEOL appropriately for the current system 2000/01/29 ***** v0.3 shipped ***** 2000/01/29 fadden - added "make install" target, with the standard autoconf defines - added some examples to the man page 2000/01/28 fadden - merged "Kind" and "Type" columns in "v" output - display a '+' when doing EOL conversions on an extracted file 2000/01/26 fadden - added UI for allowing the user to ignore bad CRCs - implemented "-j" (junk paths) for add and extract - implemented "-c" (comments) for add and extract - added totals to bottom of "v" output 2000/01/25 fadden - when extracting without type preservation, append "_rsrc_" to resource forks 2000/01/24 fadden - added support for "-k" (add as disk image) flag 2000/01/24 ***** v0.2 shipped ***** 2000/01/22 fadden - added support for "-u" (update) and "-f" (freshen) flags - set file dates in AddFile call 2000/01/20 fadden - restructed the progress updater 2000/01/19 fadden - normalized SysDefs.h, changing UNIX to UNIX_LIKE and defining for BeOS - added "shared" target to makefile - added BeOS stuff to autoconf setup 2000/01/17 fadden - started recording locked/unlocked status - some BeOS/Metrowerks "it's not gcc" changes from Eric Shepherd - implemented "-s" (stomp existing) and "-0" (no compression) modifiers 2000/01/17 ***** v0.1 shipped ***** (much time passes) mid-1998 fadden - work begins nulib2-3.1.0/nulib2/Delete.c000066400000000000000000000017631316100516500154540ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Delete files from the archive. */ #include "NuLib2.h" /* * Delete the specified files. * * This uses the "bulk" delete call, allowing the SelectionFilter callback * to do the matching against specified filenames. */ NuError DoDelete(NulibState* pState) { NuError err; NuArchive* pArchive = NULL; Assert(pState != NULL); err = OpenArchiveReadWrite(pState); if (err != kNuErrNone) goto bail; pArchive = NState_GetNuArchive(pState); Assert(pArchive != NULL); NState_SetMatchCount(pState, 0); err = NuDelete(pArchive); if (err != kNuErrNone) goto bail; if (!NState_GetMatchCount(pState)) printf("%s: no records matched\n", gProgName); bail: if (pArchive != NULL) (void) NuClose(pArchive); return err; } nulib2-3.1.0/nulib2/Extract.c000066400000000000000000000112131316100516500156530ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Extract files and test archives. */ #include "NuLib2.h" /* * Extract all of the records from the archive, pulling out and displaying * comment threads. * * The "bulk extract" call doesn't deal with comments. Since we want to * show them while we're extracting the files, we have to manually find * and extract them. */ static NuError ExtractAllRecords(NulibState* pState, NuArchive* pArchive) { NuError err; const NuRecord* pRecord; const NuThread* pThread; NuRecordIdx recordIdx; NuAttr numRecords; int idx, threadIdx; DBUG(("--- doing manual extract\n")); Assert(NState_GetCommand(pState) == kCommandExtract); /* no "-p" here */ err = NuGetAttr(pArchive, kNuAttrNumRecords, &numRecords); for (idx = 0; idx < (int) numRecords; idx++) { err = NuGetRecordIdxByPosition(pArchive, idx, &recordIdx); if (err != kNuErrNone) { fprintf(stderr, "ERROR: couldn't get record #%d (err=%d)\n", idx, err); goto bail; } err = NuGetRecord(pArchive, recordIdx, &pRecord); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to get recordIdx %u\n", recordIdx); goto bail; } /* do we want to extract this record? */ if (!IsSpecified(pState, pRecord)) continue; NState_IncMatchCount(pState); /* * Look for a comment thread. */ for (threadIdx = 0; (uint32_t)threadIdx < pRecord->recTotalThreads; threadIdx++) { pThread = NuGetThread(pRecord, threadIdx); Assert(pThread != NULL); if (NuGetThreadID(pThread) == kNuThreadIDComment && pThread->actualThreadEOF > 0) { UNICHAR* filenameUNI = CopyMORToUNI(pRecord->filenameMOR); printf("----- '%s':\n", filenameUNI); free(filenameUNI); err = NuExtractThread(pArchive, pThread->threadIdx, NState_GetCommentSink(pState)); if (err != kNuErrNone) { printf("[comment extraction failed, continuing\n"); } else { printf("\n-----\n"); } } } /* extract the record, using the usual mechanisms */ err = NuExtractRecord(pArchive, recordIdx); if (err != kNuErrNone) goto bail; } bail: return err; } /* * Extract the specified files. */ NuError DoExtract(NulibState* pState) { NuError err; NuArchive* pArchive = NULL; Assert(pState != NULL); if (NState_GetModBinaryII(pState)) return BNYDoExtract(pState); err = OpenArchiveReadOnly(pState); if (err == kNuErrIsBinary2) return BNYDoExtract(pState); if (err != kNuErrNone) goto bail; pArchive = NState_GetNuArchive(pState); Assert(pArchive != NULL); NState_SetMatchCount(pState, 0); /* * If we're not interested in comments, just use the "bulk" extract * call. If we want comments, we need to do this one at a time. */ if (!NState_GetModComments(pState)) { err = NuExtract(pArchive); if (err != kNuErrNone) goto bail; } else { err = ExtractAllRecords(pState, pArchive); if (err != kNuErrNone) goto bail; } if (!NState_GetMatchCount(pState)) printf("%s: no records match\n", gProgName); bail: if (pArchive != NULL) (void) NuClose(pArchive); return err; } /* * Extract the specified files to stdout. */ NuError DoExtractToPipe(NulibState* pState) { /* we handle the "to pipe" part farther down */ return DoExtract(pState); } /* * Do an integrity check on one or more records in the archive. */ NuError DoTest(NulibState* pState) { NuError err; NuArchive* pArchive = NULL; Assert(pState != NULL); if (NState_GetModBinaryII(pState)) return BNYDoTest(pState); err = OpenArchiveReadOnly(pState); if (err == kNuErrIsBinary2) return BNYDoTest(pState); if (err != kNuErrNone) goto bail; pArchive = NState_GetNuArchive(pState); Assert(pArchive != NULL); NState_SetMatchCount(pState, 0); err = NuTest(pArchive); if (err != kNuErrNone) goto bail; if (!NState_GetMatchCount(pState)) printf("%s: no records match\n", gProgName); bail: if (pArchive != NULL) (void) NuClose(pArchive); return err; } nulib2-3.1.0/nulib2/Filename.c000066400000000000000000000506741316100516500157770ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Filename manipulation, including file type preservation. */ #include "NuLib2.h" #include /* * =========================================================================== * Common definitions * =========================================================================== */ #define kPreserveIndic '#' /* use # rather than $ for hex indication */ #define kFilenameExtDelim '.' /* separates extension from filename */ #define kResourceFlag 'r' #define kDiskImageFlag 'i' #define kMaxExtLen 5 /* ".1234" */ #define kResourceStr "_rsrc_" /* must be longer then strlen(kResourceStr)... no problem there */ #define kMaxPathGrowth (sizeof("#XXXXXXXXYYYYYYYYZ")-1 + kMaxExtLen+1) /* ProDOS file type names; must be entirely in upper case */ static const char gFileTypeNames[256][4] = { "NON", "BAD", "PCD", "PTX", "TXT", "PDA", "BIN", "FNT", "FOT", "BA3", "DA3", "WPF", "SOS", "$0D", "$0E", "DIR", "RPD", "RPI", "AFD", "AFM", "AFR", "SCL", "PFS", "$17", "$18", "ADB", "AWP", "ASP", "$1C", "$1D", "$1E", "$1F", "TDM", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "8SC", "8OB", "8IC", "8LD", "P8C", "$2F", "$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39", "$3A", "$3B", "$3C", "$3D", "$3E", "$3F", "DIC", "OCR", "FTD", "$43", "$44", "$45", "$46", "$47", "$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F", "GWP", "GSS", "GDB", "DRW", "GDP", "HMD", "EDU", "STN", "HLP", "COM", "CFG", "ANM", "MUM", "ENT", "DVU", "FIN", "$60", "$61", "$62", "$63", "$64", "$65", "$66", "$67", "$68", "$69", "$6A", "BIO", "$6C", "TDR", "PRE", "HDV", "$70", "$71", "$72", "$73", "$74", "$75", "$76", "$77", "$78", "$79", "$7A", "$7B", "$7C", "$7D", "$7E", "$7F", "$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87", "$88", "$89", "$8A", "$8B", "$8C", "$8D", "$8E", "$8F", "$90", "$91", "$92", "$93", "$94", "$95", "$96", "$97", "$98", "$99", "$9A", "$9B", "$9C", "$9D", "$9E", "$9F", "WP ", "$A1", "$A2", "$A3", "$A4", "$A5", "$A6", "$A7", "$A8", "$A9", "$AA", "GSB", "TDF", "BDF", "$AE", "$AF", "SRC", "OBJ", "LIB", "S16", "RTL", "EXE", "PIF", "TIF", "NDA", "CDA", "TOL", "DVR", "LDF", "FST", "$BE", "DOC", "PNT", "PIC", "ANI", "PAL", "$C4", "OOG", "SCR", "CDV", "FON", "FND", "ICN", "$CB", "$CC", "$CD", "$CE", "$CF", "$D0", "$D1", "$D2", "$D3", "$D4", "MUS", "INS", "MDI", "SND", "$D9", "$DA", "DBM", "$DC", "DDD", "$DE", "$DF", "LBR", "$E1", "ATK", "$E3", "$E4", "$E5", "$E6", "$E7", "$E8", "$E9", "$EA", "$EB", "$EC", "$ED", "R16", "PAS", "CMD", "$F1", "$F2", "$F3", "$F4", "$F5", "$F6", "$F7", "$F8", "OS ", "INT", "IVR", "BAS", "VAR", "REL", "SYS" }; /* * Some file extensions we recognize. When adding files with "extended" * preservation mode, we try to assign types to files that weren't * explicitly preserved, but nevertheless have a recognizeable type. * * geoff @ gwlink.net points out that this really ought to be in an external * file rather than a hard-coded table. Ought to fix that someday. */ static const struct { const char* label; uint8_t fileType; uint16_t auxType; } gRecognizedExtensions[] = { { "ASM", 0xb0, 0x0003 }, /* APW assembly source */ { "C", 0xb0, 0x000a }, /* APW C source */ { "H", 0xb0, 0x000a }, /* APW C header */ { "CPP", 0xb0, 0x0000 }, /* generic source file */ { "BNY", 0xe0, 0x8000 }, /* Binary II lib */ { "BQY", 0xe0, 0x8000 }, /* Binary II lib, w/ compress */ { "BXY", 0xe0, 0x8000 }, /* Binary II wrap around SHK */ { "BSE", 0xe0, 0x8000 }, /* Binary II wrap around SEA */ { "SEA", 0xb3, 0xdb07 }, /* GSHK SEA */ { "TEXT", 0x04, 0x0000 }, /* ASCII text */ { "GIF", 0xc0, 0x8006 }, /* GIF image */ { "JPG", 0x06, 0x0000 }, /* JPEG (nicer than 'NON') */ { "JPEG", 0x06, 0x0000 }, /* JPEG (nicer than 'NON') */ { "SHK", 0xe0, 0x8002 }, /* ShrinkIt archive */ }; /* * Return a pointer to the three-letter representation of the file type name. */ const char* GetFileTypeString(uint32_t fileType) { if (fileType < NELEM(gFileTypeNames)) return gFileTypeNames[fileType]; else return "???"; } /* * =========================================================================== * File type preservation * =========================================================================== */ /* * Add a preservation string. * * "pathBuf" is assumed to have enough space to hold the current path * plus kMaxPathGrowth more. It will be modified in place. */ static void AddPreservationString(NulibState* pState, const NuPathnameProposal* pPathProposal, char* pathBuf) { char extBuf[kMaxPathGrowth +1]; const NuRecord* pRecord; const NuThread* pThread; NuThreadID threadID; char* cp; Assert(pState != NULL); Assert(pPathProposal != NULL); Assert(pathBuf != NULL); Assert(NState_GetModPreserveType(pState)); pRecord = pPathProposal->pRecord; pThread = pPathProposal->pThread; Assert(pRecord != NULL); Assert(pThread != NULL); cp = extBuf; /* * Cons up a preservation string. On some platforms "sprintf" doesn't * return the #of characters written, so we add it up manually. */ if (pRecord->recFileType < 0x100 && pRecord->recExtraType < 0x10000) { sprintf(cp, "%c%02x%04x", kPreserveIndic, pRecord->recFileType, pRecord->recExtraType); cp += 7; } else { sprintf(cp, "%c%08x%08x", kPreserveIndic, pRecord->recFileType, pRecord->recExtraType); cp += 17; } threadID = NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind); if (threadID == kNuThreadIDRsrcFork) *cp++ = kResourceFlag; else if (threadID == kNuThreadIDDiskImage) *cp++ = kDiskImageFlag; /* * If they've asked for "extended" type preservation, then we need * to retain either the existing extension or append an extension * based on the ProDOS file type. */ if (NState_GetModPreserveTypeExtended(pState)) { const char* pExt; char* end; /* * Find extension. Note FindExtension guarantees there's at least * one char after '.'. * * It's hard to know when this is right and when it isn't. It's * fairly likely that a text file really ought to end in ".txt", * and it's fairly unlikely that a BIN file should be ".bin", but * where do the rest fall in? We might want to force TXT files * to be ".txt", and perhaps do something clever for some others. */ if (pRecord->recFileType == 0x04 || threadID == kNuThreadIDDiskImage) pExt = NULL; else pExt = FindExtension(pState, pathBuf); if (pExt != NULL) { pExt++; /* skip past the '.' */ if (strlen(pExt) >= kMaxExtLen) { /* too long, forget it */ pExt = NULL; } else { /* if strictly decimal-numeric, don't use it (.1, .2, etc) */ (void) strtoul(pExt, &end, 10); if (*end == '\0') { pExt = NULL; } else { /* if '#' appears in it, don't use it -- it'll confuse us */ const char* ccp = pExt; while (*ccp != '\0') { if (*ccp == '#') { pExt = NULL; break; } ccp++; } } } } else { /* * There's no extension on the filename. Use the standard * ProDOS type, if one exists for this entry. We don't use * the table if it's "NON" or a hex value. */ if (threadID == kNuThreadIDDiskImage) pExt = "PO"; /* indicate it's a ProDOS-ordered image */ else if (pRecord->recFileType) { pExt = GetFileTypeString(pRecord->recFileType); if (pExt[0] == '?' || pExt[0] == '$') pExt = NULL; } } if (pExt != NULL) { *cp++ = kFilenameExtDelim; strcpy(cp, pExt); cp += strlen(pExt); } } /* make sure it's terminated */ *cp = '\0'; Assert(cp - extBuf <= kMaxPathGrowth); strcat(pathBuf, extBuf); } /* * Normalize a path for the conventions on the output filesystem. This * adds optional file type preservation. * * The path from the archive is in "pPathProposal". Thew new pathname * will be placed in the "new pathname" section of "pPathProposal". * * The new pathname may be shorter (because characters were removed) or * longer (if we add a "#XXYYYYZ" extension or replace chars with '%' codes). * * This returns the new pathname, which is held in NulibState's temporary * pathname buffer. */ const char* NormalizePath(NulibState* pState, NuPathnameProposal* pPathProposal) { NuError err = kNuErrNone; char* pathBuf; const char* startp; const char* endp; char* dstp; char localFssep; int newBufLen; Assert(pState != NULL); Assert(pPathProposal != NULL); Assert(pPathProposal->pathnameUNI != NULL); localFssep = NState_GetSystemPathSeparator(pState); /* * Set up temporary buffer space. The maximum possible expansion * requires converting all chars to '%' codes and adding the longest * possible preservation string. */ newBufLen = strlen(pPathProposal->pathnameUNI)*3 + kMaxPathGrowth +1; NState_SetTempPathnameLen(pState, newBufLen); pathBuf = NState_GetTempPathnameBuf(pState); Assert(pathBuf != NULL); if (pathBuf == NULL) return NULL; startp = pPathProposal->pathnameUNI; dstp = pathBuf; while (*startp == pPathProposal->filenameSeparator) { /* ignore leading path sep; always extract to current dir */ startp++; } /* normalize all directory components and the filename component */ while (startp != NULL) { endp = strchr(startp, pPathProposal->filenameSeparator); if (endp != NULL) { /* normalize directory component */ err = NormalizeDirectoryName(pState, startp, endp - startp, pPathProposal->filenameSeparator, &dstp, NState_GetTempPathnameLen(pState)); if (err != kNuErrNone) goto bail; *dstp++ = localFssep; startp = endp +1; } else { /* normalize filename */ err = NormalizeFileName(pState, startp, strlen(startp), pPathProposal->filenameSeparator, &dstp, NState_GetTempPathnameLen(pState)); if (err != kNuErrNone) goto bail; /* add/replace extension if necessary */ *dstp++ = '\0'; if (NState_GetModPreserveType(pState)) { AddPreservationString(pState, pPathProposal, pathBuf); } else if (NuGetThreadID(pPathProposal->pThread) == kNuThreadIDRsrcFork) { #ifndef HAS_RESOURCE_FORKS /* add this in lieu of the preservation extension */ strcat(pathBuf, kResourceStr); #endif } startp = NULL; /* we're done */ } } pPathProposal->newPathnameUNI = pathBuf; pPathProposal->newFilenameSeparator = localFssep; /* check for overflow */ Assert(dstp - pathBuf <= newBufLen); /* * If "junk paths" is set, drop everything but the last component. */ if (NState_GetModJunkPaths(pState)) { char* lastFssep; lastFssep = strrchr(pathBuf, localFssep); if (lastFssep != NULL) { Assert(*(lastFssep+1) != '\0'); /* should already have been caught*/ memmove(pathBuf, lastFssep+1, strlen(lastFssep+1)+1); } } bail: if (err != kNuErrNone) return NULL; return pathBuf; } /* * =========================================================================== * File type restoration * =========================================================================== */ /* * Try to figure out what file type is associated with a filename extension. * * This checks the standard list of ProDOS types (which should catch things * like "TXT" and "BIN") and the separate list of recognized extensions. */ static void LookupExtension(NulibState* pState, const char* ext, uint32_t* pFileType, uint32_t* pAuxType) { char uext3[4]; int i, extLen; extLen = strlen(ext); Assert(extLen > 0); /* * First step is to try to find it in the recognized types list. */ for (i = 0; i < NELEM(gRecognizedExtensions); i++) { if (strcasecmp(ext, gRecognizedExtensions[i].label) == 0) { *pFileType = gRecognizedExtensions[i].fileType; *pAuxType = gRecognizedExtensions[i].auxType; goto bail; } } /* * Second step is to try to find it in the ProDOS types list. * * The extension is converted to upper case and padded with spaces. * * [do we want to obstruct matching on things like '$f7' here?] */ if (extLen <= 3) { for (i = 2; i >= extLen; i--) uext3[i] = ' '; for ( ; i >= 0; i--) uext3[i] = toupper(ext[i]); uext3[3] = '\0'; /*printf("### converted '%s' to '%s'\n", ext, uext3);*/ for (i = 0; i < NELEM(gFileTypeNames); i++) { if (strcmp(uext3, gFileTypeNames[i]) == 0) { *pFileType = i; goto bail; } } } bail: return; } /* * Try to associate some meaning with the file extension. */ void InterpretExtension(NulibState* pState, const char* pathName, uint32_t* pFileType, uint32_t* pAuxType) { const char* pExt; Assert(pState != NULL); Assert(pathName != NULL); Assert(pFileType != NULL); Assert(pAuxType != NULL); pExt = FindExtension(pState, pathName); if (pExt != NULL) LookupExtension(pState, pExt+1, pFileType, pAuxType); } /* * Check to see if there's a preservation string on the filename. If so, * set the filetype and auxtype information, and trim the preservation * string off. * * We have to be careful not to trip on false-positive occurrences of '#' * in the filename. */ Boolean ExtractPreservationString(NulibState* pState, char* pathname, uint32_t* pFileType, uint32_t* pAuxType, NuThreadID* pThreadID) { char numBuf[9]; uint32_t fileType, auxType; NuThreadID threadID; char* pPreserve; char* cp; int digitCount; Assert(pState != NULL); Assert(pathname != NULL); Assert(pFileType != NULL); Assert(pAuxType != NULL); Assert(pThreadID != NULL); pPreserve = strrchr(pathname, kPreserveIndic); if (pPreserve == NULL) return false; /* count up the #of hex digits */ digitCount = 0; for (cp = pPreserve+1; *cp != '\0' && isxdigit((int)*cp); cp++) digitCount++; /* extract the file and aux type */ switch (digitCount) { case 6: /* ProDOS 1-byte type and 2-byte aux */ memcpy(numBuf, pPreserve+1, 2); numBuf[2] = 0; fileType = strtoul(numBuf, &cp, 16); Assert(cp == numBuf + 2); auxType = strtoul(pPreserve+3, &cp, 16); Assert(cp == pPreserve + 7); break; case 16: /* HFS 4-byte type and 4-byte creator */ memcpy(numBuf, pPreserve+1, 8); numBuf[8] = 0; fileType = strtoul(numBuf, &cp, 16); Assert(cp == numBuf + 8); auxType = strtoul(pPreserve+9, &cp, 16); Assert(cp == pPreserve + 17); break; default: /* not valid */ return false; } /* check for a threadID specifier */ threadID = kNuThreadIDDataFork; switch (*cp) { case kResourceFlag: threadID = kNuThreadIDRsrcFork; cp++; break; case kDiskImageFlag: threadID = kNuThreadIDDiskImage; cp++; break; default: /* do nothing... yet */ break; } /* make sure we were the very last component */ switch (*cp) { case kFilenameExtDelim: /* redundant "-ee" extension */ case '\0': /* end of string! */ break; default: return false; } /* truncate the original string, and return what we got */ *pPreserve = '\0'; *pFileType = fileType; *pAuxType = auxType; *pThreadID = threadID; return true; } /* * Remove NuLib2's normalization magic (e.g. "%2f" for '/'). * * This always results in the filename staying the same length or getting * smaller, so we can do it in place in the buffer. */ void DenormalizePath(NulibState* pState, char* pathBuf) { const char* srcp; char* dstp; char ch; srcp = pathBuf; dstp = pathBuf; while (*srcp != '\0') { if (*srcp == kForeignIndic) { srcp++; if (*srcp == kForeignIndic) { *dstp++ = kForeignIndic; srcp++; } else if (isxdigit((int)*srcp)) { ch = HexDigit(*srcp) << 4; srcp++; if (isxdigit((int)*srcp)) { /* valid, output char */ ch += HexDigit(*srcp); if (ch != '\0') /* used by Win32 converter */ *dstp++ = ch; srcp++; } else { /* bogus '%' with trailing hex digit found! */ *dstp++ = kForeignIndic; *dstp++ = *(srcp-1); } } else { /* bogus lone '%s' found! */ *dstp++ = kForeignIndic; } } else { *dstp++ = *srcp++; } } *dstp = '\0'; Assert(dstp <= srcp); } /* * =========================================================================== * Misc utils * =========================================================================== */ /* * Find the filename component of a local pathname. Uses the fssep defined * in pState. * * Always returns a pointer to a string; never returns NULL. */ const char* FilenameOnly(NulibState* pState, const char* pathname) { const char* retstr; const char* pSlash; char* tmpStr = NULL; Assert(pState != NULL); Assert(pathname != NULL); pSlash = strrchr(pathname, NState_GetSystemPathSeparator(pState)); if (pSlash == NULL) { retstr = pathname; /* whole thing is the filename */ goto bail; } pSlash++; if (*pSlash == '\0') { if (strlen(pathname) < 2) { retstr = pathname; /* the pathname is just "/"? Whatever */ goto bail; } /* some bonehead put an fssep on the very end; back up before it */ /* (not efficient, but this should be rare, and I'm feeling lazy) */ tmpStr = strdup(pathname); tmpStr[strlen(pathname)-1] = '\0'; pSlash = strrchr(tmpStr, NState_GetSystemPathSeparator(pState)); if (pSlash == NULL) { retstr = pathname; /* just a filename with a '/' after it */ goto bail; } pSlash++; if (*pSlash == '\0') { retstr = pathname; /* I give up! */ goto bail; } retstr = pathname + (pSlash - tmpStr); } else { retstr = pSlash; } bail: Free(tmpStr); return retstr; } /* * Return the filename extension found in a full pathname. * * An extension is the stuff following the last '.' in the filename. If * there is nothing following the last '.', then there is no extension. * * Returns a pointer to the '.' preceding the extension, or NULL if no * extension was found. */ const char* FindExtension(NulibState* pState, const char* pathname) { const char* pFilename; const char* pExt; /* * We have to isolate the filename so that we don't get excited * about "/foo.bar/file". */ pFilename = FilenameOnly(pState, pathname); Assert(pFilename != NULL); pExt = strrchr(pFilename, kFilenameExtDelim); /* also check for "/blah/foo.", which doesn't count */ if (pExt != NULL && *(pExt+1) != '\0') return pExt; return NULL; } nulib2-3.1.0/nulib2/INSTALL000066400000000000000000000172301316100516500151330ustar00rootroot00000000000000Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. nulib2-3.1.0/nulib2/List.c000066400000000000000000000325401316100516500151620ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * List files in the archive. */ #include "NuLib2.h" /* kinds of records */ enum RecordKind { kRecordKindUnknown = 0, kRecordKindDisk, kRecordKindFile, kRecordKindForkedFile }; static const char* gShortFormatNames[] = { "unc", "squ", "lz1", "lz2", "u12", "u16", "dfl", "bzp" }; #if 0 /* days of the week */ static const char* gDayNames[] = { "[ null ]", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; #endif /* months of the year */ static const char* gMonths[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* * Compute a percentage. */ int ComputePercent(uint32_t totalSize, uint32_t size) { int perc; if (!totalSize && !size) return 100; /* file is zero bytes long */ if (totalSize < 21474836) perc = (totalSize * 100) / size; else perc = totalSize / (size/100); /* don't say "0%" if it's not actually zero... it looks dumb */ if (!perc && size) perc = 1; return perc; } /* * Convert a NuDateTime structure into something printable. This uses an * abbreviated format, with date and time but not weekday or seconds. * * The buffer passed in must hold at least kDateOutputLen bytes. * * Returns "buffer" for the benefit of printf() calls. */ char* FormatDateShort(const NuDateTime* pDateTime, char* buffer) { /* is it valid? */ if (pDateTime->day > 30 || pDateTime->month > 11 || pDateTime->hour > 24 || pDateTime->minute > 59) { strcpy(buffer, " "); goto bail; } /* is it empty? */ if ((pDateTime->second | pDateTime->minute | pDateTime->hour | pDateTime->year | pDateTime->day | pDateTime->month | pDateTime->extra | pDateTime->weekDay) == 0) { strcpy(buffer, " [No Date] "); goto bail; } sprintf(buffer, "%02d-%s-%02d %02d:%02d", pDateTime->day+1, gMonths[pDateTime->month], pDateTime->year % 100, pDateTime->hour, pDateTime->minute); bail: return buffer; } /* * NuStream callback function. Displays the filename. */ static NuResult ShowContentsShort(NuArchive* pArchive, void* vpRecord) { const NuRecord* pRecord = (NuRecord*) vpRecord; NulibState* pState; Assert(pArchive != NULL); (void) NuGetExtraData(pArchive, (void**) &pState); Assert(pState != NULL); if (!IsSpecified(pState, pRecord)) goto bail; UNICHAR* filenameUNI = CopyMORToUNI(pRecord->filenameMOR); printf("%s\n", filenameUNI == NULL ? "" : filenameUNI); free(filenameUNI); bail: return kNuOK; } /* * Analyze the contents of a record to determine if it's a disk, file, * or "other". Compute the total compressed and uncompressed lengths * of all data threads. Return the "best" format. * * The "best format" and "record type" stuff assume that the entire * record contains only a disk thread or a file thread, and that any * format is interesting so long as it isn't "no compression". In * general these will be true, because ShrinkIt and NuLib create files * this way. * * You could, of course, create a single record with a data thread and * a disk image thread, but it's a fair bet ShrinkIt would ignore one * or the other. * * NOTE: GSHK likes to omit the data threads for zero-length data and * resource forks. That screws up analysis by scanning for threads. We * can work around missing resource forks by simply checking the record's * storage type. We could be clever and detect records that have no * data-class threads at all, and no additional threads other than a * comment and filename, but this is just for display. ShrinkIt doesn't * handle these records correctly in all cases, so flagging them in a * user-visible way seems reasonable. */ static NuError AnalyzeRecord(const NuRecord* pRecord, enum RecordKind* pRecordKind, uint16_t* pFormat, uint32_t* pTotalLen, uint32_t* pTotalCompLen) { const NuThread* pThread; NuThreadID threadID; uint32_t idx; *pRecordKind = kRecordKindUnknown; *pTotalLen = *pTotalCompLen = 0; *pFormat = kNuThreadFormatUncompressed; for (idx = 0; idx < pRecord->recTotalThreads; idx++) { pThread = NuGetThread(pRecord, idx); Assert(pThread != NULL); if (pThread->thThreadClass == kNuThreadClassData) { /* replace what's there if this might be more interesting */ if (*pFormat == kNuThreadFormatUncompressed) *pFormat = pThread->thThreadFormat; threadID = NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind); if (threadID == kNuThreadIDRsrcFork) *pRecordKind = kRecordKindForkedFile; else if (threadID == kNuThreadIDDiskImage) *pRecordKind = kRecordKindDisk; else if (threadID == kNuThreadIDDataFork && *pRecordKind == kRecordKindUnknown) *pRecordKind = kRecordKindFile; /* sum up, so we get both forks of forked files */ *pTotalLen += pThread->actualThreadEOF; *pTotalCompLen += pThread->thCompThreadEOF; } } /* * Fix up the case where we have a forked file, but GSHK decided not * to include a resource fork in the record. */ if (pRecord->recStorageType == kNuStorageExtended && *pRecordKind != kRecordKindForkedFile) { *pRecordKind = kRecordKindForkedFile; } return kNuErrNone; } /* * NuStream callback function. Displays the filename and several attributes. * * This is intended to mimic the output of some old version of ProDOS 8 * ShrinkIt. */ static NuResult ShowContentsVerbose(NuArchive* pArchive, void* vpRecord) { NuError err = kNuErrNone; const NuRecord* pRecord = (NuRecord*) vpRecord; enum RecordKind recordKind; uint32_t totalLen, totalCompLen; uint16_t format; NulibState* pState; char date1[kDateOutputLen]; char tmpbuf[16]; int len; Assert(pArchive != NULL); (void) NuGetExtraData(pArchive, (void**) &pState); Assert(pState != NULL); if (!IsSpecified(pState, pRecord)) goto bail; err = AnalyzeRecord(pRecord, &recordKind, &format, &totalLen, &totalCompLen); if (err != kNuErrNone) goto bail; /* * Display the filename, truncating if it's longer than 27 characters. * * Attempting to do column layout with printf string formatting (e.g. * "%-27s") doesn't really work for UTF-8 because printf() is * operating on bytes, and the conversion to a Unicode code point * is happening in the terminal. We need to do the spacing ourselves, * using the fact that one MOR character turns into one Unicode character. * * If the display isn't converting multi-byte sequences to individual * characters, this won't look right, but we can't make everybody happy. */ static const char kSpaces[27+1] = " "; UNICHAR* filenameUNI; len = strlen(pRecord->filenameMOR); if (len <= 27) { filenameUNI = CopyMORToUNI(pRecord->filenameMOR); printf("%c%s%s ", IsRecordReadOnly(pRecord) ? '+' : ' ', filenameUNI, &kSpaces[len]); } else { filenameUNI = CopyMORToUNI(pRecord->filenameMOR + len - 25); printf("%c..%s ", IsRecordReadOnly(pRecord) ? '+' : ' ', filenameUNI); } free(filenameUNI); switch (recordKind) { case kRecordKindUnknown: printf("%s- $%04X ", GetFileTypeString(pRecord->recFileType), pRecord->recExtraType); break; case kRecordKindDisk: sprintf(tmpbuf, "%dk", totalLen / 1024); printf("Disk %-6s ", tmpbuf); break; case kRecordKindFile: case kRecordKindForkedFile: printf("%s%c $%04X ", GetFileTypeString(pRecord->recFileType), recordKind == kRecordKindForkedFile ? '+' : ' ', pRecord->recExtraType); break; default: Assert(0); printf("ERROR "); } printf("%s ", FormatDateShort(&pRecord->recArchiveWhen, date1)); if (format >= NELEM(gShortFormatNames)) printf("??? "); else printf("%s ", gShortFormatNames[format]); /* compute the percent size */ if ((!totalLen && totalCompLen) || (totalLen && !totalCompLen)) printf("--- "); /* weird */ else if (totalLen < totalCompLen) printf(">100%% "); /* compression failed? */ else { sprintf(tmpbuf, "%02d%%", ComputePercent(totalCompLen, totalLen)); printf("%4s ", tmpbuf); } if (!totalLen && totalCompLen) printf(" ????"); /* weird */ else printf("%8u", totalLen); printf("\n"); NState_AddToTotals(pState, totalLen, totalCompLen); bail: if (err != kNuErrNone) { filenameUNI = CopyMORToUNI(pRecord->filenameMOR); printf("(ERROR on '%s')\n", filenameUNI == NULL ? "" : filenameUNI); free(filenameUNI); } return kNuOK; } /* * Print a short listing of the contents of an archive. */ NuError DoListShort(NulibState* pState) { NuError err; NuArchive* pArchive = NULL; Assert(pState != NULL); if (NState_GetModBinaryII(pState)) return BNYDoListShort(pState); err = OpenArchiveReadOnly(pState); if (err == kNuErrIsBinary2) return BNYDoListShort(pState); if (err != kNuErrNone) goto bail; pArchive = NState_GetNuArchive(pState); Assert(pArchive != NULL); err = NuContents(pArchive, ShowContentsShort); /* fall through with err */ bail: if (pArchive != NULL) (void) NuClose(pArchive); return err; } /* * Print a more verbose listing of the contents of an archive. */ NuError DoListVerbose(NulibState* pState) { NuError err; NuArchive* pArchive = NULL; const NuMasterHeader* pHeader; char date1[kDateOutputLen]; char date2[kDateOutputLen]; long totalLen, totalCompLen; const char* cp; Assert(pState != NULL); if (NState_GetModBinaryII(pState)) return BNYDoListVerbose(pState); err = OpenArchiveReadOnly(pState); if (err == kNuErrIsBinary2) return BNYDoListVerbose(pState); if (err != kNuErrNone) goto bail; pArchive = NState_GetNuArchive(pState); Assert(pArchive != NULL); /* * Try to get just the filename. */ if (IsFilenameStdin(NState_GetArchiveFilename(pState))) cp = ""; else cp = FilenameOnly(pState, NState_GetArchiveFilename(pState)); /* grab the master header block */ err = NuGetMasterHeader(pArchive, &pHeader); if (err != kNuErrNone) goto bail; printf(" %-15.15s Created:%s Mod:%s Recs:%5u\n\n", cp, FormatDateShort(&pHeader->mhArchiveCreateWhen, date1), FormatDateShort(&pHeader->mhArchiveModWhen, date2), pHeader->mhTotalRecords); printf(" Name Type Auxtyp Archived" " Fmat Size Un-Length\n"); printf("-------------------------------------------------" "----------------------------\n"); err = NuContents(pArchive, ShowContentsVerbose); if (err != kNuErrNone) goto bail; /* * Show the totals. NuFX overhead can be as much as 25% for archives * with lots of small files. */ NState_GetTotals(pState, &totalLen, &totalCompLen); printf("-------------------------------------------------" "----------------------------\n"); printf(" Uncomp: %ld Comp: %ld %%of orig: %d%%\n", totalLen, totalCompLen, totalLen == 0 ? 0 : ComputePercent(totalCompLen, totalLen)); #ifdef DEBUG_VERBOSE if (!NState_GetFilespecCount(pState)) { printf(" Overhead: %ld (%d%%)\n", pHeader->mhMasterEOF - totalCompLen, ComputePercent(pHeader->mhMasterEOF - totalCompLen, pHeader->mhMasterEOF)); } #endif /*(void) NuDebugDumpArchive(pArchive);*/ bail: if (pArchive != NULL) (void) NuClose(pArchive); return err; } /* * Null callback, for those times when you don't really want to do anything. */ static NuResult NullCallback(NuArchive* pArchive, void* vpRecord) { return kNuOK; } /* * Print very detailed output, suitable for debugging (requires that * debug messages be enabled in nufxlib). */ NuError DoListDebug(NulibState* pState) { NuError err; NuArchive* pArchive = NULL; Assert(pState != NULL); if (NState_GetModBinaryII(pState)) return BNYDoListDebug(pState); err = OpenArchiveReadOnly(pState); if (err == kNuErrIsBinary2) return BNYDoListDebug(pState); if (err != kNuErrNone) goto bail; pArchive = NState_GetNuArchive(pState); Assert(pArchive != NULL); /* have to do something to force the library to scan the archive */ err = NuContents(pArchive, NullCallback); if (err != kNuErrNone) goto bail; err = NuDebugDumpArchive(pArchive); if (err != kNuErrNone) fprintf(stderr, "ERROR: debugging not enabled in nufxlib\n"); /* fall through with err */ bail: if (pArchive != NULL) (void) NuClose(pArchive); return err; } nulib2-3.1.0/nulib2/Main.c000066400000000000000000000463721316100516500151430ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Main entry point and shell command argument processing. */ #include "NuLib2.h" #include /* * Globals and constants. */ const char* gProgName = "NuLib2"; /* * Which modifiers are valid with which commands? */ typedef struct ValidCombo { Command cmd; Boolean okayForPipe; Boolean filespecRequired; const char* modifiers; } ValidCombo; static const ValidCombo gValidCombos[] = { { kCommandAdd, false, true, "ekcz0jrfu" }, { kCommandDelete, false, true, "r" }, { kCommandExtract, true, false, "beslcjrfu" }, { kCommandExtractToPipe, true, false, "blr" }, { kCommandListShort, true, false, "br" }, { kCommandListVerbose, true, false, "br" }, { kCommandListDebug, true, false, "b" }, { kCommandTest, true, false, "br" }, { kCommandHelp, false, false, "" }, }; /* * Find an entry in the gValidCombos table matching the specified command. * * Returns NULL if not found. */ static const ValidCombo* FindValidComboEntry(Command cmd) { int i; for (i = 0; i < NELEM(gValidCombos); i++) { if (gValidCombos[i].cmd == cmd) return &gValidCombos[i]; } return NULL; } /* * Determine whether the specified modifier is valid when used with the * current command. */ static Boolean IsValidModifier(Command cmd, char modifier) { const ValidCombo* pvc; pvc = FindValidComboEntry(cmd); if (pvc != NULL) { if (strchr(pvc->modifiers, modifier) == NULL) return false; else return true; } else return false; } /* * Determine whether the specified command can be used with stdin as input. */ static Boolean IsValidOnPipe(Command cmd) { const ValidCombo* pvc; pvc = FindValidComboEntry(cmd); if (pvc != NULL) { return pvc->okayForPipe; } else return false; } /* * Determine whether the specified command can be used with stdin as input. */ static Boolean IsFilespecRequired(Command cmd) { const ValidCombo* pvc; pvc = FindValidComboEntry(cmd); if (pvc != NULL) { return pvc->filespecRequired; } else { /* command not found? warn about it here... */ fprintf(stderr, "%s: Command %d not found in gValidCombos table\n", gProgName, cmd); return false; } } /* * Separate the program name out of argv[0]. */ static const char* GetProgName(const NulibState* pState, const char* argv0) { const char* result; char sep; /* use the appropriate system pathname separator */ sep = NState_GetSystemPathSeparator(pState); result = strrchr(argv0, sep); if (result == NULL) result = argv0; else result++; /* advance past the separator */ return result; } /* * Print program usage. */ static void Usage(const NulibState* pState) { int32_t majorVersion, minorVersion, bugVersion; const char* nufxLibDate; const char* nufxLibFlags; (void) NuGetVersion(&majorVersion, &minorVersion, &bugVersion, &nufxLibDate, &nufxLibFlags); printf("\nNuLib2 v%s, linked with NufxLib v%d.%d.%d [%s]\n", NState_GetProgramVersion(pState), majorVersion, minorVersion, bugVersion, nufxLibFlags); printf("Copyright (C) 2000-2017, Andy McFadden. All Rights Reserved.\n"); printf("This software is distributed under terms of the BSD License.\n"); printf("Visit http://www.nulib.com/ for source code and documentation.\n\n"); printf("Usage: %s -command[modifiers] archive [filename-list]\n\n", gProgName); printf( " -a add files, create arc if needed -x extract files\n" " -t list files (short) -v list files (verbose)\n" " -p extract files to pipe, no msgs -i test archive integrity\n" " -d delete files from archive -h extended help message\n" "\n" " modifiers:\n" " -u update files (add + keep newest) -f freshen (update, no add)\n" " -r recurse into subdirs -j junk (don't record) directory names\n" " -0 don't use compression -c add one-line comments\n"); if (NuTestFeature(kNuFeatureCompressDeflate) == kNuErrNone) printf(" -z use zlib 'deflate' compression "); else printf(" -z use zlib [not included] "); if (NuTestFeature(kNuFeatureCompressBzip2) == kNuErrNone) printf("-zz use bzip2 BWT compression\n"); else printf("-zz use bzip2 [not included]\n"); printf( " -l auto-convert text files -ll convert CR/LF on ALL files\n" " -s stomp existing files w/o asking -k store files as disk images\n" " -e preserve ProDOS file types -ee preserve types and extend names\n" " -b force Binary II mode\n" ); } /* * Handle the "-h" command. */ NuError DoHelp(const NulibState* pState) { static const struct { Command cmd; char letter; const char* shortDescr; const char* longDescr; } help[] = { { kCommandListVerbose, 'v', "verbose listing of archive contents", " List archive contents in a multi-column format with summary totals.\n" " The output is similar to what ShrinkIt produces. You can specify the\n" " names of the files to list.\n" "\n" " The '-b' modifier will force NuLib2 to open the file as Binary II.\n" " This can be useful when working with encapsulated archives (.BXY and\n" " .BSE) and when the archive is presented on standard input (i.e.\n" " \"nulib2 -vb - < archive.bny\").\n", }, { kCommandListShort, 't', "quick dump of table of contents", " List the filenames, one per line, without any truncation or embellishment.\n" " Useful for feeding into another program.\n", }, { kCommandAdd, 'a', "add files to an archive", " Add files to an archive, possibly creating it first. Files in\n" " subdirectories will not be added unless the '-r' flag is provided.\n" "\n" " You can specify the '-z' or '-zz' flag to use \"deflate\" or \"bzip2\"\n" " compression, respectively. These work much better than ShrinkIt's LZW,\n" " but the files can't be unpacked on an Apple II. The flags will only be\n" " enabled if NuLib2 was built with the necessary libraries.\n", }, { kCommandExtract, 'x', "extract files from an archive", " Extract the specified items from the archive. If nothing is specified,\n" " everything is extracted. The '-r' modifier tells NuLib2 to do a prefix\n" " match, so \"nulib2 -xr archive.shk doc\" will extract everything in the\n" " \"doc\" directory. It will also extract a file called \"document\". If\n" " you just want what's in a directory, tack on the filename separator\n" " character, e.g. \"nulib2 -xr archive.shk doc:\".\n" "\n" " When working with Binary II archives, the following suboptions aren't\n" " allowed: -u -f -c -l -ll.\n", }, { kCommandExtractToPipe, 'p', "extract files to pipe", " Works just like '-x', but all files are written to stdout. Useful for\n" " viewing a file, e.g. \"nulib2 -pl archive.shk document.txt | less\".\n" " The progress indicators and interactive prompts are disabled.\n", }, { kCommandTest, 'i', "test archive integrity", " Verify the contents of an archive by extracting all files to memory and\n" " verifying all CRCs. Note that uncompressed files in archives created by\n" " P8 ShrinkIt and un-SQueezed files in Binary II archives do not have any\n" " sort of checksum.\n", }, { kCommandDelete, 'd', "delete files from archive", " Delete the named files from the archive. If you delete all of the files,\n" " the archive itself will be removed.\n", }, { kCommandHelp, 'h', "show extended help", " This is the extended help text. Go to www.nulib.com for a full manual.\n", }, }; int i; printf("%s", "\n" "Copyright (C) 2000-2007 by Andy McFadden. All Rights Reserved.\n\n" "NuLib2 uses NufxLib, a complete library of functions for accessing NuFX\n" "(ShrinkIt) archives. Both NufxLib and NuLib2 are free software, distributed\n" "under terms of the BSD License. Source code is available from\n" "http://www.nulib.com/, and copies of the licenses are included.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "README file for more details.\n\n" ); printf("Usage: %s -command[modifiers] archive [filename-list]\n\n", gProgName); printf("If \"archive\" is \"-\", the archive will be read from stdin.\n"); for (i = 0; i < NELEM(help); i++) { const ValidCombo* pvc; int j; pvc = FindValidComboEntry(help[i].cmd); if (pvc == NULL) { fprintf(stderr, "%s: internal error: couldn't find vc for %d\n", gProgName, help[i].cmd); continue; } printf("\nCommand \"-%c\": %s\n", help[i].letter, help[i].shortDescr); printf(" Valid modifiers:"); for (j = strlen(pvc->modifiers) -1; j >= 0; j--) { char ch = pvc->modifiers[j]; /* print flags, special-casing options that can be doubled */ if (ch == 'l' || ch == 'e' || ch == 'z') printf(" -%c -%c%c", ch, ch, ch); else printf(" -%c", ch); } putchar('\n'); printf("\n%s", help[i].longDescr); } putchar('\n'); printf("Compression algorithms supported:\n"); printf(" SQueeze (Huffman+RLE) ...... %s\n", NuTestFeature(kNuFeatureCompressSQ) == kNuErrNone? "yes" : "no"); printf(" LZW/1 and LZW/2 ............ %s\n", NuTestFeature(kNuFeatureCompressLZW) == kNuErrNone ? "yes" : "no"); printf(" 12- and 16-bit LZC ......... %s\n", NuTestFeature(kNuFeatureCompressLZC) == kNuErrNone ? "yes" : "no"); printf(" Deflate .................... %s\n", NuTestFeature(kNuFeatureCompressDeflate) == kNuErrNone ? "yes" : "no"); printf(" Bzip2 ...................... %s\n", NuTestFeature(kNuFeatureCompressBzip2) == kNuErrNone ? "yes" : "no"); return kNuErrNone; } /* * Process the command-line options. The results are placed into "pState". */ static int ProcessOptions(NulibState* pState, int argc, char* const* argv) { const char* cp; int idx; /* * Must have at least a command letter and an archive filename, unless * the command letter is 'h'. Special-case a solitary "-h" here. */ if (argc == 2 && (tolower(argv[1][0]) == 'h' || (argv[1][0] == '-' && tolower(argv[1][1] == 'h')) ) ) { DoHelp(NULL); return -1; } if (argc < 3) { Usage(pState); return -1; } /* * Argv[1] and any subsequent entries that have a leading hyphen * are options. Anything after that is a filename. Parse until we * think we've hit the filename. * * By UNIX convention, however, stdin is specified as a file called "-". */ for (idx = 1; idx < argc; idx++) { cp = argv[idx]; if (idx > 1 && *cp != '-') break; if (*cp == '-') cp++; if (*cp == '\0') { if (idx == 1) { fprintf(stderr, "%s: You must specify a command after the '-'\n", gProgName); goto fail; } else { /* they're using '-' for the filename */ break; } } if (idx == 1) { switch (tolower(*cp)) { case 'a': NState_SetCommand(pState, kCommandAdd); break; case 'x': NState_SetCommand(pState, kCommandExtract); break; case 'p': NState_SetCommand(pState, kCommandExtractToPipe); break; case 't': NState_SetCommand(pState, kCommandListShort); break; case 'v': NState_SetCommand(pState, kCommandListVerbose); break; case 'g': NState_SetCommand(pState, kCommandListDebug); break; case 'i': NState_SetCommand(pState, kCommandTest); break; case 'd': NState_SetCommand(pState, kCommandDelete); break; case 'h': NState_SetCommand(pState, kCommandHelp); break; default: fprintf(stderr, "%s: Unknown command '%c'\n", gProgName, *cp); goto fail; } cp++; } while (*cp != '\0') { switch (tolower(*cp)) { case 'u': NState_SetModUpdate(pState, true); break; case 'f': NState_SetModFreshen(pState, true); break; case 'r': NState_SetModRecurse(pState, true); break; case 'j': NState_SetModJunkPaths(pState, true); break; case '0': NState_SetModNoCompression(pState, true); break; case 's': NState_SetModOverwriteExisting(pState, true); break; case 'k': NState_SetModAddAsDisk(pState, true); break; case 'c': NState_SetModComments(pState, true); break; case 'b': NState_SetModBinaryII(pState, true); break; case 'z': if (*(cp+1) == 'z') { if (NuTestFeature(kNuFeatureCompressBzip2) == kNuErrNone) NState_SetModCompressBzip2(pState, true); else { fprintf(stderr, "%s: ERROR: libbz2 support not compiled in\n", gProgName); goto fail; } cp++; } else { if (NuTestFeature(kNuFeatureCompressDeflate) == kNuErrNone) NState_SetModCompressDeflate(pState, true); else { fprintf(stderr, "%s: ERROR: zlib support not compiled in\n", gProgName); goto fail; } } break; case 'e': if (*(cp-1) == 'e') /* should never point at invalid */ NState_SetModPreserveTypeExtended(pState, true); else NState_SetModPreserveType(pState, true); break; case 'l': if (*(cp-1) == 'l') /* should never point at invalid */ NState_SetModConvertAll(pState, true); else NState_SetModConvertText(pState, true); break; default: fprintf(stderr, "%s: Unknown modifier '%c'\n", gProgName, *cp); goto fail; } if (!IsValidModifier(NState_GetCommand(pState), (char)tolower(*cp))) { fprintf(stderr, "%s: The '%c' modifier doesn't make sense here\n", gProgName, tolower(*cp)); goto fail; } cp++; } } /* * Can't have tea and no tea at the same time. */ if (NState_GetModNoCompression(pState) && NState_GetModCompressDeflate(pState)) { fprintf(stderr, "%s: Can't specify both -0 and -z\n", gProgName); goto fail; } /* * See if we have an archive name. If it's "-", see if we allow that. */ Assert(idx < argc); NState_SetArchiveFilename(pState, argv[idx]); if (IsFilenameStdin(argv[idx])) { if (!IsValidOnPipe(NState_GetCommand(pState))) { fprintf(stderr, "%s: You can't do that with a pipe\n", gProgName); goto fail; } } idx++; /* * See if we have a file specification. Some of the commands require * a filespec; others just perform the requested operation on all of * the records in the archive if none is provided. */ if (idx < argc) { /* got one or more */ NState_SetFilespecPointer(pState, &argv[idx]); NState_SetFilespecCount(pState, argc - idx); } else { Assert(idx == argc); if (IsFilespecRequired(NState_GetCommand(pState))) { fprintf(stderr, "%s: This command requires a list of files\n", gProgName); goto fail; } NState_SetFilespecPointer(pState, NULL); NState_SetFilespecCount(pState, 0); } #ifdef DEBUG_VERBOSE NState_DebugDump(pState); #endif return 0; fail: fprintf(stderr, "%s: (invoke without arguments to see usage information)\n", gProgName); return -1; } /* * We have all of the parsed command line options in "pState". Now we just * have to do something useful with it. * * Returns 0 on success, 1 on error. */ int DoWork(NulibState* pState) { NuError err; switch (NState_GetCommand(pState)) { case kCommandAdd: err = DoAdd(pState); break; case kCommandExtract: err = DoExtract(pState); break; case kCommandExtractToPipe: err = DoExtractToPipe(pState); break; case kCommandTest: err = DoTest(pState); break; case kCommandListShort: err = DoListShort(pState); break; case kCommandListVerbose: err = DoListVerbose(pState); break; case kCommandListDebug: err = DoListDebug(pState); break; case kCommandDelete: err = DoDelete(pState); break; case kCommandHelp: err = DoHelp(pState); break; default: fprintf(stderr, "ERROR: unexpected command %d\n", NState_GetCommand(pState)); err = kNuErrInternal; Assert(0); break; } return (err != kNuErrNone); } /* * Entry point. */ int main(int argc, char** argv) { NulibState* pState = NULL; int32_t majorVersion, minorVersion, bugVersion; int result = 0; (void) NuGetVersion(&majorVersion, &minorVersion, &bugVersion, NULL, NULL); if (majorVersion != kNuVersionMajor || minorVersion < kNuVersionMinor) { fprintf(stderr, "ERROR: wrong version of NufxLib --" " wanted %d.%d.x, got %d.%d.%d.\n", kNuVersionMajor, kNuVersionMinor, majorVersion, minorVersion, bugVersion); goto bail; } #if 0 extern NuResult ErrorMessageHandler(NuArchive* pArchive, void* vErrorMessage); NuSetGlobalErrorMessageHandler(ErrorMessageHandler); #endif if (NState_Init(&pState) != kNuErrNone) { fprintf(stderr, "ERROR: unable to initialize globals\n"); exit(1); } gProgName = GetProgName(pState, argv[0]); if (ProcessOptions(pState, argc, argv) < 0) { result = 2; goto bail; } if (NState_ExtraInit(pState) != kNuErrNone) { fprintf(stderr, "ERROR: additional initialization failed\n"); exit(1); } result = DoWork(pState); if (result) printf("Failed.\n"); bail: NState_Free(pState); exit(result); } nulib2-3.1.0/nulib2/Makefile.in000066400000000000000000000105731316100516500161520ustar00rootroot00000000000000# # Nulib2 # Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. # This is free software; you can redistribute it and/or modify it under the # terms of the BSD License, see the file COPYING. # # Makefile for nulib2 stuff (should work with non-GNU make). # # You can use: # make (builds nulib2 and checks for libnufx.a) # make shared (builds nulib2 and checks for libnufx.so) # # This will try to link against the library in $(NUFXSRCDIR) first, then # look for a copy in the standard system install location (usually # /usr/local/lib). # # Note that this really wants to find $(NUFXLIB) for dependency checking. # If you're building against a copy in /usr/local/lib, just put a '#' in # front of the "NUFXLIB" line below. # # set this to where the NuFX library and ".h" file live NUFXSRCDIR = ../nufxlib NUFXLIB = $(NUFXSRCDIR)/$(LIB_PRODUCT) # NuLib2 install location. The man page will go into $(mandir)/man1. prefix = @prefix@ exec_prefix = @exec_prefix@ includedir = @includedir@ libdir = @libdir@ bindir = @bindir@ mandir = @mandir@ srcdir = @srcdir@ SHELL = @SHELL@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ CC = @CC@ #OPT = @CFLAGS@ -DNDEBUG OPT = @CFLAGS@ #OPT = @CFLAGS@ -DDEBUG_MSGS #OPT = @CFLAGS@ -DDEBUG_VERBOSE GCC_FLAGS = -Wall -Wwrite-strings -Wstrict-prototypes -Wpointer-arith -Wshadow CFLAGS = @BUILD_FLAGS@ -I. -I$(NUFXSRCDIR) -I$(includedir) @DEFS@ SRCS = Add.c ArcUtils.c Binary2.c Delete.c Extract.c Filename.c \ List.c Main.c MiscStuff.c MiscUtils.c State.c SysUtils.c OBJS = Add.o ArcUtils.o Binary2.o Delete.o Extract.o Filename.o \ List.o Main.o MiscStuff.o MiscUtils.o State.o SysUtils.o PRODUCT = nulib2 # this is used for dependency checking LIB_PRODUCT = libnufx.a # # Build stuff # all: $(PRODUCT) @true install: $(PRODUCT) $(srcdir)/mkinstalldirs $(bindir) $(INSTALL_PROGRAM) $(PRODUCT) $(bindir) $(srcdir)/mkinstalldirs $(mandir)/man1 $(INSTALL_DATA) nulib2.1 $(mandir)/man1/ install-shared: LIB_PRODUCT="libnufx.so" $(MAKE) -e install # Link against the shared version of libnufx. This is only needed so # the dependency checking does the right thing during development. Note # we probably don't need to link against all of LIBS, especially -lz -lbz2, # but there's little harm in doing so. shared:: LIB_PRODUCT="libnufx.so" $(MAKE) -e $(PRODUCT): $(OBJS) $(NUFXLIB) $(CC) -o $@ $(OBJS) -L$(NUFXSRCDIR) -L$(libdir) -lnufx @LIBS@ clean: -rm -f *.o core -rm -f $(PRODUCT) tags:: ctags -R --totals * $(NUFXSRCDIR)/* @#ctags *.[ch] $(NUFXSRCDIR)/*.[ch] distclean: clean -rm -f Makefile Makefile.bak -rm -f config.log config.cache config.status config.h -rm -f tags -rm -f nulib2-@host_alias@ nulib2-@host_alias@.tar.Z # Copy all of the binaries into a directory and tar them up for distribution. # All binaries except "nulib2" are stripped to reduce their size. distbin: $(PRODUCT) @ \ builddir="nulib2-@host_alias@"; \ samples=$(NUFXSRCDIR)/samples; \ echo "building $$builddir.tar.Z"; \ rm -rf $$builddir; \ mkdir -p $$builddir; \ cp -p $(PRODUCT) nulib2.1 README.txt COPYING $$samples/README-S.txt \ $$samples/exerciser $$samples/imgconv $$samples/launder \ $$samples/test-basic $$samples/test-extract \ $$samples/test-simple \ $$builddir; \ strip $$builddir/$(PRODUCT) \ $$builddir/exerciser $$builddir/imgconv $$builddir/launder \ $$builddir/test-basic $$builddir/test-extract \ $$builddir/test-simple; \ tar -cf - $$builddir | compress > $$builddir.tar.Z; \ rm -rf $$builddir # Make a tarfile with a backup of the essential files. We include "Makefile" # so that we can do a "make distclean" during packaging. baktar: @tar cvf nulib2.tar *.txt COPYING INSTALL nulib2.1 configure *.in Makefile \ Makefile.msc install-sh config.guess config.sub mkinstalldirs *.[ch] @gzip -9 nulib2.tar @mv -i nulib2.tar.gz /home/fadden/BAK/ # dependency info COMMON_HDRS = NuLib2.h SysDefs.h State.h MiscStuff.h config.h \ $(NUFXSRCDIR)/NufxLib.h Add.o: Add.c $(COMMON_HDRS) ArcUtils.o: ArcUtils.c $(COMMON_HDRS) Binary2.o: Binary2.c $(COMMON_HDRS) Delete.o: Delete.c $(COMMON_HDRS) Extract.o: Extract.c $(COMMON_HDRS) Filename.o: Filename.c $(COMMON_HDRS) List.o: List.c $(COMMON_HDRS) Main.o: Main.c $(COMMON_HDRS) MiscStuff.o: MiscStuff.c $(COMMON_HDRS) MiscUtils.o: MiscUtils.c $(COMMON_HDRS) State.o: State.c $(COMMON_HDRS) SysUtils.o: SysUtils.c $(COMMON_HDRS) nulib2-3.1.0/nulib2/Makefile.msc000066400000000000000000000042471316100516500163270ustar00rootroot00000000000000# Makefile for NuLib2 using Microsoft Visual C++. # # Tested with VS 2013 Pro. From the "VS2013 x86 Native Tools Command # Prompt", run "nmake -f makefile.msc". # # If you're including zlib support, place a copy of the zlib # library in this directory. # TOP = . NUFXSRCDIR = ..\nufxlib NUFXLIB = $(NUFXSRCDIR)\nufxlib2.lib PRODUCT = nulib2.exe CC = cl LD = link # C compiler flags # -Ox: full optimization # -Oy-: disable frame pointer omission (for easier debugging) # -MD: create a multithreaded DLL using MSVCRT.lib; alternatively, # use -MDd to create a debug executable with MSVCRTD.lib # -nologo: suppress display of copyright banner # -W3: set warning level to 3 (all production-level warnings) # -Zi: generate a PDB file with full debugging info CFLAGS = -nologo -MD -W3 -Ox -Oy- -Zi "-I$(NUFXSRCDIR)" # Warning suppression flags WFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE # Linker flags # -debug: creates debugging info for EXE or DLL in PDB file # -nologo: suppress display of copyright banner # -opt:ref: eliminates unreferenced functions and data (default for non-debug # builds, but we've enabled debug info) LDFLAGS = -nologo -debug -opt:ref ZLIB=1 !ifdef ZLIB # enable deflate support; requires zlib LDFLAGS = $(LDFLAGS) zlib.lib !endif # object files OBJS = Add.obj ArcUtils.obj Binary2.obj Delete.obj Extract.obj Filename.obj \ List.obj Main.obj MiscStuff.obj MiscUtils.obj State.obj SysUtils.obj # build targets all: $(PRODUCT) $(PRODUCT): $(OBJS) $(NUFXLIB) $(LD) $(LDFLAGS) -out:$@ $(OBJS) $(NUFXLIB) clean: -del *.obj *.pdb *.exp -del $(PRODUCT) # generic rules .c.obj: $(CC) -c $(WFLAGS) $(CFLAGS) $< # dependency info COMMON_HDRS = NuLib2.h $(NUFXSRCDIR)\NufxLib.h SysDefs.h State.h MiscStuff.h Add.obj: Add.c $(COMMON_HDRS) ArcUtils.obj: ArcUtils.c $(COMMON_HDRS) Binary2.obj: Binary2.c $(COMMON_HDRS) Delete.obj: Delete.c $(COMMON_HDRS) Extract.obj: Extract.c $(COMMON_HDRS) Filename.obj: Filename.c $(COMMON_HDRS) List.obj: List.c $(COMMON_HDRS) Main.obj: Main.c $(COMMON_HDRS) MiscStuff.obj: MiscStuff.c $(COMMON_HDRS) MiscUtils.obj: MiscUtils.c $(COMMON_HDRS) State.obj: State.c $(COMMON_HDRS) SysUtils.obj: SysUtils.c $(COMMON_HDRS) nulib2-3.1.0/nulib2/MiscStuff.c000066400000000000000000000056351316100516500161570ustar00rootroot00000000000000/* * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Misc stuff (shared between nufxlib and nulib2). This is a collection * of standard functions that aren't available in libc on this system. */ #include "SysDefs.h" #include "MiscStuff.h" #include #ifndef HAVE_STRERROR /* * Return a pointer to the appropriate string in the system table, or NULL * if the value is out of bounds. */ const char* Nu_strerror(int errnum) { extern int sys_nerr; extern char *sys_errlist[]; if (errnum < 0 || errnum > sys_nerr) return NULL; return sys_errlist[errnum]; } #endif #ifndef HAVE_MEMMOVE /* * Move a block of memory. Unlike memcpy, this is expected to work * correctly with overlapping blocks. * * This is a straightforward implementation. A much faster implementation, * from BSD, is available in the PGP 2.6.2 distribution, but this should * suffice for those few systems that don't have memmove. */ void* Nu_memmove(void* dst, const void* src, size_t n) { void* retval = dst; char* srcp = (char*)src; char* dstp = (char*)dst; /* you can normally get away with this if n==0 */ Assert(dst != NULL); Assert(src != NULL); if (dstp == srcp || !n) { /* nothing to do */ } else if (dstp > srcp) { /* start from the end */ (char*)dstp += n-1; (char*)srcp += n-1; while (n--) *dstp-- = *srcp--; } else { /* start from the front */ while (n--) *dstp++ = *srcp++; } return retval; } #endif #ifndef HAVE_STRTOUL /* * Perform strtol, but on an unsigned long. * * On systems that have strtol but don't have strtoul, the strtol * function doesn't clamp the return value, making it similar in * function to strtoul. The comparison is not exact, however, * because strtoul is expected to lots of fancy things (like set * errno to ERANGE). * * For our purposes here, strtol does all we need it to. Someday * we should replace this with a "real" version. */ unsigned long Nu_strtoul(const char *nptr, char **endptr, int base) { return strtol(nptr, endptr, base); } #endif #ifndef HAVE_STRCASECMP /* * Compare two strings, case-insensitive. */ int Nu_strcasecmp(const char *str1, const char *str2) { while (*str1 && *str2 && toupper(*str1) == toupper(*str2)) str1++, str2++; return (toupper(*str1) - toupper(*str2)); } #endif #ifndef HAVE_STRNCASECMP /* * Compare two strings, case-insensitive, stopping after "n" chars. */ int Nu_strncasecmp(const char *str1, const char *str2, size_t n) { while (n && *str1 && *str2 && toupper(*str1) == toupper(*str2)) str1++, str2++, n--; if (n) return (toupper(*str1) - toupper(*str2)); else return 0; /* no mismatch in first n chars */ } #endif nulib2-3.1.0/nulib2/MiscStuff.h000066400000000000000000000051731316100516500161610ustar00rootroot00000000000000/* * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING-LIB. * * Misc stuff (shared between nufxlib and nulib2). This is a collection * of miscellaneous types and macros that I find generally useful. */ #ifndef NULIB2_MISCSTUFF_H #define NULIB2_MISCSTUFF_H #define VALGRIND /* assume we're using it */ #include "SysDefs.h" /* * Use our versions of functions if they don't exist locally. */ #ifndef HAVE_STRERROR #define strerror Nu_strerror const char* Nu_strerror(int errnum); #endif #ifndef HAVE_MEMMOVE #define memmove Nu_memmove void* Nu_memmove(void *dest, const void *src, size_t n); #endif #ifndef HAVE_STRTOUL #define strtoul Nu_strtoul unsigned long Nu_strtoul(const char *nptr, char **endptr, int base); #endif #ifndef HAVE_STRCASECMP #define strcasecmp Nu_strcasecmp int Nu_strcasecmp(const char *s1, const char *s2); #endif #ifndef HAVE_STRNCASECMP #define strncasecmp Nu_strncasecmp int Nu_strncasecmp(const char *s1, const char *s2, size_t n); #endif /* * Misc types. */ typedef unsigned char Boolean; #define false (0) #define true (!false) /* * Handy macros. */ /* compute #of elements in a static array */ #define NELEM(x) (sizeof(x) / sizeof((x)[0])) /* convert single hex digit char to number */ #define HexDigit(x) ( !isxdigit((int)(x)) ? -1 : \ (x) <= '9' ? (x) - '0' : toupper(x) +10 - 'A' ) /* convert number from 0-15 to hex digit */ #define HexConv(x) ( ((unsigned int)(x)) <= 15 ? \ ( (x) <= 9 ? (x) + '0' : (x) -10 + 'A') : -1 ) /* * Debug stuff. */ /* * Redefine this if you want assertions to do something other than default. * Changing the definition of assert is tough, because assert.h redefines * it every time it's included. On a Solaris 2.7 system I was using, gcc * pulled assert.h in with some of the system headers, and their definition * resulted in corrupted core dumps. */ #define Assert assert #if defined(DEBUG_VERBOSE) /* quick debug printf macro */ #define DBUG(args) printf args #else #define DBUG(args) ((void)0) #endif #if defined(NDEBUG) #define DebugFill(addr, len) ((void)0) #define DebugAbort() ((void)0) #else /* when debugging, fill Malloc blocks with junk, unless we're using Purify */ #if !defined(PURIFY) && !defined(VALGRIND) #define DebugFill(addr, len) memset(addr, 0xa3, len) #else #define DebugFill(addr, len) ((void)0) #endif #define DebugAbort() abort() #endif #define kInvalidPtr ((void*)0xa3a3a3a3) #endif /*NULIB2_MISCSTUFF_H*/ nulib2-3.1.0/nulib2/MiscUtils.c000066400000000000000000000057751316100516500161750ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Misc support functions. */ #include "NuLib2.h" /* * Similar to perror(), but takes the error as an argument, and knows * about NufxLib errors as well as system errors. * * If "format" is NULL, just the error message itself is printed. */ void ReportError(NuError err, const char* format, ...) { const char* msg; va_list args; Assert(format != NULL); va_start(args, format); /* print the message, if any */ if (format != NULL) { fprintf(stderr, "%s: ERROR: ", gProgName); vfprintf(stderr, format, args); } /* print the error code data, if any */ if (err == kNuErrNone) fprintf(stderr, "\n"); else { if (format != NULL) fprintf(stderr, ": "); msg = NULL; if (err >= 0) msg = strerror(err); if (msg == NULL) msg = NuStrError(err); if (msg == NULL) fprintf(stderr, "(unknown err=%d)\n", err); else fprintf(stderr, "%s\n", msg); } va_end(args); } /* * Memory allocation wrappers. * * Under gcc these would be macros, but not all compilers can handle that. */ #ifndef USE_DMALLOC void* Malloc(size_t size) { void* _result; Assert(size > 0); _result = malloc(size); if (_result == NULL) { ReportError(kNuErrMalloc, "malloc(%u) failed", (unsigned int) size); DebugAbort(); /* leave a core dump if we're built for it */ } DebugFill(_result, size); return _result; } void* Calloc(size_t size) { void* _cresult = Malloc(size); memset(_cresult, 0, size); return _cresult; } void* Realloc(void* ptr, size_t size) { void* _result; Assert(ptr != NULL); /* disallow this usage */ Assert(size > 0); /* disallow this usage */ _result = realloc(ptr, size); if (_result == NULL) { ReportError(kNuErrMalloc, "realloc(%u) failed", (unsigned int) size); DebugAbort(); /* leave a core dump if we're built for it */ } return _result; } void Free(void* ptr) { if (ptr != NULL) free(ptr); } #endif /* * This gets called when a buffer DataSource is no longer needed. */ NuResult FreeCallback(NuArchive* pArchive, void* args) { DBUG(("+++ free callback 0x%08lx\n", (long) args)); Free(args); return kNuOK; } /* * Convert Mac OS Roman to Unicode. The caller must free the string * returned. * * Returns NULL if stringMOR is NULL or if the conversion fails. */ UNICHAR* CopyMORToUNI(const char* stringMOR) { size_t uniLen; UNICHAR* uniBuf; if (stringMOR == NULL) { return NULL; } uniLen = NuConvertMORToUNI(stringMOR, NULL, 0); if (uniLen == (size_t) -1) { return NULL; } uniBuf = (UNICHAR*) malloc(uniLen); NuConvertMORToUNI(stringMOR, uniBuf, uniLen); return uniBuf; } nulib2-3.1.0/nulib2/NuLib2.h000066400000000000000000000073501316100516500153500ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. */ #ifndef NULIB2_NULIB2_H #define NULIB2_NULIB2_H #include "SysDefs.h" /* system-dependent defs; must come first */ #include #include "State.h" #include "MiscStuff.h" #ifdef USE_DMALLOC /* enable with something like "dmalloc -l logfile -i 100 medium" */ # include "dmalloc.h" #endif /* replace unsupported chars with '%xx' */ #define kForeignIndic '%' /* use this to separate path components in stored filenames */ #define kStorageFssep ':' /* make our one-line comments this big */ #define kDefaultCommentLen 200 /* for use with FormatDateShort() */ #define kDateOutputLen 64 /* * Function prototypes. */ /* Add.c */ NuError DoAdd(NulibState* pState); /* ArcUtils.c */ char* GetSimpleComment(NulibState* pState, const char* pathname, int maxLen); Boolean IsFilenameStdin(const char* archiveName); Boolean IsSpecified(NulibState* pState, const NuRecord* pRecord); NuError OpenArchiveReadOnly(NulibState* pState); NuError OpenArchiveReadWrite(NulibState* pState); const NuThread* GetThread(const NuRecord* pRecord, uint32_t idx); Boolean IsRecordReadOnly(const NuRecord* pRecord); /* Binary2.c */ NuError BNYDoExtract(NulibState* pState); NuError BNYDoTest(NulibState* pState); NuError BNYDoListShort(NulibState* pState); NuError BNYDoListVerbose(NulibState* pState); NuError BNYDoListDebug(NulibState* pState); /* Delete.c */ NuError DoDelete(NulibState* pState); /* Extract.c */ NuError DoExtract(NulibState* pState); NuError DoExtractToPipe(NulibState* pState); NuError DoTest(NulibState* pState); /* Filename.c */ const char* GetFileTypeString(uint32_t fileType); const char* NormalizePath(NulibState* pState, NuPathnameProposal* pathProposal); void InterpretExtension(NulibState* pState, const char* pathName, uint32_t* pFileType, uint32_t* pAuxType); Boolean ExtractPreservationString(NulibState* pState, char* pathname, uint32_t* pFileType, uint32_t* pAuxType, NuThreadID* pThreadID); void DenormalizePath(NulibState* pState, char* pathBuf); const char* FilenameOnly(NulibState* pState, const char* pathname); const char* FindExtension(NulibState* pState, const char* pathname); /* List.c */ NuError DoListShort(NulibState* pState); NuError DoListVerbose(NulibState* pState); NuError DoListDebug(NulibState* pState); char* FormatDateShort(const NuDateTime* pDateTime, char* buffer); /* Main.c */ extern const char* gProgName; /* MiscUtils.c */ void ReportError(NuError err, const char* format, ...) #if defined(__GNUC__) __attribute__ ((format(printf, 2, 3))) #endif ; #ifdef USE_DMALLOC /* want file and line numbers for calls */ # define Malloc(size) malloc(size) # define Calloc(size) calloc(1, size) # define Realloc(ptr, size) realloc(ptr, size) # define Free(ptr) (ptr != NULL ? free(ptr) : (void)0) #else void* Malloc(size_t size); void* Calloc(size_t size); void* Realloc(void* ptr, size_t size); void Free(void* ptr); #endif NuResult FreeCallback(NuArchive* pArchive, void* args); UNICHAR* CopyMORToUNI(const char* stringMOR); /* SysUtils.c */ NuError NormalizeFileName(NulibState* pState, const char* srcp, long srcLen, char fssep, char** pDstp, long dstLen); NuError NormalizeDirectoryName(NulibState* pState, const char* srcp, long srcLen, char fssep, char** pDstp, long dstLen); char* MakeTempArchiveName(NulibState* pState); NuError SetFinderInfo(int fd, uint8_t proType, uint16_t proAux); NuError AddFile(NulibState* pState, NuArchive* pArchive, const char* pathname); NuError Mkdir(const char* dir); NuError TestFileExistence(const char* fileName, Boolean* pIsDir); #endif /*NULIB2_NULIB2_H*/ nulib2-3.1.0/nulib2/README-Win32.txt000066400000000000000000000006261316100516500165010ustar00rootroot00000000000000This archive contains the NuLib2 exe for Win32, plus the sample applications from the NufxLib distribution. These were built with assertions and extended tests enabled, which adds a little bit to the file size and reduces the performance somewhat, but it catches errors earlier and makes the failure messages more useful. The latest versions will always be available from http://www.nulib.com/. nulib2-3.1.0/nulib2/README.txt000066400000000000000000000126431316100516500156030ustar00rootroot00000000000000NuLib2 README, updated 2015/01/03 http://www.nulib.com/ To build NuLib2, you will also need a copy of NufxLib. This should have come in the same distribution file. Build the NufxLib library first. UNIX ==== Make sure that the "NUFXSRCDIR" define in Makefile.in points to the correct directory, or that the library has been installed in a standard location such as /usr/local/lib/. If you received NuLib2 and NufxLib in a single ".tar.gz" file, the variable is already set correctly. The makefile will look in $(NUFXSRCDIR) first, /usr/local/lib second. Run the "configure" script. Read through "INSTALL" if you haven't used one of these before, especially if you want to use a specific compiler or a particular set of compiler flags. If you have disabled deflate or enabled bzip2 support in libnufx.a, you will need to provide the same --enable-METHOD or --disable-METHOD flag to configure here. If you're using shared libraries then the link dependencies are taken care of and you don't need to do anything. Run "make depend" if you have makedepend, and then type "make". This should leave you with an executable called "nulib2". If you like, "make install" will copy files into your install directory, usually /usr/local/bin/ and /usr/local/man/. You can change this by using "./configure --prefix=directory". You may want to fiddle with the "OPT" setting in Makefile to enable or disable optimizations and assertions. Because almost all of the hard work is done by NufxLib, turning compiler optimizations on in NuLib2 has little impact on performance. A man page for nulib2 is in "nulib2.1", which you can format for viewing with "nroff -man nulib2.1". A full manual for NuLib2 is available from the www.nulib.com web site. BeOS ==== This works just like the UNIX version, but certain defaults have been changed. Running configure without arguments under BeOS is equivalent to: ./configure --prefix=/boot --includedir='${prefix}/develop/headers' --libdir='${exec_prefix}/home/config/lib' --mandir='/tmp' --bindir='${exec_prefix}/home/config/bin' If you're using BeOS/PPC, it will also do: CC=cc CFLAGS='-proc 603 -opt full' Mac OS X ======== This works just like the UNIX version, but includes support for resource forks and Finder file/aux types. Tested with Xcode v5.1.1 and Mac OS 10.8.5. Win32 ===== If you're using an environment that supports "configure" scripts, such as DJGPP, follow the UNIX instructions. NuLib2 has been tested with Microsoft Visual C++ 12 (Visual Studio 2013). To build NuLib2, run the "Visual Studio 2013 x86 Native Tools Command Prompt" shortcut to get a shell. Change to the nulib2 directory, then: nmake -f makefile.msc If you want to have zlib support enabled, you will need to have zlib.lib copied into the directory. See "makefile.msc" for more details. Unicode filename support has not been ported to Windows. Non-ASCII characters will be interpreted as the default character set (CP1252). This is the way NuLib2 has always worked in Windows, but it may not match with the behavior of CiderPress. In any event, this only affects files with non-ASCII filenames. Other Notes =========== Fun benchmark of the day: Time to compress 1525 files, totaling 19942152 bytes, on an Apple IIgs with an 8MHz ZipGS accelerator and Apple HS SCSI card, running System 6.0.1, from a 20MB ProDOS partition to a 13.9MB archive on an HFS volume, with GS/ShrinkIt 1.1: about 40 minutes. Time to compress the same files, on a 128MB 500MHz Pentium-III running Red Hat Linux 6.0, with NuLib2 v0.3: about six seconds. Here's a nifty way to evaluate GSHK vs NuLib2 (as well as Linux NuLib2 vs Win32 NuLib2): - Archive a whole bunch of files from a ProDOS volume with GS/ShrinkIt. I used a 20MB partition, which resulted in a 14MB archive. Transfer the archive to a machine running NuLib2 (perhaps a Linux system). - Create a new subdirectory, cd into it, and extract the entire archive with "nulib2 xe ../foo.shk". - Now create a new archive with all of the files, using "nulib2 aer ../new.shk *". - Change back to the directory above, and use "nulib2 v" to see what's in them, e.g. "nulib2 v foo.shk > out.orig" and "nulib2 v new.shk > out.new". - Edit both of the "out" files with vi. Do a global search-and-replace in both files to set the file dates to be the same. I used ":%s/..-...-.. ..:../01-Jan-00 00:00/". This is necessary because, like ShrinkIt, NuLib displays the date on which the files were archived, not when they were last modified. - Sort both files, with ":%!sort". This is necessary because you added the files with '*' up above, so the NuLib2-created archive has the top-level files alphabetized. - Quit out of vi. Diff the two files. I did this for a 20MB hard drive partition with 1500 files on it. The only discrepancies (accounting for a total difference of 116 bytes) were a zero-byte "Kangaroo.data" file that GSHK stored improperly and some semi-random GSHK behavior that I can't mimic. When the "Mimic ShrinkIt" flag is disabled, the resulting archive is 13K smaller. The largest archive I've tried had 4700 files for a total of 76MB (compressed down to 47MB), and contained the entire contents of four 20MB ProDOS hard drive partitions. NuLib2 under Linux handled it without breaking a sweat. Legalese ======== NuLib2, a NuFX and Binary II archive application. Copyright (C) 2000-2014 by Andy McFadden, All Rights Reserved. See COPYING for license. nulib2-3.1.0/nulib2/State.c000066400000000000000000000260231316100516500153260ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * Global-ish state object. */ #include "NuLib2.h" static const char* gProgramVersion = "3.1.0"; /* * Allocate and initialize the semi-global NuLib2 state object. */ NuError NState_Init(NulibState** ppState) { Assert(ppState != NULL); *ppState = Calloc(sizeof(**ppState)); if (*ppState == NULL) return kNuErrMalloc; /* * Initialize the contents to default values. */ (*ppState)->systemPathSeparator = PATH_SEP; #ifdef PATH_SEP2 (*ppState)->altSystemPathSeparator = PATH_SEP2; #else (*ppState)->altSystemPathSeparator = '\0'; #endif (*ppState)->programVersion = gProgramVersion; return kNuErrNone; } /* * A little extra initialization, performed after arguments are parsed. */ NuError NState_ExtraInit(NulibState* pState) { NuError err; NuValue convertEOL; /* * Create a data sink for "stdout", in case we use the "-p" command. * Set the EOL conversion according to the "-l" modifier. */ convertEOL = kNuConvertOff; if (pState->modConvertText) convertEOL = kNuConvertAuto; if (pState->modConvertAll) convertEOL = kNuConvertOn; err = NuCreateDataSinkForFP(true, convertEOL, stdout, &pState->pPipeSink); if (err != kNuErrNone) return err; /* * Create a data sink for "stdout", in case we use the "-c" modifier. * The EOL conversion is always on. */ err = NuCreateDataSinkForFP(true, kNuConvertOn, stdout, &pState->pCommentSink); return err; } /* * Free up the state structure and its contents. */ void NState_Free(NulibState* pState) { if (pState == NULL) return; Free(pState->renameToStr); /* ?? */ Free(pState->tempPathnameBuf); if (pState->pPipeSink != NULL) NuFreeDataSink(pState->pPipeSink); if (pState->pCommentSink != NULL) NuFreeDataSink(pState->pCommentSink); Free(pState); } #ifdef DEBUG_MSGS void NState_DebugDump(const NulibState* pState) { /* this table will break if the code changes, but it's just for debugging */ static const char* kCommandNames[] = { "", "add", "delete", "extract", "extractToPipe", "listShort", "listVerbose", "listDebug", "test", "help", }; Assert(pState != NULL); printf("NState:\n"); printf(" programVersion: '%s'\n", pState->programVersion); printf(" systemPathSeparator: '%c'\n", pState->systemPathSeparator); if (pState->altSystemPathSeparator != '\0') printf(" altSystemPathSeparator: '%c'\n", pState->altSystemPathSeparator); printf(" archiveFilename: '%s'\n", pState->archiveFilename); printf(" filespec: %ld (%s ...)\n", pState->filespecCount, !pState->filespecCount ? "" : *pState->filespecPointer); printf(" command: %d (%s); modifiers:\n", pState->command, kCommandNames[pState->command]); if (pState->modUpdate) printf(" update\n"); if (pState->modFreshen) printf(" freshen\n"); if (pState->modRecurse) printf(" recurse\n"); if (pState->modJunkPaths) printf(" junkPaths\n"); if (pState->modNoCompression) printf(" noCompression\n"); if (pState->modCompressDeflate) printf(" compressDeflate\n"); if (pState->modCompressBzip2) printf(" compressBzip2\n"); if (pState->modComments) printf(" comments\n"); if (pState->modBinaryII) printf(" binaryII\n"); if (pState->modConvertText) printf(" convertText\n"); if (pState->modConvertAll) printf(" convertAll\n"); if (pState->modOverwriteExisting) printf(" overwriteExisting\n"); if (pState->modPreserveType) printf(" preserveType\n"); if (pState->modPreserveTypeExtended) printf(" preserveTypeExtended\n"); printf("\n"); } #endif /* * =========================================================================== * Simple set/get functions * =========================================================================== */ char NState_GetSystemPathSeparator(const NulibState* pState) { return pState->systemPathSeparator; } char NState_GetAltSystemPathSeparator(const NulibState* pState) { return pState->altSystemPathSeparator; } const char* NState_GetProgramVersion(const NulibState* pState) { return pState->programVersion; } NuArchive* NState_GetNuArchive(const NulibState* pState) { return pState->pArchive; } void NState_SetNuArchive(NulibState* pState, NuArchive* pArchive) { pState->pArchive = pArchive; } Boolean NState_GetSuppressOutput(const NulibState* pState) { return pState->suppressOutput; } void NState_SetSuppressOutput(NulibState* pState, Boolean doSuppress) { pState->suppressOutput = doSuppress; } Boolean NState_GetInputUnavailable(const NulibState* pState) { return pState->inputUnavailable; } void NState_SetInputUnavailable(NulibState* pState, Boolean isUnavailable) { pState->inputUnavailable = isUnavailable; } NuRecordIdx NState_GetRenameFromIdx(const NulibState* pState) { return pState->renameFromIdx; } void NState_SetRenameFromIdx(NulibState* pState, NuRecordIdx recordIdx) { pState->renameFromIdx = recordIdx; } char* NState_GetRenameToStr(const NulibState* pState) { return pState->renameToStr; } void NState_SetRenameToStr(NulibState* pState, char* str) { Free(pState->renameToStr); pState->renameToStr = str; } NuDataSink* NState_GetPipeSink(const NulibState* pState) { return pState->pPipeSink; } NuDataSink* NState_GetCommentSink(const NulibState* pState) { return pState->pCommentSink; } long NState_GetMatchCount(const NulibState* pState) { return pState->matchCount; } void NState_SetMatchCount(NulibState* pState, long count) { pState->matchCount = count; } void NState_IncMatchCount(NulibState* pState) { pState->matchCount++; } void NState_AddToTotals(NulibState* pState, long len, long compLen) { pState->totalLen += len; pState->totalCompLen += compLen; } void NState_GetTotals(NulibState* pState, long* pTotalLen, long* pTotalCompLen) { *pTotalLen = pState->totalLen; *pTotalCompLen = pState->totalCompLen; } long NState_GetTempPathnameLen(NulibState* pState) { return pState->tempPathnameAlloc; } void NState_SetTempPathnameLen(NulibState* pState, long len) { char* newBuf; len++; /* add one for the '\0' */ if (pState->tempPathnameAlloc < len) { if (pState->tempPathnameBuf == NULL) newBuf = Malloc(len); else newBuf = Realloc(pState->tempPathnameBuf, len); Assert(newBuf != NULL); if (newBuf == NULL) { Free(pState->tempPathnameBuf); pState->tempPathnameBuf = NULL; pState->tempPathnameAlloc = 0; ReportError(kNuErrMalloc, "buf realloc failed (%ld)", len); return; } pState->tempPathnameBuf = newBuf; pState->tempPathnameAlloc = len; } } char* NState_GetTempPathnameBuf(NulibState* pState) { return pState->tempPathnameBuf; } Command NState_GetCommand(const NulibState* pState) { return pState->command; } void NState_SetCommand(NulibState* pState, Command cmd) { pState->command = cmd; } const char* NState_GetArchiveFilename(const NulibState* pState) { return pState->archiveFilename; } void NState_SetArchiveFilename(NulibState* pState, const char* archiveFilename) { pState->archiveFilename = archiveFilename; } char* const* NState_GetFilespecPointer(const NulibState* pState) { return pState->filespecPointer; } void NState_SetFilespecPointer(NulibState* pState, char* const* filespecPointer) { pState->filespecPointer = filespecPointer; } long NState_GetFilespecCount(const NulibState* pState) { return pState->filespecCount; } void NState_SetFilespecCount(NulibState* pState, long filespecCount) { pState->filespecCount = filespecCount; } Boolean NState_GetModUpdate(const NulibState* pState) { return pState->modUpdate; } void NState_SetModUpdate(NulibState* pState, Boolean val) { pState->modUpdate = val; } Boolean NState_GetModFreshen(const NulibState* pState) { return pState->modFreshen; } void NState_SetModFreshen(NulibState* pState, Boolean val) { pState->modFreshen = val; } Boolean NState_GetModRecurse(const NulibState* pState) { return pState->modRecurse; } void NState_SetModRecurse(NulibState* pState, Boolean val) { pState->modRecurse = val; } Boolean NState_GetModJunkPaths(const NulibState* pState) { return pState->modJunkPaths; } void NState_SetModJunkPaths(NulibState* pState, Boolean val) { pState->modJunkPaths = val; } Boolean NState_GetModNoCompression(const NulibState* pState) { return pState->modNoCompression; } void NState_SetModNoCompression(NulibState* pState, Boolean val) { pState->modNoCompression = val; } Boolean NState_GetModCompressDeflate(const NulibState* pState) { return pState->modCompressDeflate; } void NState_SetModCompressDeflate(NulibState* pState, Boolean val) { pState->modCompressDeflate = val; } Boolean NState_GetModCompressBzip2(const NulibState* pState) { return pState->modCompressBzip2; } void NState_SetModCompressBzip2(NulibState* pState, Boolean val) { pState->modCompressBzip2 = val; } Boolean NState_GetModComments(const NulibState* pState) { return pState->modComments; } void NState_SetModComments(NulibState* pState, Boolean val) { pState->modComments = val; } Boolean NState_GetModBinaryII(const NulibState* pState) { return pState->modBinaryII; } void NState_SetModBinaryII(NulibState* pState, Boolean val) { pState->modBinaryII = val; } Boolean NState_GetModConvertText(const NulibState* pState) { return pState->modConvertText; } void NState_SetModConvertText(NulibState* pState, Boolean val) { pState->modConvertText = val; } Boolean NState_GetModConvertAll(const NulibState* pState) { return pState->modConvertAll; } void NState_SetModConvertAll(NulibState* pState, Boolean val) { pState->modConvertAll = val; } Boolean NState_GetModOverwriteExisting(const NulibState* pState) { return pState->modOverwriteExisting; } void NState_SetModOverwriteExisting(NulibState* pState, Boolean val) { pState->modOverwriteExisting = val; } Boolean NState_GetModAddAsDisk(const NulibState* pState) { return pState->modAddAsDisk; } void NState_SetModAddAsDisk(NulibState* pState, Boolean val) { pState->modAddAsDisk = val; } Boolean NState_GetModPreserveType(const NulibState* pState) { return pState->modPreserveType; } void NState_SetModPreserveType(NulibState* pState, Boolean val) { pState->modPreserveType = val; } Boolean NState_GetModPreserveTypeExtended(const NulibState* pState) { return pState->modPreserveTypeExtended; } void NState_SetModPreserveTypeExtended(NulibState* pState, Boolean val) { pState->modPreserveTypeExtended = val; } nulib2-3.1.0/nulib2/State.h000066400000000000000000000140601316100516500153310ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. */ #ifndef NULIB2_STATE_H #define NULIB2_STATE_H #include "MiscStuff.h" #include "NufxLib.h" /* * Things you can tell NuLib2 to do. * * (Some debug code in NState_DebugDump() is sensitive to the order here.) */ typedef enum Command { kCommandUnknown = 0, kCommandAdd, kCommandDelete, kCommandExtract, kCommandExtractToPipe, kCommandListShort, kCommandListVerbose, kCommandListDebug, kCommandTest, kCommandHelp } Command; /* * Program-wide state. */ typedef struct NulibState { /* global goodness */ const char* programVersion; /* system-specific values */ char systemPathSeparator; char altSystemPathSeparator; /* pointer to archive we're working with */ NuArchive* pArchive; /* misc state */ Boolean suppressOutput; Boolean inputUnavailable; NuRecordIdx renameFromIdx; char* renameToStr; NuDataSink* pPipeSink; NuDataSink* pCommentSink; long matchCount; long totalLen; long totalCompLen; /* temp storage */ long tempPathnameAlloc; char* tempPathnameBuf; /* command-line options */ Command command; Boolean modUpdate; Boolean modFreshen; Boolean modRecurse; Boolean modJunkPaths; Boolean modNoCompression; Boolean modCompressDeflate; Boolean modCompressBzip2; Boolean modComments; Boolean modBinaryII; Boolean modConvertText; Boolean modConvertAll; Boolean modOverwriteExisting; Boolean modAddAsDisk; Boolean modPreserveType; Boolean modPreserveTypeExtended; const char* archiveFilename; char* const* filespecPointer; long filespecCount; } NulibState; NuError NState_Init(NulibState** ppState); NuError NState_ExtraInit(NulibState* pState); void NState_Free(NulibState* pState); #ifdef DEBUG_MSGS void NState_DebugDump(const NulibState* pState); #endif char NState_GetSystemPathSeparator(const NulibState* pState); char NState_GetAltSystemPathSeparator(const NulibState* pState); const char* NState_GetProgramVersion(const NulibState* pState); NuArchive* NState_GetNuArchive(const NulibState* pState); void NState_SetNuArchive(NulibState* pState, NuArchive* pArchive); Boolean NState_GetSuppressOutput(const NulibState* pState); void NState_SetSuppressOutput(NulibState* pState, Boolean doSuppress); Boolean NState_GetInputUnavailable(const NulibState* pState); void NState_SetInputUnavailable(NulibState* pState, Boolean isUnavailable); NuRecordIdx NState_GetRenameFromIdx(const NulibState* pState); void NState_SetRenameFromIdx(NulibState* pState, NuRecordIdx recordIdx); char* NState_GetRenameToStr(const NulibState* pState); void NState_SetRenameToStr(NulibState* pState, char* str); NuDataSink* NState_GetPipeSink(const NulibState* pState); NuDataSink* NState_GetCommentSink(const NulibState* pState); long NState_GetMatchCount(const NulibState* pState); void NState_SetMatchCount(NulibState* pState, long count); void NState_IncMatchCount(NulibState* pState); void NState_AddToTotals(NulibState* pState, long len, long compLen); void NState_GetTotals(NulibState* pState, long* pTotalLen, long* pTotalCompLen); long NState_GetTempPathnameLen(NulibState* pState); void NState_SetTempPathnameLen(NulibState* pState, long len); char* NState_GetTempPathnameBuf(NulibState* pState); Command NState_GetCommand(const NulibState* pState); void NState_SetCommand(NulibState* pState, Command cmd); const char* NState_GetArchiveFilename(const NulibState* pState); void NState_SetArchiveFilename(NulibState* pState, const char* archiveFilename); char* const* NState_GetFilespecPointer(const NulibState* pState); void NState_SetFilespecPointer(NulibState* pState, char* const* filespec); long NState_GetFilespecCount(const NulibState* pState); void NState_SetFilespecCount(NulibState* pState, long filespecCount); Boolean NState_GetModUpdate(const NulibState* pState); void NState_SetModUpdate(NulibState* pState, Boolean val); Boolean NState_GetModFreshen(const NulibState* pState); void NState_SetModFreshen(NulibState* pState, Boolean val); Boolean NState_GetModRecurse(const NulibState* pState); void NState_SetModRecurse(NulibState* pState, Boolean val); Boolean NState_GetModJunkPaths(const NulibState* pState); void NState_SetModJunkPaths(NulibState* pState, Boolean val); Boolean NState_GetModNoCompression(const NulibState* pState); void NState_SetModNoCompression(NulibState* pState, Boolean val); Boolean NState_GetModCompressDeflate(const NulibState* pState); void NState_SetModCompressDeflate(NulibState* pState, Boolean val); Boolean NState_GetModCompressBzip2(const NulibState* pState); void NState_SetModCompressBzip2(NulibState* pState, Boolean val); Boolean NState_GetModComments(const NulibState* pState); void NState_SetModComments(NulibState* pState, Boolean val); Boolean NState_GetModBinaryII(const NulibState* pState); void NState_SetModBinaryII(NulibState* pState, Boolean val); Boolean NState_GetModConvertText(const NulibState* pState); void NState_SetModConvertText(NulibState* pState, Boolean val); Boolean NState_GetModConvertAll(const NulibState* pState); void NState_SetModConvertAll(NulibState* pState, Boolean val); Boolean NState_GetModOverwriteExisting(const NulibState* pState); void NState_SetModOverwriteExisting(NulibState* pState, Boolean val); Boolean NState_GetModAddAsDisk(const NulibState* pState); void NState_SetModAddAsDisk(NulibState* pState, Boolean val); Boolean NState_GetModPreserveType(const NulibState* pState); void NState_SetModPreserveType(NulibState* pState, Boolean val); Boolean NState_GetModPreserveTypeExtended(const NulibState* pState); void NState_SetModPreserveTypeExtended(NulibState* pState, Boolean val); #endif /*NULIB2_STATE_H*/ nulib2-3.1.0/nulib2/SysDefs.h000066400000000000000000000105571316100516500156400ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * This was adapted from gzip's "tailor.h" and NuLib's "nudefs.h". */ #ifndef NULIB2_SYSDEFS_H #define NULIB2_SYSDEFS_H #ifdef HAVE_CONFIG_H # include #endif #ifdef DEBUG_VERBOSE # define DEBUG_MSGS #endif /* these should exist everywhere */ #include #include #include #include #include #include #include #include /* basic Win32 stuff -- info-zip has much more complete defs */ #if defined(_WIN32) || defined(MSDOS) # define WINDOWS_LIKE # ifndef HAVE_CONFIG_H # define HAVE_FCNTL_H # define HAVE_MALLOC_H # define HAVE_STDLIB_H # define HAVE_SYS_STAT_H # undef HAVE_SYS_TIME_H # define HAVE_SYS_TYPES_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # define HAVE_SYS_UTIME_H # define HAVE_WINDOWS_H # define HAVE_FDOPEN # undef HAVE_FTRUNCATE # define HAVE_MEMMOVE # undef HAVE_MKSTEMP # define HAVE_MKTIME # define HAVE_SNPRINTF # undef HAVE_STRCASECMP # undef HAVE_STRNCASECMP # define HAVE_STRERROR # define HAVE_STRTOUL # define HAVE_VSNPRINTF # define SNPRINTF_DECLARED # define VSNPRINTF_DECLARED # define SPRINTF_RETURNS_INT # define inline /*Visual C++6.0 can't inline ".c" files*/ # define mode_t int # endif # include # include # define FOPEN_WANTS_B # define HAVE_CHSIZE # if _MSC_VER < 1900 /* no snprintf until Visual Studio 2015 */ # define snprintf _snprintf # define vsnprintf _vsnprintf # endif #endif #ifdef HAVE_MALLOC_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #if defined(WINDOWS_LIKE) # ifndef F_OK # define F_OK 00 # endif # ifndef R_OK # define R_OK 04 # endif #endif #if defined(__unix__) || defined(__unix) || defined(__BEOS__) || \ defined(__hpux) || defined(_AIX) || defined(__APPLE__) # define UNIX_LIKE #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if defined(__OS2__) && !defined(OS2) # define OS2 #endif #if defined(OS2) && defined(MSDOS) /* MS C under OS/2 */ # undef MSDOS #endif /* this ought to get trimmed down */ #ifdef MSDOS # ifndef __GNUC__ # ifdef __TURBOC__ # define NO_OFF_T # ifdef __BORLANDC__ # define DIRENT # else # define NO_UTIME # endif # else /* MSC */ # define HAVE_SYS_UTIME_H # define NO_UTIME_H # endif # endif # define PATH_SEP '\\' # define PATH_SEP2 '/' # define PATH_SEP3 ':' # ifdef MAX_PATH # define MAX_PATH_LEN MAX_PATH # else # define MAX_PATH_LEN 128 # endif # define NO_MULTIPLE_DOTS # define MAX_EXT_CHARS 3 # define NO_CHOWN # define PROTO # ifndef HAVE_CONFIG_H # define STDC_HEADERS # endif # define NO_SIZE_CHECK # define SYSTEM_DEFAULT_EOL "\r\n" #endif #ifdef WIN32 /* Windows 95/98/NT */ # define HAVE_SYS_UTIME_H # define NO_UTIME_H # define PATH_SEP '\\' # define PATH_SEP2 '/' # define PATH_SEP3 ':' # ifdef MAX_PATH # define MAX_PATH_LEN MAX_PATH # else # define MAX_PATH_LEN 260 # endif # define PROTO # define STDC_HEADERS # define SYSTEM_DEFAULT_EOL "\r\n" #endif #ifdef MACOS # define PATH_SEP ':' # define NO_CHOWN # define NO_UTIME # define SYSTEM_DEFAULT_EOL "\r" #endif #if defined(__APPLE__) && defined(__MACH__) /* OS X */ # define MAC_LIKE # define UNIX_LIKE #endif /* not currently using filesystem resource forks */ //#if defined(__ORCAC__) || defined(MAC_LIKE) //# define HAS_RESOURCE_FORKS //#endif #if defined(APW) || defined(__ORCAC__) # define __appleiigs__ # pragma lint -1 # pragma memorymodel 1 # pragma optimize 7 /*# pragma debug 25 */ # define PATH_SEP ':' # define SYSTEM_DEFAULT_EOL "\r" # ifdef GNO # define HAS_DIRENT # endif #endif #ifdef __GNUC__ /* this was missing from BeOS __MWERKS__, and probably others */ # define HAS__FUNCTION__ #endif /* general defaults, mainly for UNIX */ #ifndef PATH_SEP # define PATH_SEP '/' #endif #ifndef SYSTEM_DEFAULT_EOL # define SYSTEM_DEFAULT_EOL "\n" #endif #ifndef MAX_PATH_LEN # define MAX_PATH_LEN 1024 #endif #endif /*NULIB2_SYSDEFS_H*/ nulib2-3.1.0/nulib2/SysUtils.c000066400000000000000000001154311316100516500160470ustar00rootroot00000000000000/* * NuLib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * * System-dependent utility functions. */ #include "NuLib2.h" #ifdef HAVE_WINDOWS_H # include #endif #ifdef MAC_LIKE # include #endif /* get a grip on this opendir/readdir stuff */ #if defined(UNIX_LIKE) # if defined(HAVE_DIRENT_H) # include # define DIR_NAME_LEN(dirent) ((int)strlen((dirent)->d_name)) typedef struct dirent DIR_TYPE; # elif defined(HAVE_SYS_DIR_H) # include # define DIR_NAME_LEN(direct) ((direct)->d_namlen) typedef struct direct DIR_TYPE; # elif defined(HAVE_NDIR_H) # include # define DIR_NAME_LEN(direct) ((direct)->d_namlen) typedef struct direct DIR_TYPE; # else # error "Port this?" # endif #endif /* * For systems (e.g. Visual C++ 6.0) that don't have these standard values. */ #ifndef S_IRUSR # define S_IRUSR 0400 # define S_IWUSR 0200 # define S_IXUSR 0100 # define S_IRWXU (S_IRUSR|S_IWUSR|S_IXUSR) # define S_IRGRP (S_IRUSR >> 3) # define S_IWGRP (S_IWUSR >> 3) # define S_IXGRP (S_IXUSR >> 3) # define S_IRWXG (S_IRWXU >> 3) # define S_IROTH (S_IRGRP >> 3) # define S_IWOTH (S_IWGRP >> 3) # define S_IXOTH (S_IXGRP >> 3) # define S_IRWXO (S_IRWXG >> 3) #endif #ifndef S_ISREG # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* * =========================================================================== * System-specific filename stuff * =========================================================================== */ // 20150103: this makes me nervous #define kTempFileNameLen 20 #if defined(UNIX_LIKE) /* * Filename normalization for typical UNIX filesystems. Only '/' is * forbidden. Maximum filename length is large enough that we might * as well just let the filesystem truncate if it gets too long, rather * than worry about truncating it cleverly. */ static NuError UNIXNormalizeFileName(NulibState* pState, const char* srcp, long srcLen, char fssep, char** pDstp, long dstLen) { char* dstp = *pDstp; while (srcLen--) { /* don't go until null found! */ Assert(*srcp != '\0'); if (*srcp == kForeignIndic) { /* change '%' to "%%" */ if (NState_GetModPreserveType(pState)) *dstp++ = *srcp; *dstp++ = *srcp++; } else if (*srcp == '/') { /* change '/' to "%2f" */ if (NState_GetModPreserveType(pState)) { *dstp++ = kForeignIndic; *dstp++ = HexConv(*srcp >> 4 & 0x0f); *dstp++ = HexConv(*srcp & 0x0f); } else { *dstp++ = '_'; } srcp++; } else { /* no need to fiddle with it */ *dstp++ = *srcp++; } } *dstp = '\0'; /* end the string, but don't advance past the null */ Assert(*pDstp - dstp <= dstLen); /* make sure we didn't overflow */ *pDstp = dstp; return kNuErrNone; } #elif defined(WINDOWS_LIKE) /* * You can't create files or directories with these names on a FAT filesystem, * because they're MS-DOS "device special files". So, we either prepend * a '_' (if we're not preserving filenames) or "%00" (if we are). The * "%00" sequence gets stripped off during denormalization. * * For some reason FAT is actually even more picky than that, insisting * that files like "CON.FOO.TXT" are also illegal. * * The list comes from the Linux kernel's fs/msdos/namei.c. */ static const char* fatReservedNames3[] = { "CON", "PRN", "NUL", "AUX", NULL }; static const char* fatReservedNames4[] = { "LPT1", "LPT2", "LPT3", "LPT4", "COM1", "COM2", "COM3", "COM4", NULL }; /* * Filename normalization for Win32 filesystems. You can't use [ \/:*?"<>| ]. */ static NuError Win32NormalizeFileName(NulibState* pState, const char* srcp, long srcLen, char fssep, char** pDstp, long dstLen) { char* dstp = *pDstp; const char* startp = srcp; static const char* kInvalid = "\\/:*?\"<>|"; /* look for a match on "aux" or "aux\..*" */ if (srcLen >= 3) { const char** ppcch; for (ppcch = fatReservedNames3; *ppcch != NULL; ppcch++) { if (strncasecmp(srcp, *ppcch, 3) == 0 && srcp[3] == '.' || srcLen == 3) { DBUG(("--- fixing '%s'\n", *ppcch)); if (NState_GetModPreserveType(pState)) { *dstp++ = kForeignIndic; *dstp++ = '0'; *dstp++ = '0'; } else *dstp++ = '_'; break; } } } if (srcLen >= 4) { const char** ppcch; for (ppcch = fatReservedNames4; *ppcch != NULL; ppcch++) { if (strncasecmp(srcp, *ppcch, 4) == 0 && srcp[4] == '.' || srcLen == 4) { DBUG(("--- fixing '%s'\n", *ppcch)); if (NState_GetModPreserveType(pState)) { *dstp++ = kForeignIndic; *dstp++ = '0'; *dstp++ = '0'; } else *dstp++ = '_'; break; } } } while (srcLen--) { /* don't go until null found! */ Assert(*srcp != '\0'); if (*srcp == kForeignIndic) { /* change '%' to "%%" */ if (NState_GetModPreserveType(pState)) *dstp++ = *srcp; *dstp++ = *srcp++; } else if (strchr(kInvalid, *srcp) != NULL) { /* change invalid char to "%2f" or '_' */ if (NState_GetModPreserveType(pState)) { *dstp++ = kForeignIndic; *dstp++ = HexConv(*srcp >> 4 & 0x0f); *dstp++ = HexConv(*srcp & 0x0f); } else { *dstp++ = '_'; } srcp++; } else { /* no need to fiddle with it */ *dstp++ = *srcp++; } } *dstp = '\0'; /* end the string, but don't advance past the null */ Assert(*pDstp - dstp <= dstLen); /* make sure we didn't overflow */ *pDstp = dstp; return kNuErrNone; } #endif /* * Normalize a file name to local filesystem conventions. The input * is quite possibly *NOT* null-terminated, since it may represent a * substring of a full pathname. Use "srcLen". * * The output filename is copied to *pDstp, which is advanced forward. * * The output buffer must be able to hold 3x the original string length. */ NuError NormalizeFileName(NulibState* pState, const char* srcp, long srcLen, char fssep, char** pDstp, long dstLen) { NuError err; Assert(srcp != NULL); Assert(srcLen > 0); Assert(dstLen > srcLen); Assert(pDstp != NULL); Assert(*pDstp != NULL); Assert(fssep > ' ' && fssep < 0x7f); #if defined(UNIX_LIKE) err = UNIXNormalizeFileName(pState, srcp, srcLen, fssep, pDstp, dstLen); #elif defined(WINDOWS_LIKE) err = Win32NormalizeFileName(pState, srcp, srcLen, fssep, pDstp, dstLen); #else #error "port this" #endif return err; } /* * Normalize a directory name to local filesystem conventions. */ NuError NormalizeDirectoryName(NulibState* pState, const char* srcp, long srcLen, char fssep, char** pDstp, long dstLen) { /* in general, directories and filenames are the same */ return NormalizeFileName(pState, srcp, srcLen, fssep, pDstp, dstLen); } /* * Given the archive filename and the file system separator, strip off the * archive filename and replace it with the name of a nonexistent file * in the same directory. * * Under UNIX we just need the file to be on the same filesystem, but * under GS/OS it has to be in the same directory. Not sure what Mac OS * or Windows requires, so it's safest to just put it in the same dir. */ char* MakeTempArchiveName(NulibState* pState) { const char* archivePathname; char fssep; const char* nameStart; char* newName = NULL; char* namePtr; char* resultName = NULL; long len; archivePathname = NState_GetArchiveFilename(pState); Assert(archivePathname != NULL); fssep = NState_GetSystemPathSeparator(pState); Assert(fssep != 0); /* we'll get confused if the archive pathname looks like "/foo/bar/" */ len = strlen(archivePathname); if (len < 1) goto bail; if (archivePathname[len-1] == fssep) { ReportError(kNuErrNone, "archive pathname can't end in '%c'", fssep); goto bail; } /* figure out where the filename ends */ nameStart = strrchr(archivePathname, fssep); if (nameStart == NULL) { /* nothing but a filename */ newName = Malloc(kTempFileNameLen +1); namePtr = newName; } else { nameStart++; /* advance past the fssep */ newName = Malloc((nameStart - archivePathname) + kTempFileNameLen +1); strcpy(newName, archivePathname); namePtr = newName + (nameStart - archivePathname); } if (newName == NULL) goto bail; /* * Create a new name with a mktemp-style template. */ strcpy(namePtr, "nulibtmpXXXXXX"); resultName = newName; bail: if (resultName == NULL) Free(newName); return resultName; } /* * =========================================================================== * Add a set of files * =========================================================================== */ /* * AddFile() and supporting functions. * * When adding one or more files, we need to add the file's attributes too, * including file type and access permissions. We may want to recurse * into subdirectories. * * Because UNIX and GS/OS have rather different schemes for scanning * directories, I'm defining the whole thing as system-dependent instead * of trying to put an OS-dependent callback inside an OS-independent * wrapper. The GS/OS directory scanning mechanism does everything stat() * does, plus picks up file types, so AddDirectory will want to pass a * lot more stuff into AddFile than the UNIX version. And the UNIX and * Windows versions need to make filetype assumptions based on filename * extensions. * * We could force GS/OS to do an opendir/readdir/stat sort of thing, and * pass around some file type info that doesn't really get set under * UNIX or Windows, but that would be slower and more clumsy. */ #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) /* * Check a file's status. * * [ Someday we may want to modify this to handle symbolic links. ] */ NuError CheckFileStatus(const char* pathname, struct stat* psb, Boolean* pExists, Boolean* pIsReadable, Boolean* pIsDir) { NuError err = kNuErrNone; int cc; Assert(pathname != NULL); Assert(pExists != NULL); Assert(pIsReadable != NULL); Assert(pIsDir != NULL); *pExists = true; *pIsReadable = true; *pIsDir = false; cc = stat(pathname, psb); if (cc) { if (errno == ENOENT) *pExists = false; else err = kNuErrFileStat; goto bail; } if (S_ISDIR(psb->st_mode)) *pIsDir = true; /* * Test if we can read this file. How do we do that? The easy but slow * way is to call access(2), the harder way is to figure out * what user/group we are and compare the appropriate file mode. */ if (access(pathname, R_OK) < 0) *pIsReadable = false; bail: return err; } #endif #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) /* * Convert from time in seconds to DateTime format. */ static void UNIXTimeToDateTime(const time_t* pWhen, NuDateTime *pDateTime) { struct tm* ptm; Assert(pWhen != NULL); Assert(pDateTime != NULL); ptm = localtime(pWhen); pDateTime->second = ptm->tm_sec; pDateTime->minute = ptm->tm_min; pDateTime->hour = ptm->tm_hour; pDateTime->day = ptm->tm_mday -1; pDateTime->month = ptm->tm_mon; pDateTime->year = ptm->tm_year; pDateTime->extra = 0; pDateTime->weekDay = ptm->tm_wday +1; } #endif #if defined(MAC_LIKE) /* * Due to historical reasons, the XATTR_FINDERINFO_NAME (defined to be * ``com.apple.FinderInfo'') extended attribute must be 32 bytes; see the * ATTR_CMN_FNDRINFO section in getattrlist(2). * * The FinderInfo block is the concatenation of a FileInfo structure * and an ExtendedFileInfo (or ExtendedFolderInfo) structure -- see * ATTR_CMN_FNDRINFO in getattrlist(2). * * All we're really interested in is the file type and creator code, * which are stored big-endian in the first 8 bytes. */ static const int kFinderInfoSize = 32; /* * Obtains the creator and file type from the Finder info block, if any, * and converts the types to ProDOS equivalents. * * If the attribute doesn't exist, this returns an error without modifying * the output args. */ static NuError GetTypesFromFinder(const char* pathnameUNI, uint32_t* pFileType, uint32_t* pAuxType) { uint8_t fiBuf[kFinderInfoSize]; size_t actual = getxattr(pathnameUNI, XATTR_FINDERINFO_NAME, fiBuf, sizeof(fiBuf), 0, 0); if (actual != kFinderInfoSize) { return kNuErrNotFound; } uint32_t fileType, creator; fileType = (fiBuf[0] << 24) | (fiBuf[1] << 16) | (fiBuf[2] << 8) | fiBuf[3]; creator = (fiBuf[4] << 24) | (fiBuf[5] << 16) | (fiBuf[6] << 8) | fiBuf[7]; Boolean found = false; uint8_t proType; uint16_t proAux; /* * Convert to ProDOS file/aux type. */ if (creator == 'pdos') { /* * TODO: handle conversion from 'pdos'/'XY ' to $XY/$0000. * I think this conversion was deprecated and not widely used; * the inability to retain the aux type renders it inapplicable * to many files. */ if (fileType == 'PSYS') { proType = 0xFF; // SYS proAux = 0x0000; found = true; } else if (fileType == 'PS16') { proType = 0xB3; // S16 proAux = 0x0000; found = true; } else { if (((fileType >> 24) & 0xFF) == 'p') { proType = (fileType >> 16) & 0xFF; proAux = (uint16_t) fileType; found = true; } } } else if (creator == 'dCpy') { if (fileType == 'dImg') { proType = 0xE0; // LBR proAux = 0x0005; found = true; } } if (!found) { switch (fileType) { case 'BINA': proType = 0x06; // BIN proAux = 0x0000; break; case 'TEXT': proType = 0x04; // TXT proAux = 0x0000; break; case 'MIDI': proType = 0xD7; // MDI proAux = 0x0000; break; case 'AIFF': proType = 0xD8; // SND proAux = 0x0000; break; case 'AIFC': proType = 0xD8; // SND proAux = 0x0001; break; default: proType = 0x00; // NON proAux = 0x0000; break; } } *pFileType = proType; *pAuxType = proAux; return kNuErrNone; } /* * Set the file type and creator type, based on the ProDOS file type * and aux type. * * This is a clone of the function in NufxLib; it exists for the * benefit of the Binary ][ code. */ NuError SetFinderInfo(int fd, uint8_t proType, uint16_t proAux) { uint8_t fiBuf[kFinderInfoSize]; size_t actual = fgetxattr(fd, XATTR_FINDERINFO_NAME, fiBuf, sizeof(fiBuf), 0, 0); if (actual == (size_t) -1 && errno == ENOATTR) { // doesn't yet have Finder info memset(fiBuf, 0, sizeof(fiBuf)); } else if (actual != kFinderInfoSize) { return kNuErrFile; } /* * Attempt to use one of the convenience types. If nothing matches, * use the generic pdos/pXYZ approach. Note that PSYS/PS16 will * lose the file's aux type. * * I'm told this is from page 336 of _Programmer's Reference for * System 6.0_. */ uint8_t* fileTypeBuf = fiBuf; uint8_t* creatorBuf = fiBuf + 4; memcpy(creatorBuf, "pdos", 4); if (proType == 0x00 && proAux == 0x0000) { memcpy(fileTypeBuf, "BINA", 4); } else if (proType == 0x04 && proAux == 0x0000) { memcpy(fileTypeBuf, "TEXT", 4); } else if (proType == 0xff) { memcpy(fileTypeBuf, "PSYS", 4); } else if (proType == 0xb3 && (proAux & 0xff00) != 0xdb00) { memcpy(fileTypeBuf, "PS16", 4); } else if (proType == 0xd7 && proAux == 0x0000) { memcpy(fileTypeBuf, "MIDI", 4); } else if (proType == 0xd8 && proAux == 0x0000) { memcpy(fileTypeBuf, "AIFF", 4); } else if (proType == 0xd8 && proAux == 0x0001) { memcpy(fileTypeBuf, "AIFC", 4); } else if (proType == 0xe0 && proAux == 0x0005) { memcpy(creatorBuf, "dCpy", 4); memcpy(fileTypeBuf, "dImg", 4); } else { fileTypeBuf[0] = 'p'; fileTypeBuf[1] = proType; fileTypeBuf[2] = (uint8_t) (proAux >> 8); fileTypeBuf[3] = (uint8_t) proAux; } if (fsetxattr(fd, XATTR_FINDERINFO_NAME, fiBuf, sizeof(fiBuf), 0, 0) != 0) { return kNuErrFile; } return kNuErrNone; } #endif /*MAC_LIKE*/ #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) /* * Replace "oldc" with "newc". If we find an instance of "newc" already * in the string, replace it with "newSubst". */ static void ReplaceFssep(char* str, char oldc, char newc, char newSubst) { while (*str != '\0') { if (*str == oldc) *str = newc; else if (*str == newc) *str = newSubst; str++; } } /* * Set the contents of a NuFileDetails structure, based on the pathname * and characteristics of the file. */ static NuError GetFileDetails(NulibState* pState, const char* pathnameMOR, struct stat* psb, NuFileDetails* pDetails) { Boolean wasPreserved; Boolean doJunk = false; Boolean adjusted; char* livePathStr; char slashDotDotSlash[5] = "_.._"; time_t now; Assert(pState != NULL); Assert(pathnameMOR != NULL); Assert(pDetails != NULL); /* set up the pathname buffer; note pDetails->storageName is const */ NState_SetTempPathnameLen(pState, strlen(pathnameMOR) +1); livePathStr = NState_GetTempPathnameBuf(pState); Assert(livePathStr != NULL); strcpy(livePathStr, pathnameMOR); /* under Win32, both '/' and '\' work... we want to settle on one */ if (NState_GetAltSystemPathSeparator(pState) != '\0') { ReplaceFssep(livePathStr, NState_GetAltSystemPathSeparator(pState), NState_GetSystemPathSeparator(pState), NState_GetSystemPathSeparator(pState)); } /* init to defaults */ memset(pDetails, 0, sizeof(*pDetails)); pDetails->threadID = kNuThreadIDDataFork; pDetails->storageNameMOR = livePathStr; /* point at temp buffer */ pDetails->origName = NULL; pDetails->fileSysID = kNuFileSysUnknown; pDetails->fileSysInfo = kStorageFssep; pDetails->fileType = 0; pDetails->extraType = 0; pDetails->storageType = kNuStorageUnknown; /* let NufxLib worry about it */ if (psb->st_mode & S_IWUSR) pDetails->access = kNuAccessUnlocked; else pDetails->access = kNuAccessLocked; /* if this is a disk image, fill in disk-specific fields */ if (NState_GetModAddAsDisk(pState)) { if ((psb->st_size & 0x1ff) != 0) { /* reject anything whose size isn't a multiple of 512 bytes */ printf("NOT storing odd-sized (%ld) file as disk image: %s\n", (long)psb->st_size, livePathStr); } else { /* set fields; note the "preserve" stuff will override this */ pDetails->threadID = kNuThreadIDDiskImage; pDetails->storageType = 512; pDetails->extraType = psb->st_size / 512; } } now = time(NULL); UNIXTimeToDateTime(&now, &pDetails->archiveWhen); UNIXTimeToDateTime(&psb->st_mtime, &pDetails->modWhen); UNIXTimeToDateTime(&psb->st_mtime, &pDetails->createWhen); #ifdef MAC_LIKE /* * Retrieve the file/aux type from the Finder info. We want the * type-preservation string to take priority, so get this first. */ (void) GetTypesFromFinder(livePathStr, &pDetails->fileType, &pDetails->extraType); #endif /* * Check for file type preservation info in the filename. If present, * set the file type values and truncate the filename. */ wasPreserved = false; if (NState_GetModPreserveType(pState)) { wasPreserved = ExtractPreservationString(pState, livePathStr, &pDetails->fileType, &pDetails->extraType, &pDetails->threadID); } /* * Do a "denormalization" pass, where we convert invalid chars (such * as '/') from percent-codes back to 8-bit characters. The filename * will always be the same size or smaller, so we can do it in place. */ if (wasPreserved) DenormalizePath(pState, livePathStr); /* * If we're in "extended" mode, and the file wasn't preserved, take a * guess at what the file type should be based on the file extension. */ if (!wasPreserved && NState_GetModPreserveTypeExtended(pState)) { InterpretExtension(pState, livePathStr, &pDetails->fileType, &pDetails->extraType); } /* * Strip bad chars off the front of the pathname. Every time we * remove one thing we potentially expose another, so we have to * loop until it's sanitized. * * The outer loop isn't really necessary under Win32, because you'd * need to do something like ".\\foo", which isn't allowed. UNIX * silently allows ".//foo", so this is a problem there. (We could * probably do away with the inner loops, but those were already * written when I saw the larger problem.) */ do { adjusted = false; /* * Check for other unpleasantness, such as a leading fssep. */ Assert(NState_GetSystemPathSeparator(pState) != '\0'); while (livePathStr[0] == NState_GetSystemPathSeparator(pState)) { /* slide it down, len is (strlen +1), -1 (dropping first char)*/ memmove(livePathStr, livePathStr+1, strlen(livePathStr)); adjusted = true; } /* * Remove leading "./". */ while (livePathStr[0] == '.' && livePathStr[1] == NState_GetSystemPathSeparator(pState)) { /* slide it down, len is (strlen +1) -2 (dropping two chars) */ memmove(livePathStr, livePathStr+2, strlen(livePathStr)-1); adjusted = true; } } while (adjusted); /* * If there's a "/../" present anywhere in the name, junk everything * but the filename. * * This won't catch "foo/bar/..", but that should've been caught as * a directory anyway. */ slashDotDotSlash[0] = NState_GetSystemPathSeparator(pState); slashDotDotSlash[3] = NState_GetSystemPathSeparator(pState); if ((livePathStr[0] == '.' && livePathStr[1] == '.') || (strstr(livePathStr, slashDotDotSlash) != NULL)) { DBUG(("Found dot dot in '%s', keeping only filename\n", livePathStr)); doJunk = true; } /* * Scan for and remove "/./" and trailing "/.". They're filesystem * no-ops that work just fine under Win32 and UNIX but could confuse * a IIgs. (Of course, the user could just omit them from the pathname.) */ /* TO DO 20030208 */ /* * If "junk paths" is set, drop everything before the last fssep char. */ if (NState_GetModJunkPaths(pState) || doJunk) { char* lastFssep; lastFssep = strrchr(livePathStr, NState_GetSystemPathSeparator(pState)); if (lastFssep != NULL) { Assert(*(lastFssep+1) != '\0'); /* should already have been caught*/ memmove(livePathStr, lastFssep+1, strlen(lastFssep+1)+1); } } /* * Finally, substitute our generally-accepted path separator in place of * the local one, stomping on anything with a ':' in it as we do. The * goal is to avoid having "subdir:foo/bar" turn into "subdir/foo/bar". * Were we a general-purpose archiver, this might be a mistake, but * we're not. NuFX doesn't really give us a choice. */ ReplaceFssep(livePathStr, NState_GetSystemPathSeparator(pState), kStorageFssep, 'X'); /*bail:*/ return kNuErrNone; } #endif /* * Do the system-independent part of the file add, including things like * adding comments. */ static NuError DoAddFile(NulibState* pState, NuArchive* pArchive, const char* pathname, const NuFileDetails* pDetails) { NuError err; NuRecordIdx recordIdx = 0; err = NuAddFile(pArchive, pathname, pDetails, false, &recordIdx); if (err == kNuErrNone) { NState_IncMatchCount(pState); } else if (err == kNuErrSkipped) { /* "maybe overwrite" UI causes this if user declines */ err = kNuErrNone; goto bail; } else if (err == kNuErrNotNewer) { /* if we were expecting this, it's okay */ if (NState_GetModFreshen(pState) || NState_GetModUpdate(pState)) { printf("SKIP older file: %s\n", pathname); err = kNuErrNone; goto bail; } } else if (err == kNuErrDuplicateNotFound) { /* if we were expecting this, it's okay */ if (NState_GetModFreshen(pState)) { printf("SKIP file not in archive: %s\n", pathname); err = kNuErrNone; goto bail; } } else if (err == kNuErrRecordExists) { printf("FAIL same filename added twice: '%s'\n", NState_GetTempPathnameBuf(pState)); goto bail_quiet; } if (err != kNuErrNone) goto bail; /* add a one-line comment if requested */ if (NState_GetModComments(pState)) { char* comment; DBUG(("Preparing comment for recordIdx=%ld\n", recordIdx)); Assert(recordIdx != 0); comment = GetSimpleComment(pState, pathname, kDefaultCommentLen); if (comment != NULL) { NuDataSource* pDataSource; err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, kDefaultCommentLen, (uint8_t*)comment, 0, strlen(comment), FreeCallback, &pDataSource); if (err != kNuErrNone) { ReportError(err, "comment buffer create failed"); Free(comment); err = kNuErrNone; /* oh well */ } else { comment = NULL; /* now owned by the data source */ err = NuAddThread(pArchive, recordIdx, kNuThreadIDComment, pDataSource, NULL); if (err != kNuErrNone) { ReportError(err, "comment thread add failed"); NuFreeDataSource(pDataSource); err = kNuErrNone; /* oh well */ } else { pDataSource = NULL; /* now owned by NufxLib */ } } } } bail: if (err != kNuErrNone) ReportError(err, "unable to add file"); bail_quiet: return err; } #if defined(UNIX_LIKE) /* ---- UNIX --------------------------------------- */ static NuError UNIXAddFile(NulibState* pState, NuArchive* pArchive, const char* pathname); /* * UNIX-style recursive directory descent. Scan the contents of a directory. * If a subdirectory is found, follow it; otherwise, call UNIXAddFile to * add the file. */ static NuError UNIXAddDirectory(NulibState* pState, NuArchive* pArchive, const char* dirName) { NuError err = kNuErrNone; DIR* dirp = NULL; DIR_TYPE* entry; char nbuf[MAX_PATH_LEN]; /* malloc might be better; this soaks stack */ char fssep; int len; Assert(pState != NULL); Assert(pArchive != NULL); Assert(dirName != NULL); DBUG(("+++ DESCEND: '%s'\n", dirName)); dirp = opendir(dirName); if (dirp == NULL) { if (errno == ENOTDIR) err = kNuErrNotDir; else err = errno ? errno : kNuErrOpenDir; ReportError(err, "failed on '%s'", dirName); goto bail; } fssep = NState_GetSystemPathSeparator(pState); /* could use readdir_r, but we don't care about reentrancy here */ while ((entry = readdir(dirp)) != NULL) { /* skip the dotsies */ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; len = strlen(dirName); if (len + DIR_NAME_LEN(entry) +2 > MAX_PATH_LEN) { err = kNuErrInternal; ReportError(err, "Filename exceeds %d bytes: %s%c%s", MAX_PATH_LEN, dirName, fssep, entry->d_name); goto bail; } /* form the new name, inserting an fssep if needed */ strcpy(nbuf, dirName); if (dirName[len-1] != fssep) nbuf[len++] = fssep; strcpy(nbuf+len, entry->d_name); err = UNIXAddFile(pState, pArchive, nbuf); if (err != kNuErrNone) goto bail; } bail: if (dirp != NULL) (void)closedir(dirp); return err; } /* * Add a file to the list we're adding to the archive. * * If the file is a directory, and we allow recursing into subdirectories, * this calls UNIXAddDirectory. If we don't allow recursion, this just * returns without an error. * * Returns with an error if the file doesn't exist or isn't readable. */ static NuError UNIXAddFile(NulibState* pState, NuArchive* pArchive, const char* pathname) { NuError err = kNuErrNone; Boolean exists, isDir, isReadable; NuFileDetails details; struct stat sb; Assert(pState != NULL); Assert(pArchive != NULL); Assert(pathname != NULL); err = CheckFileStatus(pathname, &sb, &exists, &isReadable, &isDir); if (err != kNuErrNone) { ReportError(err, "unexpected error while examining '%s'", pathname); goto bail; } if (!exists) { err = kNuErrFileNotFound; ReportError(err, "couldn't find '%s'", pathname); goto bail; } if (!isReadable) { ReportError(kNuErrNone, "file '%s' isn't readable", pathname); err = kNuErrFileNotReadable; goto bail; } if (isDir) { if (NState_GetModRecurse(pState)) err = UNIXAddDirectory(pState, pArchive, pathname); goto bail_quiet; } /* * We've found a file that we want to add. We need to decide what * filetype and auxtype it has, and whether or not it's actually the * resource fork of another file. */ DBUG(("+++ ADD '%s'\n", pathname)); err = GetFileDetails(pState, pathname, &sb, &details); if (err != kNuErrNone) goto bail; err = DoAddFile(pState, pArchive, pathname, &details); if (err != kNuErrNone) goto bail_quiet; bail: if (err != kNuErrNone) ReportError(err, "unable to add file"); bail_quiet: return err; } #elif defined(WINDOWS_LIKE) /* ---- Windows -------------------------------- */ /* * Directory structure and functions, based on zDIR in Info-Zip sources. */ typedef struct Win32dirent { char d_attr; char d_name[MAX_PATH_LEN]; int d_first; HANDLE d_hFindFile; } Win32dirent; static const char* kWildMatchAll = "*.*"; /* * Prepare a directory for reading. */ static Win32dirent* OpenDir(const char* name) { Win32dirent* dir = NULL; char* tmpStr = NULL; char* cp; WIN32_FIND_DATA fnd; dir = Malloc(sizeof(*dir)); tmpStr = Malloc(strlen(name) + (2 + sizeof(kWildMatchAll))); if (dir == NULL || tmpStr == NULL) goto failed; strcpy(tmpStr, name); cp = tmpStr + strlen(tmpStr); /* don't end in a colon (e.g. "C:") */ if ((cp - tmpStr) > 0 && strrchr(tmpStr, ':') == (cp - 1)) *cp++ = '.'; /* must end in a slash */ if ((cp - tmpStr) > 0 && strrchr(tmpStr, PATH_SEP) != (cp - 1)) *cp++ = PATH_SEP; strcpy(cp, kWildMatchAll); dir->d_hFindFile = FindFirstFile(tmpStr, &fnd); if (dir->d_hFindFile == INVALID_HANDLE_VALUE) goto failed; strcpy(dir->d_name, fnd.cFileName); dir->d_attr = (uint8_t) fnd.dwFileAttributes; dir->d_first = 1; bail: Free(tmpStr); return dir; failed: Free(dir); dir = NULL; goto bail; } /* * Get an entry from an open directory. * * Returns a NULL pointer after the last entry has been read. */ static Win32dirent* ReadDir(Win32dirent* dir) { if (dir->d_first) dir->d_first = 0; else { WIN32_FIND_DATA fnd; if (!FindNextFile(dir->d_hFindFile, &fnd)) return NULL; strcpy(dir->d_name, fnd.cFileName); dir->d_attr = (uint8_t) fnd.dwFileAttributes; } return dir; } /* * Close a directory. */ static void CloseDir(Win32dirent* dir) { if (dir == NULL) return; FindClose(dir->d_hFindFile); Free(dir); } /* might as well blend in with the UNIX version */ #define DIR_NAME_LEN(dirent) ((int)strlen((dirent)->d_name)) static NuError Win32AddFile(NulibState* pState, NuArchive* pArchive, const char* pathname); /* * Win32 recursive directory descent. Scan the contents of a directory. * If a subdirectory is found, follow it; otherwise, call Win32AddFile to * add the file. */ static NuError Win32AddDirectory(NulibState* pState, NuArchive* pArchive, const char* dirName) { NuError err = kNuErrNone; Win32dirent* dirp = NULL; Win32dirent* entry; char nbuf[MAX_PATH_LEN]; /* malloc might be better; this soaks stack */ char fssep; int len; Assert(pState != NULL); Assert(pArchive != NULL); Assert(dirName != NULL); DBUG(("+++ DESCEND: '%s'\n", dirName)); dirp = OpenDir(dirName); if (dirp == NULL) { if (errno == ENOTDIR) err = kNuErrNotDir; else err = errno ? errno : kNuErrOpenDir; ReportError(err, "failed on '%s'", dirName); goto bail; } fssep = NState_GetSystemPathSeparator(pState); /* could use readdir_r, but we don't care about reentrancy here */ while ((entry = ReadDir(dirp)) != NULL) { /* skip the dotsies */ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; len = strlen(dirName); if (len + DIR_NAME_LEN(entry) +2 > MAX_PATH_LEN) { err = kNuErrInternal; ReportError(err, "Filename exceeds %d bytes: %s%c%s", MAX_PATH_LEN, dirName, fssep, entry->d_name); goto bail; } /* form the new name, inserting an fssep if needed */ strcpy(nbuf, dirName); if (dirName[len-1] != fssep) nbuf[len++] = fssep; strcpy(nbuf+len, entry->d_name); err = Win32AddFile(pState, pArchive, nbuf); if (err != kNuErrNone) goto bail; } bail: if (dirp != NULL) (void)CloseDir(dirp); return err; } /* * Add a file to the list we're adding to the archive. If it's a directory, * and the recursive descent feature is enabled, call Win32AddDirectory to * add the contents of the dir. * * Returns with an error if the file doesn't exist or isn't readable. */ static NuError Win32AddFile(NulibState* pState, NuArchive* pArchive, const char* pathname) { NuError err = kNuErrNone; Boolean exists, isDir, isReadable; NuFileDetails details; struct stat sb; Assert(pState != NULL); Assert(pArchive != NULL); Assert(pathname != NULL); err = CheckFileStatus(pathname, &sb, &exists, &isReadable, &isDir); if (err != kNuErrNone) { ReportError(err, "unexpected error while examining '%s'", pathname); goto bail; } if (!exists) { err = kNuErrFileNotFound; ReportError(err, "couldn't find '%s'", pathname); goto bail; } if (!isReadable) { ReportError(kNuErrNone, "file '%s' isn't readable", pathname); err = kNuErrFileNotReadable; goto bail; } if (isDir) { if (NState_GetModRecurse(pState)) err = Win32AddDirectory(pState, pArchive, pathname); goto bail_quiet; } /* * We've found a file that we want to add. We need to decide what * filetype and auxtype it has, and whether or not it's actually the * resource fork of another file. */ DBUG(("+++ ADD '%s'\n", pathname)); err = GetFileDetails(pState, pathname, &sb, &details); if (err != kNuErrNone) goto bail; err = DoAddFile(pState, pArchive, pathname, &details); if (err != kNuErrNone) goto bail_quiet; bail: if (err != kNuErrNone) ReportError(err, "unable to add file"); bail_quiet: return err; } #else /* ---- unknown ----------------------------------------------------- */ # error "Port this (AddFile/AddDirectory)" #endif /* * External entry point; just calls the system-specific version. * * [ I figure the GS/OS version will want to pass a copy of the file * info from the GSOSAddDirectory function back into GSOSAddFile, so we'd * want to call it from here with a NULL pointer indicating that we * don't yet have the file info. That way we can get the file info * from the directory read call and won't have to check it again in * GSOSAddFile. ] */ NuError AddFile(NulibState* pState, NuArchive* pArchive, const char* pathname) { #if defined(UNIX_LIKE) return UNIXAddFile(pState, pArchive, pathname); #elif defined(WINDOWS_LIKE) return Win32AddFile(pState, pArchive, pathname); #else #error "Port this" #endif } /* * Invoke the system-dependent directory creation function. * * Currently only used by Binary2.c. */ NuError Mkdir(const char* dir) { NuError err = kNuErrNone; Assert(dir != NULL); #if defined(UNIX_LIKE) if (mkdir(dir, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH) < 0) { err = errno ? errno : kNuErrDirCreate; goto bail; } #elif defined(WINDOWS_LIKE) if (mkdir(dir) < 0) { err = errno ? errno : kNuErrDirCreate; goto bail; } #else #error "Port this" #endif bail: return err; } /* * Test for the existence of a file. * * Currently only used by Binary2.c. */ NuError TestFileExistence(const char* fileName, Boolean* pIsDir) { NuError err = kNuErrNone; Assert(fileName != NULL); Assert(pIsDir != NULL); #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) { struct stat sbuf; int cc; cc = stat(fileName, &sbuf); if (cc) { if (errno == ENOENT) err = kNuErrFileNotFound; else err = kNuErrFileStat; goto bail; } if (S_ISDIR(sbuf.st_mode)) *pIsDir = true; else *pIsDir = false; } #else #error "Port this" #endif bail: return err; } nulib2-3.1.0/nulib2/config.guess000066400000000000000000001247531316100516500164300ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-08-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in *86) UNAME_PROCESSOR=i686 ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nulib2-3.1.0/nulib2/config.h.in000066400000000000000000000053001316100516500161200ustar00rootroot00000000000000/* * Nulib2 * Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. * This is free software; you can redistribute it and/or modify it under the * terms of the BSD License, see the file COPYING. * */ /* config.h.in. Generated automatically from configure.in by autoheader. */ /* Define to empty if the keyword does not work. */ #undef const /* Define if utime(file, NULL) sets file's timestamp to the present. */ #undef HAVE_UTIME_NULL /* Define to `int' if doesn't define. */ #undef mode_t /* Define to `long' if doesn't define. */ #undef off_t /* Define if the setvbuf function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ #undef SETVBUF_REVERSED /* Define to `unsigned' if doesn't define. */ #undef size_t /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if your declares struct tm. */ #undef TM_IN_SYS_TIME /* Define to `int' if doesn't define. */ #undef mode_t /* Define to `long' if doesn't define. */ #undef off_t /* Define to `unsigned' if doesn't define. */ #undef size_t /* Define if you have the memmove function. */ #undef HAVE_MEMMOVE /* Define if you have the mkdir function. */ #undef HAVE_MKDIR /* Define if you have the strcasecmp function. */ #undef HAVE_STRCASECMP /* Define if you have the strncasecmp function. */ #undef HAVE_STRNCASECMP /* Define if you have the strerror function. */ #undef HAVE_STRERROR /* Define if you have the strtoul function. */ #undef HAVE_STRTOUL /* Define if you have the header file. */ #undef HAVE_DIRENT_H /* Define if you have the header file. */ #undef HAVE_FCNTL_H /* Define if you have the header file. */ #undef HAVE_LIMITS_H /* Define if you have the header file. */ #undef HAVE_MALLOC_H /* Define if you have the header file. */ #undef HAVE_STDLIB_H /* Define if you have the header file. */ #undef HAVE_NDIR_H /* Define if you have the header file. */ #undef HAVE_STRINGS_H /* Define if you have the header file. */ #undef HAVE_SYS_DIR_H /* Define if you have the header file. */ #undef HAVE_SYS_NDIR_H /* Define if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define if you have the header file. */ #undef HAVE_UNISTD_H /* Define if we want to use the dmalloc library (--enable-dmalloc). */ #undef USE_DMALLOC nulib2-3.1.0/nulib2/config.sub000066400000000000000000000757771316100516500161060ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-07-08' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | ms1 \ | msp430 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m32c) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | ms1-* \ | msp430-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; m32c-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nulib2-3.1.0/nulib2/configure000077500000000000000000004611321316100516500160150ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="Main.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_list= ac_subst_vars='LTLIBOBJS LIBOBJS BUILD_FLAGS EGREP GREP CPP INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_deflate enable_bzip2 enable_dmalloc ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-deflate don't link against libz --enable-bzip2 do link against libbz2 --enable-dmalloc do dmalloc stuff Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_list " utime.h" # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in fcntl.h limits.h malloc.h stdlib.h strings.h sys/stat.h \ sys/time.h sys/types.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done LIBS="" # Check whether --enable-deflate was given. if test "${enable_deflate+set}" = set; then : enableval=$enable_deflate; else enable_deflate=yes fi if test $enable_deflate = "yes"; then got_zlibh=false { $as_echo "$as_me:${as_lineno-$LINENO}: checking for deflate in -lz" >&5 $as_echo_n "checking for deflate in -lz... " >&6; } if ${ac_cv_lib_z_deflate+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char deflate (); int main () { return deflate (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_deflate=yes else ac_cv_lib_z_deflate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_deflate" >&5 $as_echo "$ac_cv_lib_z_deflate" >&6; } if test "x$ac_cv_lib_z_deflate" = xyes; then : got_libz=true else got_libz=false fi if $got_libz; then ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : got_zlibh=true LIBS="$LIBS -lz" fi fi if $got_zlibh; then echo " (found libz and zlib.h, enabling deflate)" $as_echo "#define ENABLE_DEFLATE 1" >>confdefs.h else echo " (couldn't find libz and zlib.h, not enabling deflate)" fi fi # Check whether --enable-bzip2 was given. if test "${enable_bzip2+set}" = set; then : enableval=$enable_bzip2; else enable_bzip2=no fi if test $enable_bzip2 = "yes"; then got_bzlibh=false { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BZ2_bzCompress in -lbz2" >&5 $as_echo_n "checking for BZ2_bzCompress in -lbz2... " >&6; } if ${ac_cv_lib_bz2_BZ2_bzCompress+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbz2 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char BZ2_bzCompress (); int main () { return BZ2_bzCompress (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bz2_BZ2_bzCompress=yes else ac_cv_lib_bz2_BZ2_bzCompress=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 $as_echo "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes; then : got_libbz=true else got_libbz=false fi if $got_libbz; then ac_fn_c_check_header_mongrel "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" if test "x$ac_cv_header_bzlib_h" = xyes; then : got_bzlibh=true LIBS="$LIBS -lbz2" fi fi if $got_bzlibh; then echo " (found libbz2 and bzlib.h, enabling bzip2)" $as_echo "#define ENABLE_BZIP2 1" >>confdefs.h else echo " (couldn't find libbz2 and bzlib.h, not enabling bzip2)" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define mode_t int _ACEOF fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi for ac_header in $ac_header_list do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether utime accepts a null argument" >&5 $as_echo_n "checking whether utime accepts a null argument... " >&6; } if ${ac_cv_func_utime_null+:} false; then : $as_echo_n "(cached) " >&6 else rm -f conftest.data; >conftest.data # Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. if test "$cross_compiling" = yes; then : ac_cv_func_utime_null='guessing yes' else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifdef HAVE_UTIME_H # include #endif int main () { struct stat s, t; return ! (stat ("conftest.data", &s) == 0 && utime ("conftest.data", 0) == 0 && stat ("conftest.data", &t) == 0 && t.st_mtime >= s.st_mtime && t.st_mtime - s.st_mtime < 120); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_utime_null=yes else ac_cv_func_utime_null=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_utime_null" >&5 $as_echo "$ac_cv_func_utime_null" >&6; } if test "x$ac_cv_func_utime_null" != xno; then ac_cv_func_utime_null=yes $as_echo "#define HAVE_UTIME_NULL 1" >>confdefs.h fi rm -f conftest.data for ac_func in memmove mkdir strtoul strcasecmp strncasecmp strerror do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test -z "$GCC"; then BUILD_FLAGS='$(OPT)' else BUILD_FLAGS='$(OPT) $(GCC_FLAGS)' fi if test "$host_os" = "beos"; then if test "$prefix" = "NONE" -a \ "$includedir" = '${prefix}/include' -a \ "$libdir" = '${exec_prefix}/lib' -a \ "$bindir" = '${exec_prefix}/bin' -a \ "$mandir" = '${prefix}/man' then echo replacing install locations with BeOS values prefix=/boot includedir='${prefix}/develop/headers' libdir='${exec_prefix}/home/config/lib' bindir='${exec_prefix}/home/config/bin' mandir='/tmp' fi fi if test "$host_cpu" = "powerpc" -a "$host_os" = "beos"; then CC=cc GCC= CFLAGS='-proc 603 -opt full' echo "forcing CC to \"$CC\" and CFLAGS to \"$CFLAGS\"" fi # Check whether --enable-dmalloc was given. if test "${enable_dmalloc+set}" = set; then : enableval=$enable_dmalloc; \ echo "--- enabling dmalloc"; LIBS="$LIBS -L/usr/local/lib -ldmalloc"; $as_echo "#define USE_DMALLOC 1" >>confdefs.h fi ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi nulib2-3.1.0/nulib2/configure.in000066400000000000000000000111111316100516500164030ustar00rootroot00000000000000dnl Nulib2 dnl Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved. dnl This is free software; you can redistribute it and/or modify it under the dnl terms of the BSD License, see the file COPYING. dnl dnl Process this file with autoconf to produce a configure script. AC_INIT(Main.c) AC_CONFIG_HEADER(config.h) dnl Checks for programs. AC_CANONICAL_HOST AC_PROG_CC AC_PROG_INSTALL dnl Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_CHECK_HEADERS(fcntl.h limits.h malloc.h stdlib.h strings.h sys/stat.h \ sys/time.h sys/types.h unistd.h) LIBS="" dnl dnl Check for libz and libbz2. We want to link against them in case dnl NufxLib has them enabled. If they're not enabled, we don't want to dnl link against them if they're shared libraries, because it'll create dnl an unnecessary shared lib dependency. Won't matter unless you try dnl to copy the binary to another machine. dnl dnl So, we try to link against the libraries unless they're explicitly dnl disabled by the person building them. Not ideal, but it'll work. dnl Of course, if nufxlib is built as a shared library, the dependencies dnl will be handled correctly without having to use -l here. dnl AC_ARG_ENABLE(deflate, [ --disable-deflate don't link against libz], [ ], [ enable_deflate=yes ]) if test $enable_deflate = "yes"; then dnl Check for zlib. Make sure it comes with zlib.h. dnl AC_CHECK_LIB(z, deflate, dnl AC_CHECK_HEADER(zlib.h, LIBS="$LIBS -lz")) got_zlibh=false AC_CHECK_LIB(z, deflate, got_libz=true, got_libz=false) if $got_libz; then AC_CHECK_HEADER(zlib.h, got_zlibh=true LIBS="$LIBS -lz") fi if $got_zlibh; then echo " (found libz and zlib.h, enabling deflate)" AC_DEFINE(ENABLE_DEFLATE) else echo " (couldn't find libz and zlib.h, not enabling deflate)" fi fi AC_ARG_ENABLE(bzip2, [ --enable-bzip2 do link against libbz2], [ ], [ enable_bzip2=no ]) if test $enable_bzip2 = "yes"; then dnl Check for libbz2. Make sure it comes with bzlib.h. dnl AC_CHECK_LIB(bz2, BZ2_bzCompress, dnl AC_CHECK_HEADER(bzlib.h, LIBS="$LIBS -lbz2")) got_bzlibh=false AC_CHECK_LIB(bz2, BZ2_bzCompress, got_libbz=true, got_libbz=false) if $got_libbz; then AC_CHECK_HEADER(bzlib.h, got_bzlibh=true LIBS="$LIBS -lbz2") fi if $got_bzlibh; then echo " (found libbz2 and bzlib.h, enabling bzip2)" AC_DEFINE(ENABLE_BZIP2) else echo " (couldn't find libbz2 and bzlib.h, not enabling bzip2)" fi fi dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_STRUCT_TM dnl Checks for library functions. dnl AC_FUNC_SETVBUF_REVERSED AC_FUNC_UTIME_NULL AC_CHECK_FUNCS(memmove mkdir strtoul strcasecmp strncasecmp strerror) dnl if we're using gcc, include gcc-specific warning flags if test -z "$GCC"; then BUILD_FLAGS='$(OPT)' else BUILD_FLAGS='$(OPT) $(GCC_FLAGS)' fi dnl --------------------------------------------------------------------------- dnl Some host-specific stuff. Variables you can test (set by the dnl AC_CANONICAL_HOST call earlier) look like this: dnl dnl $host = i686-pc-linux-gnu dnl $host_cpu = i686 dnl $host_vendor = pc dnl $host_os = linux-gnu dnl BeOS doesn't like /usr/local/include, and gets feisty about it. If libdir dnl and includedir are set to defaults, replace them with BeOS values. This dnl might be going a little too far... if test "$host_os" = "beos"; then if test "$prefix" = "NONE" -a \ "$includedir" = '${prefix}/include' -a \ "$libdir" = '${exec_prefix}/lib' -a \ "$bindir" = '${exec_prefix}/bin' -a \ "$mandir" = '${prefix}/man' then echo replacing install locations with BeOS values prefix=/boot includedir='${prefix}/develop/headers' libdir='${exec_prefix}/home/config/lib' bindir='${exec_prefix}/home/config/bin' mandir='/tmp' AC_SUBST(prefix) AC_SUBST(includedir) AC_SUBST(libdir) AC_SUBST(bindir) AC_SUBST(mandir) fi fi dnl Figure out what the build and link flags should be if test "$host_cpu" = "powerpc" -a "$host_os" = "beos"; then dnl BeOS/PPC with Metrowerks compiler CC=cc GCC= CFLAGS='-proc 603 -opt full' echo "forcing CC to \"$CC\" and CFLAGS to \"$CFLAGS\"" fi AC_SUBST(BUILD_FLAGS) AC_ARG_ENABLE(dmalloc, [ --enable-dmalloc do dmalloc stuff], \ [ echo "--- enabling dmalloc"; LIBS="$LIBS -L/usr/local/lib -ldmalloc"; AC_DEFINE(USE_DMALLOC) ]) AC_OUTPUT(Makefile) nulib2-3.1.0/nulib2/install-sh000077500000000000000000000127361316100516500161140ustar00rootroot00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 nulib2-3.1.0/nulib2/mkinstalldirs000077500000000000000000000012761316100516500167130ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Last modified: 1995-03-05 # Public domain errstatus=0 for file in ${1+"$@"} ; do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? fi if test ! -d "$pathcomp"; then errstatus=$lasterr fi pathcomp="$pathcomp/" done done exit $errstatus nulib2-3.1.0/nulib2/nulib2-man.txt000066400000000000000000000141321316100516500166050ustar00rootroot00000000000000NULIB2(1L) NULIB2(1L) NAME nulib2 - package and compress (archive) files SYNOPSIS nulib2 -command[modifiers] archive [ filenames ] DESCRIPTION nulib2 is a disk and file archiver for NuFX (ShrinkIt) files. It can add files to and extract files from .SHK, .BXY, .SEA (as created by GS/ShrinkIt), and .BSE files. In addition, it can extract files from .BNY and .BQY Binary II archives. When extracting, testing, or listing the contents of an archive, you can specify "-" for the archive name. The archive will be read from stdin. (If the archive is Binary II, you must specify the "-b" flag.) Filenames are considered case-sensitive. This man page contains a summary of available options. For full docu- mentation and the latest versions, visit http://www.nulib.com/. OPTIONS -h Get verbose help output. -a Add files to an archive. If the archive does not exist, a new one will be created. The list of files to add must be given. -d Delete files from an archive. The set of files to delete must be provided. -i Integrity test. If no files are listed, all files in the ar- chive are tested. -p Pipe extraction. All extracted files are written to stdout instead of a file on disk. Normal archive progress messages are suppressed. -t Table of contents. Provides a simple list of files in the ar- chive, one per line. -v Verbose table of contents. Output similar to what ShrinkIt dis- plays is shown. -x Extract files from an archive. If no files are listed, all files in the archive are extracted. MODIFIERS -c Comments. When extracting, comments will be displayed. When adding, you will be prompted to enter a one-line comment for every file. -e Preserve ProDOS file types. See the ProDOS File Type Preserva- tion document on http://www.nulib.com/ for details on how this works. -ee Preserve file types, using extended names. A file extension is appended to extracted files. Useful on operating systems like Windows, where filename extensions are important. When adding files, nulib2 will try to guess at correct file types by examin- ing the filename extension. -f Freshen files. When adding, files in the archive that are older than files on disk are "freshened", meaning that no new files are added, and files that are the same age or newer aren't touched. Works similarly when extracting. -j Junk directory names. Only the filename is kept; the rest of the pathname is thrown away. Empty directories aren't stored. Works when adding or extracting. -k Store files as disk images. Files that are a multiple of 512 bytes will be added as disk images rather than normal files. This does not override the "-e" flag. -l Auto-convert text files. A reasonably smart algorithm is used to identify which files are text and which aren't during extrac- tion. It then converts whatever EOL indicator is being used by the text file into something appropriate for the current system. -ll Auto-convert all files. All files being extracted are consid- ered text, and will be converted. Don't use this unless you're sure you need it. -r Recurse into subdirectories. When adding, this causes nulib2 to descend into subdirectories and store all of the files found. When extracting, testing, or deleting, this causes the files listed to match against all records whose prefix matches, allow- ing you to extract, test, or delete entire subdirectories from the archive. -u Update files. When adding, files in the archive that are older than files on disk are updated. Files in the archive that are the same age or newer aren't touched. New files will be added. Works similarly when extracting. -b Binary II. Forces NuLib2 to treat the archive as Binary II. Useful for opening NuFX-in-BNY archives (.BXY) if you want to strip the wrapper off. You must specify this for Binary II ar- chives on stdin. -0 Don't use compression. Files added will be stored without com- pression. (Note that's dash-zero, not dash-oh.) -z Use "deflate" compression. This option is only available if libz was linked against. Archives created with this algorithm will not be usable on an Apple II. -zz Use "bzip2" compression. This option is only available if libbz2 was linked against. Archives created with this algorithm will not be usable on an Apple II. EXAMPLES A simple example: nulib2 a foo.shk * creates the archive foo.shk (assuming it doesn't exist) and stores all of the files in the current directory in it, in compressed form. If you wanted to add all the files in the current directory, as well as all files in all subdirectories, you could use: nulib2 ar foo.shk * to recursively descend into the directory tree. Using the command: nulib2 xe foo.shk would extract all files from foo.shk, preserving ProDOS file types. If you then used the command: nulib2 aer foo.shk * you would add the files, preserving the file types of anything that was extracted with the "-e" flag set. A handy way to look at text documents is to use: nulib2 xeel foo.shk to convert end-of-line terminators (e.g. CRLF to LF) as the files are being extracted. The "-ee" flag adds ".TXT" to all files with a ProDOS file type of TXT ($04). SEE ALSO compress(1), tar(1), zip(1L), unzip(1L), nulib(1L) BUGS Nah. AUTHOR Copyright (C) 2007 by Andy McFadden. All Rights Reserved. 08 Feb 2003 NULIB2(1L) nulib2-3.1.0/nulib2/nulib2.1000066400000000000000000000144061316100516500153610ustar00rootroot00000000000000.\" nulib2.1 .\" Copyright (C) 2000-2007 by Andy McFadden. All Rights Reserved. .\" This is free software; you can redistribute it and/or modify it under the .\" terms of the BSD License, see the file COPYING. .\" .\" The general structure of this man page was borrowed from "zip.1" in .\" the Red Hat Linux 6.0 distribution. .\" .\" Format with: nroff -man nulib2.1 | col -b > nulib2-man.txt .\" .TH NULIB2 1L "08 Feb 2003" .SH NAME nulib2 \- package and compress (archive) files .SH SYNOPSIS .B nulib2 .RB \-command[modifiers] .I archive .I [ filenames ] .SH DESCRIPTION .I nulib2 is a disk and file archiver for NuFX (ShrinkIt) files. It can add files to and extract files from .IR .SHK , .IR .BXY , .IR .SEA (as created by GS/ShrinkIt), and .I .BSE files. In addition, it can extract files from .IR .BNY and .IR .BQY Binary II archives. .LP When extracting, testing, or listing the contents of an archive, you can specify "-" for the archive name. The archive will be read from stdin. (If the archive is Binary II, you must specify the "-b" flag.) .LP Filenames are considered case-sensitive. .\" .LP .\" The .\" .I filenames .\" will be compared in a case-sensitive fashion. While this would be .\" inappropriate for most UNIX systems, it makes sense for Apple II archives, .\" because most Apple II filesystems are case-insensitive. .LP This man page contains a summary of available options. For full documentation and the latest versions, visit http://www.nulib.com/. .SH "OPTIONS" .TP .B \-h Get verbose help output. .TP .B \-a Add files to an archive. If the archive does not exist, a new one will be created. The list of files to add must be given. .TP .B \-d Delete files from an archive. The set of files to delete must be provided. .TP .B \-i Integrity test. If no files are listed, all files in the archive are tested. .TP .B \-p Pipe extraction. All extracted files are written to stdout instead of a file on disk. Normal archive progress messages are suppressed. .TP .B \-t Table of contents. Provides a simple list of files in the archive, one per line. .TP .B \-v Verbose table of contents. Output similar to what ShrinkIt displays is shown. .TP .B \-x Extract files from an archive. If no files are listed, all files in the archive are extracted. .\" There's also a '-g' command that does a verbose archive dump, but it's .\" only available if NufxLib was built with debugging enabled. .SH "MODIFIERS" .TP .B \-c Comments. When extracting, comments will be displayed. When adding, you will be prompted to enter a one-line comment for every file. .TP .B \-e Preserve ProDOS file types. See the ProDOS File Type Preservation document on http://www.nulib.com/ for details on how this works. .TP .B \-ee Preserve file types, using extended names. A file extension is appended to extracted files. Useful on operating systems like Windows, where filename extensions are important. When adding files, .I nulib2 will try to guess at correct file types by examining the filename extension. .TP .B \-f Freshen files. When adding, files in the archive that are older than files on disk are "freshened", meaning that no new files are added, and files that are the same age or newer aren't touched. Works similarly when extracting. .TP .B \-j Junk directory names. Only the filename is kept; the rest of the pathname is thrown away. Empty directories aren't stored. Works when adding or extracting. .TP .B \-k Store files as disk images. Files that are a multiple of 512 bytes will be added as disk images rather than normal files. This does not override the "-e" flag. .TP .B \-l Auto-convert text files. A reasonably smart algorithm is used to identify which files are text and which aren't during extraction. It then converts whatever EOL indicator is being used by the text file into something appropriate for the current system. .TP .B \-ll Auto-convert all files. All files being extracted are considered text, and will be converted. Don't use this unless you're sure you need it. .TP .B \-r Recurse into subdirectories. When adding, this causes .I nulib2 to descend into subdirectories and store all of the files found. When extracting, testing, or deleting, this causes the files listed to match against all records whose prefix matches, allowing you to extract, test, or delete entire subdirectories from the archive. .TP .B \-u Update files. When adding, files in the archive that are older than files on disk are updated. Files in the archive that are the same age or newer aren't touched. New files will be added. Works similarly when extracting. .TP .B \-b Binary II. Forces NuLib2 to treat the archive as Binary II. Useful for opening NuFX-in-BNY archives (.BXY) if you want to strip the wrapper off. You must specify this for Binary II archives on stdin. .TP .B \-0 Don't use compression. Files added will be stored without compression. (Note that's dash-zero, not dash-oh.) .TP .B \-z Use "deflate" compression. This option is only available if libz was linked against. Archives created with this algorithm will not be usable on an Apple II. .TP .B \-zz Use "bzip2" compression. This option is only available if libbz2 was linked against. Archives created with this algorithm will not be usable on an Apple II. .SH "EXAMPLES" A simple example: .IP \fCnulib2 a foo.shk *\fP .LP creates the archive .I foo.shk (assuming it doesn't exist) and stores all of the files in the current directory in it, in compressed form. .LP If you wanted to add all the files in the current directory, as well as all files in all subdirectories, you could use: .IP \fCnulib2 ar foo.shk *\fP .LP to recursively descend into the directory tree. .LP Using the command: .IP \fCnulib2 xe foo.shk\fP .LP would extract all files from .I foo.shk, preserving ProDOS file types. If you then used the command: .IP \fCnulib2 aer foo.shk *\fP .LP you would add the files, preserving the file types of anything that was extracted with the "-e" flag set. .LP A handy way to look at text documents is to use: .IP \fCnulib2 xeel foo.shk\fP .LP to convert end-of-line terminators (e.g. CRLF to LF) as the files are being extracted. The "-ee" flag adds ".TXT" to all files with a ProDOS file type of TXT ($04). .SH "SEE ALSO" compress(1), tar(1), zip(1L), unzip(1L), nulib(1L) .SH BUGS Nah. .SH AUTHOR Copyright (C) 2007 by Andy McFadden. All Rights Reserved. .\" end of file