From 0dc7366b10e5a160d153305dfe6c80c34e3ac10b Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Mon, 3 Jun 2024 04:36:56 +0100 Subject: [PATCH] New server --- LICENSE | 24 +++ Makefile.pdw | 22 ++ Makefile.s64 | 24 +++ Makefile.std | 19 ++ Makefile.unix | 30 +++ Makefile.vsc | 17 ++ Makefile.w32 | 19 ++ Makefile.wcd | 21 ++ README.md | 23 +++ append.c | 153 ++++++++++++++ ar.c | 129 ++++++++++++ ar.h | 49 +++++ conv.c | 19 ++ delete.c | 182 +++++++++++++++++ display.c | 57 ++++++ extract.c | 120 +++++++++++ lib.c | 200 +++++++++++++++++++ lib.h | 15 ++ makefile.slp | 26 +++ makefile.sos | 29 +++ makefile.std | 20 ++ ranlib.c | 541 ++++++++++++++++++++++++++++++++++++++++++++++++++ replace.c | 192 ++++++++++++++++++ report.c | 125 ++++++++++++ report.h | 28 +++ stdint.h | 23 +++ 26 files changed, 2107 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile.pdw create mode 100644 Makefile.s64 create mode 100644 Makefile.std create mode 100644 Makefile.unix create mode 100644 Makefile.vsc create mode 100644 Makefile.w32 create mode 100644 Makefile.wcd create mode 100644 README.md create mode 100644 append.c create mode 100644 ar.c create mode 100644 ar.h create mode 100644 conv.c create mode 100644 delete.c create mode 100644 display.c create mode 100644 extract.c create mode 100644 lib.c create mode 100644 lib.h create mode 100644 makefile.slp create mode 100644 makefile.sos create mode 100644 makefile.std create mode 100644 ranlib.c create mode 100644 replace.c create mode 100644 report.c create mode 100644 report.h create mode 100644 stdint.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Makefile.pdw b/Makefile.pdw new file mode 100644 index 0000000..6dbb921 --- /dev/null +++ b/Makefile.pdw @@ -0,0 +1,22 @@ +#****************************************************************************** +# @file Makefile.pdw +#****************************************************************************** +AS=aswin +CC=gccwin +LD=ldwin + +COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__ +COBJ=append.o ar.o conv.o delete.o display.o extract.o lib.o ranlib.o replace.o report.o + +all: clean xar.exe + +xar.exe: $(COBJ) + $(LD) -s -o xar.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a + +.c.o: + $(CC) $(COPTS) $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + rm -f *.o xar.exe diff --git a/Makefile.s64 b/Makefile.s64 new file mode 100644 index 0000000..0ccc969 --- /dev/null +++ b/Makefile.s64 @@ -0,0 +1,24 @@ +CPP=pdcc +CC=cc64 +CFLAGS= +LD=pdld +LDFLAGS=-s -nostdlib --no-insert-timestamp --image-base 0x400000 +AS=pdas --oformat coff --64 +COPTS=-I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__64BIT__ -D__CC64__ + +OBJS=append.obj ar.obj conv.obj delete.obj display.obj extract.obj lib.obj ranlib.obj replace.obj report.obj + +TARGET=xar.exe + +all: clean $(TARGET) + +$(TARGET): $(OBJS) + $(LD) $(LDFLAGS) -o $(TARGET) ../pdos/pdpclib/w32start.obj $(OBJS) ../pdos/pdpclib/msvcrt.lib + +.c.obj: + $(CPP) -E $(COPTS) -o $*.i $< + $(CC) -c -out:$@ $*.i + rm -f $*.i + +clean: + rm -f $(OBJS) $(TARGET) diff --git a/Makefile.std b/Makefile.std new file mode 100644 index 0000000..a7f73c5 --- /dev/null +++ b/Makefile.std @@ -0,0 +1,19 @@ +AS=pdas --oformat coff +CC=gccwin +LD=pdld + +COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__ +COBJ=append.o ar.o conv.o delete.o display.o extract.o lib.o ranlib.o replace.o report.o + +all: clean xar.exe + +xar.exe: $(COBJ) + $(LD) -s -nostdlib --no-insert-timestamp -o xar.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a + +.c.o: + $(CC) $(COPTS) $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + rm -f *.o xar.exe diff --git a/Makefile.unix b/Makefile.unix new file mode 100644 index 0000000..f4f5b54 --- /dev/null +++ b/Makefile.unix @@ -0,0 +1,30 @@ +#****************************************************************************** +# @file Makefile.unix +#****************************************************************************** +SRCDIR ?= $(CURDIR) +VPATH := $(SRCDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 + +ifneq ($(shell uname -s),Darwin) +CFLAGS += -m32 +endif + +CSRC := append.c ar.c conv.c delete.c display.c extract.c lib.c ranlib.c replace.c report.c + +ifeq ($(OS), Windows_NT) +all: xar.exe + +xar.exe: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ +else +all: xar + +xar: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ +endif + +clean: + if [ -f xar.exe ]; then rm -rf xar.exe; fi + if [ -f xar ]; then rm -rf xar; fi diff --git a/Makefile.vsc b/Makefile.vsc new file mode 100644 index 0000000..b9fe4d6 --- /dev/null +++ b/Makefile.vsc @@ -0,0 +1,17 @@ +CC=cl +LD=cl + +COPTS=-c -nologo -O2 -I. +COBJ=append.obj ar.obj conv.obj delete.obj display.obj \ + extract.obj lib.obj ranlib.obj replace.obj report.obj + +all: clean xar.exe + +xar.exe: $(COBJ) + $(LD) -nologo -Fexar.exe $(COBJ) + +.c.obj: + $(CC) $(COPTS) -Fo$@ $< + +clean: + rm -f *.obj xar.exe diff --git a/Makefile.w32 b/Makefile.w32 new file mode 100644 index 0000000..ad0e650 --- /dev/null +++ b/Makefile.w32 @@ -0,0 +1,19 @@ +#****************************************************************************** +# @file Makefile.w32 +#****************************************************************************** +SRCDIR ?= $(CURDIR) +VPATH := $(SRCDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -m32 -pedantic -std=c90 + +CSRC := append.c ar.c conv.c delete.c display.c extract.c lib.c ranlib.c replace.c report.c + +all: xar.exe + +clean: + if exist xar.exe ( del /q xar.exe ) + if exist xar ( del /q xar ) + +xar.exe: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ diff --git a/Makefile.wcd b/Makefile.wcd new file mode 100644 index 0000000..8d1c0ca --- /dev/null +++ b/Makefile.wcd @@ -0,0 +1,21 @@ +#****************************************************************************** +# @file Makefile.wcd +# +# Produce MSDOS executables links with PDPCLIB created by makefile.wcd +#****************************************************************************** +CC=wcl +COPTS=-ecc -q -w -c -ml -zl -D__MSDOS__ -D__PDOS__ -fpi87 -s -zdp -zu -I. -I..\pdos\pdpclib + +all: clean xar.exe + +xar.exe: append.obj ar.obj conv.obj delete.obj display.obj extract.obj lib.obj ranlib,obj replace.obj report.obj + wlink File ar.obj Name xar.exe Form dos Library temp.lib,..\pdos\pdpclib\watcom.lib Option quiet,map + +.c.obj: + $(CC) $(COPTS) $< + wlib -b -q temp +$*.obj + +clean: + rm -f *.obj + rm -f xar.exe + rm -f temp.lib diff --git a/README.md b/README.md new file mode 100644 index 0000000..9433d5b --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +All source code is Public Domain. + +## Obtain the source code + + git clone https://git.candlhat.org/xar.git + +## Building + + BSD: + + Make sure you have gcc and gmake installed then run gmake -f Makefile.unix. + + Linux: + + Make sure you have gcc and make installed then run make -f Makefile.unix. + + macOS: + + Make sure you have xcode command line tools installed then run make -f Makefile.unix. + + Windows: + + Make sure you have mingw installed and the location within your PATH variable then run mingw32-make.exe -f Makefile.w32. diff --git a/append.c b/append.c new file mode 100644 index 0000000..bab69e9 --- /dev/null +++ b/append.c @@ -0,0 +1,153 @@ +/****************************************************************************** + * @file append.c + *****************************************************************************/ +#include +#include +#include + +#include "ar.h" +#include "lib.h" +#include "report.h" + +void append (FILE *ofp, char *fname) { + + unsigned char aout_magic[2]; + FILE *tfp; + + struct ar_header header; + char temp[17]; + + char *p, *name = fname, *contents; + long bytes, len, read; + + int need_newline = 0; + int valid = 0; + + if ((tfp = fopen (fname, "r+b")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open %s", fname); + return; + + } + + if (fread (aout_magic, 2, 1, tfp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", fname); + return; + + } + + valid = ((aout_magic[0] == 0x07 && aout_magic[1] == 0x01) || (aout_magic[0] == 0x4C && aout_magic[1] == 0x01) || (aout_magic[0] == 0x64 && aout_magic[1] == 0x86)); + + if (!valid) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "%s is not a valid a.out or coff object", fname); + return; + + } + + memset (temp, 0x20, 16); + temp[0] = '0'; + + if ((p = strrchr (fname, '/'))) { + name = (p + 1); + } + + len = strlen (name); + + if (len > 16) { + len = 16; + } + + memcpy (header.name, name, len); + + while (len < 16) { + header.name[len++] = 0x20; + } + + memcpy (header.mtime, temp, 12); + memcpy (header.owner, temp, 6); + memcpy (header.group, temp, 6); + memcpy (header.mode, temp, 8); + + fseek (tfp, 0, SEEK_END); + bytes = ftell (tfp); + + len = sprintf (temp, "%ld", bytes); + temp[len] = 0x20; + + memcpy (header.size, temp, 10); + + header.endsig[0] = 0x60; + header.endsig[1] = 0x0A; + + need_newline = (bytes % 2); + + if (fwrite (&header, sizeof (header), 1, ofp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header"); + return; + + } + + contents = xmalloc (512); + fseek (tfp, 0, SEEK_SET); + + for (;;) { + + if (bytes == 0 || feof (tfp)) { + break; + } else if (bytes >= 512) { + read = 512; + } else { + read = bytes; + } + + if (fread (contents, read, 1, tfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", fname); + return; + + } + + bytes -= read; + + if (fwrite (contents, read, 1, ofp) != 1) { + + free (contents); + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing %s to archive", fname); + return; + + } + + } + + free (contents); + + if (need_newline) { + + temp[0] = 0x0A; + + if (fwrite (temp, 1, 1, ofp) != 1) { + + fclose (tfp); + exit (EXIT_FAILURE); + + } + + } + + fclose (tfp); + +} diff --git a/ar.c b/ar.c new file mode 100644 index 0000000..65b823e --- /dev/null +++ b/ar.c @@ -0,0 +1,129 @@ +/****************************************************************************** + * @file ar.c + *****************************************************************************/ +#include +#include +#include + +#include "ar.h" +#include "lib.h" +#include "report.h" +#include "stdint.h" + +struct ar_state *state = 0; +const char *program_name = 0; + +FILE *arfp = NULL; + +int main (int argc, char **argv) { + + char ar_magic[8]; + long i; + + if (argc && *argv) { + + char *p; + program_name = *argv; + + if ((p = strrchr (program_name, '/'))) { + program_name = (p + 1); + } + + } + + state = xmalloc (sizeof (*state)); + parse_args (&argc, &argv, 1); + + if (state->append || state->replace) { + + if ((arfp = fopen (state->outfile, "r+b")) == NULL) { + + if ((arfp = fopen (state->outfile, "w+b")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to create %s", state->outfile); + return EXIT_FAILURE; + + } + + if (fwrite ("!\n", 8, 1, arfp) != 1) { + + fclose (arfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing to %s", state->outfile); + return EXIT_FAILURE; + + } + + } + + fclose (arfp); + + } + + if ((arfp = fopen (state->outfile, "r+b")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open %s", state->outfile); + return EXIT_FAILURE; + + } + + if (fread (ar_magic, 8, 1, arfp) != 1) { + + fclose (arfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", state->outfile); + return EXIT_FAILURE; + + } + + if (memcmp ("!\n", ar_magic, 8)) { + + fclose (arfp); + + report_at (program_name, 0, REPORT_ERROR, "%s is not a valid archive file", state->outfile); + return EXIT_FAILURE; + + } + + for (i = 0; i < state->nb_files; ++i) { + + if (state->append) { + + fseek (arfp, 0, SEEK_END); + append (arfp, state->files[i]); + + } else if (state->replace) { + + fseek (arfp, 8, SEEK_SET); + replace (state->files[i]); + + } else if (state->del) { + + fseek (arfp, 8, SEEK_SET); + delete (state->files[i]); + + } else if (state->extract) { + + fseek (arfp, 8, SEEK_SET); + extract (state->files[0]); + + } + + } + + if (state->display) { + + fseek (arfp, 8, SEEK_SET); + display (); + + } else if (state->ranlib) { + + fseek (arfp, 8, SEEK_SET); + ranlib (); + + } + + fclose (arfp); + return EXIT_SUCCESS; + +} diff --git a/ar.h b/ar.h new file mode 100644 index 0000000..2831f3b --- /dev/null +++ b/ar.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * @file ar.h + *****************************************************************************/ +#ifndef _AR_H +#define _AR_H + +struct ar_state { + + char **files; + long nb_files; + + const char *outfile; + + int del, move, print; + int append, replace, ranlib; + int display, extract; + +}; + +extern struct ar_state *state; +extern const char *program_name; + +struct ar_header { + + char name[16]; + char mtime[12]; + char owner[6]; + char group[6]; + char mode[8]; + char size[10]; + char endsig[2]; + +}; + +#include + +#include "stdint.h" + +extern FILE *arfp; +uint32_t conv_dec (char *str, int32_t max); + +void append (FILE *ofp, char *fname); +void delete (char *fname); +void display (void); +void extract (char *fname); +void ranlib (void); +void replace (char *fname); + +#endif /* _AR_H */ diff --git a/conv.c b/conv.c new file mode 100644 index 0000000..f8267ab --- /dev/null +++ b/conv.c @@ -0,0 +1,19 @@ +/****************************************************************************** + * @file conv.c + *****************************************************************************/ +#include "stdint.h" + +uint32_t conv_dec (char *str, int32_t max) { + + uint32_t value = 0; + + while (*str != ' ' && max-- > 0) { + + value *= 10; + value += *str++ - '0'; + + } + + return value; + +} diff --git a/delete.c b/delete.c new file mode 100644 index 0000000..e190ce0 --- /dev/null +++ b/delete.c @@ -0,0 +1,182 @@ +/****************************************************************************** + * @file delete.c + *****************************************************************************/ +#include +#include +#include + +#include "ar.h" +#include "lib.h" +#include "report.h" + +void delete (char *fname) { + + FILE *tfp = tmpfile (); + + char temp[17], *name, *p, *contents; + long bytes, len, read; + + if (fwrite ("!\x0A", 8, 1, tfp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whist writing ar header"); + return; + + } + + name = fname; + + if ((p = strrchr (fname, '/'))) { + name = (p + 1); + } + + len = strlen (name); + + if (len > 16) { + len = 16; + } + + memcpy (temp, name, len); + temp[len] = '\0'; + + for (;;) { + + struct ar_header hdr; + + if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) { + + if (feof (arfp)) { + break; + } + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile); + return; + + } + + bytes = conv_dec (hdr.size, 10); + + if (bytes % 2) { + bytes++; + } + + if (memcmp (hdr.name, "/", 1) == 0) { + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + if (memcmp (hdr.name, temp, len) == 0) { + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + if (fwrite (&hdr, sizeof (hdr), 1, tfp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header"); + exit (EXIT_FAILURE); + + } + + contents = xmalloc (512); + + for (;;) { + + if (bytes == 0 || feof (arfp)) { + break; + } else if (bytes >= 512) { + read = 512; + } else { + read = bytes; + } + + if (fread (contents, read, 1, arfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (NULL, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile); + exit (EXIT_FAILURE); + + } + + bytes -= read; + + if (fwrite (contents, read, 1, tfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (NULL, 0, REPORT_ERROR, "failed to write temp file"); + exit (EXIT_FAILURE); + + } + + } + + free (contents); + + } + + fclose (arfp); + remove (state->outfile); + + if ((arfp = fopen (state->outfile, "w+b")) == NULL) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed to open %s for writing", state->outfile); + exit (EXIT_FAILURE); + + } + + contents = xmalloc (512); + bytes = ftell (tfp); + + fseek (arfp, 0, SEEK_SET); + fseek (tfp, 0, SEEK_SET); + + for (;;) { + + if (bytes == 0 || feof (tfp)) { + break; + } else if (bytes >= 512) { + read = 512; + } else { + read = bytes; + } + + if (fread (contents, read, 1, tfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading temp file"); + return; + + } + + bytes -= read; + + if (fwrite (contents, read, 1, arfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whist writing %s", state->outfile); + exit (EXIT_FAILURE); + + } + + } + + free (contents); + fclose (tfp); + +} diff --git a/display.c b/display.c new file mode 100644 index 0000000..7038961 --- /dev/null +++ b/display.c @@ -0,0 +1,57 @@ +/****************************************************************************** + * @file display.c + *****************************************************************************/ +#include +#include + +#include "ar.h" +#include "report.h" + +void display (void) { + + char temp[17] = { 0 }; + int i; + + for (;;) { + + struct ar_header hdr; + long bytes; + + if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) { + + if (feof (arfp)) { + break; + } + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile); + return; + + } + + bytes = conv_dec (hdr.size, 10); + + if (bytes % 2) { + bytes++; + } + + fseek (arfp, bytes, SEEK_CUR); + + if (memcmp (hdr.name, "/", 1) == 0) { + continue; + } + + memcpy (temp, hdr.name, 16); + + for (i = 16; i >= 0; --i) { + + if (temp[i] == 0x20) { + temp[i] = '\0'; + } + + } + + printf ("%s\n", temp); + + } + +} diff --git a/extract.c b/extract.c new file mode 100644 index 0000000..18fd2c6 --- /dev/null +++ b/extract.c @@ -0,0 +1,120 @@ +/****************************************************************************** + * @file extract.c + *****************************************************************************/ +#include +#include +#include + +#include "ar.h" +#include "lib.h" +#include "report.h" + +void extract (char *fname) { + + FILE *ofp; + + char temp[17], *name, *p, *contents; + long bytes, len, read; + + name = fname; + + if ((p = strrchr (fname, '/'))) { + name = (p + 1); + } + + len = strlen (name); + + if (len > 16) { + len = 16; + } + + memcpy (temp, name, len); + temp[len] = '\0'; + + for (;;) { + + struct ar_header hdr; + + if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) { + + if (feof (arfp)) { + break; + } + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile); + return; + + } + + bytes = conv_dec (hdr.size, 10); + + if (memcmp (hdr.name, "/", 1) == 0) { + + if (bytes % 2) { + bytes++; + } + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + if (memcmp (hdr.name, temp, len) != 0) { + + if (bytes % 2) { + bytes++; + } + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + if ((ofp = fopen (temp, "w+b")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open %s for writing", temp); + exit (EXIT_FAILURE); + + } + + contents = xmalloc (512); + + for (;;) { + + if (bytes == 0 || feof (arfp)) { + break; + } else if (bytes >= 512) { + read = 512; + } else { + read = bytes; + } + + if (fread (contents, read, 1, arfp) != 1) { + + free (contents); + fclose (ofp); + + report_at (NULL, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile); + exit (EXIT_FAILURE); + + } + + bytes -= read; + + if (fwrite (contents, read, 1, ofp) != 1) { + + free (contents); + fclose (ofp); + + report_at (NULL, 0, REPORT_ERROR, "failed to write %s file", temp); + exit (EXIT_FAILURE); + + } + + } + + free (contents); + + } + +} diff --git a/lib.c b/lib.c new file mode 100644 index 0000000..aa774d8 --- /dev/null +++ b/lib.c @@ -0,0 +1,200 @@ +/****************************************************************************** + * @file lib.c + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "ar.h" +#include "lib.h" +#include "report.h" +#include "stdint.h" + +static void print_help (void) { + + if (!program_name) { + goto _exit; + } + + fprintf (stderr, "Usage: %s command archive-file file...\n", program_name); + fprintf (stderr, "Commands:\n\n"); + + fprintf (stderr, " d delete file(s) from the archive\n"); + fprintf (stderr, " q quick append file(s) to the archive\n"); + fprintf (stderr, " r replace existing or insert new file(s) into the archive\n"); + fprintf (stderr, " s act as ranlib\n"); + fprintf (stderr, " t display contents of the archive\n"); + fprintf (stderr, " x extract file(s) from the archive\n"); + + fprintf (stderr, "\n"); + +_exit: + + exit (EXIT_SUCCESS); + +} + +char *xstrdup (const char *str) { + + char *ptr = xmalloc (strlen (str) + 1); + strcpy (ptr, str); + + return ptr; + +} + +void *xmalloc (unsigned long size) { + + void *ptr = malloc (size); + + if (ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)"); + exit (EXIT_FAILURE); + + } + + memset (ptr, 0, size); + return ptr; + +} + +void *xrealloc (void *ptr, unsigned long size) { + + void *new_ptr = realloc (ptr, size); + + if (new_ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)"); + exit (EXIT_FAILURE); + + } + + return new_ptr; + +} + +void dynarray_add (void *ptab, long *nb_ptr, void *data) { + + int32_t nb, nb_alloc; + void **pp; + + nb = *nb_ptr; + pp = *(void ***) ptab; + + if ((nb & (nb - 1)) == 0) { + + if (!nb) { + nb_alloc = 1; + } else { + nb_alloc = nb * 2; + } + + pp = xrealloc (pp, nb_alloc * sizeof (void *)); + *(void ***) ptab = pp; + + } + + pp[nb++] = data; + *nb_ptr = nb; + +} + +void parse_args (int *pargc, char ***pargv, int optind) { + + char **argv = *pargv; + int argc = *pargc; + + const char *r; + + if (argc < 3) { + print_help (); + } + + r = argv[optind++]; + +check_options: + + if (r[0] == '-') { + ++r; + } + + while (*r != '\0') { + + char ch = *r++; + + if (ch == 'd') { + + state->del++; + continue; + + } + + if (ch == 'm') { + + state->move++; + continue; + + } + + if (ch == 'p') { + + state->print++; + continue; + + } + + if (ch == 'q') { + + state->append++; + continue; + + } + + if (ch == 'r') { + + state->replace++; + continue; + + } + + if (ch == 's') { + + state->ranlib++; + continue; + + } + + if (ch == 't') { + + state->display++; + continue; + + } + + if (ch == 'x') { + + state->extract++; + continue; + + } + + print_help (); + + } + + if (*(r = argv[optind++]) == '-') { goto check_options; } + + if (state->append + state->del + state->display + state->extract + state->move + state->print + state->ranlib + state->replace != 1) { + print_help (); + } + + state->outfile = xstrdup (r); + + while (optind < argc) { + dynarray_add (&state->files, &state->nb_files, xstrdup (argv[optind++])); + } + +} diff --git a/lib.h b/lib.h new file mode 100644 index 0000000..d1adb09 --- /dev/null +++ b/lib.h @@ -0,0 +1,15 @@ +/****************************************************************************** + * @file lib.h + *****************************************************************************/ +#ifndef _LIB_H +#define _LIB_H + +char *xstrdup (const char *str); + +void *xmalloc (unsigned long size); +void *xrealloc (void *ptr, unsigned long size); + +void dynarray_add (void *ptab, long *nb_ptr, void *data); +void parse_args (int *pargc, char ***pargv, int optind); + +#endif /* _LIB_H */ diff --git a/makefile.slp b/makefile.slp new file mode 100644 index 0000000..1749ae7 --- /dev/null +++ b/makefile.slp @@ -0,0 +1,26 @@ +# This builds the Linux 32-bit ELF executable + +AS=pdas --oformat coff +CC=gccwin +LD=pdld + +COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib \ + -U__WIN32__ -D__NOBIVA__ -D__PDOS__ \ + -D__gnu_linux__ +LDFLAGS=-s --no-insert-timestamp -nostdlib --oformat elf --emit-relocs + +COBJ=append.obj ar.obj conv.obj delete.obj display.obj extract.obj \ + lib.obj ranlib.obj replace.obj report.obj + +all: clean xar.exe + +xar.exe: $(COBJ) + $(LD) $(LDFLAGS) -o xar.exe ../pdos/pdpclib/linstart.o $(COBJ) ../pdos/pdpclib/pdplinux.a + +.c.obj: + $(CC) $(COPTS) $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + rm -f *.obj xar.exe diff --git a/makefile.sos b/makefile.sos new file mode 100644 index 0000000..18ae6f6 --- /dev/null +++ b/makefile.sos @@ -0,0 +1,29 @@ +# This builds the OS/2 32-bit version +# You will need to build PDPCLIB with the USE_MEMMGR +# option because this program does lots of small memory allocations + +AS=pdas --oformat coff +CC=gccwin +LD=pdld + +COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib \ + -U__WIN32__ -D__NOBIVA__ -D__PDOS__ \ + -D__HAVESYS__=_System -D__OS2__ -D__32BIT__ +LDFLAGS=-s --no-insert-timestamp -nostdlib --oformat lx \ + --stub ../pdos/pdpclib/needpdos.exe + +COBJ=append.obj ar.obj conv.obj delete.obj display.obj extract.obj \ + lib.obj ranlib.obj replace.obj report.obj + +all: clean xar.exe + +xar.exe: $(COBJ) + $(LD) $(LDFLAGS) -o xar.exe ../pdos/pdpclib/os2strt.obj $(COBJ) ../pdos/pdpclib/pdpos2.lib ../pdos/pdpclib/os2.lib + +.c.obj: + $(CC) $(COPTS) $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + rm -f *.obj xar.exe diff --git a/makefile.std b/makefile.std new file mode 100644 index 0000000..ddfb016 --- /dev/null +++ b/makefile.std @@ -0,0 +1,20 @@ +AS=pdas --oformat coff +CC=gccwin +LD=pdld + +COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__ +COBJ=append.obj ar.obj conv.obj delete.obj display.obj extract.obj \ + lib.obj ranlib.obj replace.obj report.obj + +all: clean xar.exe + +xar.exe: $(COBJ) + $(LD) -s -nostdlib --no-insert-timestamp -o xar.exe ../pdos/pdpclib/w32start.obj $(COBJ) ../pdos/pdpclib/msvcrt.lib + +.c.obj: + $(CC) $(COPTS) $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + rm -f *.o xar.exe diff --git a/ranlib.c b/ranlib.c new file mode 100644 index 0000000..3a88817 --- /dev/null +++ b/ranlib.c @@ -0,0 +1,541 @@ +/****************************************************************************** + * @file ranlib.c + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "ar.h" +#include "lib.h" +#include "report.h" + +#define GET_INT32(arr) ((int32_t) arr[0] | (((int32_t) arr[1]) << 8) | (((int32_t) arr[2]) << 16) | (((int32_t) arr[3]) << 24)) + +#define GET_UINT16(arr) ((uint32_t) arr[0] | (((uint32_t) arr[1]) << 8)) +#define GET_UINT32(arr) ((uint32_t) arr[0] | (((uint32_t) arr[1]) << 8) | (((uint32_t) arr[2]) << 16) | (((uint32_t) arr[3]) << 24)) + +struct aout_exec { + + unsigned char a_info[4]; + unsigned char a_text[4]; + unsigned char a_data[4]; + unsigned char a_bss[4]; + unsigned char a_syms[4]; + unsigned char a_entry[4]; + unsigned char a_trsize[4]; + unsigned char a_drsize[4]; + +}; + +struct aout_nlist { + + unsigned char n_strx[4]; + unsigned char n_type; + + unsigned char n_other; + unsigned char n_desc[2]; + + unsigned char n_value[4]; + +}; + +struct coff_exec { + + unsigned char Machine[2]; + unsigned char NumberOfSections[2]; + + unsigned char TimeDateStamp[4]; + unsigned char PointerToSymbolTable[4]; + unsigned char NumberOfSymbols[4]; + + unsigned char SizeOfOptionalHeader[2]; + unsigned char Characteristics[2]; + +}; + +struct coff_symbol { + + char Name[8]; + unsigned char Value[4]; + + unsigned char SectionNumber[2]; + unsigned char Type[2]; + + unsigned char StorageClass[1]; + unsigned char NumberOfAuxSymbols[1]; + +}; + +struct strtab { + + const char *name; + long length, offset; + +}; + +struct gstrtab { + + long count, max; + struct strtab *strtabs; + +}; + +static struct gstrtab gstrtab = { 0, 64, NULL }; + +static int add_strtab (struct gstrtab *gstrtab, struct strtab *strtab) { + + if (gstrtab->strtabs == NULL) { + + if ((gstrtab->strtabs = malloc (gstrtab->max * sizeof (*strtab))) == NULL) { + return 1; + } + + } + + if (gstrtab->count >= gstrtab->max) { + + void *tmp; + + gstrtab->max *= 2; + + if ((tmp = realloc (gstrtab->strtabs, gstrtab->max * sizeof (*strtab))) == NULL) { + return 1; + } + + gstrtab->strtabs = tmp; + + } + + gstrtab->strtabs[gstrtab->count] = *strtab; + gstrtab->count++; + + return 0; + +} + +static void aout_get_symbols (void *object, long offset) { + + struct aout_exec *hdr = (struct aout_exec *) object; + + long sym_start = sizeof (*hdr) + GET_UINT32 (hdr->a_text) + GET_UINT32 (hdr->a_data) + GET_UINT32 (hdr->a_trsize) + GET_UINT32 (hdr->a_drsize); + long strtab_start = sym_start + GET_UINT32 (hdr->a_syms); + + while (sym_start < strtab_start) { + + struct aout_nlist nlist; + memcpy (&nlist, (char *) object + sym_start, sizeof (nlist)); + + if (nlist.n_type == 5 || nlist.n_type == 7 || nlist.n_type == 9) { + + struct strtab *strtab; + char *symname = (char *) object + strtab_start + GET_INT32 (nlist.n_strx); + + strtab = xmalloc (sizeof (*strtab)); + strtab->length = strlen (symname); + + strtab->name = xstrdup (symname); + strtab->offset = offset; + + add_strtab (&gstrtab, strtab); + + } + + sym_start += sizeof (nlist); + + } + +} + +static void coff_get_symbols (void *object, long offset) { + + struct coff_exec *hdr = (struct coff_exec *) object; + + long sym_start = GET_UINT32 (hdr->PointerToSymbolTable); + long sym_cnt = GET_UINT32 (hdr->NumberOfSymbols); + long string_table_start = sym_start + (sizeof (struct coff_symbol) * sym_cnt); + + while (sym_cnt--) { + + struct coff_symbol sym; + memcpy (&sym, (char *) object + sym_start, sizeof (sym)); + + if (sym.StorageClass[0] == 2 && GET_UINT16 (sym.SectionNumber) != 0) { + + struct strtab *strtab; + + if (sym.Name[0] != 0) { + + int i, len; + + for (i = 0, len = 0; i < 8; i++) { + + if (sym.Name[i] == '\0') { + break; + } + + len++; + + } + + strtab = xmalloc (sizeof (*strtab)); + strtab->length = len; + + strtab->name = xstrdup (sym.Name); + strtab->offset = offset; + + add_strtab (&gstrtab, strtab); + + } else { + + unsigned char offset1 = (unsigned char) sym.Name[4]; + unsigned char offset2 = (unsigned char) sym.Name[5]; + unsigned char offset3 = (unsigned char) sym.Name[6]; + unsigned char offset4 = (unsigned char) sym.Name[7]; + + long final_offset = ((uint32_t) offset1 | (((uint32_t) offset2) << 8) | (((uint32_t) offset3) << 16) | (((uint32_t) offset4) << 24)); + final_offset += string_table_start; + + strtab = xmalloc (sizeof (*strtab)); + strtab->length = strlen ((char *) object + final_offset); + + strtab->name = xstrdup ((char *) object + final_offset); + strtab->offset = offset; + + add_strtab (&gstrtab, strtab); + + } + + } + + sym_start += sizeof (sym); + + } + +} + +void ranlib (void) { + + FILE *tfp = tmpfile (); + long offset = 0; + + struct ar_header header; + long bytes, i, j, len, read, val; + + unsigned char *object; + void *contents; + + char temp[16]; + int valid = 0; + + for (;;) { + + struct ar_header hdr; + long bytes; + + if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) { + + if (feof (arfp)) { + break; + } + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile); + return; + + } + + bytes = conv_dec (hdr.size, 10); + + if (bytes % 2) { + bytes++; + } + + if (memcmp (hdr.name, "/", 1) == 0) { + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + object = xmalloc (bytes); + + if (fread (object, bytes, 1, arfp) != 1) { + + free (object); + + report_at (program_name, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile); + exit (EXIT_FAILURE); + + + } + + valid = ((object[0] == 0x07 && object[1] == 0x01) || (object[0] == 0x4C && object[1] == 0x01) || (object[0] == 0x64 && object[1] == 0x86)); + + if (!valid) { + + free (object); + + offset += sizeof (hdr); + offset += bytes; + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + if (object[0] == 0x07 && object[1] == 0x01) { + aout_get_symbols (object, offset + 8); + } else { + coff_get_symbols (object, offset + 8); + } + + free (object); + + offset += sizeof (hdr); + offset += bytes; + + } + + fseek (arfp, 8, SEEK_SET); + bytes = 0; + + for (i = 0; i < gstrtab.count; ++i) { + bytes += gstrtab.strtabs[i].length + 5; + } + + for (i = 0; i < gstrtab.count; ++i) { + + gstrtab.strtabs[i].offset += bytes; + + if (bytes % 2) { + gstrtab.strtabs[i].offset++; + } + + } + + if (fwrite ("!\x0A", 8, 1, tfp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whist writing ar header"); + return; + + } + + memset (temp, 0x20, 16); + temp[0] = '0'; + + len = 1; + memcpy (header.name, "/", len); + + while (len < 16) { + header.name[len++] = 0x20; + } + + memcpy (header.mtime, temp, 12); + memcpy (header.owner, temp, 6); + memcpy (header.group, temp, 6); + memcpy (header.mode, temp, 8); + + len = sprintf (temp, "%ld", bytes + 4); + temp[len] = 0x20; + + memcpy (header.size, temp, 10); + + header.endsig[0] = 0x60; + header.endsig[1] = 0x0A; + + if (fwrite (&header, sizeof (header), 1, tfp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header"); + return; + + } + + val = gstrtab.count; + + for (i = 0; i < 4; ++i) { + temp[4 - 1 - i] = (val >> (CHAR_BIT * i)) & UCHAR_MAX; + } + + if (fwrite (temp, 4, 1, tfp) != 1) { + exit (EXIT_FAILURE); + } + + for (i = 0; i < gstrtab.count; ++i) { + + val = gstrtab.strtabs[i].offset + 4 + sizeof (header); + + for (j = 0; j < 4; ++j) { + temp[4 - 1 - j] = (val >> (CHAR_BIT * j)) & UCHAR_MAX; + } + + if (fwrite (temp, 4, 1, tfp) != 1) { + exit (EXIT_FAILURE); + } + + } + + for (i = 0; i < gstrtab.count; ++i) { + + const char *name = gstrtab.strtabs[i].name; + long length = gstrtab.strtabs[i].length; + + if (fwrite (name, length, 1, tfp) != 1) { + exit (EXIT_FAILURE); + } + + temp[0] = '\0'; + + if (fwrite (temp, 1, 1, tfp) != 1) { + exit (EXIT_FAILURE); + } + + } + + if (bytes % 2) { + + temp[0] = '\0'; + + if (fwrite (temp, 1, 1, tfp) != 1) { + exit (EXIT_FAILURE); + } + + } + + for (;;) { + + struct ar_header hdr; + + if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) { + + if (feof (arfp)) { + break; + } + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile); + return; + + } + + bytes = conv_dec (hdr.size, 10); + + if (bytes % 2) { + bytes++; + } + + if (memcmp (hdr.name, "/", 1) == 0) { + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + if (fwrite (&hdr, sizeof (hdr), 1, tfp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header"); + exit (EXIT_FAILURE); + + } + + contents = xmalloc (512); + + for (;;) { + + if (bytes == 0 || feof (arfp)) { + break; + } else if (bytes >= 512) { + read = 512; + } else { + read = bytes; + } + + if (fread (contents, read, 1, arfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (NULL, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile); + exit (EXIT_FAILURE); + + } + + bytes -= read; + + if (fwrite (contents, read, 1, tfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (NULL, 0, REPORT_ERROR, "failed to write temp file"); + exit (EXIT_FAILURE); + + } + + } + + free (contents); + + } + + fclose (arfp); + remove (state->outfile); + + if ((arfp = fopen (state->outfile, "w+b")) == NULL) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed to open %s for writing", state->outfile); + exit (EXIT_FAILURE); + + } + + contents = xmalloc (512); + bytes = ftell (tfp); + + fseek (arfp, 0, SEEK_SET); + fseek (tfp, 0, SEEK_SET); + + for (;;) { + + if (bytes == 0 || feof (tfp)) { + break; + } else if (bytes >= 512) { + read = 512; + } else { + read = bytes; + } + + if (fread (contents, read, 1, tfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading temp file"); + return; + + } + + bytes -= read; + + if (fwrite (contents, read, 1, arfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whist writing %s", state->outfile); + exit (EXIT_FAILURE); + + } + + } + + free (contents); + fclose (tfp); + +} diff --git a/replace.c b/replace.c new file mode 100644 index 0000000..3df068c --- /dev/null +++ b/replace.c @@ -0,0 +1,192 @@ +/****************************************************************************** + * @file replace.c + *****************************************************************************/ +#include +#include +#include + +#include "ar.h" +#include "lib.h" +#include "report.h" + +void replace (char *fname) { + + FILE *tfp = tmpfile (); + + char temp[17], *name, *p, *contents; + long bytes, len, read; + + if (fwrite ("!\x0A", 8, 1, tfp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whist writing ar header"); + return; + + } + + name = fname; + + if ((p = strrchr (fname, '/'))) { + name = (p + 1); + } + + len = strlen (name); + + if (len > 16) { + len = 16; + } + + memcpy (temp, name, len); + temp[len] = '\0'; + + state->append = 1; + + for (;;) { + + struct ar_header hdr; + + if (fread (&hdr, sizeof (hdr), 1, arfp) != 1) { + + if (feof (arfp)) { + break; + } + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", state->outfile); + return; + + } + + bytes = conv_dec (hdr.size, 10); + + if (bytes % 2) { + bytes++; + } + + if (memcmp (hdr.name, "/", 1) == 0) { + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + if (memcmp (hdr.name, temp, len) == 0) { + + state->append = 0; + append (tfp, fname); + + fseek (arfp, bytes, SEEK_CUR); + continue; + + } + + if (fwrite (&hdr, sizeof (hdr), 1, tfp) != 1) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing header"); + exit (EXIT_FAILURE); + + } + + contents = xmalloc (512); + + for (;;) { + + if (bytes == 0 || feof (arfp)) { + break; + } else if (bytes >= 512) { + read = 512;; + } else { + read = bytes; + } + + if (fread (contents, read, 1, arfp) != 1) { + + free (contents); + + report_at (NULL, 0, REPORT_ERROR, "failed to read %ld bytes from %s", bytes, state->outfile); + exit (EXIT_FAILURE); + + } + + bytes -= read; + + if (fwrite (contents, read, 1, tfp) != 1) { + + free (contents); + + report_at (NULL, 0, REPORT_ERROR, "failed to write temp file"); + exit (EXIT_FAILURE); + + } + + } + + free (contents); + + } + + if (state->append) { + + state->append = 0; + append (tfp, fname); + + } + + fclose (arfp); + remove (state->outfile); + + if ((arfp = fopen (state->outfile, "w+b")) == NULL) { + + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed to open %s", state->outfile); + exit (EXIT_FAILURE); + + } + + contents = xmalloc (512); + bytes = ftell (tfp); + + fseek (arfp, 0, SEEK_SET); + fseek (tfp, 0, SEEK_SET); + + for (;;) { + + if (bytes == 0 || feof (tfp)) { + break; + } else if (bytes >= 512) { + read = 512; + } else { + read = bytes; + } + + if (fread (contents, read, 1, tfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading temp file"); + return; + + } + + bytes -= read; + + if (fwrite (contents, read, 1, arfp) != 1) { + + free (contents); + fclose (tfp); + + report_at (program_name, 0, REPORT_ERROR, "failed whist writing %s", state->outfile); + exit (EXIT_FAILURE); + + } + + } + + free (contents); + fclose (tfp); + +} diff --git a/report.c b/report.c new file mode 100644 index 0000000..14ad2f6 --- /dev/null +++ b/report.c @@ -0,0 +1,125 @@ +/****************************************************************************** + * @file report.c + *****************************************************************************/ +#include +#include + +#include "report.h" + +#ifndef __PDOS__ +#if defined (_WIN32) +# include +static int OriginalConsoleColor = -1; +#endif + +static void reset_console_color (void) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + + if (OriginalConsoleColor == -1) { return; } + + SetConsoleTextAttribute (hStdError, OriginalConsoleColor); + OriginalConsoleColor = -1; + +#else + + fprintf (stderr, "\033[0m"); + +#endif + +} + +static void set_console_color (int color) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + WORD wColor; + + if (OriginalConsoleColor == -1) { + + CONSOLE_SCREEN_BUFFER_INFO csbi; + + if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) { + return; + } + + OriginalConsoleColor = csbi.wAttributes; + + } + + wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF); + SetConsoleTextAttribute (hStdError, wColor); + +#else + + fprintf (stderr, "\033[%dm", color); + +#endif + +} +#endif + +void report_at (const char *filename, unsigned long line_number, int type, const char *fmt, ...) { + + va_list ap; + + if (filename) { + + if (line_number == 0) { + fprintf (stderr, "%s: ", filename); + } else { + fprintf (stderr, "%s:", filename); + } + + } + + if (line_number > 0) { + fprintf (stderr, "%lu: ", line_number); + } + + if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_ERROR); +#endif + + if (type == REPORT_ERROR) { + fprintf (stderr, "error:"); + } else { + fprintf (stderr, "fatal error:"); + } + + } else if (type == REPORT_INTERNAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_INTERNAL_ERROR); +#endif + + fprintf (stderr, "internal error:"); + + } else if (type == REPORT_WARNING) { + +#ifndef __PDOS__ + set_console_color (COLOR_WARNING); +#endif + + fprintf (stderr, "warning:"); + + } + +#ifndef __PDOS__ + reset_console_color (); +#endif + + fprintf (stderr, " "); + + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + + fprintf (stderr, "\n"); + +} diff --git a/report.h b/report.h new file mode 100644 index 0000000..bdd121e --- /dev/null +++ b/report.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * @file report.h + *****************************************************************************/ +#ifndef _REPORT_H +#define _REPORT_H + +enum { + + REPORT_ERROR = 0, + REPORT_FATAL_ERROR, + REPORT_INTERNAL_ERROR, + REPORT_WARNING + +}; + +#if defined (_WIN32) +# define COLOR_ERROR 12 +# define COLOR_WARNING 13 +# define COLOR_INTERNAL_ERROR 19 +#else +# define COLOR_ERROR 91 +# define COLOR_INTERNAL_ERROR 94 +# define COLOR_WARNING 95 +#endif + +void report_at (const char *filename, unsigned long line_number, int type, const char *fmt, ...); + +#endif /* _REPORT_H */ diff --git a/stdint.h b/stdint.h new file mode 100644 index 0000000..f4b18c0 --- /dev/null +++ b/stdint.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * @file stdint.h + *****************************************************************************/ +#ifndef _STDINT_H +#define _STDINT_H + +#include + +typedef signed char int8_t; +typedef unsigned char uint8_t; + +typedef signed short int16_t; +typedef unsigned short uint16_t; + +#if INT_MAX == 32767 +typedef signed long int32_t; +typedef unsigned long uint32_t; +#else +typedef signed int int32_t; +typedef unsigned int uint32_t; +#endif + +#endif /* _STDINT_H */ -- 2.34.1