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