Category : C Source Code
Archive   : PATCH12.ZIP
Filename : PATCH.C

 
Output of file : PATCH.C contained in archive : PATCH12.ZIP
char rcsid[] =
"$Header: patch.c,v 2.0.1.8 90/07/15 14:00:00 aas $";

/* patch - a program to apply diffs to original files
*
* Copyright 1986, Larry Wall
*
* This program may be copied as long as you don't try to make any
* money off of it, or pretend that you wrote it.
*
* $Log: patch.c,v $
* Revision 2.0.1.7 90/07/15 14:00:00 aas
* made init temp file names a little more MS-DOS aware
*
* Revision 2.0.1.7 90/05/30 11:30:00 mward
* Added usage message vars and routines: use_msg, progname, usage, fname
* Check environment for TMP and init temp file names
*
* Revision 2.0.1.6 88/06/22 20:46:39 lwall
* patch12: rindex() wasn't declared
*
* Revision 2.0.1.5 88/06/03 15:09:37 lwall
* patch10: exit code improved.
* patch10: better support for non-flexfilenames.
*
* Revision 2.0.1.4 87/02/16 14:00:04 lwall
* Short replacement caused spurious "Out of sync" message.
*
* Revision 2.0.1.3 87/01/30 22:45:50 lwall
* Improved diagnostic on sync error.
* Moved do_ed_script() to pch.c.
*
* Revision 2.0.1.2 86/11/21 09:39:15 lwall
* Fuzz factor caused offset of installed lines.
*
* Revision 2.0.1.1 86/10/29 13:10:22 lwall
* Backwards search could terminate prematurely.
*
* Revision 2.0 86/09/17 15:37:32 lwall
* Baseline for netwide release.
*
* Revision 1.5 86/08/01 20:53:24 lwall
* Changed some %d's to %ld's.
* Linted.
*
* Revision 1.4 86/08/01 19:17:29 lwall
* Fixes for machines that can't vararg.
* Added fuzz factor.
* Generalized -p.
* General cleanup.
*
* 85/08/15 van%ucbmonet@berkeley
* Changes for 4.3bsd diff -c.
*
* Revision 1.3 85/03/26 15:07:43 lwall
* Frozen.
*
* Revision 1.2.1.9 85/03/12 17:03:35 lwall
* Changed pfp->_file to fileno(pfp).
*
* Revision 1.2.1.8 85/03/12 16:30:43 lwall
* Check i_ptr and i_womp to make sure they aren't null before freeing.
* Also allow ed output to be suppressed.
*
* Revision 1.2.1.7 85/03/12 15:56:13 lwall
* Added -p option from jromine@uci-750a.
*
* Revision 1.2.1.6 85/03/12 12:12:51 lwall
* Now checks for normalness of file to patch.
*
* Revision 1.2.1.5 85/03/12 11:52:12 lwall
* Added -D (#ifdef) option from joe@fluke.
*
* Revision 1.2.1.4 84/12/06 11:14:15 lwall
* Made smarter about SCCS subdirectories.
*
* Revision 1.2.1.3 84/12/05 11:18:43 lwall
* Added -l switch to do loose string comparison.
*
* Revision 1.2.1.2 84/12/04 09:47:13 lwall
* Failed hunk count not reset on multiple patch file.
*
* Revision 1.2.1.1 84/12/04 09:42:37 lwall
* Branch for sdcrdcf changes.
*
* Revision 1.2 84/11/29 13:29:51 lwall
* Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed
* multiple calls to mktemp(). Will now work on machines that can only
* read 32767 chars. Added -R option for diffs with new and old swapped.
* Various cosmetic changes.
*
* Revision 1.1 84/11/09 17:03:58 lwall
* Initial revision
*
*/

#include "INTERN.h"
#include "common.h"
#include "EXTERN.h"
#include "version.h"
#include "util.h"
#include "pch.h"
#include "inp.h"

/* procedures */

char *fname();
void usage();
void reinitialize_almost_everything();
void get_some_switches();
LINENUM locate_hunk();
void abort_hunk();
void apply_hunk();
void init_output();
void init_reject();
void copy_till();
void spew_output();
void dump_line();
bool patch_match();
bool similar();
void re_input();
void my_exit();


char *progname;

char *use_msg[] = {
"purpose: apply diff file(s) to original(s) to generate updated file(s)\n",
"usage: %s [options] orig patchfile [+ [options] orig]\n",
" %s "options:\n",
" - read patchfile from standard input\n",
" -? display help message (this text)\n",
" -b arg use arg as backup file extension (default is ~ or .orig)\n",
" -B arg use arg as backup file prefix (cancels -b option)\n",
" -c interpret patchfile as context diffs\n",
" -d arg use arg as directory to cd to before continuing\n",
" -D arg surround patched with \"#ifdef arg ... #endif\"\n",
" -e interpret patchfile as an ed script\n",
" -f do not ask questions\n",
" -F set max fuzz factor to (default 2, context diffs only)\n",
" -h display help message (this text)\n",
" -l loose (non \\n whitespace) pattern matching\n",
" -n interpret patchfile as a normal diff\n",
" -N ignore patches that are reversed or already applied\n",
" -o arg use arg as output file name\n",
" -p set path strip count to (default 937,# /'s to strip)\n",
" -r arg use arg as the reject file name\n",
" -R interpret patch as if orig and new were reversed at diff gen\n",
" -s silent operation - no messages\n",
" -S skip current patch, but continue\n",
" -v version - print revision header and patch level\n",
" -x set internal debugging flags to \n",
"examples\n",
" %s " %s -S + -S + "notes:\n"
" By default, the patched version is put in place of the original\n",
NULL
};


/* Return pointer to first char of file name in spec */

char *
fname(char *spec)
{
char *cptr;
char *tptr;

cptr = spec + strlen(spec);
while ((cptr!=spec) && (index("/\\:",*(cptr-1))==Nullch)) {
cptr--;
}
if ((tptr=index(cptr,'.'))!=Nullch) *tptr='\0';
return (cptr);
}


/* Print the usage message */

void
usage()
{
char **ptr;
char *name;

name = fname(progname);
for (ptr=use_msg; *ptr; ptr++) {
say2(*ptr,name);
}
}


/* Apply a set of diffs as appropriate. */

main(argc,argv)
int argc;
char **argv;
{
LINENUM where;
LINENUM newwhere;
LINENUM fuzz;
LINENUM mymaxfuzz;
int hunk = 0;
int failed = 0;
int failtotal = 0;
int i;
char tmpdir[MAXPATH];
char *tmpenv;
char c;

progname = (*argv[0]?argv[0]:"patch");
setbuf(stderr, serrbuf);
for (i = 0; i filearg[i] = Nullch;

/* initialize temp file names */
tmpenv = getenv("TMP");
strcpy(tmpdir,(tmpenv!=NULL?tmpenv:""));
if (strlen(tmpdir))
if((c=tmpdir[strlen(tmpdir)-1])!='/' && c!='\\')
strcat(tmpdir,"/");
TMPOUTNAME = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPOUTNAME));
TMPINNAME = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPINNAME));
TMPREJNAME = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPREJNAME));
TMPPATNAME = strcat(strcpy(malloc(MAXPATH),tmpdir),fname(TMPPATNAME));
Mktemp(TMPOUTNAME);
Mktemp(TMPINNAME);
Mktemp(TMPREJNAME);
Mktemp(TMPPATNAME);

/* parse switches */
Argc = argc;
Argv = argv;
get_some_switches();

/* make sure we clean up /tmp in case of disaster */
set_signals(0);

for (
open_patch_file(filearg[1]);
there_is_another_patch();
reinitialize_almost_everything()
) { /* for each patch in patch file */

if (outname == Nullch)
outname = savestr(filearg[0]);

/* initialize the patched file */
if (!skip_rest_of_patch)
init_output(TMPOUTNAME);

/* for ed script just up and do it and exit */
if (diff_type == ED_DIFF) {
do_ed_script();
continue;
}

/* initialize reject file */
init_reject(TMPREJNAME);

/* find out where all the lines are */
if (!skip_rest_of_patch)
scan_input(filearg[0]);

/* from here on, open no standard i/o files, because malloc */
/* might misfire and we can't catch it easily */

/* apply each hunk of patch */
hunk = 0;
failed = 0;
out_of_mem = FALSE;
while (another_hunk()) {
hunk++;
fuzz = Nulline;
mymaxfuzz = pch_context();
if (maxfuzz < mymaxfuzz)
mymaxfuzz = maxfuzz;
if (!skip_rest_of_patch) {
do {
where = locate_hunk(fuzz);
if (hunk == 1 && where == Nulline && !force) {
/* dwim for reversed patch? */
if (!pch_swap()) {
if (fuzz == Nulline)
say1(
"Not enough memory to try swapped hunk! Assuming unswapped.\n");
continue;
}
reverse = !reverse;
where = locate_hunk(fuzz); /* try again */
if (where == Nulline) { /* didn't find it swapped */
if (!pch_swap()) /* put it back to normal */
fatal1("Lost hunk on alloc error!\n");
reverse = !reverse;
}
else if (noreverse) {
if (!pch_swap()) /* put it back to normal */
fatal1("Lost hunk on alloc error!\n");
reverse = !reverse;
say1(
"Ignoring previously applied (or reversed) patch.\n");
skip_rest_of_patch = TRUE;
}
else {
ask3(
"%seversed (or previously applied) patch detected! %s -R? [y] ",
reverse ? "R" : "Unr",
reverse ? "Assume" : "Ignore");
if (*buf == 'n') {
ask1("Apply anyway? [n] ");
if (*buf != 'y')
skip_rest_of_patch = TRUE;
where = Nulline;
reverse = !reverse;
if (!pch_swap()) /* put it back to normal */
fatal1("Lost hunk on alloc error!\n");
}
}
}
} while (!skip_rest_of_patch && where == Nulline &&
++fuzz <= mymaxfuzz);

if (skip_rest_of_patch) { /* just got decided */
Fclose(ofp);
ofp = Nullfp;
}
}

newwhere = pch_newfirst() + last_offset;
if (skip_rest_of_patch) {
abort_hunk();
failed++;
if (verbose)
say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
}
else if (where == Nulline) {
abort_hunk();
failed++;
if (verbose)
say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
}
else {
apply_hunk(where);
if (verbose) {
say3("Hunk #%d succeeded at %ld", hunk, newwhere);
if (fuzz)
say2(" with fuzz %ld", fuzz);
if (last_offset)
say3(" (offset %ld line%s)",
last_offset, last_offset==1L?"":"s");
say1(".\n");
}
}
}

if (out_of_mem && using_plan_a) {
Argc = Argc_last;
Argv = Argv_last;
say1("\n\nRan out of memory using Plan A--trying again...\n\n");
continue;
}

assert(hunk);

/* finish spewing out the new file */
if (!skip_rest_of_patch)
spew_output();

/* and put the output where desired */
ignore_signals();
if (!skip_rest_of_patch) {
if (move_file(TMPOUTNAME, outname) < 0) {
toutkeep = TRUE;
chmod(TMPOUTNAME, filemode);
}
else
chmod(outname, filemode);
}
Fclose(rejfp);
rejfp = Nullfp;
if (failed) {
failtotal += failed;
if (!*rejname) {
Strcpy(rejname, outname);
#ifndef FLEXFILENAMES
{
char *rindex();
char *s = rindex(rejname,'/');

if (!s)
s = rejname;
if (strlen(s) > 13)
if (s[12] == '.') /* try to preserve difference */
s[12] = s[13]; /* between .h, .c, .y, etc. */
s[13] = '\0';
}
#endif
Strcat(rejname, REJEXT);
}
if (skip_rest_of_patch) {
say4("%d out of %d hunks ignored--saving rejects to %s\n",
failed, hunk, rejname);
}
else {
say4("%d out of %d hunks failed--saving rejects to %s\n",
failed, hunk, rejname);
}
if (move_file(TMPREJNAME, rejname) < 0)
trejkeep = TRUE;
}
set_signals(1);
}
my_exit(failtotal);
}

/* Prepare to find the next patch to do in the patch file. */

void
reinitialize_almost_everything()
{
re_patch();
re_input();

input_lines = 0;
last_frozen_line = 0;

filec = 0;
if (filearg[0] != Nullch && !out_of_mem) {
free(filearg[0]);
filearg[0] = Nullch;
}

if (outname != Nullch) {
free(outname);
outname = Nullch;
}

last_offset = 0;

diff_type = 0;

if (revision != Nullch) {
free(revision);
revision = Nullch;
}

reverse = FALSE;
skip_rest_of_patch = FALSE;

get_some_switches();

if (filec >= 2)
fatal1("You may not change to a different patch file.\n");
}

/* Process switches and filenames up to next '+' or end of list. */

void
get_some_switches()
{
Reg1 char *s;

rejname[0] = '\0';
Argc_last = Argc;
Argv_last = Argv;
if (!Argc)
return;
for (Argc--,Argv++; Argc; Argc--,Argv++) {
s = Argv[0];
if (strEQ(s, "+")) {
return; /* + will be skipped by for loop */
}
if (*s != '-' || !s[1]) {
if (filec == MAXFILEC)
fatal1("Too many file arguments.\n");
filearg[filec++] = savestr(s);
}
else {
switch (*++s) {
case 'b':
origext = savestr(Argv[1]);
Argc--,Argv++;
break;
case 'B':
origprae = savestr(Argv[1]);
Argc--,Argv++;
break;
case 'c':
diff_type = CONTEXT_DIFF;
break;
case 'd':
if (!*++s) {
Argc--,Argv++;
s = Argv[0];
}
if (chdir(s) < 0)
fatal2("Can't cd to %s.\n", s);
break;
case 'D':
do_defines = TRUE;
if (!*++s) {
Argc--,Argv++;
s = Argv[0];
}
if (!isalpha(*s))
fatal1("Argument to -D not an identifier.\n");
Sprintf(if_defined, "#ifdef %s\n", s);
Sprintf(not_defined, "#ifndef %s\n", s);
Sprintf(end_defined, "#endif /* %s */\n", s);
break;
case 'e':
diff_type = ED_DIFF;
break;
case 'f':
force = TRUE;
break;
case 'F':
if (*++s == '=')
s++;
maxfuzz = atoi(s);
break;
case '?':
case 'h':
usage();
my_exit(0);
break;
case 'l':
canonicalize = TRUE;
break;
case 'n':
diff_type = NORMAL_DIFF;
break;
case 'N':
noreverse = TRUE;
break;
case 'o':
outname = savestr(Argv[1]);
Argc--,Argv++;
break;
case 'p':
if (*++s == '=')
s++;
strippath = atoi(s);
break;
case 'r':
Strcpy(rejname, Argv[1]);
Argc--,Argv++;
break;
case 'R':
reverse = TRUE;
break;
case 's':
verbose = FALSE;
break;
case 'S':
skip_rest_of_patch = TRUE;
break;
case 'v':
version();
break;
#ifdef DEBUGGING
case 'x':
debug = atoi(s+1);
break;
#endif
default:
say2("Unrecognized switch: %s\n", Argv[0]);
usage();
my_exit(1);
}
}
}
}

/* Attempt to find the right place to apply this hunk of patch. */

LINENUM
locate_hunk(fuzz)
LINENUM fuzz;
{
Reg1 LINENUM first_guess = pch_first() + last_offset;
Reg2 LINENUM offset;
LINENUM pat_lines = pch_ptrn_lines();
Reg3 LINENUM max_pos_offset = input_lines - first_guess
- pat_lines + 1;
Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
+ pch_context();

if (!pat_lines) /* null range matches always */
return first_guess;
if (max_neg_offset >= first_guess) /* do not try lines < 0 */
max_neg_offset = first_guess - 1;
if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
return first_guess;
for (offset = 1; ; offset++) {
Reg5 bool check_after = (offset <= max_pos_offset);
Reg6 bool check_before = (offset <= max_neg_offset);

if (check_after && patch_match(first_guess, offset, fuzz)) {
#ifdef DEBUGGING
if (debug & 1)
say3("Offset changing from %ld to %ld\n", last_offset, offset);
#endif
last_offset = offset;
return first_guess+offset;
}
else if (check_before && patch_match(first_guess, -offset, fuzz)) {
#ifdef DEBUGGING
if (debug & 1)
say3("Offset changing from %ld to %ld\n", last_offset, -offset);
#endif
last_offset = -offset;
return first_guess-offset;
}
else if (!check_before && !check_after)
return Nulline;
}
}

/* We did not find the pattern, dump out the hunk so they can handle it. */

void
abort_hunk()
{
Reg1 LINENUM i;
Reg2 LINENUM pat_end = pch_end();
/* add in last_offset to guess the same as the previous successful hunk */
LINENUM oldfirst = pch_first() + last_offset;
LINENUM newfirst = pch_newfirst() + last_offset;
LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
LINENUM newlast = newfirst + pch_repl_lines() - 1;
char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");

fprintf(rejfp, "***************\n");
for (i=0; i<=pat_end; i++) {
switch (pch_char(i)) {
case '*':
if (oldlast < oldfirst)
fprintf(rejfp, "*** 0%s\n", stars);
else if (oldlast == oldfirst)
fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
else
fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
break;
case '=':
if (newlast < newfirst)
fprintf(rejfp, "--- 0%s\n", minuses);
else if (newlast == newfirst)
fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
else
fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
break;
case '\n':
fprintf(rejfp, "%s", pfetch(i));
break;
case ' ': case '-': case '+': case '!':
fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
break;
default:
say1("Fatal internal error in abort_hunk().\n");
abort();
}
}
}

/* We found where to apply it (we hope), so do it. */

void
apply_hunk(where)
LINENUM where;
{
Reg1 LINENUM old = 1;
Reg2 LINENUM lastline = pch_ptrn_lines();
Reg3 LINENUM new = lastline+1;
#define OUTSIDE 0
#define IN_IFNDEF 1
#define IN_IFDEF 2
#define IN_ELSE 3
Reg4 int def_state = OUTSIDE;
Reg5 bool R_do_defines = do_defines;
Reg6 LINENUM pat_end = pch_end();

where--;
while (pch_char(new) == '=' || pch_char(new) == '\n')
new++;

while (old <= lastline) {
if (pch_char(old) == '-') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == OUTSIDE) {
fputs(not_defined, ofp);
def_state = IN_IFNDEF;
}
else if (def_state == IN_IFDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
fputs(pfetch(old), ofp);
}
last_frozen_line++;
old++;
}
else if (new > pat_end)
break;
else if (pch_char(new) == '+') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == IN_IFNDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
else if (def_state == OUTSIDE) {
fputs(if_defined, ofp);
def_state = IN_IFDEF;
}
}
fputs(pfetch(new), ofp);
new++;
}
else {
if (pch_char(new) != pch_char(old)) {
say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
pch_hunk_beg() + old,
pch_hunk_beg() + new);
#ifdef DEBUGGING
say3("oldchar = '%c', newchar = '%c'\n",
pch_char(old), pch_char(new));
#endif
my_exit(1);
}
if (pch_char(new) == '!') {
copy_till(where + old - 1);
if (R_do_defines) {
fputs(not_defined, ofp);
def_state = IN_IFNDEF;
}
while (pch_char(old) == '!') {
if (R_do_defines) {
fputs(pfetch(old), ofp);
}
last_frozen_line++;
old++;
}
if (R_do_defines) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
while (pch_char(new) == '!') {
fputs(pfetch(new), ofp);
new++;
}
if (R_do_defines) {
fputs(end_defined, ofp);
def_state = OUTSIDE;
}
}
else {
assert(pch_char(new) == ' ');
old++;
new++;
}
}
}
if (new <= pat_end && pch_char(new) == '+') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == OUTSIDE) {
fputs(if_defined, ofp);
def_state = IN_IFDEF;
}
else if (def_state == IN_IFNDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
}
while (new <= pat_end && pch_char(new) == '+') {
fputs(pfetch(new), ofp);
new++;
}
}
if (R_do_defines && def_state != OUTSIDE) {
fputs(end_defined, ofp);
}
}

/* Open the new file. */

void
init_output(name)
char *name;
{
ofp = fopen(name, "w");
if (ofp == Nullfp)
fatal2("patch: can't create %s.\n", name);
}

/* Open a file to put hunks we can't locate. */

void
init_reject(name)
char *name;
{
rejfp = fopen(name, "w");
if (rejfp == Nullfp)
fatal2("patch: can't create %s.\n", name);
}

/* Copy input file to output, up to wherever hunk is to be applied. */

void
copy_till(lastline)
Reg1 LINENUM lastline;
{
Reg2 LINENUM R_last_frozen_line = last_frozen_line;

if (R_last_frozen_line > lastline)
say1("patch: misordered hunks! output will be garbled.\n");
while (R_last_frozen_line < lastline) {
dump_line(++R_last_frozen_line);
}
last_frozen_line = R_last_frozen_line;
}

/* Finish copying the input file to the output file. */

void
spew_output()
{
#ifdef DEBUGGING
if (debug & 256)
say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
#endif
if (input_lines)
copy_till(input_lines); /* dump remainder of file */
Fclose(ofp);
ofp = Nullfp;
}

/* Copy one line from input to output. */

void
dump_line(line)
LINENUM line;
{
Reg1 char *s;
Reg2 char R_newline = '\n';

/* Note: string is not null terminated. */
for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
}

/* Does the patch pattern match at line base+offset? */

bool
patch_match(base, offset, fuzz)
LINENUM base;
LINENUM offset;
LINENUM fuzz;
{
Reg1 LINENUM pline = 1 + fuzz;
Reg2 LINENUM iline;
Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;

for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
if (canonicalize) {
if (!similar(ifetch(iline, (offset >= 0)),
pfetch(pline),
pch_line_len(pline) ))
return FALSE;
}
else if (strnNE(ifetch(iline, (offset >= 0)),
pfetch(pline),
pch_line_len(pline) ))
return FALSE;
}
return TRUE;
}

/* Do two lines match with canonicalized white space? */

bool
similar(a,b,len)
Reg1 char *a;
Reg2 char *b;
Reg3 int len;
{
while (len) {
if (isspace(*b)) { /* whitespace (or \n) to match? */
if (!isspace(*a)) /* no corresponding whitespace? */
return FALSE;
while (len && isspace(*b) && *b != '\n')
b++,len--; /* skip pattern whitespace */
while (isspace(*a) && *a != '\n')
a++; /* skip target whitespace */
if (*a == '\n' || *b == '\n')
return (*a == *b); /* should end in sync */
}
else if (*a++ != *b++) /* match non-whitespace chars */
return FALSE;
else
len--; /* probably not necessary */
}
return TRUE; /* actually, this is not reached */
/* since there is always a \n */
}

/* Exit with cleanup. */

void
my_exit(status)
int status;
{
Unlink(TMPINNAME);
if (!toutkeep) {
Unlink(TMPOUTNAME);
}
if (!trejkeep) {
Unlink(TMPREJNAME);
}
Unlink(TMPPATNAME);
exit(status);
}


  3 Responses to “Category : C Source Code
Archive   : PATCH12.ZIP
Filename : PATCH.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/