From e27b5ee6468bcd87164baeabe290282ec85e0c4a Mon Sep 17 00:00:00 2001 From: Curtis McEnroe Date: Thu, 14 Mar 2019 18:38:47 -0400 Subject: Rewrite using SDL --- .gitignore | 3 + Makefile | 9 ++- cards.c | 214 +++++++++++++++++++++++++++++++++++++------------------------ cards.h | 52 +++++++-------- dump.c | 59 ++++++----------- 5 files changed, 188 insertions(+), 149 deletions(-) diff --git a/.gitignore b/.gitignore index eea74f3..3c9fa20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ +*.bmp *.o +CARDS.DLL +SOL.EXE dump diff --git a/Makefile b/Makefile index b58b5e5..2ba46a6 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,17 @@ -CFLAGS += -Wall -Wextra +CFLAGS += -std=c99 -Wall -Wextra + +SDL_PREFIX = /usr/local +CFLAGS += -I$(SDL_PREFIX)/include/SDL2 +LDFLAGS += -L$(SDL_PREFIX)/lib +LDLIBS = -lSDL2 -include config.mk BINS = dump OBJS = cards.o dump.o +all: $(BINS) + dump: cards.o dump.o $(CC) $(LDFLAGS) cards.o dump.o $(LDLIBS) -o dump diff --git a/cards.c b/cards.c index 52445a1..6369d40 100644 --- a/cards.c +++ b/cards.c @@ -14,124 +14,168 @@ * along with this program. If not, see . */ +#include #include #include #include "cards.h" -enum { - MZ_NEOff = 0x3C, +static struct SDL_Surface * +dibSurface(struct SDL_RWops *rw, Uint32 offset, Uint32 length) { + Uint32 bitmapLength = 0x0E + length; - NE_ResTableOff = 0x24, - - ResTable_AlignShift = 0x00, - ResTable_ResBlock = 0x02, - - ResBlock_TypeID = 0x00, - ResBlock_ResCount = 0x02, - ResBlock_Resource = 0x08, - - TypeID_Bitmap = 0x8002, + void *buffer = malloc(bitmapLength); + if (!buffer) { + SDL_SetError("malloc error: %s", strerror(errno)); + return NULL; + } - Resource_Off = 0x00, - Resource_Len = 0x02, - Resource_ID = 0x06, - Resource_Next = 0x0C, + struct SDL_RWops *bitmap = SDL_RWFromMem(buffer, bitmapLength); + if (!bitmap) { + free(buffer); + return NULL; + } - IDMask = 0x7FFF, + if (SDL_RWseek(rw, offset, RW_SEEK_SET) < 0) goto fail; + Uint32 dibHeaderLength = SDL_ReadLE32(rw); + Uint32 bitmapDataOffset = 0x0E + dibHeaderLength; - BMPHeader_FileLen = 0x02, - BMPHeader_Reserved = 0x06, - BMPHeader_DataOff = 0x0A, - BMPHeader_DIBHeader = 0x0E, + if (dibHeaderLength == 0x0C) { + if (SDL_RWseek(rw, 0x06, RW_SEEK_CUR) < 0) goto fail; + Uint16 bitsPerPixel = SDL_ReadLE16(rw); + bitmapDataOffset += 3 * (1 << bitsPerPixel); - DIBHeader_Len = 0x00, - DIBHeaderCore_Bits = 0x0A, + } else if (dibHeaderLength == 0x28) { + if (SDL_RWseek(rw, 0x0A, RW_SEEK_CUR) < 0) goto fail; + Uint16 bitsPerPixel = SDL_ReadLE16(rw); + if (SDL_RWseek(rw, 0x10, RW_SEEK_CUR) < 0) goto fail; + Uint32 paletteLength = SDL_ReadLE32(rw); - DIBHeaderCoreLen = 0x0C, -}; + if (!paletteLength) paletteLength = 1 << bitsPerPixel; + bitmapDataOffset += 4 * paletteLength; -static uint16_t read16(const uint8_t *ptr, size_t off) { - return (uint16_t)ptr[off] | (uint16_t)ptr[off + 1] << 8; -} -static uint32_t read32(const uint8_t *ptr, size_t off) { - return (uint32_t)ptr[off] - | (uint32_t)ptr[off + 1] << 8 - | (uint32_t)ptr[off + 2] << 16 - | (uint32_t)ptr[off + 3] << 24; -} + } else { + SDL_SetError("unrecognized DIB header length %u", dibHeaderLength); + goto fail; + } -static void write32(uint8_t *ptr, size_t off, uint32_t val) { - ptr[off + 0] = val & 0xFF; - ptr[off + 1] = val >> 8 & 0xFF; - ptr[off + 2] = val >> 16 & 0xFF; - ptr[off + 3] = val >> 24; + SDL_WriteU8(bitmap, 'B'); + SDL_WriteU8(bitmap, 'M'); + SDL_WriteLE32(bitmap, bitmapLength); + SDL_WriteLE16(bitmap, 0); // reserved + SDL_WriteLE16(bitmap, 0); // reserved + SDL_WriteLE32(bitmap, bitmapDataOffset); + + if (SDL_RWseek(rw, offset, RW_SEEK_SET) < 0) goto fail; + if (SDL_RWread(rw, &buffer[SDL_RWtell(bitmap)], length, 1) < 1) goto fail; + + SDL_RWseek(bitmap, 0, RW_SEEK_SET); + SDL_Surface *surface = SDL_LoadBMP_RW(bitmap, 1); + free(buffer); + return surface; + +fail: + SDL_RWclose(bitmap); + free(buffer); + return NULL; } -int cardsLoad(const uint8_t *ptr, size_t len) { - if (len < MZ_NEOff + 2) return -1; - if (ptr[0] != 'M' || ptr[1] != 'Z') return -1; +struct Cards *Cards_Load(struct SDL_RWops *rw) { + struct Cards *cards = calloc(1, sizeof(*cards)); + if (!cards) { + SDL_SetError("calloc error: %s", strerror(errno)); + return NULL; + } - uint16_t neOff = read16(ptr, MZ_NEOff); + if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0) goto fail; + if (SDL_ReadU8(rw) != 'M' || SDL_ReadU8(rw) != 'Z') { + SDL_SetError("invalid MZ signature"); + goto fail; + } - if (len < neOff + NE_ResTableOff + 2) return -1; - if (ptr[neOff + 0] != 'N' || ptr[neOff + 1] != 'E') return -1; + if (SDL_RWseek(rw, 0x3C, RW_SEEK_SET) < 0) goto fail; + Uint16 neOffset = SDL_ReadLE16(rw); - uint16_t resTableOff = neOff + read16(ptr, neOff + NE_ResTableOff); + if (SDL_RWseek(rw, neOffset, RW_SEEK_SET) < 0) goto fail; + if (SDL_ReadU8(rw) != 'N' || SDL_ReadU8(rw) != 'E') { + SDL_SetError("invalid NE signature"); + goto fail; + } - if (len < resTableOff + ResTable_ResBlock) return -1; + if (SDL_RWseek(rw, neOffset + 0x24, RW_SEEK_SET) < 0) goto fail; + Uint16 resourceTableOffset = neOffset + SDL_ReadLE16(rw); - uint16_t alignShift = read16(ptr, resTableOff + ResTable_AlignShift); + if (SDL_RWseek(rw, resourceTableOffset, RW_SEEK_SET) < 0) goto fail; + Uint16 alignmentShift = SDL_ReadLE16(rw); - uint16_t resBlockOff = resTableOff + ResTable_ResBlock; - uint16_t resCount; + Uint16 resourceCount; for (;;) { - if (len < resBlockOff + ResBlock_Resource) return -1; - - uint16_t typeID = read16(ptr, resBlockOff + ResBlock_TypeID); - resCount = read16(ptr, resBlockOff + ResBlock_ResCount); + Uint16 typeID = SDL_ReadLE16(rw); + resourceCount = SDL_ReadLE16(rw); + SDL_ReadLE32(rw); // reserved - if (!typeID) return -1; - if (typeID == TypeID_Bitmap) break; + if (!typeID) { + SDL_SetError("no bitmap resources"); + goto fail; + } + if (typeID == 0x8002) break; - resBlockOff += ResBlock_Resource + resCount * Resource_Next; + if (SDL_RWseek(rw, 0x0C * resourceCount, RW_SEEK_CUR) < 0) goto fail; } - uint16_t resOff = resBlockOff + ResBlock_Resource; - for (uint16_t i = 0; i < resCount; ++i, resOff += Resource_Next) { - if (len < resOff + Resource_Next) return -1; + for (Uint16 i = 0; i < resourceCount; ++i) { + Uint16 offset = SDL_ReadLE16(rw); + Uint16 length = SDL_ReadLE16(rw); + SDL_ReadLE16(rw); // flags + Uint16 id = SDL_ReadLE16(rw); + SDL_ReadLE32(rw); // reserved - uint16_t id = read16(ptr, resOff + Resource_ID); - if ((id & IDMask) >= CardsLen) continue; + id &= 0x7FFF; + if (id >= Cards_CardLen) continue; - size_t dataOff = read16(ptr, resOff + Resource_Off); - size_t dataLen = read16(ptr, resOff + Resource_Len); - dataOff <<= alignShift; - dataLen <<= alignShift; + Sint64 next = SDL_RWtell(rw); + if (next < 0) goto fail; - if (len < dataOff + dataLen) return -1; - if (dataLen < DIBHeaderCoreLen) return -1; + cards->surfaces[id] = dibSurface( + rw, + (Uint32)offset << alignmentShift, + (Uint32)length << alignmentShift + ); + if (!cards->surfaces[id]) goto fail; + + if (SDL_RWseek(rw, next, RW_SEEK_SET) < 0) goto fail; + } - uint32_t dibHeaderLen = read32(ptr, dataOff + DIBHeader_Len); - uint32_t bmpFileLen = BMPHeader_DIBHeader + dataLen; - uint32_t bmpDataOff = BMPHeader_DIBHeader + dibHeaderLen; - if (dibHeaderLen == DIBHeaderCoreLen) { - bmpDataOff += 3 * (1 << read16(ptr, dataOff + DIBHeaderCore_Bits)); + int suits[4] = { Cards_Club, Cards_Diamond, Cards_Heart, Cards_Spade }; + for (int suit = 0; suit < 4; ++suit) { + for (int rank = Cards_A; rank <= Cards_K; ++rank) { + if (cards->surfaces[suits[suit] + rank]) continue; + SDL_SetError("missing resource %d", suits[suit] + rank); + goto fail; } + } + for (int i = Cards_Empty; i <= Cards_Back12; ++i) { + if (cards->surfaces[i]) continue; + SDL_SetError("missing resource %d", i); + goto fail; + } + for (int i = Cards_X; i <= Cards_O; ++i) { + if (cards->surfaces[i]) continue; + SDL_SetError("missing resource %d", i); + goto fail; + } - uint8_t *bitmap = malloc(bmpFileLen); - if (!bitmap) return -1; + return cards; - bitmap[0] = 'B'; - bitmap[1] = 'M'; - write32(bitmap, BMPHeader_FileLen, bmpFileLen); - write32(bitmap, BMPHeader_Reserved, 0); - write32(bitmap, BMPHeader_DataOff, bmpDataOff); - memcpy(&bitmap[BMPHeader_DIBHeader], &ptr[dataOff], dataLen); +fail: + Cards_Free(cards); + return NULL; +} - cardsData[id & IDMask].ptr = bitmap; - cardsData[id & IDMask].len = bmpFileLen; +void Cards_Free(struct Cards *cards) { + for (int i = 0; i < Cards_CardLen; ++i) { + if (!cards->surfaces[i]) continue; + SDL_FreeSurface(cards->surfaces[i]); } - - return 0; + free(cards); } diff --git a/cards.h b/cards.h index 65e3c2b..23a70fb 100644 --- a/cards.h +++ b/cards.h @@ -17,33 +17,35 @@ #ifndef CARDS_H #define CARDS_H -#include -#include - -enum Cards { - CardsClub = 0x00, - CardsDiamond = 0x0D, - CardsHeart = 0x1A, - CardsSpade = 0x27, - - CardsA = 1, - Cards2, Cards3, Cards4, Cards5, Cards6, Cards7, Cards8, Cards9, Cards10, - CardsJ, CardsQ, CardsK, - - CardsEmpty = 0x35, - CardsBack1, CardsBack2, CardsBack3, CardsBack4, CardsBack5, CardsBack6, - CardsBack7, CardsBack8, CardsBack9, CardsBack10, CardsBack11, CardsBack12, - - CardsX = 0x43, - CardsO, - CardsLen, +#include +#include + +enum Cards_Card { + Cards_Club, + Cards_Diamond = 13, + Cards_Heart = 26, + Cards_Spade = 39, + + Cards_A = 1, + Cards_2, Cards_3, Cards_4, Cards_5, Cards_6, Cards_7, Cards_8, Cards_9, + Cards_10, Cards_J, Cards_Q, Cards_K, + + Cards_Empty = 53, + Cards_Back1, Cards_Back2, Cards_Back3, Cards_Back4, + Cards_Back5, Cards_Back6, Cards_Back7, Cards_Back8, + Cards_Back9, Cards_Back10, Cards_Back11, Cards_Back12, + + Cards_X = 67, + Cards_O, + + Cards_CardLen, }; -struct CardsData { - uint8_t *ptr; - size_t len; -} cardsData[CardsLen]; +struct Cards { + struct SDL_Surface *surfaces[Cards_CardLen]; +}; -int cardsLoad(const uint8_t *ptr, size_t len); +struct Cards *Cards_Load(struct SDL_RWops *rw); +void Cards_Free(struct Cards *cards); #endif diff --git a/dump.c b/dump.c index 0eefc3c..1d3b6dc 100644 --- a/dump.c +++ b/dump.c @@ -14,54 +14,37 @@ * along with this program. If not, see . */ -#include -#include #include #include -#include + +#include #include "cards.h" +static int fail(const char *prefix) { + fprintf(stderr, "%s: %s\n", prefix, SDL_GetError()); + return EXIT_FAILURE; +} + int main(int argc, char *argv[]) { - FILE *file = stdin; + struct SDL_RWops *rw; if (argc > 1) { - file = fopen(argv[1], "r"); - if (!file) err(EX_NOINPUT, "%s", argv[1]); - } - - size_t cap = 4096; - void *ptr = malloc(cap); - if (!ptr) err(EX_OSERR, "malloc"); - - size_t len = 0, read; - while (0 < (read = fread(&ptr[len], 1, cap - len, file))) { - len += read; - if (len < cap) continue; - cap *= 2; - ptr = realloc(ptr, cap); - if (!ptr) err(EX_OSERR, "realloc"); + rw = SDL_RWFromFile(argv[1], "rb"); + } else { + rw = SDL_RWFromFP(stdin, SDL_FALSE); } - if (ferror(file)) err(EX_IOERR, "fread"); - fclose(file); + if (!rw) return fail("SDL_RWFromFile"); - errno = 0; - int error = cardsLoad(ptr, len); - if (error && errno) err(EX_OSERR, "cardsLoad"); - if (error) errx(EX_DATAERR, "cannot load cards"); - - for (size_t i = 0; i < CardsLen; ++i) { - if (!cardsData[i].ptr) continue; + struct Cards *cards = Cards_Load(rw); + if (!cards) return fail("Cards_Load"); + SDL_RWclose(rw); + for (int i = 0; i < Cards_CardLen; ++i) { + if (!cards->surfaces[i]) continue; char name[sizeof("00.bmp")]; - snprintf(name, sizeof(name), "%02zd.bmp", i); - - FILE *file = fopen(name, "w"); - if (!file) err(EX_CANTCREAT, "%s", name); - - fwrite(cardsData[i].ptr, cardsData[i].len, 1, file); - if (ferror(file)) err(EX_IOERR, "fwrite"); - - error = fclose(file); - if (error) err(EX_IOERR, "fclose"); + snprintf(name, sizeof(name), "%02d.bmp", i); + SDL_SaveBMP(cards->surfaces[i], name); } + + Cards_Free(cards); } -- cgit 1.4.1 d0697ce43131343d7a9f170a61ff9&follow=1'>ui-summary: Pass filename to about-filterJason A. Donenfeld This gives the about-filter API the same semantics as source-filter, where the filter receives the filename so it can decide what to do next with it. While we're at it, plug a memory leak. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2013-05-25ui-summary: Use default branch for readme if : prefixJason A. Donenfeld If the readme value begins with ":", and has no specified branch before it, use the repository's default branch. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2013-05-25cgit.c: Do not reset HOME after unsetting it.Jason A. Donenfeld The number of odd cases in which git will try to read config is far too great to keep putting a bandaid over each one, so we'll just unset it. If it turns out that scripts really liked to know about $HOME, we can always reset it in the filter forks. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2013-05-25cgit.c: sync repo config printing with struct cgit_repoJason A. Donenfeld We've now added quite a few config keys for repositories, but we've forgotten to update the printing of it for cache files. Synchronize the two. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2013-05-25git: update to 1.8.3John Keeping No changes required, just bump the submodule and Makefile versions. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-22cache.c: cache ls_cache output properlyJohn Keeping By using the standard library's printf, cache_ls does not redirect its output to the cache when we change the process' stdout file descriptor to point to the cache file. Fix this by using "htmlf" in the same way that we do for writing HTTP headers. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-22tests: introduce strip_header() helper functionJohn Keeping This means that we can avoid hardcoding the number of headers we expect CGit to generate in test cases and simply remove whatever headers happen to by there when we are checking body content. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-22shared.c: use die_errno() where appropriateJohn Keeping This replaces some code that is re-implementing die_errno by just calling the function. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-22html.c: die when write failsJohn Keeping If we fail to write HTML output once, there's no point carrying on so just write a failure message once and die. By using Git's die_errno function we also let the user know in what way the write failed. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-22ui-log: add <span/> around commit decorationsJohn Keeping This helps projects that have a large number of tags to display them all using custom CSS. The default stylesheet has not been updated since what is useful for projects with a lot of tags is not the same as what is useful for projects with only a small number of decorations per commit. Suggested-by: Konstantin Ryabitsev <mricon@kernel.org> Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-22Makefile: fix parallel "make test"John Keeping When building the "test" target we depend on both cgit and building the Git tools. By doing this with two targets we end up running make in the git/ directory twice, concurrently if using parallel make, which causes us to build more than we need and potentially builds incorrectly if multi-step build-then-move operations overlap. Fix this by instead calling back into the makefile so that we alter the "cgit" target to also build the Git tools. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-18cache.c: fix cache_lsJohn Keeping Commit fb3655d (use struct strbuf instead of static buffers, 2013-04-06) broke the logic in cache.c::cache_ls by failing to set slot->cache_name before calling open_slot. While fixing this, also free the strbufs added by that commit once we're done with them. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-13t0109: "function" is a bash-ismJohn Keeping We try to stick to POSIX shell in the tests but a "function" keyword has found its way into t0109. Remove it. This makes the tests work with dash again. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-05-13New mailing list.Jason A. Donenfeld 2013-04-30ui-snapshot: do not access $HOMEJason A. Donenfeld It's a bit tedious to have to do this here too. If we encounter other issues with $HOME down the line, I'll look into adding some nice utility functions to handle this, or perhaps giving up on the hope that we could keep $HOME defined for scripts. This commit additionally adds a test case, should the issue surface again. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2013-04-27t0001: validate Git -rcN version numbers correctlyJohn Keeping When creating the GIT-VERSION-FILE that we use to test that the version of Git in git/ is the same as in the CGit Makefile, Git applies the transform "s/-/./g" to the version string. This doesn't affect released versions but does change RC version numbers such as 1.8.3-rc0. While CGit should only refer to a released Git version in general, it is useful to developers who want to test upcoming Git releases if the tests do work with RCs, so change t0001 to apply the same transform to our Makefile version before comparing it to the contents of GIT-VERSION-FILE. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-04-27git: update to 1.8.2.2John Keeping No changes required, just bump the submodule and Makefile version. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-04-17scan-tree: fix regression in section-from-path=-1John Keeping Commit fb3655d (use struct strbuf instead of static buffers - 2013-04-06) introduced a regression in the "section-from-path" handling when the configured value is negative. By changing the "rel" variable so that it includes a trailing slash, counting slashes from the end of the string no longer gives the same answer as it did before. Fix this by ensuring that "rel" does not have a trailing slash. Reported-by: Julius Plenz <plenz@cis.fu-berlin.de> Signed-off-by: John Keeping <john@keeping.me.uk> 2013-04-15t0001: ignore ".dirty" suffix on Git versionJohn Keeping When testing modifications in Git that affect CGit, it is annoying to have t0001 failing simply because the Git version has a ".dirty" suffix when the version of Git there does indeed match that specified in the CGit makefile. Stop this by stripping the ".dirty" suffix from the GIT_VERSION variable. Note that this brings the "Git version" behaviour in line with the "submodule version" case which does not check if the working tree in git/ is modified. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-04-15tests: set TEST_OUTPUT_DIRECTORY to the CGit test directoryJohn Keeping By default, Git's test suite puts the trash directories and test-results directory into its own directory, not that containing the tests being run. This is less convenient for inspecting test failures, so set the output directory to CGit's tests/ directory instead. Note that there is currently a bug in Git whereby it will create the trash directories in our tests/ directory regardless of the value of TEST_OUTPUT_DIRECTORY, and then fail to remove them once the tests are done. This change does currently affect the location of the test-results/ directory though. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-04-15t0109: test more URLsJohn Keeping In order to ensure that we don't access $HOME at some point after initial startup when rendering a specific view, run the strace test on a range of different pages. This ensures that we don't end up reading a configuration later for some specific view. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-04-10cgitrc.5.txt: Specify when scan-path must be defined before.Jason A. Donenfeld Several options must be specified prior to scan-path. This is consistant source of user confusion. Document these facts. Suggested-by: Lukas Fleischer <cgit@cryptocrack.de> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2013-04-10ui-snapshot.c: Prepend "V" when guessing ref namesLukas Fleischer In cgit_print_snapshot_links() we strip leading "v" and "V", while we currently only prepend a lower case "v" when parsing a snapshot file name. This results in broken snapshot links for tags that start with an upper case "V". Avoid this by prepending a "V" as a fallback. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2013-04-10t0107: Skip ZIP tests if unzip(1) isn't availableLukas Fleischer Note that we cannot use skip_all here since some tests have already been executed when ZIP tests are reached. Use test prerequisites to skip everything using unzip(1) if the binary is not available instead. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2013-04-10tests/: Do not use `sed -i`Lukas Fleischer "-i" isn't part of the POSIX standard and doesn't work on several platforms such as OpenBSD. Use a temporary file instead. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2013-04-10Add branch-sort and repo.branch-sort options.Jason A. Donenfeld When set to "name", branches are sorted by name, which is the current default. When set to "age", branches are sorted by the age of the repository. This feature was requested by Konstantin Ryabitsev for use on kernel.org. Proposed-by: Konstantin Ryabitsev <mricon@kernel.org> 2013-04-10t0109: chain operations with &&John Keeping Without '&&' between operations, we will not detect if strace or cgit exit with an error status, which would cause a false positive test status in this case. Signed-off-by: John Keeping <john@keeping.me.uk> 2013-04-10cgit.c: Do not restore unset environment variablesLukas Fleischer getenv() returns a NULL pointer if the specified variable name cannot be found in the environment. However, some setenv() implementations crash if a NULL pointer is passed as second argument. Only restore variables that are not NULL. See commit d96d2c98ebc4c2d3765f5b35c4142e0e828a421b for a related patch. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2013-04-09t0107: Use `tar -z` for gzip'ed archivesLukas Fleischer