Good weekend,

If you consider in-line option is useful for unexpand I could wrote
another patch for expand command which will do the same thing.

-- 
  Sami Kerola
  http://www.iki.fi/kerolasa/
From ef6192da066dcf3c65bc9a672ecf78c30894ac95 Mon Sep 17 00:00:00 2001
From: Sami Kerola <kerol...@iki.fi>
Date: Sat, 21 Mar 2009 18:23:04 +0100
Subject: [PATCH] in place option for unexpand
Cc: kerol...@iki.fi

---
 src/unexpand.c |  116 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 95 insertions(+), 21 deletions(-)

diff --git a/src/unexpand.c b/src/unexpand.c
index 9f6a6d7..93f1ce8 100644
--- a/src/unexpand.c
+++ b/src/unexpand.c
@@ -85,11 +85,23 @@ static bool have_read_stdin;
 /* The desired exit status.  */
 static int exit_status;
 
+/* Write back file if true */
+static bool in_place;
+
 /* For long options that have no equivalent short option, use a
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
 {
-  CONVERT_FIRST_ONLY_OPTION = CHAR_MAX + 1
+  CONVERT_FIRST_ONLY_OPTION = CHAR_MAX + 1,
+  IN_PLACE_OPTION
+};
+
+struct in_out_files
+{
+  FILE *infile;
+  FILE *outfile;
+  char *temp;
+  struct stat st;
 };
 
 static struct option const longopts[] =
@@ -97,6 +109,7 @@ static struct option const longopts[] =
   {"tabs", required_argument, NULL, 't'},
   {"all", no_argument, NULL, 'a'},
   {"first-only", no_argument, NULL, CONVERT_FIRST_ONLY_OPTION},
+  {"in-place", no_argument, NULL, IN_PLACE_OPTION},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -128,6 +141,9 @@ Mandatory arguments to long options are mandatory for short 
options too.\n\
   -t, --tabs=N     have tabs N characters apart instead of 8 (enables -a)\n\
   -t, --tabs=LIST  use comma separated LIST of tab positions (enables -a)\n\
 "), stdout);
+      fputs (_("\
+      --in-place   edit files in place\n\
+"), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
       emit_bug_reporting_address ();
@@ -234,41 +250,90 @@ validate_tab_stops (uintmax_t const *tabs, size_t entries)
    Open a filename of `-' as the standard input.
    Return NULL if there are no more input files.  */
 
-static FILE *
-next_file (FILE *fp)
+static struct in_out_files *
+next_file (struct in_out_files *iofs)
 {
   static char *prev_file;
   char *file;
+  char pattern[] = "unexpandXXXXXX";
+  char *tmpdir = NULL;
 
-  if (fp)
+  if (iofs->infile)
     {
-      if (ferror (fp))
+      if (ferror (iofs->infile))
        {
          error (0, errno, "%s", prev_file);
          exit_status = EXIT_FAILURE;
        }
       if (STREQ (prev_file, "-"))
-       clearerr (fp);          /* Also clear EOF.  */
-      else if (fclose (fp) != 0)
+       clearerr (iofs->infile);                /* Also clear EOF.  */
+      else
        {
-         error (0, errno, "%s", prev_file);
-         exit_status = EXIT_FAILURE;
-       }
+         if (fclose (iofs->infile) != 0)
+           {
+             error (0, errno, "%s", prev_file);
+             exit_status = EXIT_FAILURE;
+            }
+          if (in_place && (fclose (iofs->outfile) != 0))
+            {
+              error (0, errno, "%s", iofs->temp);
+              exit_status = EXIT_FAILURE;
+            }
+          if (rename(iofs->temp, prev_file))
+            {
+              error (0, errno, "moving a temporary file in place failed");
+              exit_status = EXIT_FAILURE;
+            }
+          if (chmod(prev_file, iofs->st.st_mode))
+            {
+              error (0, errno, "resetting file mode failed");
+              exit_status = EXIT_FAILURE;
+            }
+        }
     }
 
   while ((file = *file_list++) != NULL)
     {
       if (STREQ (file, "-"))
        {
+         if (in_place)
+           error (EXIT_FAILURE, 0, _("in place and reading stdin cannot be 
combined"));
          have_read_stdin = true;
          prev_file = file;
-         return stdin;
+         iofs->infile = stdin;
+         iofs->outfile = stdout;
+         return iofs;
        }
-      fp = fopen (file, "r");
-      if (fp)
+      iofs->infile = fopen (file, "r");
+      fstat(fileno (iofs->infile), &(iofs->st));
+      if (iofs->infile)
        {
          prev_file = file;
-         return fp;
+         if (in_place)
+           {
+              if (! ((tmpdir=getenv("TMPDIR"))))
+                {
+                  tmpdir=getenv("TMP");
+                }
+              if (!tmpdir)
+                {
+                  tmpdir = "/tmp";
+                }
+              iofs->temp = xmalloc(strlen(tmpdir) + strlen(pattern) + 2);
+              strcpy(iofs->temp, tmpdir);
+              strcat(iofs->temp, "/");
+              strcat(iofs->temp, pattern);
+             if (mkstemp(iofs->temp) == 0 ||
+               (iofs->outfile = fopen(iofs->temp, "w")) == NULL)
+               {
+                 error (EXIT_FAILURE, 0, _("creating a tmpfile failed"));
+               }
+           }
+          else
+            {
+              iofs->outfile = stdout;
+            }
+         return iofs;
        }
       error (0, errno, "%s", file);
       exit_status = EXIT_FAILURE;
@@ -276,21 +341,25 @@ next_file (FILE *fp)
   return NULL;
 }
 
-/* Change blanks to tabs, writing to stdout.
+/* Change blanks to tabs, writing to stdout or a file if in place defined.
    Read each file in `file_list', in order.  */
 
 static void
 unexpand (void)
 {
+  struct in_out_files *iofs;
+  iofs = xmalloc (sizeof(struct in_out_files));
+  iofs->infile = NULL;
+
   /* Input stream.  */
-  FILE *fp = next_file (NULL);
+  iofs = next_file (iofs);
 
   /* The array of pending blanks.  In non-POSIX locales, blanks can
      include characters other than spaces, so the blanks must be
      stored, not merely counted.  */
   char *pending_blank;
 
-  if (!fp)
+  if (!iofs->infile)
     return;
 
   /* The worst case is a non-blank character, then one blank, then a
@@ -306,7 +375,6 @@ unexpand (void)
       /* If true, perform translations.  */
       bool convert = true;
 
-
       /* The following variables have valid values only when CONVERT
         is true:  */
 
@@ -335,7 +403,7 @@ unexpand (void)
 
       do
        {
-         while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
+         while ((c = getc (iofs->infile)) < 0 && (iofs = next_file (iofs)))
            continue;
 
          if (convert)
@@ -422,7 +490,7 @@ unexpand (void)
 
              if (pending)
                {
-                 if (fwrite (pending_blank, 1, pending, stdout) != pending)
+                 if (fwrite (pending_blank, 1, pending, iofs->outfile) != 
pending)
                    error (EXIT_FAILURE, errno, _("write error"));
                  pending = 0;
                  one_blank_before_tab_stop = false;
@@ -438,17 +506,20 @@ unexpand (void)
              return;
            }
 
-         if (putchar (c) < 0)
+         if (putc(c, iofs->outfile) < 0)
            error (EXIT_FAILURE, errno, _("write error"));
        }
       while (c != '\n');
     }
+    free (iofs->temp);
+    free (iofs);
 }
 
 int
 main (int argc, char **argv)
 {
   bool have_tabval = false;
+  in_place = false;
   uintmax_t tabval IF_LINT (= 0);
   int c;
 
@@ -487,6 +558,9 @@ main (int argc, char **argv)
        case CONVERT_FIRST_ONLY_OPTION:
          convert_first_only = true;
          break;
+        case IN_PLACE_OPTION:
+          in_place = true;
+          break;
        case ',':
          if (have_tabval)
            add_tab_stop (tabval);
-- 
1.6.2

_______________________________________________
Bug-coreutils mailing list
Bug-coreutils@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-coreutils

Reply via email to