#!/bin/sh
debug=0
testcase=0
if [ "$1" == "-d" ]
then
testcase=$2
shift 2
fi
if [ $# -gt 0 ]
then
mkdir -p $1
cd $1
fi
cat >arc.c <<':eof'
#line 20 "arc.sh"
/***********************************************************************\
*************************************************************************
** **
** ARC - ABSOLUTE REVISION CONTROL. **
** **
*************************************************************************
\***********************************************************************/
static int version[] = {2,0};
static int compatiable[] = {2,0};
/***********************************************************************\
* *
* Copyright (C) 2004 SM Ryan *
* *
* For non-profit uses only, provided this copyright is *
* preserved on all copies, this work may be freely copied, *
* modified, redistributed, compiled, and incorporated in *
* other works. This work is distributed with no warranty of *
* any kind; no author or distributor accepts any responsibility *
* for the consequences of using it, or for whether it serves *
* any particular purpose or works at all, unless he or she *
* says so in writing. *
* *
\***********************************************************************/
/*
THE CRUSADES WILL NOT BE TELEVISED
As rest of the world continues to extend the Unix SCCS to RCS to CVS
in effort to patch around a fundamental design flaw with ever more
elaborate code, I will instead pursue my own course, apparently on
my own.
*sigh*
The fundamental design flaw is the Unix heritage revision control
depends on relative line positions rather than absolute line
numbers.
First consider the cycle of how revision control:
(1) The initial version of the file is put under revision control.
(2) A version of the file without any or most revision control
information (because that usually interferes with other
activities such as compilation) is extracted.
(3) This source copy is editted to effect whatever enhancements or
corrections are needed.
(4) The modified source file is compared to the revision controlled
file and the steps to edit the controlled file to match the
source file are deduced.
(5) The controlled file is updated with the editting changes.
(6) Go back to (2) or (3) as needed.
Call the set of edits deduced in (4) and applied in (5) the
correction set or the modset (modification set).
Boo Unix
In the SCCS/RCS world, the modset is expressed in relative terms.
Such, go down to the fifth line of revision 2.3.4 and insert line
xyz. This makes every update in the same branch order dependent
on all previous versions even when the actual changes are completely
independent. One work around to have plethora of branches which
have to be subsequently merged. My own experiences with RCS
are that branch merges are only slightly less painful than a root
canal. Only slightly. And when modifications are actually order
dependent, it is necessary to ensure the previous modset has been
applied to the controlled file.
With all of this, the modset is a transitory thing, so dependent
on versions and relative positions that it cannot be easily teased
out of the revision cycle. In such systems steps (4) and (5) are
fused into a single update step that has to take place on demand
whenever the file is ready to check in, progress cannot return
to step (2) or (4) until this is done. This requires write access
to the controlled files in some fashion or another. This is
where most of the complexity of modern revision control comes
from, trying to manage many different people hammerring on the
same files at the same time.
Yea CDC
Control Data had a different approach. Lines in controlled files
were given unique, absolute, and invariant names. A line could
be deleted or active, but it retain its identity. Editting
directives in modsets were always to this unique identifiers.
Whether another modset activated or deactivated a line referenced
in the modset, the referenced line retained its identity and
the modset continued to refer to the same location in the
controlled file.
This means steps (5) and (6) can be separated. It is no longer
necessary to provide write access to the primal files to anybody
except for one integrator. With this all the management functions
for locking or unlocking or atomic commits or branching or any
of the results *disappear*. Everybody who is permitted to read
the source files is permitted to read the controlled files. One
small select group is granted write permission. The integration
group can choose the time and manner of integration; if it is
necessary to hide controlled files for a time to do this, it
can be scheduled in advance.
(This program does not edit arc-files in place, but rather writes
a new copy. It is possible to keep all arc-files in a directory
and write the updated arc-files to a new, hidden directory. Once
all editting is completed, the directory names are switched around,
leaving the time the arc-files are unavailable down to a few
milliseconds.)
Management problems do remain for the integrator, how to collect
modsets and select which to apply, how to deal with overlaps and
conflicts within modsets, how to order modsets which are order
dependent. However these problems are restricted to the integrator
and can be solved with less elaborate tools.
(This program is does not attempt to solve these problems in
order to keep the code simple. As for collecting modsets, mailbots
and write-only dropbox folders (where provided) can provide that.
This program is also pretty liberal about what it permits to be
editted, ignoring overlaps and conflicts. The 'arc check' operation
can be used before 'arc edit'. The check details what the edit
will do and to whom it will do it. The resulting modset is intended
to be easily machine analyzed to find issues and report or solve
them. The 'refdeleted' example shows some of the integration
tests that can be implemented with arc check.)
(At some point I will probably have some integration automation
available based on this program but not within this program.)
Directory Structure
One of the changes from RCS to CVS is that CVS manages not only
file contents but directory contents as well. Like RCS, this program
only concerns itself with file contents. Actually with file contents
only. Most of the files are passed in through stdin and stdout.
The only time a file is named in a command is when there are two
inputs; handling more than one piped input would require tricky
scripting with file designators.
I will probably provide some checkout automation to help with
checking out sources and providing a local directory structure
to work within, eventually.
What's the Scoop
Step (4) is creating modset with all of the editting directives
to be applied in step (5). The good old CDC way was to manually
type out or keypunch the modset based on listings of the files
with their line identifiers. Then someone came up a with program
called SCOOP which would compare an extracted file to the deck
and automatically come up with the modset. This is similar to
what Unix does with diff. The difference is that SCOOP turned the
relative file position into absolute file positions, while the
Unix world left them as a relative file positions.
This program reimplements the scoop function using the diff
program. There is still a versionning problem, but it is less
intense than the one faced by RCS, and it can usually be solved
easily. The problem is the source file is compared to a version
of the arc-file, but if it is compared to the wrong version
the created modset will make unintended changes. For example
if it is extracted from an earlier version and naively compared
to a later version, it will undo all the changes between the
versions. Two techniques can resolve this is most cases.
(1) When getting the file, also get the version. Present this
version back to scoop. Scoop will ignore changes subsequent
to the version modification name when comparing the
arc-file and modified source file.
(2) Copy the arc-file to a private, invariant copy, and scoop
with this private copy instead of the public copy. Because
the modset uses absolute line identifiers, if the arc-files
diverge, the modset will refer to the same position in any
copy of the arc-file.
Note that a modset derived from one version can introduce unexpected
overlaps and conflicts with a modset derived from a different
version. This program provides information for integration tools
to identify these.
*/
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
/***********************************************************************\
* *
* String and Storage Utilities. *
* *
\***********************************************************************/
#define heap(T) ((T*)(malloc(sizeof(T))))
#define nheap(n,T) ((T*)(malloc((n)*sizeof(T))))
#define reheap(n,T,p) ((T*)(realloc((p),(n)*sizeof(T))))
#define streq(a,b) (strcmp(a,b)==0)
typedef char *chars;
static chars duplicate(chars s) {
return strcpy(malloc(strlen(s)+1),s);
}
typedef unsigned char bool; enum {false=0,true=1};
/***********************************************************************\
* *
* Read and Write Lines with Files. *
* *
\***********************************************************************/
/*
Nothing special. As long as the lines fit in memory, their size is
no further concern. NULLs (00) in the input will be inserted into
the string unchanged and end up truncating the returned string.
While it's possible to escape nulls or otherwise cope with binary
data, it's also possible to use uuencode/uudecode (or other tools)
to convert binaries to text to binaries. See also the binarc example.
The <stdio> package is responsible for translating end of lines to
and from '\n'. What <stdio> cannot deal with, arc cannot deal with.
Again arc can be made more adaptable, but to keep arc simple, it is
restricted to what <stdio> considerred text files.
*/
static chars readline(FILE *file) {
int m=0,n=0; chars s=0;
for (;;) {
int c = fgetc(file);
if (c=='\n' || c==EOF && n>0) {
s = reheap(n+1,char,s);
s[n] = 0;
return s;
}else if (c==EOF) {
return 0;
}else {
if (n+2>m) {m = 2*(n+2); s = reheap(m,char,s);}
s[n++] = c; s[n] = 0;
}
}
}
static void writeline(FILE *file,chars line) {
if (file) {
fputs(line,file); fputc('\n',file);
}
}
/***********************************************************************\
* *
* Error Reporting. *
* *
\***********************************************************************/
/*
Normally an error results in immediate exit from arc and warnings
are ignored.
arc check sets the comments file to stdout. If checking is taking
place, all errors are reported and recoverred from as well as
possible.
*/
static FILE *comments = 0;
static void errorf(char *format,...) {
va_list L;
if (comments) fputs("*arc check E ",comments);
va_start(L,format);
vfprintf(comments?comments:stderr,format,L);
va_end(L);
fputc('\n',comments?comments:stderr);
if (!comments) exit(1);
}
static void warningf(char *format,...) {
if (comments) {
va_list L;
fputs("*arc check W ",comments);
va_start(L,format);
vfprintf(comments,format,L);
va_end(L);
fputc('\n',comments);
}
}
/***********************************************************************\
* *
* ARC Internal Representation. *
* *
\***********************************************************************/
/*
This is the internal representation of the arc-file. Every line in
the file except the initial #arc are represented by one Arc struct;
the first letter of the line is the state field; M lines become
u.mod fields; A, D, R, Y, Q history lines become u.history fields;
and a and d text lines become u.line fields.
All of the Arc structs are linked into one symetric ring linked
by pre and post fields. An additional struct with state T is the
top entry of the ring, a distinguished point between the first of
modname catalog and the last text line. The top is always filled
out as if a modname M struct; it is used to stand for a missing or
unknown modname for error recovery.
Like the arc-file the arc ring will have the T top entry,
followed by the M entries in the order they were editted in,
and then the a and d lines; each line is preceded by one or more
A, D, Q, R, or Y history entries. The first M entry is also the
content name added when arc new create the arc-file.
Lines are also linked in a smaller symetric rings with mlink, mpre,
and mpost. These are all lines with the same modname as the linename.
This ring should be constructed with LINESEQs in ascending order.
The editting routines scan these small rings and update the mlink
along the way. If edit directives are in ascending line order
(which is what scoop does), this means the edit session should
make only one loop around any smaller ring.
*/
typedef struct Arc Arc;
struct Arc {
Arc *top,*pre,*post;
char state;
union {
struct {
chars name; int index;
Arc *mlink; int max;
union {
struct {
int nh; Arc **hash;
int nx; Arc **index;
} top; // state T
Arc **line; // state M
} u;
} mod; // state M or T
Arc *history; // state A or D or R or Y or Q
struct {
Arc *mod,*mpre,*mpost;
int seq;
chars text;
} line; // state a or d
} u;
};
/*
C snobs will have a fit because the -> is placed in a #define.
Tough luck.
*/
#define TOP ->top
#define PRE ->pre
#define POST ->post
#define STATE ->state
#define MODNAMES ->top->post
#define NH ->top->u.mod.u.top.nh
#define HASH ->top->u.mod.u.top.hash
#define INDEX ->top->u.mod.u.top.index
#define NX ->top->u.mod.u.top.nx
#define MODLINE ->u.mod.u.line
#define MODNAME ->u.mod.name
#define MODINDEX ->u.mod.index
#define MODMLINK ->u.mod.mlink
#define MODMAXSEQ ->u.mod.max
#define HISTORY ->u.history
#define HISTORYNAME ->u.history->u.mod.name
#define HISTORYINDEX ->u.history->u.mod.index
#define LINEMOD ->u.line.mod
#define LINENAME ->u.line.mod->u.mod.name
#define LINEINDEX ->u.line.mod->u.mod.index
#define LINEMAXSEQ ->u.line.mod->u.mod.max
#define LINEMPRE ->u.line.mpre
#define LINEMPOST ->u.line.mpost
#define LINESEQ ->u.line.seq
#define LINE ->u.line.text
static int enhash(Arc *file,chars name) {
unsigned h,h0,i;
for (i=h=0; name[i]; i++) h = 131*h + name[i];
h0 = h = h%file NH;
while (file HASH[h] && !streq(name,file HASH[h] MODNAME)) {
h += 3; if (h>=file NH) h -= file NH;
if (h==h0) return -1;
}
return h;
}
static void rehash(Arc *file) {
int i,onh = file NH; Arc **ohash = file HASH;
file NH *= 5; file HASH = nheap(file NH,Arc*); memset(file HASH,0,file NH*sizeof(Arc*));
for (i=0; i<onh; i++) {
if (ohash[i]) {
int h = enhash(file,ohash[i] MODNAME);
if (h<0) {fprintf(stderr,"hash ofl on rehash!! this is impossible!!\n"); exit(1);}
file HASH[i] = ohash[i];
}
}
free(ohash);
}
static Arc *findMod(Arc *file,chars name) {
int h = enhash(file,name);
return h>=0 ? file HASH[h] : 0;
}
static Arc *findIndex(Arc *file,int index) {
if (!file INDEX) {
int i;
for (file=file MODNAMES,file NX=0; file STATE=='M'; file=file POST) file NX += 1;
file INDEX = nheap(file NX+1,Arc*); file INDEX[0] = file TOP;
for (file=file MODNAMES,i=1; file STATE=='M'; file=file POST,i++) file INDEX[i] = file;
}
if (index>file NX) {
errorf("modification-name index out of range: %d",index); return file TOP;
}
return file INDEX[index];
}
static Arc *newTop(void) {
Arc *e = heap(Arc); memset(e,0,sizeof(Arc)); e STATE = 'T';
e TOP = e PRE = e POST = e;
e MODNAME = duplicate("<<error>>");
e NH = 17; e HASH = nheap(17,Arc*); memset(e HASH,0,17*sizeof(Arc*));
return e;
}
static Arc *newMod(Arc *file,chars name) {
int h; Arc *e = heap(Arc);
memset(e,0,sizeof(Arc)); e STATE = 'M'; e MODNAME = duplicate(name);
if (file STATE=='M' || file POST STATE!='M') {
file = file POST;
}else {
file = file MODNAMES;
while (file STATE=='M') {
file = file POST;
}
}
e MODINDEX = file PRE STATE=='M' ? file PRE MODINDEX+1 : 1;
e TOP = file TOP;
file PRE POST = e;
e PRE = file PRE;
e POST = file; file PRE = e;
h = enhash(file,name);
if (h<0) {
rehash(file); h = enhash(file,name);
if (h<0) {fprintf(stderr,"rehash didnt make space!! this is impossible!!\n"); exit(1);}
}
if (file HASH[h]) errorf("duplicate modification-name: %s",name);
else file HASH[h] = e;
free(file INDEX); file INDEX = 0;
return e;
}
static Arc *newHistory(Arc *file,char state,int index) {
Arc *e = heap(Arc); memset(e,0,sizeof(Arc)); e STATE = state; e HISTORY = findIndex(file,index);
e TOP = file TOP;
file POST PRE = e; e POST = file POST;
file POST = e; e PRE = file;
return e;
}
static Arc *newLine(Arc *file,char state,int name,int seq,chars line) {
Arc *e = heap(Arc),*m = findIndex(file,name); memset(e,0,sizeof(Arc)); e STATE = state;
e LINEMOD = m; e LINESEQ = seq; e LINE = duplicate(line);
if (m) {
if (m MODMLINK) {
m MODMLINK LINEMPOST LINEMPRE = e;
e LINEMPOST = m MODMLINK LINEMPOST;
m MODMLINK LINEMPOST = e; e LINEMPRE = m MODMLINK;
m MODMLINK = e;
}else {
m MODMLINK = e LINEMPRE = e LINEMPOST = e;
}
if (seq>m MODMAXSEQ) m MODMAXSEQ = seq;
}
e TOP = file TOP;
file POST PRE = e; e POST = file POST;
file POST = e; e PRE = file;
return e;
}
static void freeArc(Arc *file) {
file PRE POST = 0;
while (file) {
Arc *post = file POST;
switch (file STATE) {
case 'M': case 'T': free(file MODNAME); break;
case 'a': case 'd': free(file LINE); break;
}
free(file); file = post;
}
}
/***********************************************************************\
* *
* Read and Write an ARC. *
* *
\***********************************************************************/
static Arc *readArcFile(FILE *file) {
Arc *e = newTop(); int phase = '0';
chars line;
while ((line=readline(file))) {
switch (*line) {
case '#': {
chars p; int major,minor;
if (phase!='0')
errorf("arc-file has been mangled: #arc seen in phase %c",phase);
phase = 'T';
for (p=line; !isdigit(*p); ) p++;
major = strtol(p,&p,0);
minor = strtol(p+1,0,0);
if (major>version[0])
errorf("arc %d.%d cannot read later version %d.%d",
version[0],version[1],
major,minor);
else if (major<compatiable[0])
errorf("arc %d.%d cannot read earlier version %d.%d",
version[0],version[1],
major,minor);
} break;
case 'M':
if (phase!='T' && phase!='M')
errorf("arc-file has been mangled: M-line seen in phase %c",phase);
phase = 'M';
e = newMod(e,line+1); break;
case 'A': case 'D': case 'R': case 'Y': case 'Q':
if (phase!='M' && phase!='L' && phase!='H')
errorf("arc-file has been mangled: %c-line seen in phase %c",*line,phase);
phase = 'H';
e = newHistory(e,*line,strtol(line+1,0,0));
break;
case 'a': case 'd': {
chars p; int name,seq;
if (phase!='H')
errorf("arc-file has been mangled: %c-line seen in phase %c",*line,phase);
phase = 'L';
name = strtol(line+1,&p,0);
seq = strtol(p+1,&p,0);
e = newLine(e,*line,name,seq,p+1);
} break;
default: errorf("invalid line state: %s",line);
}
free(line);
}
if (phase!='L')
errorf("arc-file has been mangled: eof in phase %c",*line,phase);
return e TOP;
}
static void writeArcFile(FILE *file,Arc *e) {
e = e MODNAMES;
fprintf(file,"#arc %d.%d\n",version[0],version[1]);
while (e STATE!='T') {
switch (e STATE) {
case 'M':
fprintf(file,"M%s\n",e MODNAME);
break;
case 'A': case 'D': case 'R': case 'Y': case 'Q':
fprintf(file,"%c%d\n",e STATE,e HISTORYINDEX);
break;
case 'a': case 'd':
fprintf(file,"%c%d:%d:%s\n",
e STATE,e LINEINDEX,
e LINESEQ,e LINE);
break;
}
e = e POST;
}
}
static void createArcFile(FILE *arc,FILE *compile,chars name) {
chars line; int seq; bool any = false;
if (strchr(name,'\n')) {errorf("modifcation-name cannot have a new-line: %s",name);}
fprintf(arc,"#arc %d.%d\n",version[0],version[1]);
fprintf(arc,"M%s\n",name);
for (seq=1; (line=readline(compile)); seq++) {
any = true;
fprintf(arc,"A1\na1:%d:%s\n",seq,line);
free(line);
}
if (!any) fprintf(arc,"A1\na1:1:\n");
}
/***********************************************************************\
* *
* Extract a Source File from an ARC. *
* *
\***********************************************************************/
static Arc **writeSourceFile(FILE *file,Arc *e,bool lineids) {
int n; Arc **id= 0; bool any = false;
if (lineids) {
for (n=0,e=e MODNAMES; e STATE!='T'; e=e POST) n += e STATE=='a';
if (n==0) n = 1;
id = nheap(n,Arc*); n = 0;
}
e = e MODNAMES;
while (e STATE!='T') {
if (e STATE=='a') {
writeline(file,e LINE);
any = true;
if (id) id[n++] = e;
}
e = e POST;
}
if (id && !any) {
writeline(file,"");
id[0] = e TOP PRE;
}
return id;
}
static Arc **writeVersionnedSourceFile(FILE *file,Arc *e,bool lineids,chars versionname) {
int n; Arc **id= 0,*version = findMod(e,versionname); char state = 'd'; bool any = false;
if (!version) {
errorf("unknown version: %s",versionname);
return writeSourceFile(file,e,lineids);
}
if (lineids) {
for (n=0,e=e MODNAMES; e STATE!='T'; e=e POST) n += e STATE=='a';
if (n==0) n = 1;
id = nheap(n,Arc*); n = 0;
}
e = e MODNAMES;
while (e STATE!='T') {
switch (e STATE) {
case 'A': case 'R': case 'Q':
if (e HISTORYINDEX<=version MODINDEX) state = 'a';
break;
case 'D': case 'Y':
if (e HISTORYINDEX<=version MODINDEX) state = 'd';
break;
case 'a': case 'd':
if (state=='a') {
writeline(file,e LINE);
any = true;
if (id) id[n++] = e;
}
state = 'd';
break;
}
e = e POST;
}
if (id && !any) {
writeline(file,"");
id[0] = e TOP PRE;
}
return id;
}
static void getSourceFile(FILE *compile,FILE *arc) {
chars line;
while ((line=readline(arc))) {
if (*line=='a') {
chars p; strtol(line+1,&p,0); strtol(p+1,&p,0);
writeline(compile,p+1);
}
free(line);
}
}
/***********************************************************************\
* *
* Compare Source to the ARC Version. *
* *
\***********************************************************************/
static void scoop(FILE *edit,Arc **id,FILE *pdiff) {
chars line;
while ((line=readline(pdiff))) {
switch (*line) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
chars p;
int from = strtol(line,&p,0);
int to = *p==',' ? strtol(p+1,&p,0) : 0;
switch (*p) {
case 'c': case 'd':
fprintf(edit,"D%d:%s\n",
id[from-1] LINESEQ,
id[from-1] LINENAME);
if (to>0) {
fprintf(edit,",%d:%s\n",
id[to-1] LINESEQ,
id[to-1] LINENAME);
}
break;
case 'a':
if (from==0)
fprintf(edit,"B%d:%s\n",
id[from] LINESEQ,
id[from] LINENAME);
else
fprintf(edit,"I%d:%s\n",
id[from-1] LINESEQ,
id[from-1] LINENAME);
}
} break;
case '>':
fprintf(edit,"/%s\n",line+2);
break;
}
free(line);
}
}
/*
Is this diff command safe for all unices?
Note this uses the fact that stdin is inheritted by child processes.
The modified source file is presented on stdin to arc but not read
by this process. It is read by the child diff process as the second file
'-', which inherits the same stdin.
*/
static void scoopArcFile(FILE *edit,FILE *arc,chars modname,chars version) {
Arc *e = readArcFile(arc);
chars temporary = duplicate(tempnam(".","model"));
FILE *oldversion = fopen(temporary,"w");
Arc **id = version
? writeVersionnedSourceFile(oldversion,e,true,version)
: writeSourceFile(oldversion,e,true);
chars fdiff = "diff -d '%s' -",fremove = "rm -f '%s'",command;
FILE *pdiff;
fclose(oldversion);
fprintf(edit,"P%s\nM%s\n",e MODNAMES MODNAME,modname);
command = nheap(strlen(fdiff)+strlen(temporary)+1,char);
sprintf(command,fdiff,temporary);
pdiff = popen(command,"r");
free(command);
scoop(edit,id,pdiff);
pclose(pdiff);
free(id);
command = nheap(strlen(fremove)+strlen(temporary)+1,char);
sprintf(command,fremove,temporary);
system(command);
free(command);
free(temporary);
freeArc(e);
}
/***********************************************************************\
* *
* Edit the ARC. *
* *
\***********************************************************************/
static void changeLine(Arc *line,char op,char newstate,int index,char edit) {
if (!line) {
;
}else if (op=='!' || line->state!=newstate) {
if (comments)
fprintf(comments,"*arc check %c %c %d:%s\n",
newstate,line STATE,line LINESEQ,line LINENAME);
line->state = newstate;
newHistory(line PRE,edit,index);
}else if (op='W') {
warningf("line already %s: %d:%s",
newstate=='a'?"active":"deleted",line LINESEQ,line LINENAME);
}
}
static Arc *findSeq(Arc *file,chars name,int seq) {
Arc *t,*f,*e;
if (!(t=findMod(file,name))) {
errorf("unknown modification: %s",name);
return 0;
}
if (!t MODLINE) {
t MODLINE = nheap(t MODMAXSEQ+1,Arc*);
memset(t MODLINE,0,(t MODMAXSEQ+1)*sizeof(Arc*));
if (!(f=t MODMLINK)) {
errorf("modification does not have any lines: %d:%s",seq,t MODNAME);
return 0;
}
for (e=f;;e=e LINEMPOST) {
t MODLINE[e LINESEQ] = e;
if (e LINEMPOST==f) break;
}
}
if (seq<1 || seq>t MODMAXSEQ || !t MODLINE[seq]) {
errorf("modification does not have this line: %d:%s",seq,t MODNAME);
return 0;
}
return t MODLINE[seq];
}
static void sequenceInsertions(Arc *e) {
e = e MODNAMES;
while (e STATE!='T') {
switch (e STATE) {
case 'a': case 'd':
if (e LINESEQ==0) {
e LINEMAXSEQ += 1;
e LINESEQ = e LINEMAXSEQ;
}
}
e = e POST;
}
}
static Arc *editArc(Arc *file,FILE *edit) {
chars line = 0;
chars mod = 0; int index = 0;
bool thisdeck = true,unsequencedinserts = false;
Arc *e;
for (;;) {
Arc *BEGIN = 0,*END = 0; char op;
if (!line) line = readline(edit);
if (!line) break;
op = *line;
if (!thisdeck && op!='P') {
writeline(comments,line); free(line); line = 0; continue;
}
switch (op) {
case 'R': case 'I': case 'B': case 'D': case 'Y':
if (!mod) {
errorf("modset had no Mmodification-name: %s",line);
index = 0;
}else if (!index) {
Arc *m = findMod(file,mod);
if (m) {
errorf("duplicate modification-name: %s",mod); m = file TOP;
}else {
m = newMod(file,mod);
}
index = m MODINDEX;
}
}
switch (op) {
case 'R': case 'I': case 'B': case 'D': {
chars p; int begin = strtol(line+1,&p,0);
BEGIN = findSeq(file,p+1,begin);
writeline(comments,line); free(line); line = 0;
}
}
switch (op) {
case 'D':
if ((line=readline(edit)) && *line==',') {
chars p; int end = strtol(line+1,&p,0);
END = findSeq(file,p+1,end);
writeline(comments,line); free(line); line = 0;
}else {
END = BEGIN;
}
}
if (comments && BEGIN)
fprintf(comments,"*arc check %c %c %d:%s\n",op,BEGIN STATE,BEGIN LINESEQ,BEGIN LINENAME);
if (comments && END)
fprintf(comments,"*arc check 1 %c %d:%s\n",END STATE,END LINESEQ,END LINENAME);
switch (op) {
case 'P':
thisdeck = streq(line+1,file MODNAMES MODNAME);
index = 0;
if (unsequencedinserts) sequenceInsertions(file);
unsequencedinserts = false;
goto eatme;
case 'M':
free(mod); mod = duplicate(line+1); index = 0;
if (unsequencedinserts) sequenceInsertions(file);
unsequencedinserts = false;
goto eatme;
case 'R':
changeLine(BEGIN,'W','a',index,'R');
break;
case 'B':
if (BEGIN)
do {
BEGIN = BEGIN PRE;
} while (BEGIN STATE=='A' || BEGIN STATE=='D');
goto insert;
case 'D':
if (BEGIN && END) {
for (e=BEGIN; e!=END; e=e POST)
if (e STATE=='T') {
warningf("empty deletion range, end before beginning: %d:%s, %d:%s",
BEGIN LINESEQ,BEGIN LINENAME,
END LINESEQ,END LINENAME);
goto insert;
}
for (e=BEGIN; ; e=e POST)
if (e STATE=='a' || e STATE=='d') {
changeLine(e,'!','d',index,'D');
if (e==END) break;
}
BEGIN = END;
}
case 'I': insert:
for (;;) {
if (!line) line = readline(edit);
if (!line) break;
if (*line!='*' && *line!='#') {
if (*line!='/') break;
if (BEGIN) {
BEGIN = newLine(newHistory(BEGIN,'A',index),
'a',index,0,duplicate(line+1));
unsequencedinserts = true;
}
}
if (strncmp(line,"*arc check ",11)!=0) writeline(comments,line);
free(line); line = 0;
}
break;
case 'Y': {
Arc *yank = findMod(file,line+1); char state = 'd';
writeline(comments,line);
if (yank) {
for (file=file MODNAMES; file STATE!='T'; file=file POST) {
switch (file STATE) {
case 'A': case 'R': case 'Q':
if (file HISTORYINDEX<=yank MODINDEX) {
state = 'a';
}
break;
case 'D': case 'Y':
if (file HISTORYINDEX<=yank MODINDEX) {
state = 'd';
}
break;
case 'a': case 'd':
changeLine(file,0,state,index,state=='a'?'Q':'Y');
state = 'd';
}
}
}else {
errorf("unknown yanked modification-name: %s",line+1);
}
} goto drinkme;
case '#': case '*':
if (strncmp(line,"*arc check ",11)!=0) writeline(comments,line);
goto drinkme;
default:
errorf("invalid edit directive: %s",line);
eatme:
writeline(comments,line);
drinkme:
free(line); line = 0; break;
}
}
if (unsequencedinserts) sequenceInsertions(file);
return file TOP;
}
static void editArcFile(FILE *newarc,FILE *arc,FILE *edit) {
Arc *e = readArcFile(arc);
e = editArc(e,edit);
if (newarc) writeArcFile(newarc,e);
freeArc(e);
}
/***********************************************************************\
* *
* ARC Version. *
* *
\***********************************************************************/
static void getLastModname(FILE *output,FILE *arc) {
chars line,mod=0;
while ((line=readline(arc))) {
if (*line=='M') {
free(mod); mod = line;;
}else if (*line=='#') {
free(line);
}else {
free(line); break;
}
}
writeline(output,mod+1);
free(mod);
}
/***********************************************************************\
* *
* List the ARC. *
* *
\***********************************************************************/
static void writeEscaped(FILE *html,chars string) {
bool first = true;
while (*string) switch (*string) {
case '&': fputs("&",html); string++; first = false; break;
case '<': fputs("<",html); string++; first = false; break;
case '>': fputs(">",html); string++; first = false; break;
case '\t': fputs(" ",html); string++; break;
case ' ': if (!first) goto other; fputs(" ",html); string++; break;
other: default: first = *string==' ' || *string=='\t'; fputc(*string++,html); break;
}
}
static void listArcFile(FILE *html,FILE *arc) {
chars color[] = {"#E0E0E0","#FFFFFF"}; int colordex = 0;
chars line; Arc *e = readArcFile(arc) MODNAMES;
fprintf(html,"<html><head><title>%s</title></head><body>\n",e MODNAME);
fprintf(html,"<h3>Modification Names</h3>\n");
while (e STATE=='M') {
fprintf(html,"%s<br>\n",e MODNAME);
e = e POST;
}
fprintf(html,"<h3>Contents</h3><table width='100%%'>\n");
while (e STATE!='T') {
while (e STATE=='A' || e STATE=='D' || e STATE=='R' || e STATE=='Y' || e STATE=='Q')
e = e POST;
if (e STATE=='a' || e STATE=='d') {
chars sep = "";
fprintf(html,"<tr><td width=10 bgcolor='%s' align=center valign=top><b>%c</b></td>\n",
color[colordex],
e STATE);
fprintf(html,"<td width='60%%' bgcolor='%s' align=left valign=top><code>%s",
color[colordex],
e STATE=='d' ? "<i>" : "");
writeEscaped(html,e LINE);
fprintf(html,"%s</code></td>\n",
e STATE=='d' ? "</i>" : "");
fprintf(html,"<td width='15%%' bgcolor='%s' align=left valign=top>%d:",
color[colordex],
e LINESEQ);
writeEscaped(html,e LINENAME);
fprintf(html,"</td>\n");
fprintf(html,"<td width='25%%' bgcolor='%s' align=left valign=top>",
color[colordex]);
do {
e = e PRE;
} while (e STATE=='A' || e STATE=='D' || e STATE=='R' || e STATE=='Y' || e STATE=='Q');
e = e POST;
while (e STATE=='A' || e STATE=='D' || e STATE=='R' || e STATE=='Y' || e STATE=='Q') {
switch (e STATE) {
case 'A':
fprintf(html,"%s%s <b>add</b>",sep,e HISTORYNAME);
break;
case 'D':
fprintf(html,"%s<i>%s </i><b>del</b>",sep,e HISTORYNAME);
break;
case 'R':
fprintf(html,"%s%s <b>res</b>",sep,e HISTORYNAME);
break;
case 'Q':
fprintf(html,"%s%s <b>yrs</b>",sep,e HISTORYNAME);
break;
case 'Y':
fprintf(html,"%s<i>%s</i> <b>yan</b>",sep,e HISTORYNAME);
break;
}
sep = ";\n";
e = e POST;
}
fprintf(html,".</td></tr>\n");
e = e POST; colordex = !colordex;
}
}
fprintf(html,"</table></body></html>\n");
freeArc(e);
}
static void listActiveArcFile(FILE *html,FILE *arc) {
chars color[] = {"#E0E0E0","#FFFFFF"}; int colordex = 0;
chars line; Arc *e = readArcFile(arc) MODNAMES;
fprintf(html,"<html><head><title>%s</title></head><body>\n",e MODNAME);
fprintf(html,"<table width='100%%'>\n");
while (e STATE!='T') {
if (e STATE=='a') {
fprintf(html,"<tr><td width='80%%' bgcolor='%s' align=left valign=top><code>",
color[colordex]);
writeEscaped(html,e LINE);
fprintf(html,"</code></td>\n");
fprintf(html,"<td width='20%%' bgcolor='%s' align=left valign=top>%d:",
color[colordex],
e LINESEQ);
writeEscaped(html,e LINENAME);
fprintf(html,"</td></tr>\n");
colordex = !colordex;
}
e = e POST;
}
fprintf(html,"</table></body></html>\n");
freeArc(e);
}
/***********************************************************************\
* *
* MAIN. *
* *
\***********************************************************************/
int main(int N,chars *P) {
int ec = 0;
if (N==1) {
usage: fprintf(stderr,"arc %d.%d usage:\n"
" %s new name <compile >arc\n"
" %s get <arc >compile\n"
" %s scoop name arc [version] <compile >edit\n"
" %s edit arc <edit\n"
" %s check <edit >checked-edit\n"
" %s list <arc >html\n"
" %s active <arc >html\n"
" %s version <arc >output\n",
version[0],version[1],*P,*P,*P,*P,*P,*P,*P,*P);
return ec;
}
switch (P[1][0]) {
case 'n':
if (N!=3) {
fprintf(stderr,"arc new: expected one argument: %d\n",N-2); ec = 1; goto usage;
}
createArcFile(stdout,stdin,P[2]);
return 0;
case 'g':
if (N!=2) {
fprintf(stderr,"arc get: expected no arguments: %d\n",N-2); ec = 1; goto usage;
}
getSourceFile(stdout,stdin);
return 0;
case 's': {
FILE *arc;
if (N<4 || N>5) {
fprintf(stderr,"arc scoop: expected two or three arguments: %d\n",N-2);
ec = 1; goto usage;
}
if (!(arc=fopen(P[3],"r"))) {perror(P[3]); return 1;}
scoopArcFile(stdout,arc,P[2],N==4?0:P[4]);
} return 0;
case 'e': {
FILE *arc;
if (N!=3) {
fprintf(stderr,"arc edit: expected one argument: %d\n",N-2); ec = 1; goto usage;
}
if (!(arc=fopen(P[2],"r"))) {perror(P[2]); return 1;}
editArcFile(stdout,arc,stdin);
return 0;
}
case 'c': {
FILE *arc;
if (N!=3) {
fprintf(stderr,"arc check: expected one argument: %d\n",N-2); ec = 1; goto usage;
}
comments = stdout;
arc = fopen(P[2],"r");
if (arc) {
editArcFile(0,arc,stdin);
}else {
chars line;
printf("*arc check E cannot open arc: %s: %s\n",strerror(errno),P[2]);
while ((line==readline(stdin))) {writeline(stdout,line); free(line);}
}
return 0;
}
case 'l':
if (N!=2) {
fprintf(stderr,"arc list: expected no arguments: %d\n",N-2); ec = 1; goto usage;
}
listArcFile(stdout,stdin);
return 0;
case 'a':
if (N!=2) {
fprintf(stderr,"arc active: expected no arguments: %d\n",N-2); ec = 1; goto usage;
}
listActiveArcFile(stdout,stdin);
return 0;
case 'v':
if (N!=2) {
fprintf(stderr,"arc version: expected no arguments: %d\n",N-2); ec = 1; goto usage;
}
getLastModname(stdout,stdin);
return 0;
default:
fprintf(stderr,"arc: unrecognised operator: %s\n",P[1]); ec = 1; goto usage;
}
}
:eof
crap=`uname`
if [ $crap == IRIX64 ]
then
cc=gcc
else
cc=cc
fi
if [ $testcase -gt 0 ]
then
$cc -g -o arc arc.c
else
$cc -O -o arc arc.c
fi
mkdir arc-examples
cat >arc-examples/update <<':eos'
#!/bin/sh
modname=$1
arc=$2
arc scoop $modname $arc | arc edit $arc >$arc.new
mv $arc.new $arc
exit 0
:eos
cat >arc-examples/getp <<':eos'
#!/bin/sh
arc=$1
script=$arc.scoop
arc get <$arc
echo '#!/bin/sh' > $script
echo arc scoop '$1' $arc `arc version <$arc` >> $script
echo 'exit 0' >> $script
chmod u+rx $script
exit 0
:eos
cat >arc-examples/yank <<':eos'
#!/bin/sh
modname=$1
arc=$2
arc edit $arc >$arc.new <<:eof
M$modname-YANK
Y$modname
:eof
mv $arc.new $arc
exit 0
:eos
cat >arc-examples/refdeleted <<':eos'
#!/bin/sh
arc=$1
arc check $arc | awk '
BEGIN {show = 0; modset = ""; deck = ""; OFS = "; "}
/^M/ {show = 0; modset = substr($0,2);}
/^P/ {show = 0; deck = substr($0,2);}
/^[RY]/ {show = 0;}
/^[BID]/ {show = 1; directive = $0; continuation = $0;}
/^[,]/ {show = 1; continuation = $0;}
/^*arc check [BIDR] d/ {if (show) print deck,modset,directive;}
/^*arc check 1 d/ {if (show) print deck,modset,continuation;}
'
exit 0
:eos
cat >arc-examples/create <<':eos'
#!/bin/sh
source=$1
arc=$source.arc
arc new $source <$source >$arc
arc edit $arc <<:eof >$arc.1
Mhistory
B1:$source
/#if 0
/# YYYY-MM-DD Created $arc.
/#endif
:eof
mv $arc.1 $arc
exit 0
:eos
cat >arc-examples/workarea <<':eos'
#!/bin/sh
modname=$1
arc=$2
source=`basename $arc .arc`
mkdir -p $modname
cp $arc $modname
arc get <$arc >$modname/$source
cat <<:eof >$modname/scoop
#!/bin/sh
arc scoop $modname $arc `arc version <$arc` <$source >$source.mod
arc scoop $modname-YYYY-MM-DD-HH.MM.SS $source.arc <$source \
| arc edit $source.arc >$source.arc.new
mv $source.arc.new $source.arc
exit 0
:eof
cat <<:eof >$modname/submit
#!/bin/sh
dropfolder=\$1
echo "Enter history comments, end with Control-D."
echo B3:history >>$source.mod
echo "/# YYYY-MM-DD Updated $modname." >>$source.mod
sed 's%^%/# %' >>$source.mod
mv $source.mod \$dropfolder/$source-$modname.mod
exit 0
:eof
chmod u+rx $modname/scoop $modname/submit
exit 0
:eos
cat >arc-examples/binarc <<':eos'
#!/bin/sh
case $1
in
(new)
uuencode binary | arc new $2
;;
(get)
arc get | uudecode -p
;;
(scoop)
uuencode binary | arc $*
;;
(edit)
arc $*
;;
(check)
arc $*
;;
(list)
arc $*
;;
(version)
arc $*
;;
esac
:eos
chmod u+rx arc-examples/*
tclsh >arc-1WY.html <<':eof'
foreach line [split {<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN">
<html>
<head>
<title>ARC - ABSOLUTE REVISION CONTROL</title>
</head>
<body>
<h1>ARC - ABSOLUTE REVISION CONTROL</h1>
<ul>
<a href='#Synopsis'>Synopsis</a><br>
<a href='#Description'>Description</a><br>
<ul>
<a href='#New'>New</a><br>
<a href='#Get'>Get</a><br>
<a href='#Scoop'>Scoop</a><br>
<a href='#Edit'>Edit</a><br>
<a href='#Check'>Check</a><br>
<a href='#List'>List</a><br>
<a href='#Active'>Active</a><br>
<a href='#Version'>Version</a>
</ul>
<a href='#Formats'>File Formats</a><br>
<ul>
<a href='#arcformat'>ARC</a><br>
<a href='#modsetformat'>Modset</a>
</ul>
<a href='#Examples'>Examples</a><br>
<ul>
<a href='#exupdate'>update</a><br>
<a href='#exgetp'>getp</a><br>
<a href='#exyank'>yank</a><br>
<a href='#exrefdeleted'>refdeleted</a><br>
<a href='#excreate'>create</a><br>
<a href='#exworkarea'>workarea</a><br>
<a href='#exbinarc'>binarc</a>
</ul>
<a href='#Files'>Files</a><br>
<a href='#Errors'>Errors</a>
</ul>
<h2><a name='Synopsis'>Synopsis</a></h2>
<b>arc new</b> <i>contents-name</i> <b>< </b><i>source-file</i>
<b>></b><i>arc-file</i><br>
<b>arc get</b> <b>< </b><i>arc-file</i> <b>> </b><i>source-file</i><br>
<b>arc scoop</b> <i>modification-name</i> <i>arc-file</i>
<font size='+1'>[</font><i>version</i><font size='+1'>]</font>
<b>< </b><i>source-file</i> <b>> </b><i>modset-file</i><br>
<b>arc edit</b> <i>arc-file</i> <b><</b> <i>modset-file</i>
<b>></b> <i>new-arc-file</i><br>
<b>arc check</b> <i>arc-file</i> <b><</b> <i>modset-file</i>
<b>></b> <i>commented-modset-file</i><br>
<b>arc list</b> <b><</b> <i>arc-file</i> <b>></b> <i>html-file</i><br>
<b>arc active</b> <b><</b> <i>arc-file</i> <b>></b> <i>html-file</i><br>
<b>arc version</b> <b><</b> <i>arc-file</i> <b>></b> <i>output</i><br>
<h2><a name='Description'>Description</a></h2>
<p>Absolute Revision Control gives each line in an
<a href='#arcformat'>arc</a>-file an absolute address
which is never modified. Each line can be individually
marked as active or deleted, and has a history of
what has modified it. Changes to the file are collected
into <a href='#modsetformat'>modset</a>-files,
a collection of editting directives the convert one
version of the arc-file into the next. Lines added
by <b>arc new</b> are named with <i>contents-name</i>;
lines added by subsequent <b>arc edit</b>s are
named with the <i>modification-name</i> which inserts them.</p>
<p>Creating and extracting from an arc-file is a one step process, but updating takes two steps: (1)
determining how to change the arc-file and writing this to a modset-file, and (2) actually applying
the changes. Because the lines are given unique numbers which are used in the modset-file, the second
step does not require the same version of the arc-file as the first step. The first step can be done
manually or by using <b>arc scoop</b>. <b>arc scoop</b> compares a modified version of the extracted
arc contents to a version (the latest version or a specificly designated previous version) of the
arc-file and automatically generates the modset-file. Modset-files can be independently distributed.
Modset-files can also be applied in different orders as long as one modset-file does not use the
modset-name of another.</p>
<p><b>arc</b> does not concern itself with files, but with file contents as long as <b>arc</b> can
read and write a file as needed. An arc-file only needs to be writable when apply modset-files to
it with <b>arc edit</b>. This mean an arc-file can be
exported or shared read-only, modset-files created
and collected, and then all the modifications to the
arc-file for a build cycle updated in one session
by the arc-file owner. <b>arc</b> does not provide for
file locking, or ownership, or similar concerns
because it is not necessary. <b>arc scoop</b> creates
a modset-file to apply one modification to one
arc-file, however as long the modsets for one arc-file
do not refer to one another, they can be freely
concatenated into one file. Modsets that do refer
to each others can still be concatenated together,
be in modification order, not freely. If arc-files
are given unique names when created with <b>arc new</b>,
modset-files can use the P-directive to indicated
whether the modset applies to the editted arc-file;
with unique names, modsets for many different
arc-files can be concatenated and applied to each; then
each arc-file will only be updated with the modsets that apply to it and ignore others.</p>
<p>Each set of modifications is named, and names of
a modification applied to one arc-file must be unique.
(Whether a modification to another arc-file shares
a modification name is irrelevant to arc.) A
modification name cannot be a NULL character (00)
or a newline (\n). All other characters are available
and signficant, including preceding, trailing, and
embedded blanks. When an arc-file is first created,
it is given an initial modification name which can
be used as a unique internal identifier for the
arc-file contents.</p>
<p>(<i>ARC is inspired by an old Control Data Corporation product MODIFY, and related products such
as MADIFY, UPDATE, and DEVOUR.</i>)</p>
<h3><a name='New'>New</a></h3>
<p>Create a new arc-file. The source is <code>stdin</code>, and the arc-file is written to
<code>stdout</code>. Every line in the source file is added as an active line in the arc-file.
The arc-file will have one modification name <i>contents-name</i>, which will be the name on
each line. If <i>contents-name</i> is unique among arc-files, it can be used as internal arc-file
identifier. The created file must have at least one line.</p>
<h3><a name='Get'>Get</a></h3>
<p>Extract all active lines of the arc-file (from <code>stdin</code>) and write them to the
<code>stdout</code>, the new source-file. Only active lines are written, and they are shed of
history and line identifiers.</p>
<h3><a name='Scoop'>Scoop</a></h3>
<p>Compare a modified source file to the arc-file and generate a named set of modifications
(a modset) that will make the active lines of the arc-file match the source file. <code>stdin</code>
is the modified source file gotten from the arc-file. The modset-file is written to
<code>stdout</code>. The arc-file named explicitly.</p>
<dl>
<dt><i>modification-name</i>
<dd>
The set modifications must be given a unique name. However, the name uniqueness is not
checked until <b>arc edit</b> is run with the modset. The modification name cannot contain
null (00) or newline (\n) characters; all other characters are accepted and signficant.
</dd>
<dt><i>arc-file</i>
<dd>
The arc-file to compare against to detect modifications. Active lines in the arc-file are
compared to the read lines of the source; differences are used to create the modset-file.
Deleted lines in the arc-file are ignored. Only read-access is required for the arc-file;
also this can be a copy, and an editted copy.
</dd>
<dt><i>version</i>
<dd>
By default, the source file is compared to the arc-file as it currently is. If the arc-file
has been modified since the source file was gotten with <b>arc get</b>, the generated
modset-file will undo all those modifications. If <i>version</i> is specified, the lines
that were active in that version, ignoring all subsequent modifications, are base for
comparison. The modset-file will be relative to that version; whether it compatiable
with or conflicts with the current version is not considerred. Because an editted copy
of the arc-file can be presented to <b>arc</b>, more elaborate edits can also be done
to establish a base for comparison.
</dd>
<dt><code>stdin</code>
<dd>
The source file that the arc-file must be made to resemble. It is assumed that it is
a version of the arc-file gotten with <b>arc get</b>, modified, and then presented for
comparison. Whether this is true is outside the scope of <b>arc</b>.
</dd>
<dt><code>stdout</code>
<dd>
The generated modset. It will begin with the arc-file <i>contents-name</i> and the
<i>modification-name</i>, followed by zero or more inserts and deletes needed to make
the arc-file active lines match the source file lines. <b>arc scoop</b> does not create
R or Y directives.
</dd>
</dl>
<h3><a name='Edit'>Edit</a></h3>
<p>Apply the modset-file to the arc-file. Only read access is required for the arc-file. The
editted arc-file is written to <code>stdout</code>. The modset-file can actually be a concatenation
of many different modsets applied to the same arc-file. As long as two modsets do not refer to
each other's names, they can be editted in any order; when one modset refers to the names of others,
it must be editted after the references. If the <i>content-name</i> of each arc-file is unique and
the modsets use the P directive, then modsets of different arc-files may be freely merged. The order
of modifications is significant to the Y directive or when specifying a <i>version</i> on
<b>arc scoop</b>.</p>
<h3><a name='Check'>Check</a></h3>
<p><b>arc check</b> runs through all the actions of <b>arc edit</b> except rather than outputting
a modified arc-file, it outputs an annotated modset-file. The annotations indicate warnings, errors,
what changes would be done, and the active/deleted states of lines mentionned in the directives.
The caller can examine the annotations to diagnose errors, overlaps, conflicts, and other issues.
The input modset-file is copied to <code>stdout</code> with the modifications</p>
<ul>
<li>Old <b>arc check</b> annotations for the current arc-file are deleted. (Annotations
for other arc-files are passed through unchanged. (Concatenated modsets can be piped
through a sequence of <b>arc check</b> to produce a single annotated output file.)
<li>After an B, I, or R directive, the state (<code>a</code> for active and <code>d</code>
for deleted) of the named line is indicated:
<ul>
<i>X</i> <i>line-number</i><code>:</code><i>line-name</i><br>
<code>*arc check</code> <i>directive</i> <i>state</i>
<i>line-number</i><code>:</code><i>line-name</i>
</ul>
<li>After a D directive, the state (<code>a</code> for active and <code>d</code> for
deleted) of the beginning and ending named deleted lines are indicated (whether there
is an explicit ,-continuation):
<ul>
<code>D</code> <i>begin-line-number</i><code>:</code><i>begin-line-name</i><br>
<code>,</code> <i>end-line-number</i><code>:</code><i>end-line-name</i><br>
<code>*arc check D</code> <i>state</i>
<i>begin-line-number</i><code>:</code><i>begin-line-name</i><br>
<code>*arc check 1</code> <i>state</i>
<i>end-line-number</i><code>:</code><i>end-line-name</i>
</ul>
<li>Existing lines which are editted are listed. (In some cases, the line state may
be unchanged.) Lines inserted by the modification are not annotated. The states are
<code>a</code> for active and <code>d</code> for deleted.
<ul>
<code>*arc check</code> <i>new-state</i> <i>old-state</i>
<i>line-number</i><code>:</code><i>line-name</i><br>
</ul>
<li>Some additional situations which are normally ignored produce a warning annotation
<ul>
<code>*arc check W</code> <i>message</i><br>
</ul>
<li>Fatal errors are annotated and ignored rather than stopping <b>arc</b>
<ul>
<code>*arc check E</code> <i>message</i><br>
</ul>
</ul>
<h3><a name='List'>List</a></h3>
<p>Output an HTML list file of the arc-file contents. It lists all modication-names and each
line, active or deleted, with the line number and name, and the modification history. Deleted
lines and modification which deleted are written in italics. The first column of each html line
is the line state,<code>a</code> for active and <code>d</code> for deleted. The second column
is the line text itself. The third column is the line identifier
<i>line-number</i><code>:</code><i>line-name</i>. Line identifiers are unique and unchanging.
The <i>line-name</i> is the <i>content-name</i> or name of a subsequent modification that
added the line. <i>line-number</i> identifies the line from all others with the same name.
The fourth column is a modication history showing which modification added (<b>add</b>),
deleted (<b>del</b>), yanked and deleted (<b>yan</b>), yanked and restored (<b>yrs</b>),
or restored (<b>res</b>).
Lines can be restored with the R directive or by a yank that reactivates.</p>
<p>The grey and white bars are provided for visual alignment only. They have no other meaning.</p>
<h3><a name='Active'>Active</a></h3>
<p>Output an HTML list file of the arc-file active lines and line identifiers.
deleted lines and modification histories are not shown.</p>
<p>The grey and white bars are provided for visual alignment only. They have no other meaning.</p>
<h3><a name='Version'>Version</a></h3>
<p>Returns the name of the last modification in the arc-file and write to <code>stdout</code>.
This name can be saved and presented later in <b>arc scoop</b>. <b>arc</b> itself does not keep
track of whence or when a source file came from an arc-file. The environment must be structured
to handle this.</p>
<h2><a name='Formats'>File Formats</a></h2>
<p><b>arc</b> is only intended to be used on text files without embedded nulls (00) and which
separate lines with the new line (\n). Other line separators are not supported unless the C
standard I/O library translates them. Otherwise lines can be any length that can fit in memory
with any characters except null (00). The presence of a null (00) will result in a loss of file
contents. Binaries files should be converted with uuencode, Base-64 encoding, or other formats
before using with <b>arc</b>.</p>
<h3><a name='arcformat'>ARC</a></h3>
<p>It is recommended that an arc-file is not editted directly.</p>
<p>
<i>arc-file</i> <font face="san-serif"><b>::=</b></font> <i>contents-name</i>
<i>modification-directory</i> <i>contents</i><br>
<i>modification-directory</i> <font face="san-serif"><b>::=</b></font>
<i>modification-directory</i> <i>modification-entry</i>
<font face="san-serif"><b>|</b></font> <i>empty</i><br>
<i>contents-name</i> <font face="san-serif"><b>::=</b></font> <code>M</code>
<i>modification-name</i> <i>NL</i><br>
<i>modification-entry</i> <font face="san-serif"><b>::=</b></font> <code>M</code>
<i>modification-name</i> <i>NL</i><br>
<ul><font size='-1'><i>List all modifications that have been applied to the arc-file.
The order is signficant: within the contents, the modifications are referred by their
ordinal in this list. The contents-name is distinguish as the first modification, ordinal 1.
The next modification is ordinal 2, et cetera. When contents-name is unique for each arc-file
in a set of files, it can serve as the internal arc-file name. This uniqueness is,
however, neither required nor enforced.</i></font></ul>
<i>contents</i> <font face="san-serif"><b>::=</b></font> <i>contents</i> <i>content-line</i>
<font face="san-serif"><b>|</b></font> <i>content-line</i><br>
<i>content-line</i> <font face="san-serif"><b>::=</b></font> <i>line-histories</i>
<i>line-text</i><br>
<i>line-histories</i> <font face="san-serif"><b>::=</b></font> <i>line-histories</i>
<i>line-history</i> <font face="san-serif"><b>|</b></font> <i>line-history</i><br>
<i>line-history</i> <font face="san-serif"><b>::=</b></font> <i>operator</i>
<i>modification-ordinal</i> <i>NL</i><br>
<i>operator</i> <font face="san-serif"><b>::=</b></font> <code>A</code>
<font face="san-serif"><b>|</b></font> <code>D</code>
<font face="san-serif"><b>|</b></font> <code>R</code>
<font face="san-serif"><b>|</b></font> <code>Q</code>
<font face="san-serif"><b>|</b></font> <code>Y</code>
<br>
<ul><font size='-1'><i>The line-history indicates all modifications which have
affected the content-line:
A for added, D for deleted, Y for yanked and deleted, Q for restored by a yank,
R for restored withan R-directive. The history is the order of the modications.</i></font></ul>
<i>line-text</i> <font face="san-serif"><b>::=</b></font> <i>state</i>
<i>modification-ordinal</i> <code>:</code> <i>line-number</i> <code>:</code>
<i>any-characters-except-00-and-\n</i> <i>NL</i><br>
<i>state</i> <font face="san-serif"><b>::=</b></font> <code>a</code>
<font face="san-serif"><b>|</b></font> <code>d</code><br>
<ul><font size='-1'><i>The actual line with its unique and absolute identifier.</i></font></ul>
<i>modification-ordinal</i> <font face="san-serif"><b>::=</b></font> <i>positive-integer</i><br>
<i>line-number</i> <font face="san-serif"><b>::=</b></font> <i>positive-integer</i><br>
</p>
<h3><a name='modsetformat'>Modset</a></h3>
<p><b>arc scoop</b> can automatically create modset-files that only use insertion
and deletion. If this suffices, modset-files do not have to be editted by hand or
examined. <b>arc scoop</b> will not create R or Y directives; if these are required,
the modset-file must be created by hand or with some scripting outside the scope of
<b>arc</b>. The modset-file was designed to simplify machine generation and interpretation;
hence its unfriendly demeanor.</p>
<p>Each directive has a <i>modification-name</i> and ends with a new line (\n). If the
directive has only the
<i>modification-name</i>, it must beginning directly after the directive letter with
no intervening spaces or other characters: everything after the directive letter to
the end of the line is taken as the <i>modification-name</i>, including leading and
trailing space or any other character. If a directive has a <i>line-number</i> it may
be separated from the directive letter with spaces. The <i>line-number</i> must be
terminated with a non-digit character (<b>arc scoop</b> uses a colon (:) as its terminator).
The modification name begins immediately after the terminator (and not the line number
terminator itself). Again all characters after the terminator to the end of the line are
significant.</p>
<p>
<i>modset-file</i> <font face="san-serif"><b>::=</b></font> <i>modset-file</i>
<i>modset</i> <font face="san-serif"><b>|</b></font> <i>modset</i><br><br>
<i>modset</i> <font face="san-serif"><b>::=</b></font> <i>modset-identifier</i>
<i>editting-directives</i><br><br>
<i>modset-identifier</i> <font face="san-serif"><b>::=</b></font><br>
<code>P</code> <i>modification-name</i> <i>NL</i>
<code>M</code> <i>modification-name</i> <i>NL</i><br>
<font face="san-serif"><b>|</b></font> <code>M</code>
<i>modification-name</i> <i>NL</i> <code>P</code> <i>modification-name</i> <i>NL</i><br>
<font face="san-serif"><b>|</b></font> <code>M</code>
<i>modification-name</i> <i>NL</i><br><br>
<i>editting-directives</i> <font face="san-serif"><b>::=</b></font>
<i>editting-directives</i> <i>editting-directive</i> <font face="san-serif"><b>|</b></font>
<i>editting-directive</i><br><br>
<i>editting-directive</i> <font face="san-serif"><b>::=</b></font><br>
<i>insertion-directive</i>
<font face="san-serif"><b>|</b></font> <i>delete-replace-directive</i><br>
<font face="san-serif"><b>|</b></font> <i>restore-directive</i>
<font face="san-serif"><b>|</b></font> <i>yank-directive</i><br>
<font face="san-serif"><b>|</b></font> <i>comment</i><br>
<ul><font size='-1'><i>A P-directive or M-directive can actually be factorred
over a number of modsets. If sequence of modsets have the same P-directive but
different M directives, only the first modset needs the P-directive. Similarily
one M-directive in front modsets with different P-directives reuse the same name.
Each modset must have an M-directive with a unique modification-name within that
arc-file, either its own or the factorred name. The P-directive is optional, but
if specified, the modset is skipped if the content-name does not match the
P-directive modification-name. If content-names uniquely identify arc-files,
modifications for different arc-files can be merged into a single file.</i></font></ul>
<i>insertion-directive</i> <font face="san-serif"><b>::=</b></font><br>
<code>B</code> <i>line-identifier</i> <i>NL</i><br>
<i>insertion</i><br>
<font face="san-serif"><b>|</b></font> <code>I</code>
<i>line-identifier</i> <i>NL</i> <br>
<i>insertion</i><br>
<ul><font size='-1'><i>A B-directive inserts new lines before the identified line,
an I-directive after it. It is not an error if the insertion is empty, just pointless.
The inserted lines will be named with the current modset modification-name and
numberred automatically.</i></font></ul>
<i>delete-replace-directive</i> <font face="san-serif"><b>::=</b></font><br>
<code>D</code> <i>line-identifier</i> <i>NL</i><br>
<i>insertion</i><br>
<font face="san-serif"><b>|</b></font> <code>D</code>
<i>begin-line-identifier</i> <i>NL</i><br>
<code>,</code> <i>end-line-identifier</i> <i>NL</i><br>
<i>insertion</i> <br>
<ul><font size='-1'><i>A D-directive deletes a line or range of lines, and optionally
inserts new replacement lines after the deleted lines. The replacement lines will be
named with the current modset modification-name and numberred automatically. If the
D-directive is not followed by a ,-continuation line, a single line is deleted. A
,-continuation line is given, all lines from begin-line-identifier through the
end-line-identifier or deleted; the end-line must be the begin-line or a subsequent
line; if the end-line is before the begin-line, the deletion is ignored. A comment
cannot be placed between the D-line and a ,-continuation line.</i></font></ul>
<i>insertion</i> <font face="san-serif"><b>::=</b></font> <i>insertion</i> <i>insertion-line</i>
<font face="san-serif"><b>|</b></font> <i>insertion</i> <i>comment</i>
<font face="san-serif"><b>|</b></font> <i>empty</i><br>
<i>insertion-line</i> <font face="san-serif"><b>::=</b></font> <code>/</code>
<i>any-characters-except-00-and-\n</i> <i>NL</i><br>
<ul><font size='-1'><i>Inserted lines come after the B, D, or I directive. Each
new line is prefixed with a single slash (/) which is not part of the inserted line;
the inserted line begins immediately after the slash and continues to the end of the end.
Comments can be embedded in the insertion.</i></font></ul>
<i>restore-directive</i> <font face="san-serif"><b>::=</b></font> <code>R</code>
<i>line-identifier</i> <i>NL</i><br>
<ul><font size='-1'><i>A deleted line is made active again, regardless of why it
has been deleted. If the line is already active, this directive is ignored.</i></font></ul>
<i>yank-directive</i> <font face="san-serif"><b>::=</b></font>
<code>Y</code> <i>modification-name</i> <i>NL</i> <br>
<ul><font size='-1'><i>The Y-directive yanks all modifcations after the
named modification: it examines each
line affected by the subsequent modifications and if the
line status (active or deleted) would
change if the modifications had not been made,
the line status is reversed. The arc-file
active and deleted lines will be restored to what they were the named modification was
originally applied.</i></font></ul>
<i>comment</i> <font face="san-serif"><b>::=</b></font> <code>#</code>
<i>any-characters-except-00-and-\n</i> <i>NL</i> <font face="san-serif"><b>|</b></font>
<code>*</code> <i>any-characters-except-00-and-\n</i> <i>NL</i><br>
<ul><font size='-1'><i>#-comments are intended to be unstructured comments written and
read solely by humans. *-comments are intended to be structured comments or directives
for other tools embedded in the modset but ignored by <b>arc</b>. <b>arc edit</b>
ignores all comments. <b>arc check</b> ignores all #-comments and all *-comments not
beginning with <code>*arc check</code>.</i></font></ul>
<i>line-identifier</i> <font face="san-serif"><b>::=</b></font> <i>spacing</i>
<i>postive-integer</i> <i>terminator</i> <i>modification-name</i><br>
<i>spacing</i> <font face="san-serif"><b>::=</b></font> <i>zero-or-more-whitespace-characters</i><br>
<i>terminator</i> <font face="san-serif"><b>::=</b></font>
<i>any-single-non-digit-character-except-00-and-\n</i><br>
<ul><font size='-1'><i>Line identifiers refer to any existing line, whether
active or deleted. It is not an error to insert or delete deleted lines.
<b>arc check</b> can be used to determine the state of lines in B, D, I,
and R directives.</i></font></ul>
<h2><a name='Examples'>Examples</a></h2>
<p>By design, <b>arc</b> is simple tool which has a limitted number of functions,
but tries to do them very well. This section includes example scripts to extend
its capabilities. (These scripts do not much or any error checking and are provided
as examples rather than finished tools.)</p>
<dl>
<dt><b><a name='exupdate'>update</a></b> <i>modification-name</i>
<i>arc-file</i> <b><</b> <i>source-file</i>
<dd>Create a modset and then apply it the <i>arc-file</i> in one step.
<pre>update</pre>
<dt><b><a name='exgetp'>getp</a></b> <i>arc-file</i> <b>></b> <i>source-file</i>
<dd>Get the source file and current version. The version name is saved in new
script named <i>arc-file</i>.scoop which scoops the source file with respect
to the current version.
<pre>getp</pre>
<dt><b><a name='exyank'>yank</a></b> <i>version</i> <i>arc-file</i>
<dd>Revert to an earlier version and update the arc-file.
<pre>yank</pre>
<dt><b><a name='exrefdeleted'>refdeleted</a></b> <i>arc-file</i> <b><</b> <i>modset-file</i>
<dd>List all insertions and deletions that reference deleted lines.
<pre>refdeleted</pre>
<dt><b><a name='excreate'>create</a></b> <i>source-file</i>
<dd>Create the arc-file and add a history modification-name for subsequent comments.
The name of the arc file will be <i>source-file</i><code>.arc</code>
<pre>create</pre>
<dt><b><a name='exworkarea'>workarea</a></b> <i>modification-name</i> <i>arc-file</i>
<dd>Create an area as a directory to work on the source file. The source file is
extracted and a the arc-file is copied into the work area. The arc-file name is
<i>source-file</i><code>.arc</code> Additional scripts are created in the work
area to automate the work flow.
<dl>
<dt><b>scoop</b>
<dd>
Scoop the source file against the original archive and save as
<i>source-file</i><code>.mod</code>. The source file is also
scooped against local archive copy and editted in with current
time; this is a daily capture of the changes.
<dt><b>submit</b> <i>drop-folder</i>
<dd>
Submit <i>source-file</i><code>.mod</code> for integration. The console
is prompted for comments that are added to the arc-file history. The
modset is moved to the <i>drop-folder</i>.
</dl>
<pre>workarea</pre>
<dt><b><a name='exbinarc'>binarc</a></a></b> ...
<dd>Provide an arc interface that runs on binary files.
<pre>binarc</pre>
</dl>
<h2><a name='Files'>Files</a></h2>
<p><b>arc scoop</b>, <b>arc edit</b>, and <b>arc check</b> require a readable named arc-file
to be specified. The arc-file can have any name and reside anywhere it can be read from. Only
read access is required. In all other cases, the files are passed through <code>stdin</code>
and <code>stdout</code>; it is the caller's responsibility to assign these to the desired
disk file (if any).</p>
<h2><a name='Errors'>Errors</a></h2>
<p>On any error, <b>arc</b> prints a message to <code>stderr</code> and immediately
terminates with exit code 1; warnings are ignored. An exception when calling <b>arc check</b>:
errors and warnings are logged as annotations and <b>arc</b> continues. If there is no error or
<b>arc check</b> is called, the exit code is 0.</p>
</body>
</html>}] {
if {[regexp {^<pre>(.*)</pre>$} $line - name]} {
puts <pre>
set c [open arc-examples/$name]
puts [string map {\t { } & & < < > >} [read -nonewline $c]]
close $c
puts </pre>
} else {
puts $line
}
}
:eof
mkdir arc-test
rm -rf arc-test/*
(
PATH=`pwd`:`pwd`/arc-examples:$PATH export PATH
cd arc-test
echo -----------------------------------------1
cat <<:eof >STDIN
aaaa
bbbb
cccc
dddd
eeee
ffff
gggg
hhhh
iiii
jjjj
kkkk
AAAA
BBBB
CCCC
DDDD
EEEE
FFFF
:eof
if [ $testcase -eq 1 ]
then
echo 'run new x >q <STDIN' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc new x >q <STDIN
fi
cat >TESTCASE <<':eof'
#arc 2.0
Mx
A1
a1:1:aaaa
A1
a1:2:bbbb
A1
a1:3:cccc
A1
a1:4:dddd
A1
a1:5:eeee
A1
a1:6:ffff
A1
a1:7:gggg
A1
a1:8:hhhh
A1
a1:9:iiii
A1
a1:10:jjjj
A1
a1:11:kkkk
A1
a1:12:AAAA
A1
a1:13:BBBB
A1
a1:14:CCCC
A1
a1:15:DDDD
A1
a1:16:EEEE
A1
a1:17:FFFF
:eof
sdiff -l TESTCASE q >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------2
if [ $testcase -eq 2 ]
then
echo 'run get <q >SOURCE' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc get <q >SOURCE
fi
cat >TESTCASE <<':eof'
aaaa
bbbb
cccc
dddd
eeee
ffff
gggg
hhhh
iiii
jjjj
kkkk
AAAA
BBBB
CCCC
DDDD
EEEE
FFFF
:eof
sdiff -l TESTCASE SOURCE >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------3
cat <<:eof >STDIN
0000
1111
aaaa
bbbb
eeee
ffff
gggg
hhhh
iiii
xxxx
yyyy
zzzz
jjjj
kkkk
AAAA
BBBB
EEEE
FFFF
:eof
if [ $testcase -eq 3 ]
then
echo 'run scoop t1 q >e1 <STDIN' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc scoop t1 q >e1 <STDIN
fi
cat >TESTCASE <<':eof'
Px
Mt1
B1:x
/0000
/1111
D3:x
,4:x
I9:x
/xxxx
/yyyy
/zzzz
D14:x
,15:x
:eof
sdiff -l TESTCASE e1 >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------4
cp q q1
if [ $testcase -eq 4 ]
then
echo 'run edit q <e1 >q1' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc edit q <e1 >q1
fi
cat >TESTCASE <<':eof'
#arc 2.0
Mx
Mt1
A2
a2:1:0000
A2
a2:2:1111
A1
a1:1:aaaa
A1
a1:2:bbbb
A1
D2
d1:3:cccc
A1
D2
d1:4:dddd
A1
a1:5:eeee
A1
a1:6:ffff
A1
a1:7:gggg
A1
a1:8:hhhh
A1
a1:9:iiii
A2
a2:3:xxxx
A2
a2:4:yyyy
A2
a2:5:zzzz
A1
a1:10:jjjj
A1
a1:11:kkkk
A1
a1:12:AAAA
A1
a1:13:BBBB
A1
D2
d1:14:CCCC
A1
D2
d1:15:DDDD
A1
a1:16:EEEE
A1
a1:17:FFFF
:eof
sdiff -l TESTCASE q1 >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------5
cat <<:eof >STDIN
0000
1111
aaaa
bbbb
eeee
ffff
gggg
hhhh
iiii
xxxx
yyyy
zzzz
jjjj
kkkk
AAAA
BBBB
EEEE
FFFF
:eof
if [ $testcase -eq 5 ]
then
echo 'run scoop zed q1 x <STDIN >MODS' >gdbinput
gdb -q -x gdbinput arc
else
arc scoop zed q1 x <STDIN >MODS
fi
echo --- >>MODS
if [ $testcase -eq 5 ]
then
echo 'run scoop zed q1 <STDIN >>MODS' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc scoop zed q1 <STDIN >>MODS
fi
cat >TESTCASE <<':eof'
Px
Mzed
B1:x
/0000
/1111
D3:x
,4:x
I9:x
/xxxx
/yyyy
/zzzz
D14:x
,15:x
---
Px
Mzed
:eof
sdiff -l TESTCASE MODS >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------6
cat <<:eof >STDIN
0000
1111
aaaa
bbbb
eeee
ffff
gggg
zzzz
jjjj
kkkk
pppp
qqqq
rrrr
ssss
AAAA
FFFF
:eof
if [ $testcase -eq 6 ]
then
echo 'run scoop t2 q1 >e2 <STDIN' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc scoop t2 q1 >e2 <STDIN
fi
cat >TESTCASE <<':eof'
Px
Mt2
D8:x
,4:t1
I11:x
/pppp
/qqqq
/rrrr
/ssss
D13:x
,16:x
:eof
sdiff -l TESTCASE e2 >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------7
cat e1 e2 > e12
if [ $testcase -eq 7 ]
then
echo 'run edit q >q1 <e12' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc edit q >q1 <e12
fi
mv q1 q
cat >TESTCASE <<':eof'
#arc 2.0
Mx
Mt1
Mt2
A2
a2:1:0000
A2
a2:2:1111
A1
a1:1:aaaa
A1
a1:2:bbbb
A1
D2
d1:3:cccc
A1
D2
d1:4:dddd
A1
a1:5:eeee
A1
a1:6:ffff
A1
a1:7:gggg
A1
D3
d1:8:hhhh
A1
D3
d1:9:iiii
A2
D3
d2:3:xxxx
A2
D3
d2:4:yyyy
A2
a2:5:zzzz
A1
a1:10:jjjj
A1
a1:11:kkkk
A3
a3:1:pppp
A3
a3:2:qqqq
A3
a3:3:rrrr
A3
a3:4:ssss
A1
a1:12:AAAA
A1
D3
d1:13:BBBB
A1
D2
D3
d1:14:CCCC
A1
D2
D3
d1:15:DDDD
A1
D3
d1:16:EEEE
A1
a1:17:FFFF
:eof
sdiff -l TESTCASE q >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------8
if [ $testcase -eq 8 ]
then
echo 'run get <q >SOURCE' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc get <q >SOURCE
fi
cat >TESTCASE <<':eof'
0000
1111
aaaa
bbbb
eeee
ffff
gggg
zzzz
jjjj
kkkk
pppp
qqqq
rrrr
ssss
AAAA
FFFF
:eof
sdiff -l TESTCASE SOURCE >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------9
if [ $testcase -eq 9 ]
then
echo 'run list <q >q.html' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc list <q >q.html
fi
cat >TESTCASE <<':eof'
<html><head><title>x</title></head><body>
<h3>Modification Names</h3>
x<br>
t1<br>
t2<br>
<h3>Contents</h3><table width='100%'>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code>0000</code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>1:t1</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>t1 <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code>1111</code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>2:t1</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>t1 <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code>aaaa</code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>1:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code>bbbb</code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>2:x</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>x <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code><i>cccc</i></code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>3:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>;
<i>t1 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code><i>dddd</i></code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>4:x</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>x <b>add</b>;
<i>t1 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code>eeee</code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>5:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code>ffff</code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>6:x</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>x <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code>gggg</code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>7:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code><i>hhhh</i></code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>8:x</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>x <b>add</b>;
<i>t2 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code><i>iiii</i></code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>9:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>;
<i>t2 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code><i>xxxx</i></code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>3:t1</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>t1 <b>add</b>;
<i>t2 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code><i>yyyy</i></code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>4:t1</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>t1 <b>add</b>;
<i>t2 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code>zzzz</code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>5:t1</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>t1 <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code>jjjj</code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>10:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code>kkkk</code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>11:x</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>x <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code>pppp</code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>1:t2</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>t2 <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code>qqqq</code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>2:t2</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>t2 <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code>rrrr</code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>3:t2</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>t2 <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code>ssss</code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>4:t2</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>t2 <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code>AAAA</code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>12:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code><i>BBBB</i></code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>13:x</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>x <b>add</b>;
<i>t2 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code><i>CCCC</i></code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>14:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>;
<i>t1 </i><b>del</b>;
<i>t2 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code><i>DDDD</i></code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>15:x</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>x <b>add</b>;
<i>t1 </i><b>del</b>;
<i>t2 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#E0E0E0' align=center valign=top><b>d</b></td>
<td width='60%' bgcolor='#E0E0E0' align=left valign=top><code><i>EEEE</i></code></td>
<td width='15%' bgcolor='#E0E0E0' align=left valign=top>16:x</td>
<td width='25%' bgcolor='#E0E0E0' align=left valign=top>x <b>add</b>;
<i>t2 </i><b>del</b>.</td></tr>
<tr><td width=10 bgcolor='#FFFFFF' align=center valign=top><b>a</b></td>
<td width='60%' bgcolor='#FFFFFF' align=left valign=top><code>FFFF</code></td>
<td width='15%' bgcolor='#FFFFFF' align=left valign=top>17:x</td>
<td width='25%' bgcolor='#FFFFFF' align=left valign=top>x <b>add</b>.</td></tr>
</table></body></html>
:eof
sdiff -l TESTCASE q.html >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------10
cat <<:eof >STDIN
Mt3
Yt1
:eof
if [ $testcase -eq 10 ]
then
echo 'run edit q >q1 <STDIN' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc edit q >q1 <STDIN
fi
mv q1 q
cat >TESTCASE <<':eof'
#arc 2.0
Mx
Mt1
Mt2
Mt3
A2
a2:1:0000
A2
a2:2:1111
A1
a1:1:aaaa
A1
a1:2:bbbb
A1
D2
d1:3:cccc
A1
D2
d1:4:dddd
A1
a1:5:eeee
A1
a1:6:ffff
A1
a1:7:gggg
A1
D3
Q4
a1:8:hhhh
A1
D3
Q4
a1:9:iiii
A2
D3
Q4
a2:3:xxxx
A2
D3
Q4
a2:4:yyyy
A2
a2:5:zzzz
A1
a1:10:jjjj
A1
a1:11:kkkk
A3
Y4
d3:1:pppp
A3
Y4
d3:2:qqqq
A3
Y4
d3:3:rrrr
A3
Y4
d3:4:ssss
A1
a1:12:AAAA
A1
D3
Q4
a1:13:BBBB
A1
D2
D3
d1:14:CCCC
A1
D2
D3
d1:15:DDDD
A1
D3
Q4
a1:16:EEEE
A1
a1:17:FFFF
:eof
sdiff -l TESTCASE q >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------11
cat <<:eof >STDIN
Mt3
Yt1
:eof
if [ $testcase -eq 11 ]
then
echo 'run edit q <STDIN 2>ERRORS' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc edit q <STDIN 2>ERRORS
fi
echo ec $? >>ERRORS
cat >TESTCASE <<':eof'
duplicate modification-name: t3
ec 1
:eof
sdiff -l TESTCASE ERRORS >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------12
cat <<:eof >STDIN
Yt1
:eof
if [ $testcase -eq 12 ]
then
echo 'run edit q <STDIN 2>ERRORS' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc edit q <STDIN 2>ERRORS
fi
echo ec $? >>ERRORS
cat >TESTCASE <<':eof'
modset had no Mmodification-name: Yt1
ec 1
:eof
sdiff -l TESTCASE ERRORS >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------13
cat <<:eof >STDIN
Py
Mt3
Yt1
:eof
if [ $testcase -eq 13 ]
then
echo 'run edit q <STDIN >q1' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc edit q <STDIN >q1
fi
mv q1 q
cat >TESTCASE <<':eof'
#arc 2.0
Mx
Mt1
Mt2
Mt3
A2
a2:1:0000
A2
a2:2:1111
A1
a1:1:aaaa
A1
a1:2:bbbb
A1
D2
d1:3:cccc
A1
D2
d1:4:dddd
A1
a1:5:eeee
A1
a1:6:ffff
A1
a1:7:gggg
A1
D3
Q4
a1:8:hhhh
A1
D3
Q4
a1:9:iiii
A2
D3
Q4
a2:3:xxxx
A2
D3
Q4
a2:4:yyyy
A2
a2:5:zzzz
A1
a1:10:jjjj
A1
a1:11:kkkk
A3
Y4
d3:1:pppp
A3
Y4
d3:2:qqqq
A3
Y4
d3:3:rrrr
A3
Y4
d3:4:ssss
A1
a1:12:AAAA
A1
D3
Q4
a1:13:BBBB
A1
D2
D3
d1:14:CCCC
A1
D2
D3
d1:15:DDDD
A1
D3
Q4
a1:16:EEEE
A1
a1:17:FFFF
:eof
sdiff -l TESTCASE q >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------14
if [ $testcase -eq 14 ]
then
echo 'run version <q >VERSION' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc version <q >VERSION
fi
cat >TESTCASE <<':eof'
t3
:eof
sdiff -l TESTCASE VERSION >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------15
cat <<:eof >STDIN
Mt4
R 1:x
R 15:x
R 5:t1
:eof
if [ $testcase -eq 15 ]
then
echo 'run edit q <STDIN >q1' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc edit q <STDIN >q1
fi
mv q1 q
cat >TESTCASE <<':eof'
#arc 2.0
Mx
Mt1
Mt2
Mt3
Mt4
A2
a2:1:0000
A2
a2:2:1111
A1
a1:1:aaaa
A1
a1:2:bbbb
A1
D2
d1:3:cccc
A1
D2
d1:4:dddd
A1
a1:5:eeee
A1
a1:6:ffff
A1
a1:7:gggg
A1
D3
Q4
a1:8:hhhh
A1
D3
Q4
a1:9:iiii
A2
D3
Q4
a2:3:xxxx
A2
D3
Q4
a2:4:yyyy
A2
a2:5:zzzz
A1
a1:10:jjjj
A1
a1:11:kkkk
A3
Y4
d3:1:pppp
A3
Y4
d3:2:qqqq
A3
Y4
d3:3:rrrr
A3
Y4
d3:4:ssss
A1
a1:12:AAAA
A1
D3
Q4
a1:13:BBBB
A1
D2
D3
d1:14:CCCC
A1
D2
D3
R5
a1:15:DDDD
A1
D3
Q4
a1:16:EEEE
A1
a1:17:FFFF
:eof
sdiff -l TESTCASE q >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------16
if [ $testcase -eq 16 ]
then
echo 'run version <q >VERSION' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc version <q >VERSION
fi
cat >TESTCASE <<':eof'
t4
:eof
sdiff -l TESTCASE VERSION >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------17
if [ $testcase -eq 17 ]
then
echo 'run active <q >r.html' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc active <q >r.html
fi
cat >TESTCASE <<':eof'
<html><head><title>x</title></head><body>
<table width='100%'>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>0000</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>1:t1</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>1111</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>2:t1</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>aaaa</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>1:x</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>bbbb</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>2:x</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>eeee</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>5:x</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>ffff</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>6:x</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>gggg</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>7:x</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>hhhh</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>8:x</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>iiii</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>9:x</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>xxxx</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>3:t1</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>yyyy</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>4:t1</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>zzzz</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>5:t1</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>jjjj</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>10:x</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>kkkk</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>11:x</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>AAAA</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>12:x</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>BBBB</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>13:x</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>DDDD</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>15:x</td></tr>
<tr><td width='80%' bgcolor='#FFFFFF' align=left valign=top><code>EEEE</code></td>
<td width='20%' bgcolor='#FFFFFF' align=left valign=top>16:x</td></tr>
<tr><td width='80%' bgcolor='#E0E0E0' align=left valign=top><code>FFFF</code></td>
<td width='20%' bgcolor='#E0E0E0' align=left valign=top>17:x</td></tr>
</table></body></html>
:eof
sdiff -l TESTCASE r.html >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------18
cat <<:eof >STDIN
Mcheck1
*arc check old entry
I14:x
/abc
/def
/ghi
D1:t1
,1:x
/jkl
/mno
/pqr
D1:unknown
* error follows
?eh
Mcheck2
D1:t1
,1:x
/stu
# blah blah
/vwx
# blah blah
/yza
I12,x
/bcd
/efg
/hij
R12,x
# blah blah
:eof
if [ $testcase -eq 18 ]
then
echo 'run check q <STDIN >MODS' >gdbinput
gdb -q -x gdbinput arc
exit
else
arc check q <STDIN >MODS
fi
echo ec $? >>MODS
cat >TESTCASE <<':eof'
Mcheck1
I14:x
*arc check I d 14:x
/abc
/def
/ghi
D1:t1
,1:x
*arc check D a 1:t1
*arc check 1 a 1:x
*arc check d a 1:t1
*arc check d a 2:t1
*arc check d a 1:x
/jkl
/mno
/pqr
*arc check E unknown modification: unknown
D1:unknown
* error follows
*arc check E invalid edit directive: ?eh
?eh
Mcheck2
D1:t1
,1:x
*arc check D d 1:t1
*arc check 1 d 1:x
*arc check d d 1:t1
*arc check d d 2:t1
*arc check d d 1:x
/stu
# blah blah
/vwx
# blah blah
/yza
I12,x
*arc check I a 12:x
/bcd
/efg
/hij
R12,x
*arc check R a 12:x
*arc check W line already active: 12:x
# blah blah
ec 0
:eof
sdiff -l TESTCASE MODS >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------19
arc new example.arc <<:eof >example.arc
abc def ghi
jkl mno pqr
stu vwx yza
:eof
update example19 example.arc <<:eof
abc def ghi
ABC DEF GHI
stu vwx yza
JKL MNO PQR
:eof
cat >TESTCASE <<':eof'
#arc 2.0
Mexample.arc
Mexample19
A1
a1:1:abc def ghi
A1
D2
d1:2:jkl mno pqr
A2
a2:1:ABC DEF GHI
A1
a1:3:stu vwx yza
A2
a2:2:JKL MNO PQR
:eof
sdiff -l TESTCASE example.arc >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------20
getp example.arc >SOURCE
arc edit example.arc <<:eof >example20
Mexample20-1
D1,example19
:eof
cp example20 example.arc
echo --- >>example20
example.arc.scoop example20-2 <<:eof | tee MODS >>example20
abc def ghi
ABC DEF GHI
PQR STU VWX
:eof
arc edit example.arc <MODS >example.arc.1
mv example.arc.1 example.arc
cat >TESTCASE <<':eof'
#arc 2.0
Mexample.arc
Mexample19
Mexample20-1
A1
a1:1:abc def ghi
A1
D2
d1:2:jkl mno pqr
A2
D3
d2:1:ABC DEF GHI
A1
a1:3:stu vwx yza
A2
a2:2:JKL MNO PQR
---
Pexample.arc
Mexample20-2
D3:example.arc
,2:example19
/PQR STU VWX
:eof
sdiff -l TESTCASE example20 >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------21
cp example.arc example.arc.1
yank example20-1 example.arc.1
cat >TESTCASE <<':eof'
#arc 2.0
Mexample.arc
Mexample19
Mexample20-1
Mexample20-2
Mexample20-1-YANK
A1
a1:1:abc def ghi
A1
D2
d1:2:jkl mno pqr
A2
D3
d2:1:ABC DEF GHI
A1
D4
Q5
a1:3:stu vwx yza
A2
D4
Q5
a2:2:JKL MNO PQR
A4
Y5
d4:1:PQR STU VWX
:eof
sdiff -l TESTCASE example.arc.1 >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------22
refdeleted example.arc <<:eof >OUTPUT
Pexample.arc
Mexample23-1
I 1,example.arc
/one
I 2,example.arc
/two
Mexample23-2
I 2,example19
/three
I 1,example20-2
/four
:eof
cat >TESTCASE <<':eof'
example.arc; example23-1; I 2,example.arc
example.arc; example23-2; I 2,example19
:eof
sdiff -l TESTCASE OUTPUT >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------23
cat <<:eof >example24.x
aaaa bbbb cccc
dddd eeee ffff
gggg hhhh iii
:eof
create example24.x
cat >TESTCASE <<':eof'
#arc 2.0
Mexample24.x
Mhistory
A2
a2:1:#if 0
A2
a2:2:# YYYY-MM-DD Created example24.x.arc.
A2
a2:3:#endif
A1
a1:1:aaaa bbbb cccc
A1
a1:2: dddd eeee ffff
A1
a1:3:gggg hhhh iii
:eof
sdiff -l TESTCASE example24.x.arc >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------24
workarea example25 example24.x.arc
mkdir -p drop
(
cd example25
echo xyz >>example24.x
./scoop
./submit ../drop <<:eof
Example 25 history comments
block.
:eof
)
cat example25/example24.x >OUTPUT
echo --- >>OUTPUT
cat drop/example24.x-example25.mod >>OUTPUT
cat >TESTCASE <<':eof'
#if 0
# YYYY-MM-DD Created example24.x.arc.
#endif
aaaa bbbb cccc
dddd eeee ffff
gggg hhhh iii
xyz
---
Pexample24.x
Mexample25
I3:example24.x
/xyz
B3:history
/# YYYY-MM-DD Updated example25.
/# Example 25 history comments
/# block.
:eof
sdiff -l TESTCASE OUTPUT >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
echo -----------------------------------------25
uudecode <<':eof'
begin 644 image1.gif
M1TE&.#EAD`"0`/<```````$!`0("`@,#`P0$!`4%!08&!@<'!P@("`D)"0H*
M"@L+"PP,#`T-#0X.#@\/#Q`0$!$1$1(2$A,3$Q04%!45%186%A<7%Q@8&!D9
M&1H:&AL;&QP<'!T='1X>'A\?'R`@("$A(2(B(B,C(R0D)"4E)28F)B<G)R@H
M*"DI*2HJ*BLK*RPL+"TM+2XN+B\O+S`P,#$Q,3(R,C,S,S0T-#4U-38V-C<W
M-S@X.#DY.3HZ.CL[.SP\/#T]/3X^/C\_/T!`0$%!04)"0D-#0T1$1$5%149&
M1D='1TA(2$E)24I*2DM+2TQ,3$U-34Y.3D]/3U!04%%145)24E-34U145%55
M55965E=75UA86%E965I:6EM;6UQ<7%U=75Y>7E]?7V!@8&%A86)B8F-C8V1D
M9&5E969F9F=G9VAH:&EI:6IJ:FMK:VQL;&UM;6YN;F]O;W!P<'%Q<7)R<G-S
M<W1T='5U=79V=G=W=WAX>'EY>7IZ>GM[>WQ\?'U]?7Y^?G]_?X"`@(&!@8*"
M@H.#@X2$A(6%A8:&AH>'AXB(B(F)B8J*BHN+BXR,C(V-C8Z.CH^/CY"0D)&1
MD9*2DI.3DY24E)65E9:6EI>7EYB8F)F9F9J:FIN;FYR<G)V=G9Z>GI^?GZ"@
MH*&AH:*BHJ.CHZ2DI*6EI::FIJ>GIZBHJ*FIJ:JJJJNKJZRLK*VMK:ZNKJ^O
MK["PL+&QL;*RLK.SL[2TM+6UM;:VMK>WM[BXN+FYN;JZNKN[N[R\O+V]O;Z^
MOK^_O\#`P,'!P<+"PL/#P\3$Q,7%Q<;&QL?'Q\C(R,G)R<K*RLO+R\S,S,W-
MS<[.SL_/S]#0T-'1T=+2TM/3T]34U-75U=;6UM?7U]C8V-G9V=K:VMO;V]S<
MW-W=W=[>WM_?W^#@X.'AX>+BXN/CX^3DY.7EY>;FYN?GY^CHZ.GIZ>KJZNOK
MZ^SL[.WM[>[N[N_O[_#P\/'Q\?+R\O/S\_3T]/7U]?;V]O?W]_CX^/GY^?KZ
M^OO[^_S\_/W]_?[^_O___RP`````D`"0```(_P#_"1Q(L*#!@P@3*ES(L*'#
MAQ`C2IQ(L:+%BQ@S:OSWJZ/'CR`[;AQ)LF3#/0!2JES)<H_)ES!-IF%)<V6:
MF#AS6IQ9L^9-G4"#,N39D^5/H4B3"B1:5.51I5!U,FT*X&G4JR^G-K6*M>M&
MK46Y>AV[DZI-LF@Q@NTI-JW;AFM]OIT+,2[-MG3S$K1K5*]?A'S/_AT\,+!3
MPH@-I\2+V*WBJHT'/V8<F2PDLX<KZ_V%.24DS9L[`_@%.B_GSJ1+SSV-.;5J
MM[\DH'X]%P5F!*YIH[5M%H7NMX9]_TYKV,KPM)?-4CZ.E'53E\S'.B^:._K5
MZ3VK6X>*O:;V[4E_(?\P^QT\4MY-RYL/BKXG"O7K=5JA*CP^5+Y%[$=%N54_
M=ZK+^6=2=RO!)^!+!*IDX($E)9C2@@R.)%YZ$0K5'DT05JC1A2MQD*&&&!51
M5'T@XA27#25*%5:*.248((L6)?@9C#`E^"&-$MF((X+4[3@@AP_Z*!,*1!:)
M0A$W"JGDDAO]LD<:4$8IY9110@(2DPLYV!D"1%J1QAXA720.'S"4:>:99DHA
M#DX@04+EFU*">9"6HHUX))1A,B2.:&MBU":41,I6)X9S#FIH4QR@8`.45GXT
MT)Z=2?$02$]:0>1XA[96:*:<8I:?0)!B!@-!(4%9Q*6=<OH=G:EF6E^H9HW_
MNA20K::Z:JVXKO2J:++^0VNNF=X*+*Z[=M;KK\,.*FRRJ18KZD#(,CN;0:Q*
MVY2SL4)K;:?+;FLHME0=ZVVPFXX[*+A-B6NNLN6NBQD*1\$:KK;NBM:MNUS>
MF4:>H/(ZD(CU3EM0M8?FZR68CCHD;[H#_9FAP$'"![1XJ`9&,7HG1PD7U
MJE"I:9P:;:NK/@DGG(UZA),X`QA[44B5HFJK9N*,B>;-,/`1D\,GORDGED`'
M+?30(*9AY-%%OD@TO=<N#='()#J]$-12.S2RAU4S-/)H64^M:=<)S6?6*6`G
M9!B295=<U"E)!DUPVT#_(C%F$L"-)7]TV[TDP0!(_\!VV@+](K9H?P/.=TH_
ME_U+<G5:H?>.OSRF$MII_P)PG5A7?KEH=1N^>6>=:VYHZ(KCS?GC."YN:.:*
MGX*I:)17/K=HB2O^.7F`!RYY[)6;CGON'/G^'/"!#TX5Z[F_G>)'D,P8H_$4
M"OC1DQ&OA)N?G4&G7QJ"1A]C9TKK9@-FQKT,OH"&D4Y1M>'3QCA59'^/6?SZ
M5?N>1=#WZ%]LV=L]X=?^R=_:)A*YSM@`=94AF/H:XB31.&]_6TL)`@K'D`9N
M"8&:.<6@'`>?CHQ/-.T;SB\^6*<BL,TU'H$$"2^HH<-9STB<HE^$5#>QE#BN
M1`6<V/V6=SMO+1!$EG/7#T1Q*#E.'5!(-+36OO;VBP@.B@,4W!LDNM<J"5B)
J:+\XQ0H/A8(K2JTC*GR=61!@@T89KB-0@IB1BH`GD1#OC7",(_$"`@`[
`
end
:eof
uudecode <<':eof'
begin 644 image2.gif
M1TE&.#EAD`"0`/<```````$!`0("`@,#`P0$!`4%!08&!@<'!P@("`D)"0H*
M"@L+"PP,#`T-#0X.#@\/#Q`0$!$1$1(2$A,3$Q04%!45%186%A<7%Q@8&!D9
M&1H:&AL;&QP<'!T='1X>'A\?'R`@("$A(2(B(B,C(R0D)"4E)28F)B<G)R@H
M*"DI*2HJ*BLK*RPL+"TM+2XN+B\O+S`P,#$Q,3(R,C,S,S0T-#4U-38V-C<W
M-S@X.#DY.3HZ.CL[.SP\/#T]/3X^/C\_/T!`0$%!04)"0D-#0T1$1$5%149&
M1D='1TA(2$E)24I*2DM+2TQ,3$U-34Y.3D]/3U!04%%145)24E-34U145%55
M55965E=75UA86%E965I:6EM;6UQ<7%U=75Y>7E]?7V!@8&%A86)B8F-C8V1D
M9&5E969F9F=G9VAH:&EI:6IJ:FMK:VQL;&UM;6YN;F]O;W!P<'%Q<7)R<G-S
M<W1T='5U=79V=G=W=WAX>'EY>7IZ>GM[>WQ\?'U]?7Y^?G]_?X"`@(&!@8*"
M@H.#@X2$A(6%A8:&AH>'AXB(B(F)B8J*BHN+BXR,C(V-C8Z.CH^/CY"0D)&1
MD9*2DI.3DY24E)65E9:6EI>7EYB8F)F9F9J:FIN;FYR<G)V=G9Z>GI^?GZ"@
MH*&AH:*BHJ.CHZ2DI*6EI::FIJ>GIZBHJ*FIJ:JJJJNKJZRLK*VMK:ZNKJ^O
MK["PL+&QL;*RLK.SL[2TM+6UM;:VMK>WM[BXN+FYN;JZNKN[N[R\O+V]O;Z^
MOK^_O\#`P,'!P<+"PL/#P\3$Q,7%Q<;&QL?'Q\C(R,G)R<K*RLO+R\S,S,W-
MS<[.SL_/S]#0T-'1T=+2TM/3T]34U-75U=;6UM?7U]C8V-G9V=K:VMO;V]S<
MW-W=W=[>WM_?W^#@X.'AX>+BXN/CX^3DY.7EY>;FYN?GY^CHZ.GIZ>KJZNOK
MZ^SL[.WM[>[N[N_O[_#P\/'Q\?+R\O/S\_3T]/7U]?;V]O?W]_CX^/GY^?KZ
M^OO[^_S\_/W]_?[^_O___RP`````D`"0```(_P#_"1Q(L*#!@P@3*ES(L*'#
MAQ`C2IQ(L:+%BQ@S:OSWJZ/'CR`[;AQ)LF3#/0!2JES)<H_)ES!-IF%)<V6:
MF#AS6IQ9L^9-G4"#,N39D^5/H4B3"B1:5.51I5!U,FT*X&G4JR^G-K6*M>M&
MK46Y>AV[DZI-LF@Q@NTI-JW;AFM]OIT+,2[-MG3S$K1K5*]?A'S/_AT\,+!3
MPH@-I\2+V*WBJHT'/V8<F2PDLX<KZ_V%.24DS9L[`_@%.B_GSJ1+SSV-.;5J
MM[\DH'X]%P5F!*YIH[5M%H7NMX9]_TYKV,KPM)?-4CZ.E'53E\S'.B^:._K5
MZ3VK6X>*O:;V[4E_(?\P^QT\4MY-RYL/BKXG"O7K=5JA*CP^5+Y%[$=%N54_
M=ZK+^6=2=RO!)^!+!*IDX($E)9C2@@R.)%YZ$0K5'DT05JC1A2MQD*&&&!51
M5'T@XA27#25*%5:*.248((L6)?@9C#`E^"&-$MF((X+4[3@@AP_Z*!,*1!:)
M0A$W"JGDDAO]LD<:4$8IY9110@(2DPLYV!D"1%J1QAXA720.'S"4:>:99DHA
M#DX@04+EFU*">9"6HHUX))1A,B2.:&MBU":41,I6)X9S#FIH4QR@8`.45GXT
MT)Z=2?$02$]:0>1XA[96:*:<8I:?0)!B!@-!(4%9Q*6=<OH=G:EF6E^H9HW_
MNA20K::Z:JVXKO2J:++^0VNNF=X*+*Z[=M;KK\,.*FRRJ18KZD#(,CN;0:Q*
MVY2SL4)K;:?+;FLHME0=ZVVPFXX[*+A-B6NNLN6NBQD*1\$:KK;NBM:MNUS>
MF4:>H/(ZD(CU3EM0M8?FZR68CCHD;[H#_9FAP$'"![1XJ`9&,7HG1PD7U
MJE"I:9P:;:NK/@DGG(UZA),X`QA[44B5HFJK9N*,B>;-,/`1D\,GORDGED`'
M+?30&J9AY-%%OD@TO=<N#='()#J]$-12-_2+Q/15S1"K46M-[;M>*W0*9L:%
M/2?``)I-[=B:JDVJO6XW+*A9'L;-T=QF0:?V+Z?@_TV>VWP/:D622CII*.%"
M_C+?H%::_0O:HNWK.-9U(NFXWYXBOF-LAEH>-N>#>NXUZ'7^/#KEHC7^.>2W
MG:(YCH;76??>H;^^.>L`VKYYZ;KOR!]FIN^->E.#V\T1W,976_Q%D*3<.VV_
M4]7[A"HE^F7"_BDVO5D2**V;]A@M3A6*V0M,$>G]^<?VWQ:M3]6,^BD?X\A!
M^E<M;N='WY0$SR/VBPV=D9Q$W$>5L@DH.<!+$OJDQR#J)=`A?,/4N_H7F<<`
MP`8B24A'Q->94U3(@9VQ0<H:QC?<F06#&B)@G8PDP<.!2'$34XGJ-/0+^B5+
M@"5:X+A$ER(=6HN'+/J?N3YP"#L+'FJ&/N+;\(B502;]`A*8XY0$D`BT)]JP
D*#9P7=4Z`@D;M)`J"!!A$S_7$5,=;5'[&J/QULC&-MHM(``[
`
end
:eof
chmod u=rw,go-wrx image1.gif image2.gif
binarc new image.arc <image1.gif >image.arc
binarc scoop flipflop image.arc <image2.gif | binarc edit image.arc >image.arc.1
mv image.arc.1 image.arc
binarc get <image.arc >image.gif
cmp image1.gif image.gif >OUTPUT
echo ec $? >>OUTPUT
cmp image2.gif image.gif >>OUTPUT
echo ec $? >>OUTPUT
echo ----- >>OUTPUT
cat image.arc >>OUTPUT
cat >TESTCASE <<':eof'
image1.gif image.gif differ: char 1489, line 12
ec 1
ec 0
-----
#arc 2.0
Mimage.arc
Mflipflop
A1
a1:1:begin 600 binary
A1
a1:2:M1TE&.#EAD`"0`/<```````$!`0("`@,#`P0$!`4%!08&!@<'!P@("`D)"0H*
A1
a1:3:M"@L+"PP,#`T-#0X.#@\/#Q`0$!$1$1(2$A,3$Q04%!45%186%A<7%Q@8&!D9
A1
a1:4:M&1H:&AL;&QP<'!T='1X>'A\?'R`@("$A(2(B(B,C(R0D)"4E)28F)B<G)R@H
A1
a1:5:M*"DI*2HJ*BLK*RPL+"TM+2XN+B\O+S`P,#$Q,3(R,C,S,S0T-#4U-38V-C<W
A1
a1:6:M-S@X.#DY.3HZ.CL[.SP\/#T]/3X^/C\_/T!`0$%!04)"0D-#0T1$1$5%149&
A1
a1:7:M1D='1TA(2$E)24I*2DM+2TQ,3$U-34Y.3D]/3U!04%%145)24E-34U145%55
A1
a1:8:M55965E=75UA86%E965I:6EM;6UQ<7%U=75Y>7E]?7V!@8&%A86)B8F-C8V1D
A1
a1:9:M9&5E969F9F=G9VAH:&EI:6IJ:FMK:VQL;&UM;6YN;F]O;W!P<'%Q<7)R<G-S
A1
a1:10:M<W1T='5U=79V=G=W=WAX>'EY>7IZ>GM[>WQ\?'U]?7Y^?G]_?X"`@(&!@8*"
A1
a1:11:M@H.#@X2$A(6%A8:&AH>'AXB(B(F)B8J*BHN+BXR,C(V-C8Z.CH^/CY"0D)&1
A1
a1:12:MD9*2DI.3DY24E)65E9:6EI>7EYB8F)F9F9J:FIN;FYR<G)V=G9Z>GI^?GZ"@
A1
a1:13:MH*&AH:*BHJ.CHZ2DI*6EI::FIJ>GIZBHJ*FIJ:JJJJNKJZRLK*VMK:ZNKJ^O
A1
a1:14:MK["PL+&QL;*RLK.SL[2TM+6UM;:VMK>WM[BXN+FYN;JZNKN[N[R\O+V]O;Z^
A1
a1:15:MOK^_O\#`P,'!P<+"PL/#P\3$Q,7%Q<;&QL?'Q\C(R,G)R<K*RLO+R\S,S,W-
A1
a1:16:MS<[.SL_/S]#0T-'1T=+2TM/3T]34U-75U=;6UM?7U]C8V-G9V=K:VMO;V]S<
A1
a1:17:MW-W=W=[>WM_?W^#@X.'AX>+BXN/CX^3DY.7EY>;FYN?GY^CHZ.GIZ>KJZNOK
A1
a1:18:MZ^SL[.WM[>[N[N_O[_#P\/'Q\?+R\O/S\_3T]/7U]?;V]O?W]_CX^/GY^?KZ
A1
a1:19:M^OO[^_S\_/W]_?[^_O___RP`````D`"0```(_P#_"1Q(L*#!@P@3*ES(L*'#
A1
a1:20:MAQ`C2IQ(L:+%BQ@S:OSWJZ/'CR`[;AQ)LF3#/0!2JES)<H_)ES!-IF%)<V6:
A1
a1:21:MF#AS6IQ9L^9-G4"#,N39D^5/H4B3"B1:5.51I5!U,FT*X&G4JR^G-K6*M>M&
A1
a1:22:MK46Y>AV[DZI-LF@Q@NTI-JW;AFM]OIT+,2[-MG3S$K1K5*]?A'S/_AT\,+!3
A1
a1:23:MPH@-I\2+V*WBJHT'/V8<F2PDLX<KZ_V%.24DS9L[`_@%.B_GSJ1+SSV-.;5J
A1
a1:24:MM[\DH'X]%P5F!*YIH[5M%H7NMX9]_TYKV,KPM)?-4CZ.E'53E\S'.B^:._K5
A1
a1:25:MZ3VK6X>*O:;V[4E_(?\P^QT\4MY-RYL/BKXG"O7K=5JA*CP^5+Y%[$=%N54_
A1
a1:26:M=ZK+^6=2=RO!)^!+!*IDX($E)9C2@@R.)%YZ$0K5'DT05JC1A2MQD*&&&!51
A1
a1:27:M5'T@XA27#25*%5:*.248((L6)?@9C#`E^"&-$MF((X+4[3@@AP_Z*!,*1!:)
A1
a1:28:M0A$W"JGDDAO]LD<:4$8IY9110@(2DPLYV!D"1%J1QAXA720.'S"4:>:99DHA
A1
a1:29:M#DX@04+EFU*">9"6HHUX))1A,B2.:&MBU":41,I6)X9S#FIH4QR@8`.45GXT
A1
a1:30:MT)Z=2?$02$]:0>1XA[96:*:<8I:?0)!B!@-!(4%9Q*6=<OH=G:EF6E^H9HW_
A1
a1:31:MNA20K::Z:JVXKO2J:++^0VNNF=X*+*Z[=M;KK\,.*FRRJ18KZD#(,CN;0:Q*
A1
a1:32:MVY2SL4)K;:?+;FLHME0=ZVVPFXX[*+A-B6NNLN6NBQD*1\$:KK;NBM:MNUS>
A1
a1:33:MF4:>H/(ZD(CU3EM0M8?FZR68CCHD;[H#_9FAP$'"![1XJ`9&,7HG1PD7U
A1
a1:34:MJE"I:9P:;:NK/@DGG(UZA),X`QA[44B5HFJK9N*,B>;-,/`1D\,GORDGED`'
A1
D2
d1:35:M+?30(*9AY-%%OD@TO=<N#='()#J]$-12.S2RAU4S-/)H64^M:=<)S6?6*6`G
A1
D2
d1:36:M9!B295=<U"E)!DUPVT#_(C%F$L"-)7]TV[TDP0!(_\!VV@+](K9H?P/.=TH_
A1
D2
d1:37:ME_U+<G5:H?>.OSRF$MII_P)PG5A7?KEH=1N^>6>=:VYHZ(KCS?GC."YN:.:*
A1
D2
d1:38:MGX*I:)17/K=HB2O^.7F`!RYY[)6;CGON'/G^'/"!#TX5Z[F_G>)'D,P8H_$4
A1
D2
d1:39:M"OC1DQ&OA)N?G4&G7QJ"1A]C9TKK9@-FQKT,OH"&D4Y1M>'3QCA59'^/6?SZ
A1
D2
d1:40:M5?N>1=#WZ%]LV=L]X=?^R=_:)A*YSM@`=94AF/H:XB31.&]_6TL)`@K'D`9N
A1
D2
d1:41:M"8&:.<6@'`>?CHQ/-.T;SB\^6*<BL,TU'H$$"2^HH<-9STB<HE^$5#>QE#BN
A1
D2
d1:42:M1`6<V/V6=SMO+1!$EG/7#T1Q*#E.'5!(-+36OO;VBP@.B@,4W!LDNM<J"5B)
A1
D2
d1:43:J:+\XQ0H/A8(K2JTC*GR=61!@@T89KB-0@IB1BH`GD1#OC7",(_$"`@`[
A2
a2:1:M+?30&J9AY-%%OD@TO=<N#='()#J]$-12-_2+Q/15S1"K46M-[;M>*W0*9L:%
A2
a2:2:M/2?``)I-[=B:JDVJO6XW+*A9'L;-T=QF0:?V+Z?@_TV>VWP/:D622CII*.%"
A2
a2:3:M_C+?H%::_0O:HNWK.-9U(NFXWYXBOF-LAEH>-N>#>NXUZ'7^/#KEHC7^.>2W
A2
a2:4:MG:(YCH;76??>H;^^.>L`VKYYZ;KOR!]FIN^->E.#V\T1W,976_Q%D*3<.VV_
A2
a2:5:M4]7[A"HE^F7"_BDVO5D2**V;]A@M3A6*V0M,$>G]^<?VWQ:M3]6,^BD?X\A!
A2
a2:6:M^E<M;N='WY0$SR/VBPV=D9Q$W$>5L@DH.<!+$OJDQR#J)=`A?,/4N_H7F<<`
A2
a2:7:MP`8B24A'Q->94U3(@9VQ0<H:QC?<F06#&B)@G8PDP<.!2'$34XGJ-/0+^B5+
A2
a2:8:M@"5:X+A$ER(=6HN'+/J?N3YP"#L+'FJ&/N+;\(B502;]`A*8XY0$D`BT)]JP
A2
a2:9:D*#9P7=4Z`@D;M)`J"!!A$S_7$5,=;5'[&J/QULC&-MHM(``[
A1
a1:44:`
A1
a1:45:end
:eof
sdiff -l TESTCASE OUTPUT >DIFFS
if [ $? -gt 0 ]
then
echo FAIL
cat DIFFS
else
echo PASS
fi
)