"Fossies" - the Fresh Open Source Software Archive

Member "hd2u-1.0.4/dos2unix.c" (1 Sep 2017, 19022 Bytes) of package /linux/privat/hd2u-1.0.4.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dos2unix.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.0.3_vs_1.0.4.

    1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
    2  *
    3  * dos2unix '\n' converter 0.8.0
    4  *   based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
    5  *
    6  * Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Peter Hanecak <hany@hany.sk>
    7  * portions:
    8  * Copyright (C) 2001 Rob Ginda <rginda@netscape.com>
    9  *
   10  * dos2unix filters reading input from stdin and writing output to stdout.
   11  * Without arguments it reverts the format (i.e. if source is in UNIX format,
   12  * output is in DOS format and vice versa).
   13  *
   14  * This program is free software; you can redistribute it and/or
   15  * modify it under the terms of the GNU General Public License
   16  * as published by the Free Software Foundation; either version 2
   17  * of the License, or (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  * See the COPYING file for license information.
   29  */
   30 
   31 #include <stdio.h>
   32 #include <stdlib.h>
   33 #include <string.h>
   34 #include <errno.h>
   35 #include <getopt.h>
   36 
   37 #include "config.h"
   38 
   39 #ifdef HAVE_SYS_STAT_H
   40 #include <sys/stat.h>
   41 #endif
   42 #ifdef HAVE_UNISTD_H
   43 #include <unistd.h>
   44 #endif
   45 #ifdef __MINGW32__
   46 #include <fcntl.h>
   47 #endif
   48 
   49 /* conversions */
   50 #define CT_AUTO     0
   51 #define CT_DOS2UNIX 1
   52 #define CT_MAC2UNIX 2
   53 #define CT_UNIX2DOS 3
   54 #define CT_UNIX2MAC 4
   55 #define CT_DOS2MAC  5
   56 #define CT_MAC2DOS  6
   57 #define CT_SKIP     7
   58 #define CT_COPY     8
   59 
   60 /* input data formats (bit mask) */
   61 #define FT_UNDETERMINED 0
   62 #define FT_DOS    1
   63 #define FT_UNIX   2
   64 #define FT_MIXED  3
   65 #define FT_BINARY 4
   66 #define FT_MAC    8
   67 
   68 /* input data flags (bit mask) */
   69 #define FF_STRAYR 1
   70 
   71 /* read/write buffers size */
   72 #define BUFFER_SIZE 1024
   73 
   74 static struct option long_options[] = {
   75     { "auto", no_argument, NULL, 'A' },
   76     { "d2u", no_argument, NULL, 'U' },
   77     { "m2u", no_argument, NULL, 'T' },
   78     { "u2d", no_argument, NULL, 'D' },
   79     { "u2m", no_argument, NULL, 'M' },
   80     { "d2m", no_argument, NULL, 'O' },
   81     { "m2d", no_argument, NULL, 'C' },
   82     { "force", no_argument, NULL, 'f' },
   83     { "help", no_argument, NULL, 'h' },
   84     { "skipbin", no_argument, NULL, 'b' },
   85     { "test", no_argument, NULL, 't' },
   86     { "verbose", no_argument, NULL, 'v' },
   87     { "version", no_argument, NULL, 'V' },
   88     { 0, 0, 0, 0 }
   89 };
   90 
   91 char testmode = 0, verbose = 0, skipbin = 0, force = 0;
   92 char *argv0;
   93 
   94 /* if fn is NULL then input is stdin and output is stdout
   95  *
   96  * buffer1 vs. buffer2 size: "worst case scenario" is UNIX->DOS conversion of input consisting of only '\n' characters - for such
   97  * case buffer2 have to be two times bigger than buffer1
   98  */ 
   99 int convert(char *fn, int convType) {
  100     char c;
  101     char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE * 2], *outBuffer = (char *)&buffer2;
  102     int count1 = -1, count2 = -1, n1;
  103     int crFlag = 0, validDosEolFound = 0;
  104     int fileType = FT_UNDETERMINED, fileFlags = 0;
  105     char *tempFn = NULL;
  106     char *tempFnTemplate = "/dos2unix-XXXXXX";
  107     char *tmpdir = NULL;
  108     int temp_fd = -1;
  109     mode_t old_mode;
  110     FILE *in = NULL, *out = NULL;
  111     struct stat buf;
  112 
  113     /* ugly little macro to clean up and return */
  114 #define BAIL(_rval, _msg) {                                                    \
  115         if (in && in != stdin)                                                 \
  116             if (fclose(in) < 0) {                                              \
  117                 perror(argv0); return -2;                                      \
  118             }                                                                  \
  119         if (out && out != stdout)                                              \
  120             if (fclose(out) < 0) {                                             \
  121                 perror(argv0); return -2;                                      \
  122             }                                                                  \
  123         if (tempFn != NULL && temp_fd != -1 && remove(tempFn) < 0) {           \
  124             perror(argv0); return -2;                                          \
  125         }                                                                      \
  126         if (tempFn != NULL)                                                    \
  127             free(tempFn);                                                      \
  128         if (_rval != 0)                                                        \
  129             perror(_msg);                                                      \
  130         return _rval;                                                          \
  131     }
  132 
  133     /* open the input file, if it isn't stdin */
  134     if (fn != NULL) {
  135         if ((in = fopen(fn, "rb")) == NULL)
  136             BAIL (-1, fn);
  137         if (stat(fn, &buf) != 0)
  138             BAIL (-1, fn);
  139         if (S_ISDIR(buf.st_mode)) {
  140             fprintf(stderr, "%s is a directory!\n", fn);
  141             BAIL (0, NULL);
  142         }
  143     }
  144     else
  145         in = stdin;
  146 
  147     /* construct temp file name */
  148 #ifndef _WIN32
  149     if ((getuid() == geteuid()) && (getgid() == getegid()))
  150 #endif
  151         if (!(tmpdir=getenv("TMPDIR")))
  152             tmpdir=getenv("TMP");
  153     if (!tmpdir)
  154         tmpdir = "/tmp";
  155     tempFn = malloc(strlen(tmpdir) + strlen(tempFnTemplate) + 1);
  156     if (!tempFn)
  157         BAIL (-3, argv0);
  158     strcpy(tempFn, tmpdir);
  159     strcat(tempFn, tempFnTemplate);
  160 
  161     /* open a temp file to store input */
  162     old_mode = umask(077);
  163 #ifndef _WIN32
  164     temp_fd = mkstemp(tempFn);
  165 #else
  166     temp_fd = _open(_mktemp(tempFn), _O_WRONLY | _O_BINARY | _O_CREAT, _S_IRWXU | S_IREAD | S_IWRITE);
  167 #endif
  168     (void) umask(old_mode);
  169     if (temp_fd == -1)
  170         BAIL (-2, argv0);
  171     if ((out = fdopen(temp_fd, "w")) == NULL)
  172         BAIL (-2, argv0);
  173 
  174     /* initial scan for filetype and fileflags
  175      * also store input to temp file for later conversion */
  176     while (!feof(in)) {
  177         count1 = fread(&buffer1, sizeof(char), BUFFER_SIZE, in);
  178         if ((count1 != BUFFER_SIZE) && ferror(in))
  179             BAIL (-4, argv0);
  180 
  181         for (n1 = 0; n1 < count1; n1++) {
  182             c = buffer1[n1];
  183 
  184             if (crFlag) {
  185                 crFlag = 0;
  186                 if (c == '\n') {
  187                     validDosEolFound = 1;
  188                     continue;
  189                 }
  190                 fileFlags |= FF_STRAYR;
  191             }
  192 
  193             if (c == '\r') {
  194                 crFlag = 1;
  195                 fileType |= FT_DOS;
  196             } else if (c == '\n') {
  197                 fileType |= FT_UNIX;
  198             } else if ((c < 32 || c > 126) && c != '\t') {
  199                 fileType |= FT_BINARY;
  200             }
  201         }
  202 
  203         if ((fwrite(&buffer1, sizeof(char), count1, out) != count1) && ferror(out))
  204             BAIL (-5, argv0);
  205     }
  206     if (crFlag)
  207         fileFlags |= FF_STRAYR;
  208     /* recognize Mac files: after previous scan they looks like DOS files with stray '\r'-s and with no regular DOS "eol" */
  209     if (((fileType & FT_DOS) != 0) && (!validDosEolFound)) {
  210         fileType |= FT_MAC;
  211         fileFlags &= !FF_STRAYR;
  212     }
  213 
  214     /* if we're not working with stdin, close source (in) */
  215     if (fn != NULL) {
  216         if (fclose(in) != 0, in = NULL)
  217             BAIL (-2, argv0);
  218     }
  219 
  220     /* close temp file (out) */
  221     if (fclose(out) != 0, out = NULL)
  222         BAIL (-2, argv0);
  223 
  224 
  225     /* figure out conversion type */
  226     if ((fileType & FT_BINARY) != 0 && skipbin) {
  227             convType = CT_SKIP;
  228             fileType = FT_BINARY;   /* ensure we do not treat it as another format */
  229     }
  230     if (convType == CT_AUTO) {
  231         if ((fileType & FT_UNIX) != 0)
  232             convType = CT_UNIX2DOS;
  233         if ((fileType & FT_DOS) != 0) {
  234             convType = CT_DOS2UNIX;
  235             fileType = fileType | !FT_UNIX; /* to ensure FT_MIXED is handled as FT_DOS */
  236         }
  237         if ((fileType & FT_MAC) != 0)
  238             convType = CT_MAC2UNIX;
  239     }
  240 
  241     /* don't waste time on a null conversion */
  242     if ((fileType == FT_DOS && convType == CT_UNIX2DOS) ||
  243         (fileType == FT_DOS && convType == CT_MAC2DOS) ||
  244         (fileType == FT_UNIX && convType == CT_DOS2UNIX) ||
  245         (fileType == FT_UNIX && convType == CT_MAC2UNIX) ||
  246         (fileType == FT_MAC && convType == CT_DOS2MAC) ||
  247         (fileType == FT_MAC && convType == CT_UNIX2MAC) ||
  248         (fileType == FT_UNDETERMINED))
  249     {
  250         convType = CT_SKIP;
  251     }
  252 
  253     /* if the source is stdin, we have to reproduce input on stdout */
  254     if (fn == NULL && convType == CT_SKIP) {
  255         convType = CT_COPY;
  256         outBuffer = (char *)&buffer1;
  257     }
  258 
  259     /* verbose output: input data type */
  260     if (verbose) {
  261         fprintf (stderr, "File format of '%s': ", (fn != NULL) ? fn : "stdin");
  262         if ((fileType & FT_BINARY) != 0)
  263             fprintf (stderr, "looks binary, ");
  264         if ((fileFlags & FF_STRAYR) != 0)
  265             fprintf (stderr, "contains stray '\\r', ");
  266         if ((fileType & FT_MIXED) == FT_MIXED)
  267             fprintf (stderr, "mixed line endings found.");
  268         else {
  269         if ((fileType & FT_MAC) != 0)
  270                 fprintf (stderr, "Mac line endings found.");
  271             else if ((fileType & FT_DOS) != 0)
  272                 fprintf (stderr, "DOS line endings found.");
  273         else if ((fileType & FT_UNIX) != 0)
  274                 fprintf (stderr, "Unix line endings found.");
  275             else
  276                 fprintf (stderr, "undetermined.");
  277         }
  278         fprintf (stderr, "\n");
  279     }
  280 
  281     /* another ugly little macro to handle conversion type overriding for specific case */
  282 #define CTOVERRIDE(_ft, _oct, _rct, _msg) {                                                             \
  283         if ((fileType == _ft && convType == _oct)) {                                                    \
  284             convType = _rct;                                                                            \
  285             fprintf (stderr, "warning: Overriding conversion type based on detected source format.\n"); \
  286             if (verbose)                                                                                \
  287                 fprintf (stderr, _msg);                                                                 \
  288         }                                                                                               \
  289     }
  290 
  291     /* handle some source type vs. conversion type typos (or whatever) in a way it can make sense */
  292     if (!force) {
  293         CTOVERRIDE(FT_MAC, CT_DOS2UNIX, CT_MAC2UNIX, "  (MAC file + DOS -> UNIX conversion => MAC -> UNIX conversion)\n");
  294         CTOVERRIDE(FT_DOS, CT_MAC2UNIX, CT_DOS2UNIX, "  (DOS file + MAC -> UNIX conversion => DOS -> UNIX conversion)\n");
  295         CTOVERRIDE(FT_MAC, CT_UNIX2DOS, CT_MAC2DOS, "  (MAC file + UNIX -> DOS conversion => MAC -> DOS conversion)\n");
  296         CTOVERRIDE(FT_DOS, CT_UNIX2MAC, CT_DOS2MAC, "  (DOS file + UNIX -> MAC conversion => DOS -> MAC conversion)\n");
  297         CTOVERRIDE(FT_UNIX, CT_DOS2MAC, CT_UNIX2MAC, "  (UNIX file + DOS -> MAC conversion => UNIX -> MAC conversion)\n");
  298         CTOVERRIDE(FT_UNIX, CT_MAC2DOS, CT_UNIX2DOS, "  (UNIX file + MAC -> DOS conversion => UNIX -> DOS conversion)\n");
  299     }
  300 
  301     /* verbose output: conversion type */
  302     if (verbose & !testmode) {
  303         fprintf (stderr, "Conversion type '%s': ", (fn != NULL) ? fn : "stdin");
  304         switch (convType) {
  305             case CT_DOS2UNIX:
  306                 fprintf (stderr, "DOS -> Unix");
  307                 break;
  308             case CT_MAC2UNIX:
  309                 fprintf (stderr, "Mac -> Unix");
  310                 break;
  311             case CT_UNIX2DOS:
  312                 fprintf (stderr, "Unix -> DOS");
  313                 break;
  314             case CT_UNIX2MAC:
  315                 fprintf (stderr, "Unix -> Mac");
  316                 break;
  317             case CT_DOS2MAC:
  318                 fprintf (stderr, "DOS -> Mac");
  319                 break;
  320             case CT_MAC2DOS:
  321                 fprintf (stderr, "Mac -> DOS");
  322                 break;
  323             case CT_COPY:
  324                 fprintf (stderr, "none (copying source to target)");
  325                 break;
  326             case CT_SKIP:
  327                 fprintf (stderr, "none (skipping file)");
  328         }
  329         if (force)
  330             fprintf (stderr, " (forced)");
  331         fprintf (stderr, "\n");
  332     }
  333 
  334 
  335     /* whether we are continuing conversion */
  336     if ((convType == CT_SKIP) || testmode)
  337         BAIL (0, NULL);
  338 
  339 
  340     /* open input data in temp file */
  341     if ((in = fopen(tempFn, "rb")) == NULL)
  342         BAIL (-2, argv0);
  343 
  344     /* open the output file, if it isn't stdout */
  345     if (fn != NULL) {
  346         if ((out = fopen(fn, "wb")) == NULL)
  347             BAIL (-2, fn);
  348     }
  349     else
  350         out = stdout;
  351 
  352     /* do the actual conversion */
  353     while (!feof(in)) {
  354         count1 = fread(&buffer1, sizeof(char), BUFFER_SIZE, in);
  355         if ((count1 != BUFFER_SIZE) && ferror(in))
  356             BAIL (-6, argv0);
  357 
  358         switch (convType) {
  359             case CT_DOS2UNIX:
  360                 count2 = 0;
  361                 for (n1 = 0; n1 < count1; n1++) {
  362                     c = buffer1[n1];
  363                     if (c == '\r')
  364                         continue;
  365                     buffer2[count2++] = c;
  366                 }
  367                 break;
  368             case CT_MAC2UNIX:
  369                 for (n1 = 0; n1 < count1; n1++) {
  370                     c = buffer1[n1];
  371                     if (c == '\r')
  372                         buffer2[n1] = '\n';
  373                     else
  374                         buffer2[n1] = c;
  375                 }
  376                 count2 = count1;
  377                 break;
  378             case CT_UNIX2DOS:
  379                 count2 = 0;
  380                 for (n1 = 0; n1 < count1; n1++) {
  381                     c = buffer1[n1];
  382                     if (c == '\n')
  383                         buffer2[count2++] = '\r';
  384                     buffer2[count2++] = c;
  385                 }
  386                 break;
  387             case CT_UNIX2MAC:
  388                 for (n1 = 0; n1 < count1; n1++) {
  389                     c = buffer1[n1];
  390                     if (c == '\n')
  391                         buffer2[n1] = '\r';
  392                     else
  393                         buffer2[n1] = c;
  394                 }
  395                 count2 = count1;
  396                 break;
  397             case CT_DOS2MAC:
  398                 count2 = 0;
  399                 for (n1 = 0; n1 < count1; n1++) {
  400                     c = buffer1[n1];
  401                     if (c == '\n')
  402                         continue;
  403                     buffer2[count2++] = c;
  404                 }
  405                 break;
  406             case CT_MAC2DOS:
  407                 count2 = 0;
  408                 for (n1 = 0; n1 < count1; n1++) {
  409                     c = buffer1[n1];
  410                     buffer2[count2++] = c;
  411                     if (c == '\r')
  412                         buffer2[count2++] = '\n';
  413                 }
  414                 break;
  415             case CT_COPY:
  416                 count2 = count1;
  417         }
  418 
  419         if ((fwrite(outBuffer, sizeof(char), count2, out) != count2) && ferror(out))
  420             BAIL (-7, argv0);
  421     }
  422 
  423     BAIL (0, NULL);
  424 
  425 #undef BAIL
  426 
  427 }
  428 
  429 void help() {
  430     fprintf(stderr,
  431             "usage:\n"
  432             "\t%s [--verbose|-v] [--test|-t] [--force|-f] \\\n"
  433             "\t\t[--<x>2<y>|--auto|-<Z>] \\\n"
  434             "\t\t[<file name> [...]]\n"
  435             "where:\n", argv0);
  436     fprintf(stderr,
  437             "\t--auto, -A\toutput will be set based upon auto-detection\n"
  438             "\t\t\tof source format\n"
  439             "\t--d2u, -U\tperform DOS -> UNIX conversion\n"
  440             "\t--m2u, -T\tperform MAC -> UNIX conversion\n"
  441             "\t--u2d, -D\tperform UNIX -> DOS conversion\n"
  442             "\t--u2m, -M\tperform UNIX -> MAC conversion\n"
  443             "\t--d2m, -O\tperform DOS -> MAC conversion\n"
  444             "\t--m2d, -C\tperform MAC -> DOS conversion\n"
  445             "\n");
  446     fprintf(stderr,
  447             "\t--force\t\tsuppress internal conversion type corrections\n"
  448             "\t\t\tbased on autodetected input format\n"
  449             "\t--skipbin, -b\tskip binary files\n"
  450             "\t--test, -t\tdon't write any conversion results; useful with\n"
  451             "\t\t\t--verbose to just report on source type\n"
  452             "\t--verbose, -v\tprint extra information on stderr\n"
  453             "\t--version, -V\tprint version information on stderr\n"
  454             "\n");
  455     fprintf(stderr,
  456             "- when no options are given then input format will be automatically detected\n"
  457             "  and converted as follows:\n"
  458             "\tDOS -> UNIX\n"
  459             "\tMAC -> UNIX\n"
  460             "\tUNIX -> DOS\n"
  461             "- same as above applies if --auto option is used\n"
  462             "- when no file is given, then stdin is used as input and stdout as output\n"
  463             "- binary files will be skipped automatically if option --skipbin\n"
  464             "  (or -b) is used\n"
  465             "- stray '\\r' characters (without a following '\\n') in files in DOS format are\n"
  466             "  reported but only conversion 'DOS -> Unix' affects them (they are skipped)\n");
  467     fprintf(stderr,
  468             "- stray '\\n' characters in files in MAC format are not detected for now\n");
  469 }
  470 
  471 void displayVersion() {
  472     fprintf(stderr, PACKAGE_STRING "\n");
  473 }
  474 
  475 int main(int argc, char *argv[]) {
  476     int convType = CT_AUTO;
  477     int o;
  478 
  479     argv0 = argv[0];
  480 
  481     /* process parameters */
  482     while ((o = getopt_long(argc, argv, "ACDMOTUVbfhvt", long_options, NULL)) != EOF) {
  483         switch (o) {
  484             case 'A':
  485                 convType = CT_AUTO;
  486                 break;
  487             case 'C':
  488                 convType = CT_MAC2DOS;
  489                 break;
  490             case 'D':
  491                 convType = CT_UNIX2DOS;
  492                 break;
  493             case 'M':
  494                 convType = CT_UNIX2MAC;
  495                 break;
  496             case 'O':
  497                 convType = CT_DOS2MAC;
  498                 break;
  499             case 'T':
  500                 convType = CT_MAC2UNIX;
  501                 break;
  502             case 'U':
  503                 convType = CT_DOS2UNIX;
  504                 break;
  505             case 'b':
  506                 skipbin = 1;
  507                 break;
  508             case 'f':
  509                 force = 1;
  510                 break;
  511             case 'h':
  512                 help();
  513                 return 0;
  514             case 't':
  515                 testmode = 1;
  516                 break;
  517             case 'v':
  518                 verbose = 1;
  519                 displayVersion();
  520                 break;
  521             case 'V':
  522                 displayVersion();
  523                 return 0;
  524             case '?':
  525                 help();
  526                 return -1;
  527         }
  528     }
  529 
  530     if (optind < argc) {
  531         while(optind < argc)
  532             if ((o = convert(argv[optind++], convType)) != 0)
  533                 break;
  534     }
  535     else
  536         o = convert(NULL, convType);
  537 
  538     return o;
  539 }