home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / tidy26jul99 / tab2space.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-08  |  7.3 KB  |  382 lines

  1. #include <stdio.h>
  2. #include <stdlib.h> 
  3. #include <string.h>
  4.  
  5. typedef unsigned int uint;
  6. typedef unsigned char byte;
  7. typedef int bool;
  8.  
  9. #define true 1
  10. #define false 0
  11. #define null 0
  12. #define TABSIZE 4
  13.  
  14. #define CRLF  0
  15. #define UNIX  1
  16. #define MAC   2
  17.  
  18. typedef struct
  19. {
  20.     bool pushed;
  21.     int tabs;
  22.     int curcol;
  23.     int lastcol;
  24.     int maxcol;
  25.     int curline;
  26.     int pushed_char;
  27.     uint size;
  28.     uint length;
  29.     char *buf;
  30.     FILE *fp;
  31. } Stream;
  32.  
  33. int tabsize = TABSIZE;
  34. int endline = CRLF;
  35. bool tabs = false;
  36.  
  37. /*
  38.  Memory allocation functions vary from one environment to
  39.  the next, and experience shows that wrapping the local
  40.  mechanisms up provides for greater flexibility and allows
  41.  out of memory conditions to be detected in one place.
  42. */
  43. void *MemAlloc(unsigned int size)
  44. {
  45.     void *p;
  46.  
  47.     p = malloc(size);
  48.  
  49.     if (!p)
  50.     {
  51.         fprintf(stderr, "***** Out of memory! *****\n");
  52.         exit(1);
  53.     }
  54.  
  55.     return p;
  56. }
  57.  
  58. void *MemRealloc(void *old, unsigned int size)
  59. {
  60.     void *p;
  61.  
  62.     p = realloc(old, size);
  63.  
  64.     if (!p)
  65.     {
  66.         fprintf(stderr, "***** Out of memory! *****\n");
  67.         return NULL;
  68.     }
  69.  
  70.     return p;
  71. }
  72.  
  73. void MemFree(void *p)
  74. {
  75.     free(p);
  76.     p = null;
  77. }
  78.  
  79. Stream *NewStream(FILE *fp)
  80. {
  81.     Stream *in;
  82.  
  83.     in = (Stream *)MemAlloc(sizeof(Stream));
  84.  
  85.     memset(in, 0, sizeof(Stream));
  86.     in->fp = fp;
  87.     return in;
  88. }
  89.  
  90. void FreeStream(Stream *in)
  91. {
  92.     if (in->buf)
  93.         MemFree(in->buf);
  94.  
  95.     MemFree(in);
  96. }
  97.  
  98. void AddByte(Stream *in, uint c)
  99. {
  100.     if (in->size + 1 >= in->length)
  101.     {
  102.         while (in->size + 1 >= in->length)
  103.         {
  104.             if (in->length == 0)
  105.                 in->length = 8192;
  106.             else
  107.                 in->length = in->length * 2;
  108.         }
  109.  
  110.         in->buf = (char *)MemRealloc(in->buf, in->length*sizeof(char));
  111.     }
  112.  
  113.     in->buf[in->size++] = (char)c;
  114.     in->buf[in->size] = '\0';  /* debug */
  115. }
  116.  
  117.  
  118.  
  119. /*
  120.   Read a character from a stream, keeping track
  121.   of lines, columns etc. This is used for parsing
  122.   markup and plain text etc. A single level
  123.   pushback is allowed with UngetChar(c, in).
  124.   Returns EndOfStream if there's nothing more to read.
  125. */
  126. int ReadChar(Stream *in)
  127. {
  128.     uint c;
  129.  
  130.     if (in->pushed)
  131.     {
  132.         in->pushed = false;
  133.  
  134.         if (in->pushed_char == '\n')
  135.             in->curline--;
  136.  
  137.         return in->pushed_char;
  138.     }
  139.  
  140.     in->lastcol = in->curcol;
  141.  
  142.     /* expanding tab ? */
  143.     if (in->tabs > 0)
  144.     {
  145.         in->curcol++;
  146.         in->tabs--;
  147.         return ' ';
  148.     }
  149.     
  150.     /* Else go on with normal buffer: */
  151.     for (;;)
  152.     {
  153.         c = getc(in->fp);
  154.  
  155.         /* end of file? */
  156.         if (c < 0)
  157.             break;
  158.  
  159.         /* coerce \r\n  and isolated \r as equivalent to \n : */
  160.         if (c == '\r')
  161.         {
  162.             c = getc(in->fp);
  163.  
  164.             if (c != '\n')
  165.                 ungetc(c, in->fp);
  166.  
  167.             c = '\n';
  168.         }
  169.  
  170.         if (c == '\n')
  171.         {
  172.             if (in->maxcol < in->curcol)
  173.                 in->maxcol = in->curcol;
  174.  
  175.             in->curcol = 1;
  176.             in->curline++;
  177.             break;
  178.         }
  179.  
  180.         if (c == '\t')
  181.         {
  182.             if (tabs)
  183.               in->curcol += tabsize - ((in->curcol - 1) % tabsize);
  184.             else /* expand to spaces */
  185.             {
  186.                 in->tabs = tabsize - ((in->curcol - 1) % tabsize) - 1;
  187.                 in->curcol++;
  188.                 c = ' ';
  189.             }
  190.  
  191.             break;
  192.         }
  193.  
  194.         if (c == '\033')
  195.             break;
  196.  
  197.         /* strip control characters including '\r' */
  198.  
  199.         if (0 < c && c < 32)
  200.             continue;
  201.  
  202.         in->curcol++;
  203.         break;
  204.     }
  205.  
  206.     return c;
  207. }
  208.  
  209. Stream  *ReadFile(FILE *fin)
  210. {
  211.     int c;
  212.     Stream *in  = NewStream(fin);
  213.  
  214.     while ((c = ReadChar(in)) >= 0)
  215.         AddByte(in, (uint)c);
  216.  
  217.     return in;
  218. }
  219.  
  220. void WriteFile(Stream *in, FILE *fout)
  221. {
  222.     int i, c;
  223.     char *p;
  224.  
  225.     i = in->size;
  226.     p = in->buf;
  227.  
  228.     while (i--)
  229.     {
  230.         c = *p++;
  231.  
  232.         if (c == '\n')
  233.         {
  234.             if (endline == CRLF)
  235.             {
  236.                 putc('\r', fout);
  237.                 putc('\n', fout);
  238.             }
  239.             else if (endline == UNIX)
  240.                 putc('\n', fout);
  241.             else /* Macs which use CR */
  242.                 putc('\r', fout);
  243.  
  244.             continue;
  245.         }
  246.  
  247.         putc(c, fout);
  248.     }
  249. }
  250.  
  251. void HelpText(FILE *errout, char *prog)
  252. {
  253.     fprintf(errout, "%s: file1 file2 ...\n", prog);
  254.     fprintf(errout, "Utility to expand tabs and ensure consistent line ends\n");
  255.     fprintf(errout, "options for tab2space vers: 14th December 1998\n");
  256.     fprintf(errout, "  -t8             set tabs to 8 (default is 4)\n");
  257.     fprintf(errout, "  -crlf           set line ends to CRLF (default)\n");
  258.     fprintf(errout, "  -unix or -lf    set line ends to LF (Unix)\n");
  259.     fprintf(errout, "  -cr             set line ends to CR (Macs)\n");
  260.     fprintf(errout, "  -tabs           preserve tabs, e.g. for Makefile\n");
  261.     fprintf(errout, "  -help or -h     display this hekp message\n");
  262.     fprintf(errout, "\nNote this utility doesn't map spaces to tabs!\n");
  263. }
  264.  
  265. int main(int argc, char **argv)
  266. {
  267.     char *file, *prog;
  268.     FILE *fin, *fout;
  269.     Stream *in;
  270.  
  271.     prog = argv[0];
  272.  
  273.     while (argc > 0)
  274.     {
  275.         if (argc > 1 && argv[1][0] == '-')
  276.         {
  277.             if (strcmp(argv[1], "-help") == 0 || argv[1][1] == 'h')
  278.             {
  279.                 HelpText(stdout, prog);
  280.                 return 1;
  281.             }
  282.  
  283.             if (strcmp(argv[1], "-t") == 0)
  284.             {
  285.                 sscanf(argv[1]+2, "%d", &tabsize);
  286.                 --argc;
  287.                 ++argv;
  288.                 continue;
  289.             }
  290.  
  291.             if (strcmp(argv[1], "-unix") == 0 ||
  292.                 strcmp(argv[1], "-lf") == 0)
  293.             {
  294.                 endline = UNIX;
  295.                 --argc;
  296.                 ++argv;
  297.                 continue;
  298.             }
  299.  
  300.             if (strcmp(argv[1], "-crlf") == 0)
  301.             {
  302.                 endline = CRLF;
  303.                 --argc;
  304.                 ++argv;
  305.                 continue;
  306.             }
  307.  
  308.             if (strcmp(argv[1], "-cf") == 0)
  309.             {
  310.                 endline = MAC;
  311.                 --argc;
  312.                 ++argv;
  313.                 continue;
  314.             }
  315.  
  316.             if (strcmp(argv[1], "-tabs") == 0)
  317.             {
  318.                 tabs = true;
  319.                 --argc;
  320.                 ++argv;
  321.                 continue;
  322.             }
  323.  
  324.             --argc;
  325.             ++argv;
  326.             continue;
  327.         }
  328.  
  329.         if (argc > 1)
  330.         {
  331.             file = argv[1];
  332.             fin = fopen(file, "rb");
  333.         }
  334.         else
  335.         {
  336.             fin = stdin;
  337.             file = "stdin";
  338.         }
  339.  
  340.         if (fin != null)
  341.         {
  342.             in = ReadFile(fin);
  343.  
  344.             if (fin != stdin)
  345.                 fclose(fin);
  346.  
  347.             if (argc > 0)
  348.             {
  349.                 file = argv[1];
  350.                 fout = fopen(file, "wb");
  351.             }
  352.             else
  353.             {
  354.                 fout = stdin;
  355.                 file = "stdin";
  356.             }
  357.  
  358.             if (fout)
  359.             {
  360.                 WriteFile(in, fout);
  361.                 fclose(fout);
  362.             }
  363.             else
  364.                 fprintf(stderr, "%s - can't open \"%s\" for writing\n", prog, file);
  365.  
  366.             FreeStream(in);
  367.  
  368.         }
  369.         else
  370.             fprintf(stderr, "%s - can't open \"%s\" for reading\n", prog, file);
  371.  
  372.         --argc;
  373.         ++argv;
  374.  
  375.         if (argc <= 1)
  376.             break;
  377.     }
  378.  
  379.     return 0;
  380. }
  381.  
  382.