Initial checkin of aroff, binprint, center, less, ls, make, makemake,

passwd, ps, purge, shutdown, stty, upper, and vi.  These sources are
for the versions of the utils shipped with GNO v2.0.4.
This commit is contained in:
gdr-ftp 1998-03-09 08:30:21 +00:00
parent d00f2dadaa
commit 784e3de7cd
121 changed files with 30383 additions and 0 deletions

13
bin/aroff/Makefile Normal file
View File

@ -0,0 +1,13 @@
#
# Makefile for aroff
# AWGS WordProc -> Text formatter
#
awgs.root: awgs.c awgs.h
compile awgs.c keep=awgs
print.root: print.c awgs.h
compile print.c keep=print
awgs: awgs.root
link awgs print 2/direct256 keep=aroff

160
bin/aroff/aroff.c Normal file
View File

@ -0,0 +1,160 @@
/*
awgs.c
Main loop driver code and awgs wordproc file read routines
*/
#pragma stacksize 2048
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <gsos.h>
#include <shell.h>
#include "awgs.h"
void fileError(char *s)
{
int err;
int cl[2];
if (err = toolerror()) {
fprintf(stderr,"%s\n",s);
ERROR(&err);
cl[0] = 1; cl[1] = 0; CloseGS(cl);
exit(1);
}
}
int noboldflag = 0;
saveArray *docSaveArray;
Ruler *docRulers;
textBlock **docTextBlocks; /* an array of textBlockPtrs */
word docSACount, numRulers, numBlocks;
void readAWGS(char *file)
{
int ref,err,z; /* refnum, err temp, and loop variable */
long recBlockSize; /* size of the upcoming text block */
int cl[2]; /* pBlock for GS/OS CloseGS call */
GSString255 f; /* converted cstring(file) -> GSString */
OpenRecGS o; /* pBlock for GS/OS Open call */
SetPositionRecGS p;
IORecGS i;
f.length = strlen(file);
strcpy(f.text,file);
o.pCount = 7;
o.pathname = &f;
o.requestAccess = readEnable;
o.resourceNumber = 0;
OpenGS(&o);
if (err = toolerror()) {
fprintf(stderr,"aroff: could not open AWGS file %s\n",file);
ERROR(&err);
exit(1);
}
ref = o.refNum;
if ((o.fileType != 0x50) || (o.auxType != 0x8010l)) {
cl[0] = 1; cl[1] = ref; CloseGS(cl);
fprintf(stderr,"aroff: file (%s) is not an AWGS file\n",file);
exit(1);
}
p.pCount = 3; p.refNum = ref; p.base = startPlus; p.displacement = 668l;
SetMarkGS(&p); fileError("SetMarkGS");
i.pCount = 4;
i.refNum = ref;
i.dataBuffer = (void *) &docSACount;
i.requestCount = 2l;
ReadGS(&i); fileError("ReadGS (docSACount)");
#ifdef DEBUG
fprintf(stderr,"Number of SaveArray entries: %d\n",docSACount);
#endif
docSaveArray = calloc((size_t) docSACount, sizeof(saveArray));
i.dataBuffer = (void *) docSaveArray;
i.requestCount = sizeof(saveArray) * docSACount;
ReadGS(&i); fileError("ReadGS (docSaveArray)");
#ifdef DEBUG
fprintf(stderr," saNum textBlock rulerNum\n");
fprintf(stderr," ----- --------- --------\n");
for (z = 0; z < docSACount; z++) {
fprintf(stderr," [%3d] %5d %5d\n",
z+1, docSaveArray[z].textBlock,docSaveArray[z].rulerNum);
}
#endif
numRulers = numBlocks = 0;
for (z = 0; z < docSACount; z++) {
if (docSaveArray[z].rulerNum+1 > numRulers)
numRulers = docSaveArray[z].rulerNum+1;
if (docSaveArray[z].textBlock+1 > numBlocks)
numBlocks = docSaveArray[z].textBlock+1;
}
#ifdef DEBUG
fprintf(stderr,"Number of Rulers: %d\n",numRulers);
fprintf(stderr,"Number of Blocks: %d\n",numBlocks);
#endif
docRulers = calloc((size_t) numRulers, sizeof(Ruler));
i.dataBuffer = (void *) docRulers;
i.requestCount = sizeof(Ruler) * numRulers;
ReadGS(&i); fileError("ReadGS (docRulers)");
docTextBlocks = calloc((size_t) numBlocks, sizeof(textBlockPtr));
for (z = 0; z < numBlocks; z++) {
i.requestCount = 4l;
i.dataBuffer = (void *) &recBlockSize;
ReadGS(&i); fileError("ReadGS (recBlockSize)");
#ifdef DEBUG
fprintf(stderr,"block %d size %8ld : ",z,recBlockSize);
#endif
docTextBlocks[z] = malloc(recBlockSize);
i.requestCount = recBlockSize;
i.dataBuffer = (void *) docTextBlocks[z];
ReadGS(&i); fileError("ReadGS (textBlock)");
}
cl[0] = 1;
cl[1] = ref;
CloseGS(cl);
}
void usage(void)
{
fprintf(stderr,"aroff [-b] file1 [file ...]\n"
"-b don't do any boldfacing (useful for GNO Ref. Manuals)\n");
exit(1);
}
int main(int argc, char *argv[])
{
int i,z;
extern void printAWGS(void);
extern int _INITGNOSTDIO();
_INITGNOSTDIO();
if (argc == 1) usage();
for (i = 1; i < argc; i++) {
if (*argv[i] == '-') {
if (argv[i][1] == 'b')
{ noboldflag = 1; continue; }
else usage();
}
readAWGS(argv[i]);
printAWGS();
free(docSaveArray);
free(docRulers);
for (z = 0; z < numBlocks; z++)
free(docTextBlocks[z]);
free(docTextBlocks);
}
}

57
bin/aroff/aroff.h Normal file
View File

@ -0,0 +1,57 @@
/*
This file contains the data structures that are
used in AWGS Word Processor files.
Data structures gleaned from DTS File Type Note TN.50.8010
*/
/* #define DEBUG */
typedef struct pgraph {
word firstFont;
byte firstStyle;
byte firstSize;
byte firstColor;
word reserved;
} pgraph, *pgraphPtr;
typedef struct textBlock {
word blockSize;
word blockUsed;
pgraphPtr pgraphs;
} textBlock, *textBlockPtr;
typedef struct tabRec {
word tabLocation;
word tabType;
} tabRec, *tabRecPtr;
#define rsFULL 0x80
#define rsRIGHT 0x40
#define rsCENTER 0x20
#define rsLEFT 0x10
#define rsNOBREAK 0x08
#define rsTRIPLE 0x04
#define rsDOUBLE 0x02
#define rsSINGLE 0x01
typedef struct Ruler {
word numParagraphs;
word statusBits;
word leftMargin;
word indentMargin;
word rightMargin;
word numTabs;
tabRec tabRecs[10];
} Ruler, *RulerPtr;
typedef struct SaveArrEntry {
word textBlock; /* Text block number */
word offset; /* offset + text block = paragraph */
word attributes; /* 0 = normal text, 1 = page break paragrf */
word rulerNum; /* #of ruler associated with this paragrf */
word pixelHeight; /* height of paragraph in pixels */
word numLines; /* # of lines in this paragraph */
} saveArray, *saveArrayPtr;
extern int noboldflag;

160
bin/aroff/awgs.c Normal file
View File

@ -0,0 +1,160 @@
/*
awgs.c
Main loop driver code and awgs wordproc file read routines
*/
#pragma stacksize 2048
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <gsos.h>
#include <shell.h>
#include "awgs.h"
void fileError(char *s)
{
int err;
int cl[2];
if (err = toolerror()) {
fprintf(stderr,"%s\n",s);
ERROR(&err);
cl[0] = 1; cl[1] = 0; CloseGS(cl);
exit(1);
}
}
int noboldflag = 0;
saveArray *docSaveArray;
Ruler *docRulers;
textBlock **docTextBlocks; /* an array of textBlockPtrs */
word docSACount, numRulers, numBlocks;
void readAWGS(char *file)
{
int ref,err,z; /* refnum, err temp, and loop variable */
long recBlockSize; /* size of the upcoming text block */
int cl[2]; /* pBlock for GS/OS CloseGS call */
GSString255 f; /* converted cstring(file) -> GSString */
OpenRecGS o; /* pBlock for GS/OS Open call */
SetPositionRecGS p;
IORecGS i;
f.length = strlen(file);
strcpy(f.text,file);
o.pCount = 7;
o.pathname = &f;
o.requestAccess = readEnable;
o.resourceNumber = 0;
OpenGS(&o);
if (err = toolerror()) {
fprintf(stderr,"aroff: could not open AWGS file %s\n",file);
ERROR(&err);
exit(1);
}
ref = o.refNum;
if ((o.fileType != 0x50) || (o.auxType != 0x8010l)) {
cl[0] = 1; cl[1] = ref; CloseGS(cl);
fprintf(stderr,"aroff: file (%s) is not an AWGS file\n",file);
exit(1);
}
p.pCount = 3; p.refNum = ref; p.base = startPlus; p.displacement = 668l;
SetMarkGS(&p); fileError("SetMarkGS");
i.pCount = 4;
i.refNum = ref;
i.dataBuffer = (void *) &docSACount;
i.requestCount = 2l;
ReadGS(&i); fileError("ReadGS (docSACount)");
#ifdef DEBUG
fprintf(stderr,"Number of SaveArray entries: %d\n",docSACount);
#endif
docSaveArray = calloc((size_t) docSACount, sizeof(saveArray));
i.dataBuffer = (void *) docSaveArray;
i.requestCount = sizeof(saveArray) * docSACount;
ReadGS(&i); fileError("ReadGS (docSaveArray)");
#ifdef DEBUG
fprintf(stderr," saNum textBlock rulerNum\n");
fprintf(stderr," ----- --------- --------\n");
for (z = 0; z < docSACount; z++) {
fprintf(stderr," [%3d] %5d %5d\n",
z+1, docSaveArray[z].textBlock,docSaveArray[z].rulerNum);
}
#endif
numRulers = numBlocks = 0;
for (z = 0; z < docSACount; z++) {
if (docSaveArray[z].rulerNum+1 > numRulers)
numRulers = docSaveArray[z].rulerNum+1;
if (docSaveArray[z].textBlock+1 > numBlocks)
numBlocks = docSaveArray[z].textBlock+1;
}
#ifdef DEBUG
fprintf(stderr,"Number of Rulers: %d\n",numRulers);
fprintf(stderr,"Number of Blocks: %d\n",numBlocks);
#endif
docRulers = calloc((size_t) numRulers, sizeof(Ruler));
i.dataBuffer = (void *) docRulers;
i.requestCount = sizeof(Ruler) * numRulers;
ReadGS(&i); fileError("ReadGS (docRulers)");
docTextBlocks = calloc((size_t) numBlocks, sizeof(textBlockPtr));
for (z = 0; z < numBlocks; z++) {
i.requestCount = 4l;
i.dataBuffer = (void *) &recBlockSize;
ReadGS(&i); fileError("ReadGS (recBlockSize)");
#ifdef DEBUG
fprintf(stderr,"block %d size %8ld : ",z,recBlockSize);
#endif
docTextBlocks[z] = malloc(recBlockSize);
i.requestCount = recBlockSize;
i.dataBuffer = (void *) docTextBlocks[z];
ReadGS(&i); fileError("ReadGS (textBlock)");
}
cl[0] = 1;
cl[1] = ref;
CloseGS(cl);
}
void usage(void)
{
fprintf(stderr,"aroff [-b] file1 [file ...]\n"
"-b don't do any boldfacing (useful for GNO Ref. Manuals)\n");
exit(1);
}
int main(int argc, char *argv[])
{
int i,z;
extern void printAWGS(void);
extern int _INITGNOSTDIO();
_INITGNOSTDIO();
if (argc == 1) usage();
for (i = 1; i < argc; i++) {
if (*argv[i] == '-') {
if (argv[i][1] == 'b')
{ noboldflag = 1; continue; }
else usage();
}
readAWGS(argv[i]);
printAWGS();
free(docSaveArray);
free(docRulers);
for (z = 0; z < numBlocks; z++)
free(docTextBlocks[z]);
free(docTextBlocks);
}
}

57
bin/aroff/awgs.h Normal file
View File

@ -0,0 +1,57 @@
/*
This file contains the data structures that are
used in AWGS Word Processor files.
Data structures gleaned from DTS File Type Note TN.50.8010
*/
/* #define DEBUG */
typedef struct pgraph {
word firstFont;
byte firstStyle;
byte firstSize;
byte firstColor;
word reserved;
} pgraph, *pgraphPtr;
typedef struct textBlock {
word blockSize;
word blockUsed;
pgraphPtr pgraphs;
} textBlock, *textBlockPtr;
typedef struct tabRec {
word tabLocation;
word tabType;
} tabRec, *tabRecPtr;
#define rsFULL 0x80
#define rsRIGHT 0x40
#define rsCENTER 0x20
#define rsLEFT 0x10
#define rsNOBREAK 0x08
#define rsTRIPLE 0x04
#define rsDOUBLE 0x02
#define rsSINGLE 0x01
typedef struct Ruler {
word numParagraphs;
word statusBits;
word leftMargin;
word indentMargin;
word rightMargin;
word numTabs;
tabRec tabRecs[10];
} Ruler, *RulerPtr;
typedef struct SaveArrEntry {
word textBlock; /* Text block number */
word offset; /* offset + text block = paragraph */
word attributes; /* 0 = normal text, 1 = page break paragrf */
word rulerNum; /* #of ruler associated with this paragrf */
word pixelHeight; /* height of paragraph in pixels */
word numLines; /* # of lines in this paragraph */
} saveArray, *saveArrayPtr;
extern int noboldflag;

157
bin/aroff/print.c Normal file
View File

@ -0,0 +1,157 @@
/*
print.c
the code that formats each individual paragraph is here.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <types.h>
#include <texttool.h>
#include "awgs.h"
extern saveArray *docSaveArray;
extern Ruler *docRulers;
extern textBlock **docTextBlocks; /* an array of textBlockPtrs */
extern word docSACount, numRulers, numBlocks;
/*
1 2
01234567890123456 7890
This is a bloody ^car
z = 16;
This is a bloody
^car
col=4 (width - z - 1)
printcol=3
*/
/* 100 lines should be more than enough */
char paraBuf[100][80];
/* given a paragraph, and a pointer to it's ruler, format the
paragraph according to the ruler. */
void printPara(RulerPtr ruler, pgraphPtr pptr)
{
char *txt;
int width,z;
int curLine, col, printcol, numctrl;
int i,left,style;
curLine = col = printcol = 0;
txt = ((char *)pptr) + sizeof(pgraph);
calcLine:
/* width determines how long this line is in characters; thus, where
the break for word wrap will occur */
if (curLine == 0) width = (ruler->rightMargin - ruler->indentMargin)/8;
else width = (ruler->rightMargin - ruler->leftMargin)/8;
while (*txt != 0x0d) {
switch (*txt) {
case 1: txt+=3; break;
case 2:
style = *(++txt);
if (noboldflag) { ++txt; break; }/* turn off boldfacing */
if (style & 3) paraBuf[curLine][col++] = 15;
else paraBuf[curLine][col++] = 14;
txt++;
break;
case 3: txt+=2; break;
case 4: txt+=2; break;
case 5:
case 6:
case 7: break;
default:
if (printcol == width) {
numctrl = 0;
for (z = col - 1; z > 0; z--) {
if (paraBuf[curLine][z] == ' ') {
if (z != col - 1)
memcpy(&paraBuf[curLine+1][0],&paraBuf[curLine][z+1],
(size_t) (col - z - 1));
paraBuf[curLine][z] = 0;
curLine++; printcol -= (z + 1 + numctrl);
col -= (z + 1);
goto calcLine;
}
else if (paraBuf[curLine][z] < ' ') numctrl++;
}
curLine++; col = printcol = 0;
/* one big word... don't break line */
goto calcLine;
}
paraBuf[curLine][col] = *(txt++);
printcol++; col++;
}
}
paraBuf[curLine][col] = 0;
for (z = 0; z <= curLine; z++) {
if (z == 0) {
width = (ruler->rightMargin - ruler->indentMargin)/8;
left = (ruler->indentMargin)/8;
}
else {
width = (ruler->rightMargin - ruler->leftMargin)/8;
left = (ruler->leftMargin)/8;
}
for (i = 0; i < left; i++) putchar(' ');
printf("%s\n",paraBuf[z]);
}
}
/* this is an obsolete routine that prints a paragraph with no
formatting at all */
#ifdef NOTDEFINED
void printPara(RulerPtr ruler, pgraphPtr pptr)
{
char *txt;
txt = ((char *)pptr) + sizeof(pgraph);
while (*txt != 0x0D) {
switch (*txt) {
case 1: txt+=2; break;
case 2: txt++; break;
case 3: txt++; break;
case 4: txt++; break;
case 5:
case 6:
case 7: break;
default: putchar(*txt);
}
txt++;
}
putchar('\n');
}
#endif
/* go through each textBlock, sending each paragraph in turn to printPara. */
void printAWGS(void)
{
int z;
pgraphPtr pptr;
char *txt;
char x;
for (z = 0; z < docSACount; z++) {
pptr = (pgraphPtr) (((byte *)docTextBlocks[docSaveArray[z].textBlock])
+ docSaveArray[z].offset);
#ifdef DEBUG
fprintf(stderr,"[%d] offset %d paragraph : %08lX",z,docSaveArray[z].offset,
pptr);
fprintf(stderr," textBlock: %08lX\n",docTextBlocks[docSaveArray[z].textBlock]);
#endif
printPara(&docRulers[docSaveArray[z].rulerNum],pptr);
}
}

8
bin/binprint/Makefile Normal file
View File

@ -0,0 +1,8 @@
binprint.a: binprint.c
compile -p binprint.c keep=binprint
bprasm.a: binprint.asm
compile -p binprint.asm
binprint: binprint.a bprasm.a
link -p binprint bprasm keep=binprint

123
bin/binprint/binprint.asm Normal file
View File

@ -0,0 +1,123 @@
case on
keep bprasm
doline start
pha
tsc
phd
tcd
phb
phk
plb
counter equ 1
RTLs equ 3
dest equ 6
source equ 10
cols equ 14
actual equ 16
PREVIOUS equ 18
pei actual
stz counter
ldy #0
loop anop
lda [source],y
jsr puthex
iny
dec cols
dec actual
bne loop
ldy counter
loop2 lda cols
beq done
lda #$2020
sta [dest],y
iny
sta [dest],y
iny
iny
dec cols
bra loop2
done anop
pla
sta actual
tya
clc
inc a
adc actual
sta counter
ldy actual
chrloop dey
cpy #$ffff
beq endloop
lda [source],y
and #$ff
cmp #$7f
bcs noprint
cmp #$20
bcs printable
noprint lda #'.'
printable sep #$20
sta [source],y
rep #$20
bra chrloop
endloop ldy actual
dey
lda [source],y
and #$00ff
ora #$0d00
sta [source],y
ldy counter
plb
lda 4
sta PREVIOUS-2
lda 3
sta PREVIOUS-3
pld
tsc
clc
adc #PREVIOUS-4
tcs
tya
rtl
end
puthex private
counter equ 1
RTLs equ 3
dest equ 6
source equ 10
cols equ 14
phy
ldy counter
pha
lsr a
lsr a
lsr a
lsr a
and #$f
tax
lda hexdigits,x
sta [<dest],y
iny
pla
and #$f
tax
lda hexdigits,x
and #$00ff
ora #$2000
sta [<dest],y
iny
iny
sty counter
ply
rts
end
hexdigits privdata
dc c'0123456789ABCDEF'
end

107
bin/binprint/binprint.c Normal file
View File

@ -0,0 +1,107 @@
/*
BINPRINT.C
Displays files in hex-dump format (with ascii subdisplay if desired)
v1.2 Optimized and fixed input from terminal bug (pv)
v1.1 Added stacksize directive (jb)
v1.0 Original version by Derek Taubert
*/
#pragma optimize -1
#pragma stacksize 1024
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
extern FILE *fdopen(int,char *);
unsigned int doline(char *dest, char *source,
unsigned int actual, unsigned int cols);
unsigned char *buffer2;
main(argc,argv)
int argc;
char **argv;
{
int duh;
int a;
int c,errflg = 0,columns = 16;
size_t pos = 0;
unsigned char *buffer;
extern char *optarg;
extern int optind;
extern int getopt(int,char **,char*);
while ((c = getopt(argc,argv, "Vc:")) != EOF)
switch (c) {
case 'c' :
columns = atoi(optarg);
break;
case 'V' :
fprintf(stdout, "binprint v1.2 for GNO/ME\n");
exit(0);
default : errflg++;
}
if (errflg) {
fprintf(stderr,"usage: binprint [-c<columns>] files...\n");
exit(2);
}
argv += optind;
if (columns < 8) columns = 8;
if ((buffer2 = (unsigned char *)malloc((size_t)(columns*4)+1)) == NULL) {
fprintf(stderr,"Cannot allocate buffer space\n");
exit(1);
}
buffer = (unsigned char *)(buffer2+(columns*3));
if (optind == argc) {
duh = STDIN_FILENO;
goto action;
}
for (;optind<argc;optind++) {
if ((duh = open(*argv,O_RDONLY|O_BINARY)) == -1) {
fprintf(stderr,"error opening %s\n",*argv);
exit(1);
}
printf("\n%s\n",*argv);
action: while ((a = (int)read(duh, buffer,
(size_t)(columns * sizeof(unsigned char)))) != 0) {
printGood(pos,buffer,a,columns);
pos += a;
}
close(duh);
}
free(buffer);
free(buffer2);
exit(0);
}
printGood(off,buf,real,form)
long off;
unsigned char *buf;
int real;
int form;
{
if (!real) return;
/*
printf("%8lX: ",off);
*/
/* The following is a hack required because of buffering by the stdio
libraries. I wish it was not necesary... */
{
static char puthere[11];
int howmany;
howmany = sprintf(puthere,"%8lX: ",off);
write(STDOUT_FILENO, puthere, (size_t)howmany);
}
write(STDOUT_FILENO, buffer2, (size_t)doline(buffer2,buf,form,real));
}

123
bin/binprint/doline.asm Normal file
View File

@ -0,0 +1,123 @@
case on
keep bprasm
doline start
pha
tsc
phd
tcd
phb
phk
plb
counter equ 1
RTLs equ 3
dest equ 6
source equ 10
cols equ 14
actual equ 16
PREVIOUS equ 18
pei actual
stz counter
ldy #0
loop anop
lda [source],y
jsr puthex
iny
dec cols
dec actual
bne loop
ldy counter
loop2 lda cols
beq done
lda #$2020
sta [dest],y
iny
sta [dest],y
iny
iny
dec cols
bra loop2
done anop
pla
sta actual
tya
clc
inc a
adc actual
sta counter
ldy actual
chrloop dey
cpy #$ffff
beq endloop
lda [source],y
and #$ff
cmp #$7f
bcs noprint
cmp #$20
bcs printable
noprint lda #'.'
printable sep #$20
sta [source],y
rep #$20
bra chrloop
endloop ldy actual
dey
lda [source],y
and #$00ff
ora #$0d00
sta [source],y
ldy counter
plb
lda 4
sta PREVIOUS-2
lda 3
sta PREVIOUS-3
pld
tsc
clc
adc #PREVIOUS-4
tcs
tya
rtl
end
puthex private
counter equ 1
RTLs equ 3
dest equ 6
source equ 10
cols equ 14
phy
ldy counter
pha
lsr a
lsr a
lsr a
lsr a
and #$f
tax
lda hexdigits,x
sta [<dest],y
iny
pla
and #$f
tax
lda hexdigits,x
and #$00ff
ora #$2000
sta [<dest],y
iny
iny
sty counter
ply
rts
end
hexdigits privdata
dc c'0123456789ABCDEF'
end

5
bin/center/Makefile Normal file
View File

@ -0,0 +1,5 @@
center.a: center.c
compile center.c keep=center
center: center.a
link center 2/direct256 keep=center

133
bin/center/center.c Normal file
View File

@ -0,0 +1,133 @@
/* "center", (c) 1992 Marek Pawlowski. v1.0
Takes input from stdin, center's it, and puts it to
stdout.
Usage: center [Columns] [File]
Columns The number of columns are to be considered
"full-screen" for centering. Default 80.
File Stream to read input from. Default stdin.
This utility is in the public domain, along with
source code. Munge at will. Contact author for
redistribution rights, or inclusion in package.
Credit to Marek Pawlowski must be retained in
modified source code.
I'd like to see what you did to my source code, when
you change it. Correspond with the author (Marek
Pawlowski) at the following Email addresses:
marekp@pnet91.cts.com
marekp@cerf.net
*/
#pragma stacksize 1024
#include <stdio.h>
#include <ctype.h>
#define VERSION "1.00"
char input[81];
char output[81];
main(argc, argv)
int argc;
char **argv;
{
int t, i, x, s, fflag;
FILE *in;
/* _INITGNOSTDIO();
setvbuf(stdin,NULL,_IOLBF,256l); */
if (argc > 3)
usage(argv[0]);
s = 1;
if(argc > 1) {
for(x = 0 ; x <= (strlen(argv[1])-1) ; x++) {
s = isdigit(argv[1][x]);
t = atoi(argv[1]);
}
}
else if (argc == 1)
t = 80;
fflag = 0;
if (argc == 3) {
in = fopen(argv[2], "r");
if(!in) error(argv[1], argv[2]);
fflag = 1;
}
if(s != 0) {
if(fflag == 1)
center(in, t);
else
center(stdin, t);
}
else
usage(argv[0]);
}
/* Function to call on other subroutines to result in a completely
centered line! */
center(stream, t)
FILE *stream;
int t;
{
int x, i;
while(feof(stream) == 0) {
fgets(input, 80, stream);
i = (t - strlen(input)) / 2;
fillit(i, 0);
for(x = 0 ; x <= strlen(input) ; x++)
output[i+x] = input[x];
if(feof(stream) == 0)
fputs(output, stdout);
}
}
/* Function to tell the person that the filename offered
not be opened for reading */
error(name, file)
char *name;
char *file;
{
fprintf(stderr, "%s: cannot open %s\n", name, file);
exit(0);
}
/* Function to display the usage of the utility */
usage(file)
char *file;
{
fprintf(stderr, "Usage: %s [columns] [file]\n", file);
exit(0);
}
/* Function to fill in the left side of text with the appropriate
number of spaces */
fillit(ntf, start)
int ntf; /* Number To Fill */
int start; /* Start filling at.. */
{
int x;
for(x = start ; x <= ntf ; x++) {
output[x] = ' ';
}
}

71
bin/less/CHANGES Normal file
View File

@ -0,0 +1,71 @@
Well, first off:
we are: Mike Horwath
James Brookes
Dave Huang
5/12/92
Jawaid bitched about some stack overflowing, so, between us both, we searched
diligently for the error. Inside one of the functions, there was a stack
allocated variable over 2K in size. So, the fix was to make it a static
variable, so that it is gloabally allocated from normal memory, instead of the
stack. That error is now fixed.
Jawaid also has fixed the getenv() library call, and that was the problem with
using a $editor variable in LESS. That is now fixed.
Less now also works with either files terminated with lf's (unix normal) or
cr's (Apple IIgs normal). Works GREAT.
Fixed a bug where pipes would cause a problem if you shelled out '!' (alone),
added GS/OS specific code to take care of which stdin to use, either the pipe
or normal stuff...
5/11/92
Well, with big help from Jawaid "The God" Bazyar, piping and redirection are
now working correctly. Problems stemmed from file descriptors being set to
numbers that were not correct, meaning that, it was trying to write to the
input of a pipe or stdin.
JB put assembly into the putchr() and putstr() calls, noticable speed increase
and some savings on disk.
It prints the control codes by default, so that when you use man, it will do
things like inverse and the like correctly.
did a #pragma noroot so that it cuts off about 1K of exec file. Kind of nice
of jawaid to tell me this. Nice little savings I must say.
Reset the stacksize from 4.5K to 1K, as I was wrong about the stack usage.
Thanks go to jawaid for this bit of news also.
5/5/92
Well, another change this time to prchr(), so that you can pass terrible
command lines, and have them done right. Problem came from not outputing the
right escape type character for end of line stuff. So, that now works. NOW, I
only wish I had a terminal to test all this on, hope everythign is fine, if not
we are screwed for alot of work here.
Made the default as -e (let you hit space or return to quit when at eof) and
-m (medium prompt line, shows you the file you are viewing, nothing more).
5/4/92
changed most of the open()'s to use the correct modes of the file. solves
errors with coming back from vi and such.
changed the stacksize from default of 8K to 4.5K, seems to work like a dream.
put in an optimize -1 into the code.
Worked on the lsystem() call, as it is really messed in the head. Hopefully,
by the time you have read this, it will be written from scratch, and working
as it should.
5/3/92-5/4/92
Dave fixed all the problems with \n and \r's being wrong in places.
Dave also fixed the gno termcap entry, as sr and sl (am I right?) were not
correct for less to work right.
5/2/92-5/4/92
James and Dave did all the prototyping into the sourcecode.

16
bin/less/Info Normal file
View File

@ -0,0 +1,16 @@
Okay, less, for GNO:
if you use the newest version of MAN (v1.6), then set pager=less will let you
use less as your pager.
copy less.hlp to 31:bin so that less can find its help file.
copy less to 31:bin and type rehash to get it updated in your path.
Thats all there is to it, enjoy.
many thanks go to Jawaid Bazyar for his assembly added to 2 routines for screen
updating, as it was a major speed increase.
the termcap file included is fixed for less and alot of other utilities.
please, copy this to your 31:etc directory or there will be problems.

104
bin/less/Makefile Normal file
View File

@ -0,0 +1,104 @@
o/gsos.a: gsos.c
compile gsos.c keep=o/gsos
o/ttyin.a: ttyin.c less.h defines.h proto.h
compile ttyin.c keep=o/ttyin
o/edit.a: edit.c less.h defines.h proto.h
compile edit.c keep=o/edit
o/lsystem.a: lsystem.c less.h defines.h proto.h position.h
compile lsystem.c keep=o/lsystem
o/line.a: line.c less.h defines.h proto.h
compile line.c keep=o/line
o/help.a: help.c less.h defines.h proto.h
compile help.c keep=o/help
o/output.a: output.c less.h defines.h proto.h
compile output.c keep=o/output
o/position.a: position.c less.h defines.h proto.h position.h
compile position.c keep=o/position
o/tags.a: tags.c less.h defines.h proto.h
compile tags.c keep=o/tags
o/input.a: input.c less.h defines.h proto.h
compile input.c keep=o/input
o/command.a: command.c less.h defines.h proto.h position.h option.h cmd.h
compile command.c keep=o/command
o/optfunc.a: optfunc.c less.h defines.h proto.h option.h
compile optfunc.c keep=o/optfunc
o/screen.a: screen.c less.h defines.h proto.h
compile screen.c keep=o/screen
o/jump.a: jump.c less.h defines.h proto.h position.h
compile jump.c keep=o/jump
o/ifile.a: ifile.c less.h defines.h proto.h
compile ifile.c keep=o/ifile
o/charset.a: charset.c less.h defines.h proto.h
compile charset.c keep=o/charset
o/search.a: search.c less.h defines.h proto.h position.h
compile search.c keep=o/search
o/mark.a: mark.c less.h defines.h proto.h position.h
compile mark.c keep=o/mark
o/os.a: os.c less.h defines.h proto.h
compile os.c keep=o/os
o/main.a: main.c less.h defines.h proto.h position.h
compile main.c keep=o/main
o/option.a: option.c less.h defines.h proto.h option.h
compile option.c keep=o/option
o/opttbl.a: opttbl.c less.h defines.h proto.h option.h
compile opttbl.c keep=o/opttbl
o/forwback.a: forwback.c less.h defines.h proto.h position.h
compile forwback.c keep=o/forwback
o/version.a: version.c less.h defines.h proto.h
compile version.c keep=o/version
o/signal.a: signal.c less.h defines.h proto.h
compile signal.c keep=o/signal
o/cmdbuf.a: cmdbuf.c less.h defines.h proto.h
compile cmdbuf.c keep=o/cmdbuf
o/linenum.a: linenum.c less.h defines.h proto.h position.h
compile linenum.c keep=o/linenum
o/ch.a: ch.c less.h defines.h proto.h
compile ch.c keep=o/ch
o/decode.a: decode.c less.h defines.h proto.h cmd.h
compile decode.c keep=o/decode
o/filename.a: filename.c less.h defines.h proto.h
compile filename.c keep=o/filename
o/prompt.a: prompt.c less.h defines.h proto.h position.h
compile prompt.c keep=o/prompt
o/brac.a: brac.c less.h defines.h proto.h position.h
compile brac.c keep=o/brac
less: o/BRAC.A o/FILENAME.A o/LINENUM.A o/OS.A o/TAGS.A o/CH.A o/FORWBACK.A \
o/LSYSTEM.A o/OUTPUT.A o/TTYIN.A o/CHARSET.A o/HELP.A o/MAIN.A \
o/POSITION.A o/VERSION.A o/CMDBUF.A o/IFILE.A o/MARK.A o/PROMPT.A \
o/COMMAND.A o/INPUT.A o/OPTFUNC.A o/SCREEN.A o/DECODE.A o/JUMP.A \
o/OPTION.A o/SEARCH.A o/EDIT.A o/LINE.A o/OPTTBL.A o/SIGNAL.A o/GSOS.A
purge
compile linkscr
purge

94
bin/less/brac.c Normal file
View File

@ -0,0 +1,94 @@
/*
* Routines to perform bracket matching functions.
*/
#pragma noroot
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
/*
* Try to match the n-th open bracket
* which appears in the top displayed line (forwdir),
* or the n-th close bracket
* which appears in the bottom displayed line (!forwdir).
* The characters which serve as "open bracket" and
* "close bracket" are given.
*/
public void match_brac(obrac, cbrac, forwdir, n)
register int obrac;
register int cbrac;
int forwdir;
int n;
{
register int c;
register int nest;
POSITION pos;
int (*chget)();
extern int ch_forw_get(), ch_back_get();
/*
* Seek to the line containing the open bracket.
* This is either the top or bottom line on the screen,
* depending on the type of bracket.
*/
pos = position((forwdir) ? TOP : BOTTOM);
if (pos == NULL_POSITION || ch_seek(pos))
{
if (forwdir)
error("Nothing in top line", NULL_PARG);
else
error("Nothing in bottom line", NULL_PARG);
return;
}
/*
* Look thru the line to find the open bracket to match.
*/
do
{
/* if ((c = ch_forw_get()) == '\n' || c == EOI) */
if ((c = ch_forw_get()) == '\r' || c == EOI)
{
if (forwdir)
error("No bracket in top line", NULL_PARG);
else
error("No bracket in bottom line", NULL_PARG);
return;
}
} while (c != obrac || --n > 0);
/*
* Position the file just "after" the open bracket
* (in the direction in which we will be searching).
* If searching forward, we are already after the bracket.
* If searching backward, skip back over the open bracket.
*/
if (!forwdir)
(void) ch_back_get();
/*
* Search the file for the matching bracket.
*/
chget = (forwdir) ? ch_forw_get : ch_back_get;
nest = 0;
while ((c = (*chget)()) != EOI)
{
if (c == obrac)
nest++;
else if (c == cbrac && --nest < 0)
{
/*
* Found the matching bracket.
* If searching backward, put it on the top line.
* If searching forward, put it on the bottom line.
*/
jump_line_loc(ch_tell(), forwdir ? -1 : 1);
return;
}
}
error("No matching bracket", NULL_PARG);
}

576
bin/less/ch.c Normal file
View File

@ -0,0 +1,576 @@
/*
* Low level character input from the input file.
* We use these special purpose routines which optimize moving
* both forward and backward from the current read pointer.
*/
#pragma noroot
#include "less.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#include <fcntl.h>
#endif
public int file = -1; /* File descriptor of the input file */
public int ignore_eoi;
/*
* Pool of buffers holding the most recently used blocks of the input file.
*/
#ifdef BUFSIZ
#undef BUFSIZ
#define BUFSIZ 1840 /* was 1024, but 80x23 == 1840 */
#endif
struct buf {
struct buf *next, *prev; /* Must be first to match struct filestate */
long block;
unsigned int datasize;
unsigned char data[BUFSIZ];
};
/*
* The buffer pool is kept as a doubly-linked circular list,
* in order from most- to least-recently used.
* The circular list is anchored by the file state "thisfile".
*
* The file state is maintained in a filestate structure.
* There are two such structures, one used when input is a pipe
* and the other when input is an ordinary file.
* This is so that we can leave a pipe, look and other files,
* and return to the pipe without losing buffered data.
* Buffered data can be reconstructed for a non-pipe file by
* simply re-reading the file, but a pipe cannot be re-read.
*/
struct filestate {
struct buf *next, *prev; /* Must be first to match struct buf */
POSITION fpos;
int nbufs;
long block;
int offset;
POSITION fsize;
};
#define END_OF_CHAIN ((struct buf *)thisfile)
#define buf_head thisfile->next
#define buf_tail thisfile->prev
#define ch_nbufs thisfile->nbufs
#define ch_block thisfile->block
#define ch_offset thisfile->offset
#define ch_fpos thisfile->fpos
#define ch_fsize thisfile->fsize
static struct filestate pipefile =
{ (struct buf *)&pipefile, (struct buf *)&pipefile };
static struct filestate nonpipefile =
{ (struct buf *)&nonpipefile, (struct buf *)&nonpipefile };
static struct filestate *thisfile;
extern int ispipe;
extern int autobuf;
extern int sigs;
#if LOGFILE
extern int logfile;
extern char *namelogfile;
#endif
static int fch_get(void);
static int buffered(long block);
static int ch_addbuf(int nnew);
/*
* Get the character pointed to by the read pointer.
* ch_get() is a macro which is more efficient to call
* than fch_get (the function), in the usual case
* that the block desired is at the head of the chain.
*/
#define ch_get() ((ch_block == buf_head->block && \
ch_offset < buf_head->datasize) ? \
buf_head->data[ch_offset] : fch_get())
static int
fch_get(void)
{
register struct buf *bp;
register int n;
register int slept;
POSITION pos;
POSITION len;
slept = 0;
/*
* Look for a buffer holding the desired block.
*/
for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
if (bp->block == ch_block)
{
if (ch_offset >= bp->datasize)
/*
* Need more data in this buffer.
*/
goto read_more;
goto found;
}
/*
* Block is not in a buffer.
* Take the least recently used buffer
* and read the desired block into it.
* If the LRU buffer has data in it,
* and autobuf is true, and input is a pipe,
* then try to allocate a new buffer first.
*/
if (autobuf && ispipe && buf_tail->block != (long)(-1))
if (ch_addbuf(1))
/*
* Allocation failed: turn off autobuf.
*/
autobuf = 0;
bp = buf_tail;
bp->block = ch_block;
bp->datasize = 0;
read_more:
pos = (ch_block * BUFSIZ) + bp->datasize;
if ((len = ch_length()) != NULL_POSITION && pos >= len)
/*
* At end of file.
*/
return (EOI);
if (pos != ch_fpos)
{
/*
* Not at the correct position: must seek.
* If input is a pipe, we're in trouble (can't seek on a pipe).
* Some data has been lost: just return "?".
*/
if (ispipe)
return ('?');
if (lseek(file, (offset_t)pos, 0) == BAD_LSEEK)
{
error("seek error", NULL_PARG);
quit(1);
}
ch_fpos = pos;
}
/*
* Read the block.
* If we read less than a full block, that's ok.
* We use partial block and pick up the rest next time.
*/
n = iread(file, &bp->data[bp->datasize],
(unsigned int)(BUFSIZ - bp->datasize));
if (n == READ_INTR)
return (EOI);
if (n < 0)
{
error("read error", NULL_PARG);
quit(1);
}
ch_fpos += n;
#if LOGFILE
/*
* If we have a log file, write the new data to it.
*/
if (logfile >= 0 && n > 0)
write(logfile, (char *) &bp->data[bp->datasize], n);
#endif
bp->datasize += n;
/*
* If we have read to end of file, set ch_fsize to indicate
* the position of the end of file.
*/
if (n == 0)
{
ch_fsize = pos;
if (ignore_eoi)
{
/*
* We are ignoring EOF.
* Wait a while, then try again.
*/
if (!slept)
ierror("Waiting for data", NULL_PARG);
sleep(1);
slept = 1;
}
if (sigs)
return (EOI);
}
found:
if (buf_head != bp)
{
/*
* Move the buffer to the head of the buffer chain.
* This orders the buffer chain, most- to least-recently used.
*/
bp->next->prev = bp->prev;
bp->prev->next = bp->next;
bp->next = buf_head;
bp->prev = END_OF_CHAIN;
buf_head->prev = bp;
buf_head = bp;
}
if (ch_offset >= bp->datasize)
/*
* After all that, we still don't have enough data.
* Go back and try again.
*/
goto read_more;
return (bp->data[ch_offset]);
}
#if LOGFILE
/*
* Close the logfile.
* If we haven't read all of standard input into it, do that now.
*/
public void
end_logfile(void)
{
static int tried = 0;
if (logfile < 0)
return;
if (!tried && ch_fsize == NULL_POSITION)
{
tried = 1;
ierror("Finishing logfile", NULL_PARG);
while (ch_forw_get() != EOI)
if (sigs)
break;
}
close(logfile);
logfile = -1;
namelogfile = NULL;
}
/*
* Start a log file AFTER less has already been running.
* Invoked from the - command; see toggle_option().
* Write all the existing buffered data to the log file.
*/
public void
sync_logfile(void)
{
register struct buf *bp;
long block;
long last_block;
last_block = (ch_fpos + BUFSIZ - 1) / BUFSIZ;
for (block = 0; block <= last_block; block++)
for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
if (bp->block == block)
{
write(logfile, (char *) bp->data, bp->datasize);
break;
}
}
#endif
/*
* Determine if a specific block is currently in one of the buffers.
*/
static int
buffered(block)
long block;
{
register struct buf *bp;
for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
if (bp->block == block)
return (1);
return (0);
}
/*
* Seek to a specified position in the file.
* Return 0 if successful, non-zero if can't seek there.
*/
public int
ch_seek(pos)
register POSITION pos;
{
long new_block;
POSITION len;
len = ch_length();
if (pos < ch_zero() || (len != NULL_POSITION && pos > len))
return (1);
new_block = pos / BUFSIZ;
if (ispipe && pos != ch_fpos && !buffered(new_block))
return (1);
/*
* Set read pointer.
*/
ch_block = new_block;
ch_offset = pos % BUFSIZ;
return (0);
}
/*
* Seek to the end of the file.
*/
public int
ch_end_seek(void)
{
POSITION len;
if (!ispipe)
ch_fsize = filesize(file);
len = ch_length();
if (len != NULL_POSITION)
return (ch_seek(len));
/*
* Do it the slow way: read till end of data.
*/
while (ch_forw_get() != EOI)
if (sigs)
return (1);
return (0);
}
/*
* Seek to the beginning of the file, or as close to it as we can get.
* We may not be able to seek there if input is a pipe and the
* beginning of the pipe is no longer buffered.
*/
public int
ch_beg_seek(void)
{
register struct buf *bp, *firstbp;
/*
* Try a plain ch_seek first.
*/
if (ch_seek(ch_zero()) == 0)
return (0);
/*
* Can't get to position 0.
* Look thru the buffers for the one closest to position 0.
*/
firstbp = bp = buf_head;
if (bp == END_OF_CHAIN)
return (1);
while ((bp = bp->next) != END_OF_CHAIN)
if (bp->block < firstbp->block)
firstbp = bp;
ch_block = firstbp->block;
ch_offset = 0;
return (0);
}
/*
* Return the length of the file, if known.
*/
public POSITION
ch_length(void)
{
if (ignore_eoi)
return (NULL_POSITION);
return (ch_fsize);
}
/*
* Return the current position in the file.
*/
#define tellpos(blk,off) ((POSITION)((((long)(blk)) * BUFSIZ) + (off)))
public POSITION
ch_tell(void)
{
return (tellpos(ch_block, ch_offset));
}
/*
* Get the current char and post-increment the read pointer.
*/
public int
ch_forw_get(void)
{
register int c;
c = ch_get();
if (c == EOI)
return (EOI);
if (ch_offset < BUFSIZ-1)
ch_offset++;
else
{
#if __ZOFFSET /* NOT WORKING */
if (ch_fsize != NULL_POSITION &&
tellpos(ch_block+1, 0) >= ch_fsize)
return (EOI);
#endif
ch_block ++;
ch_offset = 0;
}
return (c);
}
/*
* Pre-decrement the read pointer and get the new current char.
*/
public int
ch_back_get(void)
{
if (ch_offset > 0)
ch_offset --;
else
{
#if __ZOFFSET /* NOT WORKING */
if (tellpos(ch_block-1, BUFSIZ-1) < ch_zero())
return (EOI);
#else
if (ch_block <= 0)
return (EOI);
#endif
if (ispipe && !buffered(ch_block-1))
return (EOI);
ch_block--;
ch_offset = BUFSIZ-1;
}
return (ch_get());
}
/*
* Allocate buffers.
* Caller wants us to have a total of at least want_nbufs buffers.
*/
public int
ch_nbuf(want_nbufs)
int want_nbufs;
{
PARG parg;
if (ch_nbufs < want_nbufs && ch_addbuf(want_nbufs - ch_nbufs))
{
/*
* Cannot allocate enough buffers.
* If we don't have ANY, then quit.
* Otherwise, just report the error and return.
*/
parg.p_int = want_nbufs - ch_nbufs;
error("Cannot allocate %d buffers", &parg);
if (ch_nbufs == 0)
quit(1);
}
return (ch_nbufs);
}
/*
* Flush any saved file state, including buffer contents.
*/
public void
ch_flush(void)
{
register struct buf *bp;
if (ispipe)
{
/*
* If input is a pipe, we don't flush buffer contents,
* since the contents can't be recovered.
*/
ch_fsize = NULL_POSITION;
return;
}
/*
* Initialize all the buffers.
*/
for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
bp->block = (long)(-1);
/*
* Figure out the size of the file, if we can.
*/
ch_fsize = filesize(file);
/*
* Seek to a known position: the beginning of the file.
*/
ch_fpos = 0;
ch_block = ch_fpos / BUFSIZ;
ch_offset = ch_fpos % BUFSIZ;
if (lseek(file, (offset_t)0, 0) == BAD_LSEEK)
{
/*
* Warning only; even if the seek fails for some reason,
* there's a good chance we're at the beginning anyway.
* {{ I think this is bogus reasoning. }}
*/
error("seek error to 0", NULL_PARG);
}
}
/*
* Allocate some new buffers.
* The buffers are added to the tail of the buffer chain.
*/
static int
ch_addbuf(nnew)
int nnew;
{
register struct buf *bp;
register struct buf *newbufs;
/*
* We don't have enough buffers.
* Allocate some new ones.
*/
newbufs = (struct buf *) calloc(nnew, sizeof(struct buf));
if (newbufs == NULL)
return (1);
/*
* Initialize the new buffers and link them together.
* Link them all onto the tail of the buffer list.
*/
ch_nbufs += nnew;
for (bp = &newbufs[0]; bp < &newbufs[nnew]; bp++)
{
bp->next = bp + 1;
bp->prev = bp - 1;
bp->block = (long)(-1);
}
newbufs[nnew-1].next = END_OF_CHAIN;
newbufs[0].prev = buf_tail;
buf_tail->next = &newbufs[0];
buf_tail = &newbufs[nnew-1];
return (0);
}
/*
* Use the pipe file state.
*/
public void
ch_pipe(void)
{
thisfile = &pipefile;
}
/*
* Use the non-pipe file state.
*/
public void
ch_nonpipe(void)
{
thisfile = &nonpipefile;
}

212
bin/less/charset.c Normal file
View File

@ -0,0 +1,212 @@
/*
* Functions to define the character set
* and do things specific to the character set.
*/
#pragma noroot
#include "less.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
/*
* Predefined character sets,
* selected by the LESSCHARSET environment variable.
*/
struct charset {
char *name;
char *desc;
} charsets[] = {
{ "ascii", "8bcccbcc18b95.b" },
{ "latin1", "8bcccbcc18b95.33b." },
{ NULL }
};
#define IS_BINARY_CHAR 01
#define IS_CONTROL_CHAR 02
static char chardef[256];
static char *binfmt = "\\%o";
public int binattr = BLINK;
extern char *getenv(char *);
static void ichardef(char *s);
static int icharset(char *name);
/*
* Define a charset, given a description string.
* The string consists of 256 letters,
* one for each character in the charset.
* If the string is shorter than 256 letters, missing letters
* are taken to be identical to the last one.
* A decimal number followed by a letter is taken to be a
* repetition of the letter.
*
* Each letter is one of:
* . normal character
* b binary character
* c control character
*/
static void
ichardef(s)
char *s;
{
register char *cp;
register int n;
register char v;
n = 0;
cp = chardef;
while (*s != '\0')
{
switch (*s++)
{
case '.':
v = 0;
break;
case 'c':
v = IS_CONTROL_CHAR;
break;
case 'b':
v = IS_BINARY_CHAR|IS_CONTROL_CHAR;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = (10 * n) + (s[-1] - '0');
continue;
default:
error("invalid chardef", NULL_PARG);
quit(1);
/*NOTREACHED*/
}
do
{
if (cp >= chardef + sizeof(chardef))
{
error("chardef longer than 256", NULL_PARG);
quit(1);
/*NOTREACHED*/
}
*cp++ = v;
} while (--n > 0);
n = 0;
}
while (cp < chardef + sizeof(chardef))
*cp++ = v;
}
/*
* Define a charset, given a charset name.
* The valid charset names are listed in the "charsets" array.
*/
static int
icharset(name)
register char *name;
{
register struct charset *p;
if (name == NULL || *name == '\0')
return (0);
for (p = charsets; p->name != NULL; p++)
{
if (strcmp(name, p->name) == 0)
{
ichardef(p->desc);
return (1);
}
}
error("invalid charset name", NULL_PARG);
quit(1);
/*NOTREACHED*/
}
/*
* Initialize charset data structures.
*/
public void
init_charset(void)
{
register char *s;
/*
* Try environment variable LESSCHARSET.
* If LESSCHARSET is not set, try LESSCHARDEF.
* If LESSCHARDEF is not set, default to "ascii" charset.
*/
s = getenv("LESSCHARSET");
if (icharset(s))
return;
s = getenv("LESSCHARDEF");
if (s != NULL && *s != '\0')
{
ichardef(s);
return;
}
(void) icharset("ascii");
s = getenv("LESSBINFMT");
if (s != NULL && *s != '\0')
{
if (*s == '*')
{
switch (s[1])
{
case 'd': binattr = BOLD; break;
case 'k': binattr = BLINK; break;
case 'u': binattr = UNDERLINE; break;
default: binattr = NORMAL; break;
}
s += 2;
}
if (*s != '\0')
binfmt = s;
}
}
/*
* Is a given character a "binary" character?
*/
public int
binary_char(c)
int c;
{
return (chardef[c] & IS_BINARY_CHAR);
}
/*
* Is a given character a "control" character?
*/
public int
control_char(c)
int c;
{
return (chardef[c] & IS_CONTROL_CHAR);
}
/*
* Return the printable form of a character.
* For example, in the "ascii" charset '\3' is printed as "^C".
*/
public char *
prchar(c)
int c;
{
static char buf[8];
if (!control_char(c))
sprintf(buf, "%c", c);
else if (!control_char(c ^ 0100))
sprintf(buf, "^%c", c ^ 0100);
else
sprintf(buf, binfmt, c);
return (buf);
}

59
bin/less/cmd.h Normal file
View File

@ -0,0 +1,59 @@
#define MAX_USERCMD 500
#define MAX_CMDLEN 16
#define A_B_LINE 2
#define A_B_SCREEN 3
#define A_B_SCROLL 4
#define A_B_SEARCH 5
#define A_DIGIT 6
#define A_DISP_OPTION 7
#define A_DEBUG 8
#define A_EXAMINE 9
#define A_FIRSTCMD 10
#define A_FREPAINT 11
#define A_F_LINE 12
#define A_F_SCREEN 13
#define A_F_SCROLL 14
#define A_F_SEARCH 15
#define A_GOEND 16
#define A_GOLINE 17
#define A_GOMARK 18
#define A_HELP 19
#define A_NEXT_FILE 20
#define A_PERCENT 21
#define A_PREFIX 22
#define A_PREV_FILE 23
#define A_QUIT 24
#define A_REPAINT 25
#define A_SETMARK 26
#define A_SHELL 27
#define A_STAT 28
#define A_FF_LINE 29
#define A_BF_LINE 30
#define A_VERSION 31
#define A_VISUAL 32
#define A_F_WINDOW 33
#define A_B_WINDOW 34
#define A_F_BRACKET 35
#define A_B_BRACKET 36
#define A_PIPE 37
#define A_INDEX_FILE 38
#define A_AGAIN_SEARCH 43
#define A_T_AGAIN_SEARCH 44
#define A_REVERSE_SEARCH 45
#define A_T_REVERSE_SEARCH 46
#define A_OPT_TOGGLE 47
#define A_OPT_SET 48
#define A_OPT_UNSET 49
#define A_F_FOREVER 50
#define A_GOPOS 51
#define A_INVALID 100
#define A_NOACTION 101
#define A_UINVALID 102
#define A_EXTRA 0200

145
bin/less/cmdbuf.c Normal file
View File

@ -0,0 +1,145 @@
/*
* Functions which manipulate the command buffer.
* Used only by command() and related functions.
*/
#pragma noroot
#include "less.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern int erase_char, kill_char;
extern int sc_width;
static char cmdbuf[120]; /* Buffer for holding a multi-char command */
static int cmd_col; /* Current column of the multi-char command */
static char *cp; /* Pointer into cmdbuf */
/*
* Reset command buffer (to empty).
*/
public void
cmd_reset(void)
{
cp = cmdbuf;
*cp = '\0';
cmd_col = 0;
}
/*
* How many characters are in the command buffer?
*/
public int
len_cmdbuf(void)
{
return (cp - cmdbuf);
}
/*
* Backspace in the command buffer.
*/
public int
cmd_erase(void)
{
register char *s;
if (cp == cmdbuf)
/*
* Backspace past beginning of the string:
* this usually means abort the command.
*/
return (1);
--cp;
if (*cp == ESC)
s = "ESC";
else
s = prchar(*cp);
while (*s++ != '\0')
{
backspace();
cmd_col--;
}
*cp = '\0';
return (0);
}
/*
* Process a single character of a multi-character command, such as
* a number, or the pattern of a search command.
*/
public int
cmd_char(c)
int c;
{
char *s;
if (c == erase_char)
{
if (cmd_erase())
return (1);
} else if (c == kill_char)
{
/* {{ Could do this faster, but who cares? }} */
while (cmd_erase() == 0)
;
} else if (cp >= &cmdbuf[sizeof(cmdbuf)-1])
{
/*
* No room in the command buffer.
*/
bell();
} else if (cmd_col >= sc_width-4)
{
/*
* No room on the screen.
* {{ Could get fancy here; maybe shift the displayed
* line and make room for more chars, like ksh. }}
*/
bell();
} else
{
/*
* Append the character to the string.
*/
*cp++ = c;
*cp = '\0';
if (c == ESC)
s = "ESC";
else
s = prchar(c);
putstr(s);
cmd_col += strlen(s);
}
return (0);
}
/*
* Return the number currently in the command buffer.
*/
public int
cmd_int(void)
{
return (atoi(cmdbuf));
}
/*
* Display a string, usually as a prompt for input into the command buffer.
*/
public void
cmd_putstr(s)
char *s;
{
putstr(s);
cmd_col += strlen(s);
}
/*
* Return a pointer to the command buffer.
*/
public char *
get_cmdbuf(void)
{
return (cmdbuf);
}

1203
bin/less/command.c Normal file

File diff suppressed because it is too large Load Diff

373
bin/less/decode.c Normal file
View File

@ -0,0 +1,373 @@
/*
* Routines to decode user commands.
*
* This is all table driven.
* A command table is a sequence of command descriptors.
* Each command descriptor is a sequence of bytes with the following format:
* <c1><c2>...<cN><0><action>
* The characters c1,c2,...,cN are the command string; that is,
* the characters which the user must type.
* It is terminated by a null <0> byte.
* The byte after the null byte is the action code associated
* with the command string.
* If an action byte is OR-ed with A_EXTRA, this indicates
* that the option byte is followed by an extra string.
*
* There may be many command tables.
* The first (default) table is built-in.
* Other tables are read in from "lesskey" files.
* All the tables are linked together and are searched in order.
*/
#pragma noroot
#include "less.h"
#include "cmd.h"
#if __MSDOS__
#include <io.h>
#include <stdlib.h>
#endif
#ifdef _ORCAC_
#include <fcntl.h>
segment "LoadSegONE";
#endif
/*
* Command table is ordered roughly according to expected
* frequency of use, so the common commands are near the beginning.
*/
static char cmdtable[] =
{
#if __MSDOS__
/*
* PC function keys.
* Note that '\0' is converted to '\200' on input.
*/
'\200','\120',0, A_F_LINE, /* down arrow */
'\200','\121',0, A_F_SCREEN, /* page down */
'\200','\110',0, A_B_LINE, /* up arrow */
'\200','\111',0, A_B_SCREEN, /* page up */
'\200','\107',0, A_GOLINE, /* home */
'\200','\117',0, A_GOEND, /* end */
'\200','\073',0, A_HELP, /* F1 */
'\200','\104',0, A_MODIFY_WINDOW, /* F10 */
'\200','\103',0, A_MODIFY_COLOURS, /* F9 */
#endif
'\r',0, A_F_LINE,
'\n',0, A_F_LINE,
'e',0, A_F_LINE,
'j',0, A_F_LINE,
CONTROL('E'),0, A_F_LINE,
CONTROL('N'),0, A_F_LINE,
'k',0, A_B_LINE,
'y',0, A_B_LINE,
CONTROL('Y'),0, A_B_LINE,
CONTROL('K'),0, A_B_LINE,
CONTROL('P'),0, A_B_LINE,
'J',0, A_FF_LINE,
'K',0, A_BF_LINE,
'Y',0, A_BF_LINE,
'd',0, A_F_SCROLL,
CONTROL('D'),0, A_F_SCROLL,
'u',0, A_B_SCROLL,
CONTROL('U'),0, A_B_SCROLL,
' ',0, A_F_SCREEN,
'f',0, A_F_SCREEN,
CONTROL('F'),0, A_F_SCREEN,
CONTROL('V'),0, A_F_SCREEN,
'b',0, A_B_SCREEN,
CONTROL('B'),0, A_B_SCREEN,
ESC,'v',0, A_B_SCREEN,
'z',0, A_F_WINDOW,
'w',0, A_B_WINDOW,
'F',0, A_F_FOREVER,
'R',0, A_FREPAINT,
'r',0, A_REPAINT,
CONTROL('R'),0, A_REPAINT,
CONTROL('L'),0, A_REPAINT,
'g',0, A_GOLINE,
'<',0, A_GOLINE,
ESC,'<',0, A_GOLINE,
'p',0, A_PERCENT,
'%',0, A_PERCENT,
'{',0, A_F_BRACKET|A_EXTRA, '{','}',0,
'}',0, A_B_BRACKET|A_EXTRA, '{','}',0,
'(',0, A_F_BRACKET|A_EXTRA, '(',')',0,
')',0, A_B_BRACKET|A_EXTRA, '(',')',0,
'[',0, A_F_BRACKET|A_EXTRA, '[',']',0,
']',0, A_B_BRACKET|A_EXTRA, '[',']',0,
ESC,CONTROL('F'),0, A_F_BRACKET,
ESC,CONTROL('B'),0, A_B_BRACKET,
'G',0, A_GOEND,
ESC,'>',0, A_GOEND,
'>',0, A_GOEND,
'P',0, A_GOPOS,
'0',0, A_DIGIT,
'1',0, A_DIGIT,
'2',0, A_DIGIT,
'3',0, A_DIGIT,
'4',0, A_DIGIT,
'5',0, A_DIGIT,
'6',0, A_DIGIT,
'7',0, A_DIGIT,
'8',0, A_DIGIT,
'9',0, A_DIGIT,
'=',0, A_STAT,
CONTROL('G'),0, A_STAT,
':','f',0, A_STAT,
'/',0, A_F_SEARCH,
'?',0, A_B_SEARCH,
ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0,
ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0,
'n',0, A_AGAIN_SEARCH,
ESC,'n',0, A_T_AGAIN_SEARCH,
'N',0, A_REVERSE_SEARCH,
ESC,'N',0, A_T_REVERSE_SEARCH,
'm',0, A_SETMARK,
'\'',0, A_GOMARK,
CONTROL('X'),CONTROL('X'),0, A_GOMARK,
'E',0, A_EXAMINE,
':','e',0, A_EXAMINE,
CONTROL('X'),CONTROL('V'),0, A_EXAMINE,
':','n',0, A_NEXT_FILE,
':','p',0, A_PREV_FILE,
':','x',0, A_INDEX_FILE,
'-',0, A_OPT_TOGGLE,
':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0,
's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0,
'_',0, A_DISP_OPTION,
'|',0, A_PIPE,
'v',0, A_VISUAL,
'!',0, A_SHELL,
'+',0, A_FIRSTCMD,
'H',0, A_HELP,
'h',0, A_HELP,
'V',0, A_VERSION,
'q',0, A_QUIT,
':','q',0, A_QUIT,
':','Q',0, A_QUIT,
'Z','Z',0, A_QUIT,
ESC,ESC,0, A_QUIT,
};
/*
* Structure to support a list of command tables.
*/
struct tablelist
{
struct tablelist *t_next;
char *t_start;
char *t_end;
};
/*
* Structure for the default command table.
*/
static struct tablelist deftable =
{ NULL, cmdtable, cmdtable+sizeof(cmdtable) };
/*
* List of tables; initially contains only the default table.
*/
static struct tablelist *tables = &deftable;
static int cmd_search(char *cmd, char *table, char *endtable, char **sp);
extern int erase_char, kill_char;
/*
* Decode a command character and return the associated action.
* The "extra" string, if any, is returned in sp.
*/
public int
cmd_decode(cmd, sp)
char *cmd;
char **sp;
{
register struct tablelist *t;
register int action;
/*
* Search thru all the command tables.
* Stop when we find an action which is not A_INVALID.
*/
for (t = tables; t != NULL; t = t->t_next)
{
action = cmd_search(cmd, t->t_start, t->t_end, sp);
if (action != A_INVALID)
break;
}
return (action);
}
/*
* Search a command table for the current command string (in cmd).
*/
static int
cmd_search(cmd, table, endtable, sp)
char *cmd;
char *table;
char *endtable;
char **sp;
{
register char *p;
register char *q;
register int a;
for (p = table, q = cmd; p < endtable; p++, q++)
{
if (*p == *q)
{
/*
* Current characters match.
* If we're at the end of the string, we've found it.
* Return the action code, which is the character
* after the null at the end of the string
* in the command table.
*/
if (*p == '\0')
{
a = *++p & 0377;
/*
* Check for an "extra" string.
*/
if (a & A_EXTRA)
{
*sp = ++p;
a &= ~A_EXTRA;
} else
*sp = NULL;
return (a);
}
} else if (*q == '\0')
{
/*
* Hit the end of the user's command,
* but not the end of the string in the command table.
* The user's command is incomplete.
*/
return (A_PREFIX);
} else
{
/*
* Not a match.
* Skip ahead to the next command in the
* command table, and reset the pointer
* to the beginning of the user's command.
*/
while (*p++ != '\0') ;
if (*p & A_EXTRA)
while (*++p != '\0') ;
q = cmd-1;
}
}
/*
* No match found in the entire command table.
*/
return (A_INVALID);
}
#if USERFILE
/*
* Set up a user command table, based on a "lesskey" file.
*/
public int
add_cmdtable(filename)
char *filename;
{
register struct tablelist *t;
register POSITION len;
register long n;
register int f;
/*
* Try to open the lesskey file.
* If we can't, return an error.
*/
f = open(filename, O_RDONLY);
if (f < 0)
return (-1);
/*
* Read the file into the user table.
* We first figure out the size of the file and allocate space for it.
* {{ Minimal error checking is done here.
* A garbage .less file will produce strange results.
* To avoid a large amount of error checking code here, we
* rely on the lesskey program to generate a good .less file. }}
*/
len = filesize(f);
if (len == NULL_POSITION || len < 3)
{
/*
* Bad file (valid file must have at least 3 chars).
*/
close(f);
return (-1);
}
if ((t = (struct tablelist *)
calloc(1, sizeof(struct tablelist))) == NULL)
{
close(f);
return (-1);
}
if ((t->t_start = (char *) calloc(len, sizeof(char))) == NULL)
{
free((char *)t);
close(f);
return (-1);
}
if (lseek(f, (offset_t)0, 0) == BAD_LSEEK)
{
free(t->t_start);
free((char *)t);
close(f);
return (-1);
}
n = read(f, t->t_start, (size_t) len);
close(f);
/*
* In a valid lesskey file, the last byte or
* the second to the last byte must be zero.
*/
if (n != len || (t->t_start[n-1] != '\0' && t->t_start[n-2] != '\0'))
{
free(t->t_start);
free((char *)t);
return (-1);
}
t->t_end = t->t_start + n;
/*
* Link it into the list of tables.
*/
t->t_next = tables;
tables = t;
return (0);
}
/*
* Try to add the lesskey file "$HOME/.less"
*/
public void
add_hometable(void)
{
char *filename;
#if __MSDOS__
filename = homefile("_less");
#else
filename = homefile("lessrc");
#endif
if (filename == NULL)
return;
/*
* Ignore errors.
*/
(void) add_cmdtable(filename);
free(filename);
}
#endif

134
bin/less/defines.h Normal file
View File

@ -0,0 +1,134 @@
/* Definition file for less */
/* Generated Sat May 2 16:21:05 CDT 1992 by linstall. */
/*
* Define XENIX if running under XENIX 3.0.
*/
#define XENIX 0
/*
* VOID is 1 if your C compiler supports the "void" type,
* 0 if it does not.
*/
#define VOID 1
/*
* VOID_POINTER is the definition of a pointer to any object.
*/
#define VOID_POINTER void *
/*
* offset_t is the type which lseek() returns.
* It is also the type of lseek()'s second argument.
*/
#define offset_t long
/*
* STAT is 1 if your system has the stat() call.
*/
#define STAT 1
/*
* PERROR is 1 if your system has the perror() call.
* (Actually, if it has sys_errlist, sys_nerr and errno.)
*/
#define PERROR 1
/*
* GET_TIME is 1 if your system has the time() call.
*/
#define GET_TIME 1
/*
* TERMIO is 1 if your system has /usr/include/termio.h.
* This is normally the case for System 5.
* If TERMIO is 0 your system must have /usr/include/sgtty.h.
* This is normally the case for BSD.
*/
#define TERMIO 0
/*
* HAS__SETJMP is 1 if your system has the _setjmp() call.
* This is normally the case only for BSD 4.2 and up,
* not for BSD 4.1 or System 5.
*/
#define HAS__SETJMP 0
/*
* SIGSETMASK is 1 if your system has the sigsetmask() call.
* This is normally the case only for BSD 4.2,
* not for BSD 4.1 or System 5.
*/
#define SIGSETMASK 1
/*
* NEED_PTEM_H is 1 if your system needs sys/ptem.h to declare struct winsize.
* This is normally the case only for SCOs System V.
*/
#define NEED_PTEM_H 0
/*
* REGCMP is 1 if your system has the regcmp() function.
* This is normally the case for System 5.
* RECOMP is 1 if your system has the re_comp() function.
* This is normally the case for BSD.
* If neither is 1, pattern matching is supported, but without metacharacters.
*/
#define REGCMP 0
#define RECOMP 0
#define REGCOMP 1
/*
* SHELL_ESCAPE is 1 if you wish to allow shell escapes.
* (This is possible only if your system supplies the system() function.)
*/
#define SHELL_ESCAPE 1
/*
* EDITOR is 1 if you wish to allow editor invocation (the "v" command).
* (This is possible only if your system supplies the system() function.)
* EDIT_PGM is the name of the (default) editor to be invoked.
*/
#define EDITOR 1
#define EDIT_PGM "vi"
/*
* TAGS is 1 if you wish to support tag files.
*/
#define TAGS 1
/*
* USERFILE is 1 if you wish to allow a .less file to specify
* user-defined key bindings.
*/
#define USERFILE 1
/*
* GLOB is 1 if you wish to have shell metacharacters expanded in filenames.
* This will generally work if your system provides the "popen" function
* and the "echo" shell command.
*/
#define GLOB 0
/*
* PIPEC is 1 if you wish to have the "|" command
* which allows the user to pipe data into a shell command.
*/
#define PIPEC 0
/*
* LOGFILE is 1 if you wish to allow the -l option (to create log files).
*/
#define LOGFILE 0
/*
* ONLY_RETURN is 1 if you want RETURN to be the only input which
* will continue past an error message.
* Otherwise, any key will continue past an error message.
*/
#define ONLY_RETURN 0
/*
* HELPFILE is the full pathname of the help file.
*/
#define HELPFILE "31:bin:less.hlp"

461
bin/less/edit.c Normal file
View File

@ -0,0 +1,461 @@
#pragma noroot
#include "less.h"
#if __MSDOS__
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#endif
#ifdef _ORCAC_
#include <unistd.h>
#include <fcntl.h>
segment "LoadSegONE";
#endif
#define ISPIPE(fd) ((fd)==STDIN_FILENO)
extern int ispipe;
extern int new_file;
extern int errmsgs;
extern int quit_at_eof;
extern int file;
extern int cbufs;
extern char *every_first_cmd;
extern int any_display;
extern int force_open;
extern int is_tty;
extern IFILE curr_ifile;
extern IFILE old_ifile;
extern struct scrpos initial_scrpos;
#if LOGFILE
extern int logfile;
extern int force_logfile;
extern char *namelogfile;
#endif
/*
* Edit a new file.
* Filename == "-" means standard input.
* Filename == NULL means just close the current file.
*/
public int
edit(filename, just_looking)
register char *filename;
int just_looking;
{
register int f;
char *s;
int answer;
int no_display;
struct scrpos scrpos;
PARG parg;
if (filename == NULL)
{
/*
* Close the current file, but don't open a new one.
*/
f = -1;
} else if (strcmp(filename, "-") == 0)
{
/*
* Use standard input.
*/
f = STDIN_FILENO;
} else if ((parg.p_string = bad_file(filename)) != NULL)
{
error("\r%s\r", &parg);
free(parg.p_string);
return (1);
#if __MSDOS__
} else if ((f = open(filename, O_RDONLY|O_BINARY)) < 0)
#else
/* } else if ((f = open(filename, 0)) < 0)*/
} else if ((f = open(filename, O_RDONLY|O_BINARY)) < 0)
#endif
{
parg.p_string = errno_message(filename);
error("%s", &parg);
free(parg.p_string);
return (1);
} else if (!force_open && !just_looking && bin_file(f))
{
parg.p_string = filename;
answer = query("\"%s\" may be a binary file. Continue? ",
&parg);
if (answer != 'y' && answer != 'Y')
{
close(f);
return (1);
}
}
if (f >= 0 && isatty(f))
{
/*
* Not really necessary to call this an error,
* but if the control terminal (for commands)
* and the input file (for data) are the same,
* we get weird results at best.
*/
#if __MSDOS__
parg.p_string = "less -?";
#else
parg.p_string = "less -\\?";
#endif
error("Cannot take input from a terminal (\"%s\" for help)",
&parg);
if (!ISPIPE(f))
close(f);
return (1);
}
#if LOGFILE
s = namelogfile;
end_logfile();
if (f >= 0 && ISPIPE(f) && s != NULL && is_tty)
use_logfile(s);
#endif
/*
* We are now committed to using the new file.
* Close the current input file and set up to use the new one.
*/
if (curr_ifile != NULL_IFILE)
{
/*
* Save the current position so that we can return to
* the same position if we edit this file again.
*/
get_scrpos(&scrpos);
if (scrpos.pos != NULL_POSITION)
{
store_pos(curr_ifile, &scrpos);
lastmark();
}
}
/*
* Close the current file, unless it is a pipe.
*/
if (!ISPIPE(file))
close(file);
file = f;
if (f < 0)
return (1);
/*
* Get the new ifile.
* Get the saved position for that file.
*/
old_ifile = curr_ifile;
curr_ifile = get_ifile(filename, curr_ifile);
get_pos(curr_ifile, &initial_scrpos);
ispipe = ISPIPE(f);
if (ispipe)
ch_pipe();
else
ch_nonpipe();
(void) ch_nbuf(cbufs);
ch_flush();
new_file = 1;
#if __MSDOS__
top_filename();
#endif
if (every_first_cmd != NULL)
ungetsc(every_first_cmd);
no_display = !any_display;
flush();
any_display = 1;
if (is_tty)
{
/*
* Output is to a real tty.
*/
/*
* Indicate there is nothing displayed yet.
*/
pos_clear();
clr_linenum();
if (no_display && errmsgs > 0)
{
/*
* We displayed some messages on error output
* (file descriptor 2; see error() function).
* Before erasing the screen contents,
* display the file name and wait for a keystroke.
*/
parg.p_string = filename;
error("%s", &parg);
}
}
return (0);
}
/*
* Edit a space-separated list of files.
* For each filename in the list, enter it into the ifile list.
* Then edit the first one.
*/
public void
edit_list(list)
char *list;
{
register char *s;
register char *es;
register char *filename;
char *good_filename;
IFILE save_curr_ifile;
/*
* good_filename keeps track of the first valid filename.
*/
good_filename = NULL;
s = list;
es = s + strlen(s);
save_curr_ifile = curr_ifile;
while ((s = skipsp(s)) < es)
{
/*
* Get the next filename and null terminate it.
*/
filename = s;
while (*s != ' ' && *s != '\0')
s++;
if (*s != '\0')
*s++ = '\0';
/*
* Try to edit the file.
* This enters it into the command line list (if it is good).
* If it is the first good file we've seen, remember it.
* {{ A little weirdness here: if any of the filenames
* are already in the list, subsequent ones get
* entered after the position where that one already
* was, instead of at the end. }}
*/
if (edit(filename, 1) == 0 && good_filename == NULL)
good_filename = filename;
}
/*
* Edit the first valid filename in the list.
*/
if (good_filename != NULL)
{
curr_ifile = save_curr_ifile;
(void) edit(good_filename, 0);
}
}
/*
* Edit the first file in the command line (ifile) list.
*/
public int
edit_first(void)
{
curr_ifile = NULL_IFILE;
return (edit_next(1));
}
/*
* Edit the last file in the command line (ifile) list.
*/
public int
edit_last(void)
{
curr_ifile = NULL_IFILE;
return (edit_prev(1));
}
/*
* Edit the next file in the command line (ifile) list.
*/
public int
edit_next(n)
int n;
{
IFILE h;
h = curr_ifile;
while (--n >= 0 || edit(get_filename(h), 0))
{
if ((h = next_ifile(h)) == NULL_IFILE)
/*
* Reached end of the ifile list.
*/
return (1);
}
/*
* Found a file that we can edit.
*/
return (0);
}
/*
* Edit the previous file in the command line list.
*/
public int
edit_prev(n)
int n;
{
IFILE h;
h = curr_ifile;
while (--n >= 0 || edit(get_filename(h), 0))
{
if ((h = prev_ifile(h)) == NULL_IFILE)
/*
* Reached beginning of the ifile list.
*/
return (1);
}
/*
* Found a file that we can edit.
*/
return (0);
}
/*
* Edit a specific file in the command line (ifile) list.
*/
public int
edit_index(n)
int n;
{
IFILE h;
h = NULL_IFILE;
do
{
if ((h = next_ifile(h)) == NULL_IFILE)
{
/*
* Reached end of the list without finding it.
*/
return (1);
}
} while (get_index(h) != n);
return (edit(get_filename(h), 0));
}
/*
* Copy a file directly to standard output.
* Used if standard output is not a tty.
*/
public void
cat_file(void)
{
register int c;
while ((c = ch_forw_get()) != EOI)
putchr(c);
flush();
}
#if LOGFILE
/*
* If the user asked for a log file and our input file
* is standard input, create the log file.
* We take care not to blindly overwrite an existing file.
*/
public void
use_logfile(filename)
char *filename;
{
register int exists;
register int answer;
PARG parg;
/*
* {{ We could use access() here. }}
*/
/* exists = open(filename, 0);*/
exists = open(filename, O_RDWR);
close(exists);
exists = (exists >= 0);
/*
* Decide whether to overwrite the log file or append to it.
* (If it doesn't exist we "overwrite" it.
*/
if (!exists || force_logfile)
{
/*
* Overwrite (or create) the log file.
*/
answer = 'O';
} else
{
/*
* Ask user what to do.
*/
parg.p_string = filename;
answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg);
}
loop:
switch (answer)
{
case 'O': case 'o':
/*
* Overwrite: create the file.
*/
logfile = creat(filename, 0644);
break;
case 'A': case 'a':
/*
* Append: open the file and seek to the end.
*/
#if __MSDOS__
logfile = open(filename, O_APPEND|O_WRONLY);
#else
/* logfile = open(filename, 1);*/
logfile = open(filename, O_APPEND|O_WRONLY);
#endif
if (lseek(logfile, (offset_t)0, 2) == BAD_LSEEK)
{
close(logfile);
logfile = -1;
}
break;
case 'D': case 'd':
/*
* Don't do anything.
*/
return;
case 'q':
quit(0);
/*NOTREACHED*/
default:
/*
* Eh?
*/
answer = query("Overwrite, Append, or Don't log? ", NULL_PARG);
goto loop;
}
if (logfile < 0)
{
/*
* Error in opening logfile.
*/
parg.p_string = filename;
error("Cannot write to \"%s\"", &parg);
}
}
#endif

369
bin/less/filename.c Normal file
View File

@ -0,0 +1,369 @@
/*
* Routines to mess around with filenames (and files).
* Much of this is very OS dependent.
*/
#pragma noroot
#include <stdio.h>
#include <string.h>
#include "less.h"
#include <fcntl.h>
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern char *getenv(char *);
extern int force_open;
extern IFILE curr_ifile;
extern IFILE old_ifile;
static POSITION seek_filesize(int f);
/*
* Return the full pathname of the given file in the "home directory".
*/
public char *
homefile(filename)
char *filename;
{
register char *pathname;
register char *homedir;
homedir = getenv("HOME");
#if __MSDOS__
/*
* Most MSDOS users do not have $HOME defined,
* so if no $HOME then look for "_less" anywhere
* on search path (always begins at current directory).
*/
if (homedir == NULL)
{
extern char *searchpath();
pathname = searchpath(filename);
if (pathname == NULL)
return (NULL);
pathname = save(pathname);
} else
{
pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2,
sizeof(char));
if (pathname == NULL)
return (NULL);
sprintf(pathname, "%s\\%s", homedir, filename);
}
#else
if (homedir == NULL)
return (NULL);
pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2,
sizeof(char));
if (pathname == NULL)
return (NULL);
sprintf(pathname, "%s/%s", homedir, filename);
#endif
return (pathname);
}
/*
* Find out where the help file is.
*/
public char *
find_helpfile(void)
{
register char *helpfile;
#if __MSDOS__
extern char *searchpath();
/*
* Look in current directory.
*/
if (access(HELPFILE,0) == 0)
return (HELPFILE);
/*
* Find the basename of HELPFILE,
* and look for it in each directory in the search path.
*/
if ((helpfile = strrchr(HELPFILE, '\\')) == NULL)
helpfile = HELPFILE;
else
helpfile++;
return (save(searchpath(helpfile)));
#else
if ((helpfile = getenv("LESSHELP")) != NULL)
return (save(helpfile));
return (save(HELPFILE));
#endif
}
/*
* Expand a string, substituting any "%" with the current filename,
* and any "#" with the previous filename.
*/
public char *
fexpand(s)
char *s;
{
register char *fr, *to;
register int n;
register char *e;
/*
* Make one pass to see how big a buffer we
* need to allocate for the expanded string.
*/
n = 0;
for (fr = s; *fr != '\0'; fr++)
{
switch (*fr)
{
case '%':
n += strlen(get_filename(curr_ifile));
break;
case '#':
if (old_ifile == NULL_IFILE)
{
error("No previous file", NULL_PARG);
return (NULL);
}
n += strlen(get_filename(old_ifile));
break;
default:
n++;
break;
}
}
e = (char *) ecalloc(n+1, sizeof(char));
/*
* Now copy the string, expanding any "%" or "#".
*/
to = e;
for (fr = s; *fr != '\0'; fr++)
{
switch (*fr)
{
case '%':
strcpy(to, get_filename(curr_ifile));
to += strlen(to);
break;
case '#':
strcpy(to, get_filename(old_ifile));
to += strlen(to);
break;
default:
*to++ = *fr;
break;
}
}
*to = '\0';
return (e);
}
/*
* Try to determine if a file is "binary".
* This is just a guess, and we need not try too hard to make it accurate.
*/
int
bin_file(f)
int f;
{
int i;
int n;
char data[64];
n = read(f, data, sizeof(data));
for (i = 0; i < n; i++)
if (binary_char((int) data[i]))
return (1);
return (0);
}
/*
* Try to determine the size of a file by seeking to the end.
*/
static POSITION
seek_filesize(f)
int f;
{
offset_t spos;
spos = lseek(f, (offset_t)0, 2);
if (spos == BAD_LSEEK)
return (NULL_POSITION);
return ((POSITION) spos);
}
/*
* Expand a filename, substituting any environment variables, etc.
*/
#if GLOB
FILE *popen(char *command, char *type);
public char *
glob(filename)
char *filename;
{
FILE *f;
char *p;
int ch;
int len;
char *cmd;
char *gfilename;
filename = fexpand(filename);
if (filename == NULL)
return (NULL);
/*
* We get the shell to expand the filename for us by passing
* an "echo" command to the shell and reading its output.
*/
p = getenv("SHELL");
if (p == NULL || *p == '\0')
{
/*
* Read the output of <echo filename>.
*/
cmd = (char *) ecalloc(strlen(filename)+6, sizeof(char));
sprintf(cmd, "echo %s", filename);
} else
{
/*
* Read the output of <$SHELL -c "echo filename">.
*/
cmd = (char *) ecalloc(strlen(p)+strlen(filename)+12, sizeof(char));
sprintf(cmd, "%s -c \"echo %s\"", p, filename);
}
f = popen(cmd, "r");
free(cmd);
if (f == NULL)
return (filename);
free(filename);
len = 100;
gfilename = (char *) ecalloc(len, sizeof(char));
for (p = gfilename; ; p++)
{
if ((ch = getc(f)) == '\n' || ch == EOF)
break;
if (p - gfilename >= len-1)
{
len *= 2;
*p = '\0';
p = (char *) ecalloc(len, sizeof(char));
strcpy(p, gfilename);
free(gfilename);
gfilename = p;
p = gfilename + strlen(gfilename);
}
*p = ch;
}
*p = '\0';
pclose(f);
if (*gfilename == '\0')
return (NULL);
return (gfilename);
}
#else
public char *
glob(filename)
char *filename;
{
return (fexpand(filename));
}
#endif
#if STAT
#include <sys/types.h>
#include <sys/stat.h>
/*
* Returns NULL if the file can be opened and
* is an ordinary file, otherwise an error message
* (if it cannot be opened or is a directory, etc.)
*/
public char *
bad_file(filename)
char *filename;
{
register char *m;
struct stat statbuf;
if (stat(filename, &statbuf) < 0)
return (errno_message(filename));
if (force_open)
return (NULL);
if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
{
static char is_dir[] = " is a directory";
m = (char *) ecalloc(strlen(filename) + sizeof(is_dir),
sizeof(char));
strcpy(m, filename);
strcat(m, is_dir);
return (m);
}
if ((statbuf.st_mode & S_IFMT) != S_IFREG)
{
static char not_reg[] = " is not a regular file";
m = (char *) ecalloc(strlen(filename) + sizeof(not_reg),
sizeof(char));
strcpy(m, filename);
strcat(m, not_reg);
return (m);
}
return (NULL);
}
/*
* Return the size of a file, as cheaply as possible.
* In Unix, we can stat the file.
*/
public POSITION
filesize(f)
int f;
{
struct stat statbuf;
if (fstat(f, &statbuf) < 0)
/*
* Can't stat; try seeking to the end.
*/
return (seek_filesize(f));
return ((POSITION) statbuf.st_size);
}
#else
/*
* If we have no way to find out, just say the file is good.
*/
public char *
bad_file(filename)
char *filename;
{
return (NULL);
}
/*
* We can find the file size by seeking.
*/
public POSITION
filesize(f)
int f;
{
return (seek_filesize(f));
}
#endif

380
bin/less/forwback.c Normal file
View File

@ -0,0 +1,380 @@
/*
* Primitives for displaying the file on the screen,
* scrolling either forward or backward.
*/
#pragma noroot
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
public int hit_eof; /* Keeps track of how many times we hit end of file */
public int screen_trashed;
public int squished;
extern int sigs;
extern int top_scroll;
extern int quiet;
extern int sc_width, sc_height;
extern int quit_at_eof;
extern int plusoption;
extern int forw_scroll;
extern int back_scroll;
extern int need_clr;
extern int ignore_eoi;
#if TAGS
extern int tagoption;
#endif
static void eof_bell(void);
static void eof_check(void);
static void squish_check(void);
/*
* Sound the bell to indicate user is trying to move past end of file.
*/
static void
eof_bell(void)
{
if (quiet == NOT_QUIET)
bell();
else
vbell();
}
/*
* Check to see if the end of file is currently "displayed".
*/
static void
eof_check(void)
{
POSITION pos;
if (ignore_eoi)
return;
if (sigs)
return;
/*
* If the bottom line is empty, we are at EOF.
* If the bottom line ends at the file length,
* we must be just at EOF.
*/
pos = position(BOTTOM_PLUS_ONE);
if (pos == NULL_POSITION || pos == ch_length())
hit_eof++;
}
/*
* If the screen is "squished", repaint it.
* "Squished" means the first displayed line is not at the top
* of the screen; this can happen when we display a short file
* for the first time.
*/
static void
squish_check(void)
{
if (!squished)
return;
squished = 0;
repaint();
}
/*
* Display n lines, scrolling forward,
* starting at position pos in the input file.
* "force" means display the n lines even if we hit end of file.
* "only_last" means display only the last screenful if n > screen size.
* "nblank" is the number of blank lines to draw before the first
* real line. If nblank > 0, the pos must be NULL_POSITION.
* The first real line after the blanks will start at ch_zero().
*/
public void
forw(n, pos, force, only_last, nblank)
register int n;
POSITION pos;
int force;
int only_last;
int nblank;
{
int eof = 0;
int nlines = 0;
int do_repaint;
static int first_time = 1;
squish_check();
/*
* do_repaint tells us not to display anything till the end,
* then just repaint the entire screen.
* We repaint if we are supposed to display only the last
* screenful and the request is for more than a screenful.
* Also if the request exceeds the forward scroll limit
* (but not if the request is for exactly a screenful, since
* repainting itself involves scrolling forward a screenful).
*/
do_repaint = (only_last && n > sc_height-1) ||
(forw_scroll >= 0 && n > forw_scroll && n != sc_height-1);
if (!do_repaint)
{
if (top_scroll && n >= sc_height - 1 && pos != ch_length())
{
/*
* Start a new screen.
* {{ This is not really desirable if we happen
* to hit eof in the middle of this screen,
* but we don't yet know if that will happen. }}
*/
if (top_scroll == 2 || first_time)
clear();
home();
force = 1;
} else
{
lower_left();
clear_eol();
}
if (pos != position(BOTTOM_PLUS_ONE) || empty_screen())
{
/*
* This is not contiguous with what is
* currently displayed. Clear the screen image
* (position table) and start a new screen.
*/
pos_clear();
add_forw_pos(pos);
force = 1;
if (top_scroll)
{
if (top_scroll == 2)
clear();
home();
} else if (!first_time)
{
putstr("...skipping...\r");
}
}
}
while (--n >= 0)
{
/*
* Read the next line of input.
*/
if (nblank > 0)
{
/*
* Still drawing blanks; don't get a line
* from the file yet.
* If this is the last blank line, get ready to
* read a line starting at ch_zero() next time.
*/
if (--nblank == 0)
pos = ch_zero();
} else
{
/*
* Get the next line from the file.
*/
pos = forw_line(pos);
if (pos == NULL_POSITION)
{
/*
* End of file: stop here unless the top line
* is still empty, or "force" is true.
*/
eof = 1;
if (!force && position(TOP) != NULL_POSITION)
break;
}
}
/*
* Add the position of the next line to the position table.
* Display the current line on the screen.
*/
add_forw_pos(pos);
nlines++;
if (do_repaint)
continue;
/*
* If this is the first screen displayed and
* we hit an early EOF (i.e. before the requested
* number of lines), we "squish" the display down
* at the bottom of the screen.
* But don't do this if a + option or a -t option
* was given. These options can cause us to
* start the display after the beginning of the file,
* and it is not appropriate to squish in that case.
*/
if (first_time && pos == NULL_POSITION && !top_scroll &&
#if TAGS
!tagoption &&
#endif
!plusoption)
{
squished = 1;
continue;
}
if (top_scroll == 1)
clear_eol();
put_line();
}
if (ignore_eoi)
hit_eof = 0;
else if (eof && !sigs)
hit_eof++;
else
eof_check();
if (nlines == 0)
eof_bell();
else if (do_repaint)
repaint();
first_time = 0;
(void) currline(BOTTOM);
}
/*
* Display n lines, scrolling backward.
*/
public void
back(n, pos, force, only_last)
register int n;
POSITION pos;
int force;
int only_last;
{
int nlines = 0;
int do_repaint;
squish_check();
do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
hit_eof = 0;
while (--n >= 0)
{
/*
* Get the previous line of input.
*/
pos = back_line(pos);
if (pos == NULL_POSITION)
{
/*
* Beginning of file: stop here unless "force" is true.
*/
if (!force)
break;
}
/*
* Add the position of the previous line to the position table.
* Display the line on the screen.
*/
add_back_pos(pos);
nlines++;
if (!do_repaint)
{
home();
add_line();
put_line();
}
}
eof_check();
if (nlines == 0)
eof_bell();
else if (do_repaint)
repaint();
(void) currline(BOTTOM);
}
/*
* Display n more lines, forward.
* Start just after the line currently displayed at the bottom of the screen.
*/
public void
forward(n, force, only_last)
int n;
int force;
int only_last;
{
POSITION pos;
if (quit_at_eof && hit_eof)
{
/*
* If the -e flag is set and we're trying to go
* forward from end-of-file, go on to the next file.
*/
if (edit_next(1))
quit(0);
return;
}
pos = position(BOTTOM_PLUS_ONE);
if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1)))
{
if (ignore_eoi)
{
/*
* ignore_eoi is to support A_F_FOREVER.
* Back up until there is a line at the bottom
* of the screen.
*/
if (empty_screen())
pos = ch_zero();
else
{
do
{
back(1, position(TOP), 1, 0);
pos = position(BOTTOM_PLUS_ONE);
} while (pos == NULL_POSITION);
}
} else
{
eof_bell();
hit_eof++;
return;
}
}
forw(n, pos, force, only_last, 0);
}
/*
* Display n more lines, backward.
* Start just before the line currently displayed at the top of the screen.
*/
public void
backward(n, force, only_last)
int n;
int force;
int only_last;
{
POSITION pos;
pos = position(TOP);
if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0))
{
eof_bell();
return;
}
back(n, pos, force, only_last);
}
/*
* Get the backwards scroll limit.
* Must call this function instead of just using the value of
* back_scroll, because the default case depends on sc_height and
* top_scroll, as well as back_scroll.
*/
public int
get_back_scroll(void)
{
if (back_scroll >= 0)
return (back_scroll);
if (top_scroll)
return (sc_height - 2);
return (10000); /* infinity */
}

32
bin/less/gsos.c Normal file
View File

@ -0,0 +1,32 @@
#pragma noroot
#pragma optimize -1
#include <types.h>
#include <shell.h>
#include <stdlib.h>
#include <string.h>
char *getenv(char *name)
{
Get_VarPB gv;
char *vn;
int l;
l = strlen(name);
gv.var_name = malloc(l+1);
gv.var_name[0] = l; memcpy(gv.var_name+1,name,(size_t)l);
gv.value = malloc(256l);
GET_VAR(&gv);
gv.value[gv.value[0]+1] = 0;
free(gv.var_name);
if (gv.value[0] == 0) { free(gv.value); return NULL; }
vn = malloc(gv.value[0]+1);
memcpy(vn,gv.value+1,gv.value[0]);
vn[gv.value[0]] = 0;
free(gv.value);
return vn;
}
/*void exit(int blah)
{
rexit(blah);
} */

58
bin/less/help.c Normal file
View File

@ -0,0 +1,58 @@
/*
* Display some help.
* Just invoke another "less" to display the help file.
*
* {{ This makes this function very simple, and makes changing the
* help file very easy, but it may present difficulties on
* (non-Unix) systems which do not supply the "system()" function. }}
*/
#pragma noroot
#include "less.h"
#if __MSDOS__
#include <io.h>
#include <dir.h>
#include <string.h>
#include <stdlib.h>
extern int output_mode;
#endif
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern char *progname;
public void
help(void)
{
char *helpfile;
char *cmd;
helpfile = find_helpfile();
if (helpfile == NULL)
{
error("Cannot find help file", NULL_PARG);
return;
}
#if __MSDOS__
putenv("LESS=-+v -+E -+s -mHPmHELP -- ?eEND -- Press g to see "
"it again:Press RETURN for more., or q when done ");
cmd = (char *) ecalloc(strlen(helpfile) + strlen(progname) + 50,
sizeof(char));
if (output_mode == 0)
sprintf(cmd, "-%s %s", progname, helpfile);
else
sprintf(cmd, "-%s -qVW4,4,76,23,Help %s", progname, helpfile);
#else
cmd = (char *) ecalloc(strlen(helpfile) + strlen(progname) + 150,
sizeof(char));
sprintf(cmd,
"-%s -m -H -+E -+s '-PmHELP -- ?eEND -- Press g to see it again:Press RETURN for more., or q when done ' %s",
progname, helpfile);
#endif
free(helpfile);
lsystem(cmd);
error("End of help", NULL_PARG);
free(cmd);
}

199
bin/less/ifile.c Normal file
View File

@ -0,0 +1,199 @@
/*
* An IFILE represents an input file.
*
* It is actually a pointer to an ifile structure,
* but is opaque outside this module.
* Ifile structures are kept in a linked list in the order they
* appear on the command line.
* Any new file which does not already appear in the list is
* inserted after the current file.
*/
#pragma noroot
#include "less.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
struct ifile {
struct ifile *h_next; /* Links for command line list */
struct ifile *h_prev;
int h_index; /* Index within command line list */
char *h_filename; /* Name of the file */
struct scrpos h_scrpos; /* Saved position within the file */
};
/*
* Convert an IFILE (external representation)
* to a struct file (internal representation), and vice versa.
*/
#define int_ifile(h) ((struct ifile *)(h))
#define ext_ifile(h) ((IFILE)(h))
/*
* Anchor for linked list.
*/
static struct ifile anchor = { &anchor, &anchor, 0 };
static int ifiles = 0;
static struct ifile *new_ifile(char *filename, struct ifile *prev);
static struct ifile *find_ifile(char *filename);
/*
* Allocate a new ifile structure and stick a filename in it.
* It should go after "prev" in the list
* (or at the beginning of the list if "prev" is NULL).
* Return a pointer to the new ifile structure.
*/
static struct ifile *
new_ifile(filename, prev)
char *filename;
struct ifile *prev;
{
register struct ifile *p;
register struct ifile *np;
/*
* Allocate and initialize structure.
*/
p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
p->h_filename = filename;
p->h_scrpos.pos = NULL_POSITION;
/*
* Link into list.
*/
if (prev == NULL)
prev = &anchor;
p->h_next = prev->h_next;
p->h_prev = prev;
prev->h_next->h_prev = p;
prev->h_next = p;
/*
* Calculate index for the new one,
* and adjust the indexes for subsequent ifiles in the list.
*/
p->h_index = prev->h_index + 1;
for (np = p->h_next; np != &anchor; np = np->h_next)
np->h_index++;
ifiles++;
return (p);
}
/*
* Get the ifile after a given one in the list.
*/
public IFILE
next_ifile(h)
IFILE h;
{
register struct ifile *p;
p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
if (p->h_next == &anchor)
return (NULL_IFILE);
return (ext_ifile(p->h_next));
}
/*
* Get the ifile before a given one in the list.
*/
public IFILE
prev_ifile(h)
IFILE h;
{
register struct ifile *p;
p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
if (p->h_prev == &anchor)
return (NULL_IFILE);
return (ext_ifile(p->h_prev));
}
/*
* Return the number of ifiles.
*/
public int
nifile(void)
{
return (ifiles);
}
/*
* Find an ifile structure, given a filename.
*/
static struct ifile *
find_ifile(filename)
char *filename;
{
register struct ifile *p;
for (p = anchor.h_next; p != &anchor; p = p->h_next)
if (strcmp(filename, p->h_filename) == 0)
return (p);
return (NULL);
}
/*
* Get the ifile associated with a filename.
* If the filename has not been seen before,
* insert the new ifile after "prev" in the list.
*/
public IFILE
get_ifile(filename, prev)
char *filename;
IFILE prev;
{
register struct ifile *p;
if ((p = find_ifile(filename)) == NULL)
p = new_ifile(save(filename), int_ifile(prev));
return (ext_ifile(p));
}
/*
* Get the filename associated with a ifile.
*/
public char *
get_filename(ifile)
IFILE ifile;
{
if (ifile == NULL)
return (NULL);
return (int_ifile(ifile)->h_filename);
}
/*
* Get the index of the file associated with a ifile.
*/
public int
get_index(ifile)
IFILE ifile;
{
return (int_ifile(ifile)->h_index);
}
/*
* Save the file position to be associated with a given file.
*/
public void
store_pos(ifile, scrpos)
IFILE ifile;
struct scrpos *scrpos;
{
int_ifile(ifile)->h_scrpos = *scrpos;
}
/*
* Recall the file position associated with a file.
* If no position has been associated with the file, return NULL_POSITION.
*/
public void
get_pos(ifile, scrpos)
IFILE ifile;
struct scrpos *scrpos;
{
*scrpos = int_ifile(ifile)->h_scrpos;
}

270
bin/less/input.c Normal file
View File

@ -0,0 +1,270 @@
/*
* High level routines dealing with getting lines of input
* from the file being viewed.
*
* When we speak of "lines" here, we mean PRINTABLE lines;
* lines processed with respect to the screen width.
* We use the term "raw line" to refer to lines simply
* delimited by newlines; not processed with respect to screen width.
*/
#pragma noroot
#include "less.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern int squeeze;
extern int chopline;
extern int sigs;
/*
* Get the next line.
* A "current" position is passed and a "new" position is returned.
* The current position is the position of the first character of
* a line. The new position is the position of the first character
* of the NEXT line. The line obtained is the line starting at curr_pos.
*/
public POSITION
forw_line(curr_pos)
POSITION curr_pos;
{
POSITION new_pos;
register int c;
int blankline;
int endline;
if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
{
null_line();
return (NULL_POSITION);
}
prewind();
plinenum(curr_pos);
(void) ch_seek(curr_pos);
c = ch_forw_get();
if (c == EOI)
{
null_line();
return (NULL_POSITION);
}
blankline = (c == '\n' || c == '\r');
for (;;)
{
if (sigs)
{
null_line();
return (NULL_POSITION);
}
/* if (c == '\n' || c == EOI) */
if (c == '\r' || c == '\n' || c == EOI) /* switch CR and LF meanings */
{
/*
* End of the line.
*/
new_pos = ch_tell();
endline = 1;
break;
}
/*
* Append the char to the line and get the next char.
*/
if (pappend(c))
{
/*
* The char won't fit in the line; the line
* is too long to print in the screen width.
* End the line here.
*/
if (chopline)
{
do
{
c = ch_forw_get();
/* } while (c != '\n' && c != EOI); */
} while (c != '\r' && c != '\n' && c != EOI);
new_pos = ch_tell();
endline = 1;
} else
{
new_pos = ch_tell() - 1;
endline = 0;
}
break;
}
c = ch_forw_get();
}
pdone(endline);
if (squeeze && blankline)
{
/*
* This line is blank.
* Skip down to the last contiguous blank line
* and pretend it is the one which we are returning.
*/
while ((c = ch_forw_get()) == '\n' || c == '\r')
if (sigs)
{
null_line();
return (NULL_POSITION);
}
if (c != EOI)
(void) ch_back_get();
new_pos = ch_tell();
}
return (new_pos);
}
/*
* Get the previous line.
* A "current" position is passed and a "new" position is returned.
* The current position is the position of the first character of
* a line. The new position is the position of the first character
* of the PREVIOUS line. The line obtained is the one starting at new_pos.
*/
public POSITION
back_line(curr_pos)
POSITION curr_pos;
{
POSITION new_pos, begin_new_pos;
int c;
int endline;
if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() ||
ch_seek(curr_pos-1))
{
null_line();
return (NULL_POSITION);
}
if (squeeze)
{
/*
* Find out if the "current" line was blank.
*/
(void) ch_forw_get(); /* Skip the newline */
c = ch_forw_get(); /* First char of "current" line */
(void) ch_back_get(); /* Restore our position */
(void) ch_back_get();
/* if (c == '\n') */
if (c == '\r' || c == '\n')
{
/*
* The "current" line was blank.
* Skip over any preceding blank lines,
* since we skipped them in forw_line().
*/
while ((c = ch_back_get()) == '\n' || c == '\r')
if (sigs)
{
null_line();
return (NULL_POSITION);
}
if (c == EOI)
{
null_line();
return (NULL_POSITION);
}
(void) ch_forw_get();
}
}
/*
* Scan backwards until we hit the beginning of the line.
*/
for (;;)
{
if (sigs)
{
null_line();
return (NULL_POSITION);
}
c = ch_back_get();
/* if (c == '\n') */
if (c == '\r' || c == '\n')
{
/*
* This is the newline ending the previous line.
* We have hit the beginning of the line.
*/
new_pos = ch_tell() + 1;
break;
}
if (c == EOI)
{
/*
* We have hit the beginning of the file.
* This must be the first line in the file.
* This must, of course, be the beginning of the line.
*/
new_pos = ch_tell();
break;
}
}
/*
* Now scan forwards from the beginning of this line.
* We keep discarding "printable lines" (based on screen width)
* until we reach the curr_pos.
*
* {{ This algorithm is pretty inefficient if the lines
* are much longer than the screen width,
* but I don't know of any better way. }}
*/
if (ch_seek(new_pos))
{
null_line();
return (NULL_POSITION);
}
endline = 0;
loop:
begin_new_pos = new_pos;
prewind();
plinenum(new_pos);
(void) ch_seek(new_pos);
do
{
c = ch_forw_get();
if (c == EOI || sigs)
{
null_line();
return (NULL_POSITION);
}
new_pos++;
/* if (c == '\n') */
if (c == '\r' || c == '\n')
{
endline = 1;
break;
}
if (pappend(c))
{
/*
* Got a full printable line, but we haven't
* reached our curr_pos yet. Discard the line
* and start a new one.
*/
if (chopline)
{
endline = 1;
break;
}
pdone(0);
(void) ch_back_get();
new_pos--;
goto loop;
}
} while (new_pos < curr_pos);
pdone(endline);
return (begin_new_pos);
}

267
bin/less/jump.c Normal file
View File

@ -0,0 +1,267 @@
/*
* Routines which jump to a new location in the file.
*/
#pragma noroot
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern int hit_eof;
extern int jump_sline;
extern int squished;
extern int screen_trashed;
extern int sc_width, sc_height;
/*
* Jump to the end of the file.
*/
public void
jump_forw(void)
{
POSITION pos;
if (ch_end_seek())
{
error("Cannot seek to end of file", NULL_PARG);
return;
}
/*
* Position the last line in the file at the last screen line.
* Go back one line from the end of the file
* to get to the beginning of the last line.
*/
pos = back_line(ch_tell());
if (pos == NULL_POSITION)
jump_loc((POSITION)0, sc_height-1);
else
jump_loc(pos, sc_height-1);
}
/*
* Jump to line n in the file.
*/
public void
jump_back(n)
int n;
{
POSITION pos;
PARG parg;
/*
* Find the position of the specified line.
* If we can seek there, just jump to it.
* If we can't seek, but we're trying to go to line number 1,
* use ch_beg_seek() to get as close as we can.
*/
pos = find_pos(n);
if (pos != NULL_POSITION && ch_seek(pos) == 0)
{
jump_loc(pos, jump_sline);
} else if (n <= 1 && ch_beg_seek() == 0)
{
jump_loc(ch_tell(), jump_sline);
error("Cannot seek to beginning of file", NULL_PARG);
} else
{
parg.p_int = n;
error("Cannot seek to line number %d", &parg);
}
}
/*
* Repaint the screen.
*/
public void
repaint(void)
{
struct scrpos scrpos;
/*
* Start at the line currently at the top of the screen
* and redisplay the screen.
*/
get_scrpos(&scrpos);
pos_clear();
jump_loc(scrpos.pos, scrpos.ln);
}
/*
* Jump to a specified percentage into the file.
*/
public void
jump_percent(percent)
int percent;
{
POSITION pos, len;
/*
* Determine the position in the file
* (the specified percentage of the file's length).
*/
if ((len = ch_length()) == NULL_POSITION)
{
error("Don't know length of file", NULL_PARG);
return;
}
/*
* {{ This calculation may overflow! }}
*/
pos = (percent * len) / 100;
if (pos >= len)
pos = len-1;
jump_line_loc(pos, jump_sline);
}
/*
* Jump to a specified position in the file.
* Like jump_loc, but the position need not be
* the first character in a line.
*/
public void
jump_line_loc(pos, sline)
POSITION pos;
int sline;
{
int c;
if (ch_seek(pos) == 0)
{
/*
* Back up to the beginning of the line.
*/
/* while ((c = ch_back_get()) != '\n' && c != EOI) */
while ((c = ch_back_get()) != '\r' && c != '\n' && c != EOI)
;
/* if (c == '\n') */
if (c == '\r' || c == '\n')
(void) ch_forw_get();
pos = ch_tell();
}
jump_loc(pos, sline);
}
/*
* Jump to a specified position in the file.
* The position must be the first character in a line.
* Place the target line on a specified line on the screen.
*/
public void
jump_loc(pos, sline)
POSITION pos;
int sline;
{
register int nline;
POSITION tpos;
POSITION bpos;
/*
* Normalize sline.
*/
sline = adjsline(sline);
if ((nline = onscreen(pos)) >= 0)
{
/*
* The line is currently displayed.
* Just scroll there.
*/
nline -= sline;
if (nline > 0)
forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0);
else
back(-nline, position(TOP), 1, 0);
return;
}
/*
* Line is not on screen.
* Seek to the desired location.
*/
if (ch_seek(pos))
{
error("Cannot seek to that file position", NULL_PARG);
return;
}
/*
* See if the desired line is before or after
* the currently displayed screen.
*/
tpos = position(TOP);
bpos = position(BOTTOM_PLUS_ONE);
if (tpos == NULL_POSITION || pos >= tpos)
{
/*
* The desired line is after the current screen.
* Move back in the file far enough so that we can
* call forw() and put the desired line at the
* sline-th line on the screen.
*/
for (nline = 0; nline < sline; nline++)
{
if (bpos != NULL_POSITION && pos <= bpos)
{
/*
* Surprise! The desired line is
* close enough to the current screen
* that we can just scroll there after all.
*/
forw(sc_height-sline+nline-1, bpos, 1, 0, 0);
return;
}
pos = back_line(pos);
if (pos == NULL_POSITION)
{
/*
* Oops. Ran into the beginning of the file.
* Exit the loop here and rely on forw()
* below to draw the required number of
* blank lines at the top of the screen.
*/
break;
}
}
lastmark();
hit_eof = 0;
squished = 0;
screen_trashed = 0;
forw(sc_height-1, pos, 1, 0, sline-nline);
} else
{
/*
* The desired line is before the current screen.
* Move forward in the file far enough so that we
* can call back() and put the desired line at the
* sline-th line on the screen.
*/
for (nline = sline; nline < sc_height - 1; nline++)
{
pos = forw_line(pos);
if (pos == NULL_POSITION)
{
/* Cannot happen! */
error("Program error: EOI in jump_loc (forw)",
NULL_PARG);
quit(1);
}
if (pos >= tpos)
{
/*
* Surprise! The desired line is
* close enough to the current screen
* that we can just scroll there after all.
*/
back(nline+1, tpos, 1, 0);
return;
}
}
lastmark();
clear();
screen_trashed = 0;
add_back_pos(pos);
back(sc_height-1, pos, 1, 0);
}
}

946
bin/less/less.1 Normal file
View File

@ -0,0 +1,946 @@
.TH LESS 1
.SH NAME
less \- opposite of more
.SH SYNOPSIS
.B "less -?"
.br
.B "less [-[+]aBcCdeEfHimMnNqQrsSuUw]"
.br
.B " [-b \fIbufs\fP] [-h \fIlines\fP] [-j \fIline\fP] [-k \fIkeyfile\fP]"
.br
.B " [-{oO} \fIlogfile\fP] [-p \fIpattern\fP] [-P \fIprompt\fP] [-t \fItag\fP]"
.br
.B " [-T \fItagfile\fP] [-x \fItab\fP] [-y \fIlines\fP] [-[z] \fIlines\fP]"
.br
.B " [+[+]\fIcmd\fP] [\fIfilename\fP]..."
.SH DESCRIPTION
.I Less
is a program similar to
.I more
(1), but which allows backward movement
in the file as well as forward movement.
Also,
.I less
does not have to read the entire input file before starting,
so with large input files it starts up faster than text editors like
.I vi
(1).
.I Less
uses termcap (or terminfo on some systems),
so it can run on a variety of terminals.
There is even limited support for hardcopy terminals.
(On a hardcopy terminal, lines which should be printed at the top
of the screen are prefixed with an up-arrow.)
.PP
Commands are based on both
.I more
and
.I vi.
Commands may be preceded by a decimal number,
called N in the descriptions below.
The number is used by some commands, as indicated.
.SH COMMANDS
In the following descriptions, ^X means control-X.
ESC stands for the ESCAPE key; for example ESC-v means the
two character sequence "ESCAPE", then "v".
.IP "h or H"
Help: display a summary of these commands.
If you forget all the other commands, remember this one.
.PP
.IP "SPACE or ^V or f or ^F"
Scroll forward N lines, default one window (see option -z below).
If N is more than the screen size, only the final screenful is displayed.
Warning: some systems use ^V as a special literalization character.
.PP
.IP "z"
Like SPACE, but if N is specified, it becomes the new window size.
.PP
.IP "RETURN or ^N or e or ^E or j or ^J"
Scroll forward N lines, default 1.
The entire N lines are displayed, even if N is more than the screen size.
.PP
.IP "d or ^D"
Scroll forward N lines, default one half of the screen size.
If N is specified, it becomes the new default for
subsequent d and u commands.
.PP
.IP "b or ^B or ESC-v"
Scroll backward N lines, default one window (see option -z below).
If N is more than the screen size, only the final screenful is displayed.
.PP
.IP "w"
Like ESC-v, but if N is specified, it becomes the new window size.
.PP
.IP "y or ^Y or ^P or k or ^K"
Scroll backward N lines, default 1.
The entire N lines are displayed, even if N is more than the screen size.
Warning: some systems use ^Y as a special job control character.
.PP
.IP "u or ^U"
Scroll backward N lines, default one half of the screen size.
If N is specified, it becomes the new default for
subsequent d and u commands.
.PP
.IP "r or ^R or ^L"
Repaint the screen.
.PP
.IP R
Repaint the screen, discarding any buffered input.
Useful if the file is changing while it is being viewed.
.PP
.IP "F"
Scroll forward, and keep trying to read when the
end of file is reached.
Normally this command would be used when already at the end of the file.
It is a way to monitor the tail of a file which is growing
while it is being viewed.
(The behavior is similar to the "tail -f" command.)
.PP
.IP "g or < or ESC-<"
Go to line N in the file, default 1 (beginning of file).
(Warning: this may be slow if N is large.)
.PP
.IP "G or > or ESC->"
Go to line N in the file, default the end of the file.
(Warning: this may be slow if N is large,
or if N is not specified and
standard input, rather than a file, is being read.)
.PP
.IP "p or %"
Go to a position N percent into the file.
N should be between 0 and 100.
(This works if standard input is being read, but only if
.I less
has already read to the end of the file.
It is always fast, but not always useful.)
.PP
.IP "{"
If a left curly bracket appears in the top line displayed
on the screen,
the { command will go to the matching right curly bracket.
The matching right curly bracket is positioned on the bottom
line of the screen.
If there is more than one left curly bracket on the top line,
a number N may be used to specify the N-th bracket on the line.
.PP
.IP "}"
If a right curly bracket appears in the bottom line displayed
on the screen,
the } command will go to the matching left curly bracket.
The matching left curly bracket is positioned on the top
line of the screen.
If there is more than one right curly bracket on the top line,
a number N may be used to specify the N-th bracket on the line.
.PP
.IP "("
Like {, but applies to parentheses rather than curly brackets.
.PP
.IP ")"
Like }, but applies to parentheses rather than curly brackets.
.PP
.IP "["
Like {, but applies to square brackets rather than curly brackets.
.PP
.IP "]"
Like }, but applies to square brackets rather than curly brackets.
.PP
.IP "ESC-^F"
Followed by two characters,
acts like {, but uses the two characters as open and close brackets,
respectively.
For example, "ESC ^F < >" could be used to
go forward to the > which matches the < in the top displayed line.
.IP "ESC-^B"
Followed by two characters,
acts like }, but uses the two characters as open and close brackets,
respectively.
For example, "ESC ^B < >" could be used to
go backward to the < which matches the > in the bottom displayed line.
.IP m
Followed by any lowercase letter,
marks the current position with that letter.
.PP
.IP "'"
(Single quote.)
Followed by any lowercase letter, returns to the position which
was previously marked with that letter.
Followed by another single quote, returns to the position at
which the last "large" movement command was executed.
Followed by a ^ or $, jumps to the beginning or end of the
file respectively.
Marks are preserved when a new file is examined,
so the ' command can be used to switch between input files.
.PP
.IP "^X^X"
Same as single quote.
.PP
.IP /pattern
Search forward in the file for the N-th line containing the pattern.
N defaults to 1.
The pattern is a regular expression, as recognized by
.I ed.
The search starts at the second line displayed
(but see the -a and -j options, which change this).
.sp
Certain characters are special
if entered at the beginning of the pattern;
they modify the type of search rather than become part of the pattern:
.RS
.IP !
Search for lines which do NOT match the pattern.
.IP *
Search multiple files.
That is, if the search reaches the end of the current file
without finding a match,
the search continues in the next file in the command line list.
.IP @
Begin the search at the first line of the first file
in the command line list,
regardless of what is currently displayed on the screen
or the settings of the -a or -j options.
.RE
.PP
.IP ?pattern
Search backward in the file for the N-th line containing the pattern.
The search starts at the line immediately before the top line displayed.
.sp
Certain characters are special as in the / command:
.RS
.IP !
Search for lines which do NOT match the pattern.
.IP *
Search multiple files.
That is, if the search reaches the beginning of the current file
without finding a match,
the search continues in the previous file in the command line list.
.IP @
Begin the search at the last line of the last file
in the command line list,
regardless of what is currently displayed on the screen
or the settings of the -a or -j options.
.RE
.PP
.IP "ESC-/pattern"
Same as "/*".
.PP
.IP "ESC-?pattern"
Same as "?*".
.PP
.IP n
Repeat previous search, for N-th line containing the last pattern.
If the previous search was modified by !, the search is made for the
N-th line NOT containing the pattern.
If the previous search was modified by *, the search continues
in the next (or previous) file if not satisfied in the current file.
There is no effect if the previous search was modified by @.
.PP
.IP N
Repeat previous search, but in the reverse direction.
.PP
.IP "ESC-n"
Repeat previous search, but crossing file boundaries.
The effect is as if the previous search were modified by *.
.PP
.IP "ESC-N"
Repeat previous search, but in the reverse direction
and crossing file boundaries.
.PP
.IP ":e [filename]"
Examine a new file.
If the filename is missing, the "current" file (see the :n and :p commands
below) from the list of files in the command line is re-examined.
A percent sign (%) in the filename is replaced by the name of the
current file.
A pound sign (#) is replaced by the name of the previously examined file.
The filename is inserted into the command line list of files
so that it can be seen by subsequent :n and :p commands.
If the filename consists of several files, they are all inserted into
the list of files and the first one is examined.
.PP
.IP "^X^V or E"
Same as :e.
Warning: some systems use ^V as a special literalization character.
.PP
.IP ":n"
Examine the next file (from the list of files given in the command line).
If a number N is specified, the N-th next file is examined.
.PP
.IP ":p"
Examine the previous file in the command line list.
If a number N is specified, the N-th previous file is examined.
.PP
.IP ":x"
Examine the first file in the command line list.
If a number N is specified, the N-th file in the list is examined.
.PP
.IP "= or ^G or :f"
Prints some information about the file being viewed,
including its name
and the line number and byte offset of the bottom line being displayed.
If possible, it also prints the length of the file,
the number of lines in the file
and the percent of the file above the last displayed line.
.PP
.IP \-
Followed by one of the command line option letters (see below),
this will change the setting of that option
and print a message describing the new setting.
If the option letter has a numeric value (such as -b or -h),
or a string value (such as -P or -t),
a new value may be entered after the option letter.
If no new value is entered, a message describing
the current setting is printed and nothing is changed.
.PP
.IP \-+
Followed by one of the command line option letters (see below),
this will reset the option to its default setting
and print a message describing the new setting.
(The "\-+\fIX\fP" command does the same thing
as "\-+\fIX\fP" on the command line.)
This does not work for string-valued options.
.PP
.IP \-\-
Followed by one of the command line option letters (see below),
this will reset the option to the "opposite" of its default setting
and print a message describing the new setting.
(The "\-\-\fIX\fP" command does the same thing
as "\-\fIX\fP" on the command line.)
This does not work for numeric or string-valued options.
.PP
.IP _
(Underscore.)
Followed by one of the command line option letters (see below),
this will print a message describing the current setting of that option.
The setting of the option is not changed.
.PP
.IP +cmd
Causes the specified cmd to be executed each time a new file is examined.
For example, +G causes
.I less
to initially display each file starting at the end
rather than the beginning.
.PP
.IP V
Prints the version number of
.I less
being run.
.PP
.IP "q or :q or :Q or ZZ or ESC ESC"
Exits
.I less.
.PP
The following
three
commands may or may not be valid, depending on your particular installation.
.PP
.IP v
Invokes an editor to edit the current file being viewed.
The editor is taken from the environment variable EDITOR,
or defaults to "vi".
See also the discussion of LESSEDIT under the section on PROMPTS below.
.PP
.IP "! shell-command"
Invokes a shell to run the shell-command given.
A percent sign (%) in the command is replaced by the name of the
current file.
A pound sign (#) is replaced by the name of the previously examined file.
"!!" repeats the last shell command.
"!" with no shell command simply invokes a shell.
In all cases, the shell is taken from the environment variable SHELL,
or defaults to "sh".
.PP
.IP "| <m> shell-command"
<m> represents any mark letter.
Pipes a section of the input file to the given shell command.
The section of the file to be piped is between the first line on
the current screen and the position marked by the letter.
<m> may also be ^ or $ to indicate beginning or end of file respectively.
If <m> is . or newline, the current screen is piped.
.PP
.SH OPTIONS
Command line options are described below.
Most options may be changed while
.I less
is running, via the "\-" command.
.PP
Options are also taken from the environment variable "LESS".
For example,
to avoid typing "less -options ..." each time
.I less
is invoked, you might tell
.I csh:
.sp
setenv LESS "-options"
.sp
or if you use
.I sh:
.sp
LESS="-options"; export LESS
.sp
The environment variable is parsed before the command line,
so command line options override the LESS environment variable.
If an option appears in the LESS variable, it can be reset
to its default on the command line by beginning the command
line option with "-+".
.sp
A dollar sign ($) may be used to signal the end of an option string.
This is important only for options like -P which take a
following string.
.IP -?
This option displays a summary of the commands accepted by
.I less
(the same as the h command).
If this option is given, all other options are ignored, and
.I less
exits after the help screen is viewed.
(Depending on how your shell interprets the question mark,
it may be necessary to quote the question mark, thus: "-\\?".)
.IP -a
Causes searches to start after the last line
displayed on the screen,
thus skipping all lines displayed on the screen.
By default, searches start at the second line on the screen
(or after the last found line; see the -j option).
.IP -b\fIn\fP
Causes
.I less
to use a non-standard number of buffers.
Buffers are 1K, and by default 10 buffers are used
(except if data in coming from standard input; see the -B option).
The number \fIn\fP specifies a different number of buffers to use.
.IP -B
Disables automatic allocation of buffers,
so that only the default number of buffers are used.
If more data is read than will fit in the buffers, the oldest
data is discarded.
By default, when data is coming from standard input,
buffers are allocated automatically as needed
to avoid loss of data.
.IP -c
Causes full screen repaints to be painted from the top line down.
By default,
full screen repaints are done by scrolling from the bottom of the screen.
.IP -C
The -C option is like -c, but the screen is cleared before it is repainted.
.IP -d
The -d option suppresses the error message
normally displayed if the terminal is dumb;
that is, lacks some important capability,
such as the ability to clear the screen or scroll backward.
The -d option does not otherwise change the behavior of
.I less
on a dumb terminal).
.IP -e
Causes
.I less
to automatically exit
the second time it reaches end-of-file.
By default, the only way to exit
.I less
is via the "q" command.
.IP -E
Causes
.I less
to automatically exit the first time it reaches end-of-file.
.IP -f
Forces non-regular files to be opened.
(A non-regular file is a directory or a device special file.)
Also suppresses the warning message when a binary file is opened.
By default,
.I less
will refuse to open non-regular files.
.IP -h\fIn\fP
Specifies a maximum number of lines to scroll backward.
If it is necessary to scroll backward more than \fIn\fP lines,
the screen is repainted in a forward direction instead.
(If the terminal does not have the ability to scroll
backward, -h0 is implied.)
.IP -i
Causes searches to ignore case; that is,
uppercase and lowercase are considered identical.
Also, text which is overstruck or underlined can be searched for.
This option is ignored if any uppercase letters
appear in the search pattern.
.IP -j\fIn\fP
Specifies a line on the screen where "target" lines
are to be positioned.
Target lines are the object of text searches,
tag searches, jumps to a line number,
jumps to a file percentage, and jumps to a marked position.
The screen line is specified by a number: the top line on the screen
is 1, the next is 2, and so on.
The number may be negative to specify a line relative to the bottom
of the screen: the bottom line on the screen is -1, the second
to the bottom is -2, and so on.
If the -j option is used, searches begin at the line immediately
after the target line.
For example, if "-j4" is used, the target line is the
fourth line on the screen, so searches begin at the fifth line
on the screen.
.IP -k\fIfilename\fP
Causes
.I less
to open and interpret the named file as a
.I lesskey
(1) file.
Multiple -k options may be specified.
If a file called .less exists in the user's home directory, this
file is also used as a
.I lesskey
file.
.IP -m
Causes
.I less
to prompt verbosely (like \fImore\fP),
with the percent into the file.
By default,
.I less
prompts with a colon.
.IP -M
Causes
.I less
to prompt even more verbosely than
.I more.
.IP -n
Suppresses line numbers.
The default (to use line numbers) may cause
.I less
to run more slowly in some cases, especially with a very large input file.
Suppressing line numbers with the -n flag will avoid this problem.
Using line numbers means: the line number will be displayed in the verbose
prompt and in the = command,
and the v command will pass the current line number to the editor
(see also the discussion of LESSEDIT in PROMPTS below).
.IP -N
Causes a line number to be displayed at the beginning of
each line in the display.
.IP -o\fIfilename\fP
Causes
.I less
to copy its input to the named file as it is being viewed.
This applies only when the input file is a pipe,
not an ordinary file.
If the file already exists,
.I less
will ask for confirmation before overwriting it.
.IP -O\fIfilename\fP
The -O option is like -o, but it will overwrite an existing
file without asking for confirmation.
.sp
If no log file has been specified,
the -o and -O options can be used from within
.I less
to specify a log file.
Without a file name, they will simply report the name of the log file.
The "s" command is equivalent to specifying -o from within
.I less.
.IP -p\fIpattern\fP
The -p option on the command line is equivalent to
specifying +/\fIpattern\fP;
that is, it tells
.I less
to start at the first occurence of \fIpattern\fP in the file.
.IP -P\fIprompt\fP
Provides a way to tailor the three prompt
styles to your own preference.
This option would normally be put in the LESS environment
variable, rather than being typed in with each
.I less
command.
Such an option must either be the last option in the LESS variable,
or be terminated by a dollar sign.
-P followed by a string changes the default (short) prompt to that string.
-Pm changes the medium (-m) prompt to the string, and
-PM changes the long (-M) prompt.
Also, -P= changes the message printed by the = command to the given string.
All prompt strings consist of a sequence of
letters and special escape sequences.
See the section on PROMPTS for more details.
.IP -q
Causes moderately "quiet" operation:
the terminal bell is not rung
if an attempt is made to scroll past the end of the file
or before the beginning of the file.
If the terminal has a "visual bell", it is used instead.
The bell will be rung on certain other errors,
such as typing an invalid character.
The default is to ring the terminal bell in all such cases.
.IP -Q
Causes totally "quiet" operation:
the terminal bell is never rung.
.IP -r
Causes "raw" control characters to be displayed.
The default is to display control characters using the caret notation;
for example, a control-A (octal 001) is displayed as "^A".
Warning: when the -r flag is used,
.I less
cannot keep track of the actual appearance of the screen
(since this depends on how the screen responds to
each type of control character).
Thus, various display problems may result,
such as long lines being split in the wrong place.
.IP -s
Causes consecutive blank lines to be squeezed into a single blank line.
This is useful when viewing
.I nroff
output.
.IP -S
Causes lines longer than the screen width to be
chopped rather than folded.
That is, the remainder of a long line is simply discarded.
The default is to fold long lines; that is, display the remainder
on the next line.
.IP -t\fItag\fP
The -t option, followed immediately by a TAG,
will edit the file containing that tag.
For this to work, there must be a file called "tags" in the
current directory, which was previously built by the
.I ctags
(1) command.
This option may also be specified from within
.I less
(using the \- command) as a way of examining a new file.
The command ":t" is equivalent to specifying -t from within
.I less.
.IP -T\fItagsfile\fP
Specifies a tags file to be used instead of "tags".
.IP -u
Causes backspaces and carriage returns to be treated as printable characters;
that is, they are sent to the terminal when they appear in the input.
.IP -U
Causes backspaces and carriage returns to be treated as control characters;
that is, they are handled as specified by the -r option.
.sp
By default, if neither -u nor -U is given,
backspaces which appear adjacent to an underscore character
are treated specially:
the underlined text is displayed
using the terminal's hardware underlining capability.
Also, backspaces which appear between two identical characters
are treated specially:
the overstruck text is printed
using the terminal's hardware boldface capability.
Other backspaces are deleted, along with the preceding character.
Carriage returns immediately followed by a newline are deleted.
Other carriage returns are handled as specified by the -r option.
.IP -w
Causes blank lines to be used to represent lines
past the end of the file.
By default,
a tilde character is used.
.IP -x\fIn\fP
Sets tab stops every \fIn\fP positions.
The default for \fIn\fP is 8.
.IP -y\fIn\fP
Specifies a maximum number of lines to scroll forward.
If it is necessary to scroll forward more than \fIn\fP lines,
the screen is repainted instead.
The -c or -C option may be used to repaint from the top of
the screen if desired.
By default, any forward movement causes scrolling.
.IP -[z]\fIn\fP
Changes the default scrolling window size to \fIn\fP lines.
The default is one screenful.
The z and w commands can also be used to change the window size.
The "z" may be omitted, as in "-\fIn\fP" for compatibility with
.I more.
.IP +
If a command line option begins with \fB+\fP,
the remainder of that option is taken to be an initial command to
.I less.
For example, +G tells
.I less
to start at the end of the file rather than the beginning,
and +/xyz tells it to start at the first occurrence of "xyz" in the file.
As a special case, +<number> acts like +<number>g;
that is, it starts the display at the specified line number
(however, see the caveat under the "g" command above).
If the option starts with ++, the initial command applies to
every file being viewed, not just the first one.
The + command described previously
may also be used to set (or change) an initial command for every file.
.SH "KEY BINDINGS"
You may define your own
.I less
commands by using the program
.I lesskey
(1)
to create a file called ".less" in your home directory.
This file specifies a set of command keys and an action
associated with each key.
See the
.I lesskey
manual page for more details.
.SH "NATIONAL CHARACTER SETS"
There are three types of characters in the input file:
.IP "normal characters"
can be displayed directly to the screen.
.IP "control characters"
should not be displayed directly, but are expected to be found
in ordinary text files (such as backspace and tab).
.IP "binary characters"
cannot be displayed directly and are not expected to be found
in text files.
.PP
By default,
.I less
uses the ASCII character set.
In the ASCII character set, characters
with values between 128 and 255 are treated as binary.
The LESSCHARSET environment variable may be used to select
another character set.
If it is set to the value "latin1",
the ISO 8859/1 character set is assumed.
Latin-1 is the same as ASCII, except characters between 128 and 255 are
treated as normal characters.
The only valid values for LESSCHARSET currently are "ascii" and "latin1".
.PP
In special cases, it may be desired to tailor
.I less
to use a character set other than the ones definable by LESSCHARSET.
In this case, the environment variable LESSCHARDEF can be used
to define a character set.
It should be set to a string where each character in the string represents
one character in the character set.
The character "." is used for a normal character, "c" for control,
and "b" for binary.
A decimal number may be used for repetition.
For example, "bccc4b." would mean character 0 is binary,
1, 2 and 3 are control, 4, 5, 6 and 7 are binary, and 8 is normal.
All characters after the last are taken to be the same as the last,
so characters 9 through 255 would be normal.
(This is an example, and does not necessarily
represent any real character set.)
.PP
Setting LESSCHARDEF to "8bcccbcc18b95.b" is the same as setting
LESSCHARSET to "ascii".
Setting LESSCHARDEF to "8bcccbcc18b95.33b." is the same as setting
LESSCHARSET to "latin1".
.PP
Control and binary characters are displayed in blinking mode.
Each such character is displayed in caret notation if possible
(e.g. ^A for control-A). Caret notation is used only if
inverting the 0100 bit results in a normal printable character.
Otherwise, the character is displayed as an octal number preceded
by a backslash.
This octal format can be changed by
setting the LESSBINFMT environment variable
to a printf-style format string; the default is '\\%o'.
The blinking mode display of control and binary characters can
be changed or disabled by preceding the LESSBINFMT format
string with a "*" and one character to select the mode:
"*k" is blinking, "*d" is bold, "*u" is underlined,
and "*n" is normal (no special display attribute).
For example, if LESSBINFMT is "*u[%x]", binary characters
are displayed in underlined hexadecimal surrounded by brackets.
.SH "PROMPTS"
The -P option allows you to tailor the prompt to your preference.
The string given to the -P option replaces the specified prompt string.
Certain characters in the string are interpreted specially.
The prompt mechanism is rather complicated to provide flexibility,
but the ordinary user need not understand the details of constructing
personalized prompt strings.
.sp
A percent sign followed by a single character is expanded
according to what the following character is:
.IP "%b\fIX\fP"
Replaced by the byte offset into the current input file.
The b is followed by a single character (shown as \fIX\fP above)
which specifies the line whose byte offset is to be used.
If the character is a "t", the byte offset of the top line in the
display is used,
an "m" means use the middle line,
a "b" means use the bottom line,
a "B" means use the line just after the bottom line,
and a "j" means use the "target" line, as specified by the -j option.
.IP "%B"
Replaced by the size of the current input file.
.IP "%E"
Replaced by the name of the editor (from the EDITOR environment variable).
See the discussion of the LESSEDIT feature below.
.IP "%f"
Replaced by the name of the current input file.
.IP "%i"
Replaced by the index of the current file in the list of
input files.
.IP "%l\fIX\fP"
Replaced by the line number of a line in the input file.
The line to be used is determined by the \fIX\fP, as with the %b option.
.IP "%L"
Replaced by the line number of the last line in the input file.
.IP "%m"
Replaced by the total number of input files.
.IP "%p\fIX\fP"
Replaced by the percent into the current input file.
The line used is determined by the \fIX\fP as with the %b option.
.IP "%s"
Same as %B.
.IP "%t"
Causes any trailing spaces to be removed.
Usually used at the end of the string, but may appear anywhere.
.IP "%x"
Replaced by the name of the next input file in the list.
.PP
If any item is unknown (for example, the file size if input
is a pipe), a question mark is printed instead.
.PP
The format of the prompt string can be changed
depending on certain conditions.
A question mark followed by a single character acts like an "IF":
depending on the following character, a condition is evaluated.
If the condition is true, any characters following the question mark
and condition character, up to a period, are included in the prompt.
If the condition is false, such characters are not included.
A colon appearing between the question mark and the
period can be used to establish an "ELSE": any characters between
the colon and the period are included in the string if and only if
the IF condition is false.
Condition characters (which follow a question mark) may be:
.IP "?a"
True if any characters have been included in the prompt so far.
.IP "?b\fIX\fP"
True if the byte offset of the specified line is known.
.IP "?B"
True if the size of current input file is known.
.IP "?e"
True if at end-of-file.
.IP "?f"
True if there is an input filename
(that is, if input is not a pipe).
.IP "?l\fIX\fP"
True if the line number of the specified line is known.
.IP "?L"
True if the line number of the last line in the file is known.
.IP "?m"
True if there is more than one input file.
.IP "?n"
True if this is the first prompt in a new input file.
.IP "?p\fIX\fP"
True if the percent into the current input file
of the specified line is known.
.IP "?s"
Same as "?B".
.IP "?x"
True if there is a next input file
(that is, if the current input file is not the last one).
.PP
Any characters other than the special ones
(question mark, colon, period, percent, and backslash)
become literally part of the prompt.
Any of the special characters may be included in the prompt literally
by preceding it with a backslash.
.PP
Some examples:
.sp
?f%f:Standard input.
.sp
This prompt prints the filename, if known;
otherwise the string "Standard input".
.sp
?f%f .?ltLine %lt:?pt%pt\\%:?btByte %bt:-...
.sp
This prompt would print the filename, if known.
The filename is followed by the line number, if known,
otherwise the percent if known, otherwise the byte offset if known.
Otherwise, a dash is printed.
Notice how each question mark has a matching period,
and how the % after the %pt
is included literally by escaping it with a backslash.
.sp
?n?f%f\ .?m(file\ %i\ of\ %m)\ ..?e(END)\ ?x-\ Next\\:\ %x..%t
.sp
This prints the filename if this is the first prompt in a file,
followed by the "file N of N" message if there is more
than one input file.
Then, if we are at end-of-file, the string "(END)" is printed
followed by the name of the next file, if there is one.
Finally, any trailing spaces are truncated.
This is the default prompt.
For reference, here are the defaults for
the other two prompts (-m and -M respectively).
Each is broken into two lines here for readability only.
.nf
.sp
?n?f%f\ .?m(file\ %i\ of\ %m)\ ..?e(END)\ ?x-\ Next\\:\ %x.:
?pB%pB\\%:byte\ %bB?s/%s...%t
.sp
?f%f\ .?n?m(file\ %i\ of\ %m)\ ..?ltline\ %lt?L/%L.\ :byte\ %bB?s/%s.\ .
?e(END)\ ?x-\ Next\\:\ %x.:?pB%pB\\%..%t
.sp
.fi
And here is the default message produced by the = command:
.nf
.sp
?f%f\ .?m(file\ %i\ of\ %m)\ .?ltline\ %lt?L/%L.\ .
byte\ %bB?s/%s.\ ?e(END)\ :?pB%pB\\%..%t
.fi
.PP
The prompt expansion features are also used for another purpose:
if an environment variable LESSEDIT is defined, it is used
as the command to be executed when the v command is invoked.
The LESSEDIT string is expanded in the same way as the prompt strings.
The default value for LESSEDIT is:
.nf
.sp
%E\ ?lm+%lm.\ %f
.sp
.fi
Note that this expands to the editor name, followed by a + and the
line number, followed by the file name.
If your editor does not accept the "+linenumber" syntax, or has other
differences in invocation syntax, the LESSEDIT variable can be
changed to modify this default.
.SH "ENVIRONMENT VARIABLES"
.IP COLUMNS
Sets the number of columns on the screen.
Takes precedence over the number of columns specified by the TERM variable.
.IP EDITOR
The name of the editor (used for the v command).
.IP HOME
Name of the user's home directory (used to find a .less file).
.IP LESS
Flags which are passed to
.I less
automatically.
.IP LESSBINFMT
Format for displaying non-printable, non-control characters.
.IP LESSCHARDEF
Defines a character set.
.IP LESSCHARSET
Selects a predefined character set.
.IP LESSEDIT
Editor prototype string (used for the v command).
See discussion under PROMPTS.
.IP LESSHELP
Name of the help file.
.IP LINES
Sets the number of lines on the screen.
Takes precedence over the number of lines specified by the TERM variable.
.IP SHELL
The shell used to execute the ! command, as well as to expand filenames.
.IP TERM
The type of terminal on which
.I less
is being run.
.SH "SEE ALSO"
lesskey(1)
.SH WARNINGS
The = command and prompts (unless changed by -P)
report the line number of the line at the top of the screen,
but the byte and percent of the line at the bottom of the screen.
.PP
If the :e command is used to name more than one file,
and one of the named files has been viewed previously,
the new files may be entered into the list in an unexpected order.
.PP
The handling of national character sets is nonstandard as well as
insufficient for multibyte characters.
It will probably change in a later release.

123
bin/less/less.h Normal file
View File

@ -0,0 +1,123 @@
/*
* Standard include file for "less".
*/
#ifdef __ORCAC__
#define _ORCAC_
#pragma optimize -1
/* #pragma lint -1 */
#endif
#include <stdlib.h>
#include <stdio.h>
#include <gno/gno.h>
/*
* Include the file of compile-time options.
*/
#include "defines.h"
/*
* Language details.
*/
#if !VOID
#define void int
#endif
#define public /* PUBLIC FUNCTION */
/*
* Special types and constants.
*/
typedef long POSITION;
/*
* {{ Warning: if POSITION is changed to other than "long",
* you may have to change some of the printfs which use "%ld"
* to print a variable of type POSITION. }}
*/
#define NULL_POSITION ((POSITION)(-1))
/*
* The type of an interrupt handler.
*/
#define HANDLER void
/*
* An IFILE represents an input file.
*/
#define IFILE VOID_POINTER
#define NULL_IFILE ((IFILE)NULL)
/*
* The structure used to represent a "screen position".
* This consists of a file position, and a screen line number.
* The meaning is that the line starting at the given file
* position is displayed on the ln-th line of the screen.
* (Screen lines before ln are empty.)
*/
struct scrpos
{
POSITION pos;
int ln;
};
typedef union parg
{
char *p_string;
int p_int;
} PARG;
#define NULL_PARG ((PARG *)NULL)
#define EOI (-1)
#ifndef NULL
#define NULL (0)
#endif
#define READ_INTR (-2)
/* How quiet should we be? */
#define NOT_QUIET 0 /* Ring bell at eof and for errors */
#define LITTLE_QUIET 1 /* Ring bell only for errors */
#define VERY_QUIET 2 /* Never ring bell */
/* How should we prompt? */
#define PR_SHORT 0 /* Prompt with colon */
#define PR_MEDIUM 1 /* Prompt with message */
#define PR_LONG 2 /* Prompt with longer message */
/* How should we handle backspaces? */
#define BS_SPECIAL 0 /* Do special things for underlining and bold */
#define BS_NORMAL 1 /* \b treated as normal char; actually output */
#define BS_CONTROL 2 /* \b treated as control char; prints as ^H */
/* How should we search? */
#define SRCH_FORW 0 /* Search forward from current position */
#define SRCH_BACK 1 /* Search backward from current position */
#define SRCH_NOMATCH 0100 /* Search for non-matching lines */
#define SRCH_PAST_EOF 0200 /* Search past end-of-file, into next file */
#define SRCH_FIRST_FILE 0400 /* Search starting at the first file */
#define SRCH_DIR(t) ((t) & 01)
#define SRCH_REVERSE(t) ((t) ^ 01)
/* Special chars used to tell put_line() to do something special */
#define NORMAL (0)
#define UNDERLINE (1)
#define BOLD (2)
#define BLINK (3)
#define INVIS (4)
#define CONTROL(c) ((c)&037)
#define ESC CONTROL('[')
#define SIGNAL(sig,func) signal(sig,func)
/* Library function declarations */
offset_t lseek();
#define BAD_LSEEK ((offset_t)-1)
VOID_POINTER calloc();
#define ch_zero() ((POSITION)0)
#include "proto.h"

104
bin/less/less.hlp Normal file
View File

@ -0,0 +1,104 @@
SUMMARY OF COMMANDS
Commands marked with * may be preceded by a number, N.
Notes in parentheses indicate the behavior if N is given.
h H Display this help.
q :q :Q ZZ Exit.
e ^E j ^N CR * Forward one line (or N lines).
y ^Y k ^K ^P * Backward one line (or N lines).
f ^F ^V SPACE * Forward one window (or N lines).
b ^B ESC-v * Backward one window (or N lines).
z * Forward one window (and set window to N).
w * Backward one window (and set window to N).
d ^D * Forward one half-window (and set half-window to N).
u ^U * Backward one half-window (and set half-window to N).
F Forward forever; like "tail -f".
r ^R ^L Repaint screen.
R Repaint screen, discarding buffered input.
NOTE: default "window" is the screen height.
default "half-window" is half of the screen height.
/pattern * Search forward for (N-th) matching line.
?pattern * Search backward for (N-th) matching line.
NOTE: search commands may be modified by one or more of:
! search for NON-matching lines.
* search multiple files.
@ start search at first file (for /) or last file (for ?).
n * Repeat previous search (for N-th occurrence).
N * Repeat previous search in reverse direction.
ESC-n * Repeat previous search, spanning files.
ESC-N * Repeat previous search, reverse dir. & spanning files.
g < ESC-< * Go to first line in file (or line N).
G > ESC-> * Go to last line in file (or line N).
p % * Go to beginning of file (or N percent into file).
{ * Go to the } matching the (N-th) { in the top line.
} * Go to the { matching the (N-th) } in the bottom line.
( * Go to the ) matching the (N-th) ( in the top line.
) * Go to the ( matching the (N-th) ) in the bottom line.
[ * Go to the ] matching the (N-th) [ in the top line.
] * Go to the [ matching the (N-th) ] in the bottom line.
ESC-^F <c1> <c2> * Go to the c1 matching the (N-th) c2 in the top line
ESC-^B <c1> <c2> * Go to the c2 matching the (N-th) c1 in the bottom line.
m<letter> Mark the current position with <letter>.
'<letter> Go to a previously marked position.
'' Go to the previous position.
^X^X Same as '.
E [file] Examine a new file.
:e ^X^V Same as E.
:n * Examine the (N-th) next file from the command line.
:p * Examine the (N-th) previous file from the command line.
= ^G :f Print current file name.
V Print version number of "less".
-<flag> Toggle a command line flag [see FLAGS below].
_<flag> Display the setting of a command line flag.
+cmd Execute the less cmd each time a new file is examined.
!command Passes the command to $SHELL to be executed.
|Xcommand Pipe file between current pos & mark X to shell command.
v Edit the current file with $EDITOR.
FLAGS
Most flags may be changed either on the command line,
or from within less by using the - command.
-? Display help (from command line).
-a Set forward search starting location.
-b [N] Number of buffers.
-B Automatically allocate buffers.
-c -C Repaint by scrolling/clearing.
-d Dumb terminal.
-e -E Quit at end of file.
-f Force open non-regular files.
-h [N] Backward scroll limit.
-i Ignore case in searches.
-j [N] Screen position of target lines.
-k [file] Use a lesskey file.
-m -M Set prompt style.
-n -N Use line numbers.
-o [file] Log file.
-O [file] Log file (unconditionally overwrite).
-p [pattern] Start at pattern (from command line).
-P [prompt] Define new prompt.
-q -Q Quiet the terminal bell.
-r Translate control characters.
-s Squeeze multiple blank lines.
-S Chop long lines.
-t [tag] Find a tag.
-T [tagsfile] Use an alternate tags file.
-u -U Change handling of backspaces.
-w Display ~ for lines after end-of-file.
-x [N] Set tab stops.
-y [N] Forward scroll limit.
-z [N] Set size of window.

361
bin/less/lesskey.c Normal file
View File

@ -0,0 +1,361 @@
/*
* lesskey [-o output] [input]
*
* Make a .less file.
* If no input file is specified, standard input is used.
* If no output file is specified, $HOME/.less is used.
*
* The .less file is used to specify (to "less") user-defined
* key bindings. Basically any sequence of 1 to MAX_CMDLEN
* keystrokes may be bound to an existing less function.
*
* The input file is an ascii file consisting of a
* sequence of lines of the form:
* string <whitespace> action [chars] <newline>
*
* "string" is a sequence of command characters which form
* the new user-defined command. The command
* characters may be:
* 1. The actual character itself.
* 2. A character preceded by ^ to specify a
* control character (e.g. ^X means control-X).
* 3. Any character (other than an octal digit) preceded by
* a \ to specify the character itself (characters which
* must be preceded by \ include ^, \, and whitespace.
* 4. A backslash followed by one to three octal digits
* to specify a character by its octal value.
* "action" is the name of a "less" action, from the table below.
* "chars" is an optional sequence of characters which is treated
* as keyboard input after the command is executed.
*
* Blank lines and lines which start with # are ignored.
*
*
* The output file is a non-ascii file, consisting of
* zero or more byte sequences of the form:
* string <0> <action>
* or
* string <0> <action|A_EXTRA> chars <0>
*
* "string" is the command string.
* "<0>" is one null byte.
* "<action>" is one byte containing the action code (the A_xxx value).
* If action is ORed with A_EXTRA, the action byte is followed
* by the null-terminated "chars" string.
*/
#include <stdio.h>
#include <string.h>
#include "less.h"
#include "cmd.h"
char usertable[MAX_USERCMD];
struct cmdname
{
char *cn_name;
int cn_action;
} cmdnames[] =
{
"back-bracket", A_B_BRACKET,
"back-line", A_B_LINE,
"back-line-force", A_BF_LINE,
"back-screen", A_B_SCREEN,
"back-scroll", A_B_SCROLL,
"back-search", A_B_SEARCH,
"back-window", A_B_WINDOW,
"debug", A_DEBUG,
"display-flag", A_DISP_OPTION,
"display-option", A_DISP_OPTION,
"end", A_GOEND,
"examine", A_EXAMINE,
"first-cmd", A_FIRSTCMD,
"firstcmd", A_FIRSTCMD,
"flush-repaint", A_FREPAINT,
"forw-bracket", A_F_BRACKET,
"forw-forever", A_F_FOREVER,
"forw-line", A_F_LINE,
"forw-line-force", A_FF_LINE,
"forw-screen", A_F_SCREEN,
"forw-scroll", A_F_SCROLL,
"forw-search", A_F_SEARCH,
"forw-window", A_F_WINDOW,
"goto-end", A_GOEND,
"goto-line", A_GOLINE,
"goto-mark", A_GOMARK,
"help", A_HELP,
"index-file", A_INDEX_FILE,
"invalid", A_UINVALID,
"next-file", A_NEXT_FILE,
"noaction", A_NOACTION,
"percent", A_PERCENT,
"pipe", A_PIPE,
"prev-file", A_PREV_FILE,
"quit", A_QUIT,
"repaint", A_REPAINT,
"repaint-flush", A_FREPAINT,
"repeat-search", A_AGAIN_SEARCH,
"repeat-search-all", A_T_AGAIN_SEARCH,
"reverse-search", A_REVERSE_SEARCH,
"reverse-search-all", A_T_REVERSE_SEARCH,
"set-mark", A_SETMARK,
"shell", A_SHELL,
"status", A_STAT,
"toggle-flag", A_OPT_TOGGLE,
"toggle-option", A_OPT_TOGGLE,
"version", A_VERSION,
"visual", A_VISUAL,
NULL, 0
};
main(argc, argv)
int argc;
char *argv[];
{
char *p; /* {{ Can't be register since we use &p }} */
register char *up; /* Pointer into usertable */
FILE *desc; /* Description file (input) */
FILE *out; /* Output file */
int linenum; /* Line number in input file */
char *currcmd; /* Start of current command string */
int errors;
int i, j;
char line[200];
char *outfile;
extern char *getenv();
/*
* Process command line arguments.
*/
outfile = NULL;
while (--argc > 0 && **(++argv) == '-')
{
switch (argv[0][1])
{
case 'o':
outfile = &argv[0][2];
if (*outfile == '\0')
{
if (--argc <= 0)
usage();
outfile = *(++argv);
}
break;
default:
usage();
}
}
if (argc > 1)
usage();
/*
* Open the input file, or use standard input if none specified.
*/
if (argc > 0)
{
if ((desc = fopen(*argv, "r")) == NULL)
{
perror(*argv);
exit(1);
}
} else
desc = stdin;
/*
* Read the input file, one line at a time.
* Each line consists of a command string,
* followed by white space, followed by an action name.
*/
linenum = 0;
errors = 0;
up = usertable;
while (fgets(line, sizeof(line), desc) != NULL)
{
++linenum;
/*
* Skip leading white space.
* Replace the final newline with a null byte.
* Ignore blank lines and comment lines.
*/
p = line;
while (*p == ' ' || *p == '\t')
++p;
for (i = 0; p[i] != '\n' && p[i] != '\0'; i++)
;
p[i] = '\0';
if (*p == '#' || *p == '\0')
continue;
/*
* Parse the command string and store it in the usertable.
*/
currcmd = up;
do
{
if (up >= usertable + MAX_USERCMD)
{
fprintf(stderr, "too many commands, line %d\n",
linenum);
exit(1);
}
if (up >= currcmd + MAX_CMDLEN)
{
fprintf(stderr, "command too long on line %d\n",
linenum);
errors++;
break;
}
*up++ = tchar(&p);
} while (*p != ' ' && *p != '\t' && *p != '\0');
/*
* Terminate the command string with a null byte.
*/
*up++ = '\0';
/*
* Skip white space between the command string
* and the action name.
* Terminate the action name with a null byte if it
* is followed by whitespace or a # comment.
*/
if (*p == '\0')
{
fprintf(stderr, "missing whitespace on line %d\n",
linenum);
errors++;
continue;
}
while (*p == ' ' || *p == '\t')
++p;
for (j = 0; p[j] != ' ' && p[j] != '\t' &&
p[j] != '#' && p[j] != '\0'; j++)
;
p[j] = '\0';
/*
* Parse the action name and store it in the usertable.
*/
for (i = 0; cmdnames[i].cn_name != NULL; i++)
if (strcmp(cmdnames[i].cn_name, p) == 0)
break;
if (cmdnames[i].cn_name == NULL)
{
fprintf(stderr, "unknown action <%s> on line %d\n",
p, linenum);
errors++;
continue;
}
*up++ = cmdnames[i].cn_action;
/*
* See if an extra string follows the action name.
*/
for (j = j+1; p[j] == ' ' || p[j] == '\t'; j++)
;
p += j;
if (*p != '\0')
{
/*
* OR the special value A_EXTRA into the action byte.
* Put the extra string after the action byte.
*/
up[-1] |= A_EXTRA;
while (*p != '\0')
*up++ = tchar(&p);
*up++ = '\0';
}
}
if (errors > 0)
{
fprintf(stderr, "%d errors; no output produced\n", errors);
exit(1);
}
/*
* Write the output file.
* If no output file was specified, use "$HOME/.less"
*/
if (outfile == NULL)
{
p = getenv("HOME");
if (p == NULL || *p == '\0')
{
fprintf(stderr, "cannot find $HOME - using current directory\n");
#if __MSDOS__
strcpy(line, "_less");
#else
strcpy(line, "lessrc");
#endif
} else
{
strcpy(line, p);
#if __MSDOS__
strcat(line, "\\_less");
#else
strcat(line, "/lessrc");
#endif
}
outfile = line;
}
if ((out = fopen(outfile, "w")) == NULL)
perror(outfile);
else
fwrite((char *)usertable, 1, up-usertable, out);
exit(0);
}
/*
* Parse one character of a string.
*/
tchar(pp)
char **pp;
{
register char *p;
register char ch;
register int i;
p = *pp;
switch (*p)
{
case '\\':
if (*++p >= '0' && *p <= '7')
{
/*
* Parse an octal number.
*/
ch = 0;
i = 0;
do
ch = 8*ch + (*p - '0');
while (*++p >= '0' && *p <= '7' && ++i < 3);
*pp = p;
return (ch);
}
/*
* Backslash followed by a char just means that char.
*/
*pp = p+1;
return (*p);
case '^':
/*
* Carat means CONTROL.
*/
*pp = p+2;
return (CONTROL(p[1]));
}
*pp = p+1;
return (*p);
}
usage()
{
fprintf(stderr, "usage: lesskey [-o output] [input]\n");
exit(1);
}

540
bin/less/line.c Normal file
View File

@ -0,0 +1,540 @@
/*
* Routines to manipulate the "line buffer".
* The line buffer holds a line of output as it is being built
* in preparation for output to the screen.
*/
#pragma noroot
#include "less.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
static char linebuf[1024]; /* Buffer which holds the current output line */
static char attr[1024]; /* Extension of linebuf to hold attributes */
static int curr; /* Index into linebuf */
static int column; /* Printable length, accounting for
backspaces, etc. */
static int overstrike; /* Next char should overstrike previous char */
static int is_null_line; /* There is no current line */
static char pendc;
extern int bs_mode;
extern int tabstop;
extern int linenums;
extern int ctldisp;
extern int twiddle;
extern int binattr;
extern int auto_wrap, ignaw;
extern int bo_s_width, bo_e_width;
extern int ul_s_width, ul_e_width;
extern int bl_s_width, bl_e_width;
extern int sc_width, sc_height;
static int pwidth(int c, int a);
static void backc(void);
static int storec(int c, int a);
static int do_append(int c);
/*
* Rewind the line buffer.
*/
public void
prewind(void)
{
curr = 0;
column = 0;
overstrike = 0;
is_null_line = 0;
pendc = '\0';
}
/*
* Insert the line number (of the given position) into the line buffer.
*/
public void
plinenum(pos)
POSITION pos;
{
register int lno;
register int i;
register int n;
/*
* We display the line number at the start of each line
* only if the -N option is set.
*/
if (linenums != 2)
return;
/*
* Get the line number and put it in the current line.
* {{ Note: since find_linenum calls forw_raw_line,
* it may seek in the input file, requiring the caller
* of plinenum to re-seek if necessary. }}
*/
lno = find_linenum(pos);
sprintf(&linebuf[curr], "%6d", lno);
n = strlen(&linebuf[curr]);
column += n;
for (i = 0; i < n; i++)
attr[curr++] = 0;
/*
* Append enough spaces to bring us to the next tab stop.
* {{ We could avoid this at the cost of adding some
* complication to the tab stop logic in pappend(). }}
*/
do
{
linebuf[curr] = ' ';
attr[curr++] = 0;
column++;
} while ((column % tabstop) != 0);
}
/*
* Return the printing width of the start (enter) sequence
* for a given character attribute.
*/
int
attr_swidth(a)
int a;
{
switch (a)
{
case BOLD: return (bo_s_width);
case UNDERLINE: return (ul_s_width);
case BLINK: return (bl_s_width);
}
return (0);
}
/*
* Return the printing width of the end (exit) sequence
* for a given character attribute.
*/
int
attr_ewidth(a)
int a;
{
switch (a)
{
case BOLD: return (bo_e_width);
case UNDERLINE: return (ul_e_width);
case BLINK: return (bl_e_width);
}
return (0);
}
/*
* Return the printing width of a given character and attribute,
* if the character were added to the current position in the line buffer.
* Adding a character with a given attribute may cause an enter or exit
* attribute sequence to be inserted, so this must be taken into account.
*/
static int
pwidth(c, a)
int c;
int a;
{
register int w;
if (c == '\b')
/*
* Backspace moves backwards one position.
*/
return (-1);
if (control_char(c))
/*
* Control characters do unpredicatable things,
* so we don't even try to guess; say it doesn't move.
* This can only happen if the -r flag is in effect.
*/
return (0);
/*
* Other characters take one space,
* plus the width of any attribute enter/exit sequence.
*/
w = 1;
if (curr > 0 && attr[curr-1] != a)
w += attr_ewidth(attr[curr-1]);
if (a && (curr == 0 || attr[curr-1] != a))
w += attr_swidth(a);
return (w);
}
/*
* Delete the previous character in the line buffer.
*/
static void
backc(void)
{
curr--;
column -= pwidth(linebuf[curr], attr[curr]);
}
/*
* Append a character and attribute to the line buffer.
*/
static int
storec(c, a)
int c;
int a;
{
register int w;
w = pwidth(c, a);
if (ctldisp > 0 && column + w + attr_ewidth(a) > sc_width)
/*
* Won't fit on screen.
*/
return (1);
if (curr >= sizeof(linebuf)-2)
/*
* Won't fit in line buffer.
*/
return (1);
/*
* Special handling for "magic cookie" terminals.
* If an attribute enter/exit sequence has a printing width > 0,
* and the sequence is adjacent to a space, delete the space.
* We just mark the space as invisible, to avoid having too
* many spaces deleted.
* {{ Note that even if the attribute width is > 1, we
* delete only one space. It's not worth trying to do more.
* It's hardly worth doing this much. }}
*/
if (curr > 0 && a != NORMAL &&
linebuf[curr-1] == ' ' && attr[curr-1] == NORMAL &&
attr_swidth(a) > 0)
{
/*
* We are about to append an enter-attribute sequence
* just after a space. Delete the space.
*/
attr[curr-1] = INVIS;
column--;
} else if (curr > 0 && attr[curr-1] != NORMAL &&
attr[curr-1] != INVIS && c == ' ' && a == NORMAL &&
attr_ewidth(attr[curr-1]) > 0)
{
/*
* We are about to append a space just after an
* exit-attribute sequence. Delete the space.
*/
a = INVIS;
column--;
}
/* End of magic cookie handling. */
linebuf[curr] = c;
attr[curr] = a;
column += w;
return (0);
}
/*
* Append a character to the line buffer.
* Expand tabs into spaces, handle underlining, boldfacing, etc.
* Returns 0 if ok, 1 if couldn't fit in buffer.
*/
public int
pappend(c)
register int c;
{
if (pendc)
{
if (do_append(pendc))
/*
* Oops. We've probably lost the char which
* was in pendc, since caller won't back up.
*/
return (1);
pendc = '\0';
}
/* if (c == '\r' && bs_mode == BS_SPECIAL)*/
if ((c == '\r' || c == '\n') && bs_mode == BS_SPECIAL)
{
/*
* Don't put the CR into the buffer until we see
* the next char. If the next char is a newline,
* discard the CR.
*/
pendc = c;
return (0);
}
return (do_append(c));
}
static int
do_append(c)
int c;
{
register char *s;
register int a;
#define STOREC(c,a) if (storec((c),(a))) return (1); else curr++
if (overstrike)
{
/*
* Overstrike the character at the current position
* in the line buffer. This will cause either
* underline (if a "_" is overstruck),
* bold (if an identical character is overstruck),
* or just deletion of the character in the buffer.
*/
overstrike = 0;
if (c == linebuf[curr])
STOREC(linebuf[curr], BOLD);
else if (c == '_')
STOREC(linebuf[curr], UNDERLINE);
else if (linebuf[curr] == '_')
STOREC(c, UNDERLINE);
else if (control_char(c))
goto do_control_char;
else
STOREC(c, NORMAL);
} else if (c == '\b')
{
switch (bs_mode)
{
case BS_NORMAL:
STOREC(c, NORMAL);
break;
case BS_CONTROL:
goto do_control_char;
case BS_SPECIAL:
if (curr == 0)
break;
backc();
overstrike = 1;
break;
}
} else if (c == '\t')
{
/*
* Expand a tab into spaces.
*/
do
{
STOREC(' ', NORMAL);
} while ((column % tabstop) != 0);
} else if (control_char(c))
{
do_control_char:
if (ctldisp == 0)
{
/*
* Output as a normal character.
*/
STOREC(c, NORMAL);
} else
{
/*
* Output in the (blinking) ^X format.
*/
s = prchar(c);
a = binattr;
/*
* Make sure we can get the entire representation
* the character on this line.
*/
if (column + strlen(s) +
attr_swidth(a) + attr_ewidth(a) > sc_width)
return (1);
for ( ; *s != 0; s++)
STOREC(*s, a);
}
} else
{
STOREC(c, NORMAL);
}
return (0);
}
/*
* Terminate the line in the line buffer.
*/
public void
pdone(endline)
int endline;
{
/* if (pendc && (pendc != '\r' || !endline)) */
if (pendc && ((pendc != '\n' && pendc != '\n') || !endline))
/*
* If we had a pending character, put it in the buffer.
* But discard a pending CR if we are at end of line
* (that is, discard the CR in a CR/LF sequence).
*/
(void) do_append(pendc);
/*
* Add a newline if necessary,
* and append a '\0' to the end of the line.
*/
if (column < sc_width || !auto_wrap || ignaw || ctldisp == 0)
{
/* linebuf[curr] = '\n'; */
linebuf[curr] = '\r';
attr[curr] = NORMAL;
curr++;
}
linebuf[curr] = '\0';
attr[curr] = NORMAL;
}
/*
* Get a character from the current line.
* Return the character as the function return value,
* and the character attribute in *ap.
*/
public int
gline(i, ap)
register int i;
register int *ap;
{
if (is_null_line)
{
/*
* If there is no current line, we pretend the line is
* either "~" or "", depending on the "twiddle" flag.
*/
*ap = NORMAL;
if (twiddle)
/* return ("~\n"[i]);
return ("\n"[i]); */
return ("~\r"[i]);
return ("\r"[i]);
}
*ap = attr[i];
return (linebuf[i] & 0377);
}
/*
* Indicate that there is no current line.
*/
public void
null_line(void)
{
is_null_line = 1;
}
/*
* Analogous to forw_line(), but deals with "raw lines":
* lines which are not split for screen width.
* {{ This is supposed to be more efficient than forw_line(). }}
*/
public POSITION
forw_raw_line(curr_pos, linep)
POSITION curr_pos;
char **linep;
{
register char *p;
register int c;
POSITION new_pos;
if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
(c = ch_forw_get()) == EOI)
return (NULL_POSITION);
p = linebuf;
for (;;)
{
/* if (c == '\n' || c == EOI) */
if (c == '\r' || c == '\n' || c == EOI)
{
new_pos = ch_tell();
break;
}
if (p >= &linebuf[sizeof(linebuf)-1])
{
/*
* Overflowed the input buffer.
* Pretend the line ended here.
* {{ The line buffer is supposed to be big
* enough that this never happens. }}
*/
new_pos = ch_tell() - 1;
break;
}
*p++ = c;
c = ch_forw_get();
}
*p = '\0';
if (linep != NULL)
*linep = linebuf;
return (new_pos);
}
/*
* Analogous to back_line(), but deals with "raw lines".
* {{ This is supposed to be more efficient than back_line(). }}
*/
public POSITION
back_raw_line(curr_pos, linep)
POSITION curr_pos;
char **linep;
{
register char *p;
register int c;
POSITION new_pos;
if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() ||
ch_seek(curr_pos-1))
return (NULL_POSITION);
p = &linebuf[sizeof(linebuf)];
*--p = '\0';
for (;;)
{
c = ch_back_get();
/* if (c == '\n') */
if (c == '\r' || c == '\n')
{
/*
* This is the newline ending the previous line.
* We have hit the beginning of the line.
*/
new_pos = ch_tell() + 1;
break;
}
if (c == EOI)
{
/*
* We have hit the beginning of the file.
* This must be the first line in the file.
* This must, of course, be the beginning of the line.
*/
new_pos = ch_zero();
break;
}
if (p <= linebuf)
{
/*
* Overflowed the input buffer.
* Pretend the line ended here.
*/
new_pos = ch_tell() + 1;
break;
}
*--p = c;
}
if (linep != NULL)
*linep = p;
return (new_pos);
}

452
bin/less/linenum.c Normal file
View File

@ -0,0 +1,452 @@
/*
* Code to handle displaying line numbers.
*
* Finding the line number of a given file position is rather tricky.
* We don't want to just start at the beginning of the file and
* count newlines, because that is slow for large files (and also
* wouldn't work if we couldn't get to the start of the file; e.g.
* if input is a long pipe).
*
* So we use the function add_lnum to cache line numbers.
* We try to be very clever and keep only the more interesting
* line numbers when we run out of space in our table. A line
* number is more interesting than another when it is far from
* other line numbers. For example, we'd rather keep lines
* 100,200,300 than 100,101,300. 200 is more interesting than
* 101 because 101 can be derived very cheaply from 100, while
* 200 is more expensive to derive from 100.
*
* The function currline() returns the line number of a given
* position in the file. As a side effect, it calls add_lnum
* to cache the line number. Therefore currline is occasionally
* called to make sure we cache line numbers often enough.
*/
#pragma noroot
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
/*
* Structure to keep track of a line number and the associated file position.
* A doubly-linked circular list of line numbers is kept ordered by line number.
*/
struct linenum
{
struct linenum *next; /* Link to next in the list */
struct linenum *prev; /* Line to previous in the list */
POSITION pos; /* File position */
POSITION gap; /* Gap between prev and next */
int line; /* Line number */
};
/*
* "gap" needs some explanation: the gap of any particular line number
* is the distance between the previous one and the next one in the list.
* ("Distance" means difference in file position.) In other words, the
* gap of a line number is the gap which would be introduced if this
* line number were deleted. It is used to decide which one to replace
* when we have a new one to insert and the table is full.
*/
#define NPOOL 50 /* Size of line number pool */
#define LONGTIME (2) /* In seconds */
public int lnloop = 0; /* Are we in the line num loop? */
static struct linenum anchor; /* Anchor of the list */
static struct linenum *freelist; /* Anchor of the unused entries */
static struct linenum pool[NPOOL]; /* The pool itself */
static struct linenum *spare; /* We always keep one spare entry */
extern int linenums;
extern int sigs;
extern int sc_height;
static void calcgap(register struct linenum *p);
static void longloopmessage(void);
static void longish(void);
/*
* Initialize the line number structures.
*/
public void
clr_linenum(void)
{
register struct linenum *p;
/*
* Put all the entries on the free list.
* Leave one for the "spare".
*/
for (p = pool; p < &pool[NPOOL-2]; p++)
p->next = p+1;
pool[NPOOL-2].next = NULL;
freelist = pool;
spare = &pool[NPOOL-1];
/*
* Initialize the anchor.
*/
anchor.next = anchor.prev = &anchor;
anchor.gap = 0;
anchor.pos = (POSITION)0;
anchor.line = 1;
}
/*
* Calculate the gap for an entry.
*/
static void
calcgap(p)
register struct linenum *p;
{
/*
* Don't bother to compute a gap for the anchor.
* Also don't compute a gap for the last one in the list.
* The gap for that last one should be considered infinite,
* but we never look at it anyway.
*/
if (p == &anchor || p->next == &anchor)
return;
p->gap = p->next->pos - p->prev->pos;
}
/*
* Add a new line number to the cache.
* The specified position (pos) should be the file position of the
* FIRST character in the specified line.
*/
public void
add_lnum(lno, pos)
int lno;
POSITION pos;
{
register struct linenum *p;
register struct linenum *new;
register struct linenum *nextp;
register struct linenum *prevp;
register POSITION mingap;
/*
* Find the proper place in the list for the new one.
* The entries are sorted by position.
*/
for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next)
if (p->line == lno)
/* We already have this one. */
return;
nextp = p;
prevp = p->prev;
if (freelist != NULL)
{
/*
* We still have free (unused) entries.
* Use one of them.
*/
new = freelist;
freelist = freelist->next;
} else
{
/*
* No free entries.
* Use the "spare" entry.
*/
new = spare;
spare = NULL;
}
/*
* Fill in the fields of the new entry,
* and insert it into the proper place in the list.
*/
new->next = nextp;
new->prev = prevp;
new->pos = pos;
new->line = lno;
nextp->prev = new;
prevp->next = new;
/*
* Recalculate gaps for the new entry and the neighboring entries.
*/
calcgap(new);
calcgap(nextp);
calcgap(prevp);
if (spare == NULL)
{
/*
* We have used the spare entry.
* Scan the list to find the one with the smallest
* gap, take it out and make it the spare.
* We should never remove the last one, so stop when
* we get to p->next == &anchor. This also avoids
* looking at the gap of the last one, which is
* not computed by calcgap.
*/
mingap = anchor.next->gap;
for (p = anchor.next; p->next != &anchor; p = p->next)
{
if (p->gap <= mingap)
{
spare = p;
mingap = p->gap;
}
}
spare->next->prev = spare->prev;
spare->prev->next = spare->next;
}
}
/*
* If we get stuck in a long loop trying to figure out the
* line number, print a message to tell the user what we're doing.
*/
static void
longloopmessage(void)
{
ierror("Calculating line numbers", NULL_PARG);
/*
* Set the lnloop flag here, so if the user interrupts while
* we are calculating line numbers, the signal handler will
* turn off line numbers (linenums=0).
*/
lnloop = 1;
}
static int loopcount;
#if GET_TIME
static long startime;
#endif
static void
longish(void)
{
#if GET_TIME
if (loopcount >= 0 && ++loopcount > 100)
{
loopcount = 0;
if (get_time() >= startime + LONGTIME)
{
longloopmessage();
loopcount = -1;
}
}
#else
if (loopcount >= 0 && ++loopcount > LONGLOOP)
{
longloopmessage();
loopcount = -1;
}
#endif
}
/*
* Find the line number associated with a given position.
* Return 0 if we can't figure it out.
*/
public int
find_linenum(pos)
POSITION pos;
{
register struct linenum *p;
register int lno;
POSITION cpos;
if (!linenums)
/*
* We're not using line numbers.
*/
return (0);
if (pos == NULL_POSITION)
/*
* Caller doesn't know what he's talking about.
*/
return (0);
if (pos <= ch_zero())
/*
* Beginning of file is always line number 1.
*/
return (1);
/*
* Find the entry nearest to the position we want.
*/
for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next)
continue;
if (p->pos == pos)
/* Found it exactly. */
return (p->line);
/*
* This is the (possibly) time-consuming part.
* We start at the line we just found and start
* reading the file forward or backward till we
* get to the place we want.
*
* First decide whether we should go forward from the
* previous one or backwards from the next one.
* The decision is based on which way involves
* traversing fewer bytes in the file.
*/
flush();
#if GET_TIME
startime = get_time();
#endif
if (p == &anchor || pos - p->prev->pos < p->pos - pos)
{
/*
* Go forward.
*/
p = p->prev;
if (ch_seek(p->pos))
return (0);
loopcount = 0;
for (lno = p->line, cpos = p->pos; cpos < pos; lno++)
{
/*
* Allow a signal to abort this loop.
*/
cpos = forw_raw_line(cpos, (char **)NULL);
if (sigs || cpos == NULL_POSITION)
return (0);
longish();
}
lnloop = 0;
/*
* We might as well cache it.
*/
add_lnum(lno, cpos);
/*
* If the given position is not at the start of a line,
* make sure we return the correct line number.
*/
if (cpos > pos)
lno--;
} else
{
/*
* Go backward.
*/
if (ch_seek(p->pos))
return (0);
loopcount = 0;
for (lno = p->line, cpos = p->pos; cpos > pos; lno--)
{
/*
* Allow a signal to abort this loop.
*/
cpos = back_raw_line(cpos, (char **)NULL);
if (sigs || cpos == NULL_POSITION)
return (0);
longish();
}
lnloop = 0;
/*
* We might as well cache it.
*/
add_lnum(lno, cpos);
}
return (lno);
}
/*
* Find the position of a given line number.
* Return NULL_POSITION if we can't figure it out.
*/
public POSITION
find_pos(lno)
int lno;
{
register struct linenum *p;
POSITION cpos;
int clno;
if (lno <= 1)
/*
* Line number 1 is beginning of file.
*/
return (ch_zero());
/*
* Find the entry nearest to the line number we want.
*/
for (p = anchor.next; p != &anchor && p->line < lno; p = p->next)
continue;
if (p->line == lno)
/* Found it exactly. */
return (p->pos);
flush();
if (p == &anchor || lno - p->prev->line < p->line - lno)
{
/*
* Go forward.
*/
p = p->prev;
if (ch_seek(p->pos))
return (NULL_POSITION);
for (clno = p->line, cpos = p->pos; clno < lno; clno++)
{
/*
* Allow a signal to abort this loop.
*/
cpos = forw_raw_line(cpos, (char **)NULL);
if (sigs || cpos == NULL_POSITION)
return (NULL_POSITION);
}
} else
{
/*
* Go backward.
*/
if (ch_seek(p->pos))
return (NULL_POSITION);
for (clno = p->line, cpos = p->pos; clno > lno; clno--)
{
/*
* Allow a signal to abort this loop.
*/
cpos = back_raw_line(cpos, (char **)NULL);
if (sigs || cpos == NULL_POSITION)
return (NULL_POSITION);
}
}
/*
* We might as well cache it.
*/
add_lnum(clno, cpos);
return (cpos);
}
/*
* Return the line number of the "current" line.
* The argument "where" tells which line is to be considered
* the "current" line (e.g. TOP, BOTTOM, MIDDLE, etc).
*/
public int
currline(where)
int where;
{
POSITION pos;
POSITION len;
int lnum;
pos = position(where);
len = ch_length();
while (pos == NULL_POSITION && where >= 0 && where < sc_height)
pos = position(++where);
if (pos == NULL_POSITION)
pos = len;
lnum = find_linenum(pos);
if (pos == len)
lnum--;
return (lnum);
}

33
bin/less/linkscr Executable file
View File

@ -0,0 +1,33 @@
13/direct256
o/MAIN
o/GSOS
o/BRAC
o/CH
o/CHARSET
o/CMDBUF
o/COMMAND
o/DECODE
o/EDIT
o/FILENAME
o/FORWBACK
o/HELP
o/IFILE
o/INPUT
o/JUMP
o/LINE
o/LINENUM
o/LSYSTEM
o/MARK
o/OPTFUNC
o/OPTION
o/OPTTBL
o/OS
o/OUTPUT
o/POSITION
o/PROMPT
o/SCREEN
o/SEARCH
o/SIGNAL
o/TAGS
o/TTYIN
o/VERSION

323
bin/less/lsystem.c Normal file
View File

@ -0,0 +1,323 @@
/*
* Routines to execute other programs.
* Necessarily very OS dependent.
*/
#pragma noroot
#include <stdio.h>
#include <signal.h>
#include "less.h"
#include "position.h"
#include <texttool.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#if __MSDOS__
#include <process.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <errno.h>
#include <dir.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
char get_swchar();
void swchar_to_dos();
void swchar_to_unix();
#endif
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern char *getenv(char *);
extern int screen_trashed;
extern IFILE curr_ifile;
/*
* Pass the specified command to a shell to be executed.
* Like plain "system()", but handles resetting terminal modes, etc.
*/
public void
lsystem(cmd)
char *cmd;
{
register int inp;
register char *shell;
register char *p;
register char *curr_filename;
DeviceRec oldstdin;
/*
* Print the command which is to be executed,
* unless the command starts with a "-".
*/
if (cmd[0] == '-')
cmd++;
else
{
lower_left();
clear_eol();
putstr("!");
putstr(cmd);
putstr("\n");
}
/*
* Close the current input file.
*/
curr_filename = get_filename(curr_ifile);
(void) edit(NULL, 0);
/*
* De-initialize the terminal and take out of raw mode.
*/
deinit();
flush(); /* Make sure the deinit chars get out */
raw_mode(0);
/*
* Restore signals to their defaults.
*/
init_signals(0);
/*
* Force standard input to be the user's terminal
* (the normal standard input), even if less's standard input
* is coming from a pipe.
*/
#if __MSDOS__
{
register int inp2;
inp = dup(0);
inp2 = open("CON", O_TEXT|O_RDONLY);
dup2(0,inp2);
}
#else
inp = dup(STDIN_FILENO);
close(STDIN_FILENO);
if (open(".tty", O_RDWR) < 0)
dup(inp);
#endif
/*
* Pass the command to the system to be executed.
* If we have a SHELL environment variable, use
* <$SHELL -c "command"> instead of just <command>.
* If the command is empty, just invoke a shell.
*/
#if __MSDOS__
{
int result;
char sw_char;
sw_char = get_swchar();
swchar_to_dos();
result = system(cmd);
if (result != 0)
perror("less");
if (sw_char == '-')
swchar_to_unix();
}
#else
p = NULL;
if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
{
if (*cmd == '\0')
p = save(shell);
else
{
p = (char *) ecalloc(strlen(shell) + strlen(cmd) + 7,
sizeof(char));
/* sprintf(p, "%s -c \"%s\"", shell, cmd);*/
sprintf(p, "%s", cmd);
}
}
if (p == NULL)
{
if (*cmd == '\0')
p = save("gsh");
else
p = save(cmd);
}
oldstdin=GetInputDevice();
SetInputDevice(3,1L);
system(p);
SetInputDevice(oldstdin.deviceType, oldstdin.ptrOrSlot);
free(p);
#endif
/*
* Restore standard input, reset signals, raw mode, etc.
*/
#if __MSDOS__
close(inp2);
dup2(0,inp);
close(inp);
#else
close(STDIN_FILENO);
dup(inp);
close(inp);
open_getchr();
/* above line added to reopen the damn terminal */
#endif
init_signals(1);
raw_mode(1);
init();
screen_trashed = 1;
/*
* Reopen the current input file.
*/
(void) edit(curr_filename, 0);
#if defined(SIGWINCH) || defined(SIGWIND)
/*
* Since we were ignoring window change signals while we executed
* the system command, we must assume the window changed.
* Warning: this leaves a signal pending (in "sigs"),
* so psignals() should be called soon after lsystem().
*/
winch();
#endif
}
#if PIPEC
/*
* Pipe a section of the input file into the given shell command.
* The section to be piped is the section "between" the current
* position and the position marked by the given letter.
*
* The "current" position means the top line displayed if the mark
* is after the current screen, or the bottom line displayed if
* the mark is before the current screen.
* If the mark is on the current screen, the whole screen is displayed.
*/
public int
pipe_mark(c, cmd)
int c;
char *cmd;
{
POSITION mpos, tpos, bpos;
/*
* mpos = the marked position.
* tpos = top of screen.
* bpos = bottom of screen.
*/
mpos = markpos(c);
if (mpos == NULL_POSITION)
return (-1);
tpos = position(TOP);
if (tpos == NULL_POSITION)
tpos = ch_zero();
bpos = position(BOTTOM);
if (c == '.')
return (pipe_data(cmd, tpos, bpos));
else if (mpos <= tpos)
return (pipe_data(cmd, mpos, tpos));
else if (bpos == NULL_POSITION)
return (pipe_data(cmd, tpos, bpos));
else
return (pipe_data(cmd, tpos, mpos));
}
/*
* Create a pipe to the given shell command.
* Feed it the file contents between the positions spos and epos.
*/
public int
pipe_data(cmd, spos, epos)
char *cmd;
POSITION spos;
POSITION epos;
{
register FILE *f;
register int c;
extern FILE *popen();
/*
* This is structured much like lsystem().
* Since we're running a shell program, we must be careful
* to perform the necessary deinitialization before running
* the command, and reinitialization after it.
*/
if (ch_seek(spos) != 0)
{
error("Cannot seek to start position", NULL_PARG);
return (-1);
}
if ((f = popen(cmd, "w")) == NULL)
{
error("Cannot create pipe", NULL_PARG);
return (-1);
}
lower_left();
clear_eol();
putstr("!");
putstr(cmd);
putstr("\n");
deinit();
flush();
raw_mode(0);
init_signals(0);
#ifdef SIGPIPE
SIGNAL(SIGPIPE, SIG_IGN);
#endif
while (epos == NULL_POSITION || spos++ <= epos)
{
/*
* Read a character from the file and give it to the pipe.
*/
c = ch_forw_get();
if (c == EOI)
break;
if (putc(c, f) == EOF)
break;
}
/*
* Finish up the last line.
*/
/* while (c != '\n' && c != EOI ) */
while (c != '\r' && c != '\n' && c != EOI )
{
c = ch_forw_get();
if (c == EOI)
break;
if (putc(c, f) == EOF)
break;
}
pclose(f);
#ifdef SIGPIPE
SIGNAL(SIGPIPE, SIG_DFL);
#endif
init_signals(1);
raw_mode(1);
init();
screen_trashed = 1;
#if defined(SIGWINCH) || defined(SIGWIND)
/* {{ Probably don't need this here. }} */
winch();
#endif
return (0);
}
#endif

293
bin/less/main.c Normal file
View File

@ -0,0 +1,293 @@
/*
* Entry point, initialization, miscellaneous routines.
*/
#pragma stacksize 1280
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
public int ispipe;
public char * every_first_cmd = NULL;
public int new_file;
public int is_tty;
public IFILE curr_ifile = NULL_IFILE;
public IFILE old_ifile = NULL_IFILE;
public struct scrpos initial_scrpos;
public int any_display = 0;
public int scroll;
public char * progname;
public int quitting;
extern int file;
extern int quit_at_eof;
extern int cbufs;
extern int errmsgs;
extern int screen_trashed;
extern int force_open;
#if LOGFILE
public int logfile = -1;
public int force_logfile = 0;
public char * namelogfile = NULL;
#endif
#if EDITOR
public char * editor;
public char * editproto;
#endif
#if TAGS
extern char * tagfile;
extern char * tagpattern;
extern int tagoption;
#endif
/*
* Entry point.
*/
int main(argc, argv)
int argc;
char *argv[];
{
IFILE h;
int nofiles;
extern char *getenv();
extern int _INITGNOSTDIO(void);
/*if(!_INITGNOSTDIO())
{
fprintf(stderr, "\n%s: requires GNO/ME to operate\n\n");
exit(1);
} */
progname = *argv++;
/*
* Process command line arguments and LESS environment arguments.
* Command line arguments override environment arguments.
*/
init_prompt();
init_charset();
init_option();
scan_option(getenv("LESS"));
#define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
while (--argc > 0 && (isoptstring(argv[0]) || isoptpending()))
scan_option(*argv++);
#undef isoptstring
if (isoptpending())
{
/*
* Last command line option was a flag requiring a
* following string, but there was no following string.
*/
nopendopt();
quit(0);
}
#if USERFILE
/*
* Try to use the lesskey file "$HOME/.less".
*/
add_hometable();
#endif
#if EDITOR
editor = getenv("EDITOR");
if (editor == NULL || *editor == '\0')
editor = EDIT_PGM;
editproto = getenv("LESSEDIT");
if (editproto == NULL || *editproto == '\0')
editproto = "%E ?lm+%lm. %f";
#endif
/*
* Set up terminal, etc.
*/
/* is_tty = isatty(1);*/
is_tty = isatty(STDOUT_FILENO);
if (!is_tty)
{
/*
* Output is not a tty.
* Just copy the input file(s) to output.
*/
if (argc <= 0)
{
if (edit("-", 0) == 0)
cat_file();
} else
{
while (--argc >= 0)
{
if (edit(*argv++, 0) == 0)
cat_file();
}
}
quit(0);
}
/*
* Call get_ifile with all the command line filenames
* to "register" them with the ifile system.
*/
h = NULL_IFILE;
while (--argc >= 0)
h = get_ifile(*argv++, h);
init_mark();
raw_mode(1);
get_term();
open_getchr();
init_signals(1);
/*
* Select the first file to examine.
*/
#if TAGS
if (tagoption)
{
/*
* A -t option was given.
* Verify that no filenames were also given.
* Edit the file selected by the "tags" search,
* and search for the proper line in the file.
*/
if (nifile() > 0)
{
error("No filenames allowed with -t option", NULL_PARG);
quit(1);
}
if (tagfile == NULL)
quit(1);
if (edit(tagfile, 0) || tagsearch())
quit(1);
nofiles = 0;
} else
#endif
if (nifile() == 0)
nofiles = edit("-", 0); /* Standard input */
else
nofiles = edit_first();
if (nofiles)
{
quit(1);
/*NOTREACHED*/
}
init();
commands();
quit(0);
/*NOTREACHED*/
}
/*
* Copy a string, truncating to the specified length if necessary.
* Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
*/
public void
strtcpy(to, from, len)
char *to;
char *from;
unsigned int len;
{
strncpy(to, from, len);
to[len-1] = '\0';
}
/*
* Copy a string to a "safe" place
* (that is, to a buffer allocated by calloc).
*/
public char *
save(s)
char *s;
{
register char *p;
p = (char *) ecalloc(strlen(s)+1, sizeof(char));
strcpy(p, s);
return (p);
}
public VOID_POINTER
ecalloc(count, size)
int count;
unsigned int size;
{
register VOID_POINTER p;
p = calloc(count, size);
if (p != NULL)
return (p);
error("Cannot allocate memory", NULL_PARG);
quit(1);
/*NOTREACHED*/
}
/*
* Skip leading spaces in a string.
*/
public char *
skipsp(s)
register char *s;
{
while (*s == ' ' || *s == '\t')
s++;
return (s);
}
/*
* Exit the program.
*/
public void
quit(status)
int status;
{
static int save_status;
/*
* Put cursor at bottom left corner, clear the line,
* reset the terminal modes, and exit.
*/
if (status < 0)
status = save_status;
else
save_status = status;
quitting = 1;
#if LOGFILE
end_logfile();
#endif
if (any_display)
{
lower_left();
clear_eol();
}
deinit();
flush();
raw_mode(0);
#if __MSDOS__
restore_screen();
/*
* If we don't close 2, we get some garbage from
* 2's buffer when it flushes automatically.
* I cannot track this one down RB
* The same bug shows up if we use ^C^C to abort.
*/
close(2);
#endif
exit(status);
}

245
bin/less/mark.c Normal file
View File

@ -0,0 +1,245 @@
#pragma noroot
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern IFILE curr_ifile;
extern int sc_height;
extern int jump_sline;
/*
* A mark is an ifile (input file) plus a position within the file.
*/
struct mark {
IFILE m_ifile;
struct scrpos m_scrpos;
};
/*
* The table of marks.
* Each mark is identified by a lowercase or uppercase letter.
*/
#define NMARKS (2*26) /* a-z, A-Z */
static struct mark marks[NMARKS];
/*
* Special mark for the "last mark"; addressed by the apostrophe.
*/
static struct mark lmark;
static struct mark *getumark(int c);
static struct mark *getmark(int c);
/*
* Initialize the mark table to show no marks are set.
*/
public void
init_mark(void)
{
int i;
for (i = 0; i < NMARKS; i++)
marks[i].m_scrpos.pos = NULL_POSITION;
lmark.m_scrpos.pos = NULL_POSITION;
}
/*
* See if a mark letter is valid (between a and z).
*/
static struct mark *
getumark(c)
int c;
{
if (c >= 'a' && c <= 'z')
return (&marks[c-'a']);
if (c >= 'A' && c <= 'Z')
return (&marks[c-'A'+26]);
error("Invalid mark letter", NULL_PARG);
return (NULL);
}
/*
* Get the mark structure identified by a character.
* The mark struct may come either from the mark table
* or may be constructed on the fly for certain characters like ^, $.
*/
static struct mark *
getmark(c)
int c;
{
register struct mark *m;
static struct mark sm;
switch (c)
{
case '^':
/*
* Beginning of the current file.
*/
m = &sm;
m->m_scrpos.pos = ch_zero();
m->m_scrpos.ln = 0;
m->m_ifile = curr_ifile;
break;
case '$':
/*
* End of the current file.
*/
if (ch_end_seek())
{
error("Cannot seek to end of file", NULL_PARG);
return (NULL);
}
m = &sm;
m->m_scrpos.pos = ch_tell();
m->m_scrpos.ln = sc_height-1;
m->m_ifile = curr_ifile;
break;
case '.':
/*
* Current position in the current file.
*/
m = &sm;
m->m_scrpos.pos = ch_tell();
m->m_scrpos.ln = 0;
m->m_ifile = curr_ifile;
break;
case '\'':
/*
* The "last mark".
*/
m = &lmark;
break;
default:
/*
* Must be a user-defined mark.
*/
m = getumark(c);
if (m == NULL)
break;
if (m->m_scrpos.pos == NULL_POSITION)
{
error("Mark not set", NULL_PARG);
return (NULL);
}
break;
}
return (m);
}
/*
* Is a mark letter is invalid?
*/
public int
badmark(c)
int c;
{
return (getmark(c) == NULL);
}
/*
* Set a user-defined mark.
*/
public void
setmark(c)
int c;
{
register struct mark *m;
struct scrpos scrpos;
m = getumark(c);
if (m == NULL)
return;
get_scrpos(&scrpos);
m->m_scrpos = scrpos;
m->m_ifile = curr_ifile;
}
/*
* Set lmark (the mark named by the apostrophe).
*/
public void
lastmark(void)
{
struct scrpos scrpos;
get_scrpos(&scrpos);
if (scrpos.pos == NULL_POSITION)
return;
lmark.m_scrpos = scrpos;
lmark.m_ifile = curr_ifile;
}
/*
* Go to a mark.
*/
public void
gomark(c)
int c;
{
register struct mark *m;
struct scrpos scrpos;
m = getmark(c);
if (m == NULL)
return;
/*
* If we're trying to go to the lastmark and
* it has not been set to anything yet,
* set it to the beginning of the current file.
*/
if (m == &lmark && m->m_scrpos.pos == NULL_POSITION)
{
m->m_ifile = curr_ifile;
m->m_scrpos.pos = ch_zero();
m->m_scrpos.ln = jump_sline;
}
/*
* If we're using lmark, we must save the screen position now,
* because if we call edit() below, lmark will change.
* (We save the screen position even if we're not using lmark.)
*/
scrpos = m->m_scrpos;
if (m->m_ifile != curr_ifile)
{
/*
* Not in the current file; edit the correct file.
*/
if (edit(get_filename(m->m_ifile), 0))
return;
}
jump_loc(scrpos.pos, scrpos.ln);
}
/*
* Return the position associated with a given mark letter.
*
* We don't return which screen line the position
* is associated with, but this doesn't matter much,
* because it's always the first non-blank line on the screen.
*/
public POSITION
markpos(c)
int c;
{
register struct mark *m;
m = getmark(c);
if (m == NULL)
return (NULL_POSITION);
if (m->m_ifile != curr_ifile)
{
error("Mark not in current file", NULL_PARG);
return (NULL_POSITION);
}
return (m->m_scrpos.pos);
}

2
bin/less/note Normal file
View File

@ -0,0 +1,2 @@
C 2.0.1 doesn't optimize anywhere near as well as C 2.0.1a3. There
is a noticeable speed difference in one particular test file.

381
bin/less/optfunc.c Normal file
View File

@ -0,0 +1,381 @@
/*
* Handling functions for command line options.
*
* Most options are handled by the generic code in option.c.
* But all string options, and a few non-string options, require
* special handling specific to the particular option.
* This special processing is done by the "handling functions" in this file.
*
* Each handling function is passed a "type" and, if it is a string
* option, the string which should be "assigned" to the option.
* The type may be one of:
* INIT The option is being initialized from the command line.
* TOGGLE The option is being changed from within the program.
* QUERY The setting of the option is merely being queried.
*/
#pragma noroot
#include "less.h"
#include "option.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern int nbufs;
extern int ispipe;
extern int cbufs;
extern int pr_type;
extern int nohelp;
extern int plusoption;
extern char *prproto[];
extern char *eqproto;
extern IFILE curr_ifile;
#if LOGFILE
extern char *namelogfile;
extern int force_logfile;
extern int logfile;
extern char *glob();
#endif
#if TAGS
public int tagoption = 0;
extern char *tagfile;
extern char *tagpattern;
extern char *tags;
#endif
#if __MSDOS__
public char *window_box = NULL;
extern int directvideo;
extern int output_mode;
#endif
#if LOGFILE
/*
* Handler for -o option.
*/
public void
opt_o(type, s)
int type;
char *s;
{
PARG parg;
switch (type)
{
case INIT:
namelogfile = s;
break;
case TOGGLE:
if (!ispipe)
{
error("Input is not a pipe", NULL_PARG);
return;
}
if (logfile >= 0)
{
error("Log file is already in use", NULL_PARG);
return;
}
s = skipsp(s);
namelogfile = glob(s);
if (namelogfile == NULL)
namelogfile = save(s);
use_logfile(s);
sync_logfile();
break;
case QUERY:
if (logfile < 0)
error("No log file", NULL_PARG);
else
{
parg.p_string = namelogfile;
error("Log file \"%s\"", &parg);
}
break;
}
}
/*
* Handler for -O option.
*/
public void
opt__O(type, s)
int type;
char *s;
{
force_logfile = 1;
opt_o(type, s);
}
/*
* Handlers for obsolete -l and -L options.
*/
public void
opt_l(type, s)
int type;
char *s;
{
error("The -l option is obsolete. Use -o", NULL_PARG);
}
public void
opt__L(type, s)
int type;
char *s;
{
error("The -L option is obsolete. Use -O", NULL_PARG);
}
#endif
#if USERFILE
public void
opt_k(type, s)
int type;
char *s;
{
PARG parg;
switch (type)
{
case INIT:
if (add_cmdtable(s))
{
parg.p_string = s;
error("Cannot use lesskey file \"%s\"", &parg);
}
break;
case QUERY:
case TOGGLE:
error("Cannot query the -k flag", NULL_PARG);
break;
}
}
#endif
#if TAGS
/*
* Handler for -t option.
*/
public void
opt_t(type, s)
int type;
char *s;
{
char *curr_filename;
switch (type)
{
case INIT:
tagoption = 1;
findtag(s);
break;
case TOGGLE:
findtag(skipsp(s));
if (tagfile != NULL)
{
curr_filename = get_filename(curr_ifile);
if (edit(tagfile, 0) == 0)
if (tagsearch())
(void) edit(curr_filename, 0);
}
break;
case QUERY:
error("Tag is required after -t", NULL_PARG);
break;
}
}
/*
* Handler for -T option.
*/
public void
opt__T(type, s)
int type;
char *s;
{
PARG parg;
switch (type)
{
case INIT:
tags = s;
break;
case TOGGLE:
s = skipsp(s);
tags = glob(s);
if (tags == NULL)
tags = save(s);
break;
case QUERY:
parg.p_string = tags;
error("Tags file \"%s\"", &parg);
break;
}
}
#endif
/*
* Handler for -p option.
*/
public void
opt_p(type, s)
int type;
register char *s;
{
switch (type)
{
case INIT:
/*
* Unget a search command for the specified string.
* {{ This won't work if the "/" command is
* changed or invalidated by a .lesskey file. }}
*/
plusoption = 1;
ungetsc(s);
ungetsc("/");
break;
case QUERY:
error("Pattern is required after -p", NULL_PARG);
break;
}
}
/*
* Handler for -P option.
*/
public void
opt__P(type, s)
int type;
register char *s;
{
register char **proto;
PARG parg;
switch (type)
{
case INIT:
case TOGGLE:
/*
* Figure out which prototype string should be changed.
*/
switch (*s)
{
case 'm': proto = &prproto[PR_MEDIUM]; s++; break;
case 'M': proto = &prproto[PR_LONG]; s++; break;
case '=': proto = &eqproto; s++; break;
default: proto = &prproto[pr_type]; break;
}
free(*proto);
*proto = save(s);
break;
case QUERY:
parg.p_string = prproto[pr_type];
error("%s", &parg);
break;
}
}
/*
* Handler for the -b option.
*/
/*ARGSUSED*/
public void
opt_b(type, s)
int type;
char *s;
{
switch (type)
{
case TOGGLE:
case QUERY:
/*
* Allocate the new number of buffers.
*/
cbufs = ch_nbuf(cbufs);
break;
case INIT:
break;
}
}
#if __MSDOS__
/*
* Handler for -v option. (use BIOS or direct video)
*/
public void
opt_v(type, s)
int type;
register char *s;
{
switch (type)
{
case INIT:
case TOGGLE:
if (output_mode == 2)
directvideo = 1;
else
directvideo = 0;
break;
case QUERY:
break;
}
}
/*
* Handler for -W option. (set/modify window boundaries)
*/
public void
opt_W(type, s)
int type;
register char *s;
{
PARG parg;
switch (type)
{
case INIT:
window_box = save(s);
break; /* get_term will take care of actually setting window */
#ifdef MOVE_WINDOW
case TOGGLE:
if (window_box != NULL)
free(window_box);
window_box = save(s);
reset_window();
break;
#endif
case QUERY:
parg.p_string = window_box;
error("%s", &parg);
break;
}
}
#endif
/*
* "-?" means display a help message.
* If from the command line, exit immediately.
*/
/*ARGSUSED*/
public void
opt_query(type, s)
int type;
char *s;
{
if (nohelp)
return;
switch (type)
{
case QUERY:
case TOGGLE:
error("Use \"h\" for help", NULL_PARG);
break;
case INIT:
raw_mode(1);
init();
help();
quit(0);
/*NOTREACHED*/
}
}

505
bin/less/option.c Normal file
View File

@ -0,0 +1,505 @@
/*
* Process command line options.
*
* Each option is a single letter which controls a program variable.
* The options have defaults which may be changed via
* the command line option, toggled via the "-" command,
* or queried via the "_" command.
*/
#pragma noroot
#include "less.h"
#include "option.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
static struct option *pendopt;
public int plusoption;
static char *propt(int c);
static char *optstring(char *s, int c);
static int flip_triple(int val, int lc);
static void nostring(int c);
extern int screen_trashed;
extern char *every_first_cmd;
/*
* Scan an argument (either from the command line or from the
* LESS environment variable) and process it.
*/
public void
scan_option(s)
char *s;
{
register struct option *o;
register int c;
char *str;
int set_default;
PARG parg;
if (s == NULL)
return;
/*
* If we have a pending string-valued option, handle it now.
* This happens if the previous option was, for example, "-P"
* without a following string. In that case, the current
* option is simply the string for the previous option.
*/
if (pendopt != NULL)
{
(*pendopt->ofunc)(INIT, s);
pendopt = NULL;
return;
}
set_default = 0;
while (*s != '\0')
{
/*
* Check some special cases first.
*/
switch (c = *s++)
{
case ' ':
case '\t':
case END_OPTION_STRING:
continue;
case '-':
/*
* "-+" means set these options back to their defaults.
* (They may have been set otherwise by previous
* options.)
*/
if (set_default = (*s == '+'))
s++;
continue;
case '+':
/*
* An option prefixed by a "+" is ungotten, so
* that it is interpreted as less commands
* processed at the start of the first input file.
* "++" means process the commands at the start of
* EVERY input file.
*/
plusoption = 1;
if (*s == '+')
every_first_cmd = save(++s);
else
ungetsc(s);
s = optstring(s, c);
continue;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/*
* Special "more" compatibility form "-<number>"
* instead of -z<number> to set the scrolling
* window size.
*/
s--;
c = 'z';
break;
}
/*
* Not a special case.
* Look up the option letter in the option table.
*/
o = findopt(c);
if (o == NULL)
{
parg.p_string = propt(c);
error("There is no %s flag (\"less -\\?\" for help)",
&parg);
quit(1);
}
switch (o->otype & OTYPE)
{
case BOOL:
if (set_default)
*(o->ovar) = o->odefault;
else
*(o->ovar) = ! o->odefault;
break;
case TRIPLE:
if (set_default)
*(o->ovar) = o->odefault;
else
*(o->ovar) = flip_triple(o->odefault,
(o->oletter == c));
break;
case STRING:
if (*s == '\0')
{
/*
* Set pendopt and return.
* We will get the string next time
* scan_option is called.
*/
pendopt = o;
return;
}
/*
* Don't do anything here.
* All processing of STRING options is done by
* the handling function.
*/
str = s;
s = optstring(s, c);
break;
case NUMBER:
*(o->ovar) = getnum(&s, c, (int*)NULL);
break;
}
/*
* If the option has a handling function, call it.
*/
if (o->ofunc != NULL)
(*o->ofunc)(INIT, str);
}
}
/*
* Toggle command line flags from within the program.
* Used by the "-" and "_" commands.
* how_toggle may be:
* OPT_NO_TOGGLE just report the current setting, without changing it.
* OPT_TOGGLE invert the current setting
* OPT_UNSET set to the default value
* OPT_SET set to the inverse of the default value
*/
public void
toggle_option(c, s, how_toggle)
int c;
char *s;
int how_toggle;
{
register struct option *o;
register int num;
int err;
PARG parg;
/*
* Look up the option letter in the option table.
*/
o = findopt(c);
if (o == NULL)
{
parg.p_string = propt(c);
error("There is no %s flag", &parg);
return;
}
if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
{
parg.p_string = propt(c);
error("Cannot change the %s flag", &parg);
return;
}
/*
* Check for something which appears to be a do_toggle
* (because the "-" command was used), but really is not.
* This could be a string option with no string, or
* a number option with no number.
*/
switch (o->otype & OTYPE)
{
case STRING:
case NUMBER:
if (how_toggle == OPT_TOGGLE && *s == '\0')
how_toggle = OPT_NO_TOGGLE;
break;
}
/*
* Now actually toggle (change) the variable.
*/
if (how_toggle != OPT_NO_TOGGLE)
{
switch (o->otype & OTYPE)
{
case BOOL:
/*
* Boolean.
*/
switch (how_toggle)
{
case OPT_TOGGLE:
*(o->ovar) = ! *(o->ovar);
break;
case OPT_UNSET:
*(o->ovar) = o->odefault;
break;
case OPT_SET:
*(o->ovar) = ! o->odefault;
break;
}
break;
case TRIPLE:
/*
* Triple:
* If user gave the lower case letter, then switch
* to 1 unless already 1, in which case make it 0.
* If user gave the upper case letter, then switch
* to 2 unless already 2, in which case make it 0.
*/
switch (how_toggle)
{
case OPT_TOGGLE:
*(o->ovar) = flip_triple(*(o->ovar),
o->oletter == c);
break;
case OPT_UNSET:
*(o->ovar) = o->odefault;
break;
case OPT_SET:
*(o->ovar) = flip_triple(o->odefault,
o->oletter == c);
break;
}
break;
case STRING:
/*
* String: don't do anything here.
* The handling function will do everything.
*/
switch (how_toggle)
{
case OPT_SET:
case OPT_UNSET:
error("Can't use \"-+\" or \"--\" for a string flag",
NULL_PARG);
return;
}
break;
case NUMBER:
/*
* Number: set the variable to the given number.
*/
switch (how_toggle)
{
case OPT_TOGGLE:
num = getnum(&s, '\0', &err);
if (!err)
*(o->ovar) = num;
break;
case OPT_UNSET:
*(o->ovar) = o->odefault;
break;
case OPT_SET:
error("Can't use \"--\" for a numeric flag",
NULL_PARG);
return;
}
break;
}
}
/*
* Call the handling function for any special action
* specific to this option.
*/
if (o->ofunc != NULL)
(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
/*
* Print a message describing the new setting.
*/
switch (o->otype & OTYPE)
{
case BOOL:
case TRIPLE:
/*
* Print the odesc message.
*/
error(o->odesc[*(o->ovar)], NULL_PARG);
break;
case NUMBER:
/*
* The message is in odesc[1] and has a %d for
* the value of the variable.
*/
parg.p_int = *(o->ovar);
error(o->odesc[1], &parg);
break;
case STRING:
/*
* Message was already printed by the handling function.
*/
break;
}
if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
screen_trashed = 1;
}
/*
* "Toggle" a triple-valued option.
*/
static int
flip_triple(val, lc)
int val;
int lc;
{
if (lc)
return ((val == 1) ? 0 : 1);
else
return ((val == 2) ? 0 : 2);
}
/*
* Return a string suitable for printing as the "name" of an option.
* For example, if the option letter is 'x', just return "-x".
*/
static char *
propt(c)
int c;
{
static char buf[8];
sprintf(buf, "-%s", prchar(c));
return (buf);
}
/*
* Determine if an option is a single character option (BOOL or TRIPLE),
* or if it a multi-character option (NUMBER).
*/
public int
single_char_option(c)
int c;
{
register struct option *o;
o = findopt(c);
if (o == NULL)
return (1);
return (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE));
}
/*
* Return the prompt to be used for a given option letter.
* Only string and number valued options have prompts.
*/
public char *
opt_prompt(c)
int c;
{
register struct option *o;
o = findopt(c);
if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
return (NULL);
return (o->odesc[0]);
}
/*
* Return whether or not there is a string option pending;
* that is, if the previous option was a string-valued option letter
* (like -P) without a following string.
* In that case, the current option is taken to be the string for
* the previous option.
*/
public int
isoptpending(void)
{
return (pendopt != NULL);
}
/*
* Print error message about missing string.
*/
static void
nostring(c)
int c;
{
PARG parg;
parg.p_string = propt(c);
error("String is required after %s", &parg);
}
/*
* Print error message if a STRING type option is not followed by a string.
*/
public void
nopendopt(void)
{
nostring(pendopt->oletter);
}
/*
* Scan to end of string or to an END_OPTION_STRING character.
* In the latter case, replace the char with a null char.
* Return a pointer to the remainder of the string, if any.
*/
static char *
optstring(s, c)
char *s;
int c;
{
register char *p;
if (*s == '\0')
{
nostring(c);
quit(1);
}
for (p = s; *p != '\0'; p++)
if (*p == END_OPTION_STRING)
{
*p = '\0';
return (p+1);
}
return (p);
}
/*
* Translate a string into a number.
* Like atoi(), but takes a pointer to a char *, and updates
* the char * to point after the translated number.
*/
public int
getnum(sp, c, errp)
char **sp;
int c;
int *errp;
{
register char *s;
register int n;
register int neg;
PARG parg;
s = skipsp(*sp);
neg = 0;
if (*s == '-')
{
neg = 1;
s++;
}
if (*s < '0' || *s > '9')
{
if (errp != NULL)
{
*errp = 1;
return (-1);
}
parg.p_string = propt(c);
error("Number is required after %s", &parg);
quit(1);
}
n = 0;
while (*s >= '0' && *s <= '9')
n = 10 * n + *s++ - '0';
*sp = s;
if (errp != NULL)
*errp = 0;
if (neg)
n = -n;
return (n);
}

38
bin/less/option.h Normal file
View File

@ -0,0 +1,38 @@
#define END_OPTION_STRING ('$')
/*
* Types of options.
*/
#define BOOL 01 /* Boolean option: 0 or 1 */
#define TRIPLE 02 /* Triple-valued option: 0, 1 or 2 */
#define NUMBER 04 /* Numeric option */
#define STRING 010 /* String-valued option */
#define NOVAR 020 /* No associated variable */
#define REPAINT 040 /* Repaint screen after toggling option */
#define NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */
#define OTYPE (BOOL|TRIPLE|NUMBER|STRING|NOVAR)
/*
* Argument to a handling function tells what type of activity:
*/
#define INIT 0 /* Initialization (from command line) */
#define QUERY 1 /* Query (from _ or - command) */
#define TOGGLE 2 /* Change value (from - command) */
/* Flag to toggle_option to specify how to "toggle" */
#define OPT_NO_TOGGLE 0
#define OPT_TOGGLE 1
#define OPT_UNSET 2
#define OPT_SET 3
struct option
{
char oletter; /* The controlling letter (a-z) */
char otype; /* Type of the option */
int odefault; /* Default value */
int *ovar; /* Pointer to the associated variable */
void (*ofunc)(); /* Pointer to special handling function */
char *odesc[3]; /* Description of each value */
};

265
bin/less/opttbl.c Normal file
View File

@ -0,0 +1,265 @@
/*
* The option table.
*/
#pragma noroot
#include "less.h"
#include "option.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
#define toupper(c) ((c)-'a'+'A')
/*
* Variables controlled by command line options.
*/
public int quiet; /* Should we suppress the audible bell? */
public int how_search; /* Where should forward searches start? */
public int top_scroll; /* Repaint screen from top?
(alternative is scroll from bottom) */
public int pr_type; /* Type of prompt (short, medium, long) */
public int bs_mode; /* How to process backspaces */
public int know_dumb; /* Don't complain about dumb terminals */
public int quit_at_eof; /* Quit after hitting end of file twice */
public int squeeze; /* Squeeze multiple blank lines into one */
public int tabstop; /* Tab settings */
public int back_scroll; /* Repaint screen on backwards movement */
public int forw_scroll; /* Repaint screen on forward movement */
public int twiddle; /* Display "~" for lines after EOF */
public int caseless; /* Do "caseless" searches */
public int linenums; /* Use line numbers */
public int cbufs; /* Current number of buffers */
public int autobuf; /* Automatically allocate buffers as needed */
public int nohelp; /* Disable the HELP command */
public int ctldisp; /* Send control chars to screen untranslated */
public int force_open; /* Open the file even if not regular file */
public int swindow; /* Size of scrolling window */
public int jump_sline; /* Screen line of "jump target" */
public int chopline; /* Truncate displayed lines at screen width */
#if __MSDOS__
public int output_mode; /* Which screen output method */
public int refresh_on_quit; /* Repaint screen on quit, if possible */
#endif
/*
* Table of all options and their semantics.
*/
static struct option option[] =
{
{ 'a', BOOL, 0, &how_search, NULL,
"Search includes displayed screen",
"Search skips displayed screen",
NULL
},
{ 'b', NUMBER, 10, &cbufs, opt_b,
"Buffers: ",
"%d buffers",
NULL
},
{ 'B', BOOL, 1, &autobuf, NULL,
"Don't automatically allocate buffers",
"Automatically allocate buffers when needed",
NULL
},
{ 'c', TRIPLE, 0, &top_scroll, NULL,
"Repaint by scrolling from bottom of screen",
"Repaint by clearing each line",
"Repaint by painting from top of screen"
},
{ 'd', BOOL|NO_TOGGLE, 0, &know_dumb, NULL,
"Assume intelligent terminal",
"Assume dumb terminal",
NULL
},
/* { 'e', TRIPLE, 0, &quit_at_eof, NULL,*/
{ 'e', TRIPLE, 1, &quit_at_eof, NULL,
"Don't quit at end-of-file",
"Quit at end-of-file",
"Quit immediately at end-of-file"
},
{ 'f', BOOL, 0, &force_open, NULL,
"Open only regular files",
"Open even non-regular files",
NULL
},
{ 'h', NUMBER, -1, &back_scroll, NULL,
"Backwards scroll limit: ",
"Backwards scroll limit is %d lines",
NULL
},
{ 'H', BOOL|NO_TOGGLE, 0, &nohelp, NULL,
"Allow help command",
"Don't allow help command",
NULL
},
{ 'i', BOOL, 0, &caseless, NULL,
"Case is significant in searches",
"Ignore case in searches",
NULL
},
{ 'j', NUMBER, 1, &jump_sline, NULL,
"Target line: ",
"Position target at screen line %d",
NULL
},
#if USERFILE
{ 'k', STRING|NO_TOGGLE, 0, NULL, opt_k,
NULL, NULL, NULL
},
#endif
#if LOGFILE
{ 'l', STRING, 0, NULL, opt_l,
NULL, NULL, NULL
},
{ 'L', STRING, 0, NULL, opt__L,
NULL, NULL, NULL
},
#endif
/* { 'm', TRIPLE, 0, &pr_type, NULL,*/
{ 'm', TRIPLE, 0, &pr_type, NULL,
"Short prompt",
"Medium prompt",
"Long prompt"
},
{ 'n', TRIPLE|REPAINT, 1, &linenums, NULL,
"Don't use line numbers",
"Use line numbers",
"Constantly display line numbers"
},
#if LOGFILE
{ 'o', STRING, 0, NULL, opt_o,
"log file: ", NULL, NULL
},
{ 'O', STRING, 0, NULL, opt__O,
"Log file: ", NULL, NULL
},
#endif
{ 'p', STRING|NO_TOGGLE, 0, NULL, opt_p,
NULL, NULL, NULL
},
{ 'P', STRING, 0, NULL, opt__P,
"prompt: ", NULL, NULL
},
{ 'q', TRIPLE, 0, &quiet, NULL,
"Ring the bell for errors AND at eof/bof",
"Ring the bell for errors but not at eof/bof",
"Never ring the bell"
},
/* { 'r', BOOL|REPAINT, 1, &ctldisp, NULL,*/
{ 'r', BOOL|REPAINT, 0, &ctldisp, NULL,
"Display control characters directly",
"Display control characters as ^X",
NULL
},
#if __MSDOS__
{ 'R', BOOL|REPAINT, 0, &refresh_on_quit, NULL,
"Don't repaint screen on quit",
"Repaint screen on quit",
NULL
},
#endif
{ 's', BOOL|REPAINT, 0, &squeeze, NULL,
"Display all blank lines",
"Squeeze multiple blank lines",
NULL
},
{ 'S', BOOL|REPAINT, 0, &chopline, NULL,
"Fold long lines",
"Chop long lines",
NULL
},
#if TAGS
{ 't', STRING, 0, NULL, opt_t,
"tag: ", NULL, NULL
},
{ 'T', STRING, 0, NULL, opt__T,
"tags file: ", NULL, NULL
},
#endif
{ 'u', TRIPLE|REPAINT, 0, &bs_mode, NULL,
"Display underlined text in underline mode",
"Backspaces cause overstrike",
"Print backspace as ^H"
},
#if __MSDOS__
{ 'v', TRIPLE|NO_TOGGLE, 0, &output_mode, opt_v,
"Output is to standard output, using ansi screen control",
"Output is to video BIOS",
"Output is directly to memory mapped video"
},
#endif
{ 'w', BOOL|REPAINT, 1, &twiddle, NULL,
"Display nothing for lines after end-of-file",
"Display ~ for lines after end-of-file",
NULL
},
#if __MSDOS__
#if MOVE_WINDOW
#define W_FLAGS STRING
#else
#define W_FLAGS STRING|NO_TOGGLE
#endif
{ 'W', W_FLAGS, 0, NULL, opt_W,
"window boundaries: ", NULL, NULL
},
#undef W_FLAGS
#endif
{ 'x', NUMBER|REPAINT, 8, &tabstop, NULL,
"Tab stops: ",
"Tab stops every %d spaces",
NULL
},
{ 'y', NUMBER, -1, &forw_scroll, NULL,
"Forward scroll limit: ",
"Forward scroll limit is %d lines",
NULL
},
{ 'z', NUMBER, -1, &swindow, NULL,
"Scroll window size: ",
"Scroll window size is %d lines",
NULL
},
{ '?', NOVAR, 0, NULL, opt_query,
NULL, NULL, NULL
},
{ '\0' }
};
/*
* Initialize each option to its default value.
*/
public void
init_option(void)
{
register struct option *o;
for (o = option; o->oletter != '\0'; o++)
{
/*
* Set each variable to its default.
*/
if (o->ovar != NULL)
*(o->ovar) = o->odefault;
}
}
/*
* Find an option in the option table.
*/
public struct option *
findopt(c)
int c;
{
register struct option *o;
for (o = option; o->oletter != '\0'; o++)
{
if (o->oletter == c)
return (o);
if ((o->otype & TRIPLE) && toupper(o->oletter) == c)
return (o);
}
return (NULL);
}

143
bin/less/os.c Normal file
View File

@ -0,0 +1,143 @@
/*
* Operating system dependent routines.
*
* Most of the stuff in here is based on Unix, but an attempt
* has been made to make things work on other operating systems.
* This will sometimes result in a loss of functionality, unless
* someone rewrites code specifically for the new operating system.
*
* The makefile provides defines to decide whether various
* Unix features are present.
*/
#pragma noroot
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include "less.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#include <fcntl.h>
#endif
/*
* BSD setjmp() saves (and longjmp() restores) the signal mask.
* This costs a system call or two per setjmp(), so if possible we clear the
* signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead.
* On other systems, setjmp() doesn't affect the signal mask and so
* _setjmp() does not exist; we just use setjmp().
*/
#if HAS__SETJMP && SIGSETMASK
#define SET_JUMP _setjmp
#define LONG_JUMP _longjmp
#else
#define SET_JUMP setjmp
#define LONG_JUMP longjmp
#endif
extern char *getenv(char *);
public int reading;
static jmp_buf read_label;
/*
* Like read() system call, but is deliberately interruptible.
* A call to intread() from a signal handler will interrupt
* any pending iread().
*/
public int iread(fd, buf, len)
int fd;
char *buf;
unsigned int len;
{
register int n;
if (SET_JUMP(read_label))
{
/*
* We jumped here from intread.
*/
reading = 0;
#if SIGSETMASK
sigsetmask(0);
#endif
return (READ_INTR);
}
flush();
reading = 1;
n = read(fd, buf, len);
reading = 0;
if (n < 0)
return (-1);
return (n);
}
/*
* Interrupt a pending iread().
*/
public void
intread(void)
{
LONG_JUMP(read_label, 1);
}
#if GET_TIME
public long
get_time(void)
{
long t;
time(&t);
return (t);
}
#endif
/*
* errno_message: Return an error message based on the value of "errno".
*/
#if PERROR
extern char *sys_errlist[];
extern int sys_nerr;
extern int errno;
public char *
errno_message(filename)
char *filename;
{
register char *p;
register char *m;
char msg[16];
if (errno < sys_nerr)
p = sys_errlist[errno];
else
{
sprintf(msg, "Error %d", errno);
p = msg;
}
m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char));
sprintf(m, "%s: %s", filename, p);
return (m);
}
#else
public char *
errno_message(filename)
char *filename;
{
register char *m;
static char msg[] = ": cannot open";
m = (char *) ecalloc(strlen(filename) + sizeof(msg), sizeof(char));
strcpy(m, filename);
strcat(m, msg);
return (m);
}
#endif

440
bin/less/output.c Normal file
View File

@ -0,0 +1,440 @@
/*
* High level routines dealing with the output to the screen.
*/
#pragma noroot
#include "less.h"
#include <unistd.h>
#include <fcntl.h>
#ifdef _ORCAC_
#define FAST
segment "LoadSegONE";
#endif
public int errmsgs; /* Count of messages displayed by error() */
public int need_clr;
extern int sigs;
extern int sc_width;
extern int so_s_width, so_e_width;
extern int screen_trashed;
extern int any_display;
#if __MSDOS__
extern int output_mode;
#endif
static int iprintnum(int num, int radix);
static int iprintf(char *fmt, PARG *parg);
/*
* Display the line which is in the line buffer.
*/
public void
put_line(void)
{
register int c;
register int i;
int a;
int curr_attr;
if (sigs)
{
/*
* Don't output if a signal is pending.
*/
screen_trashed = 1;
return;
}
curr_attr = NORMAL;
for (i = 0; (c = gline(i, &a)) != '\0'; i++)
{
if (a != curr_attr)
{
/*
* Changing attributes.
* Display the exit sequence for the old attribute
* and the enter sequence for the new one.
*/
switch (curr_attr)
{
case UNDERLINE: ul_exit(); break;
case BOLD: bo_exit(); break;
case BLINK: bl_exit(); break;
}
switch (a)
{
case UNDERLINE: ul_enter(); break;
case BOLD: bo_enter(); break;
case BLINK: bl_enter(); break;
}
curr_attr = a;
}
if (curr_attr == INVIS)
continue;
if (c == '\b')
putbs();
else
putchr(c);
}
}
/*static char obuf[1024];*/
static char obuf[1024];
static char *ob = obuf;
/*
* Flush buffered output.
*
* If we haven't displayed any file data yet,
* output messages on error output (file descriptor 2),
* otherwise output on standard output (file descriptor 1).
*
* This has the desirable effect of producing all
* error messages on error output if standard output
* is directed to a file. It also does the same if
* we never produce any real output; for example, if
* the input file(s) cannot be opened. If we do
* eventually produce output, code in edit() makes
* sure these messages can be seen before they are
* overwritten or scrolled away.
*/
public void
flush(void)
{
register int n;
register int fd;
#if __MSDOS__
if (output_mode == 0)
{
*ob = '\0';
cputs(obuf);
ob = obuf;
return;
}
#endif
n = ob - obuf;
if (n == 0)
return;
/* fd = (any_display) ? 1 : 2;*/
fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO;
if (write(fd, obuf, n) != n)
screen_trashed = 1;
ob = obuf;
}
/*
* Output a character.
*/
#ifdef FAST
public void putchr(c)
int c;
{
static char *sz=obuf+sizeof(obuf);
char *oo;
asm {
lda ob+2
sta oo+2
lda ob
sta oo
cmp sz
bcc nofl
jsl flush
lda ob
sta oo
nofl: lda need_clr
beq noncl
stz need_clr
jsl lower_left
jsl clear_eol
noncl: lda c
cmp #10
bne notnl
lda #13
notnl: pha
lda [oo]
and #0xff00
ora 1,s
sta [oo]
pla
inc ob
}
}
#else
public void putchr(c)
int c;
{
if (ob >= &obuf[sizeof(obuf)])
flush();
if (need_clr)
{
need_clr = 0;
lower_left();
clear_eol();
}
#if __MSDOS__
if (c == '\n')
*ob++ = '\r';
#endif
#ifdef __ORCAC__
if (c == '\n')
*ob++ = '\r';
else
#endif
*ob++ = c;
}
#endif
/*
* Output a string.
*/
#ifdef FAST
public void putstr(s)
register char *s;
{
static char *sz=obuf+sizeof(obuf);
char *oo;
int ytmp;
asm {
stz ytmp
lda ob+2
sta oo+2
lda ob
sta oo
lp: ldy ytmp
lda [s],y
and #0xff
beq done
pha
/* jsl putchr*/
lda oo
cmp sz
bcc nofl
jsl flush
lda ob
sta oo
nofl: lda need_clr
beq noncl
stz need_clr
jsl lower_left
jsl clear_eol
noncl: lda 1,s
cmp #10
bne notnl
lda #13
notnl: pha
lda [oo]
and #0xff00
ora 1,s
sta [oo]
pla
pla
inc ob
inc oo
inc ytmp
bra lp
done:
}
}
#else
public void putstr(s)
register char *s;
{
while (*s != '\0')
putchr(*s++);
}
#endif
/*
* Output an integer in a given radix.
*/
static int
iprintnum(num, radix)
int num;
int radix;
{
register char *s;
int r;
int neg;
char buf[10];
if (neg = (num < 0))
num = -num;
s = buf;
do
{
*s++ = (num % radix) + '0';
} while ((num /= radix) != 0);
if (neg)
*s++ = '-';
r = s - buf;
while (s > buf)
putchr(*--s);
return (r);
}
/*
* This function implements printf-like functionality
* using a more portable argument list mechanism than printf's.
*/
static int
iprintf(fmt, parg)
register char *fmt;
PARG *parg;
{
register char *s;
register int n;
register int col;
col = 0;
while (*fmt != '\0')
{
if (*fmt != '%')
{
putchr(*fmt++);
col++;
} else
{
++fmt;
switch (*fmt++) {
case 's':
s = parg->p_string;
parg++;
while (*s != '\0')
{
putchr(*s++);
col++;
}
break;
case 'd':
n = parg->p_int;
parg++;
col += iprintnum(n, 10);
break;
}
}
}
return (col);
}
/*
* Output a message in the lower left corner of the screen
* and wait for carriage return.
*/
public void
error(fmt, parg)
char *fmt;
PARG *parg;
{
int c;
int col = 0;
static char return_to_continue[] = " (press RETURN)";
errmsgs++;
if (any_display)
{
lower_left();
clear_eol();
so_enter();
col += so_s_width;
}
col += iprintf(fmt, parg);
if (!any_display)
{
/* putchr('\n');*/
putchr('\r');
return;
}
putstr(return_to_continue);
so_exit();
col += sizeof(return_to_continue) + so_e_width;
#if ONLY_RETURN
while ((c = getchr()) != '\n' && c != '\r')
bell();
#else
c = getchr();
if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
ungetcc(c);
#endif
lower_left();
if (col >= sc_width)
/*
* Printing the message has probably scrolled the screen.
* {{ Unless the terminal doesn't have auto margins,
* in which case we just hammered on the right margin. }}
*/
screen_trashed = 1;
flush();
}
static char intr_to_abort[] = "... (interrupt to abort)";
/*
* Output a message in the lower left corner of the screen
* and don't wait for carriage return.
* Usually used to warn that we are beginning a potentially
* time-consuming operation.
*/
public void
ierror(fmt, parg)
char *fmt;
PARG *parg;
{
lower_left();
clear_eol();
so_enter();
(void) iprintf(fmt, parg);
putstr(intr_to_abort);
so_exit();
flush();
need_clr = 1;
}
/*
* Output a message in the lower left corner of the screen
* and return a single-character response.
*/
public int
query(fmt, parg)
char *fmt;
PARG *parg;
{
register int c;
int col = 0;
if (any_display)
{
lower_left();
clear_eol();
}
(void) iprintf(fmt, parg);
c = getchr();
if (!any_display)
{
/* putchr('\n');*/
putchr('\r');
return (c);
}
lower_left();
if (col >= sc_width)
screen_trashed = 1;
flush();
return (c);
}

212
bin/less/position.c Normal file
View File

@ -0,0 +1,212 @@
/*
* Routines dealing with the "position" table.
* This is a table which tells the position (in the input file) of the
* first char on each currently displayed line.
*
* {{ The position table is scrolled by moving all the entries.
* Would be better to have a circular table
* and just change a couple of pointers. }}
*/
#pragma noroot
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
static POSITION *table = NULL; /* The position table */
static int table_size;
extern int sc_width, sc_height;
/*
* Return the starting file position of a line displayed on the screen.
* The line may be specified as a line number relative to the top
* of the screen, but is usually one of these special cases:
* the top (first) line on the screen
* the second line on the screen
* the bottom line on the screen
* the line after the bottom line on the screen
*/
public POSITION
position(where)
int where;
{
switch (where)
{
case BOTTOM:
where = sc_height - 2;
break;
case BOTTOM_PLUS_ONE:
where = sc_height - 1;
break;
case MIDDLE:
where = sc_height / 2;
}
return (table[where]);
}
/*
* Add a new file position to the bottom of the position table.
*/
public void
add_forw_pos(pos)
POSITION pos;
{
register int i;
/*
* Scroll the position table up.
*/
for (i = 1; i < sc_height; i++)
table[i-1] = table[i];
table[sc_height - 1] = pos;
}
/*
* Add a new file position to the top of the position table.
*/
public void
add_back_pos(pos)
POSITION pos;
{
register int i;
/*
* Scroll the position table down.
*/
for (i = sc_height - 1; i > 0; i--)
table[i] = table[i-1];
table[0] = pos;
}
/*
* Initialize the position table, done whenever we clear the screen.
*/
public void
pos_clear(void)
{
register int i;
for (i = 0; i < sc_height; i++)
table[i] = NULL_POSITION;
}
/*
* Allocate the position table.
*/
public void
pos_init(void)
{
if (sc_height <= table_size)
return;
if (table != NULL)
free((char*)table);
table = (POSITION *) ecalloc(sc_height, sizeof(POSITION));
table_size = sc_height;
}
/*
* See if the byte at a specified position is currently on the screen.
* Check the position table to see if the position falls within its range.
* Return the position table entry if found, -1 if not.
*/
public int
onscreen(pos)
POSITION pos;
{
register int i;
if (pos < table[0])
return (-1);
for (i = 1; i < sc_height; i++)
if (pos < table[i])
return (i-1);
return (-1);
}
/*
* See if the entire screen is empty.
*/
public int
empty_screen(void)
{
return (empty_lines(0, sc_height-1));
}
public int
empty_lines(s, e)
int s;
int e;
{
register int i;
for (i = s; i <= e; i++)
if (table[i] != NULL_POSITION)
return (0);
return (1);
}
/*
* Get the current screen position.
* The screen position consists of both a file position and
* a screen line number where the file position is placed on the screen.
* Normally the screen line number is 0, but if we are positioned
* such that the top few lines are empty, we may have to set
* the screen line to a number > 0.
*/
public void
get_scrpos(scrpos)
struct scrpos *scrpos;
{
register int i;
/*
* Find the first line on the screen which has something on it,
* and return the screen line number and the file position.
*/
for (i = 0; i < sc_height; i++)
if (table[i] != NULL_POSITION)
{
scrpos->ln = i+1;
scrpos->pos = table[i];
return;
}
/*
* The screen is empty.
*/
scrpos->pos = NULL_POSITION;
}
/*
* Adjust a screen line number to be a simple positive integer
* in the range { 0 .. sc_height-2 }.
* (The bottom line, sc_height-1, is reserved for prompts, etc.)
* The given "sline" may be in the range { 1 .. sc_height-1 }
* to refer to lines relative to the top of the screen (starting from 1),
* or it may be in { -1 .. -(sc_height-1) } to refer to lines
* relative to the bottom of the screen.
*/
public int
adjsline(sline)
int sline;
{
/*
* Negative screen line number means
* relative to the bottom of the screen.
*/
if (sline < 0)
sline += sc_height;
/*
* Can't be less than 1 or greater than sc_height-1.
*/
if (sline <= 0)
sline = 1;
if (sline >= sc_height)
sline = sc_height - 1;
/*
* Return zero-based line number, not one-based.
*/
return (sline-1);
}

8
bin/less/position.h Normal file
View File

@ -0,0 +1,8 @@
/*
* Include file for interfacing to position.c modules.
*/
#define TOP (0)
#define TOP_PLUS_ONE (1)
#define BOTTOM (-1)
#define BOTTOM_PLUS_ONE (-2)
#define MIDDLE (-3)

444
bin/less/prompt.c Normal file
View File

@ -0,0 +1,444 @@
/*
* Prompting and other messages.
* There are three flavors of prompts, SHORT, MEDIUM and LONG,
* selected by the -m/-M options.
* There is also the "equals message", printed by the = command.
* A prompt is a message composed of various pieces, such as the
* name of the file being viewed, the percentage into the file, etc.
*/
#pragma noroot
#include <stdio.h>
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern int pr_type;
extern int hit_eof;
extern int new_file;
extern int sc_width;
extern int so_s_width, so_e_width;
extern int linenums;
extern int sc_height;
extern int jump_sline;
extern IFILE curr_ifile;
#if EDITOR
extern char *editor;
#endif
/*
* Prototypes for the three flavors of prompts.
* These strings are expanded by pr_expand().
*/
static char s_proto[] =
"?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x..%t";
static char m_proto[] =
"?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t";
static char M_proto[] =
"?f%f .?n?m(file %i of %m) ..?ltline %lt?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t";
static char e_proto[] =
"?f%f .?m(file %i of %m) .?ltline %lt?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t";
public char *prproto[3];
public char *eqproto = e_proto;
static char message[250];
static char *mp;
static void setmp(void);
static void ap_pos(POSITION pos);
static void ap_int(int n);
static void ap_str(char *s);
static void ap_quest(void);
static POSITION curr_byte(int where);
static int cond(char c, int where);
static void protochar(int c, int where);
static char *skipcond(char *p);
static char *wherechar(char *p, int *wp);
/*
* Initialize the prompt prototype strings.
*/
public void
init_prompt(void)
{
prproto[0] = save(s_proto);
prproto[1] = save(m_proto);
prproto[2] = save(M_proto);
eqproto = save(e_proto);
}
/*
* Set the message pointer to the end of the message string.
*/
static void
setmp(void)
{
while (*mp != '\0')
mp++;
}
/*
* Append a POSITION (as a decimal integer) to the end of the message.
*/
static void
ap_pos(pos)
POSITION pos;
{
sprintf(mp, "%ld", (long)pos);
setmp();
}
/*
* Append an integer to the end of the message.
*/
static void
ap_int(n)
int n;
{
sprintf(mp, "%d", n);
setmp();
}
/*
* Append a string to the end of the message.
*/
static void
ap_str(s)
char *s;
{
strtcpy(mp, s, (unsigned int)(&message[sizeof(message)] - mp));
setmp();
}
/*
* Append a question mark to the end of the message.
*/
static void
ap_quest()
{
*mp++ = '?';
}
/*
* Return the "current" byte offset in the file.
*/
static POSITION
curr_byte(where)
int where;
{
POSITION pos;
pos = position(where);
while (pos == NULL_POSITION && where >= 0 && where < sc_height)
pos = position(++where);
if (pos == NULL_POSITION)
pos = ch_length();
return (pos);
}
/*
* Return the value of a prototype conditional.
* A prototype string may include conditionals which consist of a
* question mark followed by a single letter.
* Here we decode that letter and return the appropriate boolean value.
*/
static int
cond(c, where)
char c;
int where;
{
switch (c)
{
case 'a': /* Anything in the message yet? */
return (mp > message);
case 'b': /* Current byte offset known? */
return (curr_byte(where) != NULL_POSITION);
case 'e': /* At end of file? */
return (hit_eof);
case 'f': /* Filename known? */
return (strcmp(get_filename(curr_ifile), "-") != 0);
case 'l': /* Line number known? */
return (linenums);
case 'L': /* Final line number known? */
return (linenums && ch_length() != NULL_POSITION);
case 'm': /* More than one file? */
return (nifile() > 1);
case 'n': /* First prompt in a new file? */
return (new_file);
case 'p': /* Percent into file known? */
return (curr_byte(where) != NULL_POSITION &&
ch_length() > 0);
case 's': /* Size of file known? */
case 'B':
return (ch_length() != NULL_POSITION);
case 'x': /* Is there a "next" file? */
return (next_ifile(curr_ifile) != NULL_IFILE);
}
return (0);
}
/*
* Decode a "percent" prototype character.
* A prototype string may include various "percent" escapes;
* that is, a percent sign followed by a single letter.
* Here we decode that letter and take the appropriate action,
* usually by appending something to the message being built.
*/
static void
protochar(c, where)
int c;
int where;
{
POSITION pos;
POSITION len;
int n;
IFILE h;
switch (c)
{
case 'b': /* Current byte offset */
pos = curr_byte(where);
if (pos != NULL_POSITION)
ap_pos(pos);
else
ap_quest();
break;
#if EDITOR
case 'E': /* Editor name */
ap_str(editor);
break;
#endif
case 'f': /* File name */
ap_str(get_filename(curr_ifile));
break;
case 'i': /* Index into list of files */
ap_int(get_index(curr_ifile));
break;
case 'l': /* Current line number */
n = currline(where);
if (n != 0)
ap_int(n);
else
ap_quest();
break;
case 'L': /* Final line number */
len = ch_length();
if (len == NULL_POSITION || len == ch_zero() ||
(n = find_linenum(len)) <= 0)
ap_quest();
else
ap_int(n-1);
break;
case 'm': /* Number of files */
ap_int(nifile());
break;
case 'p': /* Percent into file */
pos = curr_byte(where);
len = ch_length();
if (pos != NULL_POSITION && len > 0)
/*
* {{ This calculation may overflow! }}
*/
ap_int((int)(100*pos / len));
else
ap_quest();
break;
case 's': /* Size of file */
case 'B':
len = ch_length();
if (len != NULL_POSITION)
ap_pos(len);
else
ap_quest();
break;
case 't': /* Truncate trailing spaces in the message */
while (mp > message && mp[-1] == ' ')
mp--;
break;
case 'x': /* Name of next file */
h = next_ifile(curr_ifile);
if (h != NULL_IFILE)
ap_str(get_filename(h));
else
ap_quest();
break;
}
}
/*
* Skip a false conditional.
* When a false condition is found (either a false IF or the ELSE part
* of a true IF), this routine scans the prototype string to decide
* where to resume parsing the string.
* We must keep track of nested IFs and skip them properly.
*/
static char *
skipcond(p)
register char *p;
{
register int iflevel;
/*
* We came in here after processing a ? or :,
* so we start nested one level deep.
*/
iflevel = 1;
for (;;) switch (*++p)
{
case '?':
/*
* Start of a nested IF.
*/
iflevel++;
break;
case ':':
/*
* Else.
* If this matches the IF we came in here with,
* then we're done.
*/
if (iflevel == 1)
return (p);
break;
case '.':
/*
* Endif.
* If this matches the IF we came in here with,
* then we're done.
*/
if (--iflevel == 0)
return (p);
break;
case '\\':
/*
* Backslash escapes the next character.
*/
++p;
break;
case '\0':
/*
* Whoops. Hit end of string.
* This is a malformed conditional, but just treat it
* as if all active conditionals ends here.
*/
return (p-1);
}
/*NOTREACHED*/
}
static char *
wherechar(p, wp)
char *p;
int *wp;
{
switch (*p)
{
case 'b': case 'l': case 'p':
switch (*++p)
{
case 't': *wp = TOP; break;
case 'm': *wp = MIDDLE; break;
case 'b': *wp = BOTTOM; break;
case 'B': *wp = BOTTOM_PLUS_ONE; break;
case 'j': *wp = adjsline(jump_sline); break;
default: *wp = TOP; p--; break;
}
}
return (p);
}
/*
* Construct a message based on a prototype string.
*/
public char *
pr_expand(proto, maxwidth)
char *proto;
int maxwidth;
{
register char *p;
register int c;
int where;
mp = message;
if (*proto == '\0')
return ("");
for (p = proto; *p != '\0'; p++)
{
switch (*p)
{
default: /* Just put the character in the message */
*mp++ = *p;
break;
case '\\': /* Backslash escapes the next character */
p++;
*mp++ = *p;
break;
case '?': /* Conditional (IF) */
if ((c = *++p) == '\0')
--p;
else
{
p = wherechar(p, &where);
if (!cond(c, where))
p = skipcond(p);
}
break;
case ':': /* ELSE */
p = skipcond(p);
break;
case '.': /* ENDIF */
break;
case '%': /* Percent escape */
if ((c = *++p) == '\0')
--p;
else
{
p = wherechar(p, &where);
protochar(c, where);
}
break;
}
}
new_file = 0;
if (mp == message)
return (NULL);
*mp = '\0';
if (maxwidth > 0 && mp >= message + maxwidth)
{
/*
* Message is too long.
* Return just the final portion of it.
*/
return (mp - maxwidth);
}
return (message);
}
/*
* Return a message suitable for printing by the "=" command.
*/
public char *
eq_message(void)
{
return (pr_expand(eqproto, 0));
}
/*
* Return a prompt.
* This depends on the prompt type (SHORT, MEDIUM, LONG), etc.
* If we can't come up with an appropriate prompt, return NULL
* and the caller will prompt with a colon.
*/
public char *
pr_string(void)
{
return (pr_expand(prproto[pr_type], sc_width-so_s_width-so_e_width-2));
}

232
bin/less/proto.h Normal file
View File

@ -0,0 +1,232 @@
/* brac.c */
public void match_brac(int obrac, int cbrac, int forwdir, int n);
/* ch.c */
public void end_logfile(void);
public void synch_logfile(void);
public int ch_seek(register POSITION pos);
public int ch_end_seek(void);
public int ch_beg_seek(void);
public POSITION ch_length(void);
public POSITION ch_tell(void);
public int ch_forw_get(void);
public int ch_back_get(void);
public int ch_nbuf(int want_nbufs);
public void ch_flush(void);
public void ch_pipe(void);
public void ch_nonpipe(void);
/* from charset.c */
public void init_charset(void);
public int binary_char(int c);
public int control_char(int c);
public char *prchar(int c);
/* from cmdbuf.c */
public void cmd_reset(void);
public int len_cmdbuf(void);
public int cmd_erase(void);
public int cmd_char(int c);
public int cmd_int(void);
public void cmd_putstr(char *s);
public char *get_cmdbuf(void);
/* command.c */
public void ungetcc(int c);
public void ungetsc(char *s);
public void commands(void);
/* decode.c */
public int cmd_decode(char *cmd, char **sp);
public int add_cmdtable(char *filename);
public void add_hometable(void);
/* edit.c */
public int edit(register char *filename, int just_looking);
public void edit_list(char *list);
public int edit_first(void);
public int edit_last(void);
public int edit_next(int n);
public int edit_prev(int n);
public int edit_index(int n);
public void cat_file(void);
public void use_logfile(char *filename);
/* filename.c */
public char *homefile(char *filename);
public char *find_helpfile(void);
public char *fexpand(char *s);
int bin_file(int f);
public char *glob(char *filename);
public char *load_file(char *filename);
public POSITION filesize(int f);
public char *bad_file(char *filename);
public POSITION filesize(int f);
/* forwback.c */
public void forw(register int n, POSITION pos, int force, int only_last,
int nblank);
public void back(register int n, POSITION pos, int force, int only_last);
public void forward(register int n, int force, int only_last);
public void backward(register int n, int force, int only_last);
public int get_back_scroll(void);
/* help.c */
public void help(void);
/* ifile.c */
public IFILE next_ifile(IFILE h);
public IFILE prev_ifile(IFILE h);
public int nifile(void);
public IFILE get_ifile(char *filename, IFILE prev);
public char *get_filename(IFILE ifile);
public int get_index(IFILE ifile);
public void store_pos(IFILE ifile, struct scrpos *scrpos);
public void get_pos(IFILE ifile, struct scrpos *scrpos);
/* from input.c */
public POSITION forw_line(POSITION curr_pos);
public POSITION back_line(POSITION curr_pos);
/* jump.c */
public void jump_forw(void);
public void jump_back(int n);
public void repaint(void);
public void jump_repaint(int percent);
public void jump_line_loc(POSITION pos, int sline);
public void jump_loc(POSITION pos, int sline);
/* line.c */
void prewind(void);
public void plinenum(POSITION pos);
int attr_swidth(int a);
int attr_ewidth(int a);
public int pappend(register int c);
public void pdone(int endline);
public int gline(register int i, register int *ap);
public void null_line(void);
public POSITION forw_raw_line(POSITION curr_pos, char **linep);
public POSITION back_raw_line(POSITION curr_pos, char **linep);
/* linenum.c */
public void clr_linenum(void);
public void add_lnum(int lno, POSITION pos);
public int find_linenum(POSITION pos);
public POSITION find_pos(int lno);
public int currline(int where);
/* lsystem.c */
public void lsystem(char *cmd);
public int pipe_mark(int c, char *cmd);
public int pipe_data(char *cmd, POSITION spos, POSITION epos);
/* main.c */
public void strtcpy(char *to, char *from, unsigned int len);
public char *save(char *s);
public VOID_POINTER ecalloc(int count, unsigned int size);
public char *skipsp(register char *s);
public void quit(int status);
/* mark.c */
public void init_mark(void);
public int badmark(int c);
public void setmark(int c);
public void lastmark(void);
public void gomark(int c);
public POSITION markpos(int c);
/* optfunc */
public void opt_o(int type, char *s);
public void opt__O(int type, char *s);
public void opt_l(int type, char *s);
public void opt__L(int type, char *s);
public void opt_k(int type, char *s);
public void opt_t(int type, char *s);
public void opt__T(int type, char *s);
public void opt_p(int type, register char *s);
public void opt__P(int type, register char *s);
public void opt_b(int type, char *s);
public void opt_v(int type, register char *s);
public void opt_W(int type, register char *s);
public void opt_query(int type, char *s);
/* from option.c */
public void scan_option(char *s);
public void toggle_option(int c, char *s, int how_toggle);
public int single_char_option(int c);
public char *opt_prompt(int c);
public int isoptpending(void);
public void nopendopt(void);
public int getnum(char **sp, int c, int *errp);
/* from opttbl.c */
public void init_option(void);
public struct option *findopt(int c);
/* from os.c */
public int iread(int fd, char *buf, unsigned int len);
public void intread(void);
public long get_time(void);
public char *errno_message(char *filename);
/* from output.c */
public void put_line(void);
public void flush(void);
public void putchr(int c);
public void putstr(char *s);
public void error(char *fmt, PARG *parg);
public void ierror(char *fmt, PARG *parg);
public int query(char *fmt, PARG *parg);
/* from position.c */
public POSITION position(int where);
public void add_forw_pos(POSITION pos);
public void add_back_pos(POSITION pos);
public void pos_clear(void);
public void pos_init(void);
public int onscreen(POSITION pos);
public int empty_screen(void);
public int empty_lines(int s, int e);
public void get_scrpos(struct scrpos *scrpos);
public int adjsline(int sline);
/* from prompt.c */
public void init_prompt(void);
public char *pr_expand(char *proto, int maxwidth);
public char *eq_message(void);
public char *pr_string(void);
/* from screen.c */
public void raw_mode(int on);
public void scrsize(int *p_height, int *p_width);
public void get_term(void);
public void init(void);
public void deinit(void);
public void home(void);
public void add_line(void);
public void lower_left(void);
public void bell(void);
public void vbell(void);
public void clear(void);
public void clear_eol(void);
public void so_enter(void);
public void so_exit(void);
public void ul_enter(void);
public void ul_exit(void);
public void bo_enter(void);
public void bo_exit(void);
public void bl_enter(void);
public void bl_exit(void);
public void backspace(void);
public void putbs(void);
/* from search.c */
public int search(int search_type, char *pattern, int n);
/* from signal.c */
public void fake_interrupt(void);
public HANDLER winch(int type);
public void init_signals(int on);
public void psignals(void);
/* from tags.c */
public void findtag(char *tag);
public int tagsearch(void);
/* from ttyin.c */
public void open_getchr(void);
public int getchr(void);

712
bin/less/screen.c Normal file
View File

@ -0,0 +1,712 @@
/*
* Routines which deal with the characteristics of the terminal.
* Uses termcap to be as terminal-independent as possible.
*
* {{ Someday this should be rewritten to use curses. }}
*/
#pragma noroot
#include <string.h>
#include "less.h"
#if XENIX
#include <sys/types.h>
#include <sys/ioctl.h>
#endif
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
#if TERMIO
#include <termio.h>
#else
#include <sgtty.h>
#endif
#if !TERMIO && defined(TIOCGWINSZ)
#include <sys/ioctl.h>
#else
/*
* For the Unix PC (ATT 7300 & 3B1):
* Since WIOCGETD is defined in sys/window.h, we can't use that to decide
* whether to include sys/window.h. Use SIGPHONE from signal.h instead.
*/
#include <signal.h>
#ifdef SIGPHONE
#include <sys/window.h>
#endif
#endif
#if NEED_PTEM_H && defined(TIOCGWINSZ)
/*
* All this just to get struct winsize. Sigh.
*/
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/ptem.h>
#endif
/*
* Strings passed to tputs() to do various terminal functions.
*/
static char
*sc_pad, /* Pad string */
*sc_home, /* Cursor home */
*sc_addline, /* Add line, scroll down following lines */
*sc_lower_left, /* Cursor to last line, first column */
*sc_move, /* General cursor positioning */
*sc_clear, /* Clear screen */
*sc_eol_clear, /* Clear to end of line */
*sc_s_in, /* Enter standout (highlighted) mode */
*sc_s_out, /* Exit standout mode */
*sc_u_in, /* Enter underline mode */
*sc_u_out, /* Exit underline mode */
*sc_b_in, /* Enter bold mode */
*sc_b_out, /* Exit bold mode */
*sc_bl_in, /* Enter blink mode */
*sc_bl_out, /* Exit blink mode */
*sc_visual_bell, /* Visual bell (flash screen) sequence */
*sc_backspace, /* Backspace cursor */
*sc_init, /* Startup terminal initialization */
*sc_deinit; /* Exit terminal de-initialization */
static int init_done = 0;
public int auto_wrap; /* Terminal does \r\n when write past margin */
public int ignaw; /* Terminal ignores \n immediately after wrap */
public int erase_char, kill_char; /* The user's erase and line-kill chars */
public int sc_width, sc_height; /* Height & width of screen */
public int bo_s_width, bo_e_width; /* Printing width of boldface seq */
public int ul_s_width, ul_e_width; /* Printing width of underline seq */
public int so_s_width, so_e_width; /* Printing width of standout seq */
public int bl_s_width, bl_e_width; /* Printing width of blink seq */
static void cannot(char *s);
static void inc_costcount(int c);
static int cost(char *t);
static char *cheaper(char *t1, char *t2, char *doit, char *def);
/*
* These two variables are sometimes defined in,
* and needed by, the termcap library.
* It may be necessary on some systems to declare them extern here.
*/
extern short ospeed; /* Terminal output baud rate */
extern char PC; /* Pad character */
extern int quiet; /* If VERY_QUIET, use visual bell for bell */
extern int know_dumb; /* Don't complain about a dumb terminal */
extern int back_scroll;
extern int swindow;
extern char *tgetstr(char *, char **);
extern char *tgoto(char *, int, int);
extern char *getenv(char *);
/*
* Change terminal to "raw mode", or restore to "normal" mode.
* "Raw mode" means
* 1. An outstanding read will complete on receipt of a single keystroke.
* 2. Input is not echoed.
* 3. On output, \n is mapped to \r\n.
* 4. \t is NOT expanded into spaces.
* 5. Signal-causing characters such as ctrl-C (interrupt),
* etc. are NOT disabled.
* It doesn't matter whether an input \n is mapped to \r, or vice versa.
*/
public void
raw_mode(on)
int on;
{
static int curr_on = 0;
if (on == curr_on)
return;
#if TERMIO
{
struct termio s;
static struct termio save_term;
if (on)
{
/*
* Get terminal modes.
*/
ioctl(2, TCGETA, &s);
/*
* Save modes and set certain variables dependent on modes.
*/
save_term = s;
ospeed = s.c_cflag & CBAUD;
erase_char = s.c_cc[VERASE];
kill_char = s.c_cc[VKILL];
/*
* Set the modes to the way we want them.
*/
s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
s.c_oflag |= (OPOST|ONLCR|TAB3);
s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
s.c_cc[VMIN] = 1;
s.c_cc[VTIME] = 0;
} else
{
/*
* Restore saved modes.
*/
s = save_term;
}
ioctl(2, TCSETAW, &s);
}
#else
{
struct sgttyb s;
static struct sgttyb save_term;
if (on)
{
/*
* Get terminal modes.
*/
ioctl(2, TIOCGETP, &s);
/*
* Save modes and set certain variables dependent on modes.
*/
save_term = s;
ospeed = s.sg_ospeed;
erase_char = s.sg_erase;
kill_char = s.sg_kill;
/*
* Set the modes to the way we want them.
*/
s.sg_flags |= CBREAK;
s.sg_flags &= ~(ECHO|XTABS);
} else
{
/*
* Restore saved modes.
*/
s = save_term;
}
ioctl(2, TIOCSETN, &s);
}
#endif
curr_on = on;
}
static void
cannot(s)
char *s;
{
PARG parg;
if (know_dumb)
/*
* User knows this is a dumb terminal, so don't tell him.
*/
return;
parg.p_string = s;
error("WARNING: terminal cannot %s", &parg);
}
/*
* Get size of the output screen.
*/
public void
scrsize(p_height, p_width)
int *p_height;
int *p_width;
{
register char *s;
#ifdef TIOCGWINSZ
struct winsize w;
#else
#ifdef WIOCGETD
struct uwdata w;
#endif
#endif
#ifdef TIOCGWINSZ
if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
*p_height = w.ws_row;
else
#else
#ifdef WIOCGETD
if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_height > 0)
*p_height = w.uw_height/w.uw_vs;
else
#endif
#endif
if ((s = getenv("LINES")) != NULL)
*p_height = atoi(s);
else
*p_height = tgetnum("li");
if (*p_height <= 0)
*p_height = 24;
#ifdef TIOCGWINSZ
if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
*p_width = w.ws_col;
else
#ifdef WIOCGETD
if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_width > 0)
*p_width = w.uw_width/w.uw_hs;
else
#endif
#endif
if ((s = getenv("COLUMNS")) != NULL)
*p_width = atoi(s);
else
*p_width = tgetnum("co");
if (*p_width <= 0)
*p_width = 80;
}
/*
* Get terminal capabilities via termcap.
*/
public void
get_term(void)
{
char *sp;
register char *t1, *t2;
register int hard;
char *term;
static char termbuf[2048];
static char sbuf[1024];
/*
* Find out what kind of terminal this is.
*/
if ((term = getenv("TERM")) == NULL)
term = "unknown";
if (tgetent(termbuf, term) <= 0)
strcpy(termbuf, "dumb:hc:");
hard = tgetflag("hc");
/*
* Get size of the screen.
*/
scrsize(&sc_height, &sc_width);
pos_init();
if (swindow < 0)
swindow = sc_height - 1;
auto_wrap = tgetflag("am");
ignaw = tgetflag("xn");
/*
* Assumes termcap variable "sg" is the printing width of:
* the standout sequence, the end standout sequence,
* the underline sequence, the end underline sequence,
* the boldface sequence, and the end boldface sequence.
*/
if ((so_s_width = tgetnum("sg")) < 0)
so_s_width = 0;
so_e_width = so_s_width;
bo_s_width = bo_e_width = so_s_width;
ul_s_width = ul_e_width = so_s_width;
bl_s_width = bl_e_width = so_s_width;
/*
* Get various string-valued capabilities.
*/
sp = sbuf;
sc_pad = tgetstr("pc", &sp);
if (sc_pad != NULL)
PC = *sc_pad;
sc_init = tgetstr("ti", &sp);
if (sc_init == NULL)
sc_init = "";
sc_deinit= tgetstr("te", &sp);
if (sc_deinit == NULL)
sc_deinit = "";
sc_eol_clear = tgetstr("ce", &sp);
if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
{
cannot("clear to end of line");
sc_eol_clear = "";
}
sc_clear = tgetstr("cl", &sp);
if (hard || sc_clear == NULL || *sc_clear == '\0')
{
cannot("clear screen");
sc_clear = "\n\n";
}
sc_move = tgetstr("cm", &sp);
if (hard || sc_move == NULL || *sc_move == '\0')
{
/*
* This is not an error here, because we don't
* always need sc_move.
* We need it only if we don't have home or lower-left.
*/
sc_move = "";
}
sc_s_in = tgetstr("so", &sp);
if (hard || sc_s_in == NULL)
sc_s_in = "";
sc_s_out = tgetstr("se", &sp);
if (hard || sc_s_out == NULL)
sc_s_out = "";
sc_u_in = tgetstr("us", &sp);
if (hard || sc_u_in == NULL)
sc_u_in = sc_s_in;
sc_u_out = tgetstr("ue", &sp);
if (hard || sc_u_out == NULL)
sc_u_out = sc_s_out;
sc_b_in = tgetstr("md", &sp);
if (hard || sc_b_in == NULL)
{
sc_b_in = sc_s_in;
sc_b_out = sc_s_out;
} else
{
sc_b_out = tgetstr("me", &sp);
if (hard || sc_b_out == NULL)
sc_b_out = "";
}
sc_bl_in = tgetstr("mb", &sp);
if (hard || sc_bl_in == NULL)
{
sc_bl_in = sc_s_in;
sc_bl_out = sc_s_out;
} else
{
sc_bl_out = sc_b_out;
}
sc_visual_bell = tgetstr("vb", &sp);
if (hard || sc_visual_bell == NULL)
sc_visual_bell = "";
if (tgetflag("bs"))
sc_backspace = "\b";
else
{
sc_backspace = tgetstr("bc", &sp);
if (sc_backspace == NULL || *sc_backspace == '\0')
sc_backspace = "\b";
}
/*
* Choose between using "ho" and "cm" ("home" and "cursor move")
* to move the cursor to the upper left corner of the screen.
*/
t1 = tgetstr("ho", &sp);
if (hard || t1 == NULL)
t1 = "";
if (*sc_move == '\0')
t2 = "";
else
{
strcpy(sp, tgoto(sc_move, 0, 0));
t2 = sp;
sp += strlen(sp) + 1;
}
sc_home = cheaper(t1, t2, "home cursor", "|\b^");
/*
* Choose between using "ll" and "cm" ("lower left" and "cursor move")
* to move the cursor to the lower left corner of the screen.
*/
t1 = tgetstr("ll", &sp);
if (hard || t1 == NULL)
t1 = "";
if (*sc_move == '\0')
t2 = "";
else
{
strcpy(sp, tgoto(sc_move, 0, sc_height-1));
t2 = sp;
sp += strlen(sp) + 1;
}
sc_lower_left = cheaper(t1, t2,
"move cursor to lower left of screen", "\r");
/*
* Choose between using "al" or "sr" ("add line" or "scroll reverse")
* to add a line at the top of the screen.
*/
t1 = tgetstr("al", &sp);
if (hard || t1 == NULL)
t1 = "";
t2 = tgetstr("sr", &sp);
if (hard || t2 == NULL)
t2 = "";
sc_addline = cheaper(t1, t2, "scroll backwards", "");
if (*sc_addline == '\0')
{
/*
* Force repaint on any backward movement.
*/
back_scroll = 0;
}
}
/*
* Return the cost of displaying a termcap string.
* We use the trick of calling tputs, but as a char printing function
* we give it inc_costcount, which just increments "costcount".
* This tells us how many chars would be printed by using this string.
* {{ Couldn't we just use strlen? }}
*/
static int costcount;
/*ARGSUSED*/
static void
inc_costcount(c)
int c;
{
costcount++;
}
static int
cost(t)
char *t;
{
costcount = 0;
tputs(t, sc_height, inc_costcount);
return (costcount);
}
/*
* Return the "best" of the two given termcap strings.
* The best, if both exist, is the one with the lower
* cost (see cost() function).
*/
static char *
cheaper(t1, t2, doit, def)
char *t1, *t2;
char *doit;
char *def;
{
if (*t1 == '\0' && *t2 == '\0')
{
cannot(doit);
return (def);
}
if (*t1 == '\0')
return (t2);
if (*t2 == '\0')
return (t1);
if (cost(t1) < cost(t2))
return (t1);
return (t2);
}
/*
* Below are the functions which perform all the
* terminal-specific screen manipulation.
*/
/*
* Initialize terminal
*/
public void
init(void)
{
tputs(sc_init, sc_height, putchr);
init_done = 1;
}
/*
* Deinitialize terminal
*/
public void
deinit(void)
{
if (!init_done)
return;
tputs(sc_deinit, sc_height, putchr);
init_done = 0;
}
/*
* Home cursor (move to upper left corner of screen).
*/
public void
home(void)
{
tputs(sc_home, 1, putchr);
}
/*
* Add a blank line (called with cursor at home).
* Should scroll the display down.
*/
public void
add_line(void)
{
tputs(sc_addline, sc_height, putchr);
}
/*
* Move cursor to lower left corner of screen.
*/
public void
lower_left(void)
{
tputs(sc_lower_left, 1, putchr);
}
/*
* Ring the terminal bell.
*/
public void
bell(void)
{
if (quiet == VERY_QUIET)
vbell();
else
putchr('\7');
}
/*
* Output the "visual bell", if there is one.
*/
public void
vbell(void)
{
if (*sc_visual_bell == '\0')
return;
tputs(sc_visual_bell, sc_height, putchr);
}
/*
* Clear the screen.
*/
public void
clear(void)
{
tputs(sc_clear, sc_height, putchr);
}
/*
* Clear from the cursor to the end of the cursor's line.
* {{ This must not move the cursor. }}
*/
public void
clear_eol(void)
{
tputs(sc_eol_clear, 1, putchr);
}
/*
* Begin "standout" (bold, underline, or whatever).
*/
public void
so_enter(void)
{
tputs(sc_s_in, 1, putchr);
}
/*
* End "standout".
*/
public void
so_exit(void)
{
tputs(sc_s_out, 1, putchr);
}
/*
* Begin "underline" (hopefully real underlining,
* otherwise whatever the terminal provides).
*/
public void
ul_enter(void)
{
tputs(sc_u_in, 1, putchr);
}
/*
* End "underline".
*/
public void
ul_exit(void)
{
tputs(sc_u_out, 1, putchr);
}
/*
* Begin "bold"
*/
public void
bo_enter(void)
{
tputs(sc_b_in, 1, putchr);
}
/*
* End "bold".
*/
public void
bo_exit(void)
{
tputs(sc_b_out, 1, putchr);
}
/*
* Begin "blink"
*/
public void
bl_enter(void)
{
tputs(sc_bl_in, 1, putchr);
}
/*
* End "blink".
*/
public void
bl_exit(void)
{
tputs(sc_bl_out, 1, putchr);
}
/*
* Erase the character to the left of the cursor
* and move the cursor left.
*/
public void
backspace(void)
{
/*
* Try to erase the previous character by overstriking with a space.
*/
tputs(sc_backspace, 1, putchr);
putchr(' ');
tputs(sc_backspace, 1, putchr);
}
/*
* Output a plain backspace, without erasing the previous char.
*/
public void
putbs(void)
{
tputs(sc_backspace, 1, putchr);
}

360
bin/less/search.c Normal file
View File

@ -0,0 +1,360 @@
/*
* Routines to search a file for a pattern.
*/
#pragma noroot
#include <string.h>
#include "less.h"
#include "position.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
#if REGCOMP
#include <regexp.h>
#endif
extern int sigs;
extern int how_search;
extern int caseless;
extern int linenums;
extern int jump_sline;
/*
* Search for the n-th occurrence of a specified pattern,
* either forward or backward.
* Return the number of matches not yet found in this file
* (that is, n minus the number of matches found).
* Return -1 if the search should be aborted.
* Caller may continue the search in another file
* if less than n matches are found in this file.
*/
public int
search(search_type, pattern, n)
int search_type;
char *pattern;
int n;
{
POSITION pos, linepos, oldpos;
register char *p;
register char *q;
register int goforw;
register int want_match;
char *line;
int linenum;
int line_match;
static int is_caseless;
#if RECOMP
char *re_comp();
PARG parg;
#else
#if REGCMP
char *regcmp();
static char *cpattern = NULL;
#else
#if REGCOMP
static struct regexp *regpattern = NULL;
#else
static char lpbuf[100];
static char *last_pattern = NULL;
#endif
#endif
#endif
/*
* Extract flags and type of search.
*/
goforw = (SRCH_DIR(search_type) == SRCH_FORW);
want_match = !(search_type & SRCH_NOMATCH);
if (pattern != NULL && *pattern != '\0' && (is_caseless = caseless))
{
/*
* Search will ignore case, unless
* there are any uppercase letters in the pattern.
*/
for (p = pattern; *p != '\0'; p++)
if (*p >= 'A' && *p <= 'Z')
{
is_caseless = 0;
break;
}
}
#if RECOMP
/*
* (re_comp handles a null pattern internally,
* so there is no need to check for a null pattern here.)
*/
if ((parg.p_string = re_comp(pattern)) != NULL)
{
error("%s", &parg);
return (-1);
}
#else
#if REGCMP
if (pattern == NULL || *pattern == '\0')
{
/*
* A null pattern means use the previous pattern.
* The compiled previous pattern is in cpattern, so just use it.
*/
if (cpattern == NULL)
{
error("No previous regular expression", NULL_PARG);
return (-1);
}
} else
{
/*
* Otherwise compile the given pattern.
*/
char *s;
if ((s = regcmp(pattern, 0)) == NULL)
{
error("Invalid pattern", NULL_PARG);
return (-1);
}
if (cpattern != NULL)
free(cpattern);
cpattern = s;
}
#else
#if REGCOMP
if (pattern == NULL || *pattern == '\0')
{
/*
* A null pattern means use the previous pattern.
* The compiled previous pattern is in regpattern,
* so just use it.
*/
if (regpattern == NULL)
{
error("No previous regular expression", NULL_PARG);
return (-1);
}
} else
{
/*
* Otherwise compile the given pattern.
*/
struct regexp *s;
if ((s = regcomp(pattern)) == NULL)
{
error("Invalid pattern", NULL_PARG);
return (-1);
}
if (regpattern != NULL)
free(regpattern);
regpattern = s;
}
#else
if (pattern == NULL || *pattern == '\0')
{
/*
* Null pattern means use the previous pattern.
*/
if (last_pattern == NULL)
{
error("No previous regular expression", NULL_PARG);
return (-1);
}
pattern = last_pattern;
} else
{
strcpy(lpbuf, pattern);
last_pattern = lpbuf;
}
#endif
#endif
#endif
/*
* Figure out where to start the search.
*/
if (empty_screen())
{
/*
* Start at the beginning (or end) of the file.
* (The empty_screen() case is mainly for
* command line initiated searches;
* for example, "+/xyz" on the command line.)
*/
if (goforw)
pos = ch_zero();
else
{
pos = ch_length();
if (pos == NULL_POSITION)
pos = ch_zero();
}
} else
{
if (how_search)
{
if (goforw)
linenum = BOTTOM_PLUS_ONE;
else
linenum = TOP;
pos = position(linenum);
} else
{
linenum = adjsline(jump_sline);
pos = position(linenum);
if (goforw)
pos = forw_raw_line(pos, (char **)NULL);
}
}
if (pos == NULL_POSITION)
{
/*
* Can't find anyplace to start searching from.
*/
error("Nothing to search", NULL_PARG);
return (-1);
}
linenum = find_linenum(pos);
oldpos = pos;
for (;;)
{
/*
* Get lines until we find a matching one or
* until we hit end-of-file (or beginning-of-file
* if we're going backwards).
*/
if (sigs)
/*
* A signal aborts the search.
*/
return (-1);
if (goforw)
{
/*
* Read the next line, and save the
* starting position of that line in linepos.
*/
linepos = pos;
pos = forw_raw_line(pos, &line);
if (linenum != 0)
linenum++;
} else
{
/*
* Read the previous line and save the
* starting position of that line in linepos.
*/
pos = back_raw_line(pos, &line);
linepos = pos;
if (linenum != 0)
linenum--;
}
if (pos == NULL_POSITION)
{
/*
* We hit EOF/BOF without a match.
*/
return (n);
}
/*
* If we're using line numbers, we might as well
* remember the information we have now (the position
* and line number of the current line).
* Don't do it for every line because it slows down
* the search. Remember the line number only if
* we're "far" from the last place we remembered it.
*/
if (linenums && abs(pos - oldpos) > 1024)
{
add_lnum(linenum, pos);
oldpos = pos;
}
if (is_caseless)
{
/*
* If this is a caseless search, convert
* uppercase in the input line to lowercase.
* While we're at it, remove any backspaces
* along with the preceding char.
* This allows us to match text which is
* underlined or overstruck.
*/
for (p = q = line; *p != '\0'; p++, q++)
{
if (*p >= 'A' && *p <= 'Z')
/* Convert uppercase to lowercase. */
*q = *p + 'a' - 'A';
else if (q > line && *p == '\b')
/* Delete BS and preceding char. */
q -= 2;
else
/* Otherwise, just copy. */
*q = *p;
}
}
/*
* Test the next line to see if we have a match.
* This is done in a variety of ways, depending
* on what pattern matching functions are available.
*/
#if REGCMP
line_match = (regex(cpattern, line) != NULL);
#else
#if RECOMP
line_match = (re_exec(line) == 1);
#else
#if REGCOMP
line_match = regexec(regpattern, line);
#else
line_match = match(pattern, line);
#endif
#endif
#endif
/*
* We are successful if want_match and line_match are
* both true (want a match and got it),
* or both false (want a non-match and got it).
*/
if (((want_match && line_match) || (!want_match && !line_match)) &&
--n <= 0)
/*
* Found the line.
*/
break;
}
jump_loc(linepos, jump_sline);
return (0);
}
#if (!REGCMP) && (!RECOMP) && (!REGCOMP)
/*
* We have neither regcmp() nor re_comp().
* We use this function to do simple pattern matching.
* It supports no metacharacters like *, etc.
*/
static int match(char *pattern, char *buf);
static int
match(pattern, buf)
char *pattern, *buf;
{
register char *pp, *lp;
for ( ; *buf != '\0'; buf++)
{
for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
if (*pp == '\0' || *lp == '\0')
break;
if (*pp == '\0')
return (1);
}
return (0);
}
#endif

242
bin/less/signal.c Normal file
View File

@ -0,0 +1,242 @@
/*
* Routines dealing with signals.
*
* A signal usually merely causes a bit to be set in the "signals" word.
* At some convenient time, the mainline code checks to see if any
* signals need processing by calling psignal().
* If we happen to be reading from a file [in iread()] at the time
* the signal is received, we call intread to interrupt the iread.
*/
#pragma noroot
#include "less.h"
#include <signal.h>
#ifdef _ORCAC_
#pragma databank 1
segment "LoadSegONE";
#endif
/*
* "sigs" contains bits indicating signals which need to be processed.
*/
public int sigs;
#define S_INTERRUPT 01
#ifdef SIGTSTP
#define S_STOP 02
#endif
#if defined(SIGWINCH) || defined(SIGWIND)
#define S_WINCH 04
#endif
extern int sc_width, sc_height;
extern int swindow;
extern int screen_trashed;
extern int lnloop;
extern int linenums;
extern int scroll;
extern int reading;
static HANDLER u_interrupt(int type, int code);
static HANDLER stop(int type, int code);
/*
* Interrupt signal handler.
*/
/* ARGSUSED*/
static HANDLER
u_interrupt(type, code)
int type;
int code;
{
SIGNAL(SIGINT, u_interrupt);
sigs |= S_INTERRUPT;
if (reading)
intread();
}
public void
fake_interrupt(void)
{
sigs |= S_INTERRUPT;
}
#ifdef SIGTSTP
/*
* "Stop" (^Z) signal handler.
*/
/* ARGSUSED*/
static HANDLER
stop(type, code)
int type;
int code;
{
SIGNAL(SIGTSTP, stop);
sigs |= S_STOP;
if (reading)
intread();
}
#endif
#ifdef SIGWINCH
/*
* "Window" change handler
*/
/* ARGSUSED*/
public HANDLER
winch(type, code)
int type;
int code;
{
SIGNAL(SIGWINCH, winch);
sigs |= S_WINCH;
if (reading)
intread();
}
#else
#ifdef SIGWIND
/*
* "Window" change handler
*/
/* ARGSUSED*/
public HANDLER
winch(type)
int type;
{
SIGNAL(SIGWIND, winch);
sigs |= S_WINCH;
if (reading)
intread();
}
#endif
#endif
#ifdef __ORCAC__
#pragma databank 0
#endif
/*
* Set up the signal handlers.
*/
public void
init_signals(on)
int on;
{
if (on)
{
/*
* Set signal handlers.
*/
(void) SIGNAL(SIGINT, u_interrupt);
#ifdef SIGTSTP
(void) SIGNAL(SIGTSTP, stop);
#endif
#ifdef SIGWINCH
(void) SIGNAL(SIGWINCH, winch);
#else
#ifdef SIGWIND
(void) SIGNAL(SIGWIND, winch);
#endif
#endif
} else
{
/*
* Restore signals to defaults.
*/
(void) SIGNAL(SIGINT, SIG_DFL);
#ifdef SIGTSTP
(void) SIGNAL(SIGTSTP, SIG_DFL);
#endif
#ifdef SIGWINCH
(void) SIGNAL(SIGWINCH, SIG_IGN);
#endif
#ifdef SIGWIND
(void) SIGNAL(SIGWIND, SIG_IGN);
#endif
}
}
/*
* Process any signals we have received.
* A received signal cause a bit to be set in "sigs".
*/
public void
psignals(void)
{
register int tsignals;
if ((tsignals = sigs) == 0)
return;
sigs = 0;
#ifdef S_WINCH
if (tsignals & S_WINCH)
{
int old_width, old_height;
/*
* Re-execute get_term() to read the new window size.
*/
old_width = sc_width;
old_height = sc_height;
swindow = -1;
get_term();
if (sc_width != old_width || sc_height != old_height)
{
scroll = (sc_height + 1) / 2;
screen_trashed = 1;
}
}
#endif
#ifdef SIGTSTP
if (tsignals & S_STOP)
{
/*
* Clean up the terminal.
*/
#ifdef SIGTTOU
SIGNAL(SIGTTOU, SIG_IGN);
#endif
lower_left();
clear_eol();
deinit();
flush();
raw_mode(0);
#ifdef SIGTTOU
SIGNAL(SIGTTOU, SIG_DFL);
#endif
SIGNAL(SIGTSTP, SIG_DFL);
kill(getpid(), SIGTSTP);
/*
* ... Bye bye. ...
* Hopefully we'll be back later and resume here...
* Reset the terminal and arrange to repaint the
* screen when we get back to the main command loop.
*/
SIGNAL(SIGTSTP, stop);
raw_mode(1);
init();
screen_trashed = 1;
}
#endif
if (tsignals & S_INTERRUPT)
{
bell();
/*
* {{ You may wish to replace the bell() with
* error("Interrupt", NULL_PARG); }}
*/
/*
* If we were interrupted while in the "calculating
* line numbers" loop, turn off line numbers.
*/
if (lnloop)
{
lnloop = 0;
if (linenums == 2)
screen_trashed = 1;
linenums = 0;
error("Line numbers turned off", NULL_PARG);
}
}
}

179
bin/less/tags.c Normal file
View File

@ -0,0 +1,179 @@
#pragma noroot
#include <stdio.h>
#include "less.h"
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
#define WHITESP(c) ((c)==' ' || (c)=='\t')
#if TAGS
public char *tagfile;
public char *tagpattern;
public char *tags = "tags";
extern int linenums;
extern int sigs;
extern int jump_sline;
/*
* Find a tag in the "tags" file.
* Sets "tagfile" to the name of the file containing the tag,
* and "tagpattern" to the search pattern which should be used
* to find the tag.
*/
public void
findtag(tag)
register char *tag;
{
register char *p;
register FILE *f;
register int taglen;
int search_char;
static char tline[200];
if ((f = fopen(tags, "r")) == NULL)
{
error("No tags file", NULL_PARG);
tagfile = NULL;
return;
}
taglen = strlen(tag);
/*
* Search the tags file for the desired tag.
*/
while (fgets(tline, sizeof(tline), f) != NULL)
{
if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen]))
continue;
/*
* Found it.
* The line contains the tag, the filename and the
* pattern, separated by white space.
* The pattern is surrounded by a pair of identical
* search characters.
* Parse the line and extract these parts.
*/
tagfile = tagpattern = NULL;
/*
* Skip over the whitespace after the tag name.
*/
for (p = tline; !WHITESP(*p) && *p != '\0'; p++)
continue;
while (WHITESP(*p))
p++;
if (*p == '\0')
/* File name is missing! */
continue;
/*
* Save the file name.
* Skip over the whitespace after the file name.
*/
tagfile = p;
while (!WHITESP(*p) && *p != '\0')
p++;
*p++ = '\0';
while (WHITESP(*p))
p++;
if (*p == '\0')
/* Pattern is missing! */
continue;
/*
* Save the pattern.
* Skip to the end of the pattern.
* Delete the initial "^" and the final "$" from the pattern.
*/
search_char = *p++;
if (*p == '^')
p++;
tagpattern = p;
while (*p != search_char && *p != '\0')
p++;
if (p[-1] == '$')
p--;
*p = '\0';
fclose(f);
return;
}
fclose(f);
error("No such tag in tags file", NULL_PARG);
tagfile = NULL;
}
/*
* Search for a tag.
* This is a stripped-down version of search().
* We don't use search() for several reasons:
* - We don't want to blow away any search string we may have saved.
* - The various regular-expression functions (from different systems:
* regcmp vs. re_comp) behave differently in the presence of
* parentheses (which are almost always found in a tag).
*/
public int
tagsearch(void)
{
POSITION pos, linepos;
int linenum;
char *line;
pos = ch_zero();
linenum = find_linenum(pos);
for (;;)
{
/*
* Get lines until we find a matching one or
* until we hit end-of-file.
*/
if (sigs)
return (1);
/*
* Read the next line, and save the
* starting position of that line in linepos.
*/
linepos = pos;
pos = forw_raw_line(pos, &line);
if (linenum != 0)
linenum++;
if (pos == NULL_POSITION)
{
/*
* We hit EOF without a match.
*/
error("Tag not found", NULL_PARG);
return (1);
}
/*
* If we're using line numbers, we might as well
* remember the information we have now (the position
* and line number of the current line).
*/
if (linenums)
add_lnum(linenum, pos);
/*
* Test the line to see if we have a match.
* Use strncmp because the pattern may be
* truncated (in the tags file) if it is too long.
*/
if (strncmp(tagpattern, line, strlen(tagpattern)) == 0)
break;
}
jump_loc(linepos, jump_sline);
return (0);
}
#endif

41
bin/less/termcap Normal file
View File

@ -0,0 +1,41 @@
#
# GNO console
#
gno|gnocon|gno-console|GNO Console Driver:\
ae=^N:am:bl=^G:bs:bw:cl=^L:cm=^^%r%+ %+ :co#80:ce=^]:\
cd=^K:do=^J:eo:eA=^O^[:ho=^Y:il=^N:i3=^L:vi=^F:vs=^B^E:ve=^A^E:\
is=^L^N:kd=^J:kl=^H:kr=^U:ku=^_:le=^H:li#24:ll=^^ 8:mb=^O:md=^O:\
me=^N:mh=^O:mr=^O:nd=^U:nl=^J:pt:rs=^N:se=^N:so=^O:ta=^I:\
ue=^N:up=^_:us=^O:xn:ns:as=^O^[:bc=^H:r1=^N:r2=^N:r3=^N:\
ms:mi:sf=^W:sr=^V:i1=^N:NP:dn=^J:
#
# ProTerm Special
#
pt|pse|proterm-special|Proterm Special Emulation:\
ae=^N:am:al=^V:bl=^T^A^E@:bs:bw:cl=^L:cm=^^%r%+ %+ :co#80:ce=^Y:\
cd=^W:dc=^D:dl=^Z:do=^J:eo:eA=^P:ho=^X:ic=^F:il=^N:i3=^L:\
is=^L^N:kd=^J:kl=^H:kr=^U:ku=^K:le=^H:li#24:ll=^^ 8:mb=^O:md=^O:\
me=^N:mh=^O:mr=^O:nd=^U:nl=\n+^A:pt:rs=^N:se=^N:so=^O:ta=^I:\
ue=^N:up=^K:us=^O:xn:ns:as=^P:bc=^H:r1=^N:r2=^N:r3=^N:\
ms:mi:sf=^J:sr=^K:as=^P:i1=^N:i3=^N:NP:dn=^J:
#
# DEC VT-100
#
d0|vt100|vt100-am|vt100am|dec-vt100|dec vt100:\
:do=^J:co#80:li#24:cl=50\E[;H\E[2J:sf=2*\ED:\
:le=^H:bs:am:cm=5\E[%i%d;%dH:nd=2\E[C:up=2\E[A:\
:ce=3\E[K:cd=50\E[J:so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:\
:md=2\E[1m:mr=2\E[7m:mb=2\E[5m:me=2\E[m:is=\E[1;24r\E[24;1H:\
:rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:ks=\E[?1h\E=:ke=\E[?1l\E>:\
:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\
:ho=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=2*\EM:vt#3:xn:\
:sc=\E7:rc=\E8:cs=\E[%i%d;%dr:
#
# MS-DOS ANSI.SYS
#
P1|ansi.sys|ansisys|PC-DOS 3.1 ANSI.SYS:\
:am:bs:ce=\E[K:cl=\E[m\E[7h\E[2J:cm=\E[%i%d;%dH:co#80:\
:ku=^K:kd=^J:kl=^H:kr=^L:kh=^^:ma=^Hh\012j^Kk^Ll^^H:\
:ho=\E[H:li#25:nd=\E[C:up=\E[A:\
:ms:md=\E[1m:me=\E[m:mr=\E[7m:se=\E[m:so=\E[1m:ue=\E[m:us=\E[4m:\
:is=U1 PC-DOS 3.1 ANSI.SYS 9-23-86\n\E[m\E[7h:

86
bin/less/ttyin.c Normal file
View File

@ -0,0 +1,86 @@
/*
* Routines dealing with getting input from the keyboard (i.e. from the user).
*/
#pragma noroot
#include "less.h"
#include <fcntl.h>
#include <stdio.h>
#if __MSDOS__
#include <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#endif
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
static int tty;
/*
* Open keyboard for input.
*/
public void
open_getchr(void)
{
#if __MDDOS__
/*
* Open a new handle to CON: in binary mode
* for unbuffered keyboard read.
*/
tty = open("CON", O_RDONLY|O_BINARY);
#else
/*
* Try /dev/tty.
* If that doesn't work, use file descriptor 2,
* which in Unix is usually attached to the screen,
* but also usually lets you read from the keyboard.
*/
tty = open(".tty", O_RDWR);
if (tty < 0)
tty = 2;
#endif
}
/*
* Get a character from the keyboard.
*/
public int
getchr(void)
{
char c;
int result;
do
{
result = iread(tty, &c, sizeof(char));
if (result == READ_INTR)
return (READ_INTR);
if (result < 0)
{
/*
* Don't call error() here,
* because error calls getchr!
*/
quit(1);
}
#if __MSDOS__
/*
* In raw read, we don't see ^C so look here for it.
*/
if (c == '\003')
raise(SIGINT);
#endif
/*
* Various parts of the program cannot handle
* an input character of '\0'.
* If a '\0' was actually typed, convert it to '\200' here.
*/
if (c == '\0')
c = '\200';
} while (result != 1);
return (c);
}

320
bin/less/version.c Normal file
View File

@ -0,0 +1,320 @@
#pragma noroot
#include "less.h"
#ifdef _ORCAC_
segment " ";
#endif
/*
* less
* Copyright (c) 1984,1985,1989 Mark Nudelman
*
* This program may be freely used and/or modified,
* with the following provisions:
* 1. This notice and the above copyright notice must remain intact.
* 2. Neither this program, nor any modification of it,
* may be sold for profit without written consent of the author.
*
* ---------------------------------------------------------------
* | Special note to the person who ported "less" to the Amiga: |
* | If you're going to be vain enough to splash your name on |
* | the screen every time someone runs less, you might at |
* | least credit the author. |
* ---------------------------------------------------------------
*
* This program is a paginator similar to "more",
* but allows you to move both forward and backward in the file.
* Commands are based on "more" and "vi".
*
* ----------------------- CHANGES ---------------------------------
*
* Allowed use on standard input 1/29/84 markn
* Added E, N, P commands 2/1/84 markn
* Added '=' command, 'stop' signal handling 4/17/84 markn
* Added line folding 4/20/84 markn
* v2: Fixed '=' command to use BOTTOM_PLUS_ONE,
* instead of TOP, added 'p' & 'v' commands 4/27/84 markn
* v3: Added -m and -t options, '-' command 5/3/84 markn
* v4: Added LESS environment variable 5/3/84 markn
* v5: New comments, fixed '-' command slightly 5/3/84 markn
* v6: Added -Q, visual bell 5/15/84 markn
* v7: Fixed jump_back(n) bug: n should count real
* lines, not folded lines. Also allow number
* on G command. 5/24/84 markn
* v8: Re-do -q and -Q commands 5/30/84 markn
* v9: Added "+<cmd>" argument 9/25/84 markn
* v10: Fixed bug in -b<n> argument processing 10/10/84 markn
* v11: Made error() ring bell if \n not entered. 10/18/84 markn
* -----------------------------------------------------------------
* v12: Reorganized signal handling and made
* portable to 4.2bsd. 2/13/85 mark
* v13: Reword error message for '-' command. 2/16/85 mark
* v14: Added -bf and -bp variants of -b. 2/22/85 mark
* v15: Miscellaneous changes. 2/25/85 mark
* v16: Added -u flag for backspace processing. 3/13/85 mark
* v17: Added j and k commands,
* changed -t default. 4/13/85 mark
* v18: Rewrote signal handling code. 4/20/85 mark
* v19: Got rid of "verbose" eq_message(). 5/2/85 mark
* Made search() scroll in some cases.
* v20: Fixed screen.c ioctls for System V. 5/21/85 mark
* v21: Fixed some first_cmd bugs. 5/23/85 mark
* v22: Added support for no RECOMP nor REGCMP. 5/24/85 mark
* v23: Miscellanous changes and prettying up. 5/25/85 mark
* Posted to USENET.
* -----------------------------------------------------------------
* v24: Added ti,te terminal init & de-init 6/3/85 Mike Kersenbrock
* v25: Added -U flag, standout mode underlining. 6/8/85 mark
* v26: Added -M flag. 6/9/85 mark
* Use underline termcap (us) if it exists.
* v27: Renamed some variables to make unique in 6/15/85 mark
* 6 chars. Minor fix to -m.
* v28: Fixed right margin bug. 6/28/85 mark
* v29: Incorporated M.Rose's changes to signal.c 6/28/85 mark
* v30: Fixed stupid bug in argument processing. 6/29/85 mark
* v31: Added -p flag, changed repaint algorithm. 7/15/85 mark
* Added kludge for magic cookie terminals.
* v32: Added cat_file if output not a tty. 7/16/85 mark
* v33: Added -e flag and EDITOR. 7/23/85 mark
* v34: Added -s flag. 7/26/85 mark
* v35: Rewrote option handling; added option.c. 7/27/85 mark
* v36: Fixed -e flag to work if not last file. 7/29/85 mark
* v37: Added -x flag. 8/10/85 mark
* v38: Changed prompting; created prompt.c. 8/19/85 mark
* v39: (Not -p) does not initially clear screen. 8/24/85 mark
* v40: Added "skipping" indicator in forw(). 8/26/85 mark
* Posted to USENET.
* -----------------------------------------------------------------
* v41: ONLY_RETURN, control char commands, 9/17/85 mark
* faster search, other minor fixes.
* v42: Added ++ command line syntax; 9/25/85 mark
* ch_fsize for pipes.
* v43: Added -h flag, changed prim.c algorithms. 10/15/85 mark
* v44: Made END print in all cases of eof; 10/16/85 mark
* ignore SIGTTOU after receiving SIGTSTP.
* v45: Never print backspaces unless -u. 10/16/85 mark
* v46: Backwards scroll in jump_loc. 10/24/85 mark
* v47: Fixed bug in edit(): *first_cmd==0 10/30/85 mark
* v48: Use TIOCSETN instead of TIOCSETP. 11/16/85 mark
* Added marks (m and ' commands).
* Posted to USENET.
* -----------------------------------------------------------------
* v49: Fixed bug: signal didn't clear mcc. 1/9/86 mark
* v50: Added ' (quote) to gomark. 1/15/86 mark
* v51: Added + cmd, fixed problem if first_cmd
* fails, made g cmd sort of "work" on pipes
* even if bof is no longer buffered. 1/16/86 mark
* v52: Made short files work better. 1/17/86 mark
* v53: Added -P option. 1/20/86 mark
* v54: Changed help to use HELPFILE. 1/20/86 mark
* v55: Messages work better if not tty output. 1/23/86 mark
* v56: Added -l option. 1/24/86 mark
* v57: Fixed -l to get confirmation before
* overwriting an existing file. 1/31/86 mark
* v58: Added filename globbing. 8/28/86 mark
* v59: Fixed some bugs with very long filenames. 9/15/86 mark
* v60: Incorporated changes from Leith (Casey)
* Leedom for boldface and -z option. 9/26/86 mark
* v61: Got rid of annoying repaints after ! cmd. 9/26/86 mark
* Posted to USENET.
* -----------------------------------------------------------------
* v62: Added is_directory(); change -z default to
* -1 instead of 24; cat-and-exit if -e and
* file is less than a screenful. 12/23/86 mark
* v63: Fixed bug in cat-and-exit if > 1 file. 1/8/87 mark
* v64: Changed puts/putstr, putc/putchr,
* getc/getchr to avoid name conflict with
* stdio functions. 1/12/87 mark
* v65: Allowed '-' command to change NUMBER
* valued options (thanks to Gary Puckering) 1/26/87 mark
* v66: Fixed bug: prepaint should use force=1. 2/13/87 mark
* v67: Added !! and % expansion to ! command. 2/24/87 mark
* v68: Added SIGWINCH and TIOCGWINSZ support;
* changed is_directory to bad_file.
* (thanks to J. Robert Ward) 2/25/87 mark
* v69: Added SIGWIND and WIOCGETD (for Unix PC). 2/25/87 mark
* v70: Changed help cmd from 'h' to 'H'; better
* error msgs in bad_file, errno_message. 3/13/87 mark
* v71: Changed -p to -c, made triple -c/-C
* for clear-eol like more's -c. 5/11/87 mark
* v72: Added -E, -L, use $SHELL in lsystem(). 6/26/87 mark
* (thanks to Steve Spearman)
* v73: Allow Examine "#" for previous file. 6/26/87 mark
* Posted to USENET 8/25/87.
* -----------------------------------------------------------------
* v74: Fix conflict in EOF symbol with stdio.h, 9/18/87 mark
* Make os.c more portable to BSD.
* v75: Fix problems in get_term (thanks to 9/23/87 mark
* Paul Eggert); new backwards scrolling in
* jump_loc (thanks to Marion Hakanson).
* v76: Added -i flag; allow single "!" to 9/23/87 mark
* invoke a shell (thanks to Franco Barber).
* v77: Added -n flag and line number support. 9/24/87 mark
* v78: Fixed problem with prompts longer than 9/25/87 mark
* the screen width.
* v79: Added the _ command. 9/29/87 mark
* v80: Allow signal to break out of linenum scan. 10/6/87 mark
* v81: Allow -b to be changed from within less. 10/6/87 mark
* v82: Add cmd_decode to use a table for key 10/7/87 mark
* binding (thanks to David Nason).
* v83: Allow .less file for user-defined keys. 10/9/87 mark
* v84: Fix -e/-E problems (thanks to Felix Lee). 10/11/87 mark
* v85: Search now keeps track of line numbers. 10/15/87 mark
* v86: Added -B option and autobuf; fixed 10/20/87 mark
* "pipe error" bug.
* v87: Fix bug re BSD signals while reading file. 3/1/88 mark
* v88: Use new format for -P option (thanks to 3/12/88 mark
* der Mouse), allow "+-c" without message,
* fix bug re BSD hangup.
* v89: Turn off line numbers if linenum scan 3/18/88 mark
* is interrupted.
* v90: Allow -P from within less. 3/30/88 mark
* v91: Added tags file support (new -t option) 3/30/88 mark
* (thanks to Brian Campbell).
* v92: Added -+option syntax. 4/4/88 mark
* v93: Add support for slow input (thanks to 4/11/88 mark
* Joe Orost & apologies for taking almost
* 3 years to get this in!)
* v94: Redo reading/signal stuff. 4/11/88 mark
* v95: Repaint screen better after signal. 4/20/88 mark
* v96: Add /! and ?! commands. 4/21/88 mark
* v97: Allow -l/-L from within less. 5/17/88 mark
* Eliminate some static arrays (use calloc).
* Posted to USENET.
* -----------------------------------------------------------------
* v98: Fix incorrect calloc call; uninitialized 10/14/88 mark
* var in exec_mca; core dump on unknown TERM.
* Make v cmd work if past last line of file.
* Fix some signal bugs.
* v99: Allow space between -X and string, 10/29/88 mark
* when X is a string-valued option.
* v100: Fix globbing bug when $SHELL not set; 1/5/89 mark
* allow spaces after -t command.
* v101: Fix problem with long (truncated) lines 1/6/89 mark
* in tags file (thanks to Neil Dixon).
* v102: Fix bug with E# when no prev file; 1/6/89 mark
* allow spaces after -l command.
* v103: Add -N, -f and -? options. Add z and w 3/14/89 mark
* commands. Add %L for prompt strings.
* v104: Added EDITPROTO. 3/16/89 mark
* v105: Fix bug in find_linenum which cached 3/20/89 mark
* incorrectly on long lines.
* v106: Added -k option and multiple lesskey 3/31/89 mark
* files.
* v107: Add 8-bit char support and -g option. 4/27/89 mark
* Split option code into 3 files.
* v108: Allocate position table dynamically 5/5/89 mark
* (thanks to Paul Eggert); change % command
* from "percent" to vi-style brace finder.
* v109: Added ESC-% command, split prim.c. 5/10/89 mark
* v110: Fixed bug in + option; fixed repaint bug 5/24/89 mark
* under Sun windows (thanks to Paul Eggert).
* v111: Generalized # and % expansion; use 5/25/89 mark
* calloc for some error messages.
* v112: Get rid of ESC-%, add {}()[] commands. 5/30/89 mark
* v113: Optimize lseeks (thanks to Paul Eggert). 5/31/89 mark
* v114: Added ESC-/ and ESC-/! commands. 7/25/89 mark
* v115: Added ESC-n command. 7/26/89 mark
* v116: Added find_pos to optimize g command. 7/31/89 mark
* v117: Change -f option to -r. 8/1/89 mark
* v118: Save positions for all previous files, 8/2/89 mark
* not just the immediately previous one.
* v119: Save marks across file boundaries. 8/7/89 mark
* Add file handle stuff.
* v120: Add :ta command. 8/11/89 mark
* v121: Add -f option. 8/16/89 mark
* v122: Fix performance with many buffers. 8/30/89 mark
* v123: Verbose prompts for string options. 8/31/89 mark
* Posted beta to USENET.
* -----------------------------------------------------------------
* v124: Reorganize search commands, 9/18/89 mark
* N = rev, ESC-n = span, add ESC-N.
* v125: Fix tab bug (thanks to Alex Liu). 9/18/89 mark
* Fix EOF bug when both -w and -c.
* v126: Add -j option. 10/25/89 mark
* v127: Fix problems with blank lines before BOF. 10/27/89 mark
* v128: Add %bj, etc. to prompt strings. 10/27/89 mark
* v129: Add -+,-- commands; add set-option and 11/3/89 mark
* unset-option to lesskey.
* v130: Generalize A_EXTRA to string, remove 11/6/89 mark
* set-option, unset-option from lesskey.
* v131: Changed name of EDITPROTO to LESSEDIT. 11/7/89 mark
* v132: Allow editing of command prefix. 11/8/89 mark
* v133: Add -y option (thanks to Jeff Sullivan). 11/16/89 mark
* v134: Glob filenames in the -l command. 12/1/89 mark
* v135: Combined {}()[] commands into one, and 12/5/89 mark
* added ESC-^F and ESC-^B commands.
* v136: Added -S, -R flags. Added | command. 1/20/90 mark
* Added warning for binary files. (thanks
* to Richard Brittain and J. Sullivan).
* v137: Rewrote horrible pappend code. 1/21/90 mark
* Added * notation for hi-bit chars.
* v138: Fix magic cookie terminal handling. 1/24/90 mark
* Get rid of "cleanup" loop in ch_get.
* v139: Added MSDOS support. (many thanks 1/27/90 mark
* to Richard Brittain).
* v140: Editing a new file adds it to the 2/7/90 mark
* command line list.
* v141: Add edit_list for editing >1 file. 2/8/90 mark
* v142: Add :x command. 2/10/90 mark
* v143: Add * and @ modifies to search cmds. 2/11/90 mark
* Change ESC-/ cmd from /@* to / *.
* v144: Messed around with ch_zero; 3/1/90 mark
* no real change.
* v145: Added -R and -v/-V for MSDOS; 3/2/90 mark
* renamed FILENAME to avoid conflict.
* v146: Pull cmdbuf functions out of command.c 3/5/90 mark
* v147: Implement ?@; fix multi-file edit bugs. 3/7/90 mark
* v148: Fixed bug in :e<file> then :e#. 3/29/90 mark
* v149: Change error,ierror,query to use PARG. 4/3/90 mark
* v150: Add LESS_CHARSET, LESS_CHARDEF. 4/6/90 mark
* v151: Remove -g option; clean up ispipe. 4/13/90 mark
* v152: lsystem() closes input file, for 4/14/90 mark
* editors which require exclusive open.
* v153: Fix bug if SHELL unset; 4/18/90 mark
* fix bug in overstrike control char.
* v154: Output to fd 2 via buffer. 4/25/90 mark
* v155: Ignore -i if uppercase in pattern 4/30/90 mark
* (thanks to Michael Rendell.)
* v156: Remove scroll limits in forw() & back(); 5/3/90 mark
* causes problems with -c.
* v157: Forward search starts at next real line 5/4/90 mark
* (not screen line) after jump target.
* v158: Added F command. 6/14/90 mark
* v159: Fix bug in exiting: output not flushed. 7/29/90 mark
* v160: Clear screen before initial output w/ -c. 7/29/90 mark
* v161: Add -T flag. 7/29/90 mark
* v162: Fix bug with +F on command line. 8/14/90 mark
* v163: Added LESSBINFMT variable. 8/21/90 mark
* v164: Added -p, LINES, COLUMNS and 9/5/90 mark
* unset mark ' == BOF, for 1003.2 D5.
* v165: At EOF with -c set, don't display empty 9/6/90 mark
* screen when try to page forward.
* v166: Fix G when final line in file wraps. 9/6/90 mark
* v167: Translate CR/LF -> LF for 1003.2. 9/11/90 mark
* v168: Return to curr file if "tag not found". 9/13/90 mark
* v169: G goes to EOF even if file has grown. 12/12/90 mark
* v170: Add optimization for BSD _setjmp; 1/17/91 mark
* fix #include ioctl.h TERMIO problem.
* (thanks to Paul Eggert)
* Posted to USENET.
* -----------------------------------------------------------------
* v171: Fix -? bug in get_filename. 3/6/91 mark
* v172: Fix G bug in empty file. 3/15/91 mark
* Fix bug with ?\n and -i and uppercase
* pattern at EOF!
* (thanks to Paul Eggert)
* v173: Change N cmd to not permanently change 3/17/91 mark
* direction. (thanks to Brian Matthews)
* v174: Fix bug with namelogfile not getting 3/18/91 mark
* cleared when change files.
* v175: Fix bug with ++cmd on command line. 3/18/91 mark
* (thanks to Jim Meyering)
* v176: Change | to not force current screen, 4/2/91 mark
* include marked line, start/end from
* top of screen. Improve search speed.
* (thanks to Don Mears)
* v177: Add LESSHELP variable. 4/2/91 mark
* Fix bug with F command with -e.
* Try /dev/tty for input before using fd 2.
*/
char version[] = "@(#) less version 177";

8
bin/ls/Makefile Normal file
View File

@ -0,0 +1,8 @@
ls.root: ls.c
compile -i ls.c keep=ls
itqsort.a: itqsort.c
compile +O itqsort.c keep=itqsort
ls: ls.root itqsort.a
link ls itqsort keep=ls

156
bin/ls/itqsort.c Normal file
View File

@ -0,0 +1,156 @@
/* From: few@autodesk.com (Frank Whaley) */
/*
* qsort.c - iterative Quicksort
*/
#pragma noroot
#define DEPTH 20 /* should be adequate for most sorts */
static
swb(a, b, len)
register char *a;
register char *b;
register unsigned len;
{
register char temp;
/* Handle the odd-number case */
if (len & 1) {
temp = *a;
*a++ = *b;
*b++ = temp;
len--;
}
asm {
ldy len
loop: cpy #0
beq done
dey
dey
lda [a],y
tax
lda [b],y
sta [a],y
txa
sta [b],y
bra loop
done: }
/* while ( len-- )
{
temp = *a;
*a++ = *b;
*b++ = temp;
} */
}
int
nqsort(bas, n, wid, cmp)
char *bas; /* base of data */
unsigned n; /* number of items to sort */
unsigned wid; /* width of an element */
int (*cmp)(); /* key comparison function */
{
unsigned mumble;
unsigned j;
unsigned k;
unsigned pvt;
unsigned cnt;
unsigned lo[DEPTH];
unsigned hi[DEPTH];
if ( n < 2 )
return 0;
/* init */
cnt = 1;
lo[0] = 0;
hi[0] = n - 1;
while ( cnt-- )
{
pvt = lo[cnt];
j = pvt + 1;
n = k = hi[cnt];
while ( j < k )
{
while ( (j < k) &&
(*cmp)(bas + (j * wid), bas + (pvt * wid)) < 1 )
++j;
while ( (j <= k) &&
(*cmp)(bas + (pvt * wid), bas + (k * wid)) < 1)
--k;
if ( j < k )
swb(bas + (j++ * wid), bas + (k-- * wid), wid);
}
if ( (*cmp)(bas + (pvt * wid), bas + (k * wid)) > 0 )
swb(bas + (pvt * wid), bas + (k * wid), wid);
if ( k > pvt )
--k;
if ( (k > pvt) && (n > j) && ((k - pvt) < (n - j)) )
{
mumble = k;
k = n;
n = mumble;
mumble = pvt;
pvt = j;
j = mumble;
}
if ( k > pvt )
{
lo[cnt] = pvt;
hi[cnt++] = k;
}
if ( n > j )
{
lo[cnt] = j;
hi[cnt++] = n;
}
if ( cnt >= DEPTH )
return -1;
}
return 0;
}
/* END of qsort.c */
#if 0
short int in[] = {10, 32, -1, 567, 3, 18, 1, -51, 789, 0};
int compr(short *a, short *b)
{
if (*a < *b) return -1;
else if (*a > *b) return 1;
else return 0;
}
int compr1(short *a, short *b)
{
if (*a < *b) return 1;
else if (*a > *b) return -1;
else return 0;
}
int main()
{
unsigned i;
nqsort(in,10,2,compr1);
for (i = 0; i < 10; i++) printf("%d\n",in[i]);
nqsort(in,10,2,compr);
for (i = 0; i < 10; i++) printf("%d\n",in[i]);
}
#endif

586
bin/ls/ls.c Normal file
View File

@ -0,0 +1,586 @@
/*
* ls
*
* version 2.0
*
* Rewritten for speed, memory usage, and reliability
*
* now checks TERM var and displays MouseText folder only if set to gnocon
* does not apply name quicksort if files are on an HFS volume
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <gsos.h>
#include <unistd.h>
#include <misctool.h>
#pragma stacksize 1024
#pragma optimize -1
/*#pragma optimize 8*/
#define CALCULATE -1
#define ONLYONE -2
unsigned fl_all,fl_reverse;
unsigned fl_gnocon;
unsigned fl_sortname,fl_sortcreate,fl_sortmod;
unsigned firstflag;
struct directory {
ResultBuf32Ptr dir_name;
struct directory *parent;
unsigned fake;
word num_entries;
longword num_bytes;
word no_sort;
unsigned width;
DirEntryRecPtrGS *entry_ptrs;
DirEntryRecPtrGS entries;
};
DirEntryRecGS dirinfo;
ResultBuf32 nameb;
lsexit(int x_code)
{
SYSTEMQUITFLAGS(0x4000);
SYSTEMQUITPATH(NULL);
exit(x_code);
}
/*#define lsexit(x) exit(x)*/
#define qsort(a,b,c,d) nqsort(a,b,c,d)
extern void SortList(void *a, int c, int b, void *d);
void nqsort(void *,unsigned, unsigned,int (*cmp)(void *,void *));
void printGS(GSString255Ptr g)
{
fwrite(g->text,g->length,1,stdout);
}
typedef struct listStruct *list;
const char month[12][4] =
{ "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
typedef struct FileTypeConv {
word type;
char rep[10];
} FileTypeConv;
FileTypeConv FTTable[] = {
0x0f, "DIR ", /* directory */
0xB0, "src ", /* apw source file */
0xb1, "obj ", /* apw object file */
0x04, "txt ", /* ascii text file */
0xb3, "s16 ", /* gs/os program file */
0xb5, "exe ", /* gs/os shell program file */
0xb8, "nda ",
0xb9, "cda ",
0xba, "tol ",
0x00, "non ", /* typeless file */
0x01, "bad ", /* bad block file */
0x06, "bin ", /* general binary file */
0x08, "fot ", /* graphics screen file */
0x19, "adb ", /* appleworks data base file */
0x1a, "awp ", /* appleworks word processor file */
0x1b, "asp ", /* appleworks spreadsheet */
0xb2, "lib ", /* apw library file */
0xb4, "rtl ", /* apw runtime library */
0xef, "pas ", /* pascal partition */
0xf0, "cmd ",
0xfa, "int ", /* integer basic program */
0xfb, "var ", /* int basic var file */
0xfc, "bas ", /* applesloth basic file */
0xfd, "var ", /* applesloth variable file */
0xfe, "rel ", /* EDASM relocatable code */
0xff, "sys ", /* prodos 8 system program file */
-1, ""};
char conv[10];
char *getFileType(int type)
{
int i;
i = 0;
while (FTTable[i].type != -1)
{
if (FTTable[i].type == type)
{
return FTTable[i].rep;
}
else i++;
}
sprintf(conv,"$%2X ",type);
return conv;
}
word curYear;
void *sortRoutine;
int columns;
int openDirectory, fl_longOutput, inK;
int dirOnly, idType, fl_recursive, fl_nosort;
int more,less;
unsigned whichTime;
void printDirName(struct directory *d, unsigned level)
{
if (d == NULL) return;
else {
printDirName(d->parent,level+1);
if (d->dir_name != NULL) {
printGS((GSString255Ptr)&d->dir_name->bufString);
if (level) putchar('/');
}
}
if (!level) putchar(':');
}
void long_out(DirEntryRecGS *entry)
{
TimeRec *time;
if (whichTime) time = &entry->createDateTime;
else time = &entry->modDateTime;
printf("%c%c%c%c%c%c%c %04lX %4s %8ld",
(entry->fileType == 0x0f) ? 'd' :
((entry->flags & 0x8000) ? 'e' : '-'),
(entry->access & 0x01) ? 'r' : '-',
(entry->access & 0x02) ? 'w' : '-',
((entry->fileType == 0xff) || (entry->fileType == 0xb5) ||
(entry->fileType == 0xb3) ||
((entry->fileType == 0xb0) && (entry->auxType == 6l)))
? 'x' : '-',
(entry->access & 0x20) ? 'b' : '-',
(entry->access & 0x40) ? 'r' : '-',
(entry->access & 0x80) ? 'd' : '-',
entry->auxType,
getFileType(entry->fileType),
entry->eof+entry->resourceEOF);
if (time->year+1900 == curYear)
printf(" %3s %2d %02d:%02d ",
month[time->month],time->day+1,time->hour,time->minute);
else printf(" %3s %2d %4d ",month[time->month],time->day+1,
time->year+1900);
/*puts(entry->name->bufString.text);*/
}
/* fake a directory read for command-line arguments */
struct directory *fakeDirect(int argc, char **argv,struct directory *par)
{
struct directory *new;
unsigned i,file_count = 0,maxWidth = 0;
unsigned err;
DirEntryRecPtrGS newents,nptr;
FileInfoRecGS fi;
ResultBuf255Ptr newn;
extern GSString255Ptr __C2GSMALLOC(char *);
new = malloc(sizeof(struct directory));
new->num_entries = argc;
new->num_bytes = 0l;
new->parent = par;
new->dir_name = NULL;
new->no_sort = 0;
new->fake = 1;
if ((argc * sizeof(DirEntryRecGS)) > 60000)
printf("exceeded ORCA pointer math bug range\n");
newents = new->entries = malloc(argc * sizeof(DirEntryRecGS));
new->entry_ptrs = malloc(argc * sizeof(DirEntryRecGS *));
fi.pCount = 12;
fi.optionList = 0l;
nptr = newents;
for (i = 0; i < argc; i++) {
new->entry_ptrs[file_count] = nptr;
nptr->pCount = 17;
nptr->optionList = NULL;
fi.pathname = __C2GSMALLOC(argv[i]);
GetFileInfoGS(&fi);
if (err=_toolErr) {
fprintf(stderr,"ls: %s: %s\n",strerror(_mapErr(err)),argv[i]);
lsexit(1);
}
nptr->name = malloc(fi.pathname->length+5);
nptr->name->bufSize = fi.pathname->length+5;
memcpy(&nptr->name->bufString,fi.pathname, fi.pathname->length+2);
nptr->name->bufString.text[fi.pathname->length] = 0;
free(fi.pathname);
if (fi.storageType == 0x05) /* extended file? */
nptr->flags = 0x8000;
else nptr->flags = 0;
nptr->fileType = fi.fileType;
/* this is used by the qsort routine to maintain
command-line ordering for directories */
if (fi.fileType == 0x0F) nptr->entryNum = i;
nptr->auxType = fi.auxType;
nptr->eof = fi.eof;
nptr->blockCount = fi.blocksUsed;
nptr->createDateTime = fi.createDateTime;
nptr->modDateTime = fi.modDateTime;
nptr->access = fi.access;
nptr->resourceEOF = fi.resourceEOF;
nptr->resourceBlocks = fi.resourceBlocks;
file_count++;
new->num_bytes += (nptr->eof + nptr->resourceEOF);
if (nptr->name->bufString.length > maxWidth)
maxWidth = nptr->name->bufString.length;
/* NOTHING AFTER THIS LINE, PLEASE */
nptr = (DirEntryRecPtrGS) ((unsigned long) nptr + sizeof(DirEntryRecGS));
}
new->width = maxWidth;
new->num_entries = file_count;
return new;
}
struct directory *readDirect(int fd,struct directory *par, ResultBuf32Ptr n)
{
struct directory *new;
unsigned i,file_count = 0,maxWidth = 0;
DirEntryRecPtrGS newents,nptr;
ResultBuf255Ptr newn;
nameb.bufSize = 36;
dirinfo.pCount = 14;
dirinfo.refNum = fd;
dirinfo.base = dirinfo.displacement = 0;
dirinfo.name = (ResultBuf255Ptr) &nameb;
GetDirEntry(&dirinfo);
new = malloc(sizeof(struct directory));
new->num_entries = dirinfo.entryNum;
new->num_bytes = 0l;
new->parent = par;
new->dir_name = n;
new->fake = 0;
if (dirinfo.fileSysID == hfsFSID) new->no_sort = 1;
else new->no_sort = 0;
if ((dirinfo.entryNum * sizeof(DirEntryRecGS)) > 60000)
printf("exceeded ORCA pointer math bug range\n");
newents = new->entries = malloc(dirinfo.entryNum * sizeof(DirEntryRecGS));
new->entry_ptrs = malloc(dirinfo.entryNum * sizeof(DirEntryRecGS *));
nptr = newents;
for (i = 0; i < new->num_entries; i++) {
new->entry_ptrs[file_count] = nptr;
nptr->pCount = 17;
nptr->refNum = fd;
nptr->base = nptr->displacement = 1;
nptr->name = (ResultBuf255Ptr) &nameb;
nptr->optionList = NULL;
GetDirEntry(nptr);
if ((fl_all) || (!(nptr->access & fileInvisible))) {
file_count++;
newn = malloc(37);
nameb.bufString.text[nameb.bufString.length] = 0;
memcpy(newn,&nameb,36);
nptr->name = newn;
new->num_bytes += (nptr->eof + nptr->resourceEOF);
if (nptr->name->bufString.length > maxWidth)
maxWidth = nptr->name->bufString.length;
/* NOTHING AFTER THIS LINE, PLEASE */
nptr = (DirEntryRecPtrGS) ((unsigned long) nptr + sizeof(DirEntryRecGS));
}
}
new->width = maxWidth;
new->num_entries = file_count;
return new;
}
int sortByType(DirEntryRecGS **a,DirEntryRecGS **b)
{
unsigned ea,eb;
if ((*a)->fileType == 0x0F) {
if ((*b)->fileType == 0x0F) {
/* if both are dirs, maintain command-line ordering */
ea = (*a)->entryNum;
eb = (*b)->entryNum;
if (ea > eb) return 1;
else if (ea == eb) return 0;
else return -1;
}
else return 1;
} else {
if ((*b)->fileType == 0x0F) return -1;
}
}
int sortByName(DirEntryRecGS **a,DirEntryRecGS **b)
{
return strcmp((*a)->name->bufString.text,(*b)->name->bufString.text) * more;
}
int sortByCreate(DirEntryRecGS **a,DirEntryRecGS **b)
{
TimeRec *time1, *time2;
time1 = &((*a)->createDateTime);
time2 = &((*b)->createDateTime);
if (time1->year > time2->year) return less;
if (time1->year < time2->year) return more;
if (time1->month > time2->month) return less;
if (time1->month < time2->month) return more;
if (time1->day > time2->day) return less;
if (time1->day < time2->day) return more;
if (time1->hour > time2->hour) return less;
if (time1->hour < time2->hour) return more;
if (time1->minute > time2->minute) return less;
if (time1->minute < time2->minute) return more;
if (time1->second > time2->second) return less;
if (time1->second < time2->second) return more;
return 0;
}
int sortByMod(DirEntryRecGS **a,DirEntryRecGS **b)
{
TimeRec *time1, *time2;
time1 = &((*a)->modDateTime);
time2 = &((*b)->modDateTime);
if (time1->year > time2->year) return less;
if (time1->year < time2->year) return more;
if (time1->month > time2->month) return less;
if (time1->month < time2->month) return more;
if (time1->day > time2->day) return less;
if (time1->day < time2->day) return more;
if (time1->hour > time2->hour) return less;
if (time1->hour < time2->hour) return more;
if (time1->minute > time2->minute) return less;
if (time1->minute < time2->minute) return more;
if (time1->second > time2->second) return less;
if (time1->second < time2->second) return more;
return 0;
}
void listDir(struct directory *d)
{
unsigned i;
unsigned dirflag;
struct directory *dd;
int fd;
int Col,Row,Height;
int j, afile = FALSE, numColumns = 1;
unsigned rWidth,width;
unsigned fakeind;
unsigned num_entries;
char *cwd;
DirEntryRecGS *entry;
num_entries = d->num_entries;
if ((fl_longOutput) && (!d->fake))
printf("total %ldk\n",(d->num_bytes / 1024l));
if (!num_entries) return;
if (d->fake && openDirectory) {
/* sort by type first */
qsort(d->entry_ptrs, num_entries, sizeof(DirEntryRecGS *), sortByType);
num_entries = 0;
while ((num_entries < d->num_entries) &&
(d->entry_ptrs[num_entries]->fileType != 0x0F))
num_entries++;
/* finally, sort the non-directory files the way they wanted */
if (num_entries)
qsort(d->entry_ptrs, num_entries, sizeof(DirEntryRecGS *), sortRoutine);
} else
if ((!fl_nosort) && (!(d->no_sort && fl_sortname)))
qsort(d->entry_ptrs, num_entries, sizeof(DirEntryRecGS *),sortRoutine);
if (!fl_longOutput && columns == CALCULATE) {
rWidth = d->width;
width = rWidth;
if (inK) width+=5;
if (idType) width++;
if (width < 15) {
rWidth = 15 - (width - rWidth);
width = 15;
} /* for jawaid :-) */
numColumns = 80 / (++width);
}
Height = (num_entries / numColumns);
if (num_entries % numColumns) Height++;
for (Row=0; Row < Height; Row ++) {
for (Col = 0; Col < numColumns; Col ++) {
i = Col * Height + Row;
if (i >= num_entries) continue;
entry = d->entry_ptrs[i];
if (entry->fileType == 0x0F) dirflag = TRUE;
/*if (mult && entry->fileType == 0x0f) continue;*/
afile = TRUE;
if (inK) printf("%4ld ",((entry->eof+entry->resourceEOF)/1024)+1);
/* time = 0 means do mod date, = 1 means do create date */
/*time = (sortRoutine == CompareCreate) ? 1 : 0;*/
if (fl_longOutput) long_out(d->entry_ptrs[i]);
printGS(&entry->name->bufString);
if (idType) {
if (entry->fileType == 0x0f) putchar('/');
else if ((entry->fileType == 0xff) || (entry->fileType == 0xb5) ||
(entry->fileType == 0xb3) ||
((entry->fileType == 0xb0) && (entry->auxType == 6l)))
putchar('*');
else putchar(' ');
}
if (Col+1 < numColumns) {
for (j=0;j<(rWidth-(int)(entry->name->bufString.length));j++)
putchar(' ');
putchar(' ');
}
}
putchar('\n');
}
if ((dirflag && fl_recursive) || (d->fake && openDirectory)) {
unsigned start_ent = (d->fake ? num_entries : 0);
/* if there were regular files in a command-line list,
put a blank line in there but don't count as first */
if (d->fake && (num_entries != 0)) {
putchar('\n');
}
for (i = start_ent; i < d->num_entries; i++) {
if (d->entry_ptrs[i]->fileType == 0x0F) {
ResultBuf32Ptr p;
p = (ResultBuf32Ptr) d->entry_ptrs[i]->name;
/* let the danged kernel do some of the work! */
if (fl_recursive) {
cwd = malloc(1024l);
getwd(cwd);
chdir(p->bufString.text);
fd = open(".",O_RDONLY);
}
else fd = open(p->bufString.text,O_RDONLY);
if (fd <= 0) {
perror("could not open");
exit(1);
}
dd = readDirect(fd,d,p);
close(fd);
/* print the directory name for recursive listings */
if (!firstflag) firstflag = 1;
else putchar('\n');
printDirName(dd,0);
putchar('\n');
listDir(dd);
if (fl_recursive) {
chdir(cwd);
free(cwd);
}
/* DISPOSE of 'dd' at this point */
}
}
}
}
int main(int argc, char **argv)
{
int fd;
struct directory *dd;
TimeRec curtime;
int ch;
extern int getopt_restart(void);
getopt_restart();
curtime = ReadTimeHex();
curYear = curtime.year + 1900;
if (isatty(STDOUT_FILENO) && (!strncmp(ttyname(STDOUT_FILENO),".ttyco",6)))
strcpy(FTTable[0].rep,"\x1B\xFXY\xE\x18 ");
else strcpy(FTTable[0].rep,"DIR "); /* we restart, remember? */
/* initialize our restartable global variables */
fl_nosort = 0; fl_reverse = 0;
more = 1; less = -1;
sortRoutine = sortByName;
columns = CALCULATE;
openDirectory = TRUE;
fl_all = FALSE;
fl_longOutput = FALSE;
inK = FALSE;
dirOnly = FALSE;
idType = FALSE;
fl_recursive = FALSE;
whichTime = 0;
firstflag = 0;
while ((ch = getopt(argc, argv, "acdflnqrst1CFR")) != EOF) {
switch(ch) {
case 'n' :
fl_nosort = TRUE;
break;
case 'r' :
more = -1; less = 1;
break;
case 't' :
sortRoutine = sortByMod;
whichTime = 0;
break;
case 'c' :
sortRoutine = sortByCreate;
whichTime = 1;
break;
case '1' :
columns = ONLYONE;
break;
case 'C' :
columns = CALCULATE;
break;
case 'a' :
fl_all = TRUE;;
break;
case 'l' :
fl_longOutput = TRUE;
break;
case 's' :
inK = TRUE;
break;
case 'f' :
dirOnly = TRUE;
fl_longOutput = FALSE;
inK = FALSE;
fl_all = TRUE;
break;
case 'q' :
break;
case 'F' :
idType = TRUE;
break;
case 'R' :
fl_recursive = TRUE;
break;
case 'd' :
openDirectory = FALSE;
fl_recursive = FALSE;
break;
default:
(void)fprintf(stderr,
"usage: ls [-acdfilnqrstu1ACLFR] [name ...]\n");
lsexit(1);
}
}
argv += optind;
argc -= optind;
if (!argc) {
fd = open(".",O_RDONLY);
if (fd <= 0) {
perror("ls:");
exit(1);
}
dd = readDirect(fd,NULL,NULL);
close(fd);
listDir(dd);
} else { /* files as arguments */
/* add the args to a special list one by one with GetFileInfo */
dd = fakeDirect(argc, argv, NULL);
if (dd->num_entries) listDir(dd);
}
lsexit(0);
}

2
bin/make/build.make Executable file
View File

@ -0,0 +1,2 @@
compile -p make.cc keep=make
link make 2/direct256 keep=make

492
bin/make/make.c Normal file
View File

@ -0,0 +1,492 @@
#pragma stacksize 2048
#pragma debug 24
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <gsos.h>
#include <shell.h>
#include <orca.h>
#pragma lint -1
/* #define DEBUG_MODE */
#define version "Make - Version 1.1"
#define NAME_SIZE 80 /* max file name size */
#define MSG_SIZE 80 /* max size of any generated message */
#define PARAM_SIZE 256 /* max size of any input parameter */
#define d_flag 'D' /* display date/time info */
#define p_flag 'P' /* programmer (debug) mode */
#define s_flag 'S' /* silent mode */
#define target_delim ':' /* target file delimiters */
#define dep_delims " ," /* dependant file delimiters */
#define comment_char '#' /* start of comment */
/* System error return values */
#define BAD_OPTION 1
#define NO_INPUT_FILE 2
#define NO_MEM_AVAIL 3
#define SYNTAX_ERR 4
#define USER_ABORT 5
#define SHELL_ERR 6
#define EOF_ERR 7
#define ILLEGAL_FILE 8
#define MEM_UNAVAIL "Not enough memory available to execute."
typedef struct readVariableDCB {
Str255 *varName, *value;
} readVariableDCB;
typedef struct executeDCB {
int flag;
char *commandString;
} executeDCB;
/* Routine prototypes */
void ShowLastParam(void);
int GetInfo(FileInfoRecPtrGS file_info, int params, char *file_name);
int FileExists(char *);
void ErrorMessage(char *);
void ErrorAbort(char *, int);
int CheckDepFiles(char *dep_params, char *target_file);
int GetTargetFile(char *params, char *target);
int ExecuteMakeCommand(char *make_command, char *target_file);
enum MODES {PARAM, CONTINUATION, COMMAND, DONE};
unsigned char valid_types[] = { 0x04, 0xB0, 0 }; /* valid file types TXT, SRC */
FILE *make_file;
char msg[MSG_SIZE], make_param[PARAM_SIZE], prog_name[NAME_SIZE];
int silent, debugging, disp_date_time;
int main(int argc, char *argv[])
{
int i, type_ok;
enum MODES mode;
char *tmp_file, *make_file_name;
char first_char, *dep_params, *target_file;
FileInfoRecGS file_info;
StopPB stop_info;
/*
Initialize all global variables so that we can run as a re-startable
command in the shell environment.
*/
make_param[0] = '\0'; /* init to NULL string */
/*dep_params[0] = '\0';
target_file[0] = '\0'; */ /* NONONONONONONO */
msg[0] = '\0';
strcpy(prog_name, argv[0]); /* for error message processing */
silent = FALSE;
debugging = FALSE;
disp_date_time = FALSE;
/* Allocate some dynamic work variables */
if ( (make_file_name = malloc(NAME_SIZE)) == NULL )
ErrorAbort(MEM_UNAVAIL, NO_MEM_AVAIL);
if ( (dep_params = malloc(PARAM_SIZE)) == NULL )
ErrorAbort(MEM_UNAVAIL, NO_MEM_AVAIL);
if ( (target_file = malloc(NAME_SIZE)) == NULL )
ErrorAbort(MEM_UNAVAIL, NO_MEM_AVAIL);
*make_file_name = 0; /* this was a bug- jb */
/* Parse the command line information */
for (i = 1; i < argc; i++)
if ( argv[i][0] == '-' || argv[i][0] == '+' ) { /* command line option */
switch (toupper(argv[i][1])) {
case p_flag: debugging = TRUE; /* set appropriate flag */
break;
case s_flag: silent = TRUE;
break;
case d_flag: disp_date_time = TRUE;
break;
default: ErrorAbort("Invalid option specified.", BAD_OPTION);
}
}
else
strcpy(make_file_name, argv[i]); /* not an opt, must be a file */
if ( !silent )
puts(version); /* display version info */
if ( strlen(make_file_name) == 0 ) { /* did we get an input file name */
strcpy(make_file_name, "makefile");
/* fputs("MAKE file: ", stdout); /* nope, ask for one */
/* if ( gets(make_file_name) == NULL ) /* make sure we got one */
/* exit(NO_INPUT_FILE); /* if not, give up */
}
/*
Allocate some work variables:
tmp_file - will be used to check for a file with the default extention.
*/
if ( (tmp_file = malloc(NAME_SIZE)) == NULL )
exit(NO_MEM_AVAIL);
strcpy(tmp_file, make_file_name); /* get a copy of the specified name */
strcat(tmp_file, ".make"); /* default extention */
if ( FileExists(tmp_file) ) /* check for default name */
strcpy(make_file_name, tmp_file); /* got it */
else
if ( !FileExists(make_file_name) ) { /* nope check specified name */
sprintf(msg, "Make file %s does not exist.", make_file_name);
ErrorAbort(msg, NO_INPUT_FILE); /* still not there, give up */
}
free(tmp_file); /* done with this memory */
GetInfo(&file_info, 3, make_file_name); /* Check input file type */
type_ok = FALSE;
for ( i=0; i < sizeof(valid_types); i++ ) /* search valid types */
if ( file_info.fileType == valid_types[i] ) {
type_ok = TRUE;
break;
}
if ( !type_ok )
ErrorAbort("Input file must be either TXT or SRC.", ILLEGAL_FILE);
/* Open the input file */
if ( (make_file = fopen(make_file_name, "r")) == NULL ) {
perror(prog_name);
sprintf(msg, "Error opening input file %s.", make_file_name);
ErrorAbort(msg, NO_INPUT_FILE);
}
mode = PARAM; /* initial mode is parameter search */
/* Read the input file and process the make commands */
while ( fgets(make_param, sizeof(make_param), make_file) != NULL ) {
if ( (i = strpos(make_param, '\n')) >= 0 )
make_param[i] = '\0'; /* remove NL character */
if ( debugging )
printf("make_param:[%s] i: %d, mode: %d\n", make_param, i, mode);
first_char = make_param[0]; /* we will check this char often */
if ( (first_char == '\0') || (first_char == comment_char) ) {
mode = PARAM; /* blank line terminates COMMAND/CONTINUE mode */
continue; /* ignore blank lines & comment lines */
}
if ( mode == CONTINUATION ) { /* CheckDepFiles wants more params */
strcpy(dep_params, make_param); /* pre-load params */
mode = CheckDepFiles(dep_params, target_file);
}
else if ( first_char != ' ' ) {
mode = PARAM; /* back into param search mode */
strcpy(dep_params, make_param); /* set up for parsing */
if ( GetTargetFile(dep_params, target_file) ) /* we should find one */
mode = CheckDepFiles(dep_params, target_file);
else
ErrorAbort("Target file specification error, no ';' found.",SYNTAX_ERR);
}
else if ( mode == COMMAND )
mode = ExecuteMakeCommand(make_param, target_file);
STOP(&stop_info); /* Check for user termination */
if ( stop_info.stop == 1 )
ErrorAbort("User termination.", USER_ABORT);
} /* while reading parameters and not in DONE mode */
if ( mode == CONTINUATION )
ErrorAbort("Unexpected End-Of-File encountered after continuation.", EOF_ERR);
fclose(make_file);
exit(0);
}
void ErrorMessage(char *error_mesg)
{
printf("%s: %s\n", prog_name, error_mesg);
}
void ShowLastParam(void)
{
ErrorMessage("Error occured at:");
ErrorMessage(make_param);
}
void ErrorAbort(char *abort_mesg, int error_num)
{
ErrorPB error_params;
if ( (error_params.error = toolerror()) != 0 ) /* If a tool error */
ERROR(&error_params); /* Have the shell display the msg */
ErrorMessage(abort_mesg); /* Display my message */
if ( strlen(make_param) > 0 ) /* If param parsing */
ShowLastParam(); /* display the param */
exit(error_num);
}
GSString255Ptr strcpygs(GSString255Ptr gs_str, char *str)
{
gs_str->length = strlen(str);
strcpy((char *) gs_str->text, str);
return(gs_str);
}
int GetInfo(FileInfoRecPtrGS file_info, int params, char *file_name)
{
GSString255 file_info_name;
#ifdef DEBUG_MODE
puts("GetInfo");
#endif
file_info->pCount = params;
file_info->pathname = strcpygs(&file_info_name, file_name);
GetFileInfoGS(file_info);
return(toolerror());
}
int FileExists(char *file_name)
{
FileInfoRecGS file_info;
return(GetInfo(&file_info, 2, file_name) ? FALSE : TRUE);
}
void TrimLeft(char *str)
{
char *tmp;
tmp = str;
while ( *tmp == ' ' && *tmp != '\0' ) tmp++;
strcpy(str, tmp);
}
void TrimRight(char *str)
{
int tmp;
tmp = strlen(str);
while ( tmp >= 0 && str[tmp] == ' ') tmp--;
str[++tmp] = '\0';
}
int ExecuteMakeCommand(char *make_command, char *target_file)
{
char var_name[80], var_value[80];
Get_VarPB get_var;
executeDCB exec_params;
#ifdef DEBUG_MODE
puts("ExecuteMakeCommand()");
#endif
TrimLeft(make_command);
if ( !silent )
printf("\n%s\n\n", make_command);
make_command[strlen(make_command)+1] = '\0'; /* add an extra NULL */
exec_params.flag = 1; /* use existing variable table */
exec_params.commandString = make_command;
EXECUTE(&exec_params);
strcpy((char *) var_name, "\pStatus");
get_var.var_name = var_name;
get_var.value = var_value;
GET_VAR(&get_var);
if ( toolerror() != 0 )
ErrorAbort("Error occured during READ_VARIABLE.", SHELL_ERR);
var_value[var_value[0]+1] = '\0';
if ( debugging )
printf("var_name: %p = %p\n",var_name, var_value);
if ( strcmp((char *) var_value+1, "0") != 0 ) {
remove(target_file);
ErrorAbort("Error occurred during the last command.", SHELL_ERR);
} /* Status != "0" */
return COMMAND; /* remain in COMMAND mode */
}
int GetTargetFile(char *params, char *target)
{
int ch;
#ifdef DEBUG_MODE
puts("GetTargetFile()");
#endif
if ( (ch = strpos(params, target_delim)) == -1 )
return FALSE;
strncpy(target, params, ch);
target[ch] = '\0';
TrimLeft(target);
strcpy(params, &params[ch+1]);
if ( debugging )
printf("params: [%s] target: [%s]\n", params, target);
return TRUE;
}
void GetModDate(TimeRec *info, char *date)
{
sprintf(date, "%d/%02d/%02d", info->month+1, info->day+1, info->year);
}
void GetModTime(TimeRec *info, char *time)
{
sprintf(time, "%d:%02d:%02d", info->hour, info->minute, info->second);
}
int DepFileOlder(char *target_file, char *dep_file)
{
FileInfoRecGS target, dependant;
char mod_date[12];
#ifdef DEBUG_MODE
puts("DepFileOlder()");
printf("target_file:[%s] dep_file:[%s]\n", target_file, dep_file);
#endif
if ( GetInfo(&target, 7, target_file) != 0 ) {
ErrorMessage("target file does not exist.");
return TRUE; /* if any errors, assume target not found */
}
if ( debugging || disp_date_time ) { /* Diaplay mod date if in debug mode */
GetModDate(&target.modDateTime, mod_date);
printf("[Date]Target: %s = %s\n", target_file, mod_date);
}
if ( GetInfo(&dependant, 7, dep_file) != 0 ) {
ErrorMessage("dependant file does not exist.");
return FALSE; /* dependant file exist? No, user must be nuts */
}
if ( debugging || disp_date_time ) { /* Diaplay mod date if in debug mode */
GetModDate(&dependant.modDateTime, mod_date);
printf("[Date]Dependant: %s = %s\n", dep_file, mod_date);
}
/* Both the target file and the dependant file exists, check mod info */
if ( ( dependant.modDateTime.year == target.modDateTime.year ) &&
( dependant.modDateTime.month == target.modDateTime.month ) &&
( dependant.modDateTime.day == target.modDateTime.day ) ) { /* equal dates */
if ( debugging || disp_date_time ) { /* display debug info */
GetModTime(&target.modDateTime, mod_date);
printf("[Time]Target: %s = %s\n", target_file, mod_date);
GetModTime(&dependant.modDateTime, mod_date);
printf("[Time]Dependant: %s = %s\n", dep_file, mod_date);
}
/* check times */
if ( dependant.modDateTime.hour > target.modDateTime.hour )
return TRUE;
else if ( dependant.modDateTime.hour < target.modDateTime.hour )
return FALSE;
else if ( dependant.modDateTime.minute > target.modDateTime.minute)
return TRUE;
else if ( dependant.modDateTime.minute < target.modDateTime.minute)
return FALSE;
else if ( dependant.modDateTime.second > target.modDateTime.second)
return TRUE; /* dependant older */
else
return FALSE; /* target older */
} else /* unequal dates */
if ( dependant.modDateTime.year > target.modDateTime.year )
return TRUE;
else if ( dependant.modDateTime.year < target.modDateTime.year )
return FALSE;
else if ( dependant.modDateTime.month > target.modDateTime.month )
return TRUE;
else if ( dependant.modDateTime.month < target.modDateTime.month )
return FALSE;
else if ( dependant.modDateTime.day > target.modDateTime.day )
return TRUE; /* dependant is older */
else
return FALSE; /* target is older */
}
void FlushParams(void)
{
char *param_token;
int read_file = FALSE, flush_complete = FALSE;
#ifdef DEBUG_MODE
puts("FlushParams()");
#endif
do {
if ( read_file ) { /* handle continuation, read another line */
if ( fgets(make_param, sizeof(make_param), make_file) == NULL )
ErrorAbort("Unexpected End-Of-File encountered after continuation.", EOF_ERR);
param_token = strtok(make_param, dep_delims); /* init parser */
read_file = FALSE; /* reset read flag */
}
else
param_token = strtok(NULL, dep_delims); /* continue reading */
if ( debugging )
printf("param_token:[%s]\n", param_token);
if ( param_token == NULL || *param_token == comment_char ) /* done yet? */
flush_complete = TRUE; /* yes, signal end */
else if ( *param_token == '\\' ) /* continuation? */
read_file = TRUE; /* yes, read another line */
} while ( !flush_complete );
}
int CheckDepFiles(char *dep_params, char *target_file)
{
int first_file;
char *dep_file;
#ifdef DEBUG_MODE
puts("CheckDepFiles()");
printf("dep_params: [%s] target_file: [%s]\n",dep_params, target_file);
#endif
first_file = TRUE;
do { /* parse all dependant files from dep_params */
if ( first_file ) { /* first time through, init parser */
dep_file = strtok(dep_params, dep_delims); /* get 1st file name */
if ( dep_file == NULL ) /* there must be at least 1 file name */
ErrorAbort("No dependant files specified.", SYNTAX_ERR);
first_file = FALSE;
}
else /* all subsequent parsing is done from the previous params */
dep_file = strtok(NULL, dep_delims);
if ( dep_file == NULL ) /* any more parameters? */
return PARAM; /* nope, back to param search mode */
if ( debugging )
printf("dep_file:[%s]\n", dep_file);
if ( *dep_file == '\\' ) /* continuation? */
return CONTINUATION; /* yes, get the next line */
else if ( *dep_file == comment_char ) /* trailing comment? */
return PARAM; /* yes, skip all commands until next param */
else if ( *dep_file == '\0' ) /* Null string? */
continue; /* yes, look some more */
else if ( DepFileOlder(target_file, dep_file) ) {
FlushParams(); /* skip over any continuation stuff */
return COMMAND; /* dependant is older, rebuild target */
}
} while ( dep_file != NULL ); /* until no more dependant files */
return PARAM; /* return to param search mode */
}

82
bin/makemake/makemake.c Normal file
View File

@ -0,0 +1,82 @@
/*
* I got tired of making new makefiles for the IIgs make that's
* available, so here's a bloody program to write them for us
*
* To create the dependency lists, the source files are searched for
* the following information:
*
* .c #include "filename"
*
* Please note that this program isn't particularly smart.
*/
#pragma stacksize 2048
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int ndepend;
char dep[32][32]; /* 32 files, 32 characters long */
char line[1024];
char linenws[1024];
void removews(char *line, char *line2)
{
int n = strlen(line);
int i,j;
j = 0;
for (i = 0; i < n; i++)
if (!isspace(line[i])) line2[j++] = line[i];
line2[j] = 0;
}
finddepend(char *top, char *fname)
{
FILE *s;
char *p,*q;
int n;
printf("scanning '%s'",fname);
fflush(stdout);
s = fopen(fname,"r");
if (s == NULL) { fprintf(stderr,"Couldn't open %s\n",fname); exit(1); }
while (!feof(s)) {
fgets(line,1023,s);
n = strlen(line);
removews(line,linenws);
if (!strncmp(linenws,"#include",8)) {
putchar('.'); fflush(stdout);
if (p = strchr(line+8,'<')) continue;
p = strchr(line+8,'"');
if (p == NULL) continue;
q = strchr(p+1,'"');
strncpy(dep[ndepend],p+1,(q-p)-1);
dep[ndepend++][q-p-1] = 0;
finddepend(top,dep[ndepend-1]);
}
}
fclose(s);
putchar('\n');
}
int main(int argc, char *argv[])
{
FILE *f;
char nbuf[80];
int i,j;
f = fopen("makefile","w");
for (i = 1; i < argc; i++) {
strcpy(nbuf,argv[i]);
*strrchr(nbuf,'.') = 0;
ndepend = 0;
finddepend("#include",argv[i]);
fprintf(f,"o/%s.a: %s",nbuf,argv[i]);
for (j = 0; j < ndepend; j++)
fprintf(f," %s",dep[j]);
fprintf(f,"\n");
fprintf(f," compile %s keep=o/%s\n\n",argv[i],nbuf);
}
fclose(f);
}

7
bin/passwd/Makefile Normal file
View File

@ -0,0 +1,7 @@
passwd.a: passwd.cc
chtyp -l cc passwd.cc
compile +w passwd.cc keep=passwd
passwd: passwd.a
link passwd keep=passwd
setvers passwd \'GNO passwd^by Eric Shepherd\' v1.0.0

51
bin/passwd/passwd.1 Normal file
View File

@ -0,0 +1,51 @@
.\" @(#)passwd.1 1.00 93/07/01 EDS;
.TH PASSWD 1 "01 July 1993"
.SH NAME
passwd \- set a user's login password
.SH SYNOPSIS
.B passwd
[
.BI \-?
|
.BI \-v
] [
.BI username
]
.SH DESCRIPTION
.B passwd
changes the specified user's password. Only root is allowed to alter
passwords other than his own. If the
.IR username
is not given, the user's own login name is assumed. Users other than root
must then enter the old password to verify permission to change the password.
Finally, the user must type the desired new password twice to insure that no
mistakes are made.
.LP
To cancel
.B passwd
, type
.IR CTRL-@
when asked to enter the new password.
The
.B \-?
flag causes
.B passwd
to display a brief usage message, and the
.B \-v
flag causes
.B passwd
to display version information.
.SH SEE ALSO
.LP
.BR login "(1)"
.SH FILES
.B /etc/passwd
\- contains the password information
.SH AUTHOR
.LP
.nf
Eric Shepherd
Internet uerics@mcl.mcl.ucsb
AOL Sheppy
.fi

209
bin/passwd/passwd.c Normal file
View File

@ -0,0 +1,209 @@
/************************************************************
**
** passwd - change user passwords
**
** Programmed by: Eric Shepherd
** Date: September 6, 1993
**
** Requires GNO 2.0
**
**===========================================================
** Revision history:
**
** 1.0: Updated version numbers to final.
** 1.0b1: Changed the sleep(1) call to an asm { cop
** 0x7F };. Also removed the "conflict" error
** message. Instead, if the call to remove
** /etc/passwd fails, we sleep and retry until
** it succeeds, thus eliminating the problem...
** there's no significant reason why that file
** will stay open longer than a moment or two.
** 1.0a4: Now uses getpass(), since it's been fixed.
** 1.0a3: Adjusted closing code to shrink the window
** during which the system is vulnerable to
** becoming unprotected. Also added code to
** retry renaming passwd.new until it succeeds.
** 1.0a2: Optimized code, added optimize and stacksize
** pragmas, added new error message for the
** off chance that the rename could fail. Code
** size reduced by about 2K.
** 1.0a1: Works completely, except that getpass()
** crashes all the time, so I don't use it.
** Also, due to apparent login bug, sometimes
** the /etc/passwd file doesn't get updated --
** the corrected file is in /etc/passwd.new.
*************************************************************/
#pragma optimize -1
#pragma stacksize 512
#include <stdio.h>
#include <string.h>
#include <gno/gno.h>
#include <sys/types.h>
#include <getopt.h>
#include <pwd.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
extern char *crypt(char *key, char *salt);
extern char *getpass(char *prompt);
char entry[129];
static unsigned char salttab[] = /* table of chars. for salt */
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
void usage(void) {
fprintf(stderr, "usage: passwd [-v|?] [username]\n");
}
void makesalt(char *salt, long seed) {
int num = 2;
while (--num >= 0) {
*salt++ = salttab[seed&0x3f];
seed >= 6;
}
}
void main(int argc, char **argv) {
extern int optind;
int ch, uid, tries;
char password[9]; /* password string (8+\0) */
char *p, *t;
char salt[3];
FILE *passfile, *newpass; /* file /etc/newpasswd */
char *uname; /* pointer to username to change passwd of */
struct passwd *passwdRec;
while ((ch = getopt(argc, argv, "v?")) != EOF)
switch (ch) {
case 'v':
fprintf(stderr, "GNO passwd v1.0 by Eric Shepherd (September 6, 1993)\n");
exit(1);
case '?':
usage();
exit(1);
}
argc -= optind; /* move to next option */
argv += optind;
/* if no username supplied, use the current user's name */
uid = getuid(); /* get the user's ID */
switch(argc) {
case 1:
uname = argv[0];
if (!(passwdRec = getpwnam(uname))) {
fprintf(stderr, "Unknown user %s.\n", uname);
exit(1);
}
/* the following code verifies that the user only tries to
change his own password, unless he is superuser */
if (uid && uid != passwdRec->pw_uid) {
fprintf(stderr, "You can't change other users' passwords.\n");
exit(1);
}
break;
case 0:
passwdRec = getpwuid(uid);
break;
default:
usage();
exit(1);
}
uname = passwdRec->pw_name; /* make sure we have the right one */
/* Here's the code to handle changing passwords */
printf("Changing password for user %s.\n", uname);
if (uid && strlen(passwdRec->pw_passwd) &&
strcmp(crypt(getpass("Old password:"), passwdRec->pw_passwd),
passwdRec->pw_passwd)) {
fprintf(stderr,"Password incorrect.\n");
exit(1);
}
for (password[0] = '\0', tries = 0;;) {
p = getpass("New password:");
if (!*p) {
printf("Password unchanged.\n");
exit(0);
}
if (strlen(p) <= 5 && (uid != 0 || ++tries < 2)) {
printf("Please enter a longer password.\n");
continue;
}
/* Let only root assign easy passwords */
for (t = p; *t && islower(*t); ++t);
if (!*t && (uid != 0 || ++tries < 2)) {
printf("All-lower-case passwords can be easy to break. Please use unusual\ncapitalization, control characters, and digits.\n");
continue;
}
strcpy(password, p); /* snag a copy of the password */
if (!strcmp(password, getpass("Retype new password:")))
break; /* ah! got it! */
printf("That's not what you typed the first time. Please start over, or\nhit CTRL-@ to quit.\n");
}
/* create salt randomly after seeding the random number generator */
srand((int) time((time_t *) NULL));
makesalt(&salt[0], rand());
/* Copy /etc/passwd to /etc/passwd.new, line-by-line, skipping
the entry for the user whose password is changing -- insert
the new entry instead. */
if (!(passfile = fopen("/etc/passwd", "r"))) {
fprintf(stderr, "Unable to open /etc/passwd.\n");
exit(1);
}
if (!(newpass = fopen("/etc/passwd.new", "w"))) {
fclose(passfile); /* it's already open, so close it -- unlike login :) */
fprintf(stderr, "Unable to write new /etc/passwd.\n");
exit(1);
}
while (!feof(passfile)) {
if (strncmp(passwdRec->pw_name, fgets(entry, 129, passfile),
strlen(passwdRec->pw_name)))
fputs(entry, newpass); /* not us -- just copy it */
else
fprintf(newpass, "%s:%s:%d:%d:%s:%s:%s\n", passwdRec->pw_name,
crypt(password, salt), passwdRec->pw_uid, passwdRec->pw_gid,
passwdRec->pw_comment, passwdRec->pw_dir, passwdRec->pw_shell);
}
fclose(passfile);
asm { cop 0x7F }; /* Jawaid sez this is better than sleep(1) */
/* Erase the old file and rename the new one */
while (remove("/etc/passwd"))
sleep(1); /* Keep trying */
fclose(newpass); /* NOW close the new file */
/* As long as the rename fails, wait a moment, then try again */
while (rename("/etc/passwd.new", "/etc/passwd"))
sleep(1); /* sleep one second before trying again */
}

46
bin/ps/ps.1 Normal file
View File

@ -0,0 +1,46 @@
.TH EPS 1
.SH NAME
.LP
.B eps
\- display extensive process status information.
.SH SYNOPSIS
.LP
.BR eps " -anlwt <" tty "> u < " user " >"
.SH DESCRIPTION
.LP
.BR eps " is an extended " ps " command which displays more"
information than the gsh builtin
.BR ps ". "
.SH USAGE
.LP
.nf
.BR \-a " : Show all processes; normally " eps " limits the processes"
displayed to those that are owned by the current user.
.sp
.BR \-n " : Show username instead of userID, which is default."
.sp
.BR \-l " : Long list. This includes PPID (parent's PID), MMID"
(Memory Manager ID) and a longer time field.
.sp
.BR \-w " : Wider list. A single w results in a 132 column wide"
listing, and two results in the whole command line being
displayed. Normally the command line will be truncated
to either 80 (default) or 132 (-w) columns.
.sp
.BR \-t " <" tty "> : Display only those processes that are owned by " tty "."
.sp
.BR \-u " <" user "> : Display only those processes that are owned by " user "."
.fi
.SH SEE ALSO
.LP
.nf
.BR ps "(1)"
.BR parent "(1)"
.fi
.SH AUTHOR
.LP
.nf
James Brookes
bb252@cleveland.freenet.edu
jamesb@cscihp.ecst.csuchico.edu
.fi

350
bin/ps/ps.c Normal file
View File

@ -0,0 +1,350 @@
/* */
/* extended ps v1.0 for GNO/ME v1.1 */
/* */
/* 6/17/93 -- initial coding, this version does everything gsh's 'ps' */
/* and also shows the Parent's PID, as well as giving a */
/* larger time field. -u, -e and -n options implemented */
/* */
/* 6/18/93 -- fixed time calculations, which were off for minutes and */
/* hours by a power of 10. */
/* */
/* 6/20/93 -- added 'sleeping' category to process state listing. */
/* */
/* 6/22/93 -- fixed display for forked child */
/* added -t option flag */
/* added rexit() call, and getopt_restart() */
/* */
/* 6/23/93 -- fixed -t option to work with ttyID of 00 */
/* */
/* 6/26/93 -- fixed miscellaneous problems with memory allocation */
/* */
/* 6/27/93 -- added -w, -ww, -l flags. */
/* */
/* Author: James Brookes */
/* jamesb@cscihp.ecst.csuchico.edu */
/* */
#pragma optimize -1
#pragma stacksize 512
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <misctool.h>
#include <limits.h>
#include <gno/kvm.h>
#include <getopt.h>
#define FALSE 0
#define TRUE 1
void print_time(long ticks);
int getuid(void);
char *ttyname(int fd);
extern int getopt_restart(void);
/* boolean global options */
int username; /* username to show */
int allprocs; /* show all processes */
int showname; /* show username */
int tty; /* tty to show */
int showtty; /* show only ttyID */
int w_counter; /* width option */
int long_list; /* long listing */
static char *status[] = { "unused", "running", "ready", "blocked", "new",
"suspended", "wait", "waitsigch", "paused",
"sleeping", "unknown" };
void usage(char *callname)
{
fprintf(stderr,"usage: %s -anlwt <tty> u <username>\n",callname);
rexit(0);
}
/* Process option flags */
void getopts(int argc, char **argv)
{
int c, username_select, tty_select;
struct passwd *pw_s;
username_select = FALSE;
tty_select = FALSE;
pw_s = (struct passwd *) malloc (sizeof(struct passwd));
username = getuid();
allprocs = FALSE;
showname = FALSE;
showtty = FALSE;
long_list = FALSE;
w_counter = 0;
if (argc == 1)
return;
while((c = getopt(argc,argv,"anwlt:u:")) != EOF)
{
switch((unsigned char)c)
{
case 'a':
allprocs = TRUE;
break;
case 'n':
showname = TRUE;
break;
case 't':
tty_select = TRUE;
showtty = TRUE;
tty = atoi(optarg);
break;
case 'u':
username_select = TRUE;
pw_s = getpwnam(optarg);
username = pw_s->pw_uid;
break;
case 'w':
w_counter++;
break;
case 'l':
long_list = TRUE;
break;
default:
usage(argv[0]);
}
}
if ((allprocs) && ((username_select) || (tty_select)))
usage(argv[0]);
}
void print_time(long ticks)
{
int secs, mins, hous, days, shortmins;
secs = (ticks/60) % 60;
mins = (ticks/3600) % 60;
hous = (ticks/216000) % 24;
days = (ticks/5184000) % 365;
if (!long_list)
shortmins = (ticks/3600) % 999;
if (long_list)
{
if (hous)
printf("%2d:",hous);
else
printf(" ");
printf("%02d:",mins);
printf("%02d ",secs);
}
else
{
printf("%03d:",shortmins);
printf("%02d ",secs);
}
}
int main(int argc, char **argv)
{
kvmt *proc_kvm;
struct pentry *proc_entry;
struct passwd *pw_s;
int i, pstate, p_uid, columns, num_chars;
char **name;
getopt_restart();
getopts(argc,argv); /* process command line options */
if (w_counter == 0) /* w option - width of screen */
w_counter = 80;
else if (w_counter == 1)
w_counter = 132;
else
w_counter = INT_MAX;
name = calloc (1024l,sizeof (char *)); /* up to 1024 usernames */
pw_s = (struct passwd *) malloc (sizeof(struct passwd));
proc_kvm = kvm_open();
/* Print header */
printf(" ID");
columns += 5;
if (long_list)
{
printf(" PPID");
columns += 6;
}
printf(" STATE TT");
columns += 13;
if (long_list)
{
printf(" MMID");
columns += 5;
}
printf(" USER");
columns+=5;
if (showname)
{
if (long_list)
{
printf(" ");
columns += 10;
}
else
{
printf(" ");
columns += 7;
}
}
else /* !showname */
{
if (long_list)
{
printf(" ");
columns += 5;
}
else
{
printf(" ");
columns += 3;
}
}
printf("TIME COMMAND\n");
columns+=6;
do /* while proc_entry != NULL */
{
i = 0;
proc_entry = kvmnextproc(proc_kvm); /* get next proc entry */
if (proc_entry == NULL) /* no more processes */
continue;
p_uid = proc_entry->p_uid;
if ((tty != proc_entry->ttyID) && (showtty));
else if ((username == p_uid) || (allprocs) || (showtty))
{
printf("%5d ",proc_kvm->pid); /* pid */
if (long_list)
printf("%5d ",proc_entry->parentpid); /* pid of parent process */
/* if processState is screwed, call it 'unknown' */
if ((proc_entry->processState < 0) || (proc_entry->processState > 9))
pstate = 10;
else
pstate = proc_entry->processState;
printf("%-9s ",status[pstate]); /* process state */
if (proc_entry->ttyID == 3) /* ttyID */
printf("co "); /* console */
else
printf("%02d ",proc_entry->ttyID);
if (long_list)
printf("%4X ",proc_entry->userID); /* MMID */
if (showname) /* -n */
{
if (name[p_uid] == NULL)
{
pw_s = getpwuid(p_uid); /* username */
name[p_uid] = (char *) malloc (strlen(pw_s->pw_name) + 1);
strcpy(name[p_uid],pw_s->pw_name);
}
printf("%-8s ",name[p_uid]);
}
else /* default--no name, just id */
printf("%04d ",p_uid);
print_time(proc_entry->ticks); /* time process has run */
num_chars = (w_counter - columns) + 5;
for (i = 8; i < num_chars; i++) /* commandline */
{
if (proc_entry->args == NULL)
{
printf("forked child of process %d",proc_entry->parentpid);
break;
}
else if (proc_entry->args[i] == '\0')
break;
else
putchar(proc_entry->args[i]);
}
if (i == num_chars)
printf("...");
printf("\n");
}
}
while(proc_entry != NULL); /* handle all proc entries */
kvm_close(proc_kvm);
free(pw_s);
rexit(0);
}

206
bin/purge/purge.asm Normal file
View File

@ -0,0 +1,206 @@
**************************************************************************
*
* GNO Purge 3.0
*
* Written by Tim Meekins, Procyon, Inc.
* Based on code originally written by Mike Westerfield.
*
* This program is public domain. enjoy it.
*
* Parts of this program are dependent on GNOlib and the ByteWorks SYSlib.
*
**************************************************************************
keep purge
mcopy purge.mac
Purge START
handle equ 0
location equ 0
nextHandle equ 4
argv equ 8
argc equ 12
verbosity equ 14
arg equ 16
;
; memory manager record
;
attributes equ 4
userID equ 6
length equ 8
last equ 12
next equ 16
phk
plb
sta ~USER_ID
sty commandline
stx commandline+2
stz verbosity
jsl ~MM_INIT
ph4 commandline
clc
tdc
adc #argv
pea 0
pha
jsl GNO_PARSEARG
sta argc
dec a
beq start
dec a
beq doopt
showusage WriteCString #Usage
jmp done
doopt ldy #4
lda [argv],y
sta arg
iny2
lda [argv],y
sta arg+2
lda [arg]
and #$FF
cmp #'-'
bne showusage
ldy #1
lda [arg],y
cmp #'v' ;the 0 too..
bne doopt
inc verbosity
start FreeMem before
FindHandle #Purge,handle
lb1 ldy #last
lda [handle],y
tax
iny2
ora [handle],y
beq lb1a
lda [handle],y
sta handle+2
stx handle
bra lb1
lb1a lda verbosity
beq lb2
WriteCString #msg1
lb2 ora2 handle,handle+2,@a
jeq lb4
ldy #next
lda [handle],y
sta nextHandle
iny2
lda [handle],y
sta nextHandle+2
ldy #attributes
lda [handle],y
jmi lb3
and #$0300
jeq lb3
lda verbosity
jeq dopurge
WriteChar #'$'
ldx handle+2
lda handle
jsr PrintHex4
WriteString #msg2
ldy #2
lda [handle],y
tax
lda [handle]
jsr PrintHex4
WriteString #msg2
ldy #attributes
lda [handle],y
jsr PrintHex2
WriteString #msg2
ldy #userID
lda [handle],y
jsr PrintHex2
WriteString #msg2
ldy #length+2
lda [handle],y
tax
dey2
lda [handle],y
jsr PrintHex4
WriteChar #' '
stz ref
apploop ldy #userID
lda [handle],y
and #%1111000011111111
LGetPathname (@a,ref),@yx
if2 @a,eq,#0,appput
inc ref
if2 ref,cc,#128,apploop
bra oops
appput WriteString @xy
oops WriteLine #empty
dopurge PurgeHandle handle
lb3 mv4 nextHandle,handle
jmp lb2
lb4 CompactMem
TotalMem @yx
NewHandle (@xy,~USER_ID,#$0000,#0),handle
ora2 handle,handle+2,@a
beq showstat
DisposeHandle handle
showstat lda verbosity
beq Done
FreeMem After
WriteCString #beforestr
ldx before+2
lda before
jsr PrintHex4
WriteCString #leftstr
WriteCString #afterstr
ldx after+2
lda after
jsr PrintHex4
WriteCString #leftstr
Done lda #0
rtl
empty str ''
ref ds 2
commandline ds 4
before ds 4
after ds 4
msg1 dc c'GNO Purge 3.0',h'0d0a0a'
dc c'Handle Ptr Attr User Length App',h'0d0a00'
msg2 str ' $'
Usage dc c'Usage: purge [-v]',h'0d0a00'
beforestr dc h'0d0a',c'Before: $',h'00'
afterstr dc c'After: $',h'00'
leftstr dc c' bytes free',h'0d0a00'
PrintHex1 Int2Hex (@a,#hex1str+1,#2)
WriteString #hex1str
rts
hex1str str '00'
PrintHex4 pha
txa
jsr PrintHex1
pla
PrintHex2 Int2Hex (@a,#hex2str+1,#4)
WriteString #hex2str
rts
hex2str str '0000'
END

361
bin/purge/purge.mac Normal file
View File

@ -0,0 +1,361 @@
MACRO
&lab LGetPathname &a1,&a2
&lab pha
pha
ph2 &a1(1)
ph2 &a1(2)
Tool $1111
pl4 &a2
mend
MACRO
&lab WriteChar &a1
&lab ph2 &a1
Tool $180c
mend
MACRO
&lab WriteLine &a1
&lab ph4 &a1
Tool $1a0c
mend
MACRO
&lab WriteString &a1
&lab ph4 &a1
Tool $1c0c
mend
MACRO
&lab Int2Hex &a1
&lab ph2 &a1(1)
ph4 &a1(2)
ph2 &a1(3)
Tool $220b
mend
MACRO
&lab tool &a1
&lab ldx #&a1
jsl $e10000
mend
MACRO
&lab ph2 &parm
lclc &char
&lab anop
aif c:&parm=0,.done
&char amid &parm,1,1
aif "&char"="#",.immediate
aif "&char"="@",.at
aif s:longa=1,.chk
rep #%00100000
.chk
aif "&char"<>"{",.absolute
&char amid &parm,l:&parm,1
aif "&char"<>"}",.error
&parm amid &parm,2,l:&parm-2
lda (&parm)
pha
ago .shorten
.absolute
lda &parm
pha
ago .shorten
.immediate
&parm amid &parm,2,l:&parm-1
pea &parm
ago .done
.at
&char amid &parm,2,1
ph&char
.shorten
aif s:longa=1,.done
sep #%00100000
.done
mexit
.error
mnote "Missing closing '}'",16
mend
MACRO
&lab ph4 &parm
lclc &char
lclc &char1
lclc &char2
&lab anop
&char amid &parm,1,1
aif "&char"="#",.immediate
aif "&char"="@",.at
aif s:longa=1,.chk1
rep #%00100000
.chk1
aif "&char"<>"{",.chk2
&char amid &parm,l:&parm,1
aif "&char"<>"}",.error
&parm amid &parm,2,l:&parm-2
ldy #2
lda (&parm),y
pha
lda (&parm)
pha
ago .shorten
.chk2
aif "&char"<>"[",.absolute
ldy #2
lda &parm,y
pha
lda &parm
pha
ago .shorten
.absolute
lda &parm+2
pha
lda &parm
pha
ago .shorten
.at
&char1 amid &parm,2,1
&char2 setc &char1
ph&char1
aif l:&parm<3,.chk2a
&char2 amid &parm,3,1
.chk2a
ph&char2
ago .shorten
.immediate
&parm amid &parm,2,l:&parm-1
pea +(&parm)|-16
pea &parm
ago .done
.shorten
aif s:longa=1,.done
sep #%00100000
.done
mexit
.error
mnote "Missing closing '}'",16
mend
MACRO
&lab pl4 &parm
lclc &char
lclc &char1
lclc &char2
&lab anop
aif s:longa=1,.start
rep #%00100000
.start
&char amid &parm,1,1
aif "&char"<>"{",.chk
&char amid &parm,l:&parm,1
aif "&char"<>"}",.error
&parm amid &parm,2,l:&parm-2
pla
sta (&parm)
ldy #2
pla
sta (&parm),y
ago .shorten
.chk
aif "&char"<>"[",.chk2
pla
sta &parm
ldy #2
pla
sta &parm,y
ago .shorten
.chk2
aif "&char"<>"@",.absolute
&char1 amid &parm,2,1
&char2 setc &char1
pl&char1
aif l:&parm<3,.chk2a
&char2 amid &parm,3,1
.chk2a
pl&char2
ago .shorten
.absolute
pla
sta &parm
pla
sta &parm+2
.shorten
aif s:longa=1,.done
sep #%00100000
.done
mexit
.error
mnote "Missing closing '}'",16
mend
MACRO
&lab Str &string
&lab dc i1'L:&string'
dc c"&string"
mend
MACRO
&lab MV4 &src,&adr
&lab lcla &count
lda &src
&count seta 1
.loop1
sta &adr(&count)
&count seta &count+1
aif &count>c:&adr,.part2
ago ^loop1
.part2
lda &src+2
&count seta 1
.loop2
sta &adr(&count)+2
&count seta &count+1
aif &count>c:&adr,.done
ago ^loop2
.done
mend
MACRO
&lab iny2
&lab iny
iny
mend
MACRO
&lab dey2
&lab dey
dey
mend
MACRO
&lab PurgeHandle &a1
&lab ph4 &a1
tool $1202
mend
MACRO
&lab FindHandle &a1,&a2
&lab pha
pha
ph4 &a1
tool $1a02
pl4 &a2
mend
MACRO
&lab CompactMem
&lab tool $1f02
mend
MACRO
&lab if2 &var,&rel,&val,&label
&lab ago .skip
ble
bgt
.skip
lclc &char1
lclc &char2
&char1 amid &var,1,1
&char2 amid &var,2,1
aif "&char1"="@",.index
lda &var
.cmp
cmp &val
ago .branch
.index
aif "&char2"="x",.x1
aif "&char2"="X",.x1
aif "&char2"="y",.y1
aif "&char2"="Y",.y1
ago ^cmp
.x1
cpx &val
ago .branch
.y1
cpy &val
.branch
&char1 amid &rel,1,1
aif "&char1"="@",.done
b&rel &label
.done
mend
MACRO
&lab bgt &loc
&lab beq *+4
bcs &loc
mend
MACRO
&lab ble &loc
&lab bcc &loc
beq &loc
mend
MACRO
&lab WriteCString &a1
&lab ph4 &a1
Tool $200c
mend
MACRO
&lab jeq &loc
&lab bne *+5
jmp &loc
mend
MACRO
&lab jmi &loc
&lab bpl *+5
jmp &loc
mend
MACRO
&lab ora2 &arg1,&arg2,&dest
&lab anop
lclc &char
&char amid &arg1,1,1
aif "&char"="@",.at1
lda &arg1
ago .add
.at1
&char amid &arg1,2,1
aif "&char"="x",.x1
aif "&char"="X",.x1
aif "&char"="y",.y1
aif "&char"="Y",.y1
ago .add
.x1
txa
ago .add
.y1
tya
.add
ora &arg2
&char amid &dest,1,1
aif "&char"="@",.at2
sta &dest
ago .b
.at2
&char amid &dest,2,1
aif "&char"="x",.x2
aif "&char"="X",.x2
aif "&char"="y",.y2
aif "&char"="Y",.y2
ago .b
.x2
tax
ago .b
.y2
tay
.b
mend
macro
&lab NewHandle &a1,&a2
&lab pha
pha
ph4 &a1(1)
ph2 &a1(2)
ph2 &a1(3)
ph4 &a1(4)
tool $0902
pl4 &a2
mend
macro
&lab DisposeHandle &a1
&lab ph4 &a1
tool $1002
mend
macro
&lab TotalMem &a1
&lab pha
pha
tool $1d02
pl4 &a1
mend
macro
&lab FreeMem &a1
&lab pha
pha
tool $1b02
pl4 &a1
mend

6
bin/stty/Makefile Normal file
View File

@ -0,0 +1,6 @@
# @(#)Makefile 5.4 (Berkeley) 6/5/91
PROG= stty
SRCS= cchar.c gfmt.c key.c modes.c print.c stty.c util.c
.include <bsd.prog.mk>

302
bin/stty/stty.c Normal file
View File

@ -0,0 +1,302 @@
/*
* stty.c
*
* Set terminal parameters
*/
#pragma stacksize 1280
#pragma optimize 9
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/ioctl.h>
#include <gno/gno.h>
#include <unistd.h>
typedef struct opts {
char *name;
int item;
} opts_s;
/* B0 - B57600 are defined before these others */
#define LCRTERA_ON 16
#define LCRTERA_OFF 17
#define LCTLECH_ON 18
#define LCTLECH_OFF 19
#define CRMOD_ON 20
#define CRMOD_OFF 21
#define ECHO_ON 22
#define ECHO_OFF 23
#define RAW_ON 24
#define RAW_OFF 25
#define CBREAK_ON 26
#define CBREAK_OFF 27
#define SUSP_C 28
#define STOP_C 29
#define START_C 30
#define QUIT_C 31
#define ERASE_C 32
#define INTR_C 33
#define EOF_C 34
char *baudtbl[] = {
"0",
"50",
"75",
"110",
"134.5",
"150",
"57600",
"300",
"600",
"1200",
"1800",
"2400",
"4800",
"9600",
"19200",
"38400"};
opts_s options[] = {
"75", B75,
"110", B110,
"134", B134,
"150", B150,
"300", B300,
"600", B600,
"1200", B1200,
"1800", B1800,
"2400", B2400,
"4800", B4800,
"9600", B9600,
"19200", B19200,
"38400", B38400,
"57600", B57600,
"lcrtera", LCRTERA_ON,
"-lcrtera", LCRTERA_OFF,
"lctlech", LCTLECH_ON,
"-lctlech", LCTLECH_OFF,
"crmod", CRMOD_ON,
"-crmod", CRMOD_OFF,
"echo", ECHO_ON,
"-echo", ECHO_OFF,
"raw", RAW_ON,
"-raw", RAW_OFF,
"cbreak", CBREAK_ON,
"-cbreak", CBREAK_OFF,
"susp", SUSP_C,
"stop", STOP_C,
"start", START_C,
"quit", QUIT_C,
"erase", ERASE_C,
"intr", INTR_C,
"eof", EOF_C,
"", 0
};
int lookup(char *s)
{
int i;
for (i = 0; options[i].item; i++) {
if (!strcmp(options[i].name,s)) return (options[i].item);
}
return 0;
}
void usage(void)
{
fprintf(stderr,"usage: stty [ option ]...\n"
"\toption: [-]raw,[-]echo,[-]cbreak,[baud]\n"
"\toption c: intr, susp, stop, start, eof, erase\n"
"\t\twhere c is ^X or \\0OCTAL or \\xHEX\n");
exit(1);
}
char parsechar(char *s)
{
int x;
if (s[0] == '^') {
if (strlen(s) != 2) usage();
if (s[1] == '?') return 0x7f;
else return toupper(s[1])-64;
}
else if (s[0] == '\\') {
if (isdigit(s[1]) && (s[0] != 0))
sscanf(s+1,"%d",&x);
else if (toupper(s[1]) == 'X')
sscanf(s+2,"%x",&x);
else if (s[1] == '0')
sscanf(s+1,"%o",&x);
else usage();
printf("char: %d\n",x);
return x;
}
if (strlen(s) != 1) usage();
return s[0];
}
struct sgttyb sg;
struct tchars tc;
struct ltchars ltc;
struct winsize wz;
long localmode;
char *dash[] = {"","-"};
char *doctrl(char c)
{
static char ss[3] = " ";
if (c == 0x7F) {
ss[0] = '^';
ss[1] = '?';
}
else if (c < 32) {
ss[0] = '^';
ss[1] = c + '@';
}
else {
ss[0] = c;
ss[1] = ' ';
}
return ss;
}
void printCurSettings(void)
{
printf("old tty, speed %s baud, %d rows, %d columns\n",
baudtbl[sg.sg_ispeed & 0xF],wz.ws_row,wz.ws_col);
printf("%seven %sodd %sraw %snl %secho %slcase %standem %stabs %scbreak\n",
dash[(sg.sg_flags & EVENP) == 0],
dash[(sg.sg_flags & ODDP) == 0],
dash[(sg.sg_flags & RAW) == 0],
dash[(sg.sg_flags & NLDELAY) == 0],
dash[(sg.sg_flags & ECHO) == 0],
dash[(sg.sg_flags & LCASE) == 0],
dash[(sg.sg_flags & TANDEM) == 0],
dash[(sg.sg_flags & XTABS) == 0],
dash[(sg.sg_flags & CBREAK) == 0]);
printf("%stilde %sflusho %slitout %spass8 %snohang\n",
dash[(localmode & LTILDE) == 0],
dash[(localmode & LFLUSHO) == 0],
dash[(localmode & LLITOUT) == 0],
dash[(localmode & LPASS8) == 0],
dash[(localmode & LNOHANG) == 0]);
printf("%spendin %snoflsh\n",
dash[(localmode & LPENDIN) == 0],
dash[(localmode & LNOFLSH) == 0]);
printf("erase kill werase rprnt flush lnext susp intr quit stop eof\n");
printf("%-7s",doctrl(sg.sg_erase));
printf("%-7s",doctrl(sg.sg_kill));
printf("%-7s",doctrl(ltc.t_werasc));
printf("%-7s",doctrl(ltc.t_rprntc));
printf("%-7s",doctrl(ltc.t_flushc));
printf("%-7s",doctrl(ltc.t_lnextc));
printf("%2s",doctrl(ltc.t_suspc));
printf("/%2s ",doctrl(ltc.t_dsuspc));
printf("%-7s",doctrl(tc.t_intrc));
printf("%-7s",doctrl(tc.t_quitc));
printf("%2s",doctrl(tc.t_stopc));
printf("/%2s ",doctrl(tc.t_startc));
printf("%-7s\n",doctrl(tc.t_eofc));
}
int main(int argc, char *argv[])
{
int i,item;
ioctl(STDIN_FILENO,TIOCGETP,&sg);
ioctl(STDIN_FILENO,TIOCGETC,&tc);
ioctl(STDIN_FILENO,TIOCGLTC,&ltc);
ioctl(STDIN_FILENO,TIOCLGET,&localmode);
ioctl(STDIN_FILENO,TIOCGWINSZ,&wz);
if (argc < 2) {
printCurSettings();
exit(0);
}
for (i = 1; i < argc;) {
switch (item = lookup(argv[i])) {
case INTR_C:
tc.t_intrc = parsechar(argv[i+1]);
i++;
break;
case SUSP_C:
ltc.t_suspc = parsechar(argv[i+1]);
i++;
break;
case STOP_C:
tc.t_stopc = parsechar(argv[i+1]);
i++;
break;
case START_C:
tc.t_startc = parsechar(argv[i+1]);
i++;
break;
case QUIT_C:
tc.t_quitc = parsechar(argv[i+1]);
i++;
break;
case ERASE_C:
sg.sg_erase = parsechar(argv[i+1]);
i++;
break;
case EOF_C:
tc.t_eofc = parsechar(argv[i+1]);
i++;
break;
case ECHO_ON:
sg.sg_flags |= ECHO;
break;
case ECHO_OFF:
sg.sg_flags &= ~ECHO;
break;
case RAW_OFF:
sg.sg_flags &= ~RAW;
break;
case RAW_ON:
sg.sg_flags |= RAW;
break;
case CBREAK_OFF:
sg.sg_flags &= ~CBREAK;
break;
case CBREAK_ON:
sg.sg_flags |= CBREAK;
break;
case CRMOD_OFF:
sg.sg_flags &= ~CRMOD;
break;
case CRMOD_ON:
sg.sg_flags |= CRMOD;
break;
case LCTLECH_ON:
localmode |= LCTLECH;
break;
case LCTLECH_OFF:
localmode &= ~LCTLECH;
break;
case LCRTERA_ON:
localmode |= LCRTERA;
break;
case LCRTERA_OFF:
localmode &= ~LCRTERA;
break;
default:
if ((item != 0) && (item <= B38400)) {
sg.sg_ispeed = item;
sg.sg_ospeed = item;
} else usage();
break;
}
i++;
}
ioctl(STDIN_FILENO,TIOCSETP,&sg);
ioctl(STDIN_FILENO,TIOCSETC,&tc);
ioctl(STDIN_FILENO,TIOCSLTC,&ltc);
ioctl(STDIN_FILENO,TIOCLSET,&localmode);
}

2
bin/upper/Makefile Normal file
View File

@ -0,0 +1,2 @@
upper.a: upper.c
compile upper.c keep=upper

22
bin/upper/upper.c Normal file
View File

@ -0,0 +1,22 @@
/* converts text to upper case, used to gsh pipe mechanism */
/* program by Tim Meekins, Copyright (C) 1991 Procyon, Inc. */
#include <stdio.h>
#include <texttool.h>
#pragma optimize -1
#pragma stacksize 1024
main()
{
char ch;
while(1)
{
ch = ReadChar(0) & 0x7f;
if (ch==0) return;
if (ch >= 'a' && ch <= 'z')
ch = ch - ('a'-'A');
WriteChar(ch);
if (ch==13) WriteChar(10);
}
}

74
bin/vi/Makefile Normal file
View File

@ -0,0 +1,74 @@
o/alloc.a: alloc.c stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile alloc.c keep=o/alloc
o/CHARSET.a: CHARSET.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile CHARSET.C keep=o/CHARSET
o/cmdline.a: cmdline.c stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile cmdline.c keep=o/cmdline
o/DEC.a: DEC.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile DEC.C keep=o/DEC
o/EDIT.a: EDIT.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile EDIT.C keep=o/EDIT
o/FILEIO.a: FILEIO.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile FILEIO.C keep=o/FILEIO
o/FORMAT.L.a: FORMAT.L.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile FORMAT.L.C keep=o/FORMAT.L
o/gsos.a: gsos.c gsos.h stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile -p gsos.c keep=o/gsos
o/HELP.a: HELP.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile HELP.C keep=o/HELP
o/INC.a: INC.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile INC.C keep=o/INC
o/LINEFUNC.a: LINEFUNC.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile LINEFUNC.C keep=o/LINEFUNC
o/main.a: main.c stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile main.c keep=o/main
o/MARK.a: MARK.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile MARK.C keep=o/MARK
o/misccmds.a: misccmds.c stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile misccmds.c keep=o/misccmds
o/MK.a: MK.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile MK.C keep=o/MK
o/PARAM.a: PARAM.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile PARAM.C keep=o/PARAM
o/regexp.a: regexp.c env.h regexp.h regmagic.h
compile regexp.c keep=o/regexp
o/REGSUB.a: REGSUB.C env.h regexp.h regmagic.h
compile REGSUB.C keep=o/REGSUB
o/S.IO.a: S.IO.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile S.IO.C keep=o/S.IO
o/SCREEN.a: SCREEN.C stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile SCREEN.C keep=o/SCREEN
o/search.a: search.c stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h regexp.h
compile search.c keep=o/search
o/VERSION.a: VERSION.C
compile VERSION.C keep=o/VERSION
o/normal.a: normal.c stevie.h env.h ascii.h keymap.h param.h term.h macros.h gsos.h
compile normal.c keep=o/normal
vi: o/sio.a o/version.a o/search.a o/screen.a o/alloc.a o/cmdline.a \
o/regsub.a o/regexp.a o/param.a o/normal.a o/mk.a o/gsos.a o/format.l.a \
o/misccmds.a o/mark.a o/main.a o/linefunc.a o/inc.a o/help.a \
o/fileio.a o/edit.a o/dec.a o/charset.a
compile linkscr keep=vi

72
bin/vi/README Normal file
View File

@ -0,0 +1,72 @@
STEVIE Source Release
This is a source release of the STEVIE editor, a public domain clone
of the UNIX editor 'vi'. The program was originally developed for the
Atari ST, but has been ported to UNIX, OS/2, BSD 4.3 and the Amiga as well.
There are currently two divergent versions of STEVIE. This version is the one
that was ported to the Amiga and then worked on by me (G. R. Walter). The other
one Tony Andrews continued to work on. My version is faster in some respects
then his version, and his version does a couple of things mine doesn't.
The files included in this release are:
README
This file.
stevie.doc
Reference manual for STEVIE. Assumes familiarity with vi.
source.doc
Quick overview of the major data structures used.
porting.doc
Tips for porting STEVIE to other systems.
makefile.dos
makefile.os2
makefile.usg
makefile.tos
makefile.bsd
makefile.amiga.lattice
Makefiles for MS DOS, OS/2, UNIX System V, Atari ST, BSD 4.3 UNIX and
the Amiga respectively.
amiga.c
amiga.h
bsd.c
bsd.h
dos.c
dos.h
os2.c
os2.h
unix.c
unix.h
tos.c
tos.h
System-dependent routines for the same.
alloc.c ascii.h cmdline.c edit.c fileio.c help.c charset.c
keymap.h linefunc.c main.c mark.c misccmds.c normal.c param.c
regexp.c regsub.c version.c regexp.h regmagic.h
param.h ptrfunc.c screen.c search.c stevie.h term.h macros.h
C source and header files for STEVIE.
To compile STEVIE for one of the provided systems:
1. Compile the regular expression library and install as
appropriate for your system.
2. Edit the file 'env.h' to set the system defines as needed.
3. Check the makefile for your system, and modify as needed.
4. Compile.
NOTE: implicit in the design is the assumption that char's are unsigned. Thus
if your compiler assumes different by default, change the default or
you may have to change the source.
Tony Andrews March 12, 1988
G. R. (Fred) Walter August 14, 1988

80
bin/vi/README.gno Normal file
View File

@ -0,0 +1,80 @@
This version of the STEVIE sources and executable requires the GNO
multitasking environment, because STEVIE uses some GNO system calls
to enable it to work more like the real 'VI'.
This archive contains only the Stevie executable. Look for the source
archive in the same place you got this one.
This version of STEVIE has been modified to use the termcap library,
allowing STEVIE to operate on a wide range of terminal types, including
gno, vt100, proterm special, etc.
Apple IIgs BBS's now have a full-screen editor for posts, etc.
The termcap file is _not_ provided; look in the same place you got
Stevie for the latest termcap file.
The termcap file should be placed in your $home directory
(see your gshrc file for where $home is) or in directory 31:etc
(choose an existing directory or create a new one, and set prefix 31
in your gshrc).
It shouldn't be too hard to modify STEVIE to work under ORCA, but considering
all the other advantages of GNO, and the growing library of software that
requires it, I recommend you purchase GNO immediately (ok, so this is a plug).
Any comments, suggestions, and bug reports should be sent to:
Internet bazyar@cs.uiuc.edu
America OnLine GNO Jawaid
GEnie PROCYON.INC
Delphi JBazyar
You know exactly where to send any flames :-)
Jawaid Bazyar
CHANGES
2/3/94
Fixed a MAJOR buffer overflow bug that was causing Stevie to barf a lot
when doing delete lines, undos, etc. Basically, my screen output buffering
routines were not checking for the end of buffer.
7/20/92
Added auto screen-redraw when Stevie is unsuspended from the shell
Fixed termcap support again- we forgot to call tputs in _one_
location, causing cursor goto's to have a '5' placed in front
of them. Also took care of the problem where Stevie wouldn't
scroll with vt100 (you need a new termcap file dated 7/19/92 or
later for this).
I now use one of GNO's TextTools features so I know the difference
between right-arrow and control-U. Happy, Matt? :-)
Sped up screen output slightly by doing buffering and going directly
through the GNO console rather than TextTools.
Claimed Stevie as our own; we won't bother to keep ours current with
the original because the authors cannot be located.
Started optimizing some stuff; done mainly for space considerations
right now (i.e. only turning off stack 'protection')
Sped up file saves ~400% by assembly-izing and using a large, custom
file I/O buffer. (normal.c: 8 seconds to less than 2)
Sped up file loads ~60-80% by using a large, custom file I/O buffer.
any further load speed increases will require changing Stevie's memory
allocation scheme-a proposition that will probably mean rewriting most
of the code in Stevie. (normal.c: 10 seconds to 6)
Typing the suspend character while in insert or replace mode adds
that character to the buffer, rather than suspending Stevie. (e.g.
typing '^Z' will insert a '^Z'.)
4/21/92
Fixed termcap support- now correctly calls termcap routine 'tputs'
to output all term control codes. Thus, Stevie now works with the
VT100 termcap entry (which has special termcap delay codes, etc in it)

161
bin/vi/TAGS Normal file
View File

@ -0,0 +1,161 @@
ISSPECIAL edit.c /^#define ISSPECIAL(c) ((c) == BS || (c) == NL ||/
alloc alloc.c /^alloc(size)$/
badcmd cmdline.c /^badcmd()$/
beginline edit.c /^beginline(flag)$/
canincrease alloc.c /^canincrease(n)$/
dec dec.c /^dec(lp)$/
doecmd cmdline.c /^doecmd(arg)$/
doshell cmdline.c /^doshell()$/
dotag cmdline.c /^dotag(tag, force)$/
edit edit.c /^edit()$/
emsg cmdline.c /^emsg(s)$/
filealloc alloc.c /^filealloc()$/
freeall alloc.c /^freeall()$/
get_line cmdline.c /^get_line(cp)$/
get_range cmdline.c /^get_range(cp)$/
getout edit.c /^getout(r)$/
gotocmdline cmdline.c /^gotocmdline(clr, firstc)$/
insertchar edit.c /^insertchar(c)$/
msg cmdline.c /^msg(s)$/
newline alloc.c /^newline(nchars)$/
onedown edit.c /^onedown(n)$/
oneleft edit.c /^oneleft()$/
oneright edit.c /^oneright()$/
oneup edit.c /^oneup(n)$/
readcmdline cmdline.c /^readcmdline(firstc, cmdline)$/
screenalloc alloc.c /^screenalloc()$/
scrolldown edit.c /^scrolldown(nlines)$/
scrollup edit.c /^scrollup(nlines)$/
smsg cmdline.c /^smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9)$/
strsave alloc.c /^strsave(string)$/
wait_return cmdline.c /^wait_return()$/
Mmain main.c /^main(argc, argv)$/
clrall mark.c /^clrall()$/
clrmark mark.c /^clrmark(line)$/
coladvance linefunc.c /^coladvance(p, want_col)$/
filemess fileio.c /^filemess(s)$/
getmark mark.c /^getmark(c)$/
help help.c /^help()$/
inc inc.c /^inc(lp)$/
longline help.c /^longline(p)$/
nextline linefunc.c /^nextline(curr)$/
prevline linefunc.c /^prevline(curr)$/
readfile fileio.c /^readfile(fname, fromp, nochangename)$/
renum fileio.c /^renum()$/
setmark mark.c /^setmark(c)$/
setpcmark mark.c /^setpcmark()$/
stuffReadbuff main.c /^stuffReadbuff(s)$/
stuffnumReadbuff main.c /^stuffnumReadbuff(n)$/
usage main.c /^usage()$/
vgetc main.c /^vgetc()$/
vpeekc main.c /^vpeekc()$/
writeit fileio.c /^writeit(fname, start, end)$/
AppendNumberToRedobuff normal.c /^AppendNumberToRedobuff(n)$/
AppendNumberToUndoUndobuff normal.c /^AppendNumberToUndoUndobuff(n)$/
AppendNumberToUndobuff normal.c /^AppendNumberToUndobuff(n)$/
AppendPositionToUndoUndobuff normal.c /^AppendPositionToUndoUndobuff(column, row)$/
AppendPositionToUndobuff normal.c /^AppendPositionToUndobuff(column, row)$/
AppendToInsbuff normal.c /^AppendToInsbuff(s)$/
AppendToRedobuff normal.c /^AppendToRedobuff(s)$/
AppendToUndoUndobuff normal.c /^AppendToUndoUndobuff(s)$/
AppendToUndobuff normal.c /^AppendToUndobuff(s)$/
DEFAULT1 normal.c /^#define DEFAULT1(x) (((x) == 0) ? 1 : (x))$/
IDCHAR normal.c /^#define IDCHAR(c) (isalpha(c) || isdigit(c) /
OpenBackward misccmds.c /^OpenBackward(can_ai)$/
OpenForward misccmds.c /^OpenForward(can_ai)$/
ResetBuffers normal.c /^ResetBuffers()$/
cntllines misccmds.c /^cntllines(pbegin, pend)$/
cursupdate screen.c /^cursupdate(type)$/
delchar misccmds.c /^delchar(fixpos, undo)$/
delline misccmds.c /^delline(nlines)$/
dochange normal.c /^dochange()$/
dodelete normal.c /^dodelete(redraw, setup_for_undo, try_to_yank)$/
dojoin normal.c /^dojoin(leading_space, strip_leading_spaces)$/
doput normal.c /^doput(dir)$/
doset param.c /^doset(arg, inter)$/
doshift normal.c /^doshift(op)$/
doyank normal.c /^doyank()$/
fileinfo misccmds.c /^fileinfo()$/
gotoline misccmds.c /^gotoline(n)$/
inschar misccmds.c /^inschar(c)$/
insstr misccmds.c /^insstr(s)$/
linewhite normal.c /^linewhite(p)$/
normal normal.c /^normal(c)$/
plines misccmds.c /^plines(s)$/
showparms param.c /^showparms(all)$/
startinsert normal.c /^startinsert(startln)$/
tabinout normal.c /^tabinout(shift_type, num)$/
updateline screen.c /^updateline()$/
C0 search.c /^#define C0(c) (((c) == ' ') || ((c) == '\\t') || /
C1 search.c /^#define C1(c) (isalpha(c) || isdigit(c) || ((c) /
OTHERDIR search.c /^#define OTHERDIR(x) (((x) == FORWARD) ? BACKWA/
bck_word search.c /^bck_word(p, type)$/
bcksearch search.c /^bcksearch(str)$/
cls search.c /^cls(c)$/
crepsearch search.c /^crepsearch(flag)$/
doglob search.c /^doglob(lp, up, cmd)$/
dosearch search.c /^dosearch(dir, str)$/
dosub search.c /^dosub(lp, up, cmd)$/
end_word search.c /^end_word(p, type)$/
findfunc search.c /^findfunc(dir)$/
format_line format_l.c /^format_line(ptr, len)$/
fwd_word search.c /^fwd_word(p, type)$/
fwdsearch search.c /^fwdsearch(str)$/
mapstring search.c /^mapstring(s)$/
regerror search.c /^regerror(s)$/
repsearch search.c /^repsearch(flag)$/
searchagain search.c /^searchagain(dir)$/
searchc search.c /^searchc(c, dir, type)$/
showmatch search.c /^showmatch()$/
ssearch search.c /^ssearch(dir, str)$/
CTRL ascii.h /^#define CTRL(x) ((x) & 0x1f)$/
NotValidFromCurschar s_io.c /^NotValidFromCurschar()$/
Update_Botchar s_io.c /^Update_Botchar()$/
s_clear s_io.c /^s_clear()$/
s_cursor_off s_io.c /^s_cursor_off()$/
s_cursor_on s_io.c /^s_cursor_on()$/
s_refresh s_io.c /^s_refresh(type)$/
screen_del s_io.c /^screen_del(row, nlines, total_rows)$/
screen_ins s_io.c /^screen_ins(row, nlines, total_rows)$/
screen_refresh s_io.c /^screen_refresh(type)$/
LINE stevie.h 134
LINEOF stevie.h /^#define LINEOF(x) ((x)->linep->num)$/
LPtr stevie.h 135
P param.h /^#define P(n) (params[n].value)$/
RowNumber macros.h /^#define RowNumber(p) (UndoInProgress ? 0 : cntllin/
anyinput macros.h /^#define anyinput() (Readbuffptr != NULL)$/
bool_t stevie.h 55
buf1line macros.h /^#define buf1line() (Filemem->linep->next == Fileen/
bufempty macros.h /^#define bufempty() (buf1line() && Filemem->linep->/
endofline macros.h /^#define endofline(p) \\$/
equal macros.h /^#define equal(a, b) (((a)->linep == (b)->linep) &&/
gchar macros.h /^#define gchar(lp) ((lp)->linep->s[(lp)->index])$/
gt macros.h /^#define gt(a, b) ((LINEOF(a) != LINEOF(b)) \\$/
gtoreq macros.h /^#define gtoreq(a, b) ((LINEOF(a) != LINEOF(b)) \\$/
lineempty macros.h /^#define lineempty(p) ((p)->linep->s[0] == NUL)$/
lt macros.h /^#define lt(a, b) ((LINEOF(a) != LINEOF(b)) \\$/
ltoreq macros.h /^#define ltoreq(a, b) ((LINEOF(a) != LINEOF(b)) \\$/
mkline mk.c /^mkline(n)$/
mkstr mk.c /^mkstr(c)$/
pchar macros.h /^#define pchar(lp, c) ((lp)->linep->s[(lp)->index] /
pswap macros.h /^#define pswap(a, b) { LPtr pswaptmp; pswaptmp = a;/
startofline macros.h /^#define startofline(p) ((p)->index == 0)$/
ExpandWildCards amiga.c /^ExpandWildCards(num_pat, pat, num_file, file)$/
GetCharacter amiga.c /^GetCharacter()$/
beep amiga.c /^beep()$/
cooked amiga.c /^cooked(afh)$/
delay amiga.c /^delay()$/
flushbuf amiga.c /^flushbuf()$/
fopenb amiga.c /^fopenb(fname, mode)$/
getCSIsequence amiga.c /^getCSIsequence()$/
get_ConUnit amiga.c /^get_ConUnit(afh)$/
get_Rows_and_Columns amiga.c /^get_Rows_and_Columns()$/
inchar amiga.c /^inchar()$/
outchar amiga.c /^outchar(c)$/
outstr amiga.c /^outstr(s)$/
raw amiga.c /^raw(afh)$/
send_packet amiga.c /^send_packet(pid, action, args, nargs)$/
sleep amiga.c /^sleep(n)$/
windexit amiga.c /^windexit(r)$/
windgoto amiga.c /^windgoto(r, c)$/
windinit amiga.c /^windinit()$/

38
bin/vi/TODO Normal file
View File

@ -0,0 +1,38 @@
To Do
-----
- Fix the update routines to not redisplay the whole bloody screen every
time a line is inserted or a character is typed. This may require
adding IIgs support for InsertLine and DeleteLine.
- Change the static buffers for insert/undo/redo/undoundo/etc to dynamic
buffers.
- Add #'d and named buffers.
IE. "xp = pull text from buffer x
- Add 'U'.
- Add { and } (move paragraph back and forward).
- In cmdline.c make get_range() give the appropriate error messages when it
gets a bad line range.
- Add & (do last search and replace on current line) and :[range]&
(do last search and replace on the range of lines).
- add :set wrapmargin command
- add :set shiftwidth command
- add :set autowrite command
- add :set showmode command
- should be able to d/pat
- should be able to ^d (backspace over entire indent (for :set ai))
- should be able to ^X and ^W in input mode
- should support '!' filters
- should support mode lines
- add checks for out of memory when strsave() is used
- after a screen resize, make sure cmdline stuff is re-displayed

211
bin/vi/alloc.c Normal file
View File

@ -0,0 +1,211 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
#ifdef AMIGA
# include <proto/exec.h>
# include <exec/memory.h>
# define PANIC_FACTOR_CHIP 40000
#endif
#ifdef GSOS
#include <stdlib.h>
#endif
/*
* This file contains various routines dealing with allocation and
* deallocation of data structures.
*/
char *alloc(unsigned size)
{
char *p; /* pointer to new storage space */
p = malloc(size);
if (p == (char *) NULL) { /* if there is no more room... */
emsg("alloc() is unable to find memory!");
sleep(5);
}
#ifdef AMIGA
if (AvailMem(MEMF_CHIP) < PANIC_FACTOR_CHIP) {
free(p);
p = (char *) NULL;
emsg("alloc() - not enough CHIP memory!");
sleep(5);
}
#endif
return (p);
}
char *strsave(char *string)
{
char *s;
s = alloc((unsigned) (strlen(string) + 1));
if (s != (char *) NULL)
strcpy(s, string);
return (s);
}
void screenalloc(void)
{
int i;
/*
* If we're changing the size of the screen, free the old arrays
*/
if (LinePointers != (LINE **) NULL)
free((char *) LinePointers);
if (LineSizes != (char *) NULL)
free(LineSizes);
LinePointers = (LINE **) malloc((unsigned) (Rows * sizeof(LINE *)));
LineSizes = malloc((unsigned) Rows);
if (LinePointers == (LINE **) NULL || LineSizes == (char *) NULL) {
fprintf(stderr, "Unable to allocate screen memory!\n");
getout(1);
}
for (i = 0; i < Rows; i++) {
LinePointers[i] = (LINE *) NULL;
LineSizes[i] = (char) 0;
}
NumLineSizes = -1;
}
/*
* Allocate and initialize a new line structure with room for 'nchars'
* characters.
*/
LINE *newline(int nchars)
{
register LINE *l;
if (nchars == 0)
nchars = 1;
l = (LINE *) alloc((unsigned) sizeof(LINE));
if (l != (LINE *) NULL) {
l->s = alloc((unsigned) nchars); /* the line is empty */
if (l->s != (char *) NULL) {
l->s[0] = NUL;
l->size = nchars;
l->prev = (LINE *) NULL; /* should be initialized by caller */
l->next = (LINE *) NULL;
} else {
free((char *) l);
l = (LINE *) NULL;
}
}
return l;
}
/*
* filealloc() - construct an initial empty file buffer
*/
void
filealloc(void)
{
Filemem->linep = newline(1);
Filetop->linep = newline(1);
Fileend->linep = newline(1);
if (Filemem->linep == (LINE *) NULL ||
Filetop->linep == (LINE *) NULL ||
Fileend->linep == (LINE *) NULL) {
fprintf(stderr, "Unable to allocate file memory!\n");
getout(1);
}
Filemem->index = 0;
Filetop->index = 0;
Fileend->index = 0;
Filetop->linep->prev = (LINE *) NULL;
Filetop->linep->next = Filemem->linep; /* connect Filetop to Filemem */
Filemem->linep->prev = Filetop->linep;
Filemem->linep->next = Fileend->linep; /* connect Filemem to Fileend */
Fileend->linep->prev = Filemem->linep;
Fileend->linep->next = (LINE *) NULL;
*Curschar = *Filemem;
*Topchar = *Filemem;
Filemem->linep->num = 0;
Fileend->linep->num = 0xffffffffL;
clrall(); /* clear all marks */
}
/*
* freeall() - free the current buffer
*
* Free all lines in the current buffer.
*/
void
freeall(void)
{
LINE *lp;
LINE *xlp;
int i;
for (lp = Filetop->linep; lp != (LINE *) NULL; lp = xlp) {
if (lp->s != (char *) NULL)
free(lp->s);
xlp = lp->next;
free((char *) lp);
}
Curschar->linep = (LINE *) NULL; /* clear pointers */
Filemem->linep = (LINE *) NULL;
Filetop->linep = (LINE *) NULL;
Fileend->linep = (LINE *) NULL;
for (i = 0; i < Rows; i++) {/* clear screen information */
LinePointers[i] = (LINE *) NULL;
LineSizes[i] = (char) 0;
}
NumLineSizes = -1;
}
/*
* canincrease(n) - returns TRUE if the current line can be increased 'n'
* bytes
*
* This routine returns immediately if the requested space is available. If not,
* it attempts to allocate the space and adjust the data structures
* accordingly. If everything fails it returns FALSE.
*/
bool_t canincrease(int n)
{
register int nsize;
register char *s; /* pointer to new space */
nsize = strlen(Curschar->linep->s) + 1 + n; /* size required */
if (nsize <= Curschar->linep->size)
return TRUE;
/*
* Need to allocate more space for the string. Allow some extra space on
* the assumption that we may need it soon. This avoids excessive numbers
* of calls to malloc while entering new text.
*/
s = alloc((unsigned) (nsize + SLOP));
if (s == (char *) NULL) {
emsg("Can't add anything, file is too big!");
State = NORMAL;
return FALSE;
}
Curschar->linep->size = nsize + SLOP;
strcpy(s, Curschar->linep->s);
free(Curschar->linep->s);
Curschar->linep->s = s;
return TRUE;
}

29
bin/vi/ascii.h Normal file
View File

@ -0,0 +1,29 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
/*
* Definitions of various common control characters
*/
#define NUL '\000'
#define BS '\010'
#define BS_STR "\010"
#define TAB '\011'
#define NL '\012'
#define NL_STR "\012"
#define CR '\015'
#define ESC '\033'
#define ESC_STR "\033"
#define UNDO_SHIFTJ '\333'
#define UNDO_SHIFTJ_STR "\333"
#define ENABLE_REDRAWING '\334'
#define ENABLE_REDRAWING_STR "\334"
#define CTRL(x) ((x) & 0x1f)

1683
bin/vi/bug2.c Normal file

File diff suppressed because it is too large Load Diff

346
bin/vi/bugstevie.h Normal file
View File

@ -0,0 +1,346 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#ifdef __ORCAC__
#ifndef MAINSEG
#pragma noroot
#endif
#endif
#include "env.h"
#include <stdio.h>
#ifndef ATARI
# ifndef UNIX
# include <stdlib.h>
# endif
#endif
#include <ctype.h>
#ifndef MWC
# include <string.h>
#endif
#include "ascii.h"
#include "keymap.h"
#include "param.h"
/*#include "term.h"*/
#include "macros.h"
#ifdef AMIGA
/*
* This is used to disable break signal handling.
*/
#include <signal.h>
#endif
extern char *strchr();
#define NORMAL 0
#define CMDLINE 1
#define INSERT 2
#define REPLACE 3
#define APPEND 4
#define UNDO 5
#define REDO 6
#define PUT 7
#define FORWARD 8
#define BACKWARD 9
#define VALID 10
#define NOT_VALID 11
#define VALID_TO_CURSCHAR 12
#define UPDATE_CURSOR 13
#define UPDATE_ALL 14
/*
* Boolean type definition and constants
*/
typedef int bool_t;
#ifndef TRUE
# define FALSE (0)
# define TRUE (1)
#endif
#define SORTOF (2)
#define YES TRUE
#define NO FALSE
#define MAYBE SORTOF
/*
* Maximum screen dimensions
*/
#define MAX_COLUMNS 140L
/*
* Buffer sizes
*/
#define CMDBUFFSIZE MAX_COLUMNS /* size of the command processing buffer */
#define LSIZE 512 /* max. size of a line in the tags file */
#define IOSIZE (1024+1) /* file i/o and sprintf buffer size */
#define YANKSIZE 5200 /* yank buffer size */
#define INSERT_SIZE 5300 /* insert, redo and undo buffer size must be
* bigger than YANKSIZE */
#define REDO_UNDO_SIZE 5400 /* redo, undo and (undo an undo) buffer size
* must be bigger than INSERT_SIZE */
#define READSIZE 5500 /* read buffer size must be bigger than
* YANKSIZE and REDO_UNDO_SIZE */
/*
* SLOP is the amount of extra space we get for text on a line during editing
* operations that need more space. This keeps us from calling alloc every
* time we get a character during insert mode. No extra space is allocated
* when the file is initially read.
*/
#define SLOP 10
/*
* LINEINC is the gap we leave between the artificial line numbers. This
* helps to avoid renumbering all the lines every time a new line is
* inserted.
*
* Since line numbers are stored in longs (32 bits), a LINEINC of 10000
* lets us have > 200,000 lines and we won't have to renumber very often.
*/
#define LINEINC 10000
#define CHANGED Changed = TRUE
#define UNCHANGED Changed = FALSE
#define S_NOT_VALID NumLineSizes = -1
#define S_LINE_NOT_VALID LineNotValid = TRUE
#define S_CHECK_TOPCHAR_AND_BOTCHAR CheckTopcharAndBotchar = TRUE
#define S_MUST_UPDATE_BOTCHAR MustUpdateBotchar = TRUE
#define S_VALID_TO_CURSCHAR ValidToCurschar = TRUE
struct line {
struct line *next; /* next line */
struct line *prev; /* previous line */
char *s; /* text for this line */
int size; /* actual size of space at 's' */
unsigned long num; /* line "number" */
};
#define LINEOF(x) ((x)->linep->num)
struct lptr {
struct line *linep; /* line we're referencing */
int index; /* position within that line */
};
typedef struct line LINE;
typedef struct lptr LPtr;
struct charinfo {
char ch_size;
char *ch_str;
};
extern struct charinfo chars[];
#ifdef AMIGA
extern int Aux_Device;
#endif
extern int State;
extern int Rows;
extern int Columns;
extern int CheckTopcharAndBotchar;
extern int MustUpdateBotchar;
extern int ValidToCurschar;
extern int LineNotValid;
extern int NumLineSizes;
extern LINE **LinePointers;
extern char *LineSizes;
extern char *Filename;
extern LPtr *Filemem;
extern LPtr *Filetop;
extern LPtr *Fileend;
extern LPtr *Topchar;
extern LPtr *Botchar;
extern LPtr *Curschar;
extern LPtr *Insstart;
extern int Cursrow;
extern int Curscol;
extern int Cursvcol;
extern int Curswant;
extern bool_t set_want_col;
extern int Prenum;
extern bool_t Changed;
extern bool_t RedrawingDisabled;
extern bool_t UndoInProgress;
extern char *IObuff;
extern char *Insbuffptr;
extern char *Insbuff;
extern char *Readbuffptr;
extern char *Readbuff;
extern char *Redobuffptr;
extern char *Redobuff;
extern char *Undobuffptr;
extern char *Undobuff;
extern char *UndoUndobuffptr;
extern char *UndoUndobuff;
extern char *Yankbuffptr;
extern char *Yankbuff;
extern char last_command;
extern char last_command_char;
extern char *strcpy();
/* alloc.c */
char *alloc();
char *strsave();
void screenalloc();
void filealloc();
void freeall();
LINE *newline();
bool_t canincrease();
/* cmdline.c */
void readcmdline();
void dotag();
void msg();
void emsg();
void smsg();
void gotocmdline();
void wait_return();
/* dec.c */
int dec();
/* edit.c */
void edit();
void insertchar();
void getout();
void scrollup();
void scrolldown();
void beginline();
bool_t oneright();
bool_t oneleft();
bool_t oneup();
bool_t onedown();
/* fileio.c */
void filemess();
void renum();
bool_t readfile();
bool_t writeit();
/* s_io.c */
void s_cursor_off();
void s_cursor_on();
void s_clear();
void s_refresh();
void NotValidFromCurschar();
void Update_Botchar();
/* help.c */
bool_t help();
/* inc.c */
int inc();
/* linefunc.c */
LPtr *nextline();
LPtr *prevline();
void coladvance();
/* main.c */
void stuffReadbuff();
void stuffnumReadbuff();
char vgetc();
char vpeekc();
/* mark.c */
void setpcmark();
void clrall();
void clrmark();
bool_t setmark();
LPtr *getmark();
/* misccmds.c */
bool_t OpenForward();
bool_t OpenBackward();
void fileinfo();
void inschar();
void insstr();
void delline();
bool_t delchar();
int cntllines();
int plines();
LPtr *gotoline();
/* normal.c */
void normal();
void ResetBuffers();
void AppendToInsbuff();
void AppendToRedobuff();
void AppendNumberToRedobuff();
void AppendToUndobuff();
void AppendNumberToUndobuff();
void AppendPositionToUndobuff();
void AppendToUndoUndobuff();
void AppendNumberToUndoUndobuff();
void AppendPositionToUndoUndobuff();
bool_t linewhite();
/* mk.c */
char *mkstr();
char *mkline();
/* param.c */
void doset();
/* screen.c */
void cursupdate();
/* search.c */
void doglob();
void dosub();
void searchagain();
bool_t dosearch();
bool_t repsearch();
bool_t searchc();
bool_t crepsearch();
bool_t findfunc();
LPtr *showmatch();
LPtr *fwd_word();
LPtr *bck_word();
LPtr *end_word();
/* format_l.c */
char *format_line();
/*
* Machine-dependent routines.
*/
#ifdef AMIGA
# include "amiga.h"
#endif
#ifdef BSD
# include "bsd.h"
#endif
#ifdef UNIX
# include "unix.h"
#endif
#ifdef TOS
# include "tos.h"
#endif
#ifdef OS2
# include "os2.h"
#endif
#ifdef DOS
# include "dos.h"
#endif
#ifdef GSOS
# include "gsos.h"
#endif

374
bin/vi/charset.c Normal file
View File

@ -0,0 +1,374 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
/*
* This file shows how to display characters on the screen. This is approach
* is something of an overkill. It's a remnant from the original code that
* isn't worth messing with for now. TABS are special-cased depending on the
* value of the "list" parameter.
*/
struct charinfo chars[] = {
/* 0 */ 0, 0, /* both must be zero */
/* 1 */ 2, "^A",
/* 2 */ 2, "^B",
/* 3 */ 2, "^C",
/* 4 */ 2, "^D",
/* 5 */ 2, "^E",
/* 6 */ 2, "^F",
/* 7 */ 2, "^G",
/* 8 */ 2, "^H",
/* 9 */ 2, "^I",
/* 10 */ 7, "[ERROR]", /* shouldn't happen */
/* 11 */ 2, "^K",
/* 12 */ 2, "^L",
/* 13 */ 2, "^M",
/* 14 */ 2, "^N",
/* 15 */ 2, "^O",
/* 16 */ 2, "^P",
/* 17 */ 2, "^Q",
/* 18 */ 2, "^R",
/* 19 */ 2, "^S",
/* 20 */ 2, "^T",
/* 21 */ 2, "^U",
/* 22 */ 2, "^V",
/* 23 */ 2, "^W",
/* 24 */ 2, "^X",
/* 25 */ 2, "^Y",
/* 26 */ 2, "^Z",
/* 27 */ 2, "^[",
/* 28 */ 2, "^\\",
/* 29 */ 2, "^]",
/* 30 */ 2, "^^",
/* 31 */ 2, "^_",
/* 32 */ 1, " ",
/* 33 */ 1, "!",
/* 34 */ 1, "\"",
/* 35 */ 1, "#",
/* 36 */ 1, "$",
/* 37 */ 1, "%",
/* 38 */ 1, "&",
/* 39 */ 1, "'",
/* 40 */ 1, "(",
/* 41 */ 1, ")",
/* 42 */ 1, "*",
/* 43 */ 1, "+",
/* 44 */ 1, ",",
/* 45 */ 1, "-",
/* 46 */ 1, ".",
/* 47 */ 1, "/",
/* 48 */ 1, "0",
/* 49 */ 1, "1",
/* 50 */ 1, "2",
/* 51 */ 1, "3",
/* 52 */ 1, "4",
/* 53 */ 1, "5",
/* 54 */ 1, "6",
/* 55 */ 1, "7",
/* 56 */ 1, "8",
/* 57 */ 1, "9",
/* 58 */ 1, ":",
/* 59 */ 1, ";",
/* 60 */ 1, "<",
/* 61 */ 1, "=",
/* 62 */ 1, ">",
/* 63 */ 1, "?",
/* 64 */ 1, "@",
/* 65 */ 1, "A",
/* 66 */ 1, "B",
/* 67 */ 1, "C",
/* 68 */ 1, "D",
/* 69 */ 1, "E",
/* 70 */ 1, "F",
/* 71 */ 1, "G",
/* 72 */ 1, "H",
/* 73 */ 1, "I",
/* 74 */ 1, "J",
/* 75 */ 1, "K",
/* 76 */ 1, "L",
/* 77 */ 1, "M",
/* 78 */ 1, "N",
/* 79 */ 1, "O",
/* 80 */ 1, "P",
/* 81 */ 1, "Q",
/* 82 */ 1, "R",
/* 83 */ 1, "S",
/* 84 */ 1, "T",
/* 85 */ 1, "U",
/* 86 */ 1, "V",
/* 87 */ 1, "W",
/* 88 */ 1, "X",
/* 89 */ 1, "Y",
/* 90 */ 1, "Z",
/* 91 */ 1, "[",
/* 92 */ 1, "\\",
/* 93 */ 1, "]",
/* 94 */ 1, "^",
/* 95 */ 1, "_",
/* 96 */ 1, "`",
/* 97 */ 1, "a",
/* 98 */ 1, "b",
/* 99 */ 1, "c",
/* 100 */ 1, "d",
/* 101 */ 1, "e",
/* 102 */ 1, "f",
/* 103 */ 1, "g",
/* 104 */ 1, "h",
/* 105 */ 1, "i",
/* 106 */ 1, "j",
/* 107 */ 1, "k",
/* 108 */ 1, "l",
/* 109 */ 1, "m",
/* 110 */ 1, "n",
/* 111 */ 1, "o",
/* 112 */ 1, "p",
/* 113 */ 1, "q",
/* 114 */ 1, "r",
/* 115 */ 1, "s",
/* 116 */ 1, "t",
/* 117 */ 1, "u",
/* 118 */ 1, "v",
/* 119 */ 1, "w",
/* 120 */ 1, "x",
/* 121 */ 1, "y",
/* 122 */ 1, "z",
/* 123 */ 1, "{",
/* 124 */ 1, "|",
/* 125 */ 1, "}",
/* 126 */ 1, "~",
/* 127 */ 2, "^?",
/* 128 */ 5, "[128]",
/* 129 */ 5, "[129]",
/* 130 */ 5, "[130]",
/* 131 */ 5, "[131]",
/* 132 */ 5, "[132]",
/* 133 */ 5, "[133]",
/* 134 */ 5, "[134]",
/* 135 */ 5, "[135]",
/* 136 */ 5, "[136]",
/* 137 */ 5, "[137]",
/* 138 */ 5, "[138]",
/* 139 */ 5, "[139]",
/* 140 */ 5, "[140]",
/* 141 */ 5, "[141]",
/* 142 */ 5, "[142]",
/* 143 */ 5, "[143]",
/* 144 */ 5, "[144]",
/* 145 */ 5, "[145]",
/* 146 */ 5, "[146]",
/* 147 */ 5, "[147]",
/* 148 */ 5, "[148]",
/* 149 */ 5, "[149]",
/* 150 */ 5, "[150]",
/* 151 */ 5, "[151]",
/* 152 */ 5, "[152]",
/* 153 */ 5, "[153]",
/* 154 */ 5, "[154]",
/* 155 */ 5, "[155]",
/* 156 */ 5, "[156]",
/* 157 */ 5, "[157]",
/* 158 */ 5, "[158]",
/* 159 */ 5, "[159]",
#ifdef AMIGA
/* 160 */ 1, "\240",
/* 161 */ 1, "\241",
/* 162 */ 1, "\242",
/* 163 */ 1, "\243",
/* 164 */ 1, "\244",
/* 165 */ 1, "\245",
/* 166 */ 1, "\246",
/* 167 */ 1, "\247",
/* 168 */ 1, "\250",
/* 169 */ 1, "\251",
/* 170 */ 1, "\252",
/* 171 */ 1, "\253",
/* 172 */ 1, "\254",
/* 173 */ 1, "\255",
/* 174 */ 1, "\256",
/* 175 */ 1, "\257",
/* 176 */ 1, "\260",
/* 177 */ 1, "\261",
/* 178 */ 1, "\262",
/* 179 */ 1, "\263",
/* 180 */ 1, "\264",
/* 181 */ 1, "\265",
/* 182 */ 1, "\266",
/* 183 */ 1, "\267",
/* 184 */ 1, "\270",
/* 185 */ 1, "\271",
/* 186 */ 1, "\272",
/* 187 */ 1, "\273",
/* 188 */ 1, "\274",
/* 189 */ 1, "\275",
/* 190 */ 1, "\276",
/* 191 */ 1, "\277",
/* 192 */ 1, "\300",
/* 193 */ 1, "\301",
/* 194 */ 1, "\302",
/* 195 */ 1, "\303",
/* 196 */ 1, "\304",
/* 197 */ 1, "\305",
/* 198 */ 1, "\306",
/* 199 */ 1, "\307",
/* 200 */ 1, "\310",
/* 201 */ 1, "\311",
/* 202 */ 1, "\312",
/* 203 */ 1, "\313",
/* 204 */ 1, "\314",
/* 205 */ 1, "\315",
/* 206 */ 1, "\316",
/* 207 */ 1, "\317",
/* 208 */ 1, "\320",
/* 209 */ 1, "\321",
/* 210 */ 1, "\322",
/* 211 */ 1, "\323",
/* 212 */ 1, "\324",
/* 213 */ 1, "\325",
/* 214 */ 1, "\326",
/* 215 */ 1, "\327",
/* 216 */ 1, "\330",
/* 217 */ 1, "\331",
/* 218 */ 1, "\332",
/* 219 */ 1, "\333",
/* 220 */ 1, "\334",
/* 221 */ 1, "\335",
/* 222 */ 1, "\336",
/* 223 */ 1, "\337",
/* 224 */ 1, "\340",
/* 225 */ 1, "\341",
/* 226 */ 1, "\342",
/* 227 */ 1, "\343",
/* 228 */ 1, "\344",
/* 229 */ 1, "\345",
/* 230 */ 1, "\346",
/* 231 */ 1, "\347",
/* 232 */ 1, "\350",
/* 233 */ 1, "\351",
/* 234 */ 1, "\352",
/* 235 */ 1, "\353",
/* 236 */ 1, "\354",
/* 237 */ 1, "\355",
/* 238 */ 1, "\356",
/* 239 */ 1, "\357",
/* 240 */ 1, "\360",
/* 241 */ 1, "\361",
/* 242 */ 1, "\362",
/* 243 */ 1, "\363",
/* 244 */ 1, "\364",
/* 245 */ 1, "\365",
/* 246 */ 1, "\366",
/* 247 */ 1, "\367",
/* 248 */ 1, "\370",
/* 249 */ 1, "\371",
/* 250 */ 1, "\372",
/* 251 */ 1, "\373",
/* 252 */ 1, "\374",
/* 253 */ 1, "\375",
/* 254 */ 1, "\376",
/* 255 */ 1, "\377"
#else
/* 160 */ 5, "[160]",
/* 161 */ 5, "[161]",
/* 162 */ 5, "[162]",
/* 163 */ 5, "[163]",
/* 164 */ 5, "[164]",
/* 165 */ 5, "[165]",
/* 166 */ 5, "[166]",
/* 167 */ 5, "[167]",
/* 168 */ 5, "[168]",
/* 169 */ 5, "[169]",
/* 170 */ 5, "[170]",
/* 171 */ 5, "[171]",
/* 172 */ 5, "[172]",
/* 173 */ 5, "[173]",
/* 174 */ 5, "[174]",
/* 175 */ 5, "[175]",
/* 176 */ 5, "[176]",
/* 177 */ 5, "[177]",
/* 178 */ 5, "[178]",
/* 179 */ 5, "[179]",
/* 180 */ 5, "[180]",
/* 181 */ 5, "[181]",
/* 182 */ 5, "[182]",
/* 183 */ 5, "[183]",
/* 184 */ 5, "[184]",
/* 185 */ 5, "[185]",
/* 186 */ 5, "[186]",
/* 187 */ 5, "[187]",
/* 188 */ 5, "[188]",
/* 189 */ 5, "[189]",
/* 190 */ 5, "[190]",
/* 191 */ 5, "[191]",
/* 192 */ 5, "[192]",
/* 193 */ 5, "[193]",
/* 194 */ 5, "[194]",
/* 195 */ 5, "[195]",
/* 196 */ 5, "[196]",
/* 197 */ 5, "[197]",
/* 198 */ 5, "[198]",
/* 199 */ 5, "[199]",
/* 200 */ 5, "[200]",
/* 201 */ 5, "[201]",
/* 202 */ 5, "[202]",
/* 203 */ 5, "[203]",
/* 204 */ 5, "[204]",
/* 205 */ 5, "[205]",
/* 206 */ 5, "[206]",
/* 207 */ 5, "[207]",
/* 208 */ 5, "[208]",
/* 209 */ 5, "[209]",
/* 210 */ 5, "[210]",
/* 211 */ 5, "[211]",
/* 212 */ 5, "[212]",
/* 213 */ 5, "[213]",
/* 214 */ 5, "[214]",
/* 215 */ 5, "[215]",
/* 216 */ 5, "[216]",
/* 217 */ 5, "[217]",
/* 218 */ 5, "[218]",
/* 219 */ 5, "[219]",
/* 220 */ 5, "[220]",
/* 221 */ 5, "[221]",
/* 222 */ 5, "[222]",
/* 223 */ 5, "[223]",
/* 224 */ 5, "[224]",
/* 225 */ 5, "[225]",
/* 226 */ 5, "[226]",
/* 227 */ 5, "[227]",
/* 228 */ 5, "[228]",
/* 229 */ 5, "[229]",
/* 230 */ 5, "[230]",
/* 231 */ 5, "[231]",
/* 232 */ 5, "[232]",
/* 233 */ 5, "[233]",
/* 234 */ 5, "[234]",
/* 235 */ 5, "[235]",
/* 236 */ 5, "[236]",
/* 237 */ 5, "[237]",
/* 238 */ 5, "[238]",
/* 239 */ 5, "[239]",
/* 240 */ 5, "[240]",
/* 241 */ 5, "[241]",
/* 242 */ 5, "[242]",
/* 243 */ 5, "[243]",
/* 244 */ 5, "[244]",
/* 245 */ 5, "[245]",
/* 246 */ 5, "[246]",
/* 247 */ 5, "[247]",
/* 248 */ 5, "[248]",
/* 249 */ 5, "[249]",
/* 250 */ 5, "[250]",
/* 251 */ 5, "[251]",
/* 252 */ 5, "[252]",
/* 253 */ 5, "[253]",
/* 254 */ 5, "[254]",
/* 255 */ 5, "[255]"
#endif
};

829
bin/vi/cmdline.c Normal file
View File

@ -0,0 +1,829 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#ifdef __ORCAC__
segment "seg2";
#include <stdarg.h>
#endif
#include "stevie.h"
static char *altfile = NULL; /* alternate file */
static int altline; /* line # in alternate file */
static char *nowrtmsg = "No write since last change (use ! to override)";
extern char **files; /* used for "n" and "rew" */
extern int curfile;
extern int numfiles;
#ifdef WILD_CARDS
char **cmd_files = NULL; /* list of input files */
int cmd_numfiles = 0; /* number of input files */
#endif
/*
* The next two variables contain the bounds of any range given in a command.
* If no range was given, both contain null line pointers. If only a single
* line was given, u_pos will contain a null line pointer.
*/
static LPtr l_pos, u_pos;
static bool_t interactive; /* TRUE if we're reading a real command line */
static bool_t doecmd(char *);
static void badcmd(void);
static void doshell(void);
static void get_range(char **);
static LPtr *get_line(char **);
#ifdef MEGAMAX
overlay "cmdline"
#endif
/*
* readcmdline() - accept a command line starting with ':', '/', or '?'
*
* readcmdline() accepts and processes colon commands and searches. If
* 'cmdline' is null, the command line is read here. Otherwise, cmdline
* points to a complete command line that should be used. This is used in
* main() to handle initialization commands in the environment variable
* "EXINIT".
*/
void
readcmdline(char firstc, char *cmdline)
/*char firstc; /* either ':', '/', or '?' */
/*char *cmdline; /* optional command string */
{
char c;
char buff[CMDBUFFSIZE];
char cmdbuf[CMDBUFFSIZE];
char argbuf[CMDBUFFSIZE];
char *p, *q, *cmd, *arg;
bool_t literal_next_flag = FALSE;
/*
* Clear the range variables.
*/
l_pos.linep = (LINE *) NULL;
u_pos.linep = (LINE *) NULL;
interactive = (cmdline == NULL);
if (interactive)
gotocmdline(YES, firstc);
p = buff;
if (firstc != ':')
*p++ = firstc;
if (interactive) {
/* collect the command string, handling '\b' and @ */
for (;;) {
c = vgetc();
if (c == CTRL('V') && !literal_next_flag) {
literal_next_flag = TRUE;
outchar('^');
continue;
}
if (c == '\n' || ((c == '\r' || c == ESC) && (!literal_next_flag)))
break;
if ((c == '\b') && (!literal_next_flag)) {
if (p > buff + (firstc != ':')) {
p--;
/*
* this is gross, but it relies only on 'gotocmdline'
*/
gotocmdline(YES, firstc == ':' ? ':' : NUL);
for (q = buff; q < p; q++)
outstr(chars[*q].ch_str);
} else {
msg("");
return; /* back to cmd mode */
}
continue;
}
if ((c == '@') && (!literal_next_flag)) {
p = buff;
if (firstc != ':')
*p++ = firstc;
gotocmdline(YES, firstc);
continue;
}
if (literal_next_flag) {
literal_next_flag = FALSE;
outchar('\b');
}
outstr(chars[c].ch_str);
*p++ = c;
}
*p = '\0';
} else {
if (strlen(cmdline) > CMDBUFFSIZE - 2) /* should really do something
* better here... */
return;
strcpy(p, cmdline);
}
/* skip any initial white space */
for (cmd = buff; *cmd != NUL && isspace(*cmd); cmd++);
/* search commands */
c = *cmd;
if (c == '/' || c == '?') {
cmd++;
/* was the command was '//' or '??' (I.E. repeat last search) */
if ((*cmd == c) || (*cmd == NUL)) {
if (c == '/')
searchagain(FORWARD);
else
searchagain(BACKWARD);
return;
}
/* If there is a matching '/' or '?' at the end, toss it */
p = strchr(cmd, NUL);
if (*(p - 1) == c && *(p - 2) != '\\')
*(p - 1) = NUL;
dosearch((c == '/') ? FORWARD : BACKWARD, cmd);
return;
}
/*
* Parse a range, if present (and update the cmd pointer).
*/
get_range(&cmd);
if (l_pos.linep != NULL) {
if (LINEOF(&l_pos) > LINEOF(&u_pos)) {
emsg("Invalid range");
return;
}
}
strcpy(cmdbuf, cmd); /* save the unmodified command */
/* isolate the command and find any argument */
for (p = cmd; *p != NUL && !isspace(*p); p++);
if (*p == NUL)
arg = NULL;
else {
*p = NUL;
for (p++; *p != NUL && isspace(*p); p++);
if (*p == NUL) {
arg = NULL;
} else {
strcpy(argbuf, p);
arg = argbuf;
}
}
if (strcmp(cmd, "q!") == 0) {
getout(0);
}
if (strcmp(cmd, "q") == 0) {
if (Changed) {
emsg(nowrtmsg);
} else {
getout(0);
}
return;
}
if (strcmp(cmd, "w") == 0) {
if (arg == NULL) {
if (Filename != NULL) {
if (!writeit(Filename, &l_pos, &u_pos)) {
emsg("Problems occured while writing output file");
}
} else {
emsg("No output file");
}
} else {
(void) writeit(arg, &l_pos, &u_pos);
}
return;
}
if (strcmp(cmd, "wq") == 0) {
if (Filename != NULL) {
if (writeit(Filename, (LPtr *) NULL, (LPtr *) NULL)) {
getout(0);
}
} else {
emsg("No output file");
}
return;
}
if (strcmp(cmd, "x") == 0) {
if (Changed) {
if (Filename != NULL) {
if (!writeit(Filename, (LPtr *) NULL, (LPtr *) NULL)) {
emsg("Problems occured while writing output file");
return;
}
} else {
emsg("No output file");
return;
}
}
getout(0);
}
if (strcmp(cmd, "f") == 0 && arg == NULL) {
fileinfo();
return;
}
if (*cmd == 'n') {
if ((curfile + 1) < numfiles) {
/*
* stuff ":e[!] FILE\n"
*/
stuffReadbuff(":e");
if (cmd[1] == '!')
stuffReadbuff("!");
stuffReadbuff(" ");
stuffReadbuff(files[++curfile]);
stuffReadbuff("\n");
} else
emsg("No more files!");
return;
}
if (*cmd == 'p') {
if (curfile > 0) {
/*
* stuff ":e[!] FILE\n"
*/
stuffReadbuff(":e");
if (cmd[1] == '!')
stuffReadbuff("!");
stuffReadbuff(" ");
stuffReadbuff(files[--curfile]);
stuffReadbuff("\n");
} else
emsg("No more files!");
return;
}
if (strncmp(cmd, "rew", 3) == 0) {
if (numfiles <= 1) /* nothing to rewind */
return;
curfile = 0;
/*
* stuff ":e[!] FILE\n"
*/
stuffReadbuff(":e");
if (cmd[3] == '!')
stuffReadbuff("!");
stuffReadbuff(" ");
stuffReadbuff(files[0]);
stuffReadbuff("\n");
return;
}
if (strcmp(cmd, "e") == 0) {
if (Changed) {
emsg(nowrtmsg);
} else {
if (strcmp(arg, "%") == 0) {
(void) doecmd(NULL);
return;
}
#ifdef WILD_CARDS
if (strcmp(arg, "#") != 0) {
ExpandWildCards(1, &arg, &cmd_numfiles, &cmd_files);
if (cmd_numfiles == 0) {
emsg("Can't open file");
return;
} else if (cmd_numfiles == 1) {
arg = cmd_files[0];
} else {
emsg("Too many file names");
}
}
#endif
(void) doecmd(arg);
}
return;
}
if (strcmp(cmd, "e!") == 0) {
if (strcmp(arg, "%") == 0) {
if (!doecmd(NULL))
ResetBuffers();
return;
}
#ifdef WILD_CARDS
if (strcmp(arg, "#") != 0) {
ExpandWildCards(1, &arg, &cmd_numfiles, &cmd_files);
if (cmd_numfiles == 0) {
emsg("Can't open file");
return;
} else if (cmd_numfiles == 1) {
arg = cmd_files[0];
} else {
emsg("Too many file names");
}
}
#endif
if (!doecmd(arg))
ResetBuffers();
return;
}
if (strcmp(cmd, "f") == 0) {
Filename = strsave(arg);
filemess("");
return;
}
if (strcmp(cmd, "r") == 0 || strcmp(cmd, ".r") == 0) {
if (arg == NULL) {
badcmd();
return;
}
#ifdef WILD_CARDS
if (strcmp(arg, "#") != 0) {
ExpandWildCards(1, &arg, &cmd_numfiles, &cmd_files);
if (cmd_numfiles == 0) {
emsg("Can't open file");
return;
} else if (cmd_numfiles == 1) {
arg = cmd_files[0];
} else {
emsg("Too many file names");
}
}
#endif
if (readfile(arg, Curschar, 1)) {
emsg("Can't open file");
return;
}
ResetBuffers();
CHANGED;
return;
}
if (strcmp(cmd, ".=") == 0) {
smsg("line %d", cntllines(Filemem, Curschar));
return;
}
if (strcmp(cmd, "$=") == 0) {
smsg("%d", cntllines(Filemem, Fileend) - 1);
return;
}
if (strncmp(cmd, "ta", 2) == 0) {
dotag(arg, cmd[2] == '!');
return;
}
if (strcmp(cmd, "set") == 0) {
doset(arg, interactive);
return;
}
if (strcmp(cmd, "help") == 0) {
if (help())
s_clear();
return;
}
if (strcmp(cmd, "version") == 0) {
extern char *Version;
msg(Version);
return;
}
if (strcmp(cmd, "sh") == 0) {
doshell();
return;
}
if (strncmp(cmd, "d", 1) == 0) {
LINE *cp;
int n;
if (l_pos.linep == NULL)
l_pos = *Curschar;
if (u_pos.linep == NULL)
u_pos = l_pos;
ResetBuffers();
n = RowNumber(&l_pos);
AppendPositionToUndoUndobuff(0, n);
AppendPositionToUndobuff(0, n);
if ((Filetop->linep->next == l_pos.linep) &&
(u_pos.linep->next == Fileend->linep))
AppendToUndobuff("a");
else if (u_pos.linep->next == Fileend->linep)
AppendToUndobuff("o");
else
AppendToUndobuff("O");
n = 0;
cp = l_pos.linep;
for (; cp != NULL && cp != Fileend->linep; cp = cp->next) {
AppendToUndobuff(cp->s);
n++;
if (cp == u_pos.linep)
break;
AppendToUndobuff(NL_STR);
}
AppendToUndobuff(ESC_STR);
if (n > 1)
AppendNumberToUndoUndobuff(n);
AppendToUndoUndobuff("dd");
*Curschar = l_pos;
delline(n);
S_NOT_VALID;
return;
}
if (strncmp(cmd, "s/", 2) == 0) {
dosub(&l_pos, &u_pos, cmdbuf + 1);
return;
}
if (strncmp(cmd, "g/", 2) == 0) {
doglob(&l_pos, &u_pos, cmdbuf + 1);
return;
}
if (cmd[0] == '!') {
if (cmd[1] == '\0') {
emsg("Incomplete shell escape command");
return;
}
outstr("\n");
flushbuf();
#ifdef BSD
set_ostate();
#endif
#ifdef UNIX
set_ostate();
#endif
(void) system(&cmd[1]);
#ifdef BSD
set_nstate();
#endif
#ifdef UNIX
set_nstate();
#endif
wait_return();
return;
}
/*
* If we got a line, but no command, then go to the line.
*/
if (*cmd == NUL && l_pos.linep != NULL) {
if (u_pos.linep != NULL)
*Curschar = u_pos;
else
*Curschar = l_pos;
S_CHECK_TOPCHAR_AND_BOTCHAR;
return;
}
badcmd();
}
/*
* get_range - parse a range specifier
*
* Ranges are of the form:
*
* addr[,addr]
*
* where 'addr' is:
*
* % (entire file)
* $ [+-NUM]
* 'x [+-NUM] (where x denotes a currently defined mark)
* . [+-NUM]
* NUM
*
* The pointer *cp is updated to point to the first character following the
* range spec. If an initial address is found, but no second, the upper bound
* is equal to the lower.
*/
static void
get_range(char **cp)
{
LPtr *l;
char *p;
if (**cp == '%') {
l_pos.index = 0;
l_pos.linep = Filetop->linep->next;
u_pos.index = 0;
u_pos.linep = Fileend->linep->prev;
(*cp)++;
return;
}
if ((l = get_line(cp)) == NULL)
return;
l_pos = *l;
for (p = *cp; *p != NUL && isspace(*p); p++);
*cp = p;
if (*p != ',') { /* is there another line spec ? */
u_pos = l_pos;
return;
}
*cp = ++p;
if ((l = get_line(cp)) == NULL) {
u_pos = l_pos;
return;
}
u_pos = *l;
}
static LPtr *
get_line(char **cp)
{
static LPtr pos;
LPtr *lp;
char *p, c;
int lnum;
pos.index = 0; /* shouldn't matter... check back later */
p = *cp;
/*
* Determine the basic form, if present.
*/
switch (c = *p++) {
case '$':
pos.linep = Fileend->linep->prev;
break;
case '.':
pos.linep = Curschar->linep;
break;
case '\'':
if ((lp = getmark(*p++)) == NULL) {
emsg("Unknown mark");
return (LPtr *) NULL;
}
pos = *lp;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
for (lnum = c - '0'; isdigit(*p); p++)
lnum = (lnum * 10) + (*p - '0');
if (lnum == 0)
lnum = 1;
pos = *gotoline(lnum);
break;
default:
return (LPtr *) NULL;
}
while (*p != NUL && isspace(*p))
p++;
if (*p == '-' || *p == '+') {
bool_t neg = (*p++ == '-');
for (lnum = 0; isdigit(*p); p++)
lnum = (lnum * 10) + (*p - '0');
if (neg)
lnum = -lnum;
pos = *gotoline(cntllines(Filemem, &pos) + lnum);
}
*cp = p;
return &pos;
}
static void
badcmd(void)
{
if (interactive)
emsg("Unrecognized command");
}
/*
* dotag(tag, force) - goto tag
*/
void
dotag(char *tag, bool_t force)
/*char *tag;
bool_t force;*/
{
FILE *tp, *fopen();
char lbuf[LSIZE];
char *fname, *str;
if ((tp = fopen("tags", "r")) == NULL) {
emsg("Can't open tags file");
return;
}
while (fgets(lbuf, LSIZE, tp) != NULL) {
if ((fname = strchr(lbuf, TAB)) == NULL) {
emsg("Format error in tags file");
return;
}
*fname++ = '\0';
if ((str = strchr(fname, TAB)) == NULL) {
emsg("Format error in tags file");
return;
}
*str++ = '\0';
if (strcmp(lbuf, tag) == 0) {
if (!force && Changed) {
emsg(nowrtmsg);
return;
}
if (doecmd(fname)) {
stuffReadbuff(str); /* str has \n at end */
stuffReadbuff("\007"); /* CTRL('G') */
fclose(tp);
return;
}
}
}
emsg("tag not found");
fclose(tp);
}
static bool_t
doecmd(char *arg)
{
int line = 1; /* line # to go to in new file */
if (arg != NULL) {
/*
* First detect a ":e" on the current file. This is mainly for ":ta"
* commands where the destination is within the current file.
*/
if (Filename != NULL) {
if (strcmp(arg, Filename) == 0) {
if (!Changed) {
altfile = Filename;
altline = cntllines(Filemem, Curschar);
return TRUE;
}
}
}
if (strcmp(arg, "#") == 0) { /* alternate */
char *s = Filename;
if (altfile == NULL) {
emsg("No alternate file");
return FALSE;
}
if (strcmp(altfile, Filename) == 0) {
if (!Changed) {
line = altline;
altline = cntllines(Filemem, Curschar);
goto DO_THE_STUFF_THING;
}
}
Filename = altfile;
altfile = s;
line = altline;
altline = cntllines(Filemem, Curschar);
} else {
altfile = Filename;
altline = cntllines(Filemem, Curschar);
Filename = strsave(arg);
}
}
if (Filename == NULL) {
emsg("No filename");
return FALSE;
}
/* clear mem and read file */
freeall();
filealloc();
UNCHANGED;
if (readfile(Filename, Filemem, 0)) {
emsg("Can't open file");
return FALSE;
}
*Topchar = *Curschar;
if (line != 1) {
DO_THE_STUFF_THING:
stuffnumReadbuff(line);
stuffReadbuff("G");
}
setpcmark();
return TRUE;
}
static void
doshell(void)
{
char *sh, *getenv();
sh = getenv("SHELL");
if (sh == NULL) {
emsg("Shell variable not set");
return;
}
gotocmdline(YES, NUL);
if (system(sh) < 0) {
emsg("Exec failed");
return;
}
wait_return();
}
void
gotocmdline(bool_t clr, char firstc)
{
windgoto(Rows - 1, 0);
if (clr)
toutstr(T_EL); /* clear the bottom line */
if (firstc)
outchar(firstc);
}
/*
* msg(s) - displays the string 's' on the status line
*/
void
msg(char *s)
{
gotocmdline(YES, NUL);
outstr(s);
#ifdef AMIGA
flushbuf();
#endif
#ifdef BSD
flushbuf();
#endif
}
/* VARARGS */
#ifdef __ORCAC__
void smsg(char *s, ...)
{
static char sbuf[MAX_COLUMNS+1];
va_list ap;
va_start(ap,s);
vsprintf(sbuf,s,ap);
msg(sbuf);
va_end(ap);
}
#else
void
smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9)
char *s;
int a1, a2, a3, a4, a5, a6, a7, a8, a9;
{
char sbuf[MAX_COLUMNS + 1];
sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9);
msg(sbuf);
}
#endif
/*
* emsg() - display an error message
*
* Rings the bell, if appropriate, and calls message() to do the real work
*/
void
emsg(char *s)
{
UndoInProgress = FALSE;
RedrawingDisabled = FALSE;
if (P(P_EB))
beep();
toutstr(T_TI);
msg(s);
toutstr(T_TP);
#ifdef AMIGA
flushbuf();
#endif
#ifdef BSD
flushbuf();
#endif
}
void
wait_return(void)
{
char c;
outstr("Press RETURN to continue");
do {
c = vgetc();
} while (c != '\r' && c != '\n');
s_clear();
}

31
bin/vi/dec.c Normal file
View File

@ -0,0 +1,31 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
/*
* dec(p)
*
* Decrement the line pointer 'p' crossing line boundaries as necessary. Return
* 1 when crossing a line, -1 when at start of file, 0 otherwise.
*/
int
dec(LPtr *lp)
{
if (lp->index > 0) { /* still within line */
lp->index--;
return 0;
}
if (lp->linep->prev != Filetop->linep) { /* there is a prior line */
lp->linep = lp->linep->prev;
lp->index = strlen(lp->linep->s);
return 1;
}
lp->index = 0; /* stick at first char */
return -1; /* at start of file */
}

412
bin/vi/edit.c Normal file
View File

@ -0,0 +1,412 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
/*
* This flag is used to make auto-indent work right on lines where only a
* <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
* reset when any other editting is done on the line. If an <ESC> or <RETURN>
* is received, and did_ai is TRUE, the line is truncated.
*/
bool_t did_ai = FALSE;
static int replace_num;
void
edit(void)
{
char c;
bool_t literal_next_flag = FALSE;
char *replace_line;
char *ptr;
int len;
void dosuspend(void);
Prenum = 0;
/* position the display and the cursor at the top of the file. */
*Topchar = *Filemem;
*Curschar = *Filemem;
Cursrow = Curscol = 0;
for (;;) {
if (!RedrawingDisabled) {
/* Figure out where the cursor is based on Curschar. */
cursupdate(UPDATE_CURSOR);
windgoto(Cursrow, Curscol);
}
c = vgetc();
if (State == NORMAL) {
/* We're in the normal (non-insert) mode. */
/* Pick up any leading digits and compute 'Prenum' */
if (isascii(c)) { /* must disallow special chars from "ascii.h" */
if ((Prenum > 0 && isdigit(c)) || (isdigit(c) && c != '0')) {
Prenum = Prenum * 10 + (c - '0');
continue;
}
}
/* execute the command */
normal(c);
if (State == INSERT && last_command == 'R') {
ptr = Curschar->linep->s + Curschar->index;
len = strlen(ptr) + 1;
replace_line = (char *) NULL;
replace_num = 0;
if (len > 1) {
replace_line = alloc((unsigned) len);
if (replace_line != (char *) NULL)
strcpy(replace_line, ptr);
}
}
Prenum = 0;
} else {
if (c == CTRL('V') && !literal_next_flag) {
literal_next_flag = TRUE;
outchar('^');
continue;
}
if (literal_next_flag) {
literal_next_flag = FALSE;
outchar('\b');
if (c != NL) {
did_ai = FALSE;
insertchar(c);
continue;
}
}
switch (c) { /* We're in insert mode */
case ESC: /* an escape ends input mode */
doESCkey:
dosuspend();
/*
* If we just did an auto-indent, truncate the line, and put
* the cursor back.
*/
if (did_ai) {
Curschar->linep->s[0] = NUL;
Curschar->index = 0;
did_ai = FALSE;
}
set_want_col = TRUE;
/*
* The cursor should end up on the last inserted character.
* This is an attempt to match the real 'vi', but it may not
* be quite right yet.
*/
if (Curschar->index != 0) {
if (gchar(Curschar) == NUL)
dec(Curschar);
else if (Insbuffptr != NULL)
dec(Curschar);
}
State = NORMAL;
msg("");
if (!UndoInProgress) {
int n;
char *p;
if (last_command == 'o')
AppendToUndobuff(UNDO_SHIFTJ_STR);
if (Insbuffptr != NULL) {
if (last_command == 'O')
AppendToUndobuff("0");
AppendToRedobuff(Insbuff);
AppendToUndoUndobuff(Insbuff);
n = 0;
for (p = Insbuff; *p != NUL; p++) {
if (*p == NL) {
if (n) {
AppendNumberToUndobuff(n);
AppendToUndobuff("dl");
n = 0;
}
AppendToUndobuff(UNDO_SHIFTJ_STR);
} else
n++;
}
if (n) {
AppendNumberToUndobuff(n);
AppendToUndobuff("dl");
}
}
if (last_command == 'c') {
AppendToUndobuff(mkstr(last_command_char));
AppendToUndobuff(Yankbuff);
AppendToUndobuff(ESC_STR);
}
AppendToRedobuff(ESC_STR);
AppendToUndoUndobuff(ESC_STR);
if (last_command == 'O')
AppendToUndobuff(UNDO_SHIFTJ_STR);
if (last_command == 'R' && replace_line != (char *) NULL) {
if (replace_num > 0) {
if (replace_num < len) {
AppendToUndobuff("i");
replace_line[replace_num] = '\0';
} else {
AppendToUndobuff("a");
}
AppendToUndobuff(replace_line);
AppendToUndobuff(ESC_STR);
free(replace_line);
}
}
}
break;
case CTRL('D'):
/*
* Control-D is treated as a backspace in insert mode to make
* auto-indent easier. This isn't completely compatible with
* vi, but it's a lot easier than doing it exactly right, and
* the difference isn't very noticeable.
*/
case BS:
/* can't backup past starting point */
if (Curschar->linep == Insstart->linep &&
Curschar->index <= Insstart->index) {
beep();
break;
}
/* can't backup to a previous line */
if (Curschar->linep != Insstart->linep &&
Curschar->index <= 0) {
beep();
break;
}
did_ai = FALSE;
dec(Curschar);
delchar(TRUE, FALSE);
/*
* It's a little strange to put backspaces into the redo
* buffer, but it makes auto-indent a lot easier to deal
* with.
*/
AppendToInsbuff(BS_STR);
if (!RedrawingDisabled) /* screen will be fixed later */
S_LINE_NOT_VALID;
break;
case CR:
case NL:
AppendToInsbuff(NL_STR);
if (!OpenForward(!RedrawingDisabled))
goto doESCkey; /* out of memory */
break;
default:
did_ai = FALSE;
insertchar(c);
break;
}
}
}
}
/*
* Special characters in this context are those that need processing other
* than the simple insertion that can be performed here. This includes ESC
* which terminates the insert, and CR/NL which need special processing to
* open up a new line. This routine tries to optimize insertions performed by
* the "redo", "undo" or "put" commands, so it needs to know when it should
* stop and defer processing to the "normal" mechanism.
*/
#define ISSPECIAL(c) ((c) == BS || (c) == NL || (c) == CR || (c) == ESC)
void
insertchar(char c)
{
/*
* If there's any pending input, grab up to MAX_COLUMNS at once.
*/
if (anyinput() && (last_command != 'R' || (gchar(Curschar) == NUL))) {
char p[MAX_COLUMNS + 1];
int i;
p[0] = c;
i = 1;
c = vpeekc();
while (!ISSPECIAL(c) && anyinput() && (i < MAX_COLUMNS)) {
p[i++] = vgetc();
c = vpeekc();
}
p[i] = '\0';
insstr(p);
replace_num += i;
AppendToInsbuff(p);
} else {
inschar(c);
replace_num++;
AppendToInsbuff(mkstr(c));
}
if (!RedrawingDisabled) /* screen will be fixed later */
S_LINE_NOT_VALID;
}
void
getout(int r)
{
windgoto(Rows - 1, 0);
outchar('\n');
windexit(r);
}
void
scrolldown(int nlines)
{
register LPtr *p;
S_MUST_UPDATE_BOTCHAR;
S_CHECK_TOPCHAR_AND_BOTCHAR;
/* Scroll up 'nlines' lines. */
while (nlines--) {
p = prevline(Topchar);
if (p == NULL)
break;
Topchar->linep = p->linep;
}
/*
* The calling routine must make sure that Curschar is in the correct
* place with relation to Botchar.
*/
}
void
scrollup(int nlines)
{
register LPtr *p;
S_MUST_UPDATE_BOTCHAR;
S_CHECK_TOPCHAR_AND_BOTCHAR;
/* Scroll down 'nlines' lines. */
while (nlines--) {
p = nextline(Topchar);
if (p == NULL)
break;
Topchar->linep = p->linep;
}
/*
* The calling routine must make sure that Curschar is in the correct
* place with relation to Topchar.
*/
}
/*
* oneright oneleft onedown oneup
*
* Move one char {right,left,down,up}. Return TRUE when sucessful, FALSE when
* we hit a boundary (of a line, or the file).
*/
bool_t
oneright(void)
{
set_want_col = TRUE;
switch (inc(Curschar)) {
case 0:
return TRUE;
case 1:
dec(Curschar); /* crossed a line, so back up */
/* FALLTHROUGH */
case -1:
return FALSE;
}
return FALSE; /* PARANOIA: should never reach here */
}
bool_t
oneleft(void)
{
set_want_col = TRUE;
switch (dec(Curschar)) {
case 0:
return TRUE;
case 1:
inc(Curschar); /* crossed a line, so back up */
/* FALLTHROUGH */
case -1:
return FALSE;
}
return FALSE; /* PARANOIA: should never reach here */
}
void
beginline(bool_t flag)
{
while (oneleft());
if (flag) {
while (isspace(gchar(Curschar)) && oneright());
}
set_want_col = TRUE;
}
bool_t
oneup(int n)
{
register int k;
S_CHECK_TOPCHAR_AND_BOTCHAR;
for (k = 0; k < n; k++) {
if (Curschar->linep->prev == Filetop->linep) {
if (k > 0)
break;
else
return FALSE;
}
Curschar->linep = Curschar->linep->prev;
}
/* try to advance to the column we want to be at */
Curschar->index = 0;
coladvance(Curschar, Curswant);
return TRUE;
}
bool_t
onedown(int n)
{
register int k;
S_CHECK_TOPCHAR_AND_BOTCHAR;
for (k = 0; k < n; k++) {
if (Curschar->linep->next == Fileend->linep) {
if (k > 0)
break;
else
return FALSE;
}
Curschar->linep = Curschar->linep->next;
}
/* try to advance to the column we want to be at */
Curschar->index = 0;
coladvance(Curschar, Curswant);
return TRUE;
}

70
bin/vi/env.h Normal file
View File

@ -0,0 +1,70 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
/*
* The defines in this file establish the environment we're compiling
* in. Set these appropriately before compiling the editor.
*/
/*
* One (and only 1) of the following defines should be uncommented. Most of
* the code is pretty machine-independent. Machine dependent code goes in a
* file like tos.c or unix.c. The only other place where machine dependent
* code goes is term.h for escape sequences.
*/
#ifndef AMIGA
# ifndef BSD
# ifndef UNIX
/* Defined in makefile : AMIGA Amiga */
/* Defined in makefile : BSD BSD 4.3 */
/* Defined in makefile : UNIX System V */
/* #define ATARI Atari ST */
/* #define OS2 Microsoft OS/2 */
/* #define DOS MS DOS 3.3 */
#define GSOS Apple //GS GS/OS 5.02
# endif
# endif
#endif
#ifdef AMIGA
# define WILD_CARDS
#endif
/*
* If ATARI is defined, one of the following compilers must be selected.
*/
#ifdef ATARI
/* #define MWC Mark William's C 3.0.9 */
/* #define MEGAMAX Megamax Compiler */
/* #define ALCYON Alcyon C compiler */
# ifdef MWC
# define AppendNumberToUndoUndobuff XX1
# define AppendPositionToUndoUndobuff XX2
# define FOPENB
# endif
# ifdef MEGAMAX
# define FOPENB
# endif
#endif
/*
* If HELP is defined, the :help command shows a vi command summary.
*/
#define HELP /* enable help command */
/*
* STRCSPN should be defined if the target system doesn't have the
* routine strcspn() available. See regexp.c for details.
*/
#ifdef ATARI
#define STRCSPN
#endif

381
bin/vi/fileio.c Normal file
View File

@ -0,0 +1,381 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
*
* Code Contributions By : Jawaid Bayzar bazyar@cs.uiuc.edu
* Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
segment "s_io";
#ifdef GSOS
#include <gsos.h>
#include <signal.h>
#include <gno/gno.h>
#include <fcntl.h>
FileInfoRecGS finfo = {4, 0l, 0xC3, 0xB0, 0l};
#endif
void
filemess(char *s)
{
sprintf(IObuff, "\"%s\" %s", ((Filename == NULL) ? "" : Filename), s);
msg(IObuff);
}
void
renum(void)
{
LPtr *p;
unsigned long l = 0;
for (p = Filemem; p != NULL; p = nextline(p), l += LINEINC)
p->linep->num = l;
Fileend->linep->num = 0xffffffffL;
}
#ifdef MEGAMAX
overlay "fileio"
#endif
#ifdef GSOS
#define BUFSIZE1 4096
char *savebuf;
int outind;
int fd;
void flushout()
{
write(fd,savebuf,outind);
outind = 0;
}
#endif
/* made a bunch of these things unsigned for speed- 816 be dumb */
bool_t
readfile(char *fname, LPtr *fromp, bool_t nochangename)
/*char *fname;
LPtr *fromp;
bool_t nochangename; /* if TRUE, don't change the Filename */
{
FILE *f, *fopen();
LINE *curr;
char buf2[80];
int c,hitEOF = 0;
unsigned short IObuffsize = 0;
unsigned long nchars = 0;
unsigned int linecnt = 0;
bool_t wasempty = bufempty();
unsigned nonascii = 0; /* count garbage characters */
unsigned nulls = 0; /* count nulls */
bool_t incomplete = FALSE; /* was the last line incomplete? */
bool_t toolong = FALSE; /* a line was too long */
char *saveb1,*locIObuff;
unsigned inind,insize;
curr = fromp->linep;
locIObuff = IObuff;
if (!nochangename)
Filename = strsave(fname);
f = fopen(fname, "r");
if (f == NULL) {
s_refresh(NOT_VALID);
filemess("");
return TRUE;
}
#ifdef GSOS
{
GSString255Ptr fn;
fn = malloc(strlen(fname)+2);
fn->length = strlen(fname);
strncpy(fn->text,fname,fn->length);
finfo.pCount = 4;
finfo.pathname = fn;
GetFileInfoGS(&finfo);
free(fn);
}
#endif
S_NOT_VALID;
#ifdef GSOS
savebuf = malloc(BUFSIZE1+1);
saveb1 = savebuf;
insize = inind = 0;
#endif
do {
if (inind == insize) {
insize = read(fileno(f), savebuf, BUFSIZE1);
if (!insize) hitEOF = 1;
inind = 0;
}
/*c = getc(f);*/
c = saveb1[inind++];
if (c == '\r') c = NL;
if (hitEOF) {
if (IObuffsize == 0)/* normal loop termination */
break;
/*
* If we get EOF in the middle of a line, note the fact and
* complete the line ourselves.
*/
incomplete = TRUE;
c = NL;
}
if (c & 0x80) { /* much faster check for hi bit set */
c &= 0x7f; /* this is faster, jesus */
nonascii++;
}
/*
* If we reached the end of the line, OR we ran out of space for it,
* then process the complete line.
*/
if (c == NL || IObuffsize == (IOSIZE - 1)) {
LINE *lp;
if (c != NL)
toolong = TRUE;
locIObuff[IObuffsize++] = NUL;
lp = newline(IObuffsize);
if (lp == NULL) {
fprintf(stderr, "not enough memory - should never happen");
getout(1);
}
strcpy(lp->s, locIObuff);
curr->next->prev = lp; /* new line to next one */
lp->next = curr->next;
curr->next = lp; /* new line to prior one */
lp->prev = curr;
curr = lp; /* new line becomes current */
IObuffsize = 0;
linecnt++;
} else if (c == NUL) {
nulls++; /* count and ignore nulls */
} else {
locIObuff[IObuffsize++] = (char) c; /* normal character */
}
nchars++;
} while (!incomplete && !toolong);
free(savebuf);
fclose(f);
/*
* If the buffer was empty when we started, we have to go back and remove
* the "dummy" line at Filemem and patch up the ptrs.
*/
if (wasempty && linecnt != 0) {
LINE *dummy = Filemem->linep; /* dummy line ptr */
Filemem->linep = Filemem->linep->next;
Filemem->linep->prev = Filetop->linep;
Filetop->linep->next = Filemem->linep;
Curschar->linep = Filemem->linep;
Topchar->linep = Filemem->linep;
free(dummy->s); /* free string space */
free((char *) dummy); /* free LINE struct */
}
renum();
if (toolong) {
s_refresh(NOT_VALID);
sprintf(IObuff, "\"%s\" Line too long", fname);
msg(IObuff);
return FALSE;
}
s_refresh(NOT_VALID);
sprintf(IObuff, "\"%s\" %s%d line%s, %ld character%s",
fname,
incomplete ? "[Incomplete last line] " : "",
linecnt, (linecnt > 1) ? "s" : "",
nchars, (nchars > 1) ? "s" : "");
buf2[0] = NUL;
if (nonascii || nulls) {
if (nonascii) {
if (nulls)
sprintf(buf2, " (%d null, %d non-ASCII)",
nulls, nonascii);
else
sprintf(buf2, " (%d non-ASCII)", nonascii);
} else
sprintf(buf2, " (%d null)", nulls);
}
strcat(IObuff, buf2);
msg(IObuff);
return FALSE;
}
/*
* writeit - write to file 'fname' lines 'start' through 'end'
*
* If either 'start' or 'end' contain null line pointers, the default is to use
* the start or end of the file respectively.
*/
bool_t
writeit(char *fname, LPtr *start, LPtr *end)
{
FILE *f;
FILE *fopen();
FILE *fopenb(); /* open in binary mode, where needed */
char *s;
long nchars;
int lines;
LPtr *p;
#ifdef GSOS
int linesize,inind;
char *line_ptr,*saveb1;
#endif
sprintf(IObuff, "\"%s\"", fname);
msg(IObuff);
#ifdef GSOS
signal(SIGTSTP,SIG_IGN);
#endif
/*
* Form the backup file name - change foo.* to foo.bak - use IObuff to
* hold the backup file name
*/
strcpy(IObuff, fname);
for (s = IObuff; *s && *s != '.'; s++);
*s = NUL;
strcat(IObuff, ".bak");
/*
* Delete any existing backup and move the current version to the backup.
* For safety, we don't remove the backup until the write has finished
* successfully. And if the 'backup' option is set, leave it around.
*/
rename(fname, IObuff);
f = P(P_CR) ? fopen(fname, "w") : fopenb(fname, "w");
if (f == NULL) {
emsg("Can't open file for writing!");
return FALSE;
}
#ifdef GSOS
savebuf = malloc(BUFSIZE1+1); /* allocate our big memory-save buffer */
saveb1 = savebuf;
#endif
/*
* If we were given a bound, start there. Otherwise just start at the
* beginning of the file.
*/
if (start == NULL || start->linep == NULL)
p = Filemem;
else
p = start;
lines = 0;
nchars = 0;
#ifdef GSOS
outind = 0;
fd = fileno(f);
#endif
do {
#ifndef GSOS
fprintf(f, "%s\n", p->linep->s);
#else
line_ptr = p->linep->s;
asm {
stz inind
agin: ldy inind
lda [line_ptr],y
and #0xff
beq done
ldy outind
cpy #BUFSIZE1
bcc otaydude
pha
jsl flushout
pla
ldy #0
otaydude: sta [saveb1],y
iny
sty outind
inc inind
jmp agin
done: sty linesize
lda #13
ldy outind
sta [saveb1],y
iny
sty outind
lda linesize
clc
adc nchars
sta nchars
}
#endif
lines++;
#ifndef GSOS
nchars += strlen(p->linep->s) + 1;
#endif
/*
* If we were given an upper bound, and we just did that line, then
* bag it now.
*/
if (end != NULL && end->linep != NULL) {
if (end->linep == p->linep)
break;
}
} while ((p = nextline(p)) != NULL);
#ifdef GSOS
flushout();
free(savebuf);
#endif
fclose(f);
/*
* Remove the backup unless they want it left around
*/
if (!P(P_BK))
remove(IObuff);
sprintf(IObuff, "\"%s\" %d line%s, %ld character%s", fname,
lines, (lines > 1) ? "s" : "",
nchars, (nchars > 1) ? "s" : "");
msg(IObuff);
UNCHANGED;
#ifdef GSOS
{
GSString255Ptr fn;
extern void stopHandler(int,int);
fn = malloc(strlen(fname)+2);
fn->length = strlen(fname);
strncpy(fn->text,fname,fn->length);
finfo.pCount = 4;
finfo.pathname = fn;
SetFileInfoGS(&finfo);
free(fn);
}
signal(SIGTSTP, stopHandler); /* handle ^Z with a message */
#endif
return TRUE;
}

81
bin/vi/format.l.c Normal file
View File

@ -0,0 +1,81 @@
/*
* format_line()
*
* Return a pointer to a string buffer containing a formated screen line.
*
* By G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
char *tab_expand = " ";
char *
format_line(char *ptr, int *len)
{
register char *dest;
register char c;
register int col;
char *p_extra;
int n_extra;
int coff; /* column offset */
dest = IObuff;
col = 0;
coff = P(P_NU) ? 8 : 0;
n_extra = 0;
p_extra = NULL;
for (;;) {
if (n_extra > 0) {
c = *p_extra++;
n_extra--;
} else {
c = *ptr++;
while (c >= 32 && c < 127) {
*dest++ = c;
col++;
if (col >= IOSIZE)
goto DONE_FORMAT_LINE;
c = *ptr++;
}
if (!P(P_LS)) {
if (c == TAB) {
/* tab amount depends on current column */
p_extra = tab_expand;
n_extra = (P(P_TS) - 1) - (col - coff) % P(P_TS);
c = ' ';
goto I_HATE_GOTOS;
} else if (c == NUL) {
break;
}
} else if (c == NUL) {
*dest++ = '$';
col++;
break;
}
if ((n_extra = chars[c].ch_size - 1) > 0) {
p_extra = chars[c].ch_str;
c = *p_extra++;
}
}
I_HATE_GOTOS:
*dest++ = c;
col++;
if (col >= IOSIZE)
break;
}
DONE_FORMAT_LINE:
if (col >= IOSIZE) {
dest--;
col--;
}
*dest = NUL;
if (len != NULL)
*len = col + coff;
return (IObuff);
}

287
bin/vi/gsos.c Normal file
View File

@ -0,0 +1,287 @@
/*
* Apple //gs GSOS system-dependent code
*/
#include <sys/types.h>
#include <texttool.h>
#include <misctool.h>
#include <shell.h>
#include <gsos.h>
/* 2/orcacdefs/gsos.h, not OUR include file */
#include "stevie.h"
#include <gno/gno.h>
#include <gno/signal.h>
#include <unistd.h>
#include "gsos.h"
#include <sys/ioctl.h>
#include <fcntl.h>
#ifdef __ORCAC__
#pragma optimize 8
#endif
char *tc_ED;
char *tc_EL;
char *tc_IL;
char *tc_DL;
char *tc_CI;
char *tc_CV;
char *tc_TP;
char *tc_TI;
char *tc_END_D;
char *tc_END_L;
typedef struct {
int flag;
char *comm;
} execPB;
typedef struct {
char *var_name;
char *value;
} readPB;
/*
* These routines only work by the grace of God (and because I
* track the old IIe cursor locations)
* GNO 1.1 has insert-line and delete-line chars in it's console
* driver. If present in the termcap file, stevie uses these.
*/
void InsertLine(void)
{
byte *WindTop = (byte *) 0x0022,
*cy = (byte *) 0x0025;
*WindTop = *cy;
WriteChar(22);
*WindTop = 0;
}
void DeleteLine(void)
{
byte *WindTop = (byte *) 0x0022,
*cy = (byte *) 0x0025;
*WindTop = *cy;
WriteChar(23);
*WindTop = 0;
}
char outbuf[1024];
int indbuf = 0;
void
flushbuf(void)
{
write(STDOUT_FILENO, outbuf, indbuf);
indbuf = 0;
}
int
outchar(char c)
{
if (c == '\n') c = '\r';
outbuf[indbuf++] = c;
if (indbuf == 1024) flushbuf(); /* GOD DAMN, JAWAID!!! */
}
int
toutchar(char c)
{
outbuf[indbuf++] = c;
if (indbuf == 1024) flushbuf(); /* GOD DAMN, JAWAID!!! */
}
void
outstr(char *s)
{
char c;
while (*s) {
if ((c = *s++) == '\n') c = '\r';
outbuf[indbuf++] = c;
if (indbuf == 1024) flushbuf(); /* GOD DAMN, JAWAID!!! */
}
}
void
toutstr(char *s)
{
/* this pretty much ignores how the delay characters need to work,
but I don't think delays really matter all that much */
tputs(s,1,toutchar);
}
int inchar(void)
{
int c;
flushbuf();
c = ReadChar(0);
if (!(c & 0x0200)) /* make sure control is not down */
switch (c & 0xFF) {
case 0x0a:
return K_DARROW;
case 0x0b:
return K_UARROW;
case 0x08:
return K_LARROW;
case 0x15:
return K_RARROW;
}
c &= 0x7F;
if (c == 0x7f) return 0x8;
return c;
}
void beep(void)
{
outchar(7);
flushbuf();
}
char *CM;
char *mp;
char tcb[100];
struct sgttyb ss;
int oldFlags;
struct ltchars ltch;
char oldsuspchar;
void nosuspend(void)
{
ioctl(STDOUT_FILENO, TIOCGLTC, &ltch);
ltch.t_suspc = -1;
ioctl(STDOUT_FILENO, TIOCSLTC, &ltch);
}
void dosuspend(void)
{
ioctl(STDOUT_FILENO, TIOCGLTC, &ltch);
ltch.t_suspc = oldsuspchar;
/*smsg("Old Suspend Char: %02X\n",oldsuspchar);*/
ioctl(STDOUT_FILENO, TIOCSLTC, &ltch);
}
/* startup termcap, and initialize the characters */
void
windinit(void)
{
char *term,*tcp;
Columns = 80;
P(P_LI) = Rows = 24;
SetInGlobals(0xFFFF,0x00);
/* TextStartUp(); */
ioctl(STDOUT_FILENO,TIOCGETP,&ss);
oldFlags = ss.sg_flags;
ss.sg_flags &= ~ECHO;
ss.sg_flags |= CBREAK; /* for benefit of terminals */
ioctl(STDOUT_FILENO,TIOCSETP,&ss); /* make sure echo is off for terms */
ioctl(STDOUT_FILENO,TIOCGLTC,&ltch);
oldsuspchar = ltch.t_suspc;
if (!(term = getenv("TERM"))) {
fprintf(stderr, "vi: TERM: parameter not set\n");
exit(1);
}
if (!(mp = malloc((size_t)1024))) {
fprintf(stderr, "vi: out of termcap space.\n");
exit(1);
}
if (tgetent(mp, term) <= 0) {
fprintf(stderr, "vi: %s: unknown terminal type\n", term);
exit(1);
}
tcp = tcb;
if (!(CM = tgetstr("cm", &tcp))) {
fprintf(stderr, "vi: terminal not capable of cursor motion\n");
exit(1);
}
tc_END_D = tgetstr("cd", &tcp);
tc_END_L = tgetstr("ce", &tcp);
tc_ED = tgetstr("cl", &tcp);
tc_TP = tgetstr("se", &tcp);
tc_TI = tgetstr("so", &tcp);
tc_CI = tgetstr("vi", &tcp);
tc_CV = tgetstr("vs", &tcp);
tc_EL = tgetstr("ce", &tcp);
tc_IL = tgetstr("al", &tcp);
tc_DL = tgetstr("dl", &tcp);
}
void
windexit(int r)
{
flushbuf();
ss.sg_flags = oldFlags;
ioctl(STDOUT_FILENO,TIOCSETP,&ss);
exit(r);
}
void
windgoto(int r, int c)
{
tputs(tgoto(CM,c,r),1,toutchar);
/*WriteChar(0x1e);
WriteChar(32+c);
WriteChar(32+r); */
}
/*
* Should do something reasonable here.
*/
/*void
sleep(n)
int n;
{
}*/
void
delay(void)
{
long l;
flushbuf();
/*
* Should do something better here...
*/
sleep(1);
}
FILE *
fopenb(fname, mode)
char *fname;
char *mode;
{
char modestr[10];
sprintf(modestr, "b%s", mode);
return fopen(fname, modestr);
}
#pragma optimize 8
/* we _must_ have this in here or we won't be in the right databank! */
#pragma databank 1
void stopHandler(int sig, int code)
{
void *oldHndl;
int redrawChar = 12;
windgoto(23,0);
flushbuf();
printf("\nType 'fg' to restart vi...\n");
oldHndl = signal(SIGTSTP,SIG_DFL);
ss.sg_flags = oldFlags;
ioctl(STDOUT_FILENO,TIOCSETP,&ss);
kill(getpid(),SIGSTOP);
signal(SIGTSTP,oldHndl);
/* push a control-L into the input buffer- kinda goofy, but it works */
ioctl(STDOUT_FILENO,TIOCSTI,&redrawChar);
ss.sg_flags &= ~ECHO;
ss.sg_flags |= CBREAK;
ioctl(STDOUT_FILENO,TIOCSETP,&ss);
}

16
bin/vi/gsos.h Normal file
View File

@ -0,0 +1,16 @@
/*
* Apple //gs GSOS Machine-dependent routines.
*/
void flushbuf(void);
int inchar(void);
int outchar(char);
void outstr(char *);
void toutstr(char *);
void beep(void);
void windinit(void);
void windexit(int);
void windgoto(int,int);
void delay(void);
unsigned int sleep(unsigned int);

321
bin/vi/help.c Normal file
View File

@ -0,0 +1,321 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
#include <texttool.h>
extern char *Version;
static int helprow;
#ifdef HELP
#ifdef MEGAMAX
overlay "help"
#endif
static void longline(char *);
bool_t
help(void)
{
char s;
toutstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Positioning within file\n\
=======================\n\
^F\t\tForward screenfull Worked on by:\n\
^B\t\tBackward screenfull Tim Thompson\n");
longline("\
^D\t\tscroll down half screen Tony Andrews\n\
^U\t\tscroll up half screen G.R. (Fred) Walter\n");
longline("\
G\t\tGoto line (end default)\n\
]]\t\tnext function\n\
[[\t\tprevious function\n\
/re\t\tnext occurence of regular expression 're'\n");
longline("\
?re\t\tprior occurence of regular expression 're'\n\
n\t\trepeat last / or ?\n\
N\t\treverse last / or ?\n\
%\t\tfind matching (, ), {, }, [, or ]\n");
longline("\
\n\
Adjusting the screen\n\
====================\n\
^L\t\tRedraw the screen\n\
^E\t\tscroll window down 1 line\n\
^Y\t\tscroll window up 1 line\n");
longline("\
z<RETURN>\tredraw, current line at top\n\
z-\t\t... at bottom\n\
z.\t\t... at center\n");
/* s = ReadChar(0);
windgoto(0, 32);
longline(Version); */
#ifdef AMIGA
longline(" ");
longline(__DATE__);
longline(" ");
longline(__TIME__);
#endif
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
toutstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Character Positioning\n\
=====================\n\
^\t\tfirst non-white\n\
0\t\tbeginning of line\n\
$\t\tend of line\n\
h\t\tbackward\n");
longline("\
l\t\tforward\n\
^H\t\tsame as h\n\
space\t\tsame as l\n\
fx\t\tfind 'x' forward\n");
longline("\
Fx\t\tfind 'x' backward\n\
tx\t\tupto 'x' forward\n\
Tx\t\tupto 'x' backward\n\
;\t\tRepeat last f, F, t, or T\n");
longline("\
,\t\tinverse of ;\n\
|\t\tto specified column\n\
%\t\tfind matching (, ), {, }, [, or ]\n");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
toutstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Line Positioning\n\
================\n\
H\t\thome window line\n\
L\t\tlast window line\n\
M\t\tmiddle window line\n");
longline("\
+\t\tnext line, at first non-white\n\
-\t\tprevious line, at first non-white\n\
CR\t\treturn, same as +\n\
j\t\tnext line, same column\n\
k\t\tprevious line, same column\n");
longline("\
\n\
Marking and Returning\n\
=====================\n\
``\t\tprevious context\n\
''\t\t... at first non-white in line\n");
longline("\
mx\t\tmark position with letter 'x'\n\
`x\t\tto mark 'x'\n\
'x\t\t... at first non-white in line\n");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
toutstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Insert and Replace\n\
==================\n\
a\t\tappend after cursor\n\
i\t\tinsert before cursor\n\
A\t\tappend at end of line\n\
I\t\tinsert before first non-blank\n");
longline("\
o\t\topen line below\n\
O\t\topen line above\n\
rx\t\treplace single char with 'x'\n\
R\t\treplace characters (not yet)\n\
~\t\treplace character under cursor with other case\n");
longline("\
\n\
Words, sentences, paragraphs\n\
============================\n\
w\t\tword forward\n\
b\t\tback word\n\
e\t\tend of word\n\
)\t\tto next sentence (not yet)\n\
}\t\tto next paragraph (not yet)\n");
longline("\
(\t\tback sentence (not yet)\n\
{\t\tback paragraph (not yet)\n\
W\t\tblank delimited word\n\
B\t\tback W\n\
E\t\tto end of W");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
toutstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Undo & Redo\n\
=============\n\
u\t\tundo last change\n\
U\t\trestore current line (not yet)\n\
.\t\trepeat last change\n");
longline("\
\n\
File manipulation\n\
=================\n");
longline("\
:w\t\twrite back changes\n\
:wq\t\twrite and quit\n\
:x\t\twrite if modified, and quit\n\
:q\t\tquit\n\
:q!\t\tquit, discard changes\n\
:e name\t\tedit file 'name'\n");
longline("\
:e!\t\tre-edit, discard changes\n\
:e #\t\tedit alternate file\n\
:w name\t\twrite file 'name'\n");
longline("\
:n\t\tedit next file in arglist\n\
:n args\t\tspecify new arglist (not yet)\n\
:rew\t\trewind arglist\n\
:f\t\tshow current file and lines\n");
longline("\
:f file\t\tchange current file name\n\
:ta tag\t\tto tag file entry 'tag'\n\
^]\t\t:ta, current word is tag");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
toutstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Operators (double to affect lines)\n\
==================================\n\
d\t\tdelete\n\
c\t\tchange\n");
longline("\
<\t\tleft shift\n\
>\t\tright shift\n\
y\t\tyank to buffer\n");
longline("\n\
Yank and Put\n\
============\n\
p\t\tput back text\n\
P\t\tput before\n\
Y\t\tyank lines");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
toutstr(T_ED);
windgoto(helprow = 0, 0);
longline("\n\
Miscellaneous operations\n\
========================\n\
C\t\tchange rest of line\n\
D\t\tdelete rest of line\n\
s\t\tsubstitute chars\n");
longline("\
S\t\tsubstitute lines (not yet)\n\
J\t\tjoin lines\n\
x\t\tdelete characters\n\
X\t\t... before cursor\n\
:!cmd\t\tsystem(\"cmd\")\n\
:[range]s/search/replace/[g]\n\
:[range]g/search[/p|/d]\n\
:[range]d\tdelete range of lines\n");
windgoto(helprow = Rows - 1, 47);
longline("<Press any key>");
vgetc();
return TRUE;
}
static void
longline(char *p)
{
# ifdef AMIGA
outstr(p);
# else
char *s;
for (s = p; *s; s++) {
if (*s == '\n')
windgoto(++helprow, 0);
else
outchar(*s);
}
# endif
}
#else
bool_t
help(void)
{
toutstr(T_ED);
windgoto(0, 0);
outstr(Version);
outstr("\n\nWorked on by:\n");
outstr("\tTim Thompson\n");
outstr("\tTony Andrews\n");
outstr("\tG.R. (Fred) Walter\n");
outstr("\nSorry, help not configured\n");
outstr("\n<Press any key>");
vgetc();
return TRUE;
}
#endif

32
bin/vi/inc.c Normal file
View File

@ -0,0 +1,32 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
/*
* inc(p)
*
* Increment the line pointer 'p' crossing line boundaries as necessary. Return
* 1 when crossing a line, -1 when at end of file, 0 otherwise.
*/
int
inc(LPtr *lp)
{
register char *p = &(lp->linep->s[lp->index]);
if (*p != NUL) { /* still within line */
lp->index++;
return ((p[1] != NUL) ? 0 : 1);
}
if (lp->linep->next != Fileend->linep) { /* there is a next line */
lp->index = 0;
lp->linep = lp->linep->next;
return 1;
}
return -1;
}

51
bin/vi/keymap.h Normal file
View File

@ -0,0 +1,51 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
/*
* Keycode definitions for special keys
*
* On systems that have any of these keys, the routine 'inchar' in the
* machine-dependent code should return one of the codes here.
*/
#define K_CGRAVE 0x1e /* control grave accent */
#define K_HELP 0x80
#define K_UNDO 0x81
#define K_INSERT 0x82
#define K_HOME 0x83
#define K_UARROW 0x84
#define K_DARROW 0x85
#define K_LARROW 0x86
#define K_RARROW 0x87
#define K_SUARROW 0x88
#define K_SDARROW 0x89
#define K_SLARROW 0x8a
#define K_SRARROW 0x8b
#define K_F1 0x8c /* function keys */
#define K_F2 0x8d
#define K_F3 0x8e
#define K_F4 0x8f
#define K_F5 0x90
#define K_F6 0x91
#define K_F7 0x92
#define K_F8 0x93
#define K_F9 0x94
#define K_F10 0x95
#define K_SF1 0x96 /* shifted function keys */
#define K_SF2 0x97
#define K_SF3 0x98
#define K_SF4 0x99
#define K_SF5 0x9a
#define K_SF6 0x9b
#define K_SF7 0x9c
#define K_SF8 0x9d
#define K_SF9 0x9e
#define K_SF10 0x9f

85
bin/vi/linefunc.c Normal file
View File

@ -0,0 +1,85 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#include "stevie.h"
/*
* nextline(curr)
*
* Return a pointer to the beginning of the next line after the one referenced
* by 'curr'. Return NULL if there is no next line (at EOF).
*/
LPtr *
nextline(LPtr *curr)
{
static LPtr next;
if (curr != NULL) {
if (curr->linep->next != Fileend->linep) {
next.index = 0;
next.linep = curr->linep->next;
return &next;
}
}
return (LPtr *) NULL;
}
/*
* prevline(curr)
*
* Return a pointer to the beginning of the line before the one referenced by
* 'curr'. Return NULL if there is no prior line.
*/
LPtr *
prevline(LPtr *curr)
{
static LPtr prev;
if (curr != NULL) {
if (curr->linep->prev != Filetop->linep) {
prev.index = 0;
prev.linep = curr->linep->prev;
return &prev;
}
}
return (LPtr *) NULL;
}
/*
* coladvance(p,col)
*
* Try to advance to the specified column, starting at p.
*/
void
coladvance(LPtr *p, int want_col)
{
register char c;
register int col;
register int incr;
if (gchar(p) != NUL) { /* already at the end of line */
for (col = 0; want_col > 0;) {
c = gchar(p);
if (c == TAB && !P(P_LS))
incr = (P(P_TS) - col % P(P_TS));
else
incr = chars[c].ch_size;
want_col -= incr;
col += incr;
/* Don't go past the end of the file or the line. */
if (inc(p)) {
dec(p);
break;
}
}
}
}

24
bin/vi/linkscr Executable file
View File

@ -0,0 +1,24 @@
o/MAIN
o/EDIT
o/LINEFUNC
o/CMDLINE
o/CHARSET
o/MK
o/FORMAT.L
o/NORMAL
o/REGEXP
o/REGSUB
o/VERSION
o/MISCCMDS
o/HELP
o/DEC
o/INC
o/SEARCH
o/ALLOC
o/S.IO
o/MARK
o/SCREEN
o/FILEIO
o/PARAM
o/GSOS

82
bin/vi/macros.h Normal file
View File

@ -0,0 +1,82 @@
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
/*
* gchar(lp) - get the character at position "lp"
*/
#define gchar(lp) ((lp)->linep->s[(lp)->index])
/*
* pchar(lp, c) - put character 'c' at position 'lp'
*/
#define pchar(lp, c) ((lp)->linep->s[(lp)->index] = (c))
/*
* pswap(a, b) - swap two position pointers
*/
#define pswap(a, b) { LPtr \
pswaptmp; pswaptmp = a; a = b; b = pswaptmp; }
/*
* Position comparisons
*/
#define lt(a, b) ((LINEOF(a) != LINEOF(b)) \
? (LINEOF(a) < LINEOF(b)) : ((a)->index < (b)->index))
#define ltoreq(a, b) ((LINEOF(a) != LINEOF(b)) \
? (LINEOF(a) < LINEOF(b)) : ((a)->index <= (b)->index))
#define gt(a, b) ((LINEOF(a) != LINEOF(b)) \
? (LINEOF(a) > LINEOF(b)) : ((a)->index > (b)->index))
#define gtoreq(a, b) ((LINEOF(a) != LINEOF(b)) \
? (LINEOF(a) > LINEOF(b)) : ((a)->index >= (b)->index))
#define equal(a, b) (((a)->linep == (b)->linep) && ((a)->index == (b)->index))
/*
* anyinput
*
* Return non-zero if input is pending.
*/
#define anyinput() (Readbuffptr != NULL)
/*
* buf1line() - return TRUE if there is only one line in file buffer
*/
#define buf1line() (Filemem->linep->next == Fileend->linep)
/*
* bufempty() - return TRUE if the file buffer is empty
*/
#define bufempty() (buf1line() && Filemem->linep->s[0] == NUL)
/*
* lineempty() - return TRUE if the line is empty
*/
#define lineempty(p) ((p)->linep->s[0] == NUL)
/*
* startofline() - return TRUE if the given position is at start of line
*/
#define startofline(p) ((p)->index == 0)
/*
* endofline() - return TRUE if the given position is at end of line
*
* This routine will probably never be called with a position resting on the NUL
* byte, but handle it correctly in case it happens.
*/
#define endofline(p) \
((p)->linep->s[(p)->index] == NUL || (p)->linep->s[(p)->index + 1] == NUL)
/*
* RowNumber() - return the row number (if no UndoInProgress)
*/
#define RowNumber(p) (UndoInProgress ? 0 : cntllines(Filemem, (p)))

Some files were not shown because too many files have changed in this diff Show More