[news.software.anu-news] Patch part 5 of 7

fritz@unocss.UUCP (Tim Russell) (08/27/89)

+-+-+-+ Beginning of part 5 +-+-+-+
Xstatic short *p_len = Null(short*);`009/* length of each line */
Xstatic char *p_char = Nullch;`009`009/* +, -, and ! */
Xstatic int hunkmax = INITHUNKMAX;`009/* size of above arrays to begin with */
Xstatic int p_indent;`009`009`009/* indent to patch */
Xstatic LINENUM p_base;`009`009`009/* where to intuit this time */
Xstatic LINENUM p_bline;`009`009`009/* line # of p_base */
Xstatic LINENUM p_start;`009`009`009/* where intuit found a patch */
Xstatic LINENUM p_sline;`009`009`009/* and the line number for it */
Xstatic LINENUM p_hunk_beg;`009`009/* line number of current hunk */
Xstatic LINENUM p_efake = -1;`009`009/* end of faked up lines--don't free */
Xstatic LINENUM p_bfake = -1;`009`009/* beg of faked up lines */
X
X/* Prepare to look for the next patch in the patch file. */
X
Xvoid
Xre_patch()
X`123
X    p_first = Nulline;
X    p_newfirst = Nulline;
X    p_ptrn_lines = Nulline;
X    p_repl_lines = Nulline;
X    p_end = (LINENUM)-1;
X    p_max = Nulline;
X    p_indent = 0;
X`125
X
X/* Open the patch file at the beginning of time. */
X
Xvoid
Xopen_patch_file(filename)
Xchar *filename;
X`123
V    if (filename == Nullch `124`124 !*filename `124`124 strEQ(filename, "-"))
X `123
X`009pfp = fopen(TMPPATNAME, "w");
X`009if (pfp == Nullfp)
X`009    fatal2("patch: can't create %s.\n", TMPPATNAME);
X`009while (fgets(buf, sizeof buf, stdin) != Nullch)
X`009    fputs(buf, pfp);
X`009Fclose(pfp);
X`009filename = TMPPATNAME;
X    `125
X    pfp = fopen(filename, "r");
X    if (pfp == Nullfp)
X`009fatal2("patch file %s not found\n", filename);
X    Fstat(fileno(pfp), &filestat);
X    p_filesize = filestat.st_size;
X    next_intuit_at(0L,1L);`009`009`009/* start at the beginning */
X    set_hunkmax();
X`125
X
X/* Make sure our dynamically realloced tables are malloced to begin with. */
X
Xvoid
Xset_hunkmax()
X`123
X#ifndef lint
X    if (p_line == Null(char**))
X`009p_line = (char**) malloc((MEM)hunkmax * sizeof(char *));
X    if (p_len == Null(short*))
X`009p_len  = (short*) malloc((MEM)hunkmax * sizeof(short));
X#endif
X    if (p_char == Nullch)
X`009p_char = (char*)  malloc((MEM)hunkmax * sizeof(char));
X`125
X
X/* Enlarge the arrays containing the current hunk of patch. */
X
Xvoid
Xgrow_hunkmax()
X`123
X    hunkmax *= 2;
X    /*`032
V     * Note that on most systems, only the p_line array ever gets fresh memor
Xy
X     * since p_len can move into p_line's old space, and p_char can move into
X     * p_len's old space.  Not on PDP-11's however.  But it doesn't matter.
X     */
V    assert(p_line != Null(char**) && p_len != Null(short*) && p_char != Nullc
Xh);
X#ifndef lint
X    p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *));
X    p_len  = (short*) realloc((char*)p_len,  (MEM)hunkmax * sizeof(short));
X    p_char = (char*)  realloc((char*)p_char, (MEM)hunkmax * sizeof(char));
X#endif
X    if (p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch)
X`009return;
X    if (!using_plan_a)
X`009fatal1("patch: out of memory (grow_hunkmax)\n");
X    out_of_mem = TRUE;`009`009/* whatever is null will be allocated again */
X`009`009`009`009/* from within plan_a(), of all places */
X`125
X
X/* True if the remainder of the patch file contains a diff of some sort. */
X
Xbool
Xthere_is_another_patch()
X`123
X    if (p_base != 0L && p_base >= p_filesize) `123
X`009if (verbose)
X`009    say1("done\n");
X`009return FALSE;
X    `125
X    if (verbose)
X`009say1("Hmm...");
X    diff_type = intuit_diff_type();
X    if (!diff_type) `123
X`009if (p_base != 0L) `123
X`009    if (verbose)
X`009`009say1("  Ignoring the trailing garbage.\ndone\n");
X`009`125
X`009else
X`009    say1("  I can't seem to find a patch in there anywhere.\n");
X`009return FALSE;
X    `125
X    if (verbose)
X`009say3("  %sooks like %s to me...\n",
X`009    (p_base == 0L ? "L" : "The next patch l"),
X`009    diff_type == CONTEXT_DIFF ? "a context diff" :
X`009    diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
X`009    diff_type == NORMAL_DIFF ? "a normal diff" :
X`009    "an ed script" );
X    if (p_indent && verbose)
X`009say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");
X    skip_to(p_start,p_sline);
X    while (filearg[0] == Nullch) `123
X`009if (force) `123
X`009    say1("No file to patch.  Skipping...\n");
X`009    filearg[0] = savestr(bestguess);
X`009    return TRUE;
X`009`125
X`009ask1("File to patch: ");
X`009if (*buf != '\n') `123
X`009    if (bestguess)
X`009`009free(bestguess);
X`009    bestguess = savestr(buf);
X`009    filearg[0] = fetchname(buf, 0, FALSE);
X`009`125
X`009if (filearg[0] == Nullch) `123
X`009    ask1("No file found--skip this patch? [n] ");
X`009    if (*buf != 'y') `123
X`009`009continue;
X`009    `125
X`009    if (verbose)
X`009`009say1("Skipping patch...\n");
X`009    filearg[0] = fetchname(bestguess, 0, TRUE);
X`009    skip_rest_of_patch = TRUE;
X`009    return TRUE;
X`009`125
X    `125
X    return TRUE;
X`125
X
X/* Determine what kind of diff is in the remaining part of the patch file. */
X
Xint
Xintuit_diff_type()
X`123
X    Reg4 long this_line = 0;
X    Reg5 long previous_line;
X    Reg6 long first_command_line = -1;
X    long fcl_line;
X    Reg7 bool last_line_was_command = FALSE;
X    Reg8 bool this_is_a_command = FALSE;
X    Reg9 bool stars_last_line = FALSE;
X    Reg10 bool stars_this_line = FALSE;
X    Reg3 int indent;
X    Reg1 char *s;
X    Reg2 char *t;
X    char *indtmp = Nullch;
X    char *oldtmp = Nullch;
X    char *newtmp = Nullch;
X    char *indname = Nullch;
X    char *oldname = Nullch;
X    char *newname = Nullch;
X    Reg11 int retval;
X    bool no_filearg = (filearg[0] == Nullch);
X
X    ok_to_create_file = FALSE;
X    Fseek(pfp, p_base, 0);
X    p_input_line = p_bline - 1;
X    for (;;) `123
X`009previous_line = this_line;
X`009last_line_was_command = this_is_a_command;
X`009stars_last_line = stars_this_line;
X`009this_line = ftell(pfp);
X`009indent = 0;
X`009p_input_line++;
X`009if (fgets(buf, sizeof buf, pfp) == Nullch) `123
X`009    if (first_command_line >= 0L) `123
X`009`009`009`009`009/* nothing but deletes!? */
X`009`009p_start = first_command_line;
X`009`009p_sline = fcl_line;
X`009`009retval = ED_DIFF;
X`009`009goto scan_exit;
X`009    `125
X`009    else `123
X`009`009p_start = this_line;
X`009`009p_sline = p_input_line;
X`009`009retval = 0;
X`009`009goto scan_exit;
X`009    `125
X`009`125
X`009for (s = buf; *s == ' ' `124`124 *s == '\t'; s++) `123
X`009    if (*s == '\t')
X`009`009indent += 8 - (indent % 8);
X`009    else
X`009`009indent++;
X`009`125
X`009for (t=s; isdigit(*t) `124`124 *t == ','; t++) ;`032
X`009this_is_a_command = (isdigit(*s) &&
X`009  (*t == 'd' `124`124 *t == 'c' `124`124 *t == 'a') );
X`009if (first_command_line < 0L && this_is_a_command) `123`032
X`009    first_command_line = this_line;
X`009    fcl_line = p_input_line;
X`009    p_indent = indent;`009`009/* assume this for now */
X`009`125
X`009if (!stars_last_line && strnEQ(s, "*** ", 4))
X`009    oldtmp = savestr(s+4);
X`009else if (strnEQ(s, "--- ", 4))
X`009    newtmp = savestr(s+4);
X`009else if (strnEQ(s, "Index:", 6))
X`009    indtmp = savestr(s+6);
X`009else if (strnEQ(s, "Prereq:", 7)) `123
X`009    for (t=s+7; isspace(*t); t++) ;
X`009    revision = savestr(t);
X`009    for (t=revision; *t && !isspace(*t); t++) ;
X`009    *t = '\0';
X`009    if (!*revision) `123
X`009`009free(revision);
X`009`009revision = Nullch;
X`009    `125
X`009`125
X`009if ((!diff_type `124`124 diff_type == ED_DIFF) &&
X`009  first_command_line >= 0L &&
X`009  strEQ(s, ".\n") ) `123
X`009    p_indent = indent;
X`009    p_start = first_command_line;
X`009    p_sline = fcl_line;
X`009    retval = ED_DIFF;
X`009    goto scan_exit;
X`009`125
X`009stars_this_line = strnEQ(s, "********", 8);
X`009if ((!diff_type `124`124 diff_type == CONTEXT_DIFF) && stars_last_line &&
X`009`009 strnEQ(s, "*** ", 4)) `123
X`009    if (!atol(s+4))
X`009`009ok_to_create_file = TRUE;
X`009    /* if this is a new context diff the character just before */
X`009    /* the newline is a '*'. */
X`009    while (*s != '\n')
X`009`009s++;
X`009    p_indent = indent;
X`009    p_start = previous_line;
X`009    p_sline = p_input_line - 1;
X`009    retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
X`009    goto scan_exit;
X`009`125
X`009if ((!diff_type `124`124 diff_type == NORMAL_DIFF) &&`032
X`009  last_line_was_command &&
X`009  (strnEQ(s, "< ", 2) `124`124 strnEQ(s, "> ", 2)) ) `123
X`009    p_start = previous_line;
X`009    p_sline = p_input_line - 1;
X`009    p_indent = indent;
X`009    retval = NORMAL_DIFF;
X`009    goto scan_exit;
X`009`125
X    `125
X  scan_exit:
X    if (no_filearg) `123
X`009if (indtmp != Nullch)
X`009    indname = fetchname(indtmp, strippath, ok_to_create_file);
X`009if (oldtmp != Nullch)
X`009    oldname = fetchname(oldtmp, strippath, ok_to_create_file);
X`009if (newtmp != Nullch)
X`009    newname = fetchname(newtmp, strippath, ok_to_create_file);
X`009if (oldname && newname) `123
X`009    if (strlen(oldname) < strlen(newname))
X`009`009filearg[0] = savestr(oldname);
X`009    else
X`009`009filearg[0] = savestr(newname);
X`009`125
X`009else if (oldname)
X`009    filearg[0] = savestr(oldname);
X`009else if (newname)
X`009    filearg[0] = savestr(newname);
X`009else if (indname)
X`009    filearg[0] = savestr(indname);
X    `125
X    if (bestguess) `123
X`009free(bestguess);
X`009bestguess = Nullch;
X    `125
X    if (filearg[0] != Nullch)
X`009bestguess = savestr(filearg[0]);
X    else if (indtmp != Nullch)
X`009bestguess = fetchname(indtmp, strippath, TRUE);
X    else `123
X`009if (oldtmp != Nullch)
X`009    oldname = fetchname(oldtmp, strippath, TRUE);
X`009if (newtmp != Nullch)
X`009    newname = fetchname(newtmp, strippath, TRUE);
X`009if (oldname && newname) `123
X`009    if (strlen(oldname) < strlen(newname))
X`009`009bestguess = savestr(oldname);
X`009    else
X`009`009bestguess = savestr(newname);
X`009`125
X`009else if (oldname)
X`009    bestguess = savestr(oldname);
X`009else if (newname)
X`009    bestguess = savestr(newname);
X    `125
X    if (indtmp != Nullch)
X`009free(indtmp);
X    if (oldtmp != Nullch)
X`009free(oldtmp);
X    if (newtmp != Nullch)
X`009free(newtmp);
X    if (indname != Nullch)
X`009free(indname);
X    if (oldname != Nullch)
X`009free(oldname);
X    if (newname != Nullch)
X`009free(newname);
X    return retval;
X`125
X
X/* Remember where this patch ends so we know where to start up again. */
X
Xvoid
Xnext_intuit_at(file_pos,file_line)
Xlong file_pos;
Xlong file_line;
X`123
X    p_base = file_pos;
X    p_bline = file_line;
X`125
X
X/* Basically a verbose fseek() to the actual diff listing. */
X
Xvoid
Xskip_to(file_pos,file_line)
Xlong file_pos;
Xlong file_line;
X`123
X    char *ret;
X
X    assert(p_base <= file_pos);
X    if (verbose && p_base < file_pos) `123
X`009Fseek(pfp, p_base, 0);
X`009say1("The text leading up to this was:\n--------------------------\n");
X`009while (ftell(pfp) < file_pos) `123
X`009    ret = fgets(buf, sizeof buf, pfp);
X`009    assert(ret != Nullch);
X`009    say2("`124%s", buf);
X`009`125
X`009say1("--------------------------\n");
X    `125
X    else
X`009Fseek(pfp, file_pos, 0);
X    p_input_line = file_line - 1;
X`125
X
X/* True if there is more of the current diff listing to process. */
X
Xbool
Xanother_hunk()
X`123
X    Reg1 char *s;
X    Reg8 char *ret;
X    Reg2 int context = 0;
X
X    while (p_end >= 0) `123
X`009if (p_end == p_efake)
X`009    p_end = p_bfake;`009`009/* don't free twice */
X`009else
X`009    free(p_line[p_end]);
X`009p_end--;
X    `125
X    assert(p_end == -1);
X    p_efake = -1;
X
X    p_max = hunkmax;`009`009`009/* gets reduced when --- found */
V    if (diff_type == CONTEXT_DIFF `124`124 diff_type == NEW_CONTEXT_DIFF) `12
X3
X`009long line_beginning = ftell(pfp);
X`009`009`009`009`009/* file pos of the current line */
X`009LINENUM repl_beginning = 0;`009/* index of --- line */
X`009Reg4 LINENUM fillcnt = 0;`009/* #lines of missing ptrn or repl */
X`009Reg5 LINENUM fillsrc;`009`009/* index of first line to copy */
X`009Reg6 LINENUM filldst;`009`009/* index of first missing line */
X`009bool ptrn_spaces_eaten = FALSE;`009/* ptrn was slightly misformed */
X`009Reg9 bool repl_could_be_missing = TRUE;
X`009`009`009`009`009/* no + or ! lines in this hunk */
X`009bool repl_missing = FALSE;`009/* we are now backtracking */
X`009long repl_backtrack_position = 0;
X`009`009`009`009`009/* file pos of first repl line */
X`009LINENUM repl_patch_line;`009/* input line number for same */
X`009Reg7 LINENUM ptrn_copiable = 0;
X`009`009`009`009`009/* # of copiable lines in ptrn */
X
X`009ret = pgets(buf, sizeof buf, pfp);
X`009p_input_line++;
X`009if (ret == Nullch `124`124 strnNE(buf, "********", 8)) `123
X`009    next_intuit_at(line_beginning,p_input_line);
X`009    return FALSE;
X`009`125
X`009p_context = 100;
X`009p_hunk_beg = p_input_line + 1;
X`009while (p_end < p_max) `123
X`009    line_beginning = ftell(pfp);
X`009    ret = pgets(buf, sizeof buf, pfp);
X`009    p_input_line++;
X`009    if (ret == Nullch) `123
X`009`009if (p_max - p_end < 4)
X`009`009    Strcpy(buf, "  \n");  /* assume blank lines got chopped */
X`009`009else `123
X`009`009    if (repl_beginning && repl_could_be_missing) `123
X`009`009`009repl_missing = TRUE;
X`009`009`009goto hunk_done;
X`009`009    `125
X`009`009    fatal1("Unexpected end of file in patch.\n");
X`009`009`125
X`009    `125
X`009    p_end++;
X`009    assert(p_end < hunkmax);
X`009    p_char[p_end] = *buf;
X`009    p_line[p_end] = Nullch;
X`009    switch (*buf) `123
X`009    case '*':
X`009`009if (strnEQ(buf, "********", 8)) `123
X`009`009    if (repl_beginning && repl_could_be_missing) `123
X`009`009`009repl_missing = TRUE;
X`009`009`009goto hunk_done;
X`009`009    `125
X`009`009    else
X`009`009`009fatal2("Unexpected end of hunk at line %ld.\n",
X`009`009`009    p_input_line);
X`009`009`125
X`009`009if (p_end != 0) `123
X`009`009    if (repl_beginning && repl_could_be_missing) `123
X`009`009`009repl_missing = TRUE;
X`009`009`009goto hunk_done;
X`009`009    `125
X`009`009    fatal3("Unexpected *** at line %ld: %s", p_input_line, buf);
X`009`009`125
X`009`009context = 0;
X`009`009p_line[p_end] = savestr(buf);
X`009`009if (out_of_mem) `123
X`009`009    p_end--;
X`009`009    return FALSE;
X`009`009`125
X`009`009for (s=buf; *s && !isdigit(*s); s++) ;
X`009`009if (!*s)
X`009`009    goto malformed;
X`009`009p_first = (LINENUM) atol(s);
X`009`009while (isdigit(*s)) s++;
X`009`009if (*s == ',') `123
X`009`009    for (; *s && !isdigit(*s); s++) ;
X`009`009    if (!*s)
X`009`009`009goto malformed;
X`009`009    p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
X`009`009`125
X`009`009else if (p_first)
X`009`009    p_ptrn_lines = 1;
X`009`009else `123
X`009`009    p_ptrn_lines = 0;
X`009`009    p_first = 1;
X`009`009`125
X`009`009p_max = p_ptrn_lines + 6;`009/* we need this much at least */
X`009`009while (p_max >= hunkmax)
X`009`009    grow_hunkmax();
X`009`009p_max = hunkmax;
X`009`009break;
-+-+-+-+-+ End of part 5 +-+-+-+-+-
-- 
---------------------------------+--------------------------------------------
 Tim Russell, Computer Operator  | Internet: russell@zeus.unl.edu
 Campus Computing                | Bitnet:   russell@unoma1
 University of Nebraska at Omaha | UUCP:     uunet!zeus.unl.edu!russell