--- /dev/null
+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 <https://unlicense.org>
--- /dev/null
+#******************************************************************************
+# @file Makefile.pdw
+#******************************************************************************
+AS=aswin
+CC=gccwin
+LD=ldwin
+
+COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__WIN32__ -D__NOBIVA__ -D__PDOS__
+COBJ=lib.o report.o rm.o
+
+all: clean rm.exe
+
+rm.exe: $(COBJ)
+ $(LD) -s -o rm.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a ../pdos/src/kernel32.a
+
+.c.o:
+ $(CC) $(COPTS) -o $*.s $<
+ $(AS) -o $@ $*.s
+ rm -f $*.s
+
+clean:
+ rm -f $(OBJ)
+ rm -f rm.exe
--- /dev/null
+#******************************************************************************
+# @file Makefile.w32
+#******************************************************************************
+SRCDIR ?= $(CURDIR)
+VPATH := $(SRCDIR)
+
+CC := gcc
+CFLAGS := -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90
+
+CSRC := lib.c report.c rm.c
+
+all: rm.exe
+
+clean:
+
+ if exist rm.exe ( del /q rm.exe )
+ if exist rm ( del /q rm )
+
+rm.exe: $(CSRC)
+
+ $(CC) $(CFLAGS) -o $@ $^
--- /dev/null
+## Licesne
+
+ All source code is Public Domain.
+
+## Obtain the source code
+
+ git clone https://git.candlhat.org/rm.git
+
+## Building
+
+ Windows:
+
+ Make sure you have mingw installed and the location within your PATH variable
+ then run mingw32-make.exe -f Makefile.w32.
--- /dev/null
+/******************************************************************************
+ * @file lib.c
+ *****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rm.h"
+#include "lib.h"
+#include "report.h"
+
+static void print_usage (void) {
+
+ if (program_name) {
+ fprintf (stderr, "Usage: %s [options] file...\n\n", program_name);
+ }
+
+}
+
+static void dynarray_add (void *ptab, long *nb_ptr, void *data) {
+
+ long 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;
+
+}
+
+char *xstrdup (const char *__p) {
+
+ char *p = xmalloc (strlen (__p) + 1);
+
+ strcpy (p, __p);
+ return p;
+
+}
+
+void parse_args (int argc, char **argv, int optind) {
+
+ const char *r;
+
+ if (argc <= optind) {
+
+ print_usage ();
+ exit (EXIT_SUCCESS);
+
+ }
+
+ r = argv[optind++];
+
+check_options:
+
+ if (r[0] == '-') {
+ ++r;
+ }
+
+ while (*r != '\0') {
+
+ char ch = *r++;
+
+ if (ch == 'f') {
+
+ state->fflag++;
+ continue;
+
+ }
+
+ if (ch == 'i') {
+
+ state->iflag++;
+ continue;
+
+ }
+
+ if (ch == 'r') {
+
+ state->rflag++;
+ continue;
+
+ }
+
+ report_at (program_name, 0, REPORT_ERROR, "invalid option -- '%c'", ch);
+
+ print_usage ();
+ exit (EXIT_FAILURE);
+
+ }
+
+ if ((r = argv[optind])) {
+
+ if (*r == '-') {
+ goto check_options;
+ }
+
+ }
+
+ if (optind >= argc) {
+
+ print_usage ();
+ exit (EXIT_FAILURE);
+
+ }
+
+ while (optind < argc) {
+ dynarray_add (&state->files, &state->nb_files, xstrdup (argv[optind++]));
+ }
+
+}
+
+void *xmalloc (unsigned long __size) {
+
+ void *ptr = malloc (__size);
+
+ if (!ptr && __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 *ptr = realloc (__ptr, __size);
+
+ if (!ptr && __size) {
+
+ report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)");
+ exit (EXIT_FAILURE);
+
+ }
+
+ return ptr;
+
+}
--- /dev/null
+/******************************************************************************
+ * @file lib.h
+ *****************************************************************************/
+#ifndef _LIB_H
+#define _LIB_H
+
+char *xstrdup (const char *__p);
+void parse_args (int argc, char **argv, int optind);
+
+void *xmalloc (unsigned long __size);
+void *xrealloc (void *__ptr, unsigned long __size);
+
+#endif /* _LIB_H */
--- /dev/null
+/******************************************************************************
+ * @file report.c
+ *****************************************************************************/
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "report.h"
+unsigned int errors = 0;
+
+#ifndef __PDOS__
+#if defined (_WIN32)
+# include <windows.h>
+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
+
+static void output_message (const char *filename, unsigned int lineno, unsigned int idx, int type, const char *fmt, va_list ap) {
+
+ if (filename) {
+
+ if (lineno == 0) {
+ fprintf (stderr, "%s: ", filename);
+ } else {
+ fprintf (stderr, "%s:", filename);
+ }
+
+ }
+
+ if (lineno > 0) {
+
+ if (idx == 0) {
+ fprintf (stderr, "%u: ", lineno);
+ } else {
+ fprintf (stderr, "%u:", lineno);
+ }
+
+ }
+
+ if (idx > 0) {
+ fprintf (stderr, "%u: ", idx);
+ }
+
+ 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, " ");
+ vfprintf (stderr, fmt, ap);
+ fprintf (stderr, "\n");
+
+ if (type != REPORT_WARNING) {
+ ++errors;
+ }
+
+}
+
+unsigned int get_error_count (void) {
+ return errors;
+}
+
+void report_at (const char *filename, unsigned int lineno, int type, const char *fmt, ...) {
+
+ va_list ap;
+
+ va_start (ap, fmt);
+ output_message (filename, lineno, 0, type, fmt, ap);
+ va_end (ap);
+
+}
--- /dev/null
+/******************************************************************************
+ * @file report.h
+ *****************************************************************************/
+#ifndef _REPORT_H
+#define _REPORT_H
+
+#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
+
+#define REPORT_WARNING 0
+#define REPORT_ERROR 1
+#define REPORT_FATAL_ERROR 3
+#define REPORT_INTERNAL_ERROR 4
+
+unsigned int get_error_count (void);
+void report_at (const char *filename, unsigned int lineno, int type, const char *fmt, ...);
+
+#endif /* _REPORT_H */
--- /dev/null
+/******************************************************************************
+ * @file ar.c
+ *****************************************************************************/
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rm.h"
+#include "lib.h"
+#include "report.h"
+
+struct rm_state *state = 0;
+const char *program_name = 0;
+
+#if defined (_WIN32)
+# include <windows.h>
+
+static BOOL IsDirectory (LPCTSTR szPath) {
+
+ DWORD dwAttrib = GetFileAttributes (szPath);
+ return (dwAttrib != 0xFFFFFFFFL && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
+
+}
+
+static void rm (const char *path) {
+
+ const char *p = path;
+ char *p2;
+
+ unsigned long len;
+
+ if (isalpha ((int) p[0]) && p[1] == ':') {
+ p += 2;
+ }
+
+ while (*p == '/') {
+ p++;
+ }
+
+ p2 = xstrdup (path);
+
+ if (IsDirectory (p2)) {
+
+ char *subpath, *filename;
+
+ HANDLE hFind;
+ WIN32_FIND_DATA FindFileData;
+
+ if (!state->rflag && !state->fflag) {
+
+ report_at (program_name, 0, REPORT_ERROR, "cannot remove directoies without -r");
+
+ free (p2);
+ return;
+
+ }
+
+ len = strlen (p2);
+
+ if (p2[len - 1] == '/') {
+
+ subpath = xmalloc (len + 5);
+ sprintf (subpath, "%s*.*", p2);
+
+ } else {
+
+ subpath = xmalloc (len + 6);
+ sprintf (subpath, "%s/*.*", p2);
+
+ }
+
+ if ((hFind = FindFirstFile (subpath, &FindFileData)) == INVALID_HANDLE_VALUE) {
+
+ free (subpath);
+ return;
+
+ }
+
+ free (subpath);
+
+ do {
+
+ filename = FindFileData.cFileName;
+
+ if (filename[0] == '.' && (filename[1] == '\0' || (filename[1] == '.' && filename[2] == '\0'))) {
+ continue;
+ }
+
+ len = strlen (path);
+
+ if (path[len - 1] == '/') {
+
+ len += (strlen (filename) + 1);
+
+ if (!(subpath = malloc (len))) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for '%s'", filename);
+ continue;
+
+ }
+
+ sprintf (subpath, "%s%s", path, filename);
+
+ } else {
+
+ len += (1 + strlen (filename) + 1);
+
+ if (!(subpath = malloc (len))) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for '%s'", filename);
+ continue;
+
+ }
+
+ sprintf (subpath, "%s/%s", path, filename);
+
+ }
+
+ rm (subpath);
+ free (subpath);
+
+ } while (FindNextFile (hFind, &FindFileData) != 0);
+
+ FindClose (hFind);
+
+ } else {
+
+ int ret = remove (p2);
+
+ if (!state->fflag && ret) {
+ report_at (program_name, 0, REPORT_ERROR, "unable to remove %s", p2);
+ }
+
+ }
+
+ free (p2);
+
+}
+#endif
+
+int main (int argc, char **argv) {
+
+ long i;
+
+ if (argc && *argv) {
+
+ char *p;
+ program_name = *argv;
+
+ if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
+ program_name = (p + 1);
+ }
+
+ }
+
+ state = xmalloc (sizeof (*state));
+ parse_args (argc, argv, 1);
+
+ for (i = 0; i < state->nb_files; ++i) {
+ rm (state->files[i]);
+ }
+
+ return (get_error_count () > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+
+}
--- /dev/null
+/******************************************************************************
+ * @file rm.h
+ *****************************************************************************/
+#ifndef _RM_H
+#define _RM_H
+
+struct rm_state {
+
+ const char **files;
+ long nb_files;
+
+ int fflag;
+ int iflag;
+ int rflag;
+
+};
+
+extern struct rm_state *state;
+extern const char *program_name;
+
+#endif /* _RM_H */