home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / utils.zip / trim.c < prev    next >
C/C++ Source or Header  |  2008-04-05  |  7KB  |  240 lines

  1. /*  T R I M -- Trim trailing whitespace from file lines and/or untabify  */
  2.  
  3. /*
  4.   Author:      F. da Cruz, The Kermit Project, Columbia University
  5.   Email:       fdc@columbia.edu
  6.   Portability: Should be portable to most UNIXes and maybe VMS.
  7.   Written in 1999, updated in 2008 to add lowercasing.
  8.  
  9.   Please send any changes back to the author.
  10.  
  11.   Copyright (C) 1999, 2008
  12.   Trustees of Columbia University in the City of New York
  13.  
  14.   This program is free software; you can redistribute it and/or modify
  15.   it under the terms of the GNU General Public License as published by
  16.   the Free Software Foundation; either version 2 of the License, or
  17.   (at your option) any later version.
  18.  
  19.   This program is distributed in the hope that it will be useful,
  20.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.   GNU General Public License for more details.
  23.  
  24.   You should have received a copy of the GNU General Public License
  25.   along with this program; if not, write to the Free Software
  26.   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  27. */
  28. #include <stdio.h>
  29. #include <ctype.h>
  30. #include <sys/stat.h>
  31.  
  32. #define MAX 32767
  33.  
  34. char buf[MAX];                /* I/O buffers */
  35. char obuf[MAX];
  36. char tmpname[256];            /* Filename buffers */
  37. char tmp2[256];
  38. FILE *fp, *op, *fopen();        /* Streams */
  39. int n = 0;                /* File counter */
  40. int lower = 0;                /* Convert to lowercase */
  41. int warn = 0;                /* Warn-only flag */
  42. int untab = 0;                /* Untabify flag */
  43. int changed = 0;            /* Flag for file changed */
  44. int stdo = 0;                /* Write to stdout instead of file */
  45. struct stat statbuf;            /* For stat() */
  46.  
  47. /* NOTE: argument bundling doesn't work - easy to fix - do this one day */
  48.  
  49. char * hlptxt[] = {
  50.     "Usage: trim [ -w -s -c -t -h ] [ file [ file [ file ... ] ] ]",
  51.     " ",
  52.     "Trims trailing whitespace from lines in given file(s), replacing each",
  53.     "file with a trimmed version and renaming the original to *.untrimmed.",
  54.     "If no files are specified on the command line, operates on stdin and",
  55.     "writes to stdout.",
  56.     " ",
  57.     "  -c = also convert to lowercase",
  58.     "  -t = also untabify (convert tabs to spaces)",
  59.     "  -s = write to stdout instead of replacing source file",
  60.     "  -w = warn only, don't change the files.",
  61.     "  -h = print this message",
  62.     " ",
  63.     "-w lists both lines with trailing whitespace and lines that would be",
  64.     "longer than 80 characters after tab expansion.  Tab settings are assumed",
  65.     "to be every 8 spaces",
  66.     "",
  67. };
  68.  
  69. usage(x) int x; {            /* Usage function */
  70.     int i;                /* Print usage message and exit */
  71.     for (i = 0; *hlptxt[i]; i++)
  72.       fprintf(stderr,"%s\n",hlptxt[i]);
  73.     exit(x);
  74. }
  75.  
  76. main(argc,argv) int argc; char *argv[]; { /* Main program */
  77.     int i;                /* Declare local variables */
  78.     int result;
  79.  
  80.     for (i = 1; i < argc; i++) {    /* For each argument... */
  81.     changed = 0;
  82.     if (n == 0 && *argv[i] == '-') { /* First do any options */
  83.         switch (*(argv[i]+1)) {
  84.           case 't':
  85.         untab = 1;
  86.         continue;
  87.           case 'w':
  88.         warn = 1;
  89.         continue;
  90.           case 'c':
  91.         lower = 1;
  92.         continue;
  93.           case 's':
  94.         stdo = 1;
  95.         continue;
  96.           case 'h':
  97.         usage(0);
  98.           default:
  99.         usage(1);
  100.         }
  101.         continue;
  102.     }
  103.     fprintf(stderr,"%3d. %s...",n,argv[i]);    /* Got a file */
  104.     if (stat(argv[i],&statbuf) < 0) {
  105.         printf("(skipped - stat error)\n");
  106.         continue;
  107.     }
  108.     if (!S_ISREG(statbuf.st_mode)) {
  109.         fprintf(stderr,"(skipped - not regular file)\n");
  110.         continue;
  111.     }
  112.     fp = fopen(argv[i], "r");    /* Try to open it */
  113.     if (fp == NULL) {        /* Check for errors */
  114.         perror(argv[i]);
  115.         continue;
  116.     }
  117.     n++;
  118.     result = process();        /* "Process" the file */
  119.     if (fclose(fp) == EOF) {    /* Close the file */
  120.         perror(argv[i]);
  121.         continue;
  122.     }
  123.     if (result < 0) continue;
  124.     if (!warn && changed) {
  125.         sprintf(tmp2,"%s.untrimmed",argv[i]);
  126.         if (rename(argv[i],tmp2) < 0) {
  127.         perror("rename");
  128.         exit(1);
  129.         }
  130.         if (rename(tmpname,argv[i]) < 0) {
  131.         perror("rename");
  132.         exit(1);
  133.         } else
  134.           fprintf(stderr,"(replaced OK)\n");
  135.     } else
  136.       if (result == 0)
  137.         fprintf(stderr,"(OK)\n");
  138.     }
  139.     if (n == 0) {            /* No files given - use stdio */
  140.     fp = stdin;
  141.     result = process();
  142.     }
  143.     exit(result == 0 ? 0 : 1);
  144. }
  145.  
  146. int
  147. process() {                /* Process the file */
  148.     int i, j, k, x, flag, bads = 0;
  149.     char * p;
  150.     long line = 0L;
  151.     if (!warn) {
  152.     sprintf(tmpname,"...tmp%03d",n);
  153.     if (fp == stdin || stdo)
  154.       op = stdout;
  155.     else
  156.       op = fopen(tmpname,"w");
  157.     if (op == NULL) { perror("fopen tmp file"); exit(1); }
  158.     }
  159. /*
  160.   Note: this used to be "while (fgets(...)) ..." but, despite what the
  161.   man page says, this terminates early in Solaris 2.5.1 (at least when
  162.   built with Sun CC).  For some reason, changing the loop exit condition
  163.   as you see it below stopped the early termination, even though the
  164.   feof() call does not catch the eof, so it's the test on the fgets()
  165.   return status that breaks the loop -- which is exactly what didn't work
  166.   when it was the while-condition.
  167. */
  168.     while (1) {
  169.     if (feof(fp))
  170.       break;
  171.     if (!fgets(buf, MAX, fp))
  172.       break;
  173.     line++;
  174.     flag = 0;
  175.     x = strlen(buf) - 1;
  176.     while (buf[x] == '\n' || buf[x] == '\r') /* Trim trailing whitespace */
  177.       buf[x--] = 0;
  178.     while (buf[x] == ' ' || buf[x] == '\t') {
  179.         changed++;
  180.         flag = 1;
  181.         if (warn) break;
  182.         buf[x--] = 0;
  183.     }
  184.     if (lower) {
  185.         int i = 0;
  186.         for (i = 0; i < x; i++) {
  187.         if (isupper(buf[i])) {
  188.             buf[i] = tolower(buf[i]);
  189.             changed++;
  190.         }
  191.         }
  192.     }
  193.     if (warn) {
  194.         if (flag) {
  195.         bads++;
  196.         if (bads == 1) printf("\n");
  197.         fprintf(stderr,"TRAILING: %4ld. [%s]\n",line,buf);
  198.         }
  199.     }
  200.     p = buf;
  201.     if (warn || untab) {        /* Expand tabs / check line length */
  202.         int z;
  203.         p = obuf;
  204.         x = strlen(buf);
  205.         for (i = 0, k = 0; k < x; k++) {
  206.         if (buf[k] != '\t') {
  207.             if (i >= MAX) {
  208.             printf("Overflow: %d\n", i);
  209.             exit(1);
  210.             }
  211.             obuf[i++] = buf[k];
  212.             continue;
  213.         }
  214.         changed++;
  215.         z = 8 - i%8;
  216.         if (z == 0) z = 8;
  217.         for (j = 0; j < z && i < MAX; j++)
  218.           obuf[i++] = ' ';
  219.         }
  220.         obuf[i] = 0;
  221.         if (i > 79) {
  222.         bads++;
  223.         if (bads == 1) printf("\n");
  224.         if (warn) {
  225.             obuf[58] = '.';
  226.             obuf[59] = '.';
  227.             obuf[60] = '.';
  228.             obuf[61] = 0;
  229.         }
  230.         fprintf(stderr,"LONGLINE: %4ld. [%s]\n",line,obuf);
  231.         }
  232.     }
  233.     if (!warn)
  234.       fprintf(op,"%s\n",p);
  235.     }
  236.     if (!warn && op != stdout)
  237.       fclose(op);
  238.     return(bads);
  239. }
  240.