makefile for C, core util rm that does not delete penciled files
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Fri, 6 Dec 2024 14:11:53 +0000 (14:11 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Fri, 6 Dec 2024 14:11:53 +0000 (14:11 +0000)
32 files changed:
README.md
developer/amd64/rm_na [new file with mode: 0755]
developer/bash🖉/bash🖉 [new symlink]
developer/cc🖉/home.cli.c
developer/cc🖉/is_authored_fs_obj.c [new file with mode: 0644]
developer/cc🖉/remove.c [new file with mode: 0644]
developer/cc🖉/unlink.lib.c [new file with mode: 0644]
developer/cc🖉/user-stem.cli.c
developer/cc🖉/user-subu.cli.c
developer/cc🖉/user.cli.c
developer/emacs🖉/emacs.el [deleted file]
developer/emacs🖉/emacs🖉 [new symlink]
developer/emacs🖉/jdbx.el [new file with mode: 0644]
developer/make🖉/RT_0.h
developer/make🖉/environment_RT_0
developer/make🖉/targets
developer/test/e/f🖉/ff [new file with mode: 0644]
developer/test/e/f🖉/g/gg [new file with mode: 0644]
developer/test/rm [new file with mode: 0755]
developer/tool🖉/env
developer/tool🖉/make
developer/tool🖉/makefile
developer/tool🖉/release
document🖉/running_IDE_and_jdb_in_test_environment.txt
env_administrator🖉
env_devloper🖉
env_tester🖉
release/amd64 [new symlink]
release/bash [new symlink]
release/emacs [new symlink]
release/make [new symlink]
tool🖉/env

index 915a0df..b9e9fca 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,6 +1,28 @@
 ï»¿\r
 This project holds the builds for simple tools and scripts tha are common to\r
-projects, documents that are shared by projects, and useful configuration files.\r
-It will also serves as a project skeleton when it is copmleted.\r
+multiple projects, documents that are on general topics or shared by projects,\r
+and useful configuration files.\r
+\r
+Currently RT-incommon does not implement the full project skeleton and work flows.\r
+For example, instead of releasing developed work product from the developer directory,\r
+there are symbolic links into the developer directory. Also the tester directory\r
+is empty.\r
+\r
+I've avoided using Mosaic or Ariadne here so as to avoid hard to think about\r
+circular dependencies.  At some point we plan to christen a release of Mosaic\r
+and Ariadne as the go-to versions, then incorproate those go-to versions into\r
+later versions of themselves, and here in the RT-incommon project.\r
+\r
+This project is used by including it as a third party tool, then picking\r
+and choosing what is to be used in the adopting project by creating\r
+symbolic links to the chosen items in the Rt-incommon release directory.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
 \r
 \r
diff --git a/developer/amd64/rm_na b/developer/amd64/rm_na
new file mode 100755 (executable)
index 0000000..57bd08d
Binary files /dev/null and b/developer/amd64/rm_na differ
diff --git a/developer/bash🖉/bash🖉 b/developer/bash🖉/bash🖉
new file mode 120000 (symlink)
index 0000000..97464d3
--- /dev/null
@@ -0,0 +1 @@
+/var/user_data/Thomas-developer/RT-incommon/developer/bash🖉
\ No newline at end of file
index 4395a60..d990d96 100644 (file)
@@ -1,3 +1,4 @@
+#define IFACE
 #include <unistd.h>
 #include <sys/types.h>
 #include <pwd.h>
diff --git a/developer/cc🖉/is_authored_fs_obj.c b/developer/cc🖉/is_authored_fs_obj.c
new file mode 100644 (file)
index 0000000..1c82e9a
--- /dev/null
@@ -0,0 +1,56 @@
+#include <string.h>
+#include <stdbool.h>
+
+static bool is_authored_fs_obj(const char *path) {
+    if (!path || strlen(path) == 0) {
+        return false;
+    }
+
+    // Check if the last character is the pencil
+    size_t len = strlen(path);
+    return path[len - 1] == '🖉';
+}
+
+
+#include <stdlib.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <string.h>
+
+static bool is_authored(const char *path) {
+    if (!path || strlen(path) == 0) {
+        return false;
+    }
+
+    // Check the path itself
+    if (is_authored_fs_obj(path)) {
+        return true;
+    }
+
+    // Check each parent directory up to the root
+    char *path_copy = strdup(path);
+    if (!path_copy) {
+        return false; // Memory allocation failure
+    }
+
+    char *parent = path_copy;
+    bool authored = false;
+
+    while (true) {
+        parent = dirname(parent);
+
+        // Check if the current directory is authored
+        if (is_authored_fs_obj(parent)) {
+            authored = true;
+            break;
+        }
+
+        // If we reach the root, stop
+        if (strcmp(parent, "/") == 0) {
+            break;
+        }
+    }
+
+    free(path_copy);
+    return authored;
+}
diff --git a/developer/cc🖉/remove.c b/developer/cc🖉/remove.c
new file mode 100644 (file)
index 0000000..3ce98f9
--- /dev/null
@@ -0,0 +1,762 @@
+#include <config.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <string.h>
+#include <stdbool.h>
+
+static bool is_authored_fs_obj(const char *path) {
+    if (!path || strlen(path) == 0) {
+        return false;
+    }
+
+    // Check if the last character is the pencil (as a string)
+    const char *suffix = "🖉";
+    size_t len = strlen(path);
+    size_t suffix_len = strlen(suffix);
+
+    if (len < suffix_len) {
+        return false;
+    }
+
+    return strcmp(path + len - suffix_len, suffix) == 0;
+}
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <limits.h>
+#include <unistd.h>
+
+static bool is_authored(const char *path) {
+    if (!path || strlen(path) == 0) {
+        fprintf(stderr, "DEBUG: Invalid path provided\n");
+        return false;
+    }
+
+    // Convert to an absolute path
+    char abs_path[PATH_MAX];
+    if (!realpath(path, abs_path)) {
+        fprintf(stderr, "DEBUG: Failed to resolve absolute path for: %s\n", path);
+        return false;
+    }
+
+    fprintf(stderr, "DEBUG: Starting check for path: %s (resolved: %s)\n", path, abs_path);
+
+    // Allocate and copy for safe modifications
+    char *current_path = strdup(abs_path);
+    if (!current_path) {
+        fprintf(stderr, "DEBUG: Memory allocation failed for current_path\n");
+        return false;
+    }
+
+    bool authored = false;
+    int iteration_count = 0;
+
+    while (true) {
+        fprintf(stderr, "DEBUG: Iteration %d, checking path: %s\n", iteration_count, current_path);
+
+        // Check if the current path is authored
+        if (is_authored_fs_obj(current_path)) {
+            fprintf(stderr, "DEBUG: Found authored path: %s\n", current_path);
+            authored = true;
+            break;
+        }
+
+        // Get parent directory
+        char *parent_path = strdup(current_path);
+        if (!parent_path) {
+            fprintf(stderr, "DEBUG: Memory allocation failed for parent_path\n");
+            break;
+        }
+        char *parent = dirname(parent_path);
+
+        // Stop condition: root or no change in path
+        if (strcmp(parent, "/") == 0 || strcmp(parent, current_path) == 0) {
+            fprintf(stderr, "DEBUG: Reached stop condition at parent: %s\n", parent);
+            free(parent_path);
+            break;
+        }
+
+        // Update current_path for the next iteration
+        free(current_path);
+        current_path = strdup(parent);
+        if (!current_path) {
+            fprintf(stderr, "DEBUG: Memory allocation failed while updating current_path\n");
+            free(parent_path);
+            break;
+        }
+
+        free(parent_path);
+        iteration_count++;
+
+        // Failsafe for infinite loops
+        if (iteration_count > 100) {
+            fprintf(stderr, "DEBUG: Too many iterations, exiting to avoid infinite loop\n");
+            break;
+        }
+    }
+
+    free(current_path);
+    return authored;
+}
+
+
+/* remove.c -- core functions for removing files and directories
+   Copyright (C) 1988-2024 Free Software Foundation, Inc.
+
+   This program 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 3 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, see <https://www.gnu.org/licenses/>.  */
+
+/* Extracted from rm.c, librarified, then rewritten twice by Jim Meyering.  */
+
+#include <config.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "system.h"
+#include "assure.h"
+#include "file-type.h"
+#include "filenamecat.h"
+#include "ignore-value.h"
+#include "remove.h"
+#include "root-dev-ino.h"
+#include "stat-time.h"
+#include "write-any-file.h"
+#include "xfts.h"
+#include "yesno.h"
+
+/* The prompt function may be called twice for a given directory.
+   The first time, we ask whether to descend into it, and the
+   second time, we ask whether to remove it.  */
+enum Prompt_action
+  {
+    PA_DESCEND_INTO_DIR = 2,
+    PA_REMOVE_DIR
+  };
+
+/* D_TYPE(D) is the type of directory entry D if known, DT_UNKNOWN
+   otherwise.  */
+#if ! HAVE_STRUCT_DIRENT_D_TYPE
+/* Any int values will do here, so long as they're distinct.
+   Undef any existing macros out of the way.  */
+# undef DT_UNKNOWN
+# undef DT_DIR
+# undef DT_LNK
+# define DT_UNKNOWN 0
+# define DT_DIR 1
+# define DT_LNK 2
+#endif
+
+/* Like fstatat, but cache on POSIX-compatible systems.  */
+static int
+cache_fstatat (int fd, char const *file, struct stat *st, int flag)
+{
+#if HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
+  /* If ST->st_atim.tv_nsec is -1, the status has not been gotten yet.
+     If less than -1, fstatat failed with errno == ST->st_ino.
+     Otherwise, the status has already been gotten, so return 0.  */
+  if (0 <= st->st_atim.tv_nsec)
+    return 0;
+  if (st->st_atim.tv_nsec == -1)
+    {
+      if (fstatat (fd, file, st, flag) == 0)
+        return 0;
+      st->st_atim.tv_nsec = -2;
+      st->st_ino = errno;
+    }
+  errno = st->st_ino;
+  return -1;
+#else
+  return fstatat (fd, file, st, flag);
+#endif
+}
+
+/* Initialize a fstatat cache *ST.  Return ST for convenience.  */
+static inline struct stat *
+cache_stat_init (struct stat *st)
+{
+#if HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
+  st->st_atim.tv_nsec = -1;
+#endif
+  return st;
+}
+
+/* Return 1 if FILE is an unwritable non-symlink,
+   0 if it is writable or some other type of file,
+   -1 and set errno if there is some problem in determining the answer.
+   Set *BUF to the file status.  */
+static int
+write_protected_non_symlink (int fd_cwd,
+                             char const *file,
+                             struct stat *buf)
+{
+  if (can_write_any_file ())
+    return 0;
+  if (cache_fstatat (fd_cwd, file, buf, AT_SYMLINK_NOFOLLOW) != 0)
+    return -1;
+  if (S_ISLNK (buf->st_mode))
+    return 0;
+  /* Here, we know FILE is not a symbolic link.  */
+
+  /* In order to be reentrant -- i.e., to avoid changing the working
+     directory, and at the same time to be able to deal with alternate
+     access control mechanisms (ACLs, xattr-style attributes) and
+     arbitrarily deep trees -- we need a function like eaccessat, i.e.,
+     like Solaris' eaccess, but fd-relative, in the spirit of openat.  */
+
+  /* In the absence of a native eaccessat function, here are some of
+     the implementation choices [#4 and #5 were suggested by Paul Eggert]:
+     1) call openat with O_WRONLY|O_NOCTTY
+        Disadvantage: may create the file and doesn't work for directory,
+        may mistakenly report 'unwritable' for EROFS or ACLs even though
+        perm bits say the file is writable.
+
+     2) fake eaccessat (save_cwd, fchdir, call euidaccess, restore_cwd)
+        Disadvantage: changes working directory (not reentrant) and can't
+        work if save_cwd fails.
+
+     3) if (euidaccess (full_name, W_OK) == 0)
+        Disadvantage: doesn't work if full_name is too long.
+        Inefficient for very deep trees (O(Depth^2)).
+
+     4) If the full pathname is sufficiently short (say, less than
+        PATH_MAX or 8192 bytes, whichever is shorter):
+        use method (3) (i.e., euidaccess (full_name, W_OK));
+        Otherwise: vfork, fchdir in the child, run euidaccess in the
+        child, then the child exits with a status that tells the parent
+        whether euidaccess succeeded.
+
+        This avoids the O(N**2) algorithm of method (3), and it also avoids
+        the failure-due-to-too-long-file-names of method (3), but it's fast
+        in the normal shallow case.  It also avoids the lack-of-reentrancy
+        and the save_cwd problems.
+        Disadvantage; it uses a process slot for very-long file names,
+        and would be very slow for hierarchies with many such files.
+
+     5) If the full file name is sufficiently short (say, less than
+        PATH_MAX or 8192 bytes, whichever is shorter):
+        use method (3) (i.e., euidaccess (full_name, W_OK));
+        Otherwise: look just at the file bits.  Perhaps issue a warning
+        the first time this occurs.
+
+        This is like (4), except for the "Otherwise" case where it isn't as
+        "perfect" as (4) but is considerably faster.  It conforms to current
+        POSIX, and is uniformly better than what Solaris and FreeBSD do (they
+        mess up with long file names). */
+
+  {
+    if (faccessat (fd_cwd, file, W_OK, AT_EACCESS) == 0)
+      return 0;
+
+    return errno == EACCES ? 1 : -1;
+  }
+}
+
+/* Return the status of the directory identified by FTS and ENT.
+   This is -1 if the directory is empty, 0 if it is nonempty,
+   and a positive error number if there was trouble determining the status,
+   e.g., it is not a directory, or permissions problems, or I/O errors.
+   Use *DIR_STATUS as a cache for the status.  */
+static int
+get_dir_status (FTS const *fts, FTSENT const *ent, int *dir_status)
+{
+  if (*dir_status == DS_UNKNOWN)
+    *dir_status = directory_status (fts->fts_cwd_fd, ent->fts_accpath);
+  return *dir_status;
+}
+
+/* Prompt whether to remove FILENAME, if required via a combination of
+   the options specified by X and/or file attributes.  If the file may
+   be removed, return RM_OK or RM_USER_ACCEPTED, the latter if the user
+   was prompted and accepted.  If the user declines to remove the file,
+   return RM_USER_DECLINED.  If not ignoring missing files and we
+   cannot lstat FILENAME, then return RM_ERROR.
+
+   IS_DIR is true if ENT designates a directory, false otherwise.
+
+   Depending on MODE, ask whether to 'descend into' or to 'remove' the
+   directory FILENAME.  MODE is ignored when FILENAME is not a directory.
+   Use and update *DIR_STATUS as needed, via the conventions of
+   get_dir_status.  */
+static enum RM_status
+prompt (FTS const *fts, FTSENT const *ent, bool is_dir,
+        struct rm_options const *x, enum Prompt_action mode,
+        int *dir_status)
+{
+  int fd_cwd = fts->fts_cwd_fd;
+  char const *full_name = ent->fts_path;
+  char const *filename = ent->fts_accpath;
+  struct stat st;
+  struct stat *sbuf = &st;
+  cache_stat_init (sbuf);
+
+  int dirent_type = is_dir ? DT_DIR : DT_UNKNOWN;
+  int write_protected = 0;
+
+  /* When nonzero, this indicates that we failed to remove a child entry,
+     either because the user declined an interactive prompt, or due to
+     some other failure, like permissions.  */
+  if (ent->fts_number)
+    return RM_USER_DECLINED;
+
+  if (x->interactive == RMI_NEVER)
+    return RM_OK;
+
+  int wp_errno = 0;
+  if (!x->ignore_missing_files
+      && (x->interactive == RMI_ALWAYS || x->stdin_tty)
+      && dirent_type != DT_LNK)
+    {
+      write_protected = write_protected_non_symlink (fd_cwd, filename, sbuf);
+      wp_errno = errno;
+    }
+
+  if (write_protected || x->interactive == RMI_ALWAYS)
+    {
+      if (0 <= write_protected && dirent_type == DT_UNKNOWN)
+        {
+          if (cache_fstatat (fd_cwd, filename, sbuf, AT_SYMLINK_NOFOLLOW) == 0)
+            {
+              if (S_ISLNK (sbuf->st_mode))
+                dirent_type = DT_LNK;
+              else if (S_ISDIR (sbuf->st_mode))
+                dirent_type = DT_DIR;
+              /* Otherwise it doesn't matter, so leave it DT_UNKNOWN.  */
+            }
+          else
+            {
+              /* This happens, e.g., with 'rm '''.  */
+              write_protected = -1;
+              wp_errno = errno;
+            }
+        }
+
+      if (0 <= write_protected)
+        switch (dirent_type)
+          {
+          case DT_LNK:
+            /* Using permissions doesn't make sense for symlinks.  */
+            if (x->interactive != RMI_ALWAYS)
+              return RM_OK;
+            break;
+
+          case DT_DIR:
+             /* Unless we're either deleting directories or deleting
+                recursively, we want to raise an EISDIR error rather than
+                prompting the user  */
+            if ( ! (x->recursive
+                    || (x->remove_empty_directories
+                        && get_dir_status (fts, ent, dir_status) != 0)))
+              {
+                write_protected = -1;
+                wp_errno = *dir_status <= 0 ? EISDIR : *dir_status;
+              }
+            break;
+          }
+
+      char const *quoted_name = quoteaf (full_name);
+
+      if (write_protected < 0)
+        {
+          error (0, wp_errno, _("cannot remove %s"), quoted_name);
+          return RM_ERROR;
+        }
+
+      /* Issue the prompt.  */
+      if (dirent_type == DT_DIR
+          && mode == PA_DESCEND_INTO_DIR
+          && get_dir_status (fts, ent, dir_status) == DS_NONEMPTY)
+        fprintf (stderr,
+                 (write_protected
+                  ? _("%s: descend into write-protected directory %s? ")
+                  : _("%s: descend into directory %s? ")),
+                 program_name, quoted_name);
+      else if (0 < *dir_status)
+        {
+          if ( ! (x->remove_empty_directories && *dir_status == EACCES))
+            {
+              error (0, *dir_status, _("cannot remove %s"), quoted_name);
+              return RM_ERROR;
+            }
+
+          /* The following code can lead to a successful deletion only with
+             the --dir (-d) option (remove_empty_directories) and an empty
+             inaccessible directory. In the first prompt call for a directory,
+             we'd normally ask whether to descend into it, but in this case
+             (it's inaccessible), that is not possible, so don't prompt.  */
+          if (mode == PA_DESCEND_INTO_DIR)
+            return RM_OK;
+
+          fprintf (stderr,
+               _("%s: attempt removal of inaccessible directory %s? "),
+                   program_name, quoted_name);
+        }
+      else
+        {
+          if (cache_fstatat (fd_cwd, filename, sbuf, AT_SYMLINK_NOFOLLOW) != 0)
+            {
+              error (0, errno, _("cannot remove %s"), quoted_name);
+              return RM_ERROR;
+            }
+
+          fprintf (stderr,
+                   (write_protected
+                    /* TRANSLATORS: In the next two strings the second %s is
+                       replaced by the type of the file.  To avoid grammatical
+                       problems, it may be more convenient to translate these
+                       strings instead as: "%1$s: %3$s is write-protected and
+                       is of type '%2$s' -- remove it? ".  */
+                    ? _("%s: remove write-protected %s %s? ")
+                    : _("%s: remove %s %s? ")),
+                   program_name, file_type (sbuf), quoted_name);
+        }
+
+      return yesno () ? RM_USER_ACCEPTED : RM_USER_DECLINED;
+    }
+  return RM_OK;
+}
+
+/* When a function like unlink, rmdir, or fstatat fails with an errno
+   value of ERRNUM, return true if the specified file system object
+   is guaranteed not to exist;  otherwise, return false.  */
+static inline bool
+nonexistent_file_errno (int errnum)
+{
+  /* Do not include ELOOP here, since the specified file may indeed
+     exist, but be (in)accessible only via too long a symlink chain.
+     Likewise for ENAMETOOLONG, since rm -f ./././.../foo may fail
+     if the "..." part expands to a long enough sequence of "./"s,
+     even though ./foo does indeed exist.
+
+     Another case to consider is when a particular name is invalid for
+     a given file system.  In 2011, smbfs returns EINVAL, but the next
+     revision of POSIX will require EILSEQ for that situation:
+     https://austingroupbugs.net/view.php?id=293
+  */
+
+  switch (errnum)
+    {
+    case EILSEQ:
+    case EINVAL:
+    case ENOENT:
+    case ENOTDIR:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* Encapsulate the test for whether the errno value, ERRNUM, is ignorable.  */
+static inline bool
+ignorable_missing (struct rm_options const *x, int errnum)
+{
+  return x->ignore_missing_files && nonexistent_file_errno (errnum);
+}
+
+/* Tell fts not to traverse into the hierarchy at ENT.  */
+static void
+fts_skip_tree (FTS *fts, FTSENT *ent)
+{
+  fts_set (fts, ent, FTS_SKIP);
+  /* Ensure that we do not process ENT a second time.  */
+  ignore_value (fts_read (fts));
+}
+
+/* Upon unlink failure, or when the user declines to remove ENT, mark
+   each of its ancestor directories, so that we know not to prompt for
+   its removal.  */
+static void
+mark_ancestor_dirs (FTSENT *ent)
+{
+  FTSENT *p;
+  for (p = ent->fts_parent; FTS_ROOTLEVEL <= p->fts_level; p = p->fts_parent)
+    {
+      if (p->fts_number)
+        break;
+      p->fts_number = 1;
+    }
+}
+
+/* Remove the file system object specified by ENT.  IS_DIR specifies
+   whether it is expected to be a directory or non-directory.
+   Return RM_OK upon success, else RM_ERROR.  */
+static enum RM_status
+excise (FTS *fts, FTSENT *ent, struct rm_options const *x, bool is_dir)
+{
+  int flag = is_dir ? AT_REMOVEDIR : 0;
+  if (unlinkat (fts->fts_cwd_fd, ent->fts_accpath, flag) == 0)
+    {
+      if (x->verbose)
+        {
+          printf ((is_dir
+                   ? _("removed directory %s\n")
+                   : _("removed %s\n")), quoteaf (ent->fts_path));
+        }
+      return RM_OK;
+    }
+
+  /* The unlinkat from kernels like linux-2.6.32 reports EROFS even for
+     nonexistent files.  When the file is indeed missing, map that to ENOENT,
+     so that rm -f ignores it, as required.  Even without -f, this is useful
+     because it makes rm print the more precise diagnostic.  */
+  if (errno == EROFS)
+    {
+      struct stat st;
+      if ( ! (fstatat (fts->fts_cwd_fd, ent->fts_accpath, &st,
+                       AT_SYMLINK_NOFOLLOW)
+              && errno == ENOENT))
+        errno = EROFS;
+    }
+
+  if (ignorable_missing (x, errno))
+    return RM_OK;
+
+  /* When failing to rmdir an unreadable directory, we see errno values
+     like EISDIR or ENOTDIR (or, on Solaris 10, EEXIST), but they would be
+     meaningless in a diagnostic.  When that happens, use the earlier, more
+     descriptive errno value.  */
+  if (ent->fts_info == FTS_DNR
+      && (errno == ENOTEMPTY || errno == EISDIR || errno == ENOTDIR
+          || errno == EEXIST)
+      && ent->fts_errno != 0)
+    errno = ent->fts_errno;
+  error (0, errno, _("cannot remove %s"), quoteaf (ent->fts_path));
+  mark_ancestor_dirs (ent);
+  return RM_ERROR;
+}
+
+/* This function is called once for every file system object that fts
+   encounters.  fts performs a depth-first traversal.
+   A directory is usually processed twice, first with fts_info == FTS_D,
+   and later, after all of its entries have been processed, with FTS_DP.
+   Return RM_ERROR upon error, RM_USER_DECLINED for a negative response
+   to an interactive prompt, and otherwise, RM_OK.  */
+static enum RM_status
+rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x)
+{
+  int dir_status = DS_UNKNOWN;
+
+if (is_authored(ent->fts_path)) {
+    fprintf(stderr, "rm: cannot remove authored %s '%s'\n",
+            (ent->fts_info == FTS_D || ent->fts_info == FTS_DP) ? "directory" : "file",
+            ent->fts_path);
+    return RM_ERROR; // Skip authored files
+}
+
+
+  switch (ent->fts_info)
+    {
+    case FTS_D:                        /* preorder directory */
+      if (! x->recursive
+          && !(x->remove_empty_directories
+               && get_dir_status (fts, ent, &dir_status) != 0))
+        {
+          /* This is the first (pre-order) encounter with a directory
+             that we cannot delete.
+             Not recursive, and it's not an empty directory (if we're removing
+             them) so arrange to skip contents.  */
+          int err = x->remove_empty_directories ? ENOTEMPTY : EISDIR;
+          error (0, err, _("cannot remove %s"), quoteaf (ent->fts_path));
+          mark_ancestor_dirs (ent);
+          fts_skip_tree (fts, ent);
+          return RM_ERROR;
+        }
+
+      /* Perform checks that can apply only for command-line arguments.  */
+      if (ent->fts_level == FTS_ROOTLEVEL)
+        {
+          /* POSIX says:
+             If the basename of a command line argument is "." or "..",
+             diagnose it and do nothing more with that argument.  */
+          if (dot_or_dotdot (last_component (ent->fts_accpath)))
+            {
+              error (0, 0,
+                     _("refusing to remove %s or %s directory: skipping %s"),
+                     quoteaf_n (0, "."), quoteaf_n (1, ".."),
+                     quoteaf_n (2, ent->fts_path));
+              fts_skip_tree (fts, ent);
+              return RM_ERROR;
+            }
+
+          /* POSIX also says:
+             If a command line argument resolves to "/" (and --preserve-root
+             is in effect -- default) diagnose and skip it.  */
+          if (ROOT_DEV_INO_CHECK (x->root_dev_ino, ent->fts_statp))
+            {
+              ROOT_DEV_INO_WARN (ent->fts_path);
+              fts_skip_tree (fts, ent);
+              return RM_ERROR;
+            }
+
+          /* If a command line argument is a mount point and
+             --preserve-root=all is in effect, diagnose and skip it.
+             This doesn't handle "/", but that's handled above.  */
+          if (x->preserve_all_root)
+            {
+              bool failed = false;
+              char *parent = file_name_concat (ent->fts_accpath, "..", nullptr);
+              struct stat statbuf;
+
+              if (!parent || lstat (parent, &statbuf))
+                {
+                  error (0, 0,
+                         _("failed to stat %s: skipping %s"),
+                         quoteaf_n (0, parent),
+                         quoteaf_n (1, ent->fts_accpath));
+                  failed = true;
+                }
+
+              free (parent);
+
+              if (failed || fts->fts_dev != statbuf.st_dev)
+                {
+                  if (! failed)
+                    {
+                      error (0, 0,
+                             _("skipping %s, since it's on a different device"),
+                             quoteaf (ent->fts_path));
+                      error (0, 0, _("and --preserve-root=all is in effect"));
+                    }
+                  fts_skip_tree (fts, ent);
+                  return RM_ERROR;
+                }
+            }
+        }
+
+      {
+        enum RM_status s = prompt (fts, ent, true /*is_dir*/, x,
+                                   PA_DESCEND_INTO_DIR, &dir_status);
+
+        if (s == RM_USER_ACCEPTED && dir_status == DS_EMPTY)
+          {
+            /* When we know (from prompt when in interactive mode)
+               that this is an empty directory, don't prompt twice.  */
+            s = excise (fts, ent, x, true);
+            if (s == RM_OK)
+              fts_skip_tree (fts, ent);
+          }
+
+        if (! (s == RM_OK || s == RM_USER_ACCEPTED))
+          {
+            mark_ancestor_dirs (ent);
+            fts_skip_tree (fts, ent);
+          }
+
+        return s;
+      }
+
+    case FTS_F:                        /* regular file */
+    case FTS_NS:               /* stat(2) failed */
+    case FTS_SL:               /* symbolic link */
+    case FTS_SLNONE:           /* symbolic link without target */
+    case FTS_DP:               /* postorder directory */
+    case FTS_DNR:              /* unreadable directory */
+    case FTS_NSOK:             /* e.g., dangling symlink */
+    case FTS_DEFAULT:          /* none of the above */
+      {
+        /* With --one-file-system, do not attempt to remove a mount point.
+           fts' FTS_XDEV ensures that we don't process any entries under
+           the mount point.  */
+        if (ent->fts_info == FTS_DP
+            && x->one_file_system
+            && FTS_ROOTLEVEL < ent->fts_level
+            && ent->fts_statp->st_dev != fts->fts_dev)
+          {
+            mark_ancestor_dirs (ent);
+            error (0, 0, _("skipping %s, since it's on a different device"),
+                   quoteaf (ent->fts_path));
+            return RM_ERROR;
+          }
+
+        bool is_dir = ent->fts_info == FTS_DP || ent->fts_info == FTS_DNR;
+        enum RM_status s = prompt (fts, ent, is_dir, x, PA_REMOVE_DIR,
+                                   &dir_status);
+        if (! (s == RM_OK || s == RM_USER_ACCEPTED))
+          return s;
+        return excise (fts, ent, x, is_dir);
+      }
+
+    case FTS_DC:               /* directory that causes cycles */
+      emit_cycle_warning (ent->fts_path);
+      fts_skip_tree (fts, ent);
+      return RM_ERROR;
+
+    case FTS_ERR:
+      /* Various failures, from opendir to ENOMEM, to failure to "return"
+         to preceding directory, can provoke this.  */
+      error (0, ent->fts_errno, _("traversal failed: %s"),
+             quotef (ent->fts_path));
+      fts_skip_tree (fts, ent);
+      return RM_ERROR;
+
+    default:
+      error (0, 0, _("unexpected failure: fts_info=%d: %s\n"
+                     "please report to %s"),
+             ent->fts_info,
+             quotef (ent->fts_path),
+             PACKAGE_BUGREPORT);
+      abort ();
+    }
+}
+
+/* Remove FILEs, honoring options specified via X.
+   Return RM_OK if successful.  */
+enum RM_status
+rm (char *const *file, struct rm_options const *x)
+{
+  enum RM_status rm_status = RM_OK;
+
+  if (*file)
+    {
+      int bit_flags = (FTS_CWDFD
+                       | FTS_NOSTAT
+                       | FTS_PHYSICAL);
+
+      if (x->one_file_system)
+        bit_flags |= FTS_XDEV;
+
+      FTS *fts = xfts_open (file, bit_flags, nullptr);
+
+      while (true)
+        {
+          FTSENT *ent;
+
+          ent = fts_read (fts);
+          if (ent == nullptr)
+            {
+              if (errno != 0)
+                {
+                  error (0, errno, _("fts_read failed"));
+                  rm_status = RM_ERROR;
+                }
+              break;
+            }
+
+          enum RM_status s = rm_fts (fts, ent, x);
+
+          affirm (VALID_STATUS (s));
+          UPDATE_STATUS (rm_status, s);
+        }
+
+      if (fts_close (fts) != 0)
+        {
+          error (0, errno, _("fts_close failed"));
+          rm_status = RM_ERROR;
+        }
+    }
+
+  return rm_status;
+}
diff --git a/developer/cc🖉/unlink.lib.c b/developer/cc🖉/unlink.lib.c
new file mode 100644 (file)
index 0000000..5418d02
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef IFACE
+#define Unix·IMPLEMENTATION
+#define IFACE
+#endif
+
+#ifndef Unix·IFACE
+#define Unix·IFACE
+
+  int unlink(const char *pathname);
+
+#endif // Unix·IFACE
+
+#ifndef Unix·IMPLEMENTATION
+
+  #define _GNU_SOURCE
+  #include <stdio.h>
+  #include <string.h>
+  #include <unistd.h>
+  #include <libgen.h>
+  #include <errno.h>
+
+  static int is_authored(const char *path) {
+      if (path == NULL) {
+          return 0;
+      }
+
+      // Check if the file itself is authored
+      const char *suffix = "🖉";
+      size_t path_len = strlen(path);
+      size_t suffix_len = strlen(suffix);
+
+      if (path_len >= suffix_len && strcmp(path + path_len - suffix_len, suffix) == 0) {
+          return 1;
+      }
+
+      // Check if the parent directory is authored
+      char *parent = strdup(path);
+      if (!parent) {
+          return 0;
+      }
+      dirname(parent);
+
+      int result = 0;
+      if (strlen(parent) >= suffix_len &&
+          strcmp(parent + strlen(parent) - suffix_len, suffix) == 0) {
+          result = 1;
+      }
+      free(parent);
+      return result;
+  }
+
+  int unlink(const char *pathname) {
+      if (is_authored(pathname)) {
+          fprintf(stderr, "unlink:: authored file not unlinked '%s'.\n", pathname);
+          errno = EPERM; // Operation not permitted
+          return -1;
+      }
+      // Call the original unlink system call
+      int (*original_unlink)(const char *) = dlsym(RTLD_NEXT, "unlink");
+      return original_unlink(pathname);
+  }
+
+#endif
index 9f8a586..d426be9 100644 (file)
@@ -1,3 +1,4 @@
+#define IFACE
 #include <unistd.h>
 #include <sys/types.h>
 #include <pwd.h>
index c20bd03..90bc630 100644 (file)
@@ -1,3 +1,4 @@
+#define IFACE
 #include <unistd.h>
 #include <sys/types.h>
 #include <pwd.h>
index 0a640e7..58ba68d 100644 (file)
@@ -1,3 +1,4 @@
+#define IFACE
 #include <unistd.h>
 #include <sys/types.h>
 #include <pwd.h>
diff --git a/developer/emacs🖉/emacs.el b/developer/emacs🖉/emacs.el
deleted file mode 100644 (file)
index 5ca4331..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-
-; The first time Emacs  encounters a link to a source file, Emacs asks if it should follow it.
-; This might suppress that initial question and follow the link.
-; (setq find-file-visit-truename t)
-
-(defun jdbx ()
-  "Set gud-jdb-sourcepath from the environment and run jdb with the correct source path."
-  (interactive)
-  (let* 
-    (
-      (sourcepath (getenv "SOURCEPATH"))
-      )
-    (if 
-      sourcepath
-      (setq gud-jdb-sourcepath (split-string sourcepath ":" t))
-      (message "Warning: SOURCEPATH is not set. `jdb` will run without source path information.")
-      )
-    (let 
-      (
-        (class-name (read-string "Enter the class to debug: " "Test_Util"))
-        )
-      (jdb (concat "jdb -sourcepath"
-             (if 
-               sourcepath 
-               (mapconcat 'identity gud-jdb-sourcepath ":") ""
-               )
-             " "
-             class-name
-             )
-        ))))
-
-(defun monitor-jdb-sourcepath (output)
-  "Monitor the jdb output for `sourcepath ARG` commands and update `gud-jdb-sourcepath` with each path in ARG."
-  (when 
-    (string-match "sourcepath \\(.+\\)" output)
-    (let* 
-      (
-        (new-paths (match-string 1 output))
-        (paths-list (split-string new-paths ":" t))
-        )
-      ;; Add each path in paths-list to gud-jdb-sourcepath if not already present
-      (dolist 
-        (path paths-list)
-        (unless 
-          (member path gud-jdb-sourcepath)
-          (setq gud-jdb-sourcepath (append gud-jdb-sourcepath (list path)))
-          )
-        )
-      (message "Updated gud-jdb-sourcepath: %s" gud-jdb-sourcepath)))
-  output)
-
-(add-hook 'gud-filter-functions 'monitor-jdb-sourcepath)
diff --git a/developer/emacs🖉/emacs🖉 b/developer/emacs🖉/emacs🖉
new file mode 120000 (symlink)
index 0000000..e355780
--- /dev/null
@@ -0,0 +1 @@
+/var/user_data/Thomas-developer/RT-incommon/developer/emacs🖉
\ No newline at end of file
diff --git a/developer/emacs🖉/jdbx.el b/developer/emacs🖉/jdbx.el
new file mode 100644 (file)
index 0000000..5ca4331
--- /dev/null
@@ -0,0 +1,52 @@
+
+; The first time Emacs  encounters a link to a source file, Emacs asks if it should follow it.
+; This might suppress that initial question and follow the link.
+; (setq find-file-visit-truename t)
+
+(defun jdbx ()
+  "Set gud-jdb-sourcepath from the environment and run jdb with the correct source path."
+  (interactive)
+  (let* 
+    (
+      (sourcepath (getenv "SOURCEPATH"))
+      )
+    (if 
+      sourcepath
+      (setq gud-jdb-sourcepath (split-string sourcepath ":" t))
+      (message "Warning: SOURCEPATH is not set. `jdb` will run without source path information.")
+      )
+    (let 
+      (
+        (class-name (read-string "Enter the class to debug: " "Test_Util"))
+        )
+      (jdb (concat "jdb -sourcepath"
+             (if 
+               sourcepath 
+               (mapconcat 'identity gud-jdb-sourcepath ":") ""
+               )
+             " "
+             class-name
+             )
+        ))))
+
+(defun monitor-jdb-sourcepath (output)
+  "Monitor the jdb output for `sourcepath ARG` commands and update `gud-jdb-sourcepath` with each path in ARG."
+  (when 
+    (string-match "sourcepath \\(.+\\)" output)
+    (let* 
+      (
+        (new-paths (match-string 1 output))
+        (paths-list (split-string new-paths ":" t))
+        )
+      ;; Add each path in paths-list to gud-jdb-sourcepath if not already present
+      (dolist 
+        (path paths-list)
+        (unless 
+          (member path gud-jdb-sourcepath)
+          (setq gud-jdb-sourcepath (append gud-jdb-sourcepath (list path)))
+          )
+        )
+      (message "Updated gud-jdb-sourcepath: %s" gud-jdb-sourcepath)))
+  output)
+
+(add-hook 'gud-filter-functions 'monitor-jdb-sourcepath)
index ba70241..f6d2c81 100644 (file)
@@ -1,5 +1,4 @@
 #ifndef RT·ENVIRONMENT_H
 #define RT·ENVIRONMENT_H
   typedef unsigned int uint;
-
 #endif
index 60d42b6..4b6513b 100644 (file)
@@ -1,70 +1,20 @@
 # makefile environment variable defaults.
-# include this in the local make file with a line such as:
-#
-#   RESOURCE:=$(REPO_HOME)/tool_shared/third_party/resource/release
-#   include $(RESOURCE)/make/environment_RT_0
-#
-# The Unix environment has traditionally combined linking and loading into one
-# program called `ld`, and the compiler conventionally also has a switch for
-# doing the linking. A programmer or user typically does not run the loader
-# explicitly, because the shall does this automatically. Consequently, the poor
-# linker has not been giving an explicit name, and no one thinks much about
-# loading.
-#
-# The ATT c compiler was called 'cc'.  However, today in makefiles 'CC' is often
-# used as the variable name for the C++ compiler.
-#
-# This all causes a bit of a problem when following the RT directory naming
-# convention, where, when practical, directories are named after the program
-# that will use the contained files.
-#
-# Here 'cc' is the directory containing files for cc, the C compiler.  The
-# directory 'linker' containers files for the unnamed linker, and, as loaders
-# are architecture specific, 'amd64' containers files for the architecture
-# 'amd64' loader. The variable CPP holds the name of the C++ compiler.
-
+#  cc is the name of the C compiler
+#  <name>.c is C source code.
 
 SHELL=/bin/bash
 
-#--------------------------------------------------------------------------------
-# useful macros
-#
-
-# a single space literal, for example if you wanted to subsitute commas to
-# spaces: $(subst $(space),;,$(string))
-
-blank :=
-space :=$(blank)  $(blank)
-
-#--------------------------------------------------------------------------------
-# main directories 
-# 
-DOCDIR=document
-EXECDIR=amd64
-LIBDIR=linker
-SRCDIR=cc
-INCDIR=cc
-TESTDIR=test
-TMPDIR=scratchpad
-TRYDIR=experiment
-
-#--------------------------------------------------------------------------------
-# Programs make uses.  
-#
 ECHO= echo -e
 #ECHO= echo
 
-# program to use to compile C, or to compile C++
-C=
-CPP=
+SRCDIR_List=cc cc🖉
+LIBDIR=scratchpad
+EXECDIR=amd64
+TMPDIR=scratchpad
 
-#--------------------------------------------------------------------------------
-# local targets
-#
 DEPFILE=$(TMPDIR)/makefile-cc.deps
-LIBFILE=$(LIBDIR)/lib$(PROJECT).a
-
-# we no longer use separate include file, but instead gate the C file
-# INCFILE=$(SRCDIR)/$(PROJECT).h
-
+LIBFILE=$(TMPDIR)/lib.a
 
+C=gcc
+CFLAGS=
+LINKFLAGS=-L$(LIBDIR) -L/lib64 -L/lib
index 2d06218..5d620af 100644 (file)
@@ -1,44 +1,42 @@
+.SUFFIXES:
+
 #--------------------------------------------------------------------------------
-# This makefile must be called through a local makefile rather than directly.
-# the local make file should include:
-#
-#  1. cp $(RESOURCE)/release/make/makefile-environment_example to get started on a make environment.
-#  2. modify it and set the variables to custom values
-#  3. the environment file should include this file, probably at $(RESOURCE)/release/make/makefile
-#  4. if tailored targets are needed, add them 
+# files have two suffixes by convention, e.g.: X.lib.c or Y.cli.c 
 #
 
-#--------------------------------------------------------------------------------
-# todo ...
+# bail early if there is no compiler
+ifeq ($(C),)
+  $(error No C compiler specified.)
+endif
 
-# should add test that incdir is not pwd before deleting the include
-# file. Currently it is working for us despite this problem because dist-clean is
-# looking for $(module).h while the include file is always $(module).lib.h.
+# keep only the source directories that are in the file system
+SRCDIR_List := $(wildcard $(SRCDIR_List))
 
-#--------------------------------------------------------------------------------
-# files named by convention
-#   this implements the .lib.c  and the .cli.c convention
-#
+# bail early if the SRCDIR_list is empty
+ifeq ($(SRCDIR_List),)
+  $(error source directory found so nothing to do)
+endif
+
+# duplicate source file names in different directories will cause
+# problems with this makefile
 
-# these are the sources edited by the programmer
-C_SOURCE_LIB=  $(wildcard $(SRCDIR)/*.lib.c)
-C_SOURCE_EXEC=  $(wildcard $(SRCDIR)/*.cli.c)
-CPP_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.cc)
-CPP_SOURCE_EXEC= $(wildcard $(SRCDIR)/*.cli.cc)
+C_SOURCE_LIB := $(foreach dir, $(SRCDIR_List), $(wildcard $(dir)/*.lib.c))
+C_SOURCE_EXEC := $(foreach dir, $(SRCDIR_List), $(wildcard $(dir)/*.cli.c))
 
 #remove the suffix to get base name
 C_BASE_LIB=  $(sort $(patsubst %.lib.c,  %, $(notdir $(C_SOURCE_LIB))))
 C_BASE_EXEC=  $(sort $(patsubst %.cli.c,  %, $(notdir $(C_SOURCE_EXEC))))
-CPP_BASE_LIB= $(sort $(patsubst %.lib.cc, %, $(notdir $(CPP_SOURCE_LIB))))
-CPP_BASE_EXEC= $(sort $(patsubst %.cli.cc, %, $(notdir $(CPP_SOURCE_EXEC))))
 
 # two sets of object files, one for the lib, and one for the command line interface progs
-OBJECT_LIB= $(patsubst %, $(TMPDIR)/%.lib.o, $(C_BASE_LIB) $(CPP_BASE_LIB))
-OBJECT_EXEC= $(patsubst %, $(TMPDIR)/%.cli.o, $(C_BASE_EXEC) $(CPP_BASE_EXEC))
+OBJECT_LIB= $(patsubst %, $(TMPDIR)/%.lib.o, $(C_BASE_LIB))
+OBJECT_EXEC= $(patsubst %, $(TMPDIR)/%.cli.o, $(C_BASE_EXEC))
 
 # executables are made from EXEC sources
-EXEC= $(patsubst %, $(EXECDIR)/%, $(C_BASE_EXEC) $(CPP_BASE_EXEC))
+EXEC= $(patsubst %, $(EXECDIR)/%, $(C_BASE_EXEC))
 
+# new C programming style uses cpp macros to the source is the header
+INCFLAG_List := $(foreach dir, $(SRCDIR_List), -I $(dir))
+CFLAGS += $(INCFLAG_List)
 
 #--------------------------------------------------------------------------------
 # targets
@@ -55,84 +53,31 @@ usage:
 version:
        @echo makefile version 7.1
        if [ ! -z "$(C)" ]; then $(C) -v; fi
-       if [ ! -z "$(CPP)" ]; then $(CPP) -v; fi
        /bin/make -v
 
-.PHONY: info
-info:
-       @echo "C: " $(C)
-       @echo "CPP: " $(CPP)
-       @echo "CPPFLAGS: " $(CPPFLAGS)
-       @echo "CPP_BASE_EXEC: " $(CPP_BASE_EXEC)
-       @echo "CPP_BASE_LIB: " $(CPP_BASE_LIB)
-       @echo "CPP_SOURCE_EXEC: " $(CPP_SOURCE_EXEC)
-       @echo "CPP_SOURCE_LIB: " $(CPP_SOURCE_LIB)
-       @echo "CFLAGS: " $(CFLAGS)
-       @echo "C_BASE_EXEC: " $(C_BASE_EXEC)
-       @echo "C_BASE_LIB: " $(C_BASE_LIB)
-       @echo "C_SOURCE_EXEC: " $(C_SOURCE_EXEC)
+.PHONY: information
+information:
+       @echo "SRCDIR_List: " $(SRCDIR_List)
        @echo "C_SOURCE_LIB: " $(C_SOURCE_LIB)
-       @echo "DEPFILE: " $(DEPFILE)
-       @echo "DOCDIR: " $(DOCDIR)
-       @echo "ECHO: " $(ECHO)
-       @echo "EXEC: " $(EXEC)
-       @echo "EXECDIR: " $(EXECDIR)
-       @echo "INCDIR: " $(INCFILE)
-       @echo "LIBDIR: " $(LIBDIR)
-       @echo "LIBFILE: " $(LIBFILE)
-       @echo "LINKFLAGS: " $(LINKFLAGS)
-       @echo "OBJECT_EXEC: " $(OBJECT_EXEC)
+       @echo "C_SOURCE_EXEC: " $(C_SOURCE_EXEC)
+       @echo "C_BASE_LIB: " $(C_BASE_LIB)
+       @echo "C_BASE_EXEC: " $(C_BASE_EXEC)
        @echo "OBJECT_LIB: " $(OBJECT_LIB)
-       @echo "SHELL: " $(SHELL)
-       @echo "SRCDIR: " $(INCFILE)
-       @echo "TESTDIR: " $(TESTDIR)
-       @echo "TMPDIR: " $(TMPDIR)
-       @echo "TRYDIR: " $(TRYDIR)
-
-# should be safe to run this in an already setup or partially setup directory
-# gee looks like a candidate for a makefile function ..
-.PHONY: setup
-setup:
-       [ ! -e $(DOCDIR)  ]  && mkdir $(DOCDIR)  || true
-       [ ! -e $(EXECDIR) ]  && mkdir $(EXECDIR) || true
-       [ ! -e $(LIBDIR)  ]  && mkdir $(LIBDIR)  || true
-       [ ! -e $(SRCDIR)  ]  && mkdir $(SRCDIR)  || true
-       [ ! -e $(TESTDIR) ]  && mkdir $(TESTDIR) || true
-       [ ! -e $(TMPDIR)  ]  && mkdir $(TMPDIR)  || true
-       [ ! -e $(TRYDIR)  ]  && mkdir $(TRYDIR)  || true
+       @echo "OBJECT_EXEC: " $(OBJECT_EXEC)
+       @echo "EXEC: " $(EXEC)
+       @echo "INCFLAG_List: " $(INCFLAG_List)
+
 
 .PHONY: dependency
 dependency:
        @rm -f $(DEPFILE)
-       @if [ -z "$(CPP)" ]; then\
-         if [ -z "$(C)" ]; then\
-           $(ECHO) "No compiler specified";\
-           exit 1;\
-         else\
-           echo "C compiler only deps" ;\
-           $(C) $(CFLAGS) -MM  $(C_SOURCE_LIB) $(C_SOURCE_EXEC) | sed 's|^.*\.o|$(TMPDIR)/&|' >> $(DEPFILE);\
-           echo "deps for C linking";\
-           for i in $(C_BASE_EXEC); do\
-             $(ECHO) >> $(DEPFILE);\
-             $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\
-             $(ECHO) " $(C) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\
-           done;\
-         fi;\
-       else\
-         $(CPP) $(CPPFLAGS) -MM  $(CPP_SOURCE_LIB) $(CPP_SOURCE_EXEC) | sed 's|^.*\.o|$(TMPDIR)/&|' >> $(DEPFILE);\
-         if [ -z "$C()" ]; then\
-           echo "CPP compiler only deps" ;\
-         else\
-           echo "CPP and C mixed compile deps" ;\
-           $(C) $(CFLAGS) -MM   $(C_SOURCE_LIB) $(C_SOURCE_EXEC) | sed 's|^.*\.o|$(TMPDIR)/&|' >> $(DEPFILE);\
-         fi;\
-         echo "deps for CPP linking";\
-         for i in $(CPP_BASE_EXEC) $(C_BASE_EXEC) ; do\
-           $(ECHO) >> $(DEPFILE);\
-           $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\
-           $(ECHO) "   $(CPP) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\
-         done;\
-       fi
+       $(C) $(CFLAGS) -MM  $(C_SOURCE_LIB) $(C_SOURCE_EXEC) | sed 's|^.*\.o|$(TMPDIR)/&|' >> $(DEPFILE);\
+       echo "deps for C linking";\
+       for i in $(C_BASE_EXEC); do\
+         $(ECHO) >> $(DEPFILE);\
+         $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\
+         $(ECHO) "     $(C) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\
+       done;
 
 .PHONY: library
 library: $(LIBFILE)
@@ -147,27 +92,17 @@ cli: $(LIBFILE)
 .PHONY: sub_cli
 sub_cli: $(EXEC)
 
-.PHONY: share
-share:
-       if [ ! -z "$(wildcard $(LIBDIR)/*)" ]; then cp $(LIBDIR)/* $(DIST_TARGET)/$(LIBDIR); fi
-       if [ ! -z "$(wildcard $(EXECDIR)/*)" ]; then cp $(EXECDIR)/* $(DIST_TARGET)/$(EXECDIR); fi
-#      if [ ! -z "$(wildcard $(SRCDIR)/*.h)" ]; then cp $(SRCDIR)/*.h $(DIST_TARGET)/include; fi
-
-
 .PHONY: clean
 clean:
-       rm -f $(DEPFILE)
-       rm -f $(LIBFILE)
-       for i in $(wildcard $(TMPDIR)/*.o); do rm $$i || true; done 
+       rm -f $(DEPFILE) $(LIBFILE)
+       for obj in $(OBJECT_LIB) $(OBJECT_EXEC); do rm -f $$obj || true; done
+
 
 .PHONY: dist-clean
 dist-clean: clean
        for i in $(EXEC); do [ -e $$i ] && rm $$i || true; done 
 
 # recipes
- $(TMPDIR)/%.o : $(SRCDIR)/%.c
+vpath %.c $(SRCDIR_List)
+$(TMPDIR)/%.o: %.c
        $(C) $(CFLAGS) -o $@ -c $<
-
- $(TMPDIR)/%.o : $(SRCDIR)/%.cc
-       $(CPP) $(CPPFLAGS) -o $@ -c $<
-
diff --git a/developer/test/e/f🖉/ff b/developer/test/e/f🖉/ff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/developer/test/e/f🖉/g/gg b/developer/test/e/f🖉/g/gg
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/developer/test/rm b/developer/test/rm
new file mode 100755 (executable)
index 0000000..93ce511
Binary files /dev/null and b/developer/test/rm differ
index 7fd5455..154c63a 100644 (file)
@@ -3,7 +3,7 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
 
 # input guards
 
-  env_must_be="tool_shared/bespoke/env"
+  env_must_be="tool_shared/bespoke🖉/env"
   error=false
   if [ "$ENV" != "$env_must_be" ]; then
     echo "$(script_fp):: error: must be run in the $env_must_be environment"
@@ -18,8 +18,8 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
 # so we can do the build
 
 export PATH=\
-"$REPO_HOME"/developer/tool/\
-:"$REPO_HOME"/tool_shared/bespoke/\
+"$REPO_HOME"/developer/tool🖉/\
+:"$REPO_HOME"/tool_shared/bespoke🖉/\
 :"$PATH"
 
 # misc
index 5ab34eb..84e1111 100755 (executable)
@@ -2,5 +2,5 @@
 
 set -e
 cd ${REPO_HOME}/developer
-/bin/make -f tool/makefile $@
+/bin/make -f tool🖉/makefile $@
 
index 8a64b72..550c796 100644 (file)
@@ -1,17 +1,17 @@
-# /bin/make must be run from $REPO_HOME/developer
 
-RESOURCE:=$(REPO_HOME)/developer
-include $(RESOURCE)/make/environment_RT_0
+RT-INCOMMON:=$(REPO_HOME)/release
 
-# override defaults
-LIBDIR=scratchpad
+include $(RT-INCOMMON)/make/environment_RT_0
 
-# compiler to use
-C=gcc
-CFLAGS= -Werror -include "$(RESOURCE)/make/RT_0.h" -I$(INCDIR) 
-LINKFLAGS=-L$(LIBDIR) -L/usr/lib64 -L/usr/lib -l$(PROJECT)
+CFLAGS+=-Werror -include "$(RT-INCOMMON)/make/RT_0.h"
+LINKFLAGS+= -l$(PROJECT)
+LIBFILE=$(LIBDIR)/lib$(PROJECT).a
 
-# Import the rules. The dash prefix means to ignore include errors. This is
-# required because the DEPFILE might not exist yet.
-include $(RESOURCE)/make/targets
+include $(RT-INCOMMON)/make/targets
 -include $(DEPFILE)
+
+
+
+
+
+
index 2846eac..ac55973 100755 (executable)
@@ -8,7 +8,7 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
     exit 1
   fi
 
-  env_must_be="developer/tool/env"
+  env_must_be="developer/tool🖉/env"
   if [ "$ENV" != "$env_must_be" ]; then
     echo "$(script_fp):: error: must be run in the $env_must_be environment"
     exit 1
@@ -16,11 +16,9 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
 
 # script local environment
 
-  release_dir="$REPO_HOME/release"
-  shell_dir="$REPO_HOME/developer/shell"
-
-  if [ ! -d "$release_dir" ]; then
-    mkdir -p "$release_dir"
+  release_dp="$REPO_HOME/release"
+  if [ ! -d "$release_dp" ]; then
+    mkdir -p "$release_dp"
   fi
 
   # Function to copy and set permissions
@@ -48,9 +46,18 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
 
   echo "Starting release process..."
 
-  # Install shell scripts
-  for script in $shell_dir/*; do
-    install_file "$script" "$release_dir" "ug+r+x"
-  done
+  # # Install shell scripts
+  # for script in $shell_dp/*; do
+  #   install_file "$script" "$release_dp" "ug+r+x"
+  # done
+
+  dev_dp="$REPO_HOME/developer"
+
+  # punt the release ...
+  ln -sf "$dev_dp"/amd64 "$release_dp"
+  ln -sf "$dev_dp"/bash🖉 "$release_dp/bash"
+  ln -sf "$dev_dp"/emacs🖉 "$release_dp/emacs"
+  ln -sf "$dev_dp"/make🖉 "$release_dp/make"
+
 
 echo "$(script_fp) done."
index 46daa61..8f45dd5 100644 (file)
@@ -48,7 +48,7 @@ In addition a reader can read this document for some general principles.
 
 4. invocation inside of Emacs
 
-   The file found in the resource project, developer/emacs/emacs.el` holds a
+   The file found in the RT-incommon project, developer/release/emacs/jdbx.el` holds a
    definition for the `jdbx` command.  This command will read the SOURCEPATH
    from the environment and run jdb in Emacs.
 
index bb09700..2f09f8a 100644 (file)
@@ -5,6 +5,6 @@ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
   exit 1
 fi
 
-source tool_shared/bespoke/env
-source tool/env
+source tool_shared/bespoke🖉/env
+source tool🖉/env
 
index 6240b20..c2f5c58 100644 (file)
@@ -5,6 +5,6 @@ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
   exit 1
 fi
 
-source tool_shared/bespoke/env
-source developer/tool/env
+source tool_shared/bespoke🖉/env
+source developer/tool🖉/env
 
index 3299023..36df441 100644 (file)
@@ -5,6 +5,6 @@ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
   exit 1
 fi
 
-source tool_shared/bespoke/env
-source tester/tool/env
+source tool_shared/bespoke🖉/env
+source tester/tool🖉/env
 
diff --git a/release/amd64 b/release/amd64
new file mode 120000 (symlink)
index 0000000..0646adb
--- /dev/null
@@ -0,0 +1 @@
+/var/user_data/Thomas-developer/RT-incommon/developer/amd64
\ No newline at end of file
diff --git a/release/bash b/release/bash
new file mode 120000 (symlink)
index 0000000..2f24fc4
--- /dev/null
@@ -0,0 +1 @@
+../developer/bash🖉/
\ No newline at end of file
diff --git a/release/emacs b/release/emacs
new file mode 120000 (symlink)
index 0000000..e0f7198
--- /dev/null
@@ -0,0 +1 @@
+../developer/emacs🖉/
\ No newline at end of file
diff --git a/release/make b/release/make
new file mode 120000 (symlink)
index 0000000..35c7676
--- /dev/null
@@ -0,0 +1 @@
+/var/user_data/Thomas-developer/RT-incommon/developer/make🖉
\ No newline at end of file
index 73eaff8..a318fa0 100644 (file)
@@ -3,7 +3,7 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
 
 # input guards
 
-  env_must_be="tool_shared/bespoke/env"
+  env_must_be="tool_shared/bespoke🖉/env"
   error=false
   if [ "$ENV" != "$env_must_be" ]; then
     echo "$(script_fp):: error: must be run in the $env_must_be environment"
@@ -16,7 +16,7 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
   if $error; then exit 1; fi
 
 export PATH=\
-"$REPO_HOME"/tool_shared/bespoke/\
+"$REPO_HOME"/tool_shared/bespoke🖉/\
 :"$PATH"
 
 # expose sneaky hidden files