Combined tool to find and fix MS-DOS line endings.

Alex Cherepanov <[email protected]> Mon, 20 Sep 2004 15:27:57 -0400
Newsgroups gmane.comp.printing.ghostscript.patches
Organization Coscript Software
Message-ID <[email protected]>
Per Igor's request here's a combined program
to find and fix MS-DOS line endings.

The program is formatted according to GNU format style:
   indent fix_cr.c

_______________________________________________
gs-code-review mailing list
[email protected]
http://www.ghostscript.com/mailman/listinfo/gs-code-review
fix_cr.c (text/plain, 4.6 KB)
/*
 * Copyright 2004 Alex Cherepanov
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
/* 
 * Search and delete '\r' characters from the files in place.
 * The file is modified only when it has '\r' characters and
 * --not-fix is not set. Binary files are not modified except
 * in the forced mode.
 *
 * This program was written to normalize line endings in MS-DOS
 * and Mac files before submitting them to the UNIX-compatible project.
 * The program loads the whole file to core, converts '\r\n' to '\n'
 * and single '\r' to '\n', and writes the file back when needed.
 */
char version[] = "$Id: $";

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>

#ifdef _MSC_VER
#  define lseek   _lseek
#  define fileno  _fileno
#  define stat    _stat
#  define S_ISDIR(s) (s & _S_IFDIR)
#endif

#define STR2MEM0(s) s,sizeof(s)

static void
error (char *fmt, ...)
{
  va_list v;
  va_start (v, fmt);
  vfprintf (stderr, fmt, v);
  perror ("strerror");
  va_end (v);
}

static int
is_binary (char *p, int len)
{
  int i, rc = 0, cnt[256];

  memset (cnt, 0, sizeof (cnt));
  for (i = 0; i < len; i++)
    cnt[p[i] & 0xFF] = 1;

  cnt['\r'] = cnt['\n'] = cnt['\t'] = cnt['\f'] = 0;
  for (i = 0; i < 32; i++)
    rc |= cnt[i];
  return rc;
}


int
main (int argc, char **argv)
{
  int i;
  int force = 0;
  int not_fix = 0;
  int max_opt = argc < 3 ? argc : 3;

  if (argc == 2)
    {
      if (!strncmp (argv[1], STR2MEM0 ("--help")))
	{
	  printf
	    ("Search and delete '\\r' characters from the files in place.\n");
	  printf
	    ("The file is modified only when it has '\\r' characters and --not-fix\n");
	  printf
	    ("flag is not set. Binary files are ignored unless forced.\n\n");
	  printf ("Usage:\tfix_cr --help\n");
	  printf ("\tfix_cr --version\n");
	  printf
	    ("\tfix_cr [ -f | --force] [ -n | --not-fix ] FILE1 FILE2 FILE3 ...\n");
	  exit (0);
	}
      if (!strncmp (argv[1], STR2MEM0 ("--version")))
	{
	  printf ("%s\n", version);
	  exit (0);
	}
    }
  for (i = 1; i < max_opt; i++)
    {
      if (!strncmp (argv[i], STR2MEM0 ("-fn"))
	  || !strncmp (argv[i], STR2MEM0 ("-nf")))
	{
	  force = not_fix = 1;
	  continue;
	}
      if (!strncmp (argv[i], STR2MEM0 ("-f"))
	  || !strncmp (argv[i], STR2MEM0 ("--force")))
	{
	  force = 1;
	  continue;
	}
      if (!strncmp (argv[i], STR2MEM0 ("-n"))
	  || !strncmp (argv[i], STR2MEM0 ("--not-fix")))
	{
	  not_fix = 1;
	  continue;
	}
      break;
    }

  for (; i < argc; i++)
    {
      long len;
      char *buf;
      struct stat st;
      FILE *f;

      if (stat (argv[i], &st) == EOF)
	{
	  error ("Cannot get status on %s\n", argv[i]);
	  exit (1);
	}
      if (S_ISDIR (st.st_mode))
	continue;
      len = st.st_size;

      f = fopen (argv[i], "rb");
      if (f == 0)
	{
	  error ("Cannot open %s for reading\n", argv[i]);
	  exit (2);
	}

      buf = malloc (len + 1);
      if (buf == 0)
	{
	  error ("Cannot allocate %d bytes\n", len + 1);
	  fclose (f);
	  exit (4);
	}
      buf[len] = 0;

      fseek (f, 0, SEEK_SET);
      if (fread (buf, 1, len, f) != len)
	{
	  error ("Error reading %s\n", argv[i]);
	  free (buf);
	  fclose (f);
	  exit (5);
	}
      fclose (f);
      if (memchr (buf, '\r', len))
	{
	  long j;
	  if (!force && is_binary (buf, len))
	    {
	      fprintf (stderr, "Skipping binary file %s\n", argv[i]);
	    }
	  else
	    {
	      printf ("%s\n", argv[i]);
	      if (!not_fix)
		{
		  f = fopen (argv[i], "wb");
		  if (!f)
		    {
		      error ("Cannot open %s for writing\n", argv[i]);
		      free (buf);
		      exit (6);
		    }
		  for (j = 0; j < len; j++)
		    {
		      char c = buf[j];
		      if (c == '\r')
			{
			  if (buf[j + 1] == '\n')
			    continue;
			  c = '\n';
			}
		      if (putc (c, f) == EOF)
			{
			  error ("Error writing %s\n", argv[i]);
			  free (buf);
			  exit (7);
			}
		    }
		  fclose (f);
		}
	    }
	}
      free (buf);
    }
  return 0;
}