=================================================================== RCS file: /cvs/djgpp/djgpp/src/utils/dtou.c,v retrieving revision 1.5 retrieving revision 1.6 diff -p -u -r1.5 -r1.6 --- djgpp/src/utils/dtou.c 2000/11/08 17:59:28 1.5 +++ /cvs/djgpp/djgpp/src/utils/dtou.c 2000/11/25 11:06:01 1.6 @@ -14,85 +14,306 @@ #define O_BINARY 0 #endif +#define IS_DIR_SEPARATOR(path) ((path) == '/' || (path) == '\\' || (path) == ':') +#define IS_LAST_CR_IN_BUF (i == l - 1) +#define IS_LAST_CR_IN_FILE (position + i + 1 == st.st_size) +#define SET_FLAG(flag) \ +do { \ + if ((flag) == 0) (flag) = 1; \ +} while (0) +#define BUF_SIZE 16384 + +/* Control characters. */ +#define LF 0x0A +#define CR 0x0D +#define CntlZ 0x1A + +/* Exit codes. */ +#define NO_ERROR 0x00 +#define IO_ERROR 0x01 /* Some I/O error occurred. */ + + static int -dtou(char *fname) +dtou(char *fname, int make_backup, int repair_mode, int strip_mode, int verbose, int vverbose, int preserve_timestamp) { - int i, k, k2, sf, df, l, l2=0, err=0, isCR=0; - char buf[16384]; - char tfname[FILENAME_MAX], *bn, *w; + int i, k, sf, df, l, l2 = 0, is_CR = 0, is_nCR = 0, is_CR_sequence = 0; + int CntlZ_flag = 0, CR_flag = 0, nCR_flag = 0, LF_flag = 0, exit_status = NO_ERROR; + int buf_counter, nbufs, LF_counter, must_rewind, position, offset, whence; + char buf[BUF_SIZE]; + char bfname[FILENAME_MAX], tfname[FILENAME_MAX], *bn, *w; struct stat st; struct utimbuf tim1; - sf = open(fname, O_RDONLY|O_BINARY); + + sf = open (fname, O_RDONLY|O_BINARY); if (sf < 1) { - perror(fname); - return 1; + perror (fname); + return IO_ERROR; } fstat (sf,&st); tim1.actime = st.st_atime; tim1.modtime = st.st_mtime; + nbufs = st.st_size / BUF_SIZE; strcpy (tfname, fname); - for (bn=w=tfname; *w; w++) - if (*w=='/' || *w=='\\' || *w==':') + for (bn = w = tfname; *w; w++) + if (IS_DIR_SEPARATOR (*w)) bn = w+1; if (bn) *bn=0; - strcat (tfname,"utod.tm$"); + strcat (tfname,"dtou.tm$"); + if (make_backup) + { + strcpy (bfname, fname); + if (pathconf ((fname), _PC_NAME_MAX) <= 12) + for (i = strlen (bfname); i > -1; i--) + if (bfname[i] == '.') + { + bfname[i] = '\0'; + break; + } + strcat (bfname,".d2u"); + } - df = open(tfname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644); + df = open (tfname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644); if (df < 1) { - perror(tfname); - close(sf); - return 1; + perror (tfname); + close (sf); + return IO_ERROR; } - k2=0; - while ((l=read(sf, buf, 16384)) > 0) + buf_counter = LF_counter = must_rewind = position = 0; + if (strip_mode) + { + offset = 0; + whence = SEEK_SET; + } + else + { + offset = -1; + whence = SEEK_CUR; + } + while ((l = read (sf, buf, BUF_SIZE)) > 0) { - int CtrlZ=0; - for (i=k=0; i0 ? write(df, buf, k) : 0); - if (l2<0 || CtrlZ) break; - if (l2!=k) { err=1; break; } + + if (!repair_mode) + if (buf[i] == CntlZ) { SET_FLAG (CntlZ_flag); break; } + + buf[k++] = buf[i]; + } + + is_CR = 0; + buf_counter++; + position += l; + if (must_rewind) + { + /* Last character/s in buf is/are CR/s. + Push it/them back and reread it/them next time. */ + position = lseek (sf, offset, whence); + must_rewind = 0; + } + + l2 = (k > 0 ? write (df, buf, k) : 0); + if (l2 < 0 || CntlZ_flag) break; + if (l2 != k) { exit_status = IO_ERROR; break; } } - if (l<0) perror (fname); - if (l2<0) perror (tfname); - if (err) fprintf (stderr,"Cannot process file %s\n",fname); + if (l < 0) perror (fname); + if (l2 < 0) perror (tfname); + if (exit_status != NO_ERROR) + fprintf (stderr,"Cannot process file %s\n",fname); - close(sf); - close(df); + close (sf); + close (df); - if (l>=0 && l2>=0 && err==0) + if (l >= 0 && l2 >= 0 && exit_status == NO_ERROR) { - remove(fname); - rename(tfname, fname); - utime(fname, &tim1); - chown(fname, st.st_uid, st.st_gid); - chmod(fname, st.st_mode); + int file_has_changed = CR_flag || nCR_flag || CntlZ_flag || LF_flag; + + if (verbose) + printf ("File: %s successfully processed.\n",fname); + if (vverbose) + printf ("File: %s\n",fname); + + if (CR_flag && vverbose) + printf ("At least one CR/LF to LF transformation occurred.\n"); + if (nCR_flag && vverbose) + printf ("Warning: At least one CR sequence stripped from a LF.\n"); + if (CntlZ_flag && vverbose) + printf ("Warning: At least one Cntl-Z has been found. File truncated at line %i.\n", LF_counter); + if (LF_flag && vverbose) + printf ("Warning: At least one LF without a preceeding CR has been found.\n"); + + if (vverbose && !file_has_changed) + printf ("File unchanged.\n"); + + if (make_backup && file_has_changed) + rename (fname, bfname); + else + remove (fname); + rename (tfname, fname); + chown (fname, st.st_uid, st.st_gid); + chmod (fname, st.st_mode); + if (preserve_timestamp || !file_has_changed) + utime (fname, &tim1); } - else + else { - remove(tfname); + remove (tfname); + if (verbose || vverbose) + printf ("File: %s. An I/O error occurred\n",fname); } - return 0; + + return exit_status; +} + +void +usage(char *progname) +{ + printf ("Usage: %s [-b] [-h] [-r] [-s] [-t] [-v] [-vv] files...\n\n", progname); + printf ("Options are:\n"); + printf (" -b: A backup of the original file is made using `.d2u' as backup\n"); + printf (" extension, if the file has been modified.\n"); + printf (" -h: Display this help and exit.\n"); + printf (" -r: Transform MSDOS-style EOF (CRLF) into UNIX-style EOL (LF).\n"); + printf (" Cntl-Z are ignored and will not truncate the file and\n"); + printf (" CR sequences in front of LF will be left unchanged.\n"); + printf (" -s: Transform MSDOS-style EOF (CRLF) into UNIX-style EOL (LF)\n"); + printf (" and strip a CR sequence of arbitrary length from the file,\n"); + printf (" if and only if the sequence is followed by LF. CR sequences\n"); + printf (" that are not followed by LF are always left unchanged.\n"); + printf (" -t: The timestamp of the modified file will not be preserved.\n"); + printf (" -v: Show if file processing has been successful or not.\n"); + printf (" -vv: Show the kind of modifications that have been done to the file.\n"); + printf ("The program is backward compatible with previous program versions if no options\n"); + printf ("are given at all. In this case, an occurrence of Cntl-Z will truncate the file,\n"); + printf ("MSDOS-style EOL (CRLF) are transformed into UNIX-style EOL (LF) and CR sequence\n"); + printf ("stripping will not happen at all. Also the timestamp will not be alterated and\n"); + printf ("no backup of the original file will be done."); } int main(int argc, char **argv) { - int rv = 0; - for (argc--, argv++; argc; argc--, argv++) - rv += dtou(*argv); - return rv; -} + int exit_status = NO_ERROR, i, make_backup, repair_mode; + int strip_mode, verbose, vverbose, preserve_timestamp; + char* progname = strlwr(strdup(argv[0])); + if (argc < 2) + { + usage (progname); + exit(NO_ERROR); + } + + /* Default for backward compatibility. */ + make_backup = repair_mode = strip_mode = verbose = vverbose = 0; + preserve_timestamp = 1; + + i = 1; + while ((argc > i) && (argv[i][0] == '-') && argv[i][1]) + { + switch (argv[i][1]) + { + case 'b': + make_backup = 1; + break; + case 'h': + usage (progname); + exit(NO_ERROR); + break; + case 'r': + repair_mode = 1; + strip_mode = 0; + break; + case 's': + strip_mode = 1; + repair_mode = 0; + break; + case 't': + preserve_timestamp = 0; + break; + case 'v': + if (argv[i][2] == 'v') + { + vverbose = 1; + verbose = 0; + } + else + { + verbose = 1; + vverbose = 0; + } + break; + default: + fprintf (stderr, "%s: invalid option -- %s\n", progname, &argv[i][1]); + fprintf (stderr, "Try `%s -h' for more information.\n", progname); + exit (IO_ERROR); + break; + } + i++; + } + + for (; i < argc; i++) + exit_status += dtou (argv[i], make_backup, repair_mode, strip_mode, verbose, vverbose, preserve_timestamp); + return exit_status; +}