#ifdef ournix #include "ournix.h" #endif char sccsID[] = "@(#) addcr.c V1.8 Copyright Julian H. Stacey 28th June 1989\n" ; /* see manual */ #include #if ( hpux || MSDOS || SVR2 || __OpenBSD__ ) #include #endif #if ( defined i386 || defined __FreeBSD__ /* allow for FreeBSD amd64 */ ) /* Find std includes with: cp /dev/null ~/tmp/tmp.c ; cc -E -dM ~/tmp/tmp.c */ #include #endif #include #include #ifdef ns32000 /* { */ #define BSD #endif /* } */ #ifdef BSD /* { */ #include #endif /* } */ #ifdef MSDOS /* { */ #include #endif /* } */ typedef char FLAG ; #define BUFSIZE 65536 /* BUFSIZE was 4096 until 15 Dec 2000, when increased to 65536, when I discovered that even 32768 was not enough for processing long lines produced by script command wrapping logs of FreeBSD cd /usr/src/release ; make release JJLATER perhaps I should make this a -l atol parameter */ char **ARGV ; int exit_count = 0 ; int src_fd ; int new_fd ; char buf_in[BUFSIZE + 1] ; char buf_out[BUFSIZE + 2] ; extern int errno ; FLAG preserve_date ; FLAG reverse = 0 ; FLAG verbose ; #ifdef scs /* { */ extern char *mktemp() ; #define TMP_NAME "adXXXXXX" #else /* }{ */ #include #ifdef MSDOS /* { */ #define TMP_NAME "adXXXXXX" #else /* }{ */ #define TMP_NAME "addcr.XXXXXX" #endif /* } */ #endif /* } */ #include /* for MAXPATHLEN */ char tmp_name[MAXPATHLEN] ; /* temporary file name */ main(argc, argv) int argc ; char **argv ; { ARGV = argv ; #ifdef VSL /* { */ #include "../../include/vsl.h" #endif /* } */ while (--argc && **++argv == '-') switch (*++*argv) { case 'r': /* reverse the process, rid trailing \r */ reverse = 1 ; break ; case 'd': /* preserve date */ preserve_date = 1 ; break ; case 'v': /* verbose */ verbose = 1 ; break ; case 'V': /* version number identification */ printf("%s",sccsID); break ; default: fprintf(stderr, "Aborting, Syntax error, Correct Usage:\n\t%s%s\n" ,*ARGV, " [-d] [-r] [-v] [-V] [files]") ; exit(1) ; break ; } if (argc == 0) exit(do_file((char *)0)) ; else { argc++ ; argv-- ; while (--argc > 0) if (do_file(*++argv)) exit_count++ ; } exit(exit_count) ; } /* Strategy: Reads input in large blocks, Writes output one line at a time. */ do_file(src_name) char *src_name ; { struct stat stat_buf ; int len1, len2 ; #ifdef MSDOS /* { */ struct utimbuf set_time ; #endif /* } */ #ifdef BSD /* { */ time_t timep[2]; #endif /* } */ char *base_p, *top_p ; char *tmp_p ; #ifdef MSDOS /* { */ char mv_cmd[500] ; #endif /* } */ int byte_count ; unsigned remnant = 0 ; /* number of bytes left over from last block read */ FLAG esoteric = 0 ; if (src_name == (char *)0) { /* no args ; pipe operation, standard input to output */ src_fd = 0 ; /* stdin */ new_fd = 1 ; /* stdout */ } else { if (verbose) { printf("%s",src_name); (void)fflush(stdout) ; } #ifdef unix /* { */ if ( lstat(src_name, &stat_buf) != 0) { fprintf(stderr,"%s: stat failed on %s.\n", *ARGV,src_name); return(1) ; } if ( #ifdef MSDOS /* { */ 0 #endif /* } */ #ifdef unix /* { */ (stat_buf.st_nlink != 1 ) || ( (stat_buf.st_mode & S_IFMT ) != S_IFREG ) #endif /* } */ ) esoteric = 1 ; #endif /* } */ if ( stat(src_name, &stat_buf) != 0) { fprintf(stderr,"%s: stat failed on %s.\n", *ARGV,src_name); return(1) ; } if (stat_buf.st_size == (off_t)0 ) return(0) ; /* now create a name in the same directory as the source, so we can guarantee no linking across devices will be attempted */ (void)strcpy(tmp_name,src_name) ; /* to end of string JJ could use strrchr instead */ for ( tmp_p = tmp_name ; (*tmp_p++ != '\0') ; ) ; for ( tmp_p -= 1 ; (*--tmp_p != '/') #ifdef MSDOS && ( *tmp_p != '\\') #endif && ( tmp_p >= tmp_name) ; ) ; #ifdef DEBUG printf("BLA X%sX X%sX\n",tmp_p + 1,TMP_NAME); #endif (void)strcpy(tmp_p + 1,TMP_NAME); if (NULL == mktemp(tmp_name)) { perror(*ARGV); fprintf(stderr, "%s: Program error, mktemp %s failed, exiting.\n", *ARGV,tmp_name); exit(++exit_count); } (void)strcat(tmp_name,".tmp"); if ((src_fd = open(src_name,O_RDWR #ifdef MSDOS /* { */ | O_BINARY #endif /* } */ )) == -1) { fprintf(stderr,"%s: Can't open %s.\n",*ARGV,src_name) ; return(1) ; } /* create output temporary file */ /* JJLATER malloc would be faster, & avoid using disc io if file is small but malloc wont allow much for msdos */ if ((new_fd = open(tmp_name,O_RDWR | O_CREAT /* | O_TRUNC */ #ifdef MSDOS /* { */ | O_BINARY #endif /* } */ , S_IREAD | S_IWRITE )) == -1) /* S_IREAD is read permission for owner */ { perror(*ARGV); fprintf(stderr, "%s: Cant open temporary file %s, exiting.\n", *ARGV,tmp_name) ; (void) close(src_fd) ; return(1) ; /* dont exit, as we just be out of unix inodes (or msdos directory entries in root directory) on this device, next argument may be a different file system, so keep trying. */ } } while ( (byte_count = read(src_fd,buf_in + remnant, (int)(BUFSIZE - remnant) ) ) > 0) /* read blocks*/ { byte_count += remnant ; buf_in[byte_count] = '\0' ; for (base_p = top_p = buf_in ; (top_p < buf_in + byte_count) ; ) { if (*top_p == '\n' ) { if (add_line(base_p,top_p -1)) return(1) ; base_p = ++top_p ; } else top_p++ ; } if (base_p == buf_in) { buf_in[byte_count] = '\0' ; fprintf(stderr,"%s: File %s, Line too long:\n %s\n", *ARGV, src_name, buf_in ) ; (void) close(src_fd) ; (void) close(new_fd) ; (void) unlink(tmp_name) ; return(1); /* dont exit, because next file might be more reasonable. */ } /* now collect remnant of input buffer excluding last \n, including last character in buffer, & move it down */ if ( base_p < ( buf_in + byte_count)) { (void)strcpy(buf_in,base_p); remnant = strlen(buf_in) ; } else remnant = 0 ; } if (src_name != (char *)0) { /* Now return data to source */ /* differentiate between regular file as opposed to the more esoteric cases of hard or symbolic link, character or block special, socket, or directory. */ if (!esoteric) { /* regular file, move file name */ (void) close(src_fd) ; (void) close(new_fd) ; #ifndef BSD /* not necessary for BSD */ (void) unlink(src_name) ; #endif #ifndef SVR2 /* { */ if ( rename(tmp_name,src_name) ) /* Microsoft C Compiler Version 3 manual says arguments should be the opposite way round to BSD, but V4 compiler produces code that works OK with BSD parameter order - thus this seems to be a bug/incompatability detected with V3 manual, (& possibly compiler, though untested) */ { perror(*ARGV); fprintf(stderr,"%s: moving %s to %s failed.\n", *ARGV, tmp_name, src_name ) ; exit(++exit_count); /* rename failure is serious, possible program error or other unexpected contingency, so dont just return, but exit */ } #else /* } { */ sprintf(mv_cmd,"mv %s %s",tmp_name, src_name); system(mv_cmd); #endif /* } */ } #ifndef MSDOS /* { */ else { /* esoteric file, copy data back */ #ifdef i386 /* { */ #define L_SET SEEK_SET /* the pointer is set to offset bytes. */ #define L_INCR SEEK_CUR /* the pointer is set to its current location plus offset. */ #define L_XTND SEEK_END /* the pointer is set to the size of the file plus offset. */ #endif /* } */ #ifdef hpux #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END #endif if ((lseek(src_fd, (off_t)0, L_SET) != 0) || (lseek(new_fd, (off_t)0, L_SET) != 0)) { perror(*ARGV) ; fprintf(stderr,"%s: Fatal error, aborting.\n", *ARGV); exit(1); } while ( (byte_count = read(new_fd,buf_in,BUFSIZE) ) > 0) { if (write(src_fd,buf_in,byte_count) != byte_count ) { /* JJLATER we should restore source here to original name */ perror(*ARGV) ; fprintf(stderr, "%s: Fatal error, aborting.\n", *ARGV); exit(1); } } (void) close(src_fd) ; (void) close(new_fd) ; (void) unlink(tmp_name) ; } #endif /* } */ if (preserve_date) { /* set time stamp */ #ifdef MSDOS /* { */ set_time.actime = stat_buf.st_atime ; set_time.modtime = stat_buf.st_mtime ; if (utime(src_name,&set_time)) #endif /* } */ #ifdef BSD /* { */ timep[0] = stat_buf.st_atime ; timep[1] = stat_buf.st_mtime ; if (utime(src_name,timep)) #endif /* } */ { fprintf(stderr, "%s: Failed to retain old time stamp on %s.\n" ,*ARGV, src_name ) ; return(1) ; } } if (verbose) { len1 = len2 = strlen(src_name) ; #define BS (char)8 while (len1--) putchar(BS) ; for ( len1 = len2 ; len1-- ; putchar(' ') ) ; for ( len1 = len2 ; len1-- ; putchar(BS) ) ; (void)fflush(stdout) ; } } return(0) ; } /* Output chars starting from base_p, incrementing up to top_p inclusive return 0 == OK , 1 == error*/ add_line(base_p,top_p) char *base_p, *top_p; { unsigned len ; char *current_p ; for (current_p = buf_out ; (base_p <= top_p); base_p++ ) if (*base_p != '\r' ) *current_p++ = *base_p ; /* suppress multiple \r\r before \n at end of line, afer addcr has been run several times on the same file, after a period of time */ #ifndef MSDOS /* { */ if (!reverse) *current_p++ = '\r' ; #endif /* } */ *current_p++ = '\n' ; *current_p = '\0' ; len = strlen(buf_out) ; if (write(new_fd,buf_out,(int)len) < len) { perror(*ARGV); fprintf(stderr,"%s: Failed to write %s.\n",*ARGV,tmp_name); (void) close(src_fd); (void) close(new_fd); (void) unlink(tmp_name); return(1) ; /* dont exit, as error could have been because we couldnt create a large temp. file, & next argument may require a smaller temp file */ } return(0) ; }