Home | History | Annotate | Line # | Download | only in patch
inp.c revision 1.1.1.1
      1  1.1.1.1  tls /* $Header: /tank/opengrok/rsync2/NetBSD/src/usr.bin/patch/inp.c,v 1.1.1.1 1997/01/09 14:47:39 tls Exp $
      2      1.1  cgd  *
      3      1.1  cgd  * $Log: inp.c,v $
      4      1.1  cgd  * Revision 1.1.1.1  1997/01/09 14:47:39  tls
      5      1.1  cgd  * Import from 4.4BSD-Lite2
      6      1.1  cgd  *
      7      1.1  cgd  * Revision 2.0  86/09/17  15:37:02  lwall
      8      1.1  cgd  * Baseline for netwide release.
      9      1.1  cgd  *
     10      1.1  cgd  */
     11      1.1  cgd 
     12      1.1  cgd #include "EXTERN.h"
     13      1.1  cgd #include "common.h"
     14      1.1  cgd #include "util.h"
     15      1.1  cgd #include "pch.h"
     16      1.1  cgd #include "INTERN.h"
     17      1.1  cgd #include "inp.h"
     18      1.1  cgd 
     19      1.1  cgd /* Input-file-with-indexable-lines abstract type */
     20      1.1  cgd 
     21      1.1  cgd static long i_size;			/* size of the input file */
     22      1.1  cgd static char *i_womp;			/* plan a buffer for entire file */
     23      1.1  cgd static char **i_ptr;			/* pointers to lines in i_womp */
     24      1.1  cgd 
     25      1.1  cgd static int tifd = -1;			/* plan b virtual string array */
     26      1.1  cgd static char *tibuf[2];			/* plan b buffers */
     27      1.1  cgd static LINENUM tiline[2] = {-1, -1};	/* 1st line in each buffer */
     28      1.1  cgd static LINENUM lines_per_buf;		/* how many lines per buffer */
     29      1.1  cgd static int tireclen;			/* length of records in tmp file */
     30      1.1  cgd 
     31      1.1  cgd /* New patch--prepare to edit another file. */
     32      1.1  cgd 
     33      1.1  cgd void
     34      1.1  cgd re_input()
     35      1.1  cgd {
     36      1.1  cgd     if (using_plan_a) {
     37      1.1  cgd 	i_size = 0;
     38      1.1  cgd #ifndef lint
     39      1.1  cgd 	if (i_ptr != Null(char**))
     40      1.1  cgd 	    free((char *)i_ptr);
     41      1.1  cgd #endif
     42      1.1  cgd 	if (i_womp != Nullch)
     43      1.1  cgd 	    free(i_womp);
     44      1.1  cgd 	i_womp = Nullch;
     45      1.1  cgd 	i_ptr = Null(char **);
     46      1.1  cgd     }
     47      1.1  cgd     else {
     48      1.1  cgd 	using_plan_a = TRUE;		/* maybe the next one is smaller */
     49      1.1  cgd 	Close(tifd);
     50      1.1  cgd 	tifd = -1;
     51      1.1  cgd 	free(tibuf[0]);
     52      1.1  cgd 	free(tibuf[1]);
     53      1.1  cgd 	tibuf[0] = tibuf[1] = Nullch;
     54      1.1  cgd 	tiline[0] = tiline[1] = -1;
     55      1.1  cgd 	tireclen = 0;
     56      1.1  cgd     }
     57      1.1  cgd }
     58      1.1  cgd 
     59      1.1  cgd /* Constuct the line index, somehow or other. */
     60      1.1  cgd 
     61      1.1  cgd void
     62      1.1  cgd scan_input(filename)
     63      1.1  cgd char *filename;
     64      1.1  cgd {
     65      1.1  cgd     if (!plan_a(filename))
     66      1.1  cgd 	plan_b(filename);
     67      1.1  cgd     if (verbose) {
     68      1.1  cgd 	say3("Patching file %s using Plan %s...\n", filename,
     69      1.1  cgd 	  (using_plan_a ? "A" : "B") );
     70      1.1  cgd     }
     71      1.1  cgd }
     72      1.1  cgd 
     73      1.1  cgd /* Try keeping everything in memory. */
     74      1.1  cgd 
     75      1.1  cgd bool
     76  1.1.1.1  tls plan_a(filename)
     77      1.1  cgd char *filename;
     78      1.1  cgd {
     79      1.1  cgd     int ifd;
     80  1.1.1.1  tls     Reg1 char *s;
     81      1.1  cgd     Reg2 LINENUM iline;
     82      1.1  cgd 
     83      1.1  cgd     if (ok_to_create_file && stat(filename, &filestat) < 0) {
     84      1.1  cgd 	if (verbose)
     85      1.1  cgd 	    say2("(Creating file %s...)\n",filename);
     86  1.1.1.1  tls 	makedirs(filename, TRUE);
     87  1.1.1.1  tls 	close(creat(filename, 0666));
     88  1.1.1.1  tls     }
     89      1.1  cgd     if (stat(filename, &filestat) < 0) {
     90      1.1  cgd 	Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX);
     91  1.1.1.1  tls 	if (stat(buf, &filestat) >= 0 || stat(buf+4, &filestat) >= 0) {
     92  1.1.1.1  tls 	    Sprintf(buf, CHECKOUT, filename);
     93      1.1  cgd 	    if (verbose)
     94  1.1.1.1  tls 		say2("Can't find %s--attempting to check it out from RCS.\n",
     95  1.1.1.1  tls 		    filename);
     96  1.1.1.1  tls 	    if (system(buf) || stat(filename, &filestat))
     97  1.1.1.1  tls 		fatal2("Can't check out %s.\n", filename);
     98  1.1.1.1  tls 	}
     99  1.1.1.1  tls 	else {
    100  1.1.1.1  tls 	    Sprintf(buf, "SCCS/%s%s", SCCSPREFIX, filename);
    101  1.1.1.1  tls 	    if (stat(buf, &filestat) >= 0 || stat(buf+5, &filestat) >= 0) {
    102  1.1.1.1  tls 		Sprintf(buf, GET, filename);
    103  1.1.1.1  tls 		if (verbose)
    104  1.1.1.1  tls 		    say2("Can't find %s--attempting to get it from SCCS.\n",
    105  1.1.1.1  tls 			filename);
    106  1.1.1.1  tls 		if (system(buf) || stat(filename, &filestat))
    107  1.1.1.1  tls 		    fatal2("Can't get %s.\n", filename);
    108      1.1  cgd 	    }
    109      1.1  cgd 	    else
    110      1.1  cgd 		fatal2("Can't find %s.\n", filename);
    111  1.1.1.1  tls 	}
    112  1.1.1.1  tls     }
    113      1.1  cgd     filemode = filestat.st_mode;
    114      1.1  cgd     if ((filemode & S_IFMT) & ~S_IFREG)
    115      1.1  cgd 	fatal2("%s is not a normal file--can't patch.\n", filename);
    116      1.1  cgd     i_size = filestat.st_size;
    117      1.1  cgd     if (out_of_mem) {
    118      1.1  cgd 	set_hunkmax();		/* make sure dynamic arrays are allocated */
    119      1.1  cgd 	out_of_mem = FALSE;
    120      1.1  cgd 	return FALSE;			/* force plan b because plan a bombed */
    121      1.1  cgd     }
    122      1.1  cgd #ifdef lint
    123      1.1  cgd     i_womp = Nullch;
    124      1.1  cgd #else
    125      1.1  cgd     i_womp = malloc((MEM)(i_size+2));	/* lint says this may alloc less than */
    126      1.1  cgd 					/* i_size, but that's okay, I think. */
    127      1.1  cgd #endif
    128  1.1.1.1  tls     if (i_womp == Nullch)
    129      1.1  cgd 	return FALSE;
    130      1.1  cgd     if ((ifd = open(filename, 0)) < 0)
    131      1.1  cgd 	fatal2("Can't open file %s\n", filename);
    132      1.1  cgd #ifndef lint
    133      1.1  cgd     if (read(ifd, i_womp, (int)i_size) != i_size) {
    134      1.1  cgd 	Close(ifd);	/* probably means i_size > 15 or 16 bits worth */
    135      1.1  cgd 	free(i_womp);	/* at this point it doesn't matter if i_womp was */
    136      1.1  cgd 	return FALSE;	/*   undersized. */
    137      1.1  cgd     }
    138      1.1  cgd #endif
    139      1.1  cgd     Close(ifd);
    140      1.1  cgd     if (i_size && i_womp[i_size-1] != '\n')
    141      1.1  cgd 	i_womp[i_size++] = '\n';
    142      1.1  cgd     i_womp[i_size] = '\0';
    143      1.1  cgd 
    144      1.1  cgd     /* count the lines in the buffer so we know how many pointers we need */
    145      1.1  cgd 
    146      1.1  cgd     iline = 0;
    147      1.1  cgd     for (s=i_womp; *s; s++) {
    148      1.1  cgd 	if (*s == '\n')
    149      1.1  cgd 	    iline++;
    150      1.1  cgd     }
    151      1.1  cgd #ifdef lint
    152      1.1  cgd     i_ptr = Null(char**);
    153      1.1  cgd #else
    154      1.1  cgd     i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
    155      1.1  cgd #endif
    156      1.1  cgd     if (i_ptr == Null(char **)) {	/* shucks, it was a near thing */
    157      1.1  cgd 	free((char *)i_womp);
    158      1.1  cgd 	return FALSE;
    159      1.1  cgd     }
    160      1.1  cgd 
    161      1.1  cgd     /* now scan the buffer and build pointer array */
    162      1.1  cgd 
    163      1.1  cgd     iline = 1;
    164      1.1  cgd     i_ptr[iline] = i_womp;
    165      1.1  cgd     for (s=i_womp; *s; s++) {
    166      1.1  cgd 	if (*s == '\n')
    167      1.1  cgd 	    i_ptr[++iline] = s+1;	/* these are NOT null terminated */
    168      1.1  cgd     }
    169      1.1  cgd     input_lines = iline - 1;
    170      1.1  cgd 
    171      1.1  cgd     /* now check for revision, if any */
    172      1.1  cgd 
    173      1.1  cgd     if (revision != Nullch) {
    174  1.1.1.1  tls 	if (!rev_in_string(i_womp)) {
    175  1.1.1.1  tls 	    if (force) {
    176      1.1  cgd 		if (verbose)
    177      1.1  cgd 		    say2("\
    178      1.1  cgd Warning: this file doesn't appear to be the %s version--patching anyway.\n",
    179  1.1.1.1  tls 			revision);
    180  1.1.1.1  tls 	    }
    181      1.1  cgd 	    else {
    182      1.1  cgd 		ask2("\
    183  1.1.1.1  tls This file doesn't appear to be the %s version--patch anyway? [n] ",
    184      1.1  cgd 		    revision);
    185      1.1  cgd 	    if (*buf != 'y')
    186      1.1  cgd 		fatal1("Aborted.\n");
    187      1.1  cgd 	    }
    188      1.1  cgd 	}
    189      1.1  cgd 	else if (verbose)
    190      1.1  cgd 	    say2("Good.  This file appears to be the %s version.\n",
    191      1.1  cgd 		revision);
    192      1.1  cgd     }
    193      1.1  cgd     return TRUE;			/* plan a will work */
    194      1.1  cgd }
    195      1.1  cgd 
    196      1.1  cgd /* Keep (virtually) nothing in memory. */
    197      1.1  cgd 
    198      1.1  cgd void
    199      1.1  cgd plan_b(filename)
    200      1.1  cgd char *filename;
    201      1.1  cgd {
    202      1.1  cgd     Reg3 FILE *ifp;
    203      1.1  cgd     Reg1 int i = 0;
    204      1.1  cgd     Reg2 int maxlen = 1;
    205      1.1  cgd     Reg4 bool found_revision = (revision == Nullch);
    206  1.1.1.1  tls 
    207      1.1  cgd     using_plan_a = FALSE;
    208  1.1.1.1  tls     if ((ifp = fopen(filename, "r")) == Nullfp)
    209      1.1  cgd 	fatal2("Can't open file %s\n", filename);
    210      1.1  cgd     if ((tifd = creat(TMPINNAME, 0666)) < 0)
    211      1.1  cgd 	fatal2("Can't open file %s\n", TMPINNAME);
    212      1.1  cgd     while (fgets(buf, sizeof buf, ifp) != Nullch) {
    213      1.1  cgd 	if (revision != Nullch && !found_revision && rev_in_string(buf))
    214      1.1  cgd 	    found_revision = TRUE;
    215      1.1  cgd 	if ((i = strlen(buf)) > maxlen)
    216      1.1  cgd 	    maxlen = i;			/* find longest line */
    217      1.1  cgd     }
    218      1.1  cgd     if (revision != Nullch) {
    219  1.1.1.1  tls 	if (!found_revision) {
    220  1.1.1.1  tls 	    if (force) {
    221      1.1  cgd 		if (verbose)
    222      1.1  cgd 		    say2("\
    223      1.1  cgd Warning: this file doesn't appear to be the %s version--patching anyway.\n",
    224  1.1.1.1  tls 			revision);
    225  1.1.1.1  tls 	    }
    226      1.1  cgd 	    else {
    227      1.1  cgd 		ask2("\
    228  1.1.1.1  tls This file doesn't appear to be the %s version--patch anyway? [n] ",
    229      1.1  cgd 		    revision);
    230      1.1  cgd 		if (*buf != 'y')
    231      1.1  cgd 		    fatal1("Aborted.\n");
    232      1.1  cgd 	    }
    233      1.1  cgd 	}
    234      1.1  cgd 	else if (verbose)
    235      1.1  cgd 	    say2("Good.  This file appears to be the %s version.\n",
    236      1.1  cgd 		revision);
    237      1.1  cgd     }
    238      1.1  cgd     Fseek(ifp, 0L, 0);		/* rewind file */
    239      1.1  cgd     lines_per_buf = BUFFERSIZE / maxlen;
    240      1.1  cgd     tireclen = maxlen;
    241  1.1.1.1  tls     tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
    242      1.1  cgd     tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
    243      1.1  cgd     if (tibuf[1] == Nullch)
    244      1.1  cgd 	fatal1("Can't seem to get enough memory.\n");
    245  1.1.1.1  tls     for (i=1; ; i++) {
    246      1.1  cgd 	if (! (i % lines_per_buf))	/* new block */
    247      1.1  cgd 	    if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
    248      1.1  cgd 		fatal1("patch: can't write temp file.\n");
    249      1.1  cgd 	if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
    250      1.1  cgd 	  == Nullch) {
    251  1.1.1.1  tls 	    input_lines = i - 1;
    252      1.1  cgd 	    if (i % lines_per_buf)
    253      1.1  cgd 		if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
    254      1.1  cgd 		    fatal1("patch: can't write temp file.\n");
    255      1.1  cgd 	    break;
    256      1.1  cgd 	}
    257      1.1  cgd     }
    258  1.1.1.1  tls     Fclose(ifp);
    259      1.1  cgd     Close(tifd);
    260      1.1  cgd     if ((tifd = open(TMPINNAME, 0)) < 0) {
    261      1.1  cgd 	fatal2("Can't reopen file %s\n", TMPINNAME);
    262      1.1  cgd     }
    263      1.1  cgd }
    264      1.1  cgd 
    265      1.1  cgd /* Fetch a line from the input file, \n terminated, not necessarily \0. */
    266      1.1  cgd 
    267      1.1  cgd char *
    268      1.1  cgd ifetch(line,whichbuf)
    269      1.1  cgd Reg1 LINENUM line;
    270      1.1  cgd int whichbuf;				/* ignored when file in memory */
    271      1.1  cgd {
    272      1.1  cgd     if (line < 1 || line > input_lines)
    273      1.1  cgd 	return "";
    274      1.1  cgd     if (using_plan_a)
    275      1.1  cgd 	return i_ptr[line];
    276      1.1  cgd     else {
    277      1.1  cgd 	LINENUM offline = line % lines_per_buf;
    278      1.1  cgd 	LINENUM baseline = line - offline;
    279      1.1  cgd 
    280      1.1  cgd 	if (tiline[0] == baseline)
    281      1.1  cgd 	    whichbuf = 0;
    282      1.1  cgd 	else if (tiline[1] == baseline)
    283      1.1  cgd 	    whichbuf = 1;
    284  1.1.1.1  tls 	else {
    285      1.1  cgd 	    tiline[whichbuf] = baseline;
    286      1.1  cgd #ifndef lint		/* complains of long accuracy */
    287  1.1.1.1  tls 	    Lseek(tifd, (off_t)baseline / lines_per_buf * BUFFERSIZE, 0);
    288      1.1  cgd #endif
    289      1.1  cgd 	    if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
    290      1.1  cgd 		fatal2("Error reading tmp file %s.\n", TMPINNAME);
    291      1.1  cgd 	}
    292      1.1  cgd 	return tibuf[whichbuf] + (tireclen*offline);
    293      1.1  cgd     }
    294      1.1  cgd }
    295      1.1  cgd 
    296      1.1  cgd /* True if the string argument contains the revision number we want. */
    297      1.1  cgd 
    298      1.1  cgd bool
    299      1.1  cgd rev_in_string(string)
    300      1.1  cgd char *string;
    301      1.1  cgd {
    302      1.1  cgd     Reg1 char *s;
    303      1.1  cgd     Reg2 int patlen;
    304      1.1  cgd 
    305      1.1  cgd     if (revision == Nullch)
    306      1.1  cgd 	return TRUE;
    307      1.1  cgd     patlen = strlen(revision);
    308      1.1  cgd     for (s = string; *s; s++) {
    309      1.1  cgd 	if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
    310      1.1  cgd 		isspace(s[patlen+1] )) {
    311      1.1  cgd 	    return TRUE;
    312      1.1  cgd 	}
    313  1.1.1.1  tls     }
    314                   return FALSE;
    315               }
    316               
    317